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,
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);
......
......@@ -6683,26 +6683,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. */
......
......@@ -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
_g_filename_is_hidden (const gchar *name)
{
......
......@@ -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 *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,
......
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