Commit b1472812 authored by Paolo Bacchilega's avatar Paolo Bacchilega

libarchive: sanitize filenames before extracting

parent de2209a9
...@@ -512,6 +512,7 @@ extract_archive_thread (GSimpleAsyncResult *result, ...@@ -512,6 +512,7 @@ extract_archive_thread (GSimpleAsyncResult *result,
while ((r = archive_read_next_header (a, &entry)) == ARCHIVE_OK) { while ((r = archive_read_next_header (a, &entry)) == ARCHIVE_OK) {
const char *pathname; const char *pathname;
char *fullpath; char *fullpath;
const char *relative_path;
GFile *file; GFile *file;
GFile *parent; GFile *parent;
GOutputStream *ostream; GOutputStream *ostream;
...@@ -531,7 +532,12 @@ extract_archive_thread (GSimpleAsyncResult *result, ...@@ -531,7 +532,12 @@ extract_archive_thread (GSimpleAsyncResult *result,
} }
fullpath = (*pathname == '/') ? g_strdup (pathname) : g_strconcat ("/", pathname, NULL); 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 */ /* honor the skip_older and overwrite options */
...@@ -615,14 +621,22 @@ extract_archive_thread (GSimpleAsyncResult *result, ...@@ -615,14 +621,22 @@ extract_archive_thread (GSimpleAsyncResult *result,
linkname = archive_entry_hardlink (entry); linkname = archive_entry_hardlink (entry);
if (linkname != NULL) { if (linkname != NULL) {
char *link_fullpath; char *link_fullpath;
GFile *link_file; const char *relative_path;
char *oldname; GFile *link_file;
char *newname; char *oldname;
int r; char *newname;
int r;
link_fullpath = (*linkname == '/') ? g_strdup (linkname) : g_strconcat ("/", linkname, NULL); 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); oldname = g_file_get_path (link_file);
newname = g_file_get_path (file); newname = g_file_get_path (file);
......
...@@ -6683,26 +6683,35 @@ query_info_ready_for_overwrite_dialog_cb (GObject *source_object, ...@@ -6683,26 +6683,35 @@ query_info_ready_for_overwrite_dialog_cb (GObject *source_object,
static void static void
_fr_window_ask_overwrite_dialog (OverwriteData *odata) _fr_window_ask_overwrite_dialog (OverwriteData *odata)
{ {
gboolean perform_extraction = TRUE;
if ((odata->edata->overwrite == FR_OVERWRITE_ASK) && (odata->current_file != NULL)) { if ((odata->edata->overwrite == FR_OVERWRITE_ASK) && (odata->current_file != NULL)) {
const char *base_name; const char *base_name;
GFile *destination; GFile *destination;
base_name = _g_path_get_relative_basename ((char *) odata->current_file->data, odata->edata->base_dir, odata->edata->junk_paths); base_name = _g_path_get_relative_basename_safe ((char *) odata->current_file->data, odata->edata->base_dir, odata->edata->junk_paths);
destination = g_file_get_child (odata->edata->destination, base_name); if (base_name != NULL) {
g_file_query_info_async (destination, destination = g_file_get_child (odata->edata->destination, base_name);
G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, g_file_query_info_async (destination,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
G_PRIORITY_DEFAULT, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
odata->window->priv->cancellable, G_PRIORITY_DEFAULT,
query_info_ready_for_overwrite_dialog_cb, odata->window->priv->cancellable,
odata); 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 /* speed optimization: passing NULL when extracting all the
* files is faster if the command supports the * files is faster if the command supports the
* propCanExtractAll property. */ * propCanExtractAll property. */
......
...@@ -1020,6 +1020,46 @@ _g_path_get_relative_basename (const char *path, ...@@ -1020,6 +1020,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 gboolean
_g_filename_is_hidden (const gchar *name) _g_filename_is_hidden (const gchar *name)
{ {
......
...@@ -145,6 +145,10 @@ gboolean _g_path_is_parent_of (const char *dirname ...@@ -145,6 +145,10 @@ gboolean _g_path_is_parent_of (const char *dirname
const char * _g_path_get_relative_basename (const char *path, const char * _g_path_get_relative_basename (const char *path,
const char *base_dir, const char *base_dir,
gboolean junk_paths); 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); gboolean _g_filename_is_hidden (const char *name);
const char * _g_filename_get_extension (const char *filename); const char * _g_filename_get_extension (const char *filename);
gboolean _g_filename_has_extension (const char *filename, gboolean _g_filename_has_extension (const char *filename,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment