@@ -, +, @@ --- unzip.1 | 3 +++ unzip.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) --- b/unzip.1 +++ b/unzip.1 @@ -81,6 +81,9 @@ When extracting files from the zipfile, they are written to stdout. The normal output is suppressed as if .Fl q was specified. +.It Fl P Ar passphrase +Extract encrypted files using a passphrase. Putting a passphrase in +plaintext using this option is a bad idea. .It Fl q Quiet: print less information while extracting. .It Fl t --- b/unzip.c +++ b/unzip.c @@ -55,6 +55,8 @@ #include #include +#include + /* command-line options */ static int a_opt; /* convert EOL */ @@ -68,6 +70,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 */ @@ -851,6 +854,35 @@ test(struct archive *a, struct archive_entry *e) return error_count; } +/* + * Callback function for reading one passphrase. + * Originally from cpio.c and passphrase.c, libarchive. + */ +#define PPBUFF_SIZE 1024 +static const char * +passphrase_callback(struct archive *a, void *_client_data) +{ + char **passphrase_buf = (char **)_client_data; + char *p; + + if (*passphrase_buf == NULL) { + *passphrase_buf = malloc(PPBUFF_SIZE); + if (*passphrase_buf == NULL) { + errno = ENOMEM; + error("malloc()"); + } + } + + p = readpassphrase("Enter passphrase:", *passphrase_buf, + PPBUFF_SIZE, RPP_ECHO_OFF); + + if (p == NULL && errno != EINTR) { + error("readpassphrase()"); + } + + return p; +} + /* * Main loop: open the zipfile, iterate over its contents and decide what * to do with each entry. @@ -881,6 +913,12 @@ unzip(const char *fn) } } + if (P_arg) { + archive_read_add_passphrase(a, P_arg); + } else { + archive_read_set_passphrase_callback(a, &P_arg, &passphrase_callback); + } + total_size = 0; file_count = 0; error_count = 0; @@ -953,7 +991,7 @@ getopts(int argc, char *argv[]) #else optreset = optind = 1; #endif - while ((opt = getopt(argc, argv, "aCcd:fjLlnopqtuvx:yZ1")) != -1) + while ((opt = getopt(argc, argv, "aCcd:fjLlnopP:qtuvx:yZ1")) != -1) switch (opt) { case '1': Z1_opt = 1; @@ -993,6 +1031,9 @@ getopts(int argc, char *argv[]) case 'p': p_opt = 1; break; + case 'P': + P_arg = optarg; + break; case 'q': q_opt = 1; break; --