"Fossies" - the Fresh Open Source Software Archive

Member "littleutils-1.2.5/littleutils/orig/tempname.c" (29 Oct 2021, 9943 Bytes) of package /linux/privat/littleutils-1.2.5.tar.lz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "tempname.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.2.4_vs_1.2.5.

    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_t64
   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_time64(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_time64 (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_time64 (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