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