1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2009, 2010 Joerg Sonnenberger <joerg@NetBSD.org> 5 * Copyright (c) 2007-2008 Dag-Erling Smørgrav 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer 13 * in this position and unchanged. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $FreeBSD$ 31 * 32 * This file would be much shorter if we didn't care about command-line 33 * compatibility with Info-ZIP's UnZip, which requires us to duplicate 34 * parts of libarchive in order to gain more detailed control of its 35 * behaviour for the purpose of implementing the -n, -o, -L and -a 36 * options. 37 */ 38 39 #include "bsdunzip_platform.h" 40 41 #ifdef HAVE_SYS_QUEUE_H 42 #include <sys/queue.h> 43 #else 44 #include "la_queue.h" 45 #endif 46 #ifdef HAVE_SYS_STAT_H 47 #include <sys/stat.h> 48 #endif 49 50 #ifdef HAVE_CTYPE_H 51 #include <ctype.h> 52 #endif 53 #ifdef HAVE_ERRNO_H 54 #include <errno.h> 55 #endif 56 #ifdef HAVE_FCNTL_H 57 #include <fcntl.h> 58 #endif 59 #ifdef HAVE_FNMATCH_H 60 #include <fnmatch.h> 61 #endif 62 #ifdef HAVE_STDARG_H 63 #include <stdarg.h> 64 #endif 65 #include <stdio.h> 66 #ifdef HAVE_STDLIB_H 67 #include <stdlib.h> 68 #endif 69 #ifdef HAVE_STRING_H 70 #include <string.h> 71 #endif 72 #ifdef HAVE_UNISTD_H 73 #include <unistd.h> 74 #endif 75 #if ((!defined(HAVE_UTIMENSAT) && defined(HAVE_LUTIMES)) || \ 76 (!defined(HAVE_FUTIMENS) && defined(HAVE_FUTIMES))) 77 #ifdef HAVE_SYS_TIME_H 78 #include <sys/time.h> 79 #endif 80 #endif 81 82 #include "bsdunzip.h" 83 #include "passphrase.h" 84 #include "err.h" 85 86 /* command-line options */ 87 static int a_opt; /* convert EOL */ 88 static int C_opt; /* match case-insensitively */ 89 static int c_opt; /* extract to stdout */ 90 static const char *d_arg; /* directory */ 91 static int f_opt; /* update existing files only */ 92 static const char *O_arg; /* encoding */ 93 static int j_opt; /* junk directories */ 94 static int L_opt; /* lowercase names */ 95 static int n_opt; /* never overwrite */ 96 static int o_opt; /* always overwrite */ 97 static int p_opt; /* extract to stdout, quiet */ 98 static const char *P_arg; /* passphrase */ 99 static int q_opt; /* quiet */ 100 static int t_opt; /* test */ 101 static int u_opt; /* update */ 102 static int v_opt; /* verbose/list */ 103 static const char *y_str = ""; /* 4 digit year */ 104 static int Z1_opt; /* zipinfo mode list files only */ 105 static int version_opt; /* version string */ 106 107 /* debug flag */ 108 static int unzip_debug; 109 110 /* zipinfo mode */ 111 static int zipinfo_mode; 112 113 /* running on tty? */ 114 static int tty; 115 116 /* processing exclude list */ 117 static int unzip_exclude_mode = 0; 118 119 int bsdunzip_optind; 120 121 /* convenience macro */ 122 /* XXX should differentiate between ARCHIVE_{WARN,FAIL,RETRY} */ 123 #define ac(call) \ 124 do { \ 125 int acret = (call); \ 126 if (acret != ARCHIVE_OK) \ 127 errorx("%s", archive_error_string(a)); \ 128 } while (0) 129 130 /* 131 * Indicates that last info() did not end with EOL. This helps error() et 132 * al. avoid printing an error message on the same line as an incomplete 133 * informational message. 134 */ 135 static int noeol; 136 137 /* for an interactive passphrase input */ 138 static char *passphrase_buf; 139 140 /* fatal error message + errno */ 141 static void 142 error(const char *fmt, ...) 143 { 144 va_list ap; 145 146 if (noeol) 147 fprintf(stdout, "\n"); 148 fflush(stdout); 149 fprintf(stderr, "unzip: "); 150 va_start(ap, fmt); 151 vfprintf(stderr, fmt, ap); 152 va_end(ap); 153 fprintf(stderr, ": %s\n", strerror(errno)); 154 exit(EXIT_FAILURE); 155 } 156 157 /* fatal error message, no errno */ 158 static void 159 errorx(const char *fmt, ...) 160 { 161 va_list ap; 162 163 if (noeol) 164 fprintf(stdout, "\n"); 165 fflush(stdout); 166 fprintf(stderr, "unzip: "); 167 va_start(ap, fmt); 168 vfprintf(stderr, fmt, ap); 169 va_end(ap); 170 fprintf(stderr, "\n"); 171 exit(EXIT_FAILURE); 172 } 173 174 /* non-fatal error message + errno */ 175 static void 176 warning(const char *fmt, ...) 177 { 178 va_list ap; 179 180 if (noeol) 181 fprintf(stdout, "\n"); 182 fflush(stdout); 183 fprintf(stderr, "unzip: "); 184 va_start(ap, fmt); 185 vfprintf(stderr, fmt, ap); 186 va_end(ap); 187 fprintf(stderr, ": %s\n", strerror(errno)); 188 } 189 190 /* non-fatal error message, no errno */ 191 static void 192 warningx(const char *fmt, ...) 193 { 194 va_list ap; 195 196 if (noeol) 197 fprintf(stdout, "\n"); 198 fflush(stdout); 199 fprintf(stderr, "unzip: "); 200 va_start(ap, fmt); 201 vfprintf(stderr, fmt, ap); 202 va_end(ap); 203 fprintf(stderr, "\n"); 204 } 205 206 /* informational message (if not -q) */ 207 static void 208 info(const char *fmt, ...) 209 { 210 va_list ap; 211 212 if (q_opt && !unzip_debug) 213 return; 214 va_start(ap, fmt); 215 vfprintf(stdout, fmt, ap); 216 va_end(ap); 217 fflush(stdout); 218 219 if (*fmt == '\0') 220 noeol = 1; 221 else 222 noeol = fmt[strlen(fmt) - 1] != '\n'; 223 } 224 225 /* debug message (if unzip_debug) */ 226 static void 227 debug(const char *fmt, ...) 228 { 229 va_list ap; 230 231 if (!unzip_debug) 232 return; 233 va_start(ap, fmt); 234 vfprintf(stderr, fmt, ap); 235 va_end(ap); 236 fflush(stderr); 237 238 if (*fmt == '\0') 239 noeol = 1; 240 else 241 noeol = fmt[strlen(fmt) - 1] != '\n'; 242 } 243 244 /* duplicate a path name, possibly converting to lower case */ 245 static char * 246 pathdup(const char *path) 247 { 248 char *str; 249 size_t i, len; 250 251 if (path == NULL || path[0] == '\0') 252 return (NULL); 253 254 len = strlen(path); 255 while (len && path[len - 1] == '/') 256 len--; 257 if ((str = malloc(len + 1)) == NULL) { 258 errno = ENOMEM; 259 error("malloc()"); 260 } 261 if (L_opt) { 262 for (i = 0; i < len; ++i) 263 str[i] = tolower((unsigned char)path[i]); 264 } else { 265 memcpy(str, path, len); 266 } 267 str[len] = '\0'; 268 269 return (str); 270 } 271 272 /* concatenate two path names */ 273 static char * 274 pathcat(const char *prefix, const char *path) 275 { 276 char *str; 277 size_t prelen, len; 278 279 prelen = prefix ? strlen(prefix) + 1 : 0; 280 len = strlen(path) + 1; 281 if ((str = malloc(prelen + len)) == NULL) { 282 errno = ENOMEM; 283 error("malloc()"); 284 } 285 if (prefix) { 286 memcpy(str, prefix, prelen); /* includes zero */ 287 str[prelen - 1] = '/'; /* splat zero */ 288 } 289 memcpy(str + prelen, path, len); /* includes zero */ 290 291 return (str); 292 } 293 294 /* 295 * Pattern lists for include / exclude processing 296 */ 297 struct pattern { 298 STAILQ_ENTRY(pattern) link; 299 char pattern[]; 300 }; 301 302 STAILQ_HEAD(pattern_list, pattern); 303 static struct pattern_list include = STAILQ_HEAD_INITIALIZER(include); 304 static struct pattern_list exclude = STAILQ_HEAD_INITIALIZER(exclude); 305 306 /* 307 * Add an entry to a pattern list 308 */ 309 static void 310 add_pattern(struct pattern_list *list, const char *pattern) 311 { 312 struct pattern *entry; 313 size_t len; 314 315 debug("adding pattern '%s'\n", pattern); 316 len = strlen(pattern); 317 if ((entry = malloc(sizeof *entry + len + 1)) == NULL) { 318 errno = ENOMEM; 319 error("malloc()"); 320 } 321 memcpy(entry->pattern, pattern, len + 1); 322 STAILQ_INSERT_TAIL(list, entry, link); 323 } 324 325 /* 326 * Match a string against a list of patterns 327 */ 328 static int 329 match_pattern(struct pattern_list *list, const char *str) 330 { 331 struct pattern *entry; 332 333 STAILQ_FOREACH(entry, list, link) { 334 #ifdef HAVE_FNMATCH 335 if (fnmatch(entry->pattern, str, C_opt ? FNM_CASEFOLD : 0) == 0) 336 return (1); 337 #else 338 #error "Unsupported platform: fnmatch() is required" 339 #endif 340 } 341 return (0); 342 } 343 344 /* 345 * Verify that a given pathname is in the include list and not in the 346 * exclude list. 347 */ 348 static int 349 accept_pathname(const char *pathname) 350 { 351 352 if (!STAILQ_EMPTY(&include) && !match_pattern(&include, pathname)) 353 return (0); 354 if (!STAILQ_EMPTY(&exclude) && match_pattern(&exclude, pathname)) 355 return (0); 356 return (1); 357 } 358 359 /* 360 * Create the specified directory with the specified mode, taking certain 361 * precautions on they way. 362 */ 363 static void 364 make_dir(const char *path, int mode) 365 { 366 struct stat sb; 367 368 if (lstat(path, &sb) == 0) { 369 if (S_ISDIR(sb.st_mode)) 370 return; 371 /* 372 * Normally, we should either ask the user about removing 373 * the non-directory of the same name as a directory we 374 * wish to create, or respect the -n or -o command-line 375 * options. However, this may lead to a later failure or 376 * even compromise (if this non-directory happens to be a 377 * symlink to somewhere unsafe), so we don't. 378 */ 379 380 /* 381 * Don't check unlink() result; failure will cause mkdir() 382 * to fail later, which we will catch. 383 */ 384 (void)unlink(path); 385 } 386 if (mkdir(path, mode) != 0 && errno != EEXIST) 387 error("mkdir('%s')", path); 388 } 389 390 /* 391 * Ensure that all directories leading up to (but not including) the 392 * specified path exist. 393 * 394 * XXX inefficient + modifies the file in-place 395 */ 396 static void 397 make_parent(char *path) 398 { 399 struct stat sb; 400 char *sep; 401 402 sep = strrchr(path, '/'); 403 if (sep == NULL || sep == path) 404 return; 405 *sep = '\0'; 406 if (lstat(path, &sb) == 0) { 407 if (S_ISDIR(sb.st_mode)) { 408 *sep = '/'; 409 return; 410 } 411 unlink(path); 412 } 413 make_parent(path); 414 mkdir(path, 0755); 415 *sep = '/'; 416 417 #if 0 418 for (sep = path; (sep = strchr(sep, '/')) != NULL; sep++) { 419 /* root in case of absolute d_arg */ 420 if (sep == path) 421 continue; 422 *sep = '\0'; 423 make_dir(path, 0755); 424 *sep = '/'; 425 } 426 #endif 427 } 428 429 /* 430 * Extract a directory. 431 */ 432 static void 433 extract_dir(struct archive *a, struct archive_entry *e, const char *path) 434 { 435 int mode; 436 437 /* 438 * Dropbox likes to create '/' directory entries, just ignore 439 * such junk. 440 */ 441 if (*path == '\0') 442 return; 443 444 mode = archive_entry_mode(e) & 0777; 445 if (mode == 0) 446 mode = 0755; 447 448 /* 449 * Some zipfiles contain directories with weird permissions such 450 * as 0644 or 0444. This can cause strange issues such as being 451 * unable to extract files into the directory we just created, or 452 * the user being unable to remove the directory later without 453 * first manually changing its permissions. Therefore, we whack 454 * the permissions into shape, assuming that the user wants full 455 * access and that anyone who gets read access also gets execute 456 * access. 457 */ 458 mode |= 0700; 459 if (mode & 0040) 460 mode |= 0010; 461 if (mode & 0004) 462 mode |= 0001; 463 464 info(" creating: %s/\n", path); 465 make_dir(path, mode); 466 ac(archive_read_data_skip(a)); 467 } 468 469 static unsigned char buffer[8192]; 470 static char spinner[] = { '|', '/', '-', '\\' }; 471 472 static int 473 handle_existing_file(char **path) 474 { 475 size_t alen; 476 ssize_t len; 477 char buf[4]; 478 479 for (;;) { 480 fprintf(stderr, 481 "replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", 482 *path); 483 if (fgets(buf, sizeof(buf), stdin) == NULL) { 484 clearerr(stdin); 485 printf("NULL\n(EOF or read error, " 486 "treating as \"[N]one\"...)\n"); 487 n_opt = 1; 488 return -1; 489 } 490 switch (*buf) { 491 case 'A': 492 o_opt = 1; 493 /* FALLTHROUGH */ 494 case 'y': 495 case 'Y': 496 (void)unlink(*path); 497 return 1; 498 case 'N': 499 n_opt = 1; 500 /* FALLTHROUGH */ 501 case 'n': 502 return -1; 503 case 'r': 504 case 'R': 505 printf("New name: "); 506 fflush(stdout); 507 free(*path); 508 *path = NULL; 509 alen = 0; 510 len = getline(path, &alen, stdin); 511 if ((*path)[len - 1] == '\n') 512 (*path)[len - 1] = '\0'; 513 return 0; 514 default: 515 break; 516 } 517 } 518 } 519 520 /* 521 * Detect binary files by a combination of character white list and 522 * black list. NUL bytes and other control codes without use in text files 523 * result directly in switching the file to binary mode. Otherwise, at least 524 * one white-listed byte has to be found. 525 * 526 * Black-listed: 0..6, 14..25, 28..31 527 * 0xf3ffc07f = 11110011111111111100000001111111b 528 * White-listed: 9..10, 13, >= 32 529 * 0x00002600 = 00000000000000000010011000000000b 530 * 531 * See the proginfo/txtvsbin.txt in the zip sources for a detailed discussion. 532 */ 533 #define BYTE_IS_BINARY(x) ((x) < 32 && (0xf3ffc07fU & (1U << (x)))) 534 #define BYTE_IS_TEXT(x) ((x) >= 32 || (0x00002600U & (1U << (x)))) 535 536 static int 537 check_binary(const unsigned char *buf, size_t len) 538 { 539 int rv; 540 for (rv = 1; len--; ++buf) { 541 if (BYTE_IS_BINARY(*buf)) 542 return 1; 543 if (BYTE_IS_TEXT(*buf)) 544 rv = 0; 545 } 546 547 return rv; 548 } 549 550 /* 551 * Extract to a file descriptor 552 */ 553 static int 554 extract2fd(struct archive *a, char *pathname, int fd) 555 { 556 int cr, text, warn; 557 ssize_t len; 558 unsigned char *p, *q, *end; 559 560 text = a_opt; 561 warn = 0; 562 cr = 0; 563 564 /* loop over file contents and write to fd */ 565 for (int n = 0; ; n++) { 566 if (fd != STDOUT_FILENO) 567 if (tty && (n % 4) == 0) 568 info(" %c\b\b", spinner[(n / 4) % sizeof spinner]); 569 570 len = archive_read_data(a, buffer, sizeof buffer); 571 572 if (len < 0) 573 ac(len); 574 575 /* left over CR from previous buffer */ 576 if (a_opt && cr) { 577 if (len == 0 || buffer[0] != '\n') 578 if (write(fd, "\r", 1) != 1) 579 error("write('%s')", pathname); 580 cr = 0; 581 } 582 583 /* EOF */ 584 if (len == 0) 585 break; 586 end = buffer + len; 587 588 /* 589 * Detect whether this is a text file. The correct way to 590 * do this is to check the least significant bit of the 591 * "internal file attributes" field of the corresponding 592 * file header in the central directory, but libarchive 593 * does not provide access to this field, so we have to 594 * guess by looking for non-ASCII characters in the 595 * buffer. Hopefully we won't guess wrong. If we do 596 * guess wrong, we print a warning message later. 597 */ 598 if (a_opt && n == 0) { 599 if (check_binary(buffer, len)) 600 text = 0; 601 } 602 603 /* simple case */ 604 if (!a_opt || !text) { 605 if (write(fd, buffer, len) != len) 606 error("write('%s')", pathname); 607 continue; 608 } 609 610 /* hard case: convert \r\n to \n (sigh...) */ 611 for (p = buffer; p < end; p = q + 1) { 612 for (q = p; q < end; q++) { 613 if (!warn && BYTE_IS_BINARY(*q)) { 614 warningx("%s may be corrupted due" 615 " to weak text file detection" 616 " heuristic", pathname); 617 warn = 1; 618 } 619 if (q[0] != '\r') 620 continue; 621 if (&q[1] == end) { 622 cr = 1; 623 break; 624 } 625 if (q[1] == '\n') 626 break; 627 } 628 if (write(fd, p, q - p) != q - p) 629 error("write('%s')", pathname); 630 } 631 } 632 633 return text; 634 } 635 636 /* 637 * Extract a regular file. 638 */ 639 static void 640 extract_file(struct archive *a, struct archive_entry *e, char **path) 641 { 642 int mode; 643 struct timespec mtime; 644 struct stat sb; 645 int fd, check, text; 646 const char *linkname; 647 #if defined(HAVE_UTIMENSAT) || defined(HAVE_FUTIMENS) 648 struct timespec ts[2]; 649 #endif 650 #if ((!defined(HAVE_UTIMENSAT) && defined(HAVE_LUTIMES)) || \ 651 (!defined(HAVE_FUTIMENS) && defined(HAVE_FUTIMES))) 652 struct timeval times[2]; 653 #endif 654 655 mode = archive_entry_mode(e) & 0777; 656 if (mode == 0) 657 mode = 0644; 658 mtime.tv_sec = archive_entry_mtime(e); 659 mtime.tv_nsec = archive_entry_mtime_nsec(e); 660 661 /* look for existing file of same name */ 662 recheck: 663 if (lstat(*path, &sb) == 0) { 664 if (u_opt || f_opt) { 665 /* check if up-to-date */ 666 if (S_ISREG(sb.st_mode) && ( 667 #if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 668 sb.st_mtimespec.tv_sec > mtime.tv_sec || 669 (sb.st_mtimespec.tv_sec == mtime.tv_sec && 670 sb.st_mtimespec.tv_nsec >= mtime.tv_nsec) 671 #elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 672 sb.st_mtim.tv_sec > mtime.tv_sec || 673 (sb.st_mtim.tv_sec == mtime.tv_sec && 674 sb.st_mtim.tv_nsec >= mtime.tv_nsec) 675 #elif HAVE_STRUCT_STAT_ST_MTIME_N 676 sb.st_mtime > mtime.tv_sec || 677 (sb.st_mtime == mtime.tv_sec && 678 sb.st_mtime_n => mtime.tv_nsec) 679 #elif HAVE_STRUCT_STAT_ST_MTIME_USEC 680 sb.st_mtime > mtime.tv_sec || 681 (sb.st_mtime == mtime.tv_sec && 682 sb.st_mtime_usec => mtime.tv_nsec / 1000) 683 #else 684 sb.st_mtime > mtime.tv_sec 685 #endif 686 )) 687 return; 688 (void)unlink(*path); 689 } else if (o_opt) { 690 /* overwrite */ 691 (void)unlink(*path); 692 } else if (n_opt) { 693 /* do not overwrite */ 694 return; 695 } else { 696 check = handle_existing_file(path); 697 if (check == 0) 698 goto recheck; 699 if (check == -1) 700 return; /* do not overwrite */ 701 } 702 } else { 703 if (f_opt) 704 return; 705 } 706 707 #if defined(HAVE_UTIMENSAT) || defined(HAVE_FUTIMENS) 708 ts[0].tv_sec = 0; 709 ts[0].tv_nsec = UTIME_NOW; 710 ts[1] = mtime; 711 #endif 712 #if ((!defined(HAVE_UTIMENSAT) && defined(HAVE_LUTIMES)) || \ 713 (!defined(HAVE_FUTIMENS) && defined(HAVE_FUTIMES))) 714 times[0].tv_sec = 0; 715 times[0].tv_usec = -1; 716 times[1].tv_sec = mtime.tv_sec; 717 times[1].tv_usec = mtime.tv_nsec / 1000; 718 #endif 719 720 /* process symlinks */ 721 linkname = archive_entry_symlink(e); 722 if (linkname != NULL) { 723 if (symlink(linkname, *path) != 0) 724 error("symlink('%s')", *path); 725 info(" extracting: %s -> %s\n", *path, linkname); 726 #ifdef HAVE_LCHMOD 727 if (lchmod(*path, mode) != 0) 728 warning("Cannot set mode for '%s'", *path); 729 #endif 730 /* set access and modification time */ 731 #if defined(HAVE_UTIMENSAT) 732 if (utimensat(AT_FDCWD, *path, ts, AT_SYMLINK_NOFOLLOW) != 0) 733 warning("utimensat('%s')", *path); 734 #elif defined(HAVE_LUTIMES) 735 gettimeofday(×[0], NULL); 736 if (lutimes(*path, times) != 0) 737 warning("lutimes('%s')", *path); 738 #endif 739 return; 740 } 741 742 if ((fd = open(*path, O_RDWR|O_CREAT|O_TRUNC, mode)) < 0) 743 error("open('%s')", *path); 744 745 info(" extracting: %s", *path); 746 747 text = extract2fd(a, *path, fd); 748 749 if (tty) 750 info(" \b\b"); 751 if (text) 752 info(" (text)"); 753 info("\n"); 754 755 /* set access and modification time */ 756 #if defined(HAVE_FUTIMENS) 757 if (futimens(fd, ts) != 0) 758 error("futimens('%s')", *path); 759 #elif defined(HAVE_FUTIMES) 760 gettimeofday(×[0], NULL); 761 if (futimes(fd, times) != 0) 762 error("futimes('%s')", *path); 763 #endif 764 if (close(fd) != 0) 765 error("close('%s')", *path); 766 } 767 768 /* 769 * Extract a zipfile entry: first perform some sanity checks to ensure 770 * that it is either a directory or a regular file and that the path is 771 * not absolute and does not try to break out of the current directory; 772 * then call either extract_dir() or extract_file() as appropriate. 773 * 774 * This is complicated a bit by the various ways in which we need to 775 * manipulate the path name. Case conversion (if requested by the -L 776 * option) happens first, but the include / exclude patterns are applied 777 * to the full converted path name, before the directory part of the path 778 * is removed in accordance with the -j option. Sanity checks are 779 * intentionally done earlier than they need to be, so the user will get a 780 * warning about insecure paths even for files or directories which 781 * wouldn't be extracted anyway. 782 */ 783 static void 784 extract(struct archive *a, struct archive_entry *e) 785 { 786 char *pathname, *realpathname; 787 mode_t filetype; 788 char *p, *q; 789 790 if ((pathname = pathdup(archive_entry_pathname(e))) == NULL) { 791 warningx("skipping empty or unreadable filename entry"); 792 ac(archive_read_data_skip(a)); 793 return; 794 } 795 filetype = archive_entry_filetype(e); 796 797 /* sanity checks */ 798 if (pathname[0] == '/' || 799 strncmp(pathname, "../", 3) == 0 || 800 strstr(pathname, "/../") != NULL) { 801 warningx("skipping insecure entry '%s'", pathname); 802 ac(archive_read_data_skip(a)); 803 free(pathname); 804 return; 805 } 806 807 /* I don't think this can happen in a zipfile.. */ 808 if (!S_ISDIR(filetype) && !S_ISREG(filetype) && !S_ISLNK(filetype)) { 809 warningx("skipping non-regular entry '%s'", pathname); 810 ac(archive_read_data_skip(a)); 811 free(pathname); 812 return; 813 } 814 815 /* skip directories in -j case */ 816 if (S_ISDIR(filetype) && j_opt) { 817 ac(archive_read_data_skip(a)); 818 free(pathname); 819 return; 820 } 821 822 /* apply include / exclude patterns */ 823 if (!accept_pathname(pathname)) { 824 ac(archive_read_data_skip(a)); 825 free(pathname); 826 return; 827 } 828 829 /* apply -j and -d */ 830 if (j_opt) { 831 for (p = q = pathname; *p; ++p) 832 if (*p == '/') 833 q = p + 1; 834 realpathname = pathcat(d_arg, q); 835 } else { 836 realpathname = pathcat(d_arg, pathname); 837 } 838 839 /* ensure that parent directory exists */ 840 make_parent(realpathname); 841 842 if (S_ISDIR(filetype)) 843 extract_dir(a, e, realpathname); 844 else 845 extract_file(a, e, &realpathname); 846 847 free(realpathname); 848 free(pathname); 849 } 850 851 static void 852 extract_stdout(struct archive *a, struct archive_entry *e) 853 { 854 char *pathname; 855 mode_t filetype; 856 857 if ((pathname = pathdup(archive_entry_pathname(e))) == NULL) { 858 warningx("skipping empty or unreadable filename entry"); 859 ac(archive_read_data_skip(a)); 860 return; 861 } 862 filetype = archive_entry_filetype(e); 863 864 /* I don't think this can happen in a zipfile.. */ 865 if (!S_ISDIR(filetype) && !S_ISREG(filetype) && !S_ISLNK(filetype)) { 866 warningx("skipping non-regular entry '%s'", pathname); 867 ac(archive_read_data_skip(a)); 868 free(pathname); 869 return; 870 } 871 872 /* skip directories in -j case */ 873 if (S_ISDIR(filetype)) { 874 ac(archive_read_data_skip(a)); 875 free(pathname); 876 return; 877 } 878 879 /* apply include / exclude patterns */ 880 if (!accept_pathname(pathname)) { 881 ac(archive_read_data_skip(a)); 882 free(pathname); 883 return; 884 } 885 886 if (c_opt) 887 info("x %s\n", pathname); 888 889 (void)extract2fd(a, pathname, STDOUT_FILENO); 890 891 free(pathname); 892 } 893 894 /* 895 * Print the name of an entry to stdout. 896 */ 897 static void 898 list(struct archive *a, struct archive_entry *e) 899 { 900 char buf[20]; 901 time_t mtime; 902 struct tm *tm; 903 904 mtime = archive_entry_mtime(e); 905 tm = localtime(&mtime); 906 if (*y_str) 907 strftime(buf, sizeof(buf), "%m-%d-%G %R", tm); 908 else 909 strftime(buf, sizeof(buf), "%m-%d-%g %R", tm); 910 911 if (!zipinfo_mode) { 912 if (v_opt == 1) { 913 printf(" %8ju %s %s\n", 914 (uintmax_t)archive_entry_size(e), 915 buf, archive_entry_pathname(e)); 916 } else if (v_opt == 2) { 917 printf("%8ju Stored %7ju 0%% %s %08x %s\n", 918 (uintmax_t)archive_entry_size(e), 919 (uintmax_t)archive_entry_size(e), 920 buf, 921 0U, 922 archive_entry_pathname(e)); 923 } 924 } else { 925 if (Z1_opt) 926 printf("%s\n",archive_entry_pathname(e)); 927 } 928 ac(archive_read_data_skip(a)); 929 } 930 931 /* 932 * Extract to memory to check CRC 933 */ 934 static int 935 test(struct archive *a, struct archive_entry *e) 936 { 937 ssize_t len; 938 int error_count; 939 940 error_count = 0; 941 if (S_ISDIR(archive_entry_filetype(e))) 942 return 0; 943 944 info(" testing: %s\t", archive_entry_pathname(e)); 945 while ((len = archive_read_data(a, buffer, sizeof buffer)) > 0) 946 /* nothing */; 947 if (len < 0) { 948 info(" %s\n", archive_error_string(a)); 949 ++error_count; 950 } else { 951 info(" OK\n"); 952 } 953 954 /* shouldn't be necessary, but it doesn't hurt */ 955 ac(archive_read_data_skip(a)); 956 957 return error_count; 958 } 959 960 /* 961 * Callback function for reading passphrase. 962 * Originally from cpio.c and passphrase.c, libarchive. 963 */ 964 #define PPBUFF_SIZE 1024 965 static const char * 966 passphrase_callback(struct archive *a, void *_client_data) 967 { 968 char *p; 969 970 (void)a; /* UNUSED */ 971 (void)_client_data; /* UNUSED */ 972 973 if (passphrase_buf == NULL) { 974 passphrase_buf = malloc(PPBUFF_SIZE); 975 if (passphrase_buf == NULL) { 976 errno = ENOMEM; 977 error("malloc()"); 978 } 979 } 980 981 p = lafe_readpassphrase("\nEnter password: ", passphrase_buf, 982 PPBUFF_SIZE); 983 984 if (p == NULL && errno != EINTR) 985 error("Error reading password"); 986 987 return p; 988 } 989 990 /* 991 * Main loop: open the zipfile, iterate over its contents and decide what 992 * to do with each entry. 993 */ 994 static void 995 unzip(const char *fn) 996 { 997 struct archive *a; 998 struct archive_entry *e; 999 int ret; 1000 uintmax_t total_size, file_count, error_count; 1001 1002 if ((a = archive_read_new()) == NULL) 1003 error("archive_read_new failed"); 1004 1005 ac(archive_read_support_format_zip(a)); 1006 1007 if (O_arg) 1008 ac(archive_read_set_format_option(a, "zip", "hdrcharset", O_arg)); 1009 1010 if (P_arg) 1011 archive_read_add_passphrase(a, P_arg); 1012 else 1013 archive_read_set_passphrase_callback(a, NULL, 1014 &passphrase_callback); 1015 1016 ac(archive_read_open_filename(a, fn, 8192)); 1017 1018 if (!zipinfo_mode) { 1019 if (!p_opt && !q_opt) 1020 printf("Archive: %s\n", fn); 1021 if (v_opt == 1) { 1022 printf(" Length %sDate Time Name\n", y_str); 1023 printf(" -------- %s---- ---- ----\n", y_str); 1024 } else if (v_opt == 2) { 1025 printf(" Length Method Size Ratio %sDate Time CRC-32 Name\n", y_str); 1026 printf("-------- ------ ------- ----- %s---- ---- ------ ----\n", y_str); 1027 } 1028 } 1029 1030 total_size = 0; 1031 file_count = 0; 1032 error_count = 0; 1033 for (;;) { 1034 ret = archive_read_next_header(a, &e); 1035 if (ret == ARCHIVE_EOF) 1036 break; 1037 ac(ret); 1038 if (!zipinfo_mode) { 1039 if (t_opt) 1040 error_count += test(a, e); 1041 else if (v_opt) 1042 list(a, e); 1043 else if (p_opt || c_opt) 1044 extract_stdout(a, e); 1045 else 1046 extract(a, e); 1047 } else { 1048 if (Z1_opt) 1049 list(a, e); 1050 } 1051 1052 total_size += archive_entry_size(e); 1053 ++file_count; 1054 } 1055 1056 if (zipinfo_mode) { 1057 if (v_opt == 1) { 1058 printf(" -------- %s-------\n", y_str); 1059 printf(" %8ju %s%ju file%s\n", 1060 total_size, y_str, file_count, file_count != 1 ? "s" : ""); 1061 } else if (v_opt == 2) { 1062 printf("-------- ------- --- %s-------\n", y_str); 1063 printf("%8ju %7ju 0%% %s%ju file%s\n", 1064 total_size, total_size, y_str, file_count, 1065 file_count != 1 ? "s" : ""); 1066 } 1067 } 1068 1069 ac(archive_read_free(a)); 1070 1071 if (passphrase_buf != NULL) { 1072 memset(passphrase_buf, 0, PPBUFF_SIZE); 1073 free(passphrase_buf); 1074 } 1075 1076 if (t_opt) { 1077 if (error_count > 0) { 1078 errorx("%ju checksum error(s) found.", error_count); 1079 } 1080 else { 1081 printf("No errors detected in compressed data of %s.\n", 1082 fn); 1083 } 1084 } 1085 } 1086 1087 static void 1088 usage(void) 1089 { 1090 1091 fprintf(stderr, 1092 "Usage: unzip [-aCcfjLlnopqtuvyZ1] [{-O|-I} encoding] [-d dir] [-x pattern] [-P password] zipfile\n" 1093 " [member ...]\n"); 1094 exit(EXIT_FAILURE); 1095 } 1096 1097 static void 1098 version(void) 1099 { 1100 printf("bsdunzip %s - %s \n", 1101 BSDUNZIP_VERSION_STRING, 1102 archive_version_details()); 1103 exit(0); 1104 } 1105 1106 static int 1107 getopts(int argc, char *argv[]) 1108 { 1109 struct bsdunzip *bsdunzip, bsdunzip_storage; 1110 int opt; 1111 bsdunzip_optind = 1; 1112 1113 bsdunzip = &bsdunzip_storage; 1114 memset(bsdunzip, 0, sizeof(*bsdunzip)); 1115 1116 bsdunzip->argv = argv; 1117 bsdunzip->argc = argc; 1118 1119 while ((opt = bsdunzip_getopt(bsdunzip)) != -1) { 1120 unzip_exclude_mode = 0; 1121 switch (opt) { 1122 case 'a': 1123 a_opt = 1; 1124 break; 1125 case 'C': 1126 C_opt = 1; 1127 break; 1128 case 'c': 1129 c_opt = 1; 1130 break; 1131 case 'd': 1132 d_arg = bsdunzip->argument; 1133 break; 1134 case 'f': 1135 f_opt = 1; 1136 break; 1137 case 'I': 1138 case 'O': 1139 O_arg = bsdunzip->argument; 1140 break; 1141 case 'j': 1142 j_opt = 1; 1143 break; 1144 case 'L': 1145 L_opt = 1; 1146 break; 1147 case 'l': 1148 if (v_opt == 0) 1149 v_opt = 1; 1150 break; 1151 case 'n': 1152 n_opt = 1; 1153 break; 1154 case 'o': 1155 o_opt = 1; 1156 q_opt = 1; 1157 break; 1158 case 'p': 1159 p_opt = 1; 1160 break; 1161 case 'P': 1162 P_arg = bsdunzip->argument; 1163 break; 1164 case 'q': 1165 q_opt = 1; 1166 break; 1167 case 't': 1168 t_opt = 1; 1169 break; 1170 case 'u': 1171 u_opt = 1; 1172 break; 1173 case 'v': 1174 v_opt = 2; 1175 break; 1176 case 'x': 1177 add_pattern(&exclude, bsdunzip->argument); 1178 unzip_exclude_mode = 1; 1179 break; 1180 case 'y': 1181 y_str = " "; 1182 break; 1183 case 'Z': 1184 zipinfo_mode = 1; 1185 if (bsdunzip->argument != NULL && 1186 strcmp(bsdunzip->argument, "1") == 0) { 1187 Z1_opt = 1; 1188 } 1189 break; 1190 case OPTION_VERSION: 1191 version_opt = 1; 1192 break; 1193 case OPTION_NONE: 1194 break; 1195 default: 1196 usage(); 1197 } 1198 if (opt == OPTION_NONE) 1199 break; 1200 } 1201 return (bsdunzip_optind); 1202 } 1203 1204 int 1205 main(int argc, char *argv[]) 1206 { 1207 const char *zipfile; 1208 int nopts; 1209 1210 lafe_setprogname(*argv, "bsdunzip"); 1211 1212 if (isatty(STDOUT_FILENO)) 1213 tty = 1; 1214 1215 if (getenv("UNZIP_DEBUG") != NULL) 1216 unzip_debug = 1; 1217 for (int i = 0; i < argc; ++i) 1218 debug("%s%c", argv[i], (i < argc - 1) ? ' ' : '\n'); 1219 1220 #ifdef __GLIBC__ 1221 /* Prevent GNU getopt(3) from rearranging options. */ 1222 setenv("POSIXLY_CORRECT", "", 1); 1223 #endif 1224 /* 1225 * Info-ZIP's unzip(1) expects certain options to come before the 1226 * zipfile name, and others to come after - though it does not 1227 * enforce this. For simplicity, we accept *all* options both 1228 * before and after the zipfile name. 1229 */ 1230 nopts = getopts(argc, argv); 1231 1232 if (version_opt == 1) { 1233 version(); 1234 exit(EXIT_SUCCESS); 1235 } 1236 1237 /* 1238 * When more of the zipinfo mode options are implemented, this 1239 * will need to change. 1240 */ 1241 if (zipinfo_mode && !Z1_opt) { 1242 printf("Zipinfo mode needs additional options\n"); 1243 exit(EXIT_FAILURE); 1244 } 1245 1246 if (argc <= nopts) 1247 usage(); 1248 zipfile = argv[nopts++]; 1249 1250 if (strcmp(zipfile, "-") == 0) 1251 zipfile = NULL; /* STDIN */ 1252 1253 unzip_exclude_mode = 0; 1254 1255 while (nopts < argc && *argv[nopts] != '-') 1256 add_pattern(&include, argv[nopts++]); 1257 1258 nopts--; /* fake argv[0] */ 1259 nopts += getopts(argc - nopts, argv + nopts); 1260 1261 /* 1262 * For compatibility with Info-ZIP's unzip(1) we need to treat 1263 * non-option arguments following an -x after the zipfile as 1264 * exclude list members. 1265 */ 1266 if (unzip_exclude_mode) { 1267 while (nopts < argc && *argv[nopts] != '-') 1268 add_pattern(&exclude, argv[nopts++]); 1269 nopts--; /* fake argv[0] */ 1270 nopts += getopts(argc - nopts, argv + nopts); 1271 } 1272 1273 /* There may be residual arguments if we encountered -- */ 1274 while (nopts < argc) 1275 add_pattern(&include, argv[nopts++]); 1276 1277 if (n_opt + o_opt + u_opt > 1) 1278 errorx("-n, -o and -u are contradictory"); 1279 1280 unzip(zipfile); 1281 1282 exit(EXIT_SUCCESS); 1283 } 1284