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