1331722Seadler/* 21573Srgrimes * Copyright (c) 1987, 1993 31573Srgrimes * The Regents of the University of California. All rights reserved. 41573Srgrimes * 51573Srgrimes * Redistribution and use in source and binary forms, with or without 61573Srgrimes * modification, are permitted provided that the following conditions 71573Srgrimes * are met: 81573Srgrimes * 1. Redistributions of source code must retain the above copyright 91573Srgrimes * notice, this list of conditions and the following disclaimer. 101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111573Srgrimes * notice, this list of conditions and the following disclaimer in the 121573Srgrimes * documentation and/or other materials provided with the distribution. 13249808Semaste * 3. Neither the name of the University nor the names of its contributors 141573Srgrimes * may be used to endorse or promote products derived from this software 151573Srgrimes * without specific prior written permission. 161573Srgrimes * 171573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271573Srgrimes * SUCH DAMAGE. 281573Srgrimes */ 291573Srgrimes 301573Srgrimes#if defined(LIBC_SCCS) && !defined(lint) 311573Srgrimesstatic char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93"; 321573Srgrimes#endif /* LIBC_SCCS and not lint */ 3392986Sobrien#include <sys/cdefs.h> 3492986Sobrien__FBSDID("$FreeBSD$"); 351573Srgrimes 36111010Snectar#include "namespace.h" 37180938Sjhb#include <sys/param.h> 381573Srgrimes#include <sys/stat.h> 391573Srgrimes#include <fcntl.h> 401573Srgrimes#include <errno.h> 411573Srgrimes#include <stdio.h> 4233295Simp#include <stdlib.h> 4368590Skris#include <string.h> 4416586Sjraynard#include <ctype.h> 4511667Sphk#include <unistd.h> 46111010Snectar#include "un-namespace.h" 471573Srgrimes 4892905Sobrienchar *_mktemp(char *); 491573Srgrimes 50254151Sjillesstatic int _gettemp(char *, int *, int, int, int); 5134016Sbde 5268590Skrisstatic const unsigned char padchar[] = 5368590Skris"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 5468590Skris 5516586Sjraynardint 56254151Sjillesmkostemps(char *path, int slen, int oflags) 57254151Sjilles{ 58254151Sjilles int fd; 59254151Sjilles 60254151Sjilles return (_gettemp(path, &fd, 0, slen, oflags) ? fd : -1); 61254151Sjilles} 62254151Sjilles 63254151Sjillesint 64249810Semastemkstemps(char *path, int slen) 6545303Simp{ 6645303Simp int fd; 6745303Simp 68254151Sjilles return (_gettemp(path, &fd, 0, slen, 0) ? fd : -1); 6945303Simp} 7045303Simp 7145303Simpint 72254151Sjillesmkostemp(char *path, int oflags) 73254151Sjilles{ 74254151Sjilles int fd; 75254151Sjilles 76254151Sjilles return (_gettemp(path, &fd, 0, 0, oflags) ? fd : -1); 77254151Sjilles} 78254151Sjilles 79254151Sjillesint 80249810Semastemkstemp(char *path) 811573Srgrimes{ 8240540Speter int fd; 831573Srgrimes 84254151Sjilles return (_gettemp(path, &fd, 0, 0, 0) ? fd : -1); 851573Srgrimes} 861573Srgrimes 871573Srgrimeschar * 88249810Semastemkdtemp(char *path) 8933295Simp{ 90254151Sjilles return (_gettemp(path, (int *)NULL, 1, 0, 0) ? path : (char *)NULL); 9133295Simp} 9233295Simp 9333295Simpchar * 94249810Semaste_mktemp(char *path) 9533295Simp{ 96254151Sjilles return (_gettemp(path, (int *)NULL, 0, 0, 0) ? path : (char *)NULL); 9733295Simp} 9833295Simp 9933295Simp__warn_references(mktemp, 10033295Simp "warning: mktemp() possibly used unsafely; consider using mkstemp()"); 10133295Simp 10233295Simpchar * 103249810Semastemktemp(char *path) 1041573Srgrimes{ 10597345Srobert return (_mktemp(path)); 1061573Srgrimes} 1071573Srgrimes 10816586Sjraynardstatic int 109254151Sjilles_gettemp(char *path, int *doopen, int domkdir, int slen, int oflags) 1101573Srgrimes{ 111180938Sjhb char *start, *trv, *suffp, *carryp; 11268590Skris char *pad; 1131573Srgrimes struct stat sbuf; 11468590Skris int rval; 11568590Skris uint32_t rand; 116180938Sjhb char carrybuf[MAXPATHLEN]; 1171573Srgrimes 118254151Sjilles if ((doopen != NULL && domkdir) || slen < 0 || 119254151Sjilles (oflags & ~(O_APPEND | O_DIRECT | O_SHLOCK | O_EXLOCK | O_SYNC | 120254151Sjilles O_CLOEXEC)) != 0) { 12133295Simp errno = EINVAL; 12297345Srobert return (0); 12333295Simp } 12433295Simp 12597345Srobert for (trv = path; *trv != '\0'; ++trv) 12633295Simp ; 127204447Sjh if (trv - path >= MAXPATHLEN) { 128204447Sjh errno = ENAMETOOLONG; 129204447Sjh return (0); 130204447Sjh } 13145303Simp trv -= slen; 13245303Simp suffp = trv; 13333295Simp --trv; 134180938Sjhb if (trv < path || NULL != strchr(suffp, '/')) { 13545303Simp errno = EINVAL; 13645303Simp return (0); 13745303Simp } 13868590Skris 13968590Skris /* Fill space with random characters */ 14097168Srobert while (trv >= path && *trv == 'X') { 141180696Sache rand = arc4random_uniform(sizeof(padchar) - 1); 14268590Skris *trv-- = padchar[rand]; 14333295Simp } 14434016Sbde start = trv + 1; 14533295Simp 146180938Sjhb /* save first combination of random characters */ 147180938Sjhb memcpy(carrybuf, start, suffp - start); 148180938Sjhb 1491573Srgrimes /* 15068590Skris * check the target directory. 1511573Srgrimes */ 15297345Srobert if (doopen != NULL || domkdir) { 15397345Srobert for (; trv > path; --trv) { 15433295Simp if (*trv == '/') { 15533295Simp *trv = '\0'; 15633295Simp rval = stat(path, &sbuf); 15733295Simp *trv = '/'; 15833295Simp if (rval != 0) 15997345Srobert return (0); 16033295Simp if (!S_ISDIR(sbuf.st_mode)) { 16133295Simp errno = ENOTDIR; 16297345Srobert return (0); 16333295Simp } 16433295Simp break; 1651573Srgrimes } 1661573Srgrimes } 1671573Srgrimes } 1681573Srgrimes 1691573Srgrimes for (;;) { 1701573Srgrimes if (doopen) { 1711573Srgrimes if ((*doopen = 172254151Sjilles _open(path, O_CREAT|O_EXCL|O_RDWR|oflags, 0600)) >= 173254151Sjilles 0) 17497345Srobert return (1); 1751573Srgrimes if (errno != EEXIST) 17697345Srobert return (0); 17733295Simp } else if (domkdir) { 17833295Simp if (mkdir(path, 0700) == 0) 17997345Srobert return (1); 18033295Simp if (errno != EEXIST) 18197345Srobert return (0); 18233295Simp } else if (lstat(path, &sbuf)) 18397345Srobert return (errno == ENOENT); 1841573Srgrimes 18568590Skris /* If we have a collision, cycle through the space of filenames */ 186180938Sjhb for (trv = start, carryp = carrybuf;;) { 187180938Sjhb /* have we tried all possible permutations? */ 188180938Sjhb if (trv == suffp) 189180938Sjhb return (0); /* yes - exit with EEXIST */ 190180938Sjhb pad = strchr(padchar, *trv); 191180938Sjhb if (pad == NULL) { 192180938Sjhb /* this should never happen */ 193180938Sjhb errno = EIO; 19497345Srobert return (0); 195180938Sjhb } 196180938Sjhb /* increment character */ 197180938Sjhb *trv = (*++pad == '\0') ? padchar[0] : *pad; 198180938Sjhb /* carry to next position? */ 199180938Sjhb if (*trv == *carryp) { 200180938Sjhb /* increment position and loop */ 201180938Sjhb ++trv; 202180938Sjhb ++carryp; 203180938Sjhb } else { 204180938Sjhb /* try with new name */ 2051573Srgrimes break; 2061573Srgrimes } 2071573Srgrimes } 2081573Srgrimes } 2091573Srgrimes /*NOTREACHED*/ 2101573Srgrimes} 211