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 archive_string_init(&temp_name); 259 260 if (template == NULL) { 261 /* Get a temporary directory. */ 262 if (tmpdir == NULL) { 263 size_t l; 264 wchar_t *tmp; 265 266 l = GetTempPathW(0, NULL); 267 if (l == 0) { 268 la_dosmaperr(GetLastError()); 269 goto exit_tmpfile; 270 } 271 tmp = malloc(l*sizeof(wchar_t)); 272 if (tmp == NULL) { 273 errno = ENOMEM; 274 goto exit_tmpfile; 275 } 276 GetTempPathW((DWORD)l, tmp); 277 archive_wstrcpy(&temp_name, tmp); 278 free(tmp); 279 } else { 280 if (archive_wstring_append_from_mbs(&temp_name, tmpdir, 281 strlen(tmpdir)) < 0) 282 goto exit_tmpfile; 283 if (temp_name.length == 0 || 284 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->length == 0 || 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.length == 0 || 482 temp_name.s[temp_name.length-1] != '/') 483 archive_strappend_char(&temp_name, '/'); 484 } 485 #ifdef O_TMPFILE 486 fd = open(temp_name.s, O_RDWR|O_CLOEXEC|O_TMPFILE|O_EXCL, 0600); 487 if(fd >= 0) 488 goto exit_tmpfile; 489 #endif 490 archive_strcat(&temp_name, "libarchive_XXXXXX"); 491 fd = mkstemp(temp_name.s); 492 if (fd < 0) 493 goto exit_tmpfile; 494 __archive_ensure_cloexec_flag(fd); 495 unlink(temp_name.s); 496 exit_tmpfile: 497 archive_string_free(&temp_name); 498 return (fd); 499 } 500 501 int 502 __archive_mkstemp(char *template) 503 { 504 int fd = -1; 505 fd = mkstemp(template); 506 if (fd >= 0) 507 __archive_ensure_cloexec_flag(fd); 508 return (fd); 509 } 510 511 #else /* !HAVE_MKSTEMP */ 512 513 /* 514 * We use a private routine. 515 */ 516 517 static int 518 __archive_mktempx(const char *tmpdir, char *template) 519 { 520 static const char num[] = { 521 '0', '1', '2', '3', '4', '5', '6', '7', 522 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 523 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 524 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 525 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 526 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 527 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 528 'u', 'v', 'w', 'x', 'y', 'z' 529 }; 530 struct archive_string temp_name; 531 struct stat st; 532 int fd; 533 char *tp, *ep; 534 535 fd = -1; 536 if (template == NULL) { 537 archive_string_init(&temp_name); 538 if (tmpdir == NULL) { 539 if (get_tempdir(&temp_name) != ARCHIVE_OK) 540 goto exit_tmpfile; 541 } else 542 archive_strcpy(&temp_name, tmpdir); 543 if (temp_name.length > 0 && temp_name.s[temp_name.length-1] == '/') { 544 temp_name.s[temp_name.length-1] = '\0'; 545 temp_name.length --; 546 } 547 if (la_stat(temp_name.s, &st) < 0) 548 goto exit_tmpfile; 549 if (!S_ISDIR(st.st_mode)) { 550 errno = ENOTDIR; 551 goto exit_tmpfile; 552 } 553 archive_strcat(&temp_name, "/libarchive_"); 554 tp = temp_name.s + archive_strlen(&temp_name); 555 archive_strcat(&temp_name, "XXXXXXXXXX"); 556 ep = temp_name.s + archive_strlen(&temp_name); 557 template = temp_name.s; 558 } else { 559 tp = strchr(template, 'X'); 560 if (tp == NULL) /* No X, programming error */ 561 abort(); 562 for (ep = tp; *ep == 'X'; ep++) 563 continue; 564 if (*ep) /* X followed by non X, programming error */ 565 abort(); 566 } 567 568 do { 569 char *p; 570 571 p = tp; 572 archive_random(p, ep - p); 573 while (p < ep) { 574 int d = *((unsigned char *)p) % sizeof(num); 575 *p++ = num[d]; 576 } 577 fd = open(template, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 578 0600); 579 } while (fd < 0 && errno == EEXIST); 580 if (fd < 0) 581 goto exit_tmpfile; 582 __archive_ensure_cloexec_flag(fd); 583 if (template == temp_name.s) 584 unlink(temp_name.s); 585 exit_tmpfile: 586 if (template == temp_name.s) 587 archive_string_free(&temp_name); 588 return (fd); 589 } 590 591 int 592 __archive_mktemp(const char *tmpdir) 593 { 594 return __archive_mktempx(tmpdir, NULL); 595 } 596 597 int 598 __archive_mkstemp(char *template) 599 { 600 return __archive_mktempx(NULL, template); 601 } 602 603 #endif /* !HAVE_MKSTEMP */ 604 #endif /* !_WIN32 || __CYGWIN__ */ 605 606 /* 607 * Set FD_CLOEXEC flag to a file descriptor if it is not set. 608 * We have to set the flag if the platform does not provide O_CLOEXEC 609 * or F_DUPFD_CLOEXEC flags. 610 * 611 * Note: This function is absolutely called after creating a new file 612 * descriptor even if the platform seemingly provides O_CLOEXEC or 613 * F_DUPFD_CLOEXEC macros because it is possible that the platform 614 * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it. 615 */ 616 void 617 __archive_ensure_cloexec_flag(int fd) 618 { 619 #if defined(_WIN32) && !defined(__CYGWIN__) 620 (void)fd; /* UNUSED */ 621 #else 622 int flags; 623 624 if (fd >= 0) { 625 flags = fcntl(fd, F_GETFD); 626 if (flags != -1 && (flags & FD_CLOEXEC) == 0) 627 fcntl(fd, F_SETFD, flags | FD_CLOEXEC); 628 } 629 #endif 630 } 631 632 /* 633 * Utility function to sort a group of strings using quicksort. 634 */ 635 static int 636 archive_utility_string_sort_helper(char **strings, unsigned int n) 637 { 638 unsigned int i, lesser_count, greater_count; 639 char **lesser, **greater, **tmp, *pivot; 640 int retval1, retval2; 641 642 /* A list of 0 or 1 elements is already sorted */ 643 if (n <= 1) 644 return (ARCHIVE_OK); 645 646 lesser_count = greater_count = 0; 647 lesser = greater = NULL; 648 pivot = strings[0]; 649 for (i = 1; i < n; i++) 650 { 651 if (strcmp(strings[i], pivot) < 0) 652 { 653 lesser_count++; 654 tmp = realloc(lesser, lesser_count * sizeof(*tmp)); 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 = realloc(greater, greater_count * sizeof(*tmp)); 667 if (!tmp) { 668 free(greater); 669 free(lesser); 670 return (ARCHIVE_FATAL); 671 } 672 greater = tmp; 673 greater[greater_count - 1] = strings[i]; 674 } 675 } 676 677 /* quicksort(lesser) */ 678 retval1 = archive_utility_string_sort_helper(lesser, lesser_count); 679 for (i = 0; i < lesser_count; i++) 680 strings[i] = lesser[i]; 681 free(lesser); 682 683 /* pivot */ 684 strings[lesser_count] = pivot; 685 686 /* quicksort(greater) */ 687 retval2 = archive_utility_string_sort_helper(greater, greater_count); 688 for (i = 0; i < greater_count; i++) 689 strings[lesser_count + 1 + i] = greater[i]; 690 free(greater); 691 692 return (retval1 < retval2) ? retval1 : retval2; 693 } 694 695 int 696 archive_utility_string_sort(char **strings) 697 { 698 unsigned int size = 0; 699 while (strings[size] != NULL) 700 size++; 701 return archive_utility_string_sort_helper(strings, size); 702 } 703