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 archive_wstring_append_from_mbs(&temp_name, tmpdir, 247 strlen(tmpdir)); 248 if (temp_name.s[temp_name.length-1] != L'/') 249 archive_wstrappend_wchar(&temp_name, L'/'); 250 } 251 252 /* Check if temp_name is a directory. */ 253 attr = GetFileAttributesW(temp_name.s); 254 if (attr == (DWORD)-1) { 255 if (GetLastError() != ERROR_FILE_NOT_FOUND) { 256 la_dosmaperr(GetLastError()); 257 goto exit_tmpfile; 258 } 259 ws = __la_win_permissive_name_w(temp_name.s); 260 if (ws == NULL) { 261 errno = EINVAL; 262 goto exit_tmpfile; 263 } 264 attr = GetFileAttributesW(ws); 265 if (attr == (DWORD)-1) { 266 la_dosmaperr(GetLastError()); 267 goto exit_tmpfile; 268 } 269 } 270 if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { 271 errno = ENOTDIR; 272 goto exit_tmpfile; 273 } 274 275 /* 276 * Create a temporary file. 277 */ 278 archive_wstrcat(&temp_name, L"libarchive_"); 279 xp = temp_name.s + archive_strlen(&temp_name); 280 archive_wstrcat(&temp_name, L"XXXXXXXXXX"); 281 ep = temp_name.s + archive_strlen(&temp_name); 282 283 if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 284 CRYPT_VERIFYCONTEXT)) { 285 la_dosmaperr(GetLastError()); 286 goto exit_tmpfile; 287 } 288 289 for (;;) { 290 wchar_t *p; 291 HANDLE h; 292 293 /* Generate a random file name through CryptGenRandom(). */ 294 p = xp; 295 if (!CryptGenRandom(hProv, (ep - p)*sizeof(wchar_t), (BYTE*)p)) { 296 la_dosmaperr(GetLastError()); 297 goto exit_tmpfile; 298 } 299 for (; p < ep; p++) 300 *p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))]; 301 302 free(ws); 303 ws = __la_win_permissive_name_w(temp_name.s); 304 if (ws == NULL) { 305 errno = EINVAL; 306 goto exit_tmpfile; 307 } 308 /* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to 309 * delete this temporary file immediately when this 310 * file closed. */ 311 h = CreateFileW(ws, 312 GENERIC_READ | GENERIC_WRITE | DELETE, 313 0,/* Not share */ 314 NULL, 315 CREATE_NEW,/* Create a new file only */ 316 FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, 317 NULL); 318 if (h == INVALID_HANDLE_VALUE) { 319 /* The same file already exists. retry with 320 * a new filename. */ 321 if (GetLastError() == ERROR_FILE_EXISTS) 322 continue; 323 /* Otherwise, fail creation temporary file. */ 324 la_dosmaperr(GetLastError()); 325 goto exit_tmpfile; 326 } 327 fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR); 328 if (fd == -1) { 329 CloseHandle(h); 330 goto exit_tmpfile; 331 } else 332 break;/* success! */ 333 } 334 exit_tmpfile: 335 if (hProv != (HCRYPTPROV)NULL) 336 CryptReleaseContext(hProv, 0); 337 free(ws); 338 archive_wstring_free(&temp_name); 339 return (fd); 340 } 341 342 #else 343 344 static int 345 get_tempdir(struct archive_string *temppath) 346 { 347 const char *tmp; 348 349 tmp = getenv("TMPDIR"); 350 if (tmp == NULL) 351 #ifdef _PATH_TMP 352 tmp = _PATH_TMP; 353 #else 354 tmp = "/tmp"; 355 #endif 356 archive_strcpy(temppath, tmp); 357 if (temppath->s[temppath->length-1] != '/') 358 archive_strappend_char(temppath, '/'); 359 return (ARCHIVE_OK); 360 } 361 362 #if defined(HAVE_MKSTEMP) 363 364 /* 365 * We can use mkstemp(). 366 */ 367 368 int 369 __archive_mktemp(const char *tmpdir) 370 { 371 struct archive_string temp_name; 372 int fd = -1; 373 374 archive_string_init(&temp_name); 375 if (tmpdir == NULL) { 376 if (get_tempdir(&temp_name) != ARCHIVE_OK) 377 goto exit_tmpfile; 378 } else { 379 archive_strcpy(&temp_name, tmpdir); 380 if (temp_name.s[temp_name.length-1] != '/') 381 archive_strappend_char(&temp_name, '/'); 382 } 383 archive_strcat(&temp_name, "libarchive_XXXXXX"); 384 fd = mkstemp(temp_name.s); 385 if (fd < 0) 386 goto exit_tmpfile; 387 unlink(temp_name.s); 388 exit_tmpfile: 389 archive_string_free(&temp_name); 390 return (fd); 391 } 392 393 #else 394 395 /* 396 * We use a private routine. 397 */ 398 399 int 400 __archive_mktemp(const char *tmpdir) 401 { 402 static const char num[] = { 403 '0', '1', '2', '3', '4', '5', '6', '7', 404 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 405 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 406 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 407 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 408 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 409 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 410 'u', 'v', 'w', 'x', 'y', 'z' 411 }; 412 struct archive_string temp_name; 413 struct stat st; 414 int fd; 415 char *tp, *ep; 416 unsigned seed; 417 418 fd = -1; 419 archive_string_init(&temp_name); 420 if (tmpdir == NULL) { 421 if (get_tempdir(&temp_name) != ARCHIVE_OK) 422 goto exit_tmpfile; 423 } else 424 archive_strcpy(&temp_name, tmpdir); 425 if (temp_name.s[temp_name.length-1] == '/') { 426 temp_name.s[temp_name.length-1] = '\0'; 427 temp_name.length --; 428 } 429 if (stat(temp_name.s, &st) < 0) 430 goto exit_tmpfile; 431 if (!S_ISDIR(st.st_mode)) { 432 errno = ENOTDIR; 433 goto exit_tmpfile; 434 } 435 archive_strcat(&temp_name, "/libarchive_"); 436 tp = temp_name.s + archive_strlen(&temp_name); 437 archive_strcat(&temp_name, "XXXXXXXXXX"); 438 ep = temp_name.s + archive_strlen(&temp_name); 439 440 fd = open("/dev/random", O_RDONLY); 441 if (fd < 0) 442 seed = time(NULL); 443 else { 444 if (read(fd, &seed, sizeof(seed)) < 0) 445 seed = time(NULL); 446 close(fd); 447 } 448 do { 449 char *p; 450 451 p = tp; 452 while (p < ep) 453 *p++ = num[((unsigned)rand_r(&seed)) % sizeof(num)]; 454 fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR, 0600); 455 } while (fd < 0 && errno == EEXIST); 456 if (fd < 0) 457 goto exit_tmpfile; 458 unlink(temp_name.s); 459 exit_tmpfile: 460 archive_string_free(&temp_name); 461 return (fd); 462 } 463 464 #endif /* HAVE_MKSTEMP */ 465 #endif /* !_WIN32 || __CYGWIN__ */ 466