comics: Remove support for tar and tar-like commands

When handling tar files, or using a command with tar-compatible syntax,
to open comic-book archives, both the archive name (the name of the
comics file) and the filename (the name of a page within the archive)
are quoted to not be interpreted by the shell.

But the filename is completely with the attacker's control and can start
with "--" which leads to tar interpreting it as a command line flag.

This can be exploited by creating a CBT file (a tar archive with the
.cbt suffix) with an embedded file named something like this:
"--checkpoint-action=exec=bash -c 'touch ~/hacked;'.jpg"

CBT files are infinitely rare (CBZ is usually used for DRM-free
commercial releases, CBR for those from more dubious provenance), so
removing support is the easiest way to avoid the bug triggering. All
this code was rewritten in the development release for GNOME 3.26 to not
shell out to any command, closing off this particular attack vector.

This also removes the ability to use libarchive's bsdtar-compatible
binary for CBZ (ZIP), CB7 (7zip), and CBR (RAR) formats. The first two
are already supported by unzip and 7zip respectively. libarchive's RAR
support is limited, so unrar is a requirement anyway.

Discovered by Felix Wilhelm from the Google Security Team.

https://bugzilla.gnome.org/show_bug.cgi?id=784630
comics_check_decompress_command	(gchar          *mime_type, 
				 ComicsDocument *comics_document,
				 GError         **error)
{
	gboolean success;
	gchar *std_out, *std_err;
	gint retval;
	GError *err = NULL;
	
	/* FIXME, use proper cbr/cbz mime types once they're
	 * included in shared-mime-info */
	
	if (g_content_type_is_a (mime_type, "application/x-cbr") ||
	    g_content_type_is_a (mime_type, "application/x-rar")) {
	        /* The RARLAB provides a no-charge proprietary (freeware) 
	        * decompress-only client for Linux called unrar. Another 
		* option is a GPLv2-licensed command-line tool developed by 
		* the Gna! project. Confusingly enough, the free software RAR 
		* decoder is also named unrar. For this reason we need to add 
		* some lines for disambiguation. Sorry for the added the 
		* complexity but it's life :)
		* Finally, some distributions, like Debian, rename this free 
		* option as unrar-free. 
		* */
		comics_document->selected_command = 
					g_find_program_in_path ("unrar");
		if (comics_document->selected_command) {
			/* We only use std_err to avoid printing useless error 
			 * messages on the terminal */
			success = 
				g_spawn_command_line_sync (
				              comics_document->selected_command, 
							   &std_out, &std_err,
							   &retval, &err);
			if (!success) {
				g_propagate_error (error, err);
				g_error_free (err);
				return FALSE;
			/* I don't check retval status because RARLAB unrar 
			 * doesn't have a way to return 0 without involving an 
			 * operation with a file*/
			} else if (WIFEXITED (retval)) {
				if (g_strrstr (std_out,"freeware") != NULL)
					/* The RARLAB freeware client */
					comics_document->command_usage = RARLABS;
				else
					/* The Gna! free software client */
					comics_document->command_usage = GNAUNRAR;

				g_free (std_out);
				g_free (std_err);
				return TRUE;
			}
		}
		/* The Gna! free software client with Debian naming convention */
		comics_document->selected_command = 
				g_find_program_in_path ("unrar-free");
		if (comics_document->selected_command) {
 			comics_document->command_usage = GNAUNRAR;
 			return TRUE;
 		}
 	} else if (g_content_type_is_a (mime_type, "application/x-cbz") ||
 		   g_content_type_is_a (mime_type, "application/zip")) {
 		/* InfoZIP's unzip program */
		comics_document->selected_command = 
				g_find_program_in_path ("unzip");
		comics_document->alternative_command =
				g_find_program_in_path ("zipnote");
		if (comics_document->selected_command &&
		    comics_document->alternative_command) {
			comics_document->command_usage = UNZIP;
			return TRUE;
		}
		/* fallback mode using 7za and 7z from p7zip project  */
		comics_document->selected_command =
				g_find_program_in_path ("7za");
		if (comics_document->selected_command) {
			comics_document->command_usage = P7ZIP;
			return TRUE;
		}
		comics_document->selected_command =
				g_find_program_in_path ("7z");
		if (comics_document->selected_command) {
 			comics_document->command_usage = P7ZIP;
 			return TRUE;
 		}
 
 	} else if (g_content_type_is_a (mime_type, "application/x-cb7") ||
 		   g_content_type_is_a (mime_type, "application/x-7z-compressed")) {
		/* 7zr, 7za and 7z are the commands from the p7zip project able 
		 * to decompress .7z files */ 
		comics_document->selected_command =
				g_find_program_in_path ("7zr");
		if (comics_document->selected_command) {
			comics_document->command_usage = P7ZIP;
			return TRUE;
		}
		comics_document->selected_command =
				g_find_program_in_path ("7za");
		if (comics_document->selected_command) {
			comics_document->command_usage = P7ZIP;
			return TRUE;
		}
		comics_document->selected_command =
				g_find_program_in_path ("7z");
		if (comics_document->selected_command) {
 			comics_document->command_usage = P7ZIP;
 			return TRUE;
 		}
 	} else {
 		g_set_error (error,
 			     EV_DOCUMENT_ERROR,
			     EV_DOCUMENT_ERROR_INVALID,
			     _("Not a comic book MIME type: %s"),
			     mime_type);
			     return FALSE;
	}
	g_set_error_literal (error,
			     EV_DOCUMENT_ERROR,
			     EV_DOCUMENT_ERROR_INVALID,
			     _("Can’t find an appropriate command to "
			     "decompress this type of comic book"));
	return FALSE;
}

comics_check_decompress_command	(gchar          *mime_type, 
				 ComicsDocument *comics_document,
				 GError         **error)
{
	gboolean success;
	gchar *std_out, *std_err;
	gint retval;
	GError *err = NULL;
	
	/* FIXME, use proper cbr/cbz mime types once they're
	 * included in shared-mime-info */
	
	if (g_content_type_is_a (mime_type, "application/x-cbr") ||
	    g_content_type_is_a (mime_type, "application/x-rar")) {
	        /* The RARLAB provides a no-charge proprietary (freeware) 
	        * decompress-only client for Linux called unrar. Another 
		* option is a GPLv2-licensed command-line tool developed by 
		* the Gna! project. Confusingly enough, the free software RAR 
		* decoder is also named unrar. For this reason we need to add 
		* some lines for disambiguation. Sorry for the added the 
		* complexity but it's life :)
		* Finally, some distributions, like Debian, rename this free 
		* option as unrar-free. 
		* */
		comics_document->selected_command = 
					g_find_program_in_path ("unrar");
		if (comics_document->selected_command) {
			/* We only use std_err to avoid printing useless error 
			 * messages on the terminal */
			success = 
				g_spawn_command_line_sync (
				              comics_document->selected_command, 
							   &std_out, &std_err,
							   &retval, &err);
			if (!success) {
				g_propagate_error (error, err);
				g_error_free (err);
				return FALSE;
			/* I don't check retval status because RARLAB unrar 
			 * doesn't have a way to return 0 without involving an 
			 * operation with a file*/
			} else if (WIFEXITED (retval)) {
				if (g_strrstr (std_out,"freeware") != NULL)
					/* The RARLAB freeware client */
					comics_document->command_usage = RARLABS;
				else
					/* The Gna! free software client */
					comics_document->command_usage = GNAUNRAR;

				g_free (std_out);
				g_free (std_err);
				return TRUE;
			}
		}
		/* The Gna! free software client with Debian naming convention */
		comics_document->selected_command = 
				g_find_program_in_path ("unrar-free");
		if (comics_document->selected_command) {
 			comics_document->command_usage = GNAUNRAR;
 			return TRUE;
 		}
		comics_document->selected_command =
				g_find_program_in_path ("bsdtar");
		if (comics_document->selected_command) {
			comics_document->command_usage = TAR;
			return TRUE;
		}
 	} else if (g_content_type_is_a (mime_type, "application/x-cbz") ||
 		   g_content_type_is_a (mime_type, "application/zip")) {
 		/* InfoZIP's unzip program */
		comics_document->selected_command = 
				g_find_program_in_path ("unzip");
		comics_document->alternative_command =
				g_find_program_in_path ("zipnote");
		if (comics_document->selected_command &&
		    comics_document->alternative_command) {
			comics_document->command_usage = UNZIP;
			return TRUE;
		}
		/* fallback mode using 7za and 7z from p7zip project  */
		comics_document->selected_command =
				g_find_program_in_path ("7za");
		if (comics_document->selected_command) {
			comics_document->command_usage = P7ZIP;
			return TRUE;
		}
		comics_document->selected_command =
				g_find_program_in_path ("7z");
		if (comics_document->selected_command) {
 			comics_document->command_usage = P7ZIP;
 			return TRUE;
 		}
		comics_document->selected_command =
				g_find_program_in_path ("bsdtar");
		if (comics_document->selected_command) {
			comics_document->command_usage = TAR;
			return TRUE;
		}
 
 	} else if (g_content_type_is_a (mime_type, "application/x-cb7") ||
 		   g_content_type_is_a (mime_type, "application/x-7z-compressed")) {
		/* 7zr, 7za and 7z are the commands from the p7zip project able 
		 * to decompress .7z files */ 
		comics_document->selected_command =
				g_find_program_in_path ("7zr");
		if (comics_document->selected_command) {
			comics_document->command_usage = P7ZIP;
			return TRUE;
		}
		comics_document->selected_command =
				g_find_program_in_path ("7za");
		if (comics_document->selected_command) {
			comics_document->command_usage = P7ZIP;
			return TRUE;
		}
		comics_document->selected_command =
				g_find_program_in_path ("7z");
		if (comics_document->selected_command) {
 			comics_document->command_usage = P7ZIP;
 			return TRUE;
 		}
		comics_document->selected_command =
				g_find_program_in_path ("bsdtar");
		if (comics_document->selected_command) {
			comics_document->command_usage = TAR;
			return TRUE;
		}
	} else if (g_content_type_is_a (mime_type, "application/x-cbt") ||
		   g_content_type_is_a (mime_type, "application/x-tar")) {
		/* tar utility (Tape ARchive) */
		comics_document->selected_command =
				g_find_program_in_path ("tar");
		if (comics_document->selected_command) {
			comics_document->command_usage = TAR;
			return TRUE;
		}
		comics_document->selected_command =
				g_find_program_in_path ("bsdtar");
		if (comics_document->selected_command) {
			comics_document->command_usage = TAR;
			return TRUE;
		}
 	} else {
 		g_set_error (error,
 			     EV_DOCUMENT_ERROR,
			     EV_DOCUMENT_ERROR_INVALID,
			     _("Not a comic book MIME type: %s"),
			     mime_type);
			     return FALSE;
	}
	g_set_error_literal (error,
			     EV_DOCUMENT_ERROR,
			     EV_DOCUMENT_ERROR_INVALID,
			     _("Can’t find an appropriate command to "
			     "decompress this type of comic book"));
	return FALSE;
}
