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); }