Coverage Report

Created: 2025-08-26 06:26

/src/p11-kit/common/compat.c
Line
Count
Source (jump to first uncovered line)
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
#ifndef __sun
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 *
132
getprogname (void)
133
0
{
134
0
  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
0
  name = program_invocation_name;
145
0
  assert (name);
146
0
  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
0
    if (!p11_program_realpath)
156
0
      p11_program_realpath = realpath ("/proc/self/exe", NULL);
157
158
0
    if (p11_program_realpath &&
159
0
        strncmp (p11_program_realpath, name,
160
0
           strlen (p11_program_realpath)) == 0)
161
      /* Use the executable path if the prefix matches. */
162
0
      name = strrchr (p11_program_realpath, '/') + 1;
163
0
    else
164
      /* Otherwise fall back to
165
       * program_invocation_short_name. */
166
0
      name = program_invocation_short_name;
167
0
  } else {
168
0
    name = program_invocation_short_name;
169
0
  }
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
0
  return name;
180
0
}
181
182
#else /* OS_WIN32 */
183
184
extern char **__argv;
185
static char prognamebuf[256];
186
187
const char *
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
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 *
241
p11_dl_error (void)
242
0
{
243
0
  const char *msg = dlerror ();
244
0
  return msg ? strdup (msg) : NULL;
245
0
}
246
247
struct _p11_mmap {
248
  int fd;
249
  void *data;
250
  size_t size;
251
};
252
253
p11_mmap *
254
p11_mmap_open (const char *path,
255
               struct stat *sb,
256
               void **data,
257
               size_t *size)
258
0
{
259
0
  struct stat stb;
260
0
  p11_mmap *map;
261
262
0
  map = calloc (1, sizeof (p11_mmap));
263
0
  if (map == NULL)
264
0
    return NULL;
265
266
0
  map->fd = open (path, O_RDONLY | O_CLOEXEC);
267
0
  if (map->fd == -1) {
268
0
    free (map);
269
0
    return NULL;
270
0
  }
271
272
0
  if (sb == NULL) {
273
0
    sb = &stb;
274
0
    if (fstat (map->fd, &stb) < 0) {
275
0
      close (map->fd);
276
0
      free (map);
277
0
      return NULL;
278
0
    }
279
0
  }
280
281
  /* Workaround for broken ZFS on Linux */
282
0
  if (S_ISDIR (sb->st_mode)) {
283
0
    errno = EISDIR;
284
0
    close (map->fd);
285
0
    free (map);
286
0
    return NULL;
287
0
  }
288
289
0
  if (sb->st_size == 0) {
290
0
    *data = "";
291
0
    *size = 0;
292
0
    return map;
293
0
  }
294
295
0
  map->size = sb->st_size;
296
0
  map->data = mmap (NULL, map->size, PROT_READ, MAP_PRIVATE, map->fd, 0);
297
0
  if (map->data == MAP_FAILED) {
298
0
    close (map->fd);
299
0
    free (map);
300
0
    return NULL;
301
0
  }
302
303
0
  *data = map->data;
304
0
  *size = map->size;
305
0
  return map;
306
0
}
307
308
void
309
p11_mmap_close (p11_mmap *map)
310
0
{
311
0
  if (map->size)
312
0
    munmap (map->data, map->size);
313
0
  close (map->fd);
314
0
  free (map);
315
0
}
316
317
#endif /* OS_UNIX */
318
319
#ifdef OS_WIN32
320
321
char *
322
p11_dl_error (void)
323
{
324
  DWORD code = GetLastError();
325
  LPVOID msg_buf = NULL;
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
  if (msg_buf == NULL)
336
    return NULL;
337
338
  result = strdup (msg_buf);
339
  LocalFree (msg_buf);
340
  return result;
341
}
342
343
int
344
p11_thread_create (p11_thread_t *thread,
345
                   p11_thread_routine routine,
346
                   void *arg)
347
{
348
  assert (thread);
349
350
  *thread = CreateThread (NULL, 0,
351
                          (LPTHREAD_START_ROUTINE)routine,
352
                          arg, 0, NULL);
353
354
  if (*thread == NULL)
355
    return GetLastError ();
356
357
  return 0;
358
}
359
360
int
361
p11_thread_join (p11_thread_t thread)
362
{
363
  DWORD res;
364
365
  res = WaitForSingleObject (thread, INFINITE);
366
  if (res == WAIT_FAILED)
367
    return GetLastError ();
368
369
  CloseHandle (thread);
370
  return 0;
371
}
372
373
struct _p11_mmap {
374
  HANDLE file;
375
  HANDLE mapping;
376
  void *data;
377
};
378
379
p11_mmap *
380
p11_mmap_open (const char *path,
381
               struct stat *sb,
382
               void **data,
383
               size_t *size)
384
{
385
  HANDLE mapping;
386
  LARGE_INTEGER large;
387
  DWORD errn;
388
  p11_mmap *map;
389
390
  map = calloc (1, sizeof (p11_mmap));
391
  if (map == NULL) {
392
    errno = ENOMEM;
393
    return NULL;
394
  }
395
396
  map->file  = CreateFile (path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
397
  if (map->file == INVALID_HANDLE_VALUE) {
398
    errn = GetLastError ();
399
    free (map);
400
    SetLastError (errn);
401
    if (errn == ERROR_PATH_NOT_FOUND || errn == ERROR_FILE_NOT_FOUND)
402
      errno = ENOENT;
403
    else if (errn == ERROR_ACCESS_DENIED)
404
      errno = EPERM;
405
    return NULL;
406
  }
407
408
  if (sb == NULL) {
409
    if (!GetFileSizeEx (map->file, &large)) {
410
      errn = GetLastError ();
411
      CloseHandle (map->file);
412
      free (map);
413
      SetLastError (errn);
414
      if (errn == ERROR_ACCESS_DENIED)
415
        errno = EPERM;
416
      return NULL;
417
    }
418
  } else {
419
    large.QuadPart = sb->st_size;
420
  }
421
422
  mapping = CreateFileMapping (map->file, NULL, PAGE_READONLY, 0, 0, NULL);
423
  if (!mapping) {
424
    errn = GetLastError ();
425
    CloseHandle (map->file);
426
    free (map);
427
    SetLastError (errn);
428
    if (errn == ERROR_ACCESS_DENIED)
429
      errno = EPERM;
430
    return NULL;
431
  }
432
433
  map->data = MapViewOfFile (mapping, FILE_MAP_READ, 0, 0, large.QuadPart);
434
  CloseHandle (mapping);
435
436
  if (map->data == NULL) {
437
    errn = GetLastError ();
438
    CloseHandle (map->file);
439
    free (map);
440
    SetLastError (errn);
441
    if (errn == ERROR_ACCESS_DENIED)
442
      errno = EPERM;
443
    return NULL;
444
  }
445
446
  *data = map->data;
447
  *size = large.QuadPart;
448
  return map;
449
}
450
451
void
452
p11_mmap_close (p11_mmap *map)
453
{
454
  UnmapViewOfFile (map->data);
455
  CloseHandle (map->file);
456
  free (map);
457
}
458
459
#endif /* OS_WIN32 */
460
461
#ifndef HAVE_STRNSTR
462
#include <string.h>
463
464
/*
465
 * Find the first occurrence of find in s, where the search is limited to the
466
 * first slen characters of s.
467
 */
468
char *
469
strnstr (const char *s,
470
         const char *find,
471
         size_t slen)
472
0
{
473
0
  char c, sc;
474
0
  size_t len;
475
476
0
  if ((c = *find++) != '\0') {
477
0
    len = strlen (find);
478
0
    do {
479
0
      do {
480
0
        if (slen-- < 1 || (sc = *s++) == '\0')
481
0
          return (NULL);
482
0
      } while (sc != c);
483
0
      if (len > slen)
484
0
        return (NULL);
485
0
    } while (strncmp(s, find, len) != 0);
486
0
    s--;
487
0
  }
488
0
  return ((char *)s);
489
0
}
490
491
#endif /* HAVE_STRNSTR */
492
493
#ifndef HAVE_MEMDUP
494
495
void *
496
memdup (const void *data,
497
        size_t length)
498
0
{
499
0
  void *dup;
500
501
0
  if (!data)
502
0
    return NULL;
503
504
0
  dup = malloc (length);
505
0
  if (dup != NULL)
506
0
    memcpy (dup, data, length);
507
508
0
  return dup;
509
0
}
510
511
#endif /* HAVE_MEMDUP */
512
513
/*
514
 * WORKAROUND: So in lots of released builds of firefox a completely broken strndup()
515
 * is present. It does not NULL terminate its string output. It is unconditionally
516
 * defined, and overrides the libc strndup() function on platforms where it
517
 * exists as a function. For this reason we (for now) unconditionally define
518
 * strndup().
519
 */
520
521
#if 1 /* #ifndef HAVE_STRNDUP */
522
523
/*
524
 * HAVE_STRNDUP may be undefined if strndup() isn't working. So it may be
525
 * present, and yet strndup may still be a defined header macro.
526
 */
527
#ifdef strndup
528
#undef strndup
529
#endif
530
531
char *
532
strndup (const char *data,
533
         size_t length);
534
535
char *
536
strndup (const char *data,
537
         size_t length)
538
0
{
539
0
  char *ret;
540
541
0
  ret = malloc (length + 1);
542
0
  if (ret != NULL) {
543
0
    strncpy (ret, data, length);
544
0
    ret[length] = 0;
545
0
  }
546
547
0
  return ret;
548
0
}
549
550
#endif /* HAVE_STRNDUP */
551
552
#ifndef HAVE_REALLOCARRAY
553
554
void *
555
reallocarray (void *ptr,
556
        size_t nmemb,
557
        size_t size)
558
{
559
  assert (nmemb >= 0 && size >= 0);
560
  if (nmemb != 0 && SIZE_MAX / nmemb < size) {
561
    errno = ENOMEM;
562
    return NULL;
563
  }
564
  return realloc (ptr, nmemb * size);
565
}
566
567
#endif /* HAVE_MEMDUP */
568
569
#ifndef HAVE_STRCONCAT
570
571
#include <stdarg.h>
572
573
char *
574
strconcat (const char *first,
575
           ...)
576
0
{
577
0
  size_t length = 0;
578
0
  const char *arg;
579
0
  char *result, *at;
580
0
  va_list va;
581
582
0
  va_start (va, first);
583
584
0
  for (arg = first; arg; arg = va_arg (va, const char*)) {
585
0
    size_t old_length = length;
586
0
    length += strlen (arg);
587
0
    if (length < old_length) {
588
0
      va_end (va);
589
0
      return_val_if_reached (NULL);
590
0
    }
591
0
  }
592
593
0
  va_end (va);
594
595
0
  at = result = malloc (length + 1);
596
0
  if (result == NULL)
597
0
         return NULL;
598
599
0
  va_start (va, first);
600
601
0
  for (arg = first; arg; arg = va_arg (va, const char*)) {
602
0
         length = strlen (arg);
603
0
         memcpy (at, arg, length);
604
0
         at += length;
605
0
  }
606
607
0
  va_end (va);
608
609
0
  *at = 0;
610
0
  return result;
611
0
}
612
613
#endif /* HAVE_STRCONCAT */
614
615
#ifndef HAVE_VASPRINTF
616
#include <stdio.h>
617
618
int vasprintf(char **strp, const char *fmt, va_list ap);
619
620
int
621
vasprintf (char **strp,
622
           const char *fmt,
623
           va_list ap)
624
{
625
  char *buf = NULL;
626
  char *nbuf;
627
  int guess = 128;
628
  int length = 0;
629
  va_list orig, aq;
630
  int ret;
631
632
  if (fmt == NULL) {
633
    errno = EINVAL;
634
    return -1;
635
  }
636
637
  va_copy (orig, ap);
638
  for (;;) {
639
    nbuf = realloc (buf, guess);
640
    if (!nbuf) {
641
      free (buf);
642
      va_end (orig);
643
      return -1;
644
    }
645
646
    buf = nbuf;
647
    length = guess;
648
649
    va_copy (aq, orig);
650
    ret = vsnprintf (buf, length, fmt, aq);
651
    va_end (aq);
652
653
    if (ret < 0)
654
      guess *= 2;
655
656
    else if (ret >= length)
657
      guess = ret + 1;
658
659
    else
660
      break;
661
  }
662
  va_end (orig);
663
664
  *strp = buf;
665
  return ret;
666
}
667
668
#endif /* HAVE_VASPRINTF */
669
670
#ifndef HAVE_ASPRINTF
671
672
int asprintf(char **strp, const char *fmt, ...);
673
674
int
675
asprintf (char **strp,
676
          const char *fmt,
677
          ...)
678
{
679
  va_list va;
680
  int ret;
681
682
  va_start (va, fmt);
683
  ret = vasprintf (strp, fmt, va);
684
  va_end (va);
685
686
  return ret;
687
}
688
689
#endif /* HAVE_ASPRINTF */
690
691
#ifndef HAVE_GMTIME_R
692
693
struct tm *
694
gmtime_r (const time_t *timep,
695
          struct tm *result)
696
{
697
#ifdef OS_WIN32
698
  /*
699
   * On win32 gmtime() returns thread local storage, so we can
700
   * just copy it out into the buffer without worrying about races.
701
   */
702
  struct tm *tg;
703
  tg = gmtime (timep);
704
  if (!tg)
705
    return NULL;
706
  memcpy (result, tg, sizeof (struct tm));
707
  return result;
708
#else
709
  #error Need either gmtime_r() function on Unix
710
#endif
711
}
712
713
#endif /* HAVE_GMTIME_R */
714
715
#if !defined(HAVE_MKDTEMP) || !defined(HAVE_MKSTEMP)
716
#include <sys/stat.h>
717
#include <fcntl.h>
718
719
static int
720
_gettemp (char *path,
721
          int *doopen,
722
          int domkdir,
723
          int slen)
724
{
725
  static const char padchar[] =
726
    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
727
  static const int maxpathlen = 1024;
728
729
  char *start, *trv, *suffp, *carryp;
730
  char *pad;
731
  struct stat sbuf;
732
  int rval;
733
  int rnd;
734
  char carrybuf[maxpathlen];
735
736
  if ((doopen != NULL && domkdir) || slen < 0) {
737
    errno = EINVAL;
738
    return (0);
739
  }
740
741
  for (trv = path; *trv != '\0'; ++trv)
742
    ;
743
  if (trv - path >= maxpathlen) {
744
    errno = ENAMETOOLONG;
745
    return (0);
746
  }
747
  trv -= slen;
748
  suffp = trv;
749
  --trv;
750
  if (trv < path || NULL != strchr (suffp, '/')) {
751
    errno = EINVAL;
752
    return (0);
753
  }
754
755
  /* Fill space with random characters */
756
  while (trv >= path && *trv == 'X') {
757
    rnd = rand () % (sizeof (padchar) - 1);
758
    *trv-- = padchar[rnd];
759
  }
760
  start = trv + 1;
761
762
  /* save first combination of random characters */
763
  memcpy (carrybuf, start, suffp - start);
764
765
  /*
766
   * check the target directory.
767
   */
768
  if (doopen != NULL || domkdir) {
769
    for (; trv > path; --trv) {
770
      if (*trv == '/') {
771
        *trv = '\0';
772
        rval = stat(path, &sbuf);
773
        *trv = '/';
774
        if (rval != 0)
775
          return (0);
776
        if (!S_ISDIR(sbuf.st_mode)) {
777
          errno = ENOTDIR;
778
          return (0);
779
        }
780
        break;
781
      }
782
    }
783
  }
784
785
  for (;;) {
786
    if (doopen) {
787
      if ((*doopen = open (path, O_BINARY | O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0600)) >= 0)
788
        return (1);
789
      if (errno != EEXIST)
790
        return (0);
791
    } else if (domkdir) {
792
#ifdef OS_UNIX
793
      if (mkdir (path, 0700) == 0)
794
#else
795
      if (mkdir (path) == 0)
796
#endif
797
        return (1);
798
      if (errno != EEXIST)
799
        return (0);
800
#ifdef OS_UNIX
801
    } else if (lstat (path, &sbuf))
802
#else
803
    } else if (stat (path, &sbuf))
804
#endif
805
      return (errno == ENOENT);
806
807
    /* If we have a collision, cycle through the space of filenames */
808
    for (trv = start, carryp = carrybuf;;) {
809
      /* have we tried all possible permutations? */
810
      if (trv == suffp)
811
        return (0); /* yes - exit with EEXIST */
812
      pad = strchr(padchar, *trv);
813
      if (pad == NULL) {
814
        /* this should never happen */
815
        errno = EIO;
816
        return (0);
817
      }
818
      /* increment character */
819
      *trv = (*++pad == '\0') ? padchar[0] : *pad;
820
      /* carry to next position? */
821
      if (*trv == *carryp) {
822
        /* increment position and loop */
823
        ++trv;
824
        ++carryp;
825
      } else {
826
        /* try with new name */
827
        break;
828
      }
829
    }
830
  }
831
832
  /*NOTREACHED*/
833
}
834
835
#endif /* !HAVE_MKDTEMP || !HAVE_MKSTEMP */
836
837
#ifndef HAVE_MKSTEMP
838
839
int
840
mkstemp (char *template)
841
{
842
  int fd;
843
844
  return (_gettemp (template, &fd, 0, 0) ? fd : -1);
845
}
846
847
#endif /* HAVE_MKSTEMP */
848
849
#ifndef HAVE_MKDTEMP
850
851
char *
852
mkdtemp (char *template)
853
{
854
  return (_gettemp (template, (int *)NULL, 1, 0) ? template : (char *)NULL);
855
}
856
857
#endif /* HAVE_MKDTEMP */
858
859
#ifndef HAVE_GETAUXVAL
860
861
unsigned long
862
_p11_getauxval (unsigned long type)
863
{
864
  static unsigned long secure = 0UL;
865
  static bool check_secure_initialized = false;
866
867
  /*
868
   * This is the only one our stand-in impl supports and is
869
   * also the only type we define in compat.h header
870
   */
871
  assert (type == AT_SECURE);
872
873
  if (!check_secure_initialized) {
874
#if defined(HAVE___LIBC_ENABLE_SECURE) && !defined(__GNU__)
875
    extern int __libc_enable_secure;
876
    secure = __libc_enable_secure;
877
878
#elif defined(HAVE_ISSETUGID) && \
879
  !((defined __APPLE__ && defined __MACH__) || (defined __FreeBSD__))
880
    secure = issetugid ();
881
882
#elif defined(OS_UNIX)
883
    uid_t ruid, euid, suid; /* Real, effective and saved user ID's */
884
    gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */
885
886
#ifdef HAVE_GETRESUID
887
    if (getresuid (&ruid, &euid, &suid) != 0 ||
888
        getresgid (&rgid, &egid, &sgid) != 0)
889
#endif /* HAVE_GETRESUID */
890
    {
891
      suid = ruid = getuid ();
892
      sgid = rgid = getgid ();
893
      euid = geteuid ();
894
      egid = getegid ();
895
    }
896
897
    secure = (ruid != euid || ruid != suid ||
898
              rgid != egid || rgid != sgid);
899
#endif /* OS_UNIX */
900
    check_secure_initialized = true;
901
  }
902
903
  return secure;
904
}
905
906
#endif /* HAVE_GETAUXVAL */
907
908
char *
909
secure_getenv (const char *name)
910
1.35k
{
911
1.35k
  if (_p11_getauxval (AT_SECURE))
912
0
    return NULL;
913
1.35k
  return getenv (name);
914
1.35k
}
915
916
#ifndef HAVE_ISATTY
917
918
int
919
isatty (int fd)
920
{
921
  return 0;
922
}
923
924
#endif /* HAVE_ISATTY */
925
926
void
927
p11_dl_close (void *dl)
928
0
{
929
#ifdef OS_WIN32
930
  FreeLibrary (dl);
931
#else
932
0
  (void) dlclose (dl);
933
0
#endif
934
0
}
935
936
937
#ifdef OS_UNIX
938
939
#include <unistd.h>
940
941
#ifndef HAVE_FDWALK
942
943
#ifdef HAVE_SYS_RESOURCE_H
944
#include <sys/resource.h>
945
#endif
946
947
int
948
fdwalk (int (* cb) (void *data, int fd),
949
        void *data)
950
0
{
951
0
  int open_max;
952
0
  int res = 0;
953
0
  int fd;
954
955
0
#ifdef HAVE_SYS_RESOURCE_H
956
0
  struct rlimit rl;
957
0
#endif
958
959
0
#ifdef __linux__
960
0
  DIR *dir;
961
962
0
  dir = opendir ("/proc/self/fd");
963
0
  if (dir != NULL) {
964
0
    struct dirent *de;
965
966
0
    while ((de = readdir (dir)) != NULL) {
967
0
      char *end;
968
0
      long num;
969
970
0
      end = NULL;
971
0
      num = (int) strtol (de->d_name, &end, 10);
972
973
      /* didn't parse or is the opendir() fd */
974
0
      if (!end || *end != '\0' ||
975
0
          (int)num == dirfd (dir))
976
0
        continue;
977
978
0
      fd = num;
979
980
      /* call the callback */
981
0
      res = cb (data, fd);
982
0
      if (res != 0)
983
0
        break;
984
0
    }
985
986
0
    closedir (dir);
987
0
    return res;
988
0
  }
989
0
#endif
990
991
  /* No /proc, brute force */
992
0
#ifdef HAVE_SYS_RESOURCE_H
993
0
  if (getrlimit (RLIMIT_NOFILE, &rl) == 0 && rl.rlim_max != RLIM_INFINITY)
994
0
    open_max = rl.rlim_max;
995
0
  else
996
0
#endif
997
0
    open_max = sysconf (_SC_OPEN_MAX);
998
999
0
  for (fd = 0; fd < open_max; fd++) {
1000
0
    res = cb (data, fd);
1001
0
    if (res != 0)
1002
0
      break;
1003
0
  }
1004
1005
0
  return res;
1006
0
}
1007
1008
#endif /* HAVE_FDWALK */
1009
1010
#endif /* OS_UNIX */
1011
1012
void
1013
p11_strerror_r (int errnum,
1014
    char *buf,
1015
    size_t buflen)
1016
0
{
1017
#if defined(HAVE_XSI_STRERROR_R)
1018
  strerror_r (errnum, buf, buflen);
1019
#elif defined(HAVE_GNU_STRERROR_R)
1020
  char *str = strerror_r (errnum, buf, buflen);
1021
0
  strncpy (buf, str, buflen);
1022
#elif defined(OS_WIN32)
1023
#if _WIN32_WINNT < 0x502 /* WinXP or older */
1024
  int n = sys_nerr;
1025
  const char *p;
1026
  if (errnum < 0 || errnum >= n)
1027
    p = sys_errlist[n];
1028
  else
1029
    p = sys_errlist[errnum];
1030
  if (buf == NULL || buflen == 0)
1031
    return;
1032
  strncpy(buf, p, buflen);
1033
  buf[buflen - 1] = '\0';
1034
#else /* Server 2003 or newer */
1035
  strerror_s (buf, buflen, errnum);
1036
#endif /* _WIN32_WINNT */
1037
#else
1038
  #error no strerror_r implementation
1039
#endif
1040
0
}
1041
1042
int
1043
p11_ascii_tolower (int c)
1044
0
{
1045
0
  if (c >= 'A' && c <= 'Z')
1046
0
    return 'a' + (c - 'A');
1047
0
  return c;
1048
0
}
1049
1050
int
1051
p11_ascii_toupper (int c)
1052
0
{
1053
0
  if (c >= 'a' && c <= 'z')
1054
0
    return 'A' + (c - 'a');
1055
0
  return c;
1056
0
}
1057
1058
bool
1059
p11_ascii_strcaseeq (const char *s1,
1060
         const char *s2)
1061
0
{
1062
0
  while (p11_ascii_tolower (*s1) == p11_ascii_tolower (*s2++))
1063
0
    if (*s1++ == '\0')
1064
0
      return true;
1065
0
  return false;
1066
0
}