Commit message: do not follow symlinks when deleting a folder recursively

[bug #698554]
CVE: CVE-2016-7162
CWE: CWE-20
Vulnerability description: The _g_file_remove_directory function in file-utils.c in File Roller 3.5.4 through 3.20.2 allows remote attackers to delete arbitrary files via a symlink attack on a folder in an archive.

Project: file-roller

_g_file_remove_directory (GFile         *directory,
			  GCancellable  *cancellable,
			  GError       **error)
{
	GFileEnumerator *enumerator;
	GFileInfo       *info;
	gboolean         error_occurred = FALSE;

	if (directory == NULL)
		return TRUE;

	enumerator = g_file_enumerate_children (directory,
					        G_FILE_ATTRIBUTE_STANDARD_NAME "," G_FILE_ATTRIBUTE_STANDARD_TYPE,
						G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
					        cancellable,
					        error);

	while (! error_occurred && (info = g_file_enumerator_next_file (enumerator, cancellable, error)) != NULL) {
		GFile *child;

		child = g_file_get_child (directory, g_file_info_get_name (info));
		switch (g_file_info_get_file_type (info)) {
		case G_FILE_TYPE_DIRECTORY:
			if (! _g_file_remove_directory (child, cancellable, error))
				error_occurred = TRUE;
			break;
		default:
			if (! g_file_delete (child, cancellable, error))
				error_occurred = TRUE;
			break;
		}

		g_object_unref (child);
		g_object_unref (info);
	}

	if (! error_occurred && ! g_file_delete (directory, cancellable, error))
 		error_occurred = TRUE;

	g_object_unref (enumerator);

	return ! error_occurred;
}

Project: file-roller

_g_file_is_temp_work_dir (GFile *file)
{
	gboolean  result = FALSE;
	char     *path;
	int       i;

	path = g_file_get_path (file);
	if (path[0] != '/') {
		g_free (path);
		return FALSE;
	}

	for (i = 0; try_folder[i] != NULL; i++) {
		const char *folder;

		folder = get_nth_temp_folder_to_try (i);
		if (strncmp (path, folder, strlen (folder)) == 0) {
			if (strncmp (path + strlen (folder), "/.fr-", 5) == 0) {
				result = TRUE;
				break;
			}
		}
	}

	g_free (path);

	return result;
}

Project: file-roller

_g_path_get_temp_work_dir (const char *parent_folder)
{
        guint64  max_size = 0;
        char    *best_folder = NULL;
        int      i;
        char    *template;
        char    *result = NULL;

        if (parent_folder == NULL) {
                /* find the folder with more free space. */

                for (i = 0; try_folder[i] != NULL; i++) {
                        const char *folder;
                        GFile      *file;
                        guint64     size;

                        folder = get_nth_temp_folder_to_try (i);
                        file = g_file_new_for_path (folder);
                        size = _g_file_get_free_space (file);
                        g_object_unref (file);

                        if (max_size < size) {
                                max_size = size;
                                g_free (best_folder);
                                best_folder = g_strdup (folder);
                        }
                }
        }
        else
                best_folder = g_strdup (parent_folder);

        if (best_folder == NULL)
                return NULL;

        template = g_strconcat (best_folder, "/.fr-XXXXXX", NULL);
        result = mkdtemp (template);
        g_free (best_folder);

        if ((result == NULL) || (*result == '\0')) {
                g_free (template);
                result = NULL;
        }

        return result;
}