1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1987, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include "namespace.h" 33 #include <sys/param.h> 34 #include <sys/stat.h> 35 #include <fcntl.h> 36 #include <errno.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <ctype.h> 41 #include <unistd.h> 42 #include "un-namespace.h" 43 44 char *_mktemp(char *); 45 46 static int _gettemp(int, char *, int *, int, int, int); 47 48 static const unsigned char padchar[] = 49 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 50 51 int 52 mkostempsat(int dfd, char *path, int slen, int oflags) 53 { 54 int fd; 55 56 return (_gettemp(dfd, path, &fd, 0, slen, oflags) ? fd : -1); 57 } 58 59 int 60 mkostemps(char *path, int slen, int oflags) 61 { 62 int fd; 63 64 return (_gettemp(AT_FDCWD, path, &fd, 0, slen, oflags) ? fd : -1); 65 } 66 67 int 68 mkstemps(char *path, int slen) 69 { 70 int fd; 71 72 return (_gettemp(AT_FDCWD, path, &fd, 0, slen, 0) ? fd : -1); 73 } 74 75 int 76 mkostemp(char *path, int oflags) 77 { 78 int fd; 79 80 return (_gettemp(AT_FDCWD, path, &fd, 0, 0, oflags) ? fd : -1); 81 } 82 83 int 84 mkstemp(char *path) 85 { 86 int fd; 87 88 return (_gettemp(AT_FDCWD, path, &fd, 0, 0, 0) ? fd : -1); 89 } 90 91 char * 92 mkdtemp(char *path) 93 { 94 return (_gettemp(AT_FDCWD, path, (int *)NULL, 1, 0, 0) ? path : (char *)NULL); 95 } 96 97 char * 98 _mktemp(char *path) 99 { 100 return (_gettemp(AT_FDCWD, path, (int *)NULL, 0, 0, 0) ? path : (char *)NULL); 101 } 102 103 __warn_references(mktemp, 104 "warning: mktemp() possibly used unsafely; consider using mkstemp()"); 105 106 char * 107 mktemp(char *path) 108 { 109 return (_mktemp(path)); 110 } 111 112 static int 113 _gettemp(int dfd, char *path, int *doopen, int domkdir, int slen, int oflags) 114 { 115 char *start, *trv, *suffp, *carryp; 116 char *pad; 117 struct stat sbuf; 118 uint32_t rand; 119 char carrybuf[MAXPATHLEN]; 120 int saved; 121 122 if ((doopen != NULL && domkdir) || slen < 0 || 123 (oflags & ~(O_APPEND | O_DIRECT | O_SHLOCK | O_EXLOCK | O_SYNC | 124 O_CLOEXEC)) != 0) { 125 errno = EINVAL; 126 return (0); 127 } 128 129 trv = path + strlen(path); 130 if (trv - path >= MAXPATHLEN) { 131 errno = ENAMETOOLONG; 132 return (0); 133 } 134 trv -= slen; 135 suffp = trv; 136 --trv; 137 if (trv < path || NULL != strchr(suffp, '/')) { 138 errno = EINVAL; 139 return (0); 140 } 141 142 /* Fill space with random characters */ 143 while (trv >= path && *trv == 'X') { 144 rand = arc4random_uniform(sizeof(padchar) - 1); 145 *trv-- = padchar[rand]; 146 } 147 start = trv + 1; 148 149 saved = 0; 150 oflags |= O_CREAT | O_EXCL | O_RDWR; 151 for (;;) { 152 if (doopen) { 153 *doopen = _openat(dfd, path, oflags, 0600); 154 if (*doopen >= 0) 155 return (1); 156 if (errno != EEXIST) 157 return (0); 158 } else if (domkdir) { 159 if (mkdir(path, 0700) == 0) 160 return (1); 161 if (errno != EEXIST) 162 return (0); 163 } else if (lstat(path, &sbuf)) 164 return (errno == ENOENT); 165 166 /* save first combination of random characters */ 167 if (!saved) { 168 memcpy(carrybuf, start, suffp - start); 169 saved = 1; 170 } 171 172 /* If we have a collision, cycle through the space of filenames */ 173 for (trv = start, carryp = carrybuf;;) { 174 /* have we tried all possible permutations? */ 175 if (trv == suffp) 176 return (0); /* yes - exit with EEXIST */ 177 pad = strchr(padchar, *trv); 178 if (pad == NULL) { 179 /* this should never happen */ 180 errno = EIO; 181 return (0); 182 } 183 /* increment character */ 184 *trv = (*++pad == '\0') ? padchar[0] : *pad; 185 /* carry to next position? */ 186 if (*trv == *carryp) { 187 /* increment position and loop */ 188 ++trv; 189 ++carryp; 190 } else { 191 /* try with new name */ 192 break; 193 } 194 } 195 } 196 /*NOTREACHED*/ 197 } 198