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