Module Name:    src
Committed By:   christos
Date:           Thu Feb 18 17:58:51 UTC 2021

Modified Files:
        src/usr.bin/unzip: unzip.1 unzip.c

Log Message:
Add support for password protected zip files (Alex Kozlov)
Also some KNF


To generate a diff of this commit:
cvs rdiff -u -r1.12 -r1.13 src/usr.bin/unzip/unzip.1
cvs rdiff -u -r1.25 -r1.26 src/usr.bin/unzip/unzip.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/unzip/unzip.1
diff -u src/usr.bin/unzip/unzip.1:1.12 src/usr.bin/unzip/unzip.1:1.13
--- src/usr.bin/unzip/unzip.1:1.12	Thu Feb 18 12:04:39 2021
+++ src/usr.bin/unzip/unzip.1	Thu Feb 18 12:58:51 2021
@@ -25,7 +25,7 @@
 .\" SUCH DAMAGE.
 .\"
 .\" $FreeBSD: revision 180125$
-.\" $NetBSD: unzip.1,v 1.12 2021/02/18 17:04:39 christos Exp $
+.\" $NetBSD: unzip.1,v 1.13 2021/02/18 17:58:51 christos Exp $
 .\"
 .Dd February 18, 2021
 .Dt UNZIP 1
@@ -83,6 +83,9 @@ When extracting files from the zipfile, 
 The normal output is suppressed as if
 .Fl q
 was specified.
+.It Fl P Ar password
+Extract encrypted files using a password. Putting a password on
+the command line using this option can be insecure.
 .It Fl q
 Quiet: print less information while extracting.
 .It Fl t

Index: src/usr.bin/unzip/unzip.c
diff -u src/usr.bin/unzip/unzip.c:1.25 src/usr.bin/unzip/unzip.c:1.26
--- src/usr.bin/unzip/unzip.c:1.25	Thu Feb 18 12:05:51 2021
+++ src/usr.bin/unzip/unzip.c	Thu Feb 18 12:58:51 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: unzip.c,v 1.25 2021/02/18 17:05:51 christos Exp $ */
+/* $NetBSD: unzip.c,v 1.26 2021/02/18 17:58:51 christos Exp $ */
 
 /*-
  * Copyright (c) 2009, 2010 Joerg Sonnenberger <jo...@netbsd.org>
@@ -37,10 +37,11 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: unzip.c,v 1.25 2021/02/18 17:05:51 christos Exp $");
+__RCSID("$NetBSD: unzip.c,v 1.26 2021/02/18 17:58:51 christos Exp $");
 
 #ifdef __GLIBC__
 #define _GNU_SOURCE
+#define explicit_memset memset_s
 #endif
 
 #include <sys/queue.h>
@@ -58,6 +59,9 @@ __RCSID("$NetBSD: unzip.c,v 1.25 2021/02
 
 #include <archive.h>
 #include <archive_entry.h>
+#ifdef __GLIBC__
+#include <readpassphrase.h>
+#endif
 
 /* command-line options */
 static int		 a_opt;		/* convert EOL */
@@ -71,6 +75,7 @@ static int		 n_opt;		/* never overwrite 
 static int		 o_opt;		/* always overwrite */
 static int		 p_opt;		/* extract to stdout, quiet */
 static int		 q_opt;		/* quiet */
+static char		*P_arg;		/* passphrase */
 static int		 t_opt;		/* test */
 static int		 u_opt;		/* update */
 static int		 v_opt;		/* verbose/list */
@@ -92,7 +97,7 @@ static int		 tty;
 		int acret = (call);				\
 		if (acret != ARCHIVE_OK)			\
 			errorx("%s", archive_error_string(a));	\
-	} while (0)
+	} while (/*CONSTCONST*/0)
 
 /*
  * Indicates that last info() did not end with EOL.  This helps error() et
@@ -101,6 +106,9 @@ static int		 tty;
  */
 static int noeol;
 
+/* for an interactive passphrase input */
+static char passbuf[1024];
+
 /* fatal error message + errno */
 __dead __printflike(1, 2) static void
 error(const char *fmt, ...)
@@ -110,12 +118,12 @@ error(const char *fmt, ...)
 	if (noeol)
 		fprintf(stdout, "\n");
 	fflush(stdout);
-	fprintf(stderr, "unzip: ");
+	fprintf(stderr, "%s: ", getprogname());
 	va_start(ap, fmt);
 	vfprintf(stderr, fmt, ap);
 	va_end(ap);
 	fprintf(stderr, ": %s\n", strerror(errno));
-	exit(1);
+	exit(EXIT_FAILURE);
 }
 
 /* fatal error message, no errno */
@@ -127,12 +135,12 @@ errorx(const char *fmt, ...)
 	if (noeol)
 		fprintf(stdout, "\n");
 	fflush(stdout);
-	fprintf(stderr, "unzip: ");
+	fprintf(stderr, "%s: ", getprogname());
 	va_start(ap, fmt);
 	vfprintf(stderr, fmt, ap);
 	va_end(ap);
 	fprintf(stderr, "\n");
-	exit(1);
+	exit(EXIT_FAILURE);
 }
 
 /* non-fatal error message + errno */
@@ -227,7 +235,7 @@ pathdup(const char *path)
 	}
 	str[len] = '\0';
 
-	return (str);
+	return str;
 }
 
 /* concatenate two path names */
@@ -249,7 +257,7 @@ pathcat(const char *prefix, const char *
 	}
 	memcpy(str + prelen, path, len);	/* includes zero */
 
-	return (str);
+	return str;
 }
 
 /*
@@ -293,9 +301,9 @@ match_pattern(struct pattern_list *list,
 
 	STAILQ_FOREACH(entry, list, link) {
 		if (fnmatch(entry->pattern, str, C_opt ? FNM_CASEFOLD : 0) == 0)
-			return (1);
+			return 1;
 	}
-	return (0);
+	return 0;
 }
 
 /*
@@ -307,10 +315,10 @@ accept_pathname(const char *pathname)
 {
 
 	if (!STAILQ_EMPTY(&include) && !match_pattern(&include, pathname))
-		return (0);
+		return 0;
 	if (!STAILQ_EMPTY(&exclude) && match_pattern(&exclude, pathname))
-		return (0);
-	return (1);
+		return 0;
+	return 1;
 }
 
 /*
@@ -853,6 +861,34 @@ test(struct archive *a, struct archive_e
 }
 
 /*
+ * Callback function for reading passphrase.
+ * Originally from cpio.c and passphrase.c, libarchive.
+ */
+static const char *
+passphrase_callback(struct archive *a, void *client_data)
+{
+	char *p;
+	static const char prompt[] = "\nEnter passphrase:";
+
+	(void)a; /* UNUSED */
+	(void)client_data; /* UNUSED */
+
+#if defined(RPP_ECHO_OFF)
+	p = readpassphrase(prompt, passbuf, sizeof(passbuf), RPP_ECHO_OFF);
+#elif defined(GETPASS_NEED_TTY)
+	p = getpass_r(prompt, passbuf, sizeof(passbuf));
+#else
+	p = getpass(prompt);
+	if (p != NULL)
+		strlcpy(passbuf, p, sizeof(passbuf));
+#endif
+	if (p == NULL && errno != EINTR)
+		error("Error reading password");
+
+	return p;
+}
+
+/*
  * Main loop: open the zipfile, iterate over its contents and decide what
  * to do with each entry.
  */
@@ -868,6 +904,12 @@ unzip(const char *fn)
 		error("archive_read_new failed");
 
 	ac(archive_read_support_format_zip(a));
+
+	if (P_arg)
+		archive_read_add_passphrase(a, P_arg);
+	else
+		archive_read_set_passphrase_callback(a, passbuf, &passphrase_callback);
+
 	ac(archive_read_open_filename(a, fn, 8192));
 
 	if (!q_opt && !p_opt)
@@ -915,6 +957,7 @@ unzip(const char *fn)
 
 	ac(archive_read_free(a));
 
+	explicit_memset(passbuf, 0, sizeof(passbuf));
 	if (t_opt) {
 		if (error_count > 0) {
 			errorx("%ju checksum error(s) found.", error_count);
@@ -930,15 +973,16 @@ static void __dead
 usage(void)
 {
 
-	fprintf(stderr, "Usage: %s [-aCcfjLlnopqtuvy] [-d dir] [-x pattern] "
-	    "zipfile\n", getprogname());
-	exit(1);
+	fprintf(stderr, "Usage: %s [-aCcfjLlnopqtuvy] [-d <dir>] "
+	    "[-x <pattern>] [-P <passphrase>] <zipfile>\n", getprogname());
+	exit(EXIT_FAILURE);
 }
 
 static int
 getopts(int argc, char *argv[])
 {
 	int opt;
+	size_t len;
 
 #ifdef __GLIBC__
 	optind = 0;
@@ -984,6 +1028,11 @@ getopts(int argc, char *argv[])
 		case 'p':
 			p_opt = 1;
 			break;
+		case 'P':
+			len = strlcpy(passbuf, optarg, sizeof(passbuf));
+			memset(optarg, '*', len);
+			P_arg = passbuf;
+			break;
 		case 'q':
 			q_opt = 1;
 			break;
@@ -1006,7 +1055,7 @@ getopts(int argc, char *argv[])
 			usage();
 		}
 
-	return (optind);
+	return optind;
 }
 
 int
@@ -1051,5 +1100,5 @@ main(int argc, char *argv[])
 
 	unzip(zipfile);
 
-	exit(0);
+	exit(EXIT_SUCCESS);
 }

Reply via email to