1/*-
2 * Copyright (c) 2009-2012 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
49#include "archive.h"
50#include "archive_private.h"
51#include "archive_string.h"
52
53#ifndef O_CLOEXEC
54#define O_CLOEXEC	0
55#endif
56
57/* Generic initialization of 'struct archive' objects. */
58int
59__archive_clean(struct archive *a)
60{
61	archive_string_conversion_free(a);
62	return (ARCHIVE_OK);
63}
64
65int
66archive_version_number(void)
67{
68	return (ARCHIVE_VERSION_NUMBER);
69}
70
71const char *
72archive_version_string(void)
73{
74	return (ARCHIVE_VERSION_STRING);
75}
76
77int
78archive_errno(struct archive *a)
79{
80	return (a->archive_error_number);
81}
82
83const char *
84archive_error_string(struct archive *a)
85{
86
87	if (a->error != NULL  &&  *a->error != '\0')
88		return (a->error);
89	else
90		return (NULL);
91}
92
93int
94archive_file_count(struct archive *a)
95{
96	return (a->file_count);
97}
98
99int
100archive_format(struct archive *a)
101{
102	return (a->archive_format);
103}
104
105const char *
106archive_format_name(struct archive *a)
107{
108	return (a->archive_format_name);
109}
110
111
112int
113archive_compression(struct archive *a)
114{
115	return archive_filter_code(a, 0);
116}
117
118const char *
119archive_compression_name(struct archive *a)
120{
121	return archive_filter_name(a, 0);
122}
123
124
125/*
126 * Return a count of the number of compressed bytes processed.
127 */
128int64_t
129archive_position_compressed(struct archive *a)
130{
131	return archive_filter_bytes(a, -1);
132}
133
134/*
135 * Return a count of the number of uncompressed bytes processed.
136 */
137int64_t
138archive_position_uncompressed(struct archive *a)
139{
140	return archive_filter_bytes(a, 0);
141}
142
143void
144archive_clear_error(struct archive *a)
145{
146	archive_string_empty(&a->error_string);
147	a->error = NULL;
148	a->archive_error_number = 0;
149}
150
151void
152archive_set_error(struct archive *a, int error_number, const char *fmt, ...)
153{
154	va_list ap;
155
156	a->archive_error_number = error_number;
157	if (fmt == NULL) {
158		a->error = NULL;
159		return;
160	}
161
162	archive_string_empty(&(a->error_string));
163	va_start(ap, fmt);
164	archive_string_vsprintf(&(a->error_string), fmt, ap);
165	va_end(ap);
166	a->error = a->error_string.s;
167}
168
169void
170archive_copy_error(struct archive *dest, struct archive *src)
171{
172	dest->archive_error_number = src->archive_error_number;
173
174	archive_string_copy(&dest->error_string, &src->error_string);
175	dest->error = dest->error_string.s;
176}
177
178void
179__archive_errx(int retvalue, const char *msg)
180{
181	static const char *msg1 = "Fatal Internal Error in libarchive: ";
182	size_t s;
183
184	s = write(2, msg1, strlen(msg1));
185	(void)s; /* UNUSED */
186	s = write(2, msg, strlen(msg));
187	(void)s; /* UNUSED */
188	s = write(2, "\n", 1);
189	(void)s; /* UNUSED */
190	exit(retvalue);
191}
192
193/*
194 * Create a temporary file
195 */
196#if defined(_WIN32) && !defined(__CYGWIN__)
197
198/*
199 * Do not use Windows tmpfile() function.
200 * It will make a temporary file under the root directory
201 * and it'll cause permission error if a user who is
202 * non-Administrator creates temporary files.
203 * Also Windows version of mktemp family including _mktemp_s
204 * are not secure.
205 */
206int
207__archive_mktemp(const char *tmpdir)
208{
209	static const wchar_t num[] = {
210		L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',
211		L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F',
212		L'G', L'H', L'I', L'J', L'K', L'L', L'M', L'N',
213		L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V',
214		L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd',
215		L'e', L'f', L'g', L'h', L'i', L'j', L'k', L'l',
216		L'm', L'n', L'o', L'p', L'q', L'r', L's', L't',
217		L'u', L'v', L'w', L'x', L'y', L'z'
218	};
219	HCRYPTPROV hProv;
220	struct archive_wstring temp_name;
221	wchar_t *ws;
222	DWORD attr;
223	wchar_t *xp, *ep;
224	int fd;
225
226	hProv = (HCRYPTPROV)NULL;
227	fd = -1;
228	ws = NULL;
229	archive_string_init(&temp_name);
230
231	/* Get a temporary directory. */
232	if (tmpdir == NULL) {
233		size_t l;
234		wchar_t *tmp;
235
236		l = GetTempPathW(0, NULL);
237		if (l == 0) {
238			la_dosmaperr(GetLastError());
239			goto exit_tmpfile;
240		}
241		tmp = malloc(l*sizeof(wchar_t));
242		if (tmp == NULL) {
243			errno = ENOMEM;
244			goto exit_tmpfile;
245		}
246		GetTempPathW((DWORD)l, tmp);
247		archive_wstrcpy(&temp_name, tmp);
248		free(tmp);
249	} else {
250		if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
251		    strlen(tmpdir)) < 0)
252			goto exit_tmpfile;
253		if (temp_name.s[temp_name.length-1] != L'/')
254			archive_wstrappend_wchar(&temp_name, L'/');
255	}
256
257	/* Check if temp_name is a directory. */
258	attr = GetFileAttributesW(temp_name.s);
259	if (attr == (DWORD)-1) {
260		if (GetLastError() != ERROR_FILE_NOT_FOUND) {
261			la_dosmaperr(GetLastError());
262			goto exit_tmpfile;
263		}
264		ws = __la_win_permissive_name_w(temp_name.s);
265		if (ws == NULL) {
266			errno = EINVAL;
267			goto exit_tmpfile;
268		}
269		attr = GetFileAttributesW(ws);
270		if (attr == (DWORD)-1) {
271			la_dosmaperr(GetLastError());
272			goto exit_tmpfile;
273		}
274	}
275	if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
276		errno = ENOTDIR;
277		goto exit_tmpfile;
278	}
279
280	/*
281	 * Create a temporary file.
282	 */
283	archive_wstrcat(&temp_name, L"libarchive_");
284	xp = temp_name.s + archive_strlen(&temp_name);
285	archive_wstrcat(&temp_name, L"XXXXXXXXXX");
286	ep = temp_name.s + archive_strlen(&temp_name);
287
288	if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
289		CRYPT_VERIFYCONTEXT)) {
290		la_dosmaperr(GetLastError());
291		goto exit_tmpfile;
292	}
293
294	for (;;) {
295		wchar_t *p;
296		HANDLE h;
297
298		/* Generate a random file name through CryptGenRandom(). */
299		p = xp;
300		if (!CryptGenRandom(hProv, (DWORD)(ep - p)*sizeof(wchar_t),
301		    (BYTE*)p)) {
302			la_dosmaperr(GetLastError());
303			goto exit_tmpfile;
304		}
305		for (; p < ep; p++)
306			*p = num[((DWORD)*p) % (sizeof(num)/sizeof(num[0]))];
307
308		free(ws);
309		ws = __la_win_permissive_name_w(temp_name.s);
310		if (ws == NULL) {
311			errno = EINVAL;
312			goto exit_tmpfile;
313		}
314		/* Specifies FILE_FLAG_DELETE_ON_CLOSE flag is to
315		 * delete this temporary file immediately when this
316		 * file closed. */
317		h = CreateFileW(ws,
318		    GENERIC_READ | GENERIC_WRITE | DELETE,
319		    0,/* Not share */
320		    NULL,
321		    CREATE_NEW,/* Create a new file only */
322		    FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
323		    NULL);
324		if (h == INVALID_HANDLE_VALUE) {
325			/* The same file already exists. retry with
326			 * a new filename. */
327			if (GetLastError() == ERROR_FILE_EXISTS)
328				continue;
329			/* Otherwise, fail creation temporary file. */
330			la_dosmaperr(GetLastError());
331			goto exit_tmpfile;
332		}
333		fd = _open_osfhandle((intptr_t)h, _O_BINARY | _O_RDWR);
334		if (fd == -1) {
335			CloseHandle(h);
336			goto exit_tmpfile;
337		} else
338			break;/* success! */
339	}
340exit_tmpfile:
341	if (hProv != (HCRYPTPROV)NULL)
342		CryptReleaseContext(hProv, 0);
343	free(ws);
344	archive_wstring_free(&temp_name);
345	return (fd);
346}
347
348#else
349
350static int
351get_tempdir(struct archive_string *temppath)
352{
353	const char *tmp;
354
355	tmp = getenv("TMPDIR");
356	if (tmp == NULL)
357#ifdef _PATH_TMP
358		tmp = _PATH_TMP;
359#else
360                tmp = "/tmp";
361#endif
362	archive_strcpy(temppath, tmp);
363	if (temppath->s[temppath->length-1] != '/')
364		archive_strappend_char(temppath, '/');
365	return (ARCHIVE_OK);
366}
367
368#if defined(HAVE_MKSTEMP)
369
370/*
371 * We can use mkstemp().
372 */
373
374int
375__archive_mktemp(const char *tmpdir)
376{
377	struct archive_string temp_name;
378	int fd = -1;
379
380	archive_string_init(&temp_name);
381	if (tmpdir == NULL) {
382		if (get_tempdir(&temp_name) != ARCHIVE_OK)
383			goto exit_tmpfile;
384	} else {
385		archive_strcpy(&temp_name, tmpdir);
386		if (temp_name.s[temp_name.length-1] != '/')
387			archive_strappend_char(&temp_name, '/');
388	}
389	archive_strcat(&temp_name, "libarchive_XXXXXX");
390	fd = mkstemp(temp_name.s);
391	if (fd < 0)
392		goto exit_tmpfile;
393	__archive_ensure_cloexec_flag(fd);
394	unlink(temp_name.s);
395exit_tmpfile:
396	archive_string_free(&temp_name);
397	return (fd);
398}
399
400#else
401
402/*
403 * We use a private routine.
404 */
405
406int
407__archive_mktemp(const char *tmpdir)
408{
409        static const char num[] = {
410		'0', '1', '2', '3', '4', '5', '6', '7',
411		'8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
412		'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
413		'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
414		'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
415		'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
416		'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
417		'u', 'v', 'w', 'x', 'y', 'z'
418        };
419	struct archive_string temp_name;
420	struct stat st;
421	int fd;
422	char *tp, *ep;
423	unsigned seed;
424
425	fd = -1;
426	archive_string_init(&temp_name);
427	if (tmpdir == NULL) {
428		if (get_tempdir(&temp_name) != ARCHIVE_OK)
429			goto exit_tmpfile;
430	} else
431		archive_strcpy(&temp_name, tmpdir);
432	if (temp_name.s[temp_name.length-1] == '/') {
433		temp_name.s[temp_name.length-1] = '\0';
434		temp_name.length --;
435	}
436	if (stat(temp_name.s, &st) < 0)
437		goto exit_tmpfile;
438	if (!S_ISDIR(st.st_mode)) {
439		errno = ENOTDIR;
440		goto exit_tmpfile;
441	}
442	archive_strcat(&temp_name, "/libarchive_");
443	tp = temp_name.s + archive_strlen(&temp_name);
444	archive_strcat(&temp_name, "XXXXXXXXXX");
445	ep = temp_name.s + archive_strlen(&temp_name);
446
447	fd = open("/dev/random", O_RDONLY | O_CLOEXEC);
448	__archive_ensure_cloexec_flag(fd);
449	if (fd < 0)
450		seed = time(NULL);
451	else {
452		if (read(fd, &seed, sizeof(seed)) < 0)
453			seed = time(NULL);
454		close(fd);
455	}
456	do {
457		char *p;
458
459		p = tp;
460		while (p < ep)
461			*p++ = num[((unsigned)rand_r(&seed)) % sizeof(num)];
462		fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
463			  0600);
464	} while (fd < 0 && errno == EEXIST);
465	if (fd < 0)
466		goto exit_tmpfile;
467	__archive_ensure_cloexec_flag(fd);
468	unlink(temp_name.s);
469exit_tmpfile:
470	archive_string_free(&temp_name);
471	return (fd);
472}
473
474#endif /* HAVE_MKSTEMP */
475#endif /* !_WIN32 || __CYGWIN__ */
476
477/*
478 * Set FD_CLOEXEC flag to a file descriptor if it is not set.
479 * We have to set the flag if the platform does not provide O_CLOEXEC
480 * or F_DUPFD_CLOEXEC flags.
481 *
482 * Note: This function is absolutely called after creating a new file
483 * descriptor even if the platform seemingly provides O_CLOEXEC or
484 * F_DUPFD_CLOEXEC macros because it is possible that the platform
485 * merely declares those macros, especially Linux 2.6.18 - 2.6.24 do it.
486 */
487void
488__archive_ensure_cloexec_flag(int fd)
489{
490#if defined(_WIN32) && !defined(__CYGWIN__)
491	(void)fd; /* UNSED */
492#else
493	int flags;
494
495	if (fd >= 0) {
496		flags = fcntl(fd, F_GETFD);
497		if (flags != -1 && (flags & FD_CLOEXEC) == 0)
498			fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
499	}
500#endif
501}
502