(root)/
m4-1.4.19/
lib/
tempname.c
       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 General Public
       6     License as published by the Free Software Foundation; either
       7     version 3 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     General Public License for more details.
      13  
      14     You should have received a copy of the GNU 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)
      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)
     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,
     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)
     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, void *flags _GL_UNUSED)
     185  {
     186    return __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR);
     187  }
     188  
     189  static int
     190  try_nocreate (char *tmpl, void *flags _GL_UNUSED)
     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,
     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,
     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)
     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,
     341                int (*tryfunc) (char *, void *))
     342  {
     343    return try_tempname_len (tmpl, suffixlen, args, tryfunc, 6);
     344  }
     345  #endif