1 /*
2  * Copyright (c) 2011 Collabora Ltd.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *     * Redistributions of source code must retain the above
9  *       copyright notice, this list of conditions and the
10  *       following disclaimer.
11  *     * Redistributions in binary form must reproduce the
12  *       above copyright notice, this list of conditions and
13  *       the following disclaimer in the documentation and/or
14  *       other materials provided with the distribution.
15  *     * The names of contributors to this software may not be
16  *       used to endorse or promote products derived from this
17  *       software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
29  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
30  * DAMAGE.
31  *
32  * Author: Stef Walter <stefw@collabora.co.uk>
33  */
34 
35 #include "config.h"
36 
37 /*
38  * This is needed to expose pthread_mutexattr_settype and PTHREAD_MUTEX_DEFAULT
39  * on older pthreads implementations
40  *
41  * This is excluded on SunOS due to it making the code compile in < XPG6 mode
42  * which is not supported with a C99 compiler.
43  */
44 #if !defined(__sun) && !defined(__DragonFly__)
45 #define _XOPEN_SOURCE 700
46 #endif
47 
48 /*
49  * This is needed to expose issetugid, getresuid, and getresgid, which are
50  * hidden with the _XOPEN_SOURCE setting above
51  */
52 #ifdef __FreeBSD__
53 #undef __BSD_VISIBLE
54 #define __BSD_VISIBLE 1
55 #endif
56 
57 #include "compat.h"
58 #include "debug.h"
59 
60 #include <assert.h>
61 #include <dirent.h>
62 #include <errno.h>
63 #include <stdint.h>
64 #include <stdlib.h>
65 #include <string.h>
66 #ifdef OS_UNIX
67 #include <unistd.h>
68 #endif
69 
70 /*-
71  * Portions of this file are covered by the following copyright:
72  *
73  * Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
74  * Copyright (c) 1990, 1993
75  * Copyright (c) 1987, 1993
76  *      The Regents of the University of California.  All rights reserved.
77  *
78  * This code is derived from software contributed to Berkeley by
79  * Chris Torek.
80  *
81  * Redistribution and use in source and binary forms, with or without
82  * modification, are permitted provided that the following conditions
83  * are met:
84  * 1. Redistributions of source code must retain the above copyright
85  *    notice, this list of conditions and the following disclaimer.
86  * 2. Redistributions in binary form must reproduce the above copyright
87  *    notice, this list of conditions and the following disclaimer in the
88  *    documentation and/or other materials provided with the distribution.
89  * 4. Neither the name of the University nor the names of its contributors
90  *    may be used to endorse or promote products derived from this software
91  *    without specific prior written permission.
92  *
93  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
94  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
95  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
96  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
97  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
98  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
99  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
100  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
101  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
102  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
103  * SUCH DAMAGE.
104  */
105 
106 #ifndef HAVE_GETPROGNAME
107 
108 #ifdef OS_UNIX
109 
110 #if defined (HAVE_PROGRAM_INVOCATION_SHORT_NAME) && !HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME
111 extern char *program_invocation_short_name;
112 #endif
113 
114 #if defined (HAVE___PROGNAME) && !HAVE_DECL___PROGNAME
115 extern char *__progname;
116 #endif
117 
118 #ifdef __linux__
119 /* This symbol is also defined in library.c so as to be freed by the library
120  * destructor.  If weak symbols are not supported nor library.c is not linked we
121  * simply leak the memory allocated with realpath().  */
122 #ifdef __GNUC__
123 extern char *p11_program_realpath;
124 
125 char *p11_program_realpath __attribute__((weak));
126 #else
127 static char *p11_program_realpath;
128 #endif
129 #endif
130 
131 const char *
getprogname(void)132 getprogname (void)
133 {
134 	const char *name;
135 
136 #if defined (HAVE_GETEXECNAME)
137 	const char *p;
138 	name = getexecname();
139 	p = strrchr (name ? name : "", '/');
140 	if (p != NULL)
141 		name = p + 1;
142 #elif defined (HAVE_PROGRAM_INVOCATION_SHORT_NAME)
143 #ifdef __linux__
144 	name = program_invocation_name;
145 	assert (name);
146 	if (*name == '/') {
147 		/*
148 		 * Some programs pack command line arguments into argv[0].
149 		 * Check if it is the case by reading /proc/self/exe and extract
150 		 * the program name.
151 		 *
152 		 * Logic borrowed from:
153 		 * <https://github.com/mesa3d/mesa/commit/759b94038987bb983398cd4b1d2cb1c8f79817a9>.
154 		 */
155 		if (!p11_program_realpath)
156 			p11_program_realpath = realpath ("/proc/self/exe", NULL);
157 
158 		if (p11_program_realpath &&
159 		    strncmp (p11_program_realpath, name,
160 			     strlen (p11_program_realpath)) == 0)
161 			/* Use the executable path if the prefix matches. */
162 			name = strrchr (p11_program_realpath, '/') + 1;
163 		else
164 			/* Otherwise fall back to
165 			 * program_invocation_short_name. */
166 			name = program_invocation_short_name;
167 	} else {
168 		name = program_invocation_short_name;
169 	}
170 #else
171 	name = program_invocation_short_name;
172 #endif
173 #elif defined (HAVE___PROGNAME)
174 	name = __progname;
175 #else
176 	#error No way to retrieve short program name
177 #endif
178 
179 	return name;
180 }
181 
182 #else /* OS_WIN32 */
183 
184 extern char **__argv;
185 static char prognamebuf[256];
186 
187 const char *
getprogname(void)188 getprogname (void)
189 {
190 	const char *name;
191 	const char *p, *p2;
192 	size_t length;
193 
194 	name = __argv[0];
195 	if (name == NULL)
196 		return NULL;
197 
198 	p = strrchr (name, '\\');
199 	p2 = strrchr (name, '/');
200 	if (p2 > p)
201 		p = p2;
202 	if (p != NULL)
203 		name = p + 1;
204 
205 	length = sizeof (prognamebuf) - 1;
206 	strncpy (prognamebuf, name, length);
207 	prognamebuf[length] = 0;
208 	length = strlen (prognamebuf);
209 	if (length > 4 && _stricmp (prognamebuf + (length - 4), ".exe") == 0)
210 		prognamebuf[length - 4] = '\0';
211 
212 	return prognamebuf;
213 }
214 
215 #endif /* OS_WIN32 */
216 
217 #endif /* HAVE_GETPROGNAME */
218 
219 #ifdef OS_UNIX
220 #include <sys/stat.h>
221 #include <sys/mman.h>
222 #include <fcntl.h>
223 #include <unistd.h>
224 
225 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
226 void
p11_recursive_mutex_init(p11_mutex_t * mutex)227 p11_recursive_mutex_init (p11_mutex_t *mutex)
228 {
229 	pthread_mutexattr_t attr;
230 	int ret;
231 
232 	pthread_mutexattr_init (&attr);
233 	pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
234 	ret = pthread_mutex_init (mutex, &attr);
235 	assert (ret == 0);
236 	pthread_mutexattr_destroy (&attr);
237 }
238 #endif
239 
240 char *
p11_dl_error(void)241 p11_dl_error (void)
242 {
243 	const char *msg = dlerror ();
244 	return msg ? strdup (msg) : NULL;
245 }
246 
247 struct _p11_mmap {
248 	int fd;
249 	void *data;
250 	size_t size;
251 };
252 
253 p11_mmap *
p11_mmap_open(const char * path,struct stat * sb,void ** data,size_t * size)254 p11_mmap_open (const char *path,
255                struct stat *sb,
256                void **data,
257                size_t *size)
258 {
259 	struct stat stb;
260 	p11_mmap *map;
261 
262 	map = calloc (1, sizeof (p11_mmap));
263 	if (map == NULL)
264 		return NULL;
265 
266 	map->fd = open (path, O_RDONLY | O_CLOEXEC);
267 	if (map->fd == -1) {
268 		free (map);
269 		return NULL;
270 	}
271 
272 	if (sb == NULL) {
273 		sb = &stb;
274 		if (fstat (map->fd, &stb) < 0) {
275 			close (map->fd);
276 			free (map);
277 			return NULL;
278 		}
279 	}
280 
281 	/* Workaround for broken ZFS on Linux */
282 	if (S_ISDIR (sb->st_mode)) {
283 		errno = EISDIR;
284 		close (map->fd);
285 		free (map);
286 		return NULL;
287 	}
288 
289 	if (sb->st_size == 0) {
290 		*data = "";
291 		*size = 0;
292 		return map;
293 	}
294 
295 	map->size = sb->st_size;
296 	map->data = mmap (NULL, map->size, PROT_READ, MAP_PRIVATE, map->fd, 0);
297 	if (map->data == MAP_FAILED) {
298 		close (map->fd);
299 		free (map);
300 		return NULL;
301 	}
302 
303 	*data = map->data;
304 	*size = map->size;
305 	return map;
306 }
307 
308 void
p11_mmap_close(p11_mmap * map)309 p11_mmap_close (p11_mmap *map)
310 {
311 	if (map->size)
312 		munmap (map->data, map->size);
313 	close (map->fd);
314 	free (map);
315 }
316 
317 #endif /* OS_UNIX */
318 
319 #ifdef OS_WIN32
320 
321 char *
p11_dl_error(void)322 p11_dl_error (void)
323 {
324 	DWORD code = GetLastError();
325 	LPVOID msg_buf;
326 	char *result;
327 
328 	FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
329 	                FORMAT_MESSAGE_FROM_SYSTEM |
330 	                FORMAT_MESSAGE_IGNORE_INSERTS,
331 	                NULL, code,
332 	                MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
333 	                (LPSTR)&msg_buf, 0, NULL);
334 
335 	result = strdup (msg_buf);
336 	LocalFree (msg_buf);
337 	return result;
338 }
339 
340 int
p11_thread_create(p11_thread_t * thread,p11_thread_routine routine,void * arg)341 p11_thread_create (p11_thread_t *thread,
342                    p11_thread_routine routine,
343                    void *arg)
344 {
345 	assert (thread);
346 
347 	*thread = CreateThread (NULL, 0,
348 	                        (LPTHREAD_START_ROUTINE)routine,
349 	                        arg, 0, NULL);
350 
351 	if (*thread == NULL)
352 		return GetLastError ();
353 
354 	return 0;
355 }
356 
357 int
p11_thread_join(p11_thread_t thread)358 p11_thread_join (p11_thread_t thread)
359 {
360 	DWORD res;
361 
362 	res = WaitForSingleObject (thread, INFINITE);
363 	if (res == WAIT_FAILED)
364 		return GetLastError ();
365 
366 	CloseHandle (thread);
367 	return 0;
368 }
369 
370 struct _p11_mmap {
371 	HANDLE file;
372 	HANDLE mapping;
373 	void *data;
374 };
375 
376 p11_mmap *
p11_mmap_open(const char * path,struct stat * sb,void ** data,size_t * size)377 p11_mmap_open (const char *path,
378                struct stat *sb,
379                void **data,
380                size_t *size)
381 {
382 	HANDLE mapping;
383 	LARGE_INTEGER large;
384 	DWORD errn;
385 	p11_mmap *map;
386 
387 	map = calloc (1, sizeof (p11_mmap));
388 	if (map == NULL) {
389 		errno = ENOMEM;
390 		return NULL;
391 	}
392 
393 	map->file  = CreateFile (path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
394 	if (map->file == INVALID_HANDLE_VALUE) {
395 		errn = GetLastError ();
396 		free (map);
397 		SetLastError (errn);
398 		if (errn == ERROR_PATH_NOT_FOUND || errn == ERROR_FILE_NOT_FOUND)
399 			errno = ENOENT;
400 		else if (errn == ERROR_ACCESS_DENIED)
401 			errno = EPERM;
402 		return NULL;
403 	}
404 
405 	if (sb == NULL) {
406 		if (!GetFileSizeEx (map->file, &large)) {
407 			errn = GetLastError ();
408 			CloseHandle (map->file);
409 			free (map);
410 			SetLastError (errn);
411 			if (errn == ERROR_ACCESS_DENIED)
412 				errno = EPERM;
413 			return NULL;
414 		}
415 	} else {
416 		large.QuadPart = sb->st_size;
417 	}
418 
419 	mapping = CreateFileMapping (map->file, NULL, PAGE_READONLY, 0, 0, NULL);
420 	if (!mapping) {
421 		errn = GetLastError ();
422 		CloseHandle (map->file);
423 		free (map);
424 		SetLastError (errn);
425 		if (errn == ERROR_ACCESS_DENIED)
426 			errno = EPERM;
427 		return NULL;
428 	}
429 
430 	map->data = MapViewOfFile (mapping, FILE_MAP_READ, 0, 0, large.QuadPart);
431 	CloseHandle (mapping);
432 
433 	if (map->data == NULL) {
434 		errn = GetLastError ();
435 		CloseHandle (map->file);
436 		free (map);
437 		SetLastError (errn);
438 		if (errn == ERROR_ACCESS_DENIED)
439 			errno = EPERM;
440 		return NULL;
441 	}
442 
443 	*data = map->data;
444 	*size = large.QuadPart;
445 	return map;
446 }
447 
448 void
p11_mmap_close(p11_mmap * map)449 p11_mmap_close (p11_mmap *map)
450 {
451 	UnmapViewOfFile (map->data);
452 	CloseHandle (map->file);
453 	free (map);
454 }
455 
456 #endif /* OS_WIN32 */
457 
458 #ifndef HAVE_STRNSTR
459 #include <string.h>
460 
461 /*
462  * Find the first occurrence of find in s, where the search is limited to the
463  * first slen characters of s.
464  */
465 char *
strnstr(const char * s,const char * find,size_t slen)466 strnstr (const char *s,
467          const char *find,
468          size_t slen)
469 {
470 	char c, sc;
471 	size_t len;
472 
473 	if ((c = *find++) != '\0') {
474 		len = strlen (find);
475 		do {
476 			do {
477 				if (slen-- < 1 || (sc = *s++) == '\0')
478 					return (NULL);
479 			} while (sc != c);
480 			if (len > slen)
481 				return (NULL);
482 		} while (strncmp(s, find, len) != 0);
483 		s--;
484 	}
485 	return ((char *)s);
486 }
487 
488 #endif /* HAVE_STRNSTR */
489 
490 #ifndef HAVE_MEMDUP
491 
492 void *
memdup(const void * data,size_t length)493 memdup (const void *data,
494         size_t length)
495 {
496 	void *dup;
497 
498 	if (!data)
499 		return NULL;
500 
501 	dup = malloc (length);
502 	if (dup != NULL)
503 		memcpy (dup, data, length);
504 
505 	return dup;
506 }
507 
508 #endif /* HAVE_MEMDUP */
509 
510 /*
511  * WORKAROUND: So in lots of released builds of firefox a completely broken strndup()
512  * is present. It does not NULL terminate its string output. It is unconditionally
513  * defined, and overrides the libc strndup() function on platforms where it
514  * exists as a function. For this reason we (for now) unconditionally define
515  * strndup().
516  */
517 
518 #if 1 /* #ifndef HAVE_STRNDUP */
519 
520 /*
521  * HAVE_STRNDUP may be undefined if strndup() isn't working. So it may be
522  * present, and yet strndup may still be a defined header macro.
523  */
524 #ifdef strndup
525 #undef strndup
526 #endif
527 
528 char *
529 strndup (const char *data,
530          size_t length);
531 
532 char *
strndup(const char * data,size_t length)533 strndup (const char *data,
534          size_t length)
535 {
536 	char *ret;
537 
538 	ret = malloc (length + 1);
539 	if (ret != NULL) {
540 		strncpy (ret, data, length);
541 		ret[length] = 0;
542 	}
543 
544 	return ret;
545 }
546 
547 #endif /* HAVE_STRNDUP */
548 
549 #ifndef HAVE_REALLOCARRAY
550 
551 void *
reallocarray(void * ptr,size_t nmemb,size_t size)552 reallocarray (void *ptr,
553 	      size_t nmemb,
554 	      size_t size)
555 {
556 	assert (nmemb >= 0 && size >= 0);
557 	if (nmemb != 0 && SIZE_MAX / nmemb < size) {
558 		errno = ENOMEM;
559 		return NULL;
560 	}
561 	return realloc (ptr, nmemb * size);
562 }
563 
564 #endif /* HAVE_MEMDUP */
565 
566 #ifndef HAVE_STRCONCAT
567 
568 #include <stdarg.h>
569 
570 char *
strconcat(const char * first,...)571 strconcat (const char *first,
572            ...)
573 {
574 	size_t length = 0;
575 	const char *arg;
576 	char *result, *at;
577 	va_list va;
578 
579 	va_start (va, first);
580 
581 	for (arg = first; arg; arg = va_arg (va, const char*)) {
582 		size_t old_length = length;
583 		length += strlen (arg);
584 		if (length < old_length) {
585 			va_end (va);
586 			return_val_if_reached (NULL);
587 		}
588 	}
589 
590 	va_end (va);
591 
592 	at = result = malloc (length + 1);
593 	if (result == NULL)
594 	       return NULL;
595 
596 	va_start (va, first);
597 
598 	for (arg = first; arg; arg = va_arg (va, const char*)) {
599 	       length = strlen (arg);
600 	       memcpy (at, arg, length);
601 	       at += length;
602 	}
603 
604 	va_end (va);
605 
606 	*at = 0;
607 	return result;
608 }
609 
610 #endif /* HAVE_STRCONCAT */
611 
612 #ifndef HAVE_VASPRINTF
613 #include <stdio.h>
614 
615 int vasprintf(char **strp, const char *fmt, va_list ap);
616 
617 int
vasprintf(char ** strp,const char * fmt,va_list ap)618 vasprintf (char **strp,
619            const char *fmt,
620            va_list ap)
621 {
622 	char *buf = NULL;
623 	char *nbuf;
624 	int guess = 128;
625 	int length = 0;
626 	va_list orig, aq;
627 	int ret;
628 
629 	if (fmt == NULL) {
630 		errno = EINVAL;
631 		return -1;
632 	}
633 
634 	va_copy (orig, ap);
635 	for (;;) {
636 		nbuf = realloc (buf, guess);
637 		if (!nbuf) {
638 			free (buf);
639 			va_end (orig);
640 			return -1;
641 		}
642 
643 		buf = nbuf;
644 		length = guess;
645 
646 		va_copy (aq, orig);
647 		ret = vsnprintf (buf, length, fmt, aq);
648 		va_end (aq);
649 
650 		if (ret < 0)
651 			guess *= 2;
652 
653 		else if (ret >= length)
654 			guess = ret + 1;
655 
656 		else
657 			break;
658 	}
659 	va_end (orig);
660 
661 	*strp = buf;
662 	return ret;
663 }
664 
665 #endif /* HAVE_VASPRINTF */
666 
667 #ifndef HAVE_ASPRINTF
668 
669 int asprintf(char **strp, const char *fmt, ...);
670 
671 int
asprintf(char ** strp,const char * fmt,...)672 asprintf (char **strp,
673           const char *fmt,
674           ...)
675 {
676 	va_list va;
677 	int ret;
678 
679 	va_start (va, fmt);
680 	ret = vasprintf (strp, fmt, va);
681 	va_end (va);
682 
683 	return ret;
684 }
685 
686 #endif /* HAVE_ASPRINTF */
687 
688 #ifndef HAVE_GMTIME_R
689 
690 struct tm *
gmtime_r(const time_t * timep,struct tm * result)691 gmtime_r (const time_t *timep,
692           struct tm *result)
693 {
694 #ifdef OS_WIN32
695 	/*
696 	 * On win32 gmtime() returns thread local storage, so we can
697 	 * just copy it out into the buffer without worrying about races.
698 	 */
699 	struct tm *tg;
700 	tg = gmtime (timep);
701 	if (!tg)
702 		return NULL;
703 	memcpy (result, tg, sizeof (struct tm));
704 	return result;
705 #else
706 	#error Need either gmtime_r() function on Unix
707 #endif
708 }
709 
710 #endif /* HAVE_GMTIME_R */
711 
712 #if !defined(HAVE_MKDTEMP) || !defined(HAVE_MKSTEMP)
713 #include <sys/stat.h>
714 #include <fcntl.h>
715 
716 static int
_gettemp(char * path,int * doopen,int domkdir,int slen)717 _gettemp (char *path,
718           int *doopen,
719           int domkdir,
720           int slen)
721 {
722 	static const char padchar[] =
723 		"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
724 	static const int maxpathlen = 1024;
725 
726 	char *start, *trv, *suffp, *carryp;
727 	char *pad;
728 	struct stat sbuf;
729 	int rval;
730 	int rnd;
731 	char carrybuf[maxpathlen];
732 
733 	if ((doopen != NULL && domkdir) || slen < 0) {
734 		errno = EINVAL;
735 		return (0);
736 	}
737 
738 	for (trv = path; *trv != '\0'; ++trv)
739 		;
740 	if (trv - path >= maxpathlen) {
741 		errno = ENAMETOOLONG;
742 		return (0);
743 	}
744 	trv -= slen;
745 	suffp = trv;
746 	--trv;
747 	if (trv < path || NULL != strchr (suffp, '/')) {
748 		errno = EINVAL;
749 		return (0);
750 	}
751 
752 	/* Fill space with random characters */
753 	while (trv >= path && *trv == 'X') {
754 		rnd = rand () % (sizeof (padchar) - 1);
755 		*trv-- = padchar[rnd];
756 	}
757 	start = trv + 1;
758 
759 	/* save first combination of random characters */
760 	memcpy (carrybuf, start, suffp - start);
761 
762 	/*
763 	 * check the target directory.
764 	 */
765 	if (doopen != NULL || domkdir) {
766 		for (; trv > path; --trv) {
767 			if (*trv == '/') {
768 				*trv = '\0';
769 				rval = stat(path, &sbuf);
770 				*trv = '/';
771 				if (rval != 0)
772 					return (0);
773 				if (!S_ISDIR(sbuf.st_mode)) {
774 					errno = ENOTDIR;
775 					return (0);
776 				}
777 				break;
778 			}
779 		}
780 	}
781 
782 	for (;;) {
783 		if (doopen) {
784 			if ((*doopen = open (path, O_BINARY | O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0600)) >= 0)
785 				return (1);
786 			if (errno != EEXIST)
787 				return (0);
788 		} else if (domkdir) {
789 #ifdef OS_UNIX
790 			if (mkdir (path, 0700) == 0)
791 #else
792 			if (mkdir (path) == 0)
793 #endif
794 				return (1);
795 			if (errno != EEXIST)
796 				return (0);
797 #ifdef OS_UNIX
798 		} else if (lstat (path, &sbuf))
799 #else
800 		} else if (stat (path, &sbuf))
801 #endif
802 			return (errno == ENOENT);
803 
804 		/* If we have a collision, cycle through the space of filenames */
805 		for (trv = start, carryp = carrybuf;;) {
806 			/* have we tried all possible permutations? */
807 			if (trv == suffp)
808 				return (0); /* yes - exit with EEXIST */
809 			pad = strchr(padchar, *trv);
810 			if (pad == NULL) {
811 				/* this should never happen */
812 				errno = EIO;
813 				return (0);
814 			}
815 			/* increment character */
816 			*trv = (*++pad == '\0') ? padchar[0] : *pad;
817 			/* carry to next position? */
818 			if (*trv == *carryp) {
819 				/* increment position and loop */
820 				++trv;
821 				++carryp;
822 			} else {
823 				/* try with new name */
824 				break;
825 			}
826 		}
827 	}
828 
829 	/*NOTREACHED*/
830 }
831 
832 #endif /* !HAVE_MKDTEMP || !HAVE_MKSTEMP */
833 
834 #ifndef HAVE_MKSTEMP
835 
836 int
mkstemp(char * template)837 mkstemp (char *template)
838 {
839 	int fd;
840 
841 	return (_gettemp (template, &fd, 0, 0) ? fd : -1);
842 }
843 
844 #endif /* HAVE_MKSTEMP */
845 
846 #ifndef HAVE_MKDTEMP
847 
848 char *
mkdtemp(char * template)849 mkdtemp (char *template)
850 {
851 	return (_gettemp (template, (int *)NULL, 1, 0) ? template : (char *)NULL);
852 }
853 
854 #endif /* HAVE_MKDTEMP */
855 
856 #ifndef HAVE_GETAUXVAL
857 
858 unsigned long
getauxval(unsigned long type)859 getauxval (unsigned long type)
860 {
861 	static unsigned long secure = 0UL;
862 	static bool check_secure_initialized = false;
863 
864 	/*
865 	 * This is the only one our stand-in impl supports and is
866 	 * also the only type we define in compat.h header
867 	 */
868 	assert (type == AT_SECURE);
869 
870 	if (!check_secure_initialized) {
871 #if defined(HAVE___LIBC_ENABLE_SECURE)
872 		extern int __libc_enable_secure;
873 		secure = __libc_enable_secure;
874 
875 #elif defined(HAVE_ISSETUGID) && \
876 	!((defined __APPLE__ && defined __MACH__) || (defined __FreeBSD__) || (defined(__DragonFly__)))
877 		secure = issetugid ();
878 
879 #elif defined(OS_UNIX)
880 		uid_t ruid, euid, suid; /* Real, effective and saved user ID's */
881 		gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */
882 
883 #ifdef HAVE_GETRESUID
884 		if (getresuid (&ruid, &euid, &suid) != 0 ||
885 		    getresgid (&rgid, &egid, &sgid) != 0)
886 #endif /* HAVE_GETRESUID */
887 		{
888 			suid = ruid = getuid ();
889 			sgid = rgid = getgid ();
890 			euid = geteuid ();
891 			egid = getegid ();
892 		}
893 
894 		secure = (ruid != euid || ruid != suid ||
895 		          rgid != egid || rgid != sgid);
896 #endif /* OS_UNIX */
897 		check_secure_initialized = true;
898 	}
899 
900 	return secure;
901 }
902 
903 #endif /* HAVE_GETAUXVAL */
904 
905 char *
secure_getenv(const char * name)906 secure_getenv (const char *name)
907 {
908 	if (getauxval (AT_SECURE))
909 		return NULL;
910 	return getenv (name);
911 }
912 
913 #ifndef HAVE_STRERROR_R
914 
915 int
strerror_r(int errnum,char * buf,size_t buflen)916 strerror_r (int errnum,
917             char *buf,
918             size_t buflen)
919 {
920 #ifdef OS_WIN32
921 #if _WIN32_WINNT < 0x502 /* WinXP or older */
922 	int n = sys_nerr;
923 	const char *p;
924 	if (errnum < 0 || errnum >= n)
925 		p = sys_errlist[n];
926 	else
927 		p = sys_errlist[errnum];
928 	if (buf == NULL || buflen == 0)
929 		return EINVAL;
930 	strncpy(buf, p, buflen);
931 	buf[buflen-1] = 0;
932 	return 0;
933 #else /* Server 2003 or newer */
934 	return strerror_s (buf, buflen, errnum);
935 #endif /*_WIN32_WINNT*/
936 
937 #else
938 	#error no strerror_r implementation
939 #endif
940 }
941 
942 #endif /* HAVE_STRERROR_R */
943 
944 void
p11_dl_close(void * dl)945 p11_dl_close (void *dl)
946 {
947 #ifdef OS_WIN32
948 	FreeLibrary (dl);
949 #else
950 	(void) dlclose (dl);
951 #endif
952 }
953 
954 
955 #ifdef OS_UNIX
956 
957 #include <unistd.h>
958 
959 #ifndef HAVE_FDWALK
960 
961 #ifdef HAVE_SYS_RESOURCE_H
962 #include <sys/resource.h>
963 #endif
964 
965 int
fdwalk(int (* cb)(void * data,int fd),void * data)966 fdwalk (int (* cb) (void *data, int fd),
967         void *data)
968 {
969 	int open_max;
970 	int res = 0;
971 	int fd;
972 
973 #ifdef HAVE_SYS_RESOURCE_H
974 	struct rlimit rl;
975 #endif
976 
977 #ifdef __linux__
978 	DIR *dir;
979 
980 	dir = opendir ("/proc/self/fd");
981 	if (dir != NULL) {
982 		struct dirent *de;
983 
984 		while ((de = readdir (dir)) != NULL) {
985 			char *end;
986 			long num;
987 
988 			end = NULL;
989 			num = (int) strtol (de->d_name, &end, 10);
990 
991 			/* didn't parse or is the opendir() fd */
992 			if (!end || *end != '\0' ||
993 			    (int)num == dirfd (dir))
994 				continue;
995 
996 			fd = num;
997 
998 			/* call the callback */
999 			res = cb (data, fd);
1000 			if (res != 0)
1001 				break;
1002 		}
1003 
1004 		closedir (dir);
1005 		return res;
1006 	}
1007 #endif
1008 
1009 	/* No /proc, brute force */
1010 #ifdef HAVE_SYS_RESOURCE_H
1011 	if (getrlimit (RLIMIT_NOFILE, &rl) == 0 && rl.rlim_max != RLIM_INFINITY)
1012 		open_max = rl.rlim_max;
1013 	else
1014 #endif
1015 		open_max = sysconf (_SC_OPEN_MAX);
1016 
1017 	for (fd = 0; fd < open_max; fd++) {
1018 		res = cb (data, fd);
1019 		if (res != 0)
1020 			break;
1021 	}
1022 
1023 	return res;
1024 }
1025 
1026 #endif /* HAVE_FDWALK */
1027 
1028 #endif /* OS_UNIX */
1029 
1030 int
p11_ascii_tolower(int c)1031 p11_ascii_tolower (int c)
1032 {
1033 	if (c >= 'A' && c <= 'Z')
1034 		return 'a' + (c - 'A');
1035 	return c;
1036 }
1037 
1038 int
p11_ascii_toupper(int c)1039 p11_ascii_toupper (int c)
1040 {
1041 	if (c >= 'a' && c <= 'z')
1042 		return 'A' + (c - 'a');
1043 	return c;
1044 }
1045