Home | History | Annotate | Line # | Download | only in import
      1  1.1.1.2  christos /* Copyright (C) 1991-2022 Free Software Foundation, Inc.
      2      1.1  christos    This file is part of the GNU C Library.
      3      1.1  christos 
      4      1.1  christos    The GNU C Library is free software; you can redistribute it and/or
      5  1.1.1.2  christos    modify it under the terms of the GNU Lesser General Public
      6      1.1  christos    License as published by the Free Software Foundation; either
      7  1.1.1.2  christos    version 2.1 of the License, or (at your option) any later version.
      8      1.1  christos 
      9      1.1  christos    The GNU C Library is distributed in the hope that it will be useful,
     10      1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     11      1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  1.1.1.2  christos    Lesser General Public License for more details.
     13      1.1  christos 
     14  1.1.1.2  christos    You should have received a copy of the GNU Lesser General Public
     15      1.1  christos    License along with the GNU C Library; if not, see
     16      1.1  christos    <https://www.gnu.org/licenses/>.  */
     17      1.1  christos 
     18      1.1  christos #if !_LIBC
     19      1.1  christos # include <libc-config.h>
     20      1.1  christos # include "tempname.h"
     21      1.1  christos #endif
     22      1.1  christos 
     23      1.1  christos #include <sys/types.h>
     24      1.1  christos #include <assert.h>
     25  1.1.1.2  christos #include <stdbool.h>
     26      1.1  christos 
     27      1.1  christos #include <errno.h>
     28      1.1  christos 
     29      1.1  christos #include <stdio.h>
     30      1.1  christos #ifndef P_tmpdir
     31      1.1  christos # define P_tmpdir "/tmp"
     32      1.1  christos #endif
     33      1.1  christos #ifndef TMP_MAX
     34      1.1  christos # define TMP_MAX 238328
     35      1.1  christos #endif
     36      1.1  christos #ifndef __GT_FILE
     37      1.1  christos # define __GT_FILE      0
     38      1.1  christos # define __GT_DIR       1
     39      1.1  christos # define __GT_NOCREATE  2
     40      1.1  christos #endif
     41      1.1  christos #if !_LIBC && (GT_FILE != __GT_FILE || GT_DIR != __GT_DIR       \
     42      1.1  christos                || GT_NOCREATE != __GT_NOCREATE)
     43      1.1  christos # error report this to bug-gnulib@gnu.org
     44      1.1  christos #endif
     45      1.1  christos 
     46      1.1  christos #include <stddef.h>
     47      1.1  christos #include <stdlib.h>
     48      1.1  christos #include <string.h>
     49      1.1  christos 
     50      1.1  christos #include <fcntl.h>
     51  1.1.1.2  christos #include <stdalign.h>
     52      1.1  christos #include <stdint.h>
     53      1.1  christos #include <sys/random.h>
     54      1.1  christos #include <sys/stat.h>
     55  1.1.1.2  christos #include <time.h>
     56      1.1  christos 
     57      1.1  christos #if _LIBC
     58      1.1  christos # define struct_stat64 struct stat64
     59      1.1  christos # define __secure_getenv __libc_secure_getenv
     60      1.1  christos #else
     61      1.1  christos # define struct_stat64 struct stat
     62      1.1  christos # define __gen_tempname gen_tempname
     63      1.1  christos # define __mkdir mkdir
     64      1.1  christos # define __open open
     65  1.1.1.2  christos # define __lstat64(file, buf) lstat (file, buf)
     66  1.1.1.2  christos # define __stat64(file, buf) stat (file, buf)
     67  1.1.1.2  christos # define __getrandom getrandom
     68  1.1.1.2  christos # define __clock_gettime64 clock_gettime
     69  1.1.1.2  christos # define __timespec64 timespec
     70      1.1  christos #endif
     71      1.1  christos 
     72      1.1  christos /* Use getrandom if it works, falling back on a 64-bit linear
     73  1.1.1.2  christos    congruential generator that starts with Var's value
     74  1.1.1.2  christos    mixed in with a clock's low-order bits if available.  */
     75      1.1  christos typedef uint_fast64_t random_value;
     76  1.1.1.2  christos #define RANDOM_VALUE_MAX UINT_FAST64_MAX
     77  1.1.1.2  christos #define BASE_62_DIGITS 10 /* 62**10 < UINT_FAST64_MAX */
     78  1.1.1.2  christos #define BASE_62_POWER (62LL * 62 * 62 * 62 * 62 * 62 * 62 * 62 * 62 * 62)
     79  1.1.1.2  christos 
     80  1.1.1.2  christos static random_value
     81  1.1.1.2  christos random_bits (random_value var, bool use_getrandom)
     82  1.1.1.2  christos {
     83  1.1.1.2  christos   random_value r;
     84  1.1.1.2  christos   /* Without GRND_NONBLOCK it can be blocked for minutes on some systems.  */
     85  1.1.1.2  christos   if (use_getrandom && __getrandom (&r, sizeof r, GRND_NONBLOCK) == sizeof r)
     86  1.1.1.2  christos     return r;
     87  1.1.1.2  christos #if _LIBC || (defined CLOCK_MONOTONIC && HAVE_CLOCK_GETTIME)
     88  1.1.1.2  christos   /* Add entropy if getrandom did not work.  */
     89  1.1.1.2  christos   struct __timespec64 tv;
     90  1.1.1.2  christos   __clock_gettime64 (CLOCK_MONOTONIC, &tv);
     91  1.1.1.2  christos   var ^= tv.tv_nsec;
     92      1.1  christos #endif
     93  1.1.1.2  christos   return 2862933555777941757 * var + 3037000493;
     94  1.1.1.2  christos }
     95      1.1  christos 
     96      1.1  christos #if _LIBC
     97      1.1  christos /* Return nonzero if DIR is an existent directory.  */
     98      1.1  christos static int
     99      1.1  christos direxists (const char *dir)
    100      1.1  christos {
    101      1.1  christos   struct_stat64 buf;
    102  1.1.1.2  christos   return __stat64 (dir, &buf) == 0 && S_ISDIR (buf.st_mode);
    103      1.1  christos }
    104      1.1  christos 
    105      1.1  christos /* Path search algorithm, for tmpnam, tmpfile, etc.  If DIR is
    106      1.1  christos    non-null and exists, uses it; otherwise uses the first of $TMPDIR,
    107      1.1  christos    P_tmpdir, /tmp that exists.  Copies into TMPL a template suitable
    108      1.1  christos    for use with mk[s]temp.  Will fail (-1) if DIR is non-null and
    109      1.1  christos    doesn't exist, none of the searched dirs exists, or there's not
    110      1.1  christos    enough space in TMPL. */
    111      1.1  christos int
    112      1.1  christos __path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx,
    113      1.1  christos                int try_tmpdir)
    114      1.1  christos {
    115      1.1  christos   const char *d;
    116      1.1  christos   size_t dlen, plen;
    117      1.1  christos 
    118      1.1  christos   if (!pfx || !pfx[0])
    119      1.1  christos     {
    120      1.1  christos       pfx = "file";
    121      1.1  christos       plen = 4;
    122      1.1  christos     }
    123      1.1  christos   else
    124      1.1  christos     {
    125      1.1  christos       plen = strlen (pfx);
    126      1.1  christos       if (plen > 5)
    127      1.1  christos         plen = 5;
    128      1.1  christos     }
    129      1.1  christos 
    130      1.1  christos   if (try_tmpdir)
    131      1.1  christos     {
    132      1.1  christos       d = __secure_getenv ("TMPDIR");
    133      1.1  christos       if (d != NULL && direxists (d))
    134      1.1  christos         dir = d;
    135      1.1  christos       else if (dir != NULL && direxists (dir))
    136      1.1  christos         /* nothing */ ;
    137      1.1  christos       else
    138      1.1  christos         dir = NULL;
    139      1.1  christos     }
    140      1.1  christos   if (dir == NULL)
    141      1.1  christos     {
    142      1.1  christos       if (direxists (P_tmpdir))
    143      1.1  christos         dir = P_tmpdir;
    144      1.1  christos       else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp"))
    145      1.1  christos         dir = "/tmp";
    146      1.1  christos       else
    147      1.1  christos         {
    148      1.1  christos           __set_errno (ENOENT);
    149      1.1  christos           return -1;
    150      1.1  christos         }
    151      1.1  christos     }
    152      1.1  christos 
    153      1.1  christos   dlen = strlen (dir);
    154      1.1  christos   while (dlen > 1 && dir[dlen - 1] == '/')
    155      1.1  christos     dlen--;                     /* remove trailing slashes */
    156      1.1  christos 
    157      1.1  christos   /* check we have room for "${dir}/${pfx}XXXXXX\0" */
    158      1.1  christos   if (tmpl_len < dlen + 1 + plen + 6 + 1)
    159      1.1  christos     {
    160      1.1  christos       __set_errno (EINVAL);
    161      1.1  christos       return -1;
    162      1.1  christos     }
    163      1.1  christos 
    164      1.1  christos   sprintf (tmpl, "%.*s/%.*sXXXXXX", (int) dlen, dir, (int) plen, pfx);
    165      1.1  christos   return 0;
    166      1.1  christos }
    167      1.1  christos #endif /* _LIBC */
    168      1.1  christos 
    169      1.1  christos #if _LIBC
    170      1.1  christos static int try_tempname_len (char *, int, void *, int (*) (char *, void *),
    171      1.1  christos                              size_t);
    172      1.1  christos #endif
    173      1.1  christos 
    174      1.1  christos static int
    175      1.1  christos try_file (char *tmpl, void *flags)
    176      1.1  christos {
    177      1.1  christos   int *openflags = flags;
    178      1.1  christos   return __open (tmpl,
    179      1.1  christos                  (*openflags & ~O_ACCMODE)
    180      1.1  christos                  | O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
    181      1.1  christos }
    182      1.1  christos 
    183      1.1  christos static int
    184  1.1.1.2  christos try_dir (char *tmpl, _GL_UNUSED void *flags)
    185      1.1  christos {
    186      1.1  christos   return __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR);
    187      1.1  christos }
    188      1.1  christos 
    189      1.1  christos static int
    190  1.1.1.2  christos try_nocreate (char *tmpl, _GL_UNUSED void *flags)
    191      1.1  christos {
    192      1.1  christos   struct_stat64 st;
    193      1.1  christos 
    194  1.1.1.2  christos   if (__lstat64 (tmpl, &st) == 0 || errno == EOVERFLOW)
    195      1.1  christos     __set_errno (EEXIST);
    196      1.1  christos   return errno == ENOENT ? 0 : -1;
    197      1.1  christos }
    198      1.1  christos 
    199      1.1  christos /* These are the characters used in temporary file names.  */
    200      1.1  christos static const char letters[] =
    201      1.1  christos "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    202      1.1  christos 
    203      1.1  christos /* Generate a temporary file name based on TMPL.  TMPL must match the
    204      1.1  christos    rules for mk[s]temp (i.e., end in at least X_SUFFIX_LEN "X"s,
    205      1.1  christos    possibly with a suffix).
    206      1.1  christos    The name constructed does not exist at the time of the call to
    207      1.1  christos    this function.  TMPL is overwritten with the result.
    208      1.1  christos 
    209      1.1  christos    KIND may be one of:
    210      1.1  christos    __GT_NOCREATE:       simply verify that the name does not exist
    211      1.1  christos                         at the time of the call.
    212      1.1  christos    __GT_FILE:           create the file using open(O_CREAT|O_EXCL)
    213      1.1  christos                         and return a read-write fd.  The file is mode 0600.
    214      1.1  christos    __GT_DIR:            create a directory, which will be mode 0700.
    215      1.1  christos 
    216      1.1  christos    We use a clever algorithm to get hard-to-predict names. */
    217      1.1  christos #ifdef _LIBC
    218      1.1  christos static
    219      1.1  christos #endif
    220      1.1  christos int
    221      1.1  christos gen_tempname_len (char *tmpl, int suffixlen, int flags, int kind,
    222      1.1  christos                   size_t x_suffix_len)
    223      1.1  christos {
    224      1.1  christos   static int (*const tryfunc[]) (char *, void *) =
    225      1.1  christos     {
    226      1.1  christos       [__GT_FILE] = try_file,
    227      1.1  christos       [__GT_DIR] = try_dir,
    228      1.1  christos       [__GT_NOCREATE] = try_nocreate
    229      1.1  christos     };
    230      1.1  christos   return try_tempname_len (tmpl, suffixlen, &flags, tryfunc[kind],
    231      1.1  christos                            x_suffix_len);
    232      1.1  christos }
    233      1.1  christos 
    234      1.1  christos #ifdef _LIBC
    235      1.1  christos static
    236      1.1  christos #endif
    237      1.1  christos int
    238      1.1  christos try_tempname_len (char *tmpl, int suffixlen, void *args,
    239      1.1  christos                   int (*tryfunc) (char *, void *), size_t x_suffix_len)
    240      1.1  christos {
    241      1.1  christos   size_t len;
    242      1.1  christos   char *XXXXXX;
    243      1.1  christos   unsigned int count;
    244      1.1  christos   int fd = -1;
    245      1.1  christos   int save_errno = errno;
    246      1.1  christos 
    247      1.1  christos   /* A lower bound on the number of temporary files to attempt to
    248      1.1  christos      generate.  The maximum total number of temporary file names that
    249      1.1  christos      can exist for a given template is 62**6.  It should never be
    250      1.1  christos      necessary to try all of these combinations.  Instead if a reasonable
    251      1.1  christos      number of names is tried (we define reasonable as 62**3) fail to
    252      1.1  christos      give the system administrator the chance to remove the problems.
    253      1.1  christos      This value requires that X_SUFFIX_LEN be at least 3.  */
    254      1.1  christos #define ATTEMPTS_MIN (62 * 62 * 62)
    255      1.1  christos 
    256      1.1  christos   /* The number of times to attempt to generate a temporary file.  To
    257      1.1  christos      conform to POSIX, this must be no smaller than TMP_MAX.  */
    258      1.1  christos #if ATTEMPTS_MIN < TMP_MAX
    259      1.1  christos   unsigned int attempts = TMP_MAX;
    260      1.1  christos #else
    261      1.1  christos   unsigned int attempts = ATTEMPTS_MIN;
    262      1.1  christos #endif
    263      1.1  christos 
    264  1.1.1.2  christos   /* A random variable.  The initial value is used only the for fallback path
    265  1.1.1.2  christos      on 'random_bits' on 'getrandom' failure.  Its initial value tries to use
    266  1.1.1.2  christos      some entropy from the ASLR and ignore possible bits from the stack
    267  1.1.1.2  christos      alignment.  */
    268  1.1.1.2  christos   random_value v = ((uintptr_t) &v) / alignof (max_align_t);
    269      1.1  christos 
    270      1.1  christos   /* How many random base-62 digits can currently be extracted from V.  */
    271      1.1  christos   int vdigits = 0;
    272      1.1  christos 
    273  1.1.1.2  christos   /* Whether to consume entropy when acquiring random bits.  On the
    274  1.1.1.2  christos      first try it's worth the entropy cost with __GT_NOCREATE, which
    275  1.1.1.2  christos      is inherently insecure and can use the entropy to make it a bit
    276  1.1.1.2  christos      less secure.  On the (rare) second and later attempts it might
    277  1.1.1.2  christos      help against DoS attacks.  */
    278  1.1.1.2  christos   bool use_getrandom = tryfunc == try_nocreate;
    279  1.1.1.2  christos 
    280      1.1  christos   /* Least unfair value for V.  If V is less than this, V can generate
    281      1.1  christos      BASE_62_DIGITS digits fairly.  Otherwise it might be biased.  */
    282      1.1  christos   random_value const unfair_min
    283      1.1  christos     = RANDOM_VALUE_MAX - RANDOM_VALUE_MAX % BASE_62_POWER;
    284      1.1  christos 
    285      1.1  christos   len = strlen (tmpl);
    286      1.1  christos   if (len < x_suffix_len + suffixlen
    287      1.1  christos       || strspn (&tmpl[len - x_suffix_len - suffixlen], "X") < x_suffix_len)
    288      1.1  christos     {
    289      1.1  christos       __set_errno (EINVAL);
    290      1.1  christos       return -1;
    291      1.1  christos     }
    292      1.1  christos 
    293      1.1  christos   /* This is where the Xs start.  */
    294      1.1  christos   XXXXXX = &tmpl[len - x_suffix_len - suffixlen];
    295      1.1  christos 
    296      1.1  christos   for (count = 0; count < attempts; ++count)
    297      1.1  christos     {
    298      1.1  christos       for (size_t i = 0; i < x_suffix_len; i++)
    299      1.1  christos         {
    300      1.1  christos           if (vdigits == 0)
    301      1.1  christos             {
    302      1.1  christos               do
    303  1.1.1.2  christos                 {
    304  1.1.1.2  christos                   v = random_bits (v, use_getrandom);
    305  1.1.1.2  christos                   use_getrandom = true;
    306  1.1.1.2  christos                 }
    307      1.1  christos               while (unfair_min <= v);
    308      1.1  christos 
    309      1.1  christos               vdigits = BASE_62_DIGITS;
    310      1.1  christos             }
    311      1.1  christos 
    312      1.1  christos           XXXXXX[i] = letters[v % 62];
    313      1.1  christos           v /= 62;
    314      1.1  christos           vdigits--;
    315      1.1  christos         }
    316      1.1  christos 
    317      1.1  christos       fd = tryfunc (tmpl, args);
    318      1.1  christos       if (fd >= 0)
    319      1.1  christos         {
    320      1.1  christos           __set_errno (save_errno);
    321      1.1  christos           return fd;
    322      1.1  christos         }
    323      1.1  christos       else if (errno != EEXIST)
    324      1.1  christos         return -1;
    325      1.1  christos     }
    326      1.1  christos 
    327      1.1  christos   /* We got out of the loop because we ran out of combinations to try.  */
    328      1.1  christos   __set_errno (EEXIST);
    329      1.1  christos   return -1;
    330      1.1  christos }
    331      1.1  christos 
    332      1.1  christos int
    333      1.1  christos __gen_tempname (char *tmpl, int suffixlen, int flags, int kind)
    334      1.1  christos {
    335      1.1  christos   return gen_tempname_len (tmpl, suffixlen, flags, kind, 6);
    336      1.1  christos }
    337      1.1  christos 
    338      1.1  christos #if !_LIBC
    339      1.1  christos int
    340      1.1  christos try_tempname (char *tmpl, int suffixlen, void *args,
    341      1.1  christos               int (*tryfunc) (char *, void *))
    342      1.1  christos {
    343      1.1  christos   return try_tempname_len (tmpl, suffixlen, args, tryfunc, 6);
    344      1.1  christos }
    345      1.1  christos #endif
    346