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