1 /*- 2 * Copyright (c) 2009-2012,2014 Michihiro NAKAJIMA 3 * Copyright (c) 2003-2007 Tim Kientzle 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "archive_platform.h" 28 29 #ifdef HAVE_SYS_TYPES_H 30 #include <sys/types.h> 31 #endif 32 #ifdef HAVE_ERRNO_H 33 #include <errno.h> 34 #endif 35 #ifdef HAVE_FCNTL_H 36 #include <fcntl.h> 37 #endif 38 #ifdef HAVE_STDLIB_H 39 #include <stdlib.h> 40 #endif 41 #ifdef HAVE_STRING_H 42 #include <string.h> 43 #endif 44 #if defined(_WIN32) && !defined(__CYGWIN__) 45 #if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA 46 /* don't use bcrypt when XP needs to be supported */ 47 #include <bcrypt.h> 48 49 /* Common in other bcrypt implementations, but missing from VS2008. */ 50 #ifndef BCRYPT_SUCCESS 51 #define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS) 52 #endif 53 54 #elif defined(HAVE_WINCRYPT_H) 55 #include <wincrypt.h> 56 #endif 57 #endif 58 #ifdef HAVE_ZLIB_H 59 #include <zlib.h> 60 #endif 61 #ifdef HAVE_LZMA_H 62 #include <lzma.h> 63 #endif 64 #ifdef HAVE_BZLIB_H 65 #include <bzlib.h> 66 #endif 67 #ifdef HAVE_LZ4_H 68 #include <lz4.h> 69 #endif 70 71 #include "archive.h" 72 #include "archive_private.h" 73 #include "archive_random_private.h" 74 #include "archive_string.h" 75 76 #ifndef O_CLOEXEC 77 #define O_CLOEXEC 0 78 #endif 79 80 static int archive_utility_string_sort_helper(char **, unsigned int); 81 82 /* Generic initialization of 'struct archive' objects. */ 83 int 84 __archive_clean(struct archive *a) 85 { 86 archive_string_conversion_free(a); 87 return (ARCHIVE_OK); 88 } 89 90 int 91 archive_version_number(void) 92 { 93 return (ARCHIVE_VERSION_NUMBER); 94 } 95 96 const char * 97 archive_version_string(void) 98 { 99 return (ARCHIVE_VERSION_STRING); 100 } 101 102 int 103 archive_errno(struct archive *a) 104 { 105 return (a->archive_error_number); 106 } 107 108 const char * 109 archive_error_string(struct archive *a) 110 { 111 112 if (a->error != NULL && *a->error != '\0') 113 return (a->error); 114 else 115 return (NULL); 116 } 117 118 int 119 archive_file_count(struct archive *a) 120 { 121 return (a->file_count); 122 } 123 124 int 125 archive_format(struct archive *a) 126 { 127 return (a->archive_format); 128 } 129 130 const char * 131 archive_format_name(struct archive *a) 132 { 133 return (a->archive_format_name); 134 } 135 136 137 int 138 archive_compression(struct archive *a) 139 { 140 return archive_filter_code(a, 0); 141 } 142 143 const char * 144 archive_compression_name(struct archive *a) 145 { 146 return archive_filter_name(a, 0); 147 } 148 149 150 /* 151 * Return a count of the number of compressed bytes processed. 152 */ 153 la_int64_t 154 archive_position_compressed(struct archive *a) 155 { 156 return archive_filter_bytes(a, -1); 157 } 158 159 /* 160 * Return a count of the number of uncompressed bytes processed. 161 */ 162 la_int64_t 163 archive_position_uncompressed(struct archive *a) 164 { 165 return archive_filter_bytes(a, 0); 166 } 167 168 void 169 archive_clear_error(struct archive *a) 170 { 171 archive_string_empty(&a->error_string); 172 a->error = NULL; 173 a->archive_error_number = 0; 174 } 175 176 void 177 archive_set_error(struct archive *a, int error_number, const char *fmt, ...) 178 { 179 va_list ap; 180 181 a->archive_error_number = error_number; 182 if (fmt == NULL) { 183 a->error = NULL; 184 return; 185 } 186 187 archive_string_empty(&(a->error_string)); 188 va_start(ap, fmt); 189 archive_string_vsprintf(&(a->error_string), fmt, ap); 190 va_end(ap); 191 a->error = a->error_string.s; 192 } 193 194 void 195 archive_copy_error(struct archive *dest, struct archive *src) 196 { 197 dest->archive_error_number = src->archive_error_number; 198 199 archive_string_copy(&dest->error_string, &src->error_string); 200 dest->error = dest->error_string.s; 201 } 202 203 void 204 __archive_errx(int retvalue, const char *msg) 205 { 206 static const char msg1[] = "Fatal Internal Error in libarchive: "; 207 size_t s; 208 209 s = write(2, msg1, strlen(msg1)); 210 (void)s; /* UNUSED */ 211 s = write(2, msg, strlen(msg)); 212 (void)s; /* UNUSED */ 213 s = write(2, "\n", 1); 214 (void)s; /* UNUSED */ 215 exit(retvalue); 216 } 217 218 /* 219 * Create a temporary file 220 */ 221 #if defined(_WIN32) && !defined(__CYGWIN__) 222 223 /* 224 * Do not use Windows tmpfile() function. 225 * It will make a temporary file under the root directory 226 * and it'll cause permission error if a user who is 227 * non-Administrator creates temporary files. 228 * Also Windows version of mktemp family including _mktemp_s 229 * are not secure. 230 */ 231 static int 232 __archive_mktempx(const char *tmpdir, wchar_t *template) 233 { 234 static const wchar_t prefix[] = L"libarchive_"; 235 static const wchar_t suffix[] = L"XXXXXXXXXX"; 236 static const wchar_t num[] = { 237 L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', 238 L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F', 239 L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N', 240 L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V', 241 L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd', 242 L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l', 243 L'm', L'n', L'o', L'p', L'q', L'r', L's', L't', 244 L'u', L'v', L'w', L'x', L'y', L'z' 245 }; 246 struct archive_wstring temp_name; 247 wchar_t *ws; 248 DWORD attr; 249 wchar_t *xp, *ep; 250 int fd; 251 #if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA 252 BCRYPT_ALG_HANDLE hAlg = NULL; 253 #else 254 HCRYPTPROV hProv = (HCRYPTPROV)NULL; 255 #endif 256 fd = -1; 257 ws = NULL; 258 259 if (template == NULL) { 260 archive_string_init(&temp_name); 261 262 /* Get a temporary directory. */ 263 if (tmpdir == NULL) { 264 size_t l; 265 wchar_t *tmp; 266 267 l = GetTempPathW(0, NULL); 268 if (l == 0) { 269 la_dosmaperr(GetLastError()); 270 goto exit_tmpfile; 271 } 272 tmp = malloc(l*sizeof(wchar_t)); 273 if (tmp == NULL) { 274 errno = ENOMEM; 275 goto exit_tmpfile; 276 } 277 GetTempPathW((DWORD)l, tmp); 278 archive_wstrcpy(&temp_name, tmp); 279 free(tmp); 280 } else { 281 if (archive_wstring_append_from_mbs(&temp_name, tmpdir, 282 strlen(tmpdir)) < 0) 283 goto exit_tmpfile; 284 if (temp_name.s[temp_name.length-1] != L'/') 285 archive_wstrappend_wchar(&temp_name, L'/'); 286 } 287 288 /* Check if temp_name is a directory. */ 289 attr = GetFileAttributesW(temp_name.s); 290 if (attr == (DWORD)-1) { 291 if (GetLastError() != ERROR_FILE_NOT_FOUND) { 292 la_dosmaperr(GetLastError()); 293 goto exit_tmpfile; 294 } 295 ws = __la_win_permissive_name_w(temp_name.s); 296 if (ws == NULL) { 297 errno = EINVAL; 298 goto exit_tmpfile; 299 } 300 attr = GetFileAttributesW(ws); 301 if (attr == (DWORD)-1) { 302 la_dosmaperr(GetLastError()); 303 goto exit_tmpfile; 304 } 305 } 306 if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { 307 errno = ENOTDIR; 308 goto exit_tmpfile; 309 } 310 311 /* 312 * Create a temporary file. 313 */ 314 archive_wstrcat(&temp_name, prefix); 315 archive_wstrcat(&temp_name, suffix); 316 ep = temp_name.s + archive_strlen(&temp_name); 317 xp = ep - wcslen(suffix); 318 template = temp_name.s; 319 } else { 320 xp = wcschr(template, L'X'); 321 if (xp == NULL) /* No X, programming error */ 322 abort(); 323 for (ep = xp; *ep == L'X'; ep++) 324 continue; 325 if (*ep) /* X followed by non X, programming error */ 326 abort(); 327 } 328 329 #if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA 330 if (!BCRYPT_SUCCESS(BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM, 331 NULL, 0))) { 332 la_dosmaperr(GetLastError()); 333 goto exit_tmpfile; 334 } 335 #else 336 if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 337 CRYPT_VERIFYCONTEXT)) { 338 la_dosmaperr(GetLastError()); 339 goto exit_tmpfile; 340 } 341 #endif 342 343 for (;;) { 344 wchar_t *p; 345 HANDLE h; 346 # if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ 347 CREATEFILE2_EXTENDED_PARAMETERS createExParams; 348 #endif 349 350 /* Generate a random file name through CryptGenRandom(). */ 351 p = xp; 352 #if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA 353 if (!BCRYPT_SUCCESS(BCryptGenRandom(hAlg, (PUCHAR)p, 354 (DWORD)(ep - p)*sizeof(wchar_t), 0))) { 355 la_dosmaperr(GetLastError()); 356 goto exit_tmpfile; 357 } 358 #else 359 if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t), 360 (BYTE*)p)) { 361 la_dosmaperr(GetLastError()); 362 goto exit_tmpfile; 363 } 364 #endif 365 for (; p < ep; p++) 366 *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))]; 367 368 free(ws); 369 ws = __la_win_permissive_name_w(template); 370 if (ws == NULL) { 371 errno = EINVAL; 372 goto exit_tmpfile; 373 } 374 if (template == temp_name.s) { 375 attr = FILE_ATTRIBUTE_TEMPORARY | 376 FILE_FLAG_DELETE_ON_CLOSE; 377 } else { 378 /* mkstemp */ 379 attr = FILE_ATTRIBUTE_NORMAL; 380 } 381 # if _WIN32_WINNT >= 0x0602 /* _WIN32_WINNT_WIN8 */ 382 ZeroMemory(&createExParams, sizeof(createExParams)); 383 createExParams.dwSize = sizeof(createExParams); 384 createExParams.dwFileAttributes = attr & 0xFFFF; 385 createExParams.dwFileFlags = attr & 0xFFF00000; 386 h = CreateFile2(ws, 387 GENERIC_READ | GENERIC_WRITE | DELETE, 388 0,/* Not share */ 389 CREATE_NEW, 390 &createExParams); 391 #else 392 h = CreateFileW(ws, 393 GENERIC_READ | GENERIC_WRITE | DELETE, 394 0,/* Not share */ 395 NULL, 396 CREATE_NEW,/* Create a new file only */ 397 attr, 398 NULL); 399 #endif 400 if (h == INVALID_HANDLE_VALUE) { 401 /* The same file already exists. retry with 402 * a new filename. */ 403 if (GetLastError() == ERROR_FILE_EXISTS) 404 continue; 405 /* Otherwise, fail creation temporary file. */ 406 la_dosmaperr(GetLastError()); 407 goto exit_tmpfile; 408 } 409 fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR); 410 if (fd == -1) { 411 la_dosmaperr(GetLastError()); 412 CloseHandle(h); 413 goto exit_tmpfile; 414 } else 415 break;/* success! */ 416 } 417 exit_tmpfile: 418 #if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA 419 if (hAlg != NULL) 420 BCryptCloseAlgorithmProvider(hAlg, 0); 421 #else 422 if (hProv != (HCRYPTPROV)NULL) 423 CryptReleaseContext(hProv, 0); 424 #endif 425 free(ws); 426 if (template == temp_name.s) 427 archive_wstring_free(&temp_name); 428 return (fd); 429 } 430 431 int 432 __archive_mktemp(const char *tmpdir) 433 { 434 return __archive_mktempx(tmpdir, NULL); 435 } 436 437 int 438 __archive_mkstemp(wchar_t *template) 439 { 440 return __archive_mktempx(NULL, template); 441 } 442 443 #else 444 445 static int 446 get_tempdir(struct archive_string *temppath) 447 { 448 const char *tmp; 449 450 tmp = getenv("TMPDIR"); 451 if (tmp == NULL) 452 #ifdef _PATH_TMP 453 tmp = _PATH_TMP; 454 #else 455 tmp = "/tmp"; 456 #endif 457 archive_strcpy(temppath, tmp); 458 if (temppath->s[temppath->length-1] != '/') 459 archive_strappend_char(temppath, '/'); 460 return (ARCHIVE_OK); 461 } 462 463 #if defined(HAVE_MKSTEMP) 464 465 /* 466 * We can use mkstemp(). 467 */ 468 469 int 470 __archive_mktemp(const char *tmpdir) 471 { 472 struct archive_string temp_name; 473 int fd = -1; 474 475 archive_string_init(&temp_name); 476 if (tmpdir == NULL) { 477 if (get_tempdir(&temp_name) != ARCHIVE_OK) 478 goto exit_tmpfile; 479 } else { 480 archive_strcpy(&temp_name, tmpdir); 481 if (temp_name.s[temp_name.length-1] != '/') 482 archive_strappend_char(&temp_name, '/'); 483 } 484 #ifdef O_TMPFILE 485 fd = open(temp_name.s, O_RDWR|O_CLOEXEC|O_TMPFILE|O_EXCL, 0600); 486 if(fd >= 0) 487 goto exit_tmpfile; 488 #endif 489 archive_strcat(&temp_name, "libarchive_XXXXXX"); 490 fd = mkstemp(temp_name.s); 491 if (fd < 0) 492 goto exit_tmpfile; 493 __archive_ensure_cloexec_flag(fd); 494 unlink(temp_name.s); 495 exit_tmpfile: 496 archive_string_free(&temp_name); 497 return (fd); 498 } 499 500 int 501 __archive_mkstemp(char *template) 502 { 503 int fd = -1; 504 fd = mkstemp(template); 505 if (fd >= 0) 506 __archive_ensure_cloexec_flag(fd); 507 return (fd); 508 } 509 510 #else /* !HAVE_MKSTEMP */ 511 512 /* 513 * We use a private routine. 514 */ 515 516 static int 517 __archive_mktempx(const char *tmpdir, char *template) 518 { 519 static const char num[] = { 520 '0', '1', '2', '3', '4', '5', '6', '7', 521 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 522 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 523 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 524 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 525 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 526 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 527 'u', 'v', 'w', 'x', 'y', 'z' 528 }; 529 struct archive_string temp_name; 530 struct stat st; 531 int fd; 532 char *tp, *ep; 533 534 fd = -1; 535 if (template == NULL) { 536 archive_string_init(&temp_name); 537 if (tmpdir == NULL) { 538 if (get_tempdir(&temp_name) != ARCHIVE_OK) 539 goto exit_tmpfile; 540 } else 541 archive_strcpy(&temp_name, tmpdir); 542 if (temp_name.s[temp_name.length-1] == '/') { 543 temp_name.s[temp_name.length-1] = '\0'; 544 temp_name.length --; 545 } 546 if (la_stat(temp_name.s, &st) < 0) 547 goto exit_tmpfile; 548 if (!S_ISDIR(st.st_mode)) { 549 errno = ENOTDIR; 550 goto exit_tmpfile; 551 } 552 archive_strcat(&temp_name, "/libarchive_"); 553 tp = temp_name.s + archive_strlen(&temp_name); 554 archive_strcat(&temp_name, "XXXXXXXXXX"); 555 ep = temp_name.s + archive_strlen(&temp_name); 556 template = temp_name.s; 557 } else { 558 tp = strchr(template, 'X'); 559 if (tp == NULL) /* No X, programming error */ 560 abort(); 561 for (ep = tp; *ep == 'X'; ep++) 562 continue; 563 if (*ep) /* X followed by non X, programming error */ 564 abort(); 565 } 566 567 do { 568 char *p; 569 570 p = tp; 571 archive_random(p, ep - p); 572 while (p < ep) { 573 int d = *((unsigned char *)p) % sizeof(num); 574 *p++ = num[d]; 575 } 576 fd = open(template, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 577 0600); 578 } while (fd < 0 && errno == EEXIST); 579 if (fd < 0) 580 goto exit_tmpfile; 581 __archive_ensure_cloexec_flag(fd); 582 if (template == temp_name.s) 583 unlink(temp_name.s); 584 exit_tmpfile: 585 if (template == temp_name.s) 586 archive_string_free(&temp_name); 587 return (fd); 588 } 589 590 int 591 __archive_mktemp(const char *tmpdir) 592 { 593 return __archive_mktempx(tmpdir, NULL); 594 } 595 596 int 597 __archive_mkstemp(char *template) 598 { 599 return __archive_mktempx(NULL, template); 600 } 601 602 #endif /* !HAVE_MKSTEMP */ 603 #endif /* !_WIN32 || __CYGWIN__ */ 604 605 /* 606 * Set FD_CLOEXEC flag to a file descriptor if it is not set. 607 * We have to set the flag if the platform does not provide O_CLOEXEC 608 * or F_DUPFD_CLOEXEC flags. 609 * 610 * Note: This function is absolutely called after creating a new file 611 * descriptor even if the platform seemingly provides O_CLOEXEC or 612 * F_DUPFD_CLOEXEC macros because it is possible that the platform 613 * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it. 614 */ 615 void 616 __archive_ensure_cloexec_flag(int fd) 617 { 618 #if defined(_WIN32) && !defined(__CYGWIN__) 619 (void)fd; /* UNUSED */ 620 #else 621 int flags; 622 623 if (fd >= 0) { 624 flags = fcntl(fd, F_GETFD); 625 if (flags != -1 && (flags & FD_CLOEXEC) == 0) 626 fcntl(fd, F_SETFD, flags | FD_CLOEXEC); 627 } 628 #endif 629 } 630 631 /* 632 * Utility function to sort a group of strings using quicksort. 633 */ 634 static int 635 archive_utility_string_sort_helper(char **strings, unsigned int n) 636 { 637 unsigned int i, lesser_count, greater_count; 638 char **lesser, **greater, **tmp, *pivot; 639 int retval1, retval2; 640 641 /* A list of 0 or 1 elements is already sorted */ 642 if (n <= 1) 643 return (ARCHIVE_OK); 644 645 lesser_count = greater_count = 0; 646 lesser = greater = NULL; 647 pivot = strings[0]; 648 for (i = 1; i < n; i++) 649 { 650 if (strcmp(strings[i], pivot) < 0) 651 { 652 lesser_count++; 653 tmp = (char **)realloc(lesser, 654 lesser_count * sizeof(char *)); 655 if (!tmp) { 656 free(greater); 657 free(lesser); 658 return (ARCHIVE_FATAL); 659 } 660 lesser = tmp; 661 lesser[lesser_count - 1] = strings[i]; 662 } 663 else 664 { 665 greater_count++; 666 tmp = (char **)realloc(greater, 667 greater_count * sizeof(char *)); 668 if (!tmp) { 669 free(greater); 670 free(lesser); 671 return (ARCHIVE_FATAL); 672 } 673 greater = tmp; 674 greater[greater_count - 1] = strings[i]; 675 } 676 } 677 678 /* quicksort(lesser) */ 679 retval1 = archive_utility_string_sort_helper(lesser, lesser_count); 680 for (i = 0; i < lesser_count; i++) 681 strings[i] = lesser[i]; 682 free(lesser); 683 684 /* pivot */ 685 strings[lesser_count] = pivot; 686 687 /* quicksort(greater) */ 688 retval2 = archive_utility_string_sort_helper(greater, greater_count); 689 for (i = 0; i < greater_count; i++) 690 strings[lesser_count + 1 + i] = greater[i]; 691 free(greater); 692 693 return (retval1 < retval2) ? retval1 : retval2; 694 } 695 696 int 697 archive_utility_string_sort(char **strings) 698 { 699 unsigned int size = 0; 700 while (strings[size] != NULL) 701 size++; 702 return archive_utility_string_sort_helper(strings, size); 703 } 704