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: 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 #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
__archive_clean(struct archive * a)74 __archive_clean(struct archive *a)
75 {
76 	archive_string_conversion_free(a);
77 	return (ARCHIVE_OK);
78 }
79 
80 int
archive_version_number(void)81 archive_version_number(void)
82 {
83 	return (ARCHIVE_VERSION_NUMBER);
84 }
85 
86 const char *
archive_version_string(void)87 archive_version_string(void)
88 {
89 	return (ARCHIVE_VERSION_STRING);
90 }
91 
92 int
archive_errno(struct archive * a)93 archive_errno(struct archive *a)
94 {
95 	return (a->archive_error_number);
96 }
97 
98 const char *
archive_error_string(struct archive * a)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
archive_file_count(struct archive * a)109 archive_file_count(struct archive *a)
110 {
111 	return (a->file_count);
112 }
113 
114 int
archive_format(struct archive * a)115 archive_format(struct archive *a)
116 {
117 	return (a->archive_format);
118 }
119 
120 const char *
archive_format_name(struct archive * a)121 archive_format_name(struct archive *a)
122 {
123 	return (a->archive_format_name);
124 }
125 
126 
127 int
archive_compression(struct archive * a)128 archive_compression(struct archive *a)
129 {
130 	return archive_filter_code(a, 0);
131 }
132 
133 const char *
archive_compression_name(struct archive * a)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
archive_position_compressed(struct archive * a)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
archive_position_uncompressed(struct archive * a)153 archive_position_uncompressed(struct archive *a)
154 {
155 	return archive_filter_bytes(a, 0);
156 }
157 
158 void
archive_clear_error(struct archive * a)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
archive_set_error(struct archive * a,int error_number,const char * fmt,...)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
archive_copy_error(struct archive * dest,struct archive * src)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
__archive_errx(int retvalue,const char * msg)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 int
__archive_mktemp(const char * tmpdir)222 __archive_mktemp(const char *tmpdir)
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 	archive_string_init(&temp_name);
247 
248 	/* Get a temporary directory. */
249 	if (tmpdir == NULL) {
250 		size_t l;
251 		wchar_t *tmp;
252 
253 		l = GetTempPathW(0, NULL);
254 		if (l == 0) {
255 			la_dosmaperr(GetLastError());
256 			goto exit_tmpfile;
257 		}
258 		tmp = malloc(l*sizeof(wchar_t));
259 		if (tmp == NULL) {
260 			errno = ENOMEM;
261 			goto exit_tmpfile;
262 		}
263 		GetTempPathW((DWORD)l, tmp);
264 		archive_wstrcpy(&temp_name, tmp);
265 		free(tmp);
266 	} else {
267 		if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
268 		    strlen(tmpdir)) < 0)
269 			goto exit_tmpfile;
270 		if (temp_name.s[temp_name.length-1] != L'/')
271 			archive_wstrappend_wchar(&temp_name, L'/');
272 	}
273 
274 	/* Check if temp_name is a directory. */
275 	attr = GetFileAttributesW(temp_name.s);
276 	if (attr == (DWORD)-1) {
277 		if (GetLastError() != ERROR_FILE_NOT_FOUND) {
278 			la_dosmaperr(GetLastError());
279 			goto exit_tmpfile;
280 		}
281 		ws = __la_win_permissive_name_w(temp_name.s);
282 		if (ws == NULL) {
283 			errno = EINVAL;
284 			goto exit_tmpfile;
285 		}
286 		attr = GetFileAttributesW(ws);
287 		if (attr == (DWORD)-1) {
288 			la_dosmaperr(GetLastError());
289 			goto exit_tmpfile;
290 		}
291 	}
292 	if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
293 		errno = ENOTDIR;
294 		goto exit_tmpfile;
295 	}
296 
297 	/*
298 	 * Create a temporary file.
299 	 */
300 	archive_wstrcat(&temp_name, prefix);
301 	archive_wstrcat(&temp_name, suffix);
302 	ep = temp_name.s + archive_strlen(&temp_name);
303 	xp = ep - wcslen(suffix);
304 
305 	if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
306 		CRYPT_VERIFYCONTEXT)) {
307 		la_dosmaperr(GetLastError());
308 		goto exit_tmpfile;
309 	}
310 
311 	for (;;) {
312 		wchar_t *p;
313 		HANDLE h;
314 
315 		/* Generate a random file name through CryptGenRandom(). */
316 		p = xp;
317 		if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),
318 		    (BYTE*)p)) {
319 			la_dosmaperr(GetLastError());
320 			goto exit_tmpfile;
321 		}
322 		for (; p < ep; p++)
323 			*p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
324 
325 		free(ws);
326 		ws = __la_win_permissive_name_w(temp_name.s);
327 		if (ws == NULL) {
328 			errno = EINVAL;
329 			goto exit_tmpfile;
330 		}
331 		/* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to
332 		 * delete this temporary file immediately when this
333 		 * file closed. */
334 		h = CreateFileW(ws,
335 		    GENERIC_READ | GENERIC_WRITE | DELETE,
336 		    0,/* Not share */
337 		    NULL,
338 		    CREATE_NEW,/* Create a new file only */
339 		    FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
340 		    NULL);
341 		if (h == INVALID_HANDLE_VALUE) {
342 			/* The same file already exists. retry with
343 			 * a new filename. */
344 			if (GetLastError() == ERROR_FILE_EXISTS)
345 				continue;
346 			/* Otherwise, fail creation temporary file. */
347 			la_dosmaperr(GetLastError());
348 			goto exit_tmpfile;
349 		}
350 		fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
351 		if (fd == -1) {
352 			CloseHandle(h);
353 			goto exit_tmpfile;
354 		} else
355 			break;/* success! */
356 	}
357 exit_tmpfile:
358 	if (hProv != (HCRYPTPROV)NULL)
359 		CryptReleaseContext(hProv, 0);
360 	free(ws);
361 	archive_wstring_free(&temp_name);
362 	return (fd);
363 }
364 
365 #else
366 
367 static int
get_tempdir(struct archive_string * temppath)368 get_tempdir(struct archive_string *temppath)
369 {
370 	const char *tmp;
371 
372 	tmp = getenv("TMPDIR");
373 	if (tmp == NULL)
374 #ifdef _PATH_TMP
375 		tmp = _PATH_TMP;
376 #else
377                 tmp = "/tmp";
378 #endif
379 	archive_strcpy(temppath, tmp);
380 	if (temppath->s[temppath->length-1] != '/')
381 		archive_strappend_char(temppath, '/');
382 	return (ARCHIVE_OK);
383 }
384 
385 #if defined(HAVE_MKSTEMP)
386 
387 /*
388  * We can use mkstemp().
389  */
390 
391 int
__archive_mktempx(const char * tmpdir,struct archive_string * template)392 __archive_mktempx(const char *tmpdir, struct archive_string *template)
393 {
394 	struct archive_string temp_name;
395 	int fd = -1;
396 
397 	if (template == NULL) {
398 		archive_string_init(template = &temp_name);
399 		if (tmpdir == NULL) {
400 			if (get_tempdir(&temp_name) != ARCHIVE_OK)
401 				goto exit_tmpfile;
402 		} else {
403 			archive_strcpy(&temp_name, tmpdir);
404 			if (temp_name.s[temp_name.length-1] != '/')
405 				archive_strappend_char(&temp_name, '/');
406 		}
407 		archive_strcat(&temp_name, "libarchive_XXXXXX");
408 	}
409 	fd = mkstemp(template->s);
410 	if (fd < 0)
411 		goto exit_tmpfile;
412 	__archive_ensure_cloexec_flag(fd);
413 
414 	if (template == &temp_name)
415 		unlink(temp_name.s);
416 exit_tmpfile:
417 	if (template == &temp_name)
418 		archive_string_free(&temp_name);
419 	return (fd);
420 }
421 
422 #else
423 
424 /*
425  * We use a private routine.
426  */
427 
428 int
__archive_mktempx(const char * tmpdir,struct archive_string * template)429 __archive_mktempx(const char *tmpdir, struct archive_string *template)
430 {
431         static const char num[] = {
432 		'0', '1', '2', '3', '4', '5', '6', '7',
433 		'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
434 		'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
435 		'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
436 		'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
437 		'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
438 		'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
439 		'u', 'v', 'w', 'x', 'y', 'z'
440         };
441 	struct archive_string temp_name;
442 	struct stat st;
443 	int fd;
444 	char *tp, *ep;
445 
446 	fd = -1;
447 	if (template == NULL) {
448 		archive_string_init(template = &temp_name);
449 		if (tmpdir == NULL) {
450 			if (get_tempdir(&temp_name) != ARCHIVE_OK)
451 				goto exit_tmpfile;
452 		} else
453 			archive_strcpy(&temp_name, tmpdir);
454 		if (temp_name.s[temp_name.length-1] == '/') {
455 			temp_name.s[temp_name.length-1] = '\0';
456 			temp_name.length --;
457 		}
458 		if (la_stat(temp_name.s, &st) < 0)
459 			goto exit_tmpfile;
460 		if (!S_ISDIR(st.st_mode)) {
461 			errno = ENOTDIR;
462 			goto exit_tmpfile;
463 		}
464 		archive_strcat(&temp_name, "/libarchive_");
465 		tp = temp_name.s + archive_strlen(&temp_name);
466 		archive_strcat(&temp_name, "XXXXXXXXXX");
467 		ep = temp_name.s + archive_strlen(&temp_name);
468 	} else {
469 		tp = strchr(template->s, 'X');
470 		if (tp == NULL)	/* No X, programming error */
471 			abort();
472 		for (ep = *tp; *ep == 'X'; ep++)
473 			continue;
474 		if (*ep)	/* X followed by non X, programming error */
475 			abort();
476 	}
477 
478 	do {
479 		char *p;
480 
481 		p = tp;
482 		archive_random(p, ep - p);
483 		while (p < ep) {
484 			int d = *((unsigned char *)p) % sizeof(num);
485 			*p++ = num[d];
486 		}
487 		fd = open(template->s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
488 			  0600);
489 	} while (fd < 0 && errno == EEXIST);
490 	if (fd < 0)
491 		goto exit_tmpfile;
492 	__archive_ensure_cloexec_flag(fd);
493 	if (template == &temp_name)
494 		unlink(temp_name.s);
495 exit_tmpfile:
496 	if (template == &temp_name)
497 		archive_string_free(&temp_name);
498 	return (fd);
499 }
500 
501 #endif /* HAVE_MKSTEMP */
502 
503 int
__archive_mktemp(const char * tmpdir)504 __archive_mktemp(const char *tmpdir)
505 {
506 	return __archive_mktempx(tmpdir, NULL);
507 }
508 #endif /* !_WIN32 || __CYGWIN__ */
509 
510 /*
511  * Set FD_CLOEXEC flag to a file descriptor if it is not set.
512  * We have to set the flag if the platform does not provide O_CLOEXEC
513  * or F_DUPFD_CLOEXEC flags.
514  *
515  * Note: This function is absolutely called after creating a new file
516  * descriptor even if the platform seemingly provides O_CLOEXEC or
517  * F_DUPFD_CLOEXEC macros because it is possible that the platform
518  * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
519  */
520 void
__archive_ensure_cloexec_flag(int fd)521 __archive_ensure_cloexec_flag(int fd)
522 {
523 #if defined(_WIN32) && !defined(__CYGWIN__)
524 	(void)fd; /* UNUSED */
525 #else
526 	int flags;
527 
528 	if (fd >= 0) {
529 		flags = fcntl(fd, F_GETFD);
530 		if (flags != -1 && (flags & FD_CLOEXEC) == 0)
531 			fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
532 	}
533 #endif
534 }
535 
536 /*
537  * Utility function to sort a group of strings using quicksort.
538  */
539 static int
archive_utility_string_sort_helper(char ** strings,unsigned int n)540 archive_utility_string_sort_helper(char **strings, unsigned int n)
541 {
542 	unsigned int i, lesser_count, greater_count;
543 	char **lesser, **greater, **tmp, *pivot;
544 	int retval1, retval2;
545 
546 	/* A list of 0 or 1 elements is already sorted */
547 	if (n <= 1)
548 		return (ARCHIVE_OK);
549 
550 	lesser_count = greater_count = 0;
551 	lesser = greater = NULL;
552 	pivot = strings[0];
553 	for (i = 1; i < n; i++)
554 	{
555 		if (strcmp(strings[i], pivot) < 0)
556 		{
557 			lesser_count++;
558 			tmp = (char **)realloc(lesser,
559 				lesser_count * sizeof(char *));
560 			if (!tmp) {
561 				free(greater);
562 				free(lesser);
563 				return (ARCHIVE_FATAL);
564 			}
565 			lesser = tmp;
566 			lesser[lesser_count - 1] = strings[i];
567 		}
568 		else
569 		{
570 			greater_count++;
571 			tmp = (char **)realloc(greater,
572 				greater_count * sizeof(char *));
573 			if (!tmp) {
574 				free(greater);
575 				free(lesser);
576 				return (ARCHIVE_FATAL);
577 			}
578 			greater = tmp;
579 			greater[greater_count - 1] = strings[i];
580 		}
581 	}
582 
583 	/* quicksort(lesser) */
584 	retval1 = archive_utility_string_sort_helper(lesser, lesser_count);
585 	for (i = 0; i < lesser_count; i++)
586 		strings[i] = lesser[i];
587 	free(lesser);
588 
589 	/* pivot */
590 	strings[lesser_count] = pivot;
591 
592 	/* quicksort(greater) */
593 	retval2 = archive_utility_string_sort_helper(greater, greater_count);
594 	for (i = 0; i < greater_count; i++)
595 		strings[lesser_count + 1 + i] = greater[i];
596 	free(greater);
597 
598 	return (retval1 < retval2) ? retval1 : retval2;
599 }
600 
601 int
archive_utility_string_sort(char ** strings)602 archive_utility_string_sort(char **strings)
603 {
604 	  unsigned int size = 0;
605 	  while (strings[size] != NULL)
606 		size++;
607 	  return archive_utility_string_sort_helper(strings, size);
608 }
609