[file-roller/gnome-3-6] libarchive: sanitize filenames before extracting



commit 1e73fce51545a067767b5ba84202e73175ad0672
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Mon May 27 21:18:21 2013 +0200

    libarchive: sanitize filenames before extracting

 src/fr-archive-libarchive.c |   28 +++++++++++++++++++++-------
 src/fr-window.c             |   33 +++++++++++++++++++++------------
 src/glib-utils.c            |   40 ++++++++++++++++++++++++++++++++++++++++
 src/glib-utils.h            |    4 ++++
 4 files changed, 86 insertions(+), 19 deletions(-)
---
diff --git a/src/fr-archive-libarchive.c b/src/fr-archive-libarchive.c
index a48128d..bd1d56f 100644
--- a/src/fr-archive-libarchive.c
+++ b/src/fr-archive-libarchive.c
@@ -512,6 +512,7 @@ extract_archive_thread (GSimpleAsyncResult *result,
        while ((r = archive_read_next_header (a, &entry)) == ARCHIVE_OK) {
                const char    *pathname;
                char          *fullpath;
+               const char    *relative_path;
                GFile         *file;
                GFile         *parent;
                GOutputStream *ostream;
@@ -531,7 +532,12 @@ extract_archive_thread (GSimpleAsyncResult *result,
                }
 
                fullpath = (*pathname == '/') ? g_strdup (pathname) : g_strconcat ("/", pathname, NULL);
-               file = g_file_get_child (extract_data->destination, _g_path_get_relative_basename (fullpath, 
extract_data->base_dir, extract_data->junk_paths));
+               relative_path = _g_path_get_relative_basename_safe (fullpath, extract_data->base_dir, 
extract_data->junk_paths);
+               if (relative_path == NULL) {
+                       archive_read_data_skip (a);
+                       continue;
+               }
+               file = g_file_get_child (extract_data->destination, relative_path);
 
                /* honor the skip_older and overwrite options */
 
@@ -615,14 +621,22 @@ extract_archive_thread (GSimpleAsyncResult *result,
 
                        linkname = archive_entry_hardlink (entry);
                        if (linkname != NULL) {
-                               char  *link_fullpath;
-                               GFile *link_file;
-                               char  *oldname;
-                               char  *newname;
-                               int    r;
+                               char        *link_fullpath;
+                               const char  *relative_path;
+                               GFile       *link_file;
+                               char        *oldname;
+                               char        *newname;
+                               int          r;
 
                                link_fullpath = (*linkname == '/') ? g_strdup (linkname) : g_strconcat ("/", 
linkname, NULL);
-                               link_file = g_file_get_child (extract_data->destination, 
_g_path_get_relative_basename (link_fullpath, extract_data->base_dir, extract_data->junk_paths));
+                               relative_path = _g_path_get_relative_basename_safe (link_fullpath, 
extract_data->base_dir, extract_data->junk_paths);
+                               if (relative_path == NULL) {
+                                       g_free (link_fullpath);
+                                       archive_read_data_skip (a);
+                                       continue;
+                               }
+
+                               link_file = g_file_get_child (extract_data->destination, relative_path);
                                oldname = g_file_get_path (link_file);
                                newname = g_file_get_path (file);
 
diff --git a/src/fr-window.c b/src/fr-window.c
index e033869..454c439 100644
--- a/src/fr-window.c
+++ b/src/fr-window.c
@@ -6667,26 +6667,35 @@ query_info_ready_for_overwrite_dialog_cb (GObject      *source_object,
 static void
 _fr_window_ask_overwrite_dialog (OverwriteData *odata)
 {
+       gboolean perform_extraction = TRUE;
+
        if ((odata->edata->overwrite == FR_OVERWRITE_ASK) && (odata->current_file != NULL)) {
                const char *base_name;
                GFile      *destination;
 
-               base_name = _g_path_get_relative_basename ((char *) odata->current_file->data, 
odata->edata->base_dir, odata->edata->junk_paths);
-               destination = g_file_get_child (odata->edata->destination, base_name);
-               g_file_query_info_async (destination,
-                                        G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_STANDARD_NAME 
"," G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
-                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
-                                        G_PRIORITY_DEFAULT,
-                                        odata->window->priv->cancellable,
-                                        query_info_ready_for_overwrite_dialog_cb,
-                                        odata);
+               base_name = _g_path_get_relative_basename_safe ((char *) odata->current_file->data, 
odata->edata->base_dir, odata->edata->junk_paths);
+               if (base_name != NULL) {
+                       destination = g_file_get_child (odata->edata->destination, base_name);
+                       g_file_query_info_async (destination,
+                                                G_FILE_ATTRIBUTE_STANDARD_TYPE "," 
G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
+                                                G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+                                                G_PRIORITY_DEFAULT,
+                                                odata->window->priv->cancellable,
+                                                query_info_ready_for_overwrite_dialog_cb,
+                                                odata);
 
-               g_object_unref (destination);
+                       g_object_unref (destination);
 
-               return;
+                       return;
+               }
+               else
+                       perform_extraction = FALSE;
        }
 
-       if (odata->edata->file_list != NULL) {
+       if (odata->edata->file_list == NULL)
+               perform_extraction = FALSE;
+
+       if (perform_extraction) {
                /* speed optimization: passing NULL when extracting all the
                 * files is faster if the command supports the
                 * propCanExtractAll property. */
diff --git a/src/glib-utils.c b/src/glib-utils.c
index 119edf4..092ff97 100644
--- a/src/glib-utils.c
+++ b/src/glib-utils.c
@@ -984,6 +984,46 @@ _g_path_get_relative_basename (const char *path,
 }
 
 
+#define ISDOT(c) ((c) == '.')
+#define ISSLASH(c) ((c) == '/')
+
+
+static const char *
+sanitize_filename (const char *file_name)
+{
+       size_t      prefix_len;
+       char const *p;
+
+       prefix_len = 0;
+       for (p = file_name; *p; ) {
+               if (ISDOT (p[0]) && ISDOT (p[1]) && (ISSLASH (p[2]) || !p[2]))
+                       prefix_len = p + 2 - file_name;
+
+               do {
+                       char c = *p++;
+                       if (ISSLASH (c))
+                               break;
+               }
+               while (*p);
+       }
+
+       p = file_name + prefix_len;
+       while (ISSLASH (*p))
+               p++;
+
+       return p;
+}
+
+
+const char *
+_g_path_get_relative_basename_safe (const char *path,
+                                   const char *base_dir,
+                                   gboolean    junk_paths)
+{
+       return sanitize_filename (_g_path_get_relative_basename (path, base_dir, junk_paths));
+}
+
+
 gboolean
 _g_filename_is_hidden (const gchar *name)
 {
diff --git a/src/glib-utils.h b/src/glib-utils.h
index c409ea1..0837887 100644
--- a/src/glib-utils.h
+++ b/src/glib-utils.h
@@ -138,6 +138,10 @@ gboolean            _g_path_is_parent_of           (const char          *dirname
 const char *        _g_path_get_relative_basename  (const char          *path,
                                                    const char          *base_dir,
                                                    gboolean             junk_paths);
+const char *        _g_path_get_relative_basename_safe
+                                                  (const char          *path,
+                                                   const char          *base_dir,
+                                                   gboolean             junk_paths);
 gboolean            _g_filename_is_hidden          (const char          *name);
 const char *        _g_filename_get_extension      (const char          *filename);
 gboolean            _g_filename_has_extension      (const char          *filename,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]