1/* Copyright (C) 1991-2020 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 26#include <errno.h> 27 28#include <stdio.h> 29#ifndef P_tmpdir 30# define P_tmpdir "/tmp" 31#endif 32#ifndef TMP_MAX 33# define TMP_MAX 238328 34#endif 35#ifndef __GT_FILE 36# define __GT_FILE 0 37# define __GT_DIR 1 38# define __GT_NOCREATE 2 39#endif 40#if !_LIBC && (GT_FILE != __GT_FILE || GT_DIR != __GT_DIR \ 41 || GT_NOCREATE != __GT_NOCREATE) 42# error report this to bug-gnulib@gnu.org 43#endif 44 45#include <stddef.h> 46#include <stdlib.h> 47#include <string.h> 48 49#include <fcntl.h> 50#include <stdint.h> 51#include <sys/random.h> 52#include <sys/stat.h> 53 54#if _LIBC 55# define struct_stat64 struct stat64 56# define __secure_getenv __libc_secure_getenv 57#else 58# define struct_stat64 struct stat 59# define __gen_tempname gen_tempname 60# define __mkdir mkdir 61# define __open open 62# define __lxstat64(version, file, buf) lstat (file, buf) 63#endif 64 65#ifdef _LIBC 66# include <random-bits.h> 67# define RANDOM_BITS(Var) ((Var) = random_bits ()) 68typedef uint32_t random_value; 69# define RANDOM_VALUE_MAX UINT32_MAX 70# define BASE_62_DIGITS 5 /* 62**5 < UINT32_MAX */ 71# define BASE_62_POWER (62 * 62 * 62 * 62 * 62) /* 2**BASE_62_DIGITS */ 72#else 73/* Use getrandom if it works, falling back on a 64-bit linear 74 congruential generator that starts with whatever Var's value 75 happens to be. */ 76# define RANDOM_BITS(Var) \ 77 ((void) (getrandom (&(Var), sizeof (Var), 0) == sizeof (Var) \ 78 || ((Var) = 2862933555777941757 * (Var) + 3037000493))) 79typedef uint_fast64_t random_value; 80# define RANDOM_VALUE_MAX UINT_FAST64_MAX 81# define BASE_62_DIGITS 10 /* 62**10 < UINT_FAST64_MAX */ 82# define BASE_62_POWER (62LL * 62 * 62 * 62 * 62 * 62 * 62 * 62 * 62 * 62) 83#endif 84 85#if _LIBC 86/* Return nonzero if DIR is an existent directory. */ 87static int 88direxists (const char *dir) 89{ 90 struct_stat64 buf; 91 return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode); 92} 93 94/* Path search algorithm, for tmpnam, tmpfile, etc. If DIR is 95 non-null and exists, uses it; otherwise uses the first of $TMPDIR, 96 P_tmpdir, /tmp that exists. Copies into TMPL a template suitable 97 for use with mk[s]temp. Will fail (-1) if DIR is non-null and 98 doesn't exist, none of the searched dirs exists, or there's not 99 enough space in TMPL. */ 100int 101__path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, 102 int try_tmpdir) 103{ 104 const char *d; 105 size_t dlen, plen; 106 107 if (!pfx || !pfx[0]) 108 { 109 pfx = "file"; 110 plen = 4; 111 } 112 else 113 { 114 plen = strlen (pfx); 115 if (plen > 5) 116 plen = 5; 117 } 118 119 if (try_tmpdir) 120 { 121 d = __secure_getenv ("TMPDIR"); 122 if (d != NULL && direxists (d)) 123 dir = d; 124 else if (dir != NULL && direxists (dir)) 125 /* nothing */ ; 126 else 127 dir = NULL; 128 } 129 if (dir == NULL) 130 { 131 if (direxists (P_tmpdir)) 132 dir = P_tmpdir; 133 else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp")) 134 dir = "/tmp"; 135 else 136 { 137 __set_errno (ENOENT); 138 return -1; 139 } 140 } 141 142 dlen = strlen (dir); 143 while (dlen > 1 && dir[dlen - 1] == '/') 144 dlen--; /* remove trailing slashes */ 145 146 /* check we have room for "${dir}/${pfx}XXXXXX\0" */ 147 if (tmpl_len < dlen + 1 + plen + 6 + 1) 148 { 149 __set_errno (EINVAL); 150 return -1; 151 } 152 153 sprintf (tmpl, "%.*s/%.*sXXXXXX", (int) dlen, dir, (int) plen, pfx); 154 return 0; 155} 156#endif /* _LIBC */ 157 158#if _LIBC 159static int try_tempname_len (char *, int, void *, int (*) (char *, void *), 160 size_t); 161#endif 162 163static int 164try_file (char *tmpl, void *flags) 165{ 166 int *openflags = flags; 167 return __open (tmpl, 168 (*openflags & ~O_ACCMODE) 169 | O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); 170} 171 172static int 173try_dir (char *tmpl, void *flags _GL_UNUSED) 174{ 175 return __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR); 176} 177 178static int 179try_nocreate (char *tmpl, void *flags _GL_UNUSED) 180{ 181 struct_stat64 st; 182 183 if (__lxstat64 (_STAT_VER, tmpl, &st) == 0 || errno == EOVERFLOW) 184 __set_errno (EEXIST); 185 return errno == ENOENT ? 0 : -1; 186} 187 188/* These are the characters used in temporary file names. */ 189static const char letters[] = 190"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 191 192/* Generate a temporary file name based on TMPL. TMPL must match the 193 rules for mk[s]temp (i.e., end in at least X_SUFFIX_LEN "X"s, 194 possibly with a suffix). 195 The name constructed does not exist at the time of the call to 196 this function. TMPL is overwritten with the result. 197 198 KIND may be one of: 199 __GT_NOCREATE: simply verify that the name does not exist 200 at the time of the call. 201 __GT_FILE: create the file using open(O_CREAT|O_EXCL) 202 and return a read-write fd. The file is mode 0600. 203 __GT_DIR: create a directory, which will be mode 0700. 204 205 We use a clever algorithm to get hard-to-predict names. */ 206#ifdef _LIBC 207static 208#endif 209int 210gen_tempname_len (char *tmpl, int suffixlen, int flags, int kind, 211 size_t x_suffix_len) 212{ 213 static int (*const tryfunc[]) (char *, void *) = 214 { 215 [__GT_FILE] = try_file, 216 [__GT_DIR] = try_dir, 217 [__GT_NOCREATE] = try_nocreate 218 }; 219 return try_tempname_len (tmpl, suffixlen, &flags, tryfunc[kind], 220 x_suffix_len); 221} 222 223#ifdef _LIBC 224static 225#endif 226int 227try_tempname_len (char *tmpl, int suffixlen, void *args, 228 int (*tryfunc) (char *, void *), size_t x_suffix_len) 229{ 230 size_t len; 231 char *XXXXXX; 232 unsigned int count; 233 int fd = -1; 234 int save_errno = errno; 235 236 /* A lower bound on the number of temporary files to attempt to 237 generate. The maximum total number of temporary file names that 238 can exist for a given template is 62**6. It should never be 239 necessary to try all of these combinations. Instead if a reasonable 240 number of names is tried (we define reasonable as 62**3) fail to 241 give the system administrator the chance to remove the problems. 242 This value requires that X_SUFFIX_LEN be at least 3. */ 243#define ATTEMPTS_MIN (62 * 62 * 62) 244 245 /* The number of times to attempt to generate a temporary file. To 246 conform to POSIX, this must be no smaller than TMP_MAX. */ 247#if ATTEMPTS_MIN < TMP_MAX 248 unsigned int attempts = TMP_MAX; 249#else 250 unsigned int attempts = ATTEMPTS_MIN; 251#endif 252 253 /* A random variable. */ 254 random_value v; 255 256 /* How many random base-62 digits can currently be extracted from V. */ 257 int vdigits = 0; 258 259 /* Least unfair value for V. If V is less than this, V can generate 260 BASE_62_DIGITS digits fairly. Otherwise it might be biased. */ 261 random_value const unfair_min 262 = RANDOM_VALUE_MAX - RANDOM_VALUE_MAX % BASE_62_POWER; 263 264 len = strlen (tmpl); 265 if (len < x_suffix_len + suffixlen 266 || strspn (&tmpl[len - x_suffix_len - suffixlen], "X") < x_suffix_len) 267 { 268 __set_errno (EINVAL); 269 return -1; 270 } 271 272 /* This is where the Xs start. */ 273 XXXXXX = &tmpl[len - x_suffix_len - suffixlen]; 274 275 for (count = 0; count < attempts; ++count) 276 { 277 for (size_t i = 0; i < x_suffix_len; i++) 278 { 279 if (vdigits == 0) 280 { 281 do 282 RANDOM_BITS (v); 283 while (unfair_min <= v); 284 285 vdigits = BASE_62_DIGITS; 286 } 287 288 XXXXXX[i] = letters[v % 62]; 289 v /= 62; 290 vdigits--; 291 } 292 293 fd = tryfunc (tmpl, args); 294 if (fd >= 0) 295 { 296 __set_errno (save_errno); 297 return fd; 298 } 299 else if (errno != EEXIST) 300 return -1; 301 } 302 303 /* We got out of the loop because we ran out of combinations to try. */ 304 __set_errno (EEXIST); 305 return -1; 306} 307 308int 309__gen_tempname (char *tmpl, int suffixlen, int flags, int kind) 310{ 311 return gen_tempname_len (tmpl, suffixlen, flags, kind, 6); 312} 313 314#if !_LIBC 315int 316try_tempname (char *tmpl, int suffixlen, void *args, 317 int (*tryfunc) (char *, void *)) 318{ 319 return try_tempname_len (tmpl, suffixlen, args, tryfunc, 6); 320} 321#endif 322