1 /*- 2 * Copyright (c) 2009,2010 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 __FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:14Z kientzle $"); 29 30 #ifdef HAVE_SYS_TYPES_H 31 #include <sys/types.h> 32 #endif 33 #ifdef HAVE_ERRNO_H 34 #include <errno.h> 35 #endif 36 #ifdef HAVE_FCNTL_H 37 #include <fcntl.h> 38 #endif 39 #ifdef HAVE_STDLIB_H 40 #include <stdlib.h> 41 #endif 42 #ifdef HAVE_STRING_H 43 #include <string.h> 44 #endif 45 #if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__) 46 #include <wincrypt.h> 47 #endif 48 49 #include "archive.h" 50 #include "archive_private.h" 51 #include "archive_string.h" 52 53 /* Generic initialization of 'struct archive' objects. */ 54 int 55 __archive_clean(struct archive *a) 56 { 57 archive_string_conversion_free(a); 58 return (ARCHIVE_OK); 59 } 60 61 int 62 archive_version_number(void) 63 { 64 return (ARCHIVE_VERSION_NUMBER); 65 } 66 67 const char * 68 archive_version_string(void) 69 { 70 return (ARCHIVE_VERSION_STRING); 71 } 72 73 int 74 archive_errno(struct archive *a) 75 { 76 return (a->archive_error_number); 77 } 78 79 const char * 80 archive_error_string(struct archive *a) 81 { 82 83 if (a->error != NULL && *a->error != '\0') 84 return (a->error); 85 else 86 return (NULL); 87 } 88 89 int 90 archive_file_count(struct archive *a) 91 { 92 return (a->file_count); 93 } 94 95 int 96 archive_format(struct archive *a) 97 { 98 return (a->archive_format); 99 } 100 101 const char * 102 archive_format_name(struct archive *a) 103 { 104 return (a->archive_format_name); 105 } 106 107 108 int 109 archive_compression(struct archive *a) 110 { 111 return archive_filter_code(a, 0); 112 } 113 114 const char * 115 archive_compression_name(struct archive *a) 116 { 117 return archive_filter_name(a, 0); 118 } 119 120 121 /* 122 * Return a count of the number of compressed bytes processed. 123 */ 124 int64_t 125 archive_position_compressed(struct archive *a) 126 { 127 return archive_filter_bytes(a, -1); 128 } 129 130 /* 131 * Return a count of the number of uncompressed bytes processed. 132 */ 133 int64_t 134 archive_position_uncompressed(struct archive *a) 135 { 136 return archive_filter_bytes(a, 0); 137 } 138 139 void 140 archive_clear_error(struct archive *a) 141 { 142 archive_string_empty(&a->error_string); 143 a->error = NULL; 144 a->archive_error_number = 0; 145 } 146 147 void 148 archive_set_error(struct archive *a, int error_number, const char *fmt, ...) 149 { 150 va_list ap; 151 152 a->archive_error_number = error_number; 153 if (fmt == NULL) { 154 a->error = NULL; 155 return; 156 } 157 158 archive_string_empty(&(a->error_string)); 159 va_start(ap, fmt); 160 archive_string_vsprintf(&(a->error_string), fmt, ap); 161 va_end(ap); 162 a->error = a->error_string.s; 163 } 164 165 void 166 archive_copy_error(struct archive *dest, struct archive *src) 167 { 168 dest->archive_error_number = src->archive_error_number; 169 170 archive_string_copy(&dest->error_string, &src->error_string); 171 dest->error = dest->error_string.s; 172 } 173 174 void 175 __archive_errx(int retvalue, const char *msg) 176 { 177 static const char *msg1 = "Fatal Internal Error in libarchive: "; 178 size_t s; 179 180 s = write(2, msg1, strlen(msg1)); 181 (void)s; /* UNUSED */ 182 s = write(2, msg, strlen(msg)); 183 (void)s; /* UNUSED */ 184 s = write(2, "\n", 1); 185 (void)s; /* UNUSED */ 186 exit(retvalue); 187 } 188 189 /* 190 * Create a temporary file 191 */ 192 #if defined(_WIN32) && !defined(__CYGWIN__) 193 194 /* 195 * Do not use Windows tmpfile() function. 196 * It will make a temporary file under the root directory 197 * and it'll cause permission error if a user who is 198 * non-Administrator creates temporary files. 199 * Also Windows version of mktemp family including _mktemp_s 200 * are not secure. 201 */ 202 int 203 __archive_mktemp(const char *tmpdir) 204 { 205 static const wchar_t num[] = { 206 L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', 207 L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F', 208 L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N', 209 L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V', 210 L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd', 211 L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l', 212 L'm', L'n', L'o', L'p', L'q', L'r', L's', L't', 213 L'u', L'v', L'w', L'x', L'y', L'z' 214 }; 215 HCRYPTPROV hProv; 216 struct archive_wstring temp_name; 217 wchar_t *ws; 218 DWORD attr; 219 wchar_t *xp, *ep; 220 int fd; 221 222 hProv = (HCRYPTPROV)NULL; 223 fd = -1; 224 ws = NULL; 225 archive_string_init(&temp_name); 226 227 /* Get a temporary directory. */ 228 if (tmpdir == NULL) { 229 size_t l; 230 wchar_t *tmp; 231 232 l = GetTempPathW(0, NULL); 233 if (l == 0) { 234 la_dosmaperr(GetLastError()); 235 goto exit_tmpfile; 236 } 237 tmp = malloc(l*sizeof(wchar_t)); 238 if (tmp == NULL) { 239 errno = ENOMEM; 240 goto exit_tmpfile; 241 } 242 GetTempPathW(l, tmp); 243 archive_wstrcpy(&temp_name, tmp); 244 free(tmp); 245 } else { 246 if (archive_wstring_append_from_mbs(&temp_name, tmpdir, 247 strlen(tmpdir)) < 0) 248 goto exit_tmpfile; 249 if (temp_name.s[temp_name.length-1] != L'/') 250 archive_wstrappend_wchar(&temp_name, L'/'); 251 } 252 253 /* Check if temp_name is a directory. */ 254 attr = GetFileAttributesW(temp_name.s); 255 if (attr == (DWORD)-1) { 256 if (GetLastError() != ERROR_FILE_NOT_FOUND) { 257 la_dosmaperr(GetLastError()); 258 goto exit_tmpfile; 259 } 260 ws = __la_win_permissive_name_w(temp_name.s); 261 if (ws == NULL) { 262 errno = EINVAL; 263 goto exit_tmpfile; 264 } 265 attr = GetFileAttributesW(ws); 266 if (attr == (DWORD)-1) { 267 la_dosmaperr(GetLastError()); 268 goto exit_tmpfile; 269 } 270 } 271 if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { 272 errno = ENOTDIR; 273 goto exit_tmpfile; 274 } 275 276 /* 277 * Create a temporary file. 278 */ 279 archive_wstrcat(&temp_name, L"libarchive_"); 280 xp = temp_name.s + archive_strlen(&temp_name); 281 archive_wstrcat(&temp_name, L"XXXXXXXXXX"); 282 ep = temp_name.s + archive_strlen(&temp_name); 283 284 if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 285 CRYPT_VERIFYCONTEXT)) { 286 la_dosmaperr(GetLastError()); 287 goto exit_tmpfile; 288 } 289 290 for (;;) { 291 wchar_t *p; 292 HANDLE h; 293 294 /* Generate a random file name through CryptGenRandom(). */ 295 p = xp; 296 if (!CryptGenRandom(hProv, (ep - p)*sizeof(wchar_t), (BYTE*)p)) { 297 la_dosmaperr(GetLastError()); 298 goto exit_tmpfile; 299 } 300 for (; p < ep; p++) 301 *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))]; 302 303 free(ws); 304 ws = __la_win_permissive_name_w(temp_name.s); 305 if (ws == NULL) { 306 errno = EINVAL; 307 goto exit_tmpfile; 308 } 309 /* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to 310 * delete this temporary file immediately when this 311 * file closed. */ 312 h = CreateFileW(ws, 313 GENERIC_READ | GENERIC_WRITE | DELETE, 314 0,/* Not share */ 315 NULL, 316 CREATE_NEW,/* Create a new file only */ 317 FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, 318 NULL); 319 if (h == INVALID_HANDLE_VALUE) { 320 /* The same file already exists. retry with 321 * a new filename. */ 322 if (GetLastError() == ERROR_FILE_EXISTS) 323 continue; 324 /* Otherwise, fail creation temporary file. */ 325 la_dosmaperr(GetLastError()); 326 goto exit_tmpfile; 327 } 328 fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR); 329 if (fd == -1) { 330 CloseHandle(h); 331 goto exit_tmpfile; 332 } else 333 break;/* success! */ 334 } 335 exit_tmpfile: 336 if (hProv != (HCRYPTPROV)NULL) 337 CryptReleaseContext(hProv, 0); 338 free(ws); 339 archive_wstring_free(&temp_name); 340 return (fd); 341 } 342 343 #else 344 345 static int 346 get_tempdir(struct archive_string *temppath) 347 { 348 const char *tmp; 349 350 tmp = getenv("TMPDIR"); 351 if (tmp == NULL) 352 #ifdef _PATH_TMP 353 tmp = _PATH_TMP; 354 #else 355 tmp = "/tmp"; 356 #endif 357 archive_strcpy(temppath, tmp); 358 if (temppath->s[temppath->length-1] != '/') 359 archive_strappend_char(temppath, '/'); 360 return (ARCHIVE_OK); 361 } 362 363 #if defined(HAVE_MKSTEMP) 364 365 /* 366 * We can use mkstemp(). 367 */ 368 369 int 370 __archive_mktemp(const char *tmpdir) 371 { 372 struct archive_string temp_name; 373 int fd = -1; 374 375 archive_string_init(&temp_name); 376 if (tmpdir == NULL) { 377 if (get_tempdir(&temp_name) != ARCHIVE_OK) 378 goto exit_tmpfile; 379 } else { 380 archive_strcpy(&temp_name, tmpdir); 381 if (temp_name.s[temp_name.length-1] != '/') 382 archive_strappend_char(&temp_name, '/'); 383 } 384 archive_strcat(&temp_name, "libarchive_XXXXXX"); 385 fd = mkstemp(temp_name.s); 386 if (fd < 0) 387 goto exit_tmpfile; 388 unlink(temp_name.s); 389 exit_tmpfile: 390 archive_string_free(&temp_name); 391 return (fd); 392 } 393 394 #else 395 396 /* 397 * We use a private routine. 398 */ 399 400 int 401 __archive_mktemp(const char *tmpdir) 402 { 403 static const char num[] = { 404 '0', '1', '2', '3', '4', '5', '6', '7', 405 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 406 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 407 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 408 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 409 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 410 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 411 'u', 'v', 'w', 'x', 'y', 'z' 412 }; 413 struct archive_string temp_name; 414 struct stat st; 415 int fd; 416 char *tp, *ep; 417 unsigned seed; 418 419 fd = -1; 420 archive_string_init(&temp_name); 421 if (tmpdir == NULL) { 422 if (get_tempdir(&temp_name) != ARCHIVE_OK) 423 goto exit_tmpfile; 424 } else 425 archive_strcpy(&temp_name, tmpdir); 426 if (temp_name.s[temp_name.length-1] == '/') { 427 temp_name.s[temp_name.length-1] = '\0'; 428 temp_name.length --; 429 } 430 if (stat(temp_name.s, &st) < 0) 431 goto exit_tmpfile; 432 if (!S_ISDIR(st.st_mode)) { 433 errno = ENOTDIR; 434 goto exit_tmpfile; 435 } 436 archive_strcat(&temp_name, "/libarchive_"); 437 tp = temp_name.s + archive_strlen(&temp_name); 438 archive_strcat(&temp_name, "XXXXXXXXXX"); 439 ep = temp_name.s + archive_strlen(&temp_name); 440 441 fd = open("/dev/random", O_RDONLY); 442 if (fd < 0) 443 seed = time(NULL); 444 else { 445 if (read(fd, &seed, sizeof(seed)) < 0) 446 seed = time(NULL); 447 close(fd); 448 } 449 do { 450 char *p; 451 452 p = tp; 453 while (p < ep) 454 *p++ = num[((unsigned)rand_r(&seed)) % sizeof(num)]; 455 fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR, 0600); 456 } while (fd < 0 && errno == EEXIST); 457 if (fd < 0) 458 goto exit_tmpfile; 459 unlink(temp_name.s); 460 exit_tmpfile: 461 archive_string_free(&temp_name); 462 return (fd); 463 } 464 465 #endif /* HAVE_MKSTEMP */ 466 #endif /* !_WIN32 || __CYGWIN__ */ 467