root/maint/gnulib/lib/tempname.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. random_bits
  2. direxists
  3. __path_search
  4. try_file
  5. try_dir
  6. try_nocreate
  7. gen_tempname_len
  8. try_tempname_len
  9. __gen_tempname
  10. try_tempname

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

/* [previous][next][first][last][top][bottom][index][help] */