Skip to content

Commit

Permalink
unzip: sync with NetBSD upstream to add passphrase support
Browse files Browse the repository at this point in the history
- Add support for password protected zip archives.
  We use memset_s() rather than explicit_bzero() for more portable
  (See PR).
- Use success/failure macro in exit()
- Mention ZIPX format in unzip(1)

Submitted by:	Mingye Wang and Alex Kozlov (ak@)
PR:		244181
Reviewed by:	mizhka
Obtained from:	NetBSD
Differential Revision:	https://reviews.freebsd.org/D28892

(cherry picked from commit a4724ff)
  • Loading branch information
nyan- committed Oct 2, 2021
1 parent e089402 commit cea130c
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 10 deletions.
10 changes: 8 additions & 2 deletions usr.bin/unzip/unzip.1
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd December 12, 2015
.Dd September 25, 2021
.Dt UNZIP 1
.Os
.Sh NAME
Expand All @@ -35,6 +35,8 @@
.Nm
.Op Fl aCcfjLlnopqtuvy
.Op Fl d Ar dir
.Op Fl x Ar pattern
.Op Fl P Ar password
.Ar zipfile
.Sh DESCRIPTION
.\" ...
Expand Down Expand Up @@ -81,6 +83,10 @@ 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 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
Expand Down Expand Up @@ -172,7 +178,7 @@ utility is only able to process ZIP archives handled by
.Xr libarchive 3 .
Depending on the installed version of
.Xr libarchive 3 ,
this may or may not include self-extracting archives.
this may or may not include self-extracting or ZIPX archives.
.Sh SEE ALSO
.Xr libarchive 3
.Sh HISTORY
Expand Down
66 changes: 58 additions & 8 deletions usr.bin/unzip/unzip.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@

#include <archive.h>
#include <archive_entry.h>
#include <readpassphrase.h>

/* command-line options */
static int a_opt; /* convert EOL */
Expand All @@ -63,6 +64,7 @@ static int L_opt; /* lowercase names */
static int n_opt; /* never overwrite */
static int o_opt; /* always overwrite */
static int p_opt; /* extract to stdout, quiet */
static char *P_arg; /* passphrase */
static int q_opt; /* quiet */
static int t_opt; /* test */
static int u_opt; /* update */
Expand Down Expand Up @@ -95,6 +97,9 @@ static int tty;
*/
static int noeol;

/* for an interactive passphrase input */
static char *passphrase_buf;

/* fatal error message + errno */
static void
error(const char *fmt, ...)
Expand All @@ -109,7 +114,7 @@ error(const char *fmt, ...)
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, ": %s\n", strerror(errno));
exit(1);
exit(EXIT_FAILURE);
}

/* fatal error message, no errno */
Expand All @@ -126,7 +131,7 @@ errorx(const char *fmt, ...)
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
exit(1);
exit(EXIT_FAILURE);
}

/* non-fatal error message + errno */
Expand Down Expand Up @@ -854,6 +859,36 @@ test(struct archive *a, struct archive_entry *e)
return error_count;
}

/*
* Callback function for reading 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 *p;

(void)a; /* UNUSED */
(void)_client_data; /* UNUSED */

if (passphrase_buf == NULL) {
passphrase_buf = malloc(PPBUFF_SIZE);
if (passphrase_buf == NULL) {
errno = ENOMEM;
error("malloc()");
}
}

p = readpassphrase("\nEnter password: ", passphrase_buf,
PPBUFF_SIZE, RPP_ECHO_OFF);

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.
Expand All @@ -870,6 +905,13 @@ 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, NULL,
&passphrase_callback);

ac(archive_read_open_filename(a, fn, 8192));

if (!zipinfo_mode) {
Expand Down Expand Up @@ -925,6 +967,11 @@ unzip(const char *fn)

ac(archive_read_free(a));

if (passphrase_buf != NULL) {
memset_s(passphrase_buf, PPBUFF_SIZE, 0, PPBUFF_SIZE);
free(passphrase_buf);
}

if (t_opt) {
if (error_count > 0) {
errorx("%ju checksum error(s) found.", error_count);
Expand All @@ -940,9 +987,9 @@ static void
usage(void)
{

fprintf(stderr, "Usage: unzip [-aCcfjLlnopqtuvyZ1] [-d dir] [-x pattern] "
"zipfile\n");
exit(1);
fprintf(stderr, "Usage: unzip [-aCcfjLlnopqtuvyZ1] [-d dir] "
"[-x pattern] [-P password] zipfile\n");
exit(EXIT_FAILURE);
}

static int
Expand All @@ -951,7 +998,7 @@ getopts(int argc, char *argv[])
int opt;

optreset = optind = 1;
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;
Expand Down Expand Up @@ -991,6 +1038,9 @@ getopts(int argc, char *argv[])
case 'p':
p_opt = 1;
break;
case 'P':
P_arg = optarg;
break;
case 'q':
q_opt = 1;
break;
Expand Down Expand Up @@ -1047,7 +1097,7 @@ main(int argc, char *argv[])
*/
if (zipinfo_mode && !Z1_opt) {
printf("Zipinfo mode needs additional options\n");
exit(1);
exit(EXIT_FAILURE);
}

if (argc <= nopts)
Expand All @@ -1068,5 +1118,5 @@ main(int argc, char *argv[])

unzip(zipfile);

exit(0);
exit(EXIT_SUCCESS);
}

0 comments on commit cea130c

Please sign in to comment.