mktemp.c revision 65935979311373f2c7fa27cbfc189f49b188ca3a
1/* $OpenBSD: mktemp.c,v 1.33 2014/05/06 22:55:27 millert Exp $ */ 2/* 3 * Copyright (c) 1996-1998, 2008 Theo de Raadt 4 * Copyright (c) 1997, 2008-2009 Todd C. Miller 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/types.h> 20#include <sys/stat.h> 21#include <errno.h> 22#include <fcntl.h> 23#include <limits.h> 24#include <stdio.h> 25#include <stdlib.h> 26#include <string.h> 27#include <ctype.h> 28#include <unistd.h> 29 30#define MKTEMP_NAME 0 31#define MKTEMP_FILE 1 32#define MKTEMP_DIR 2 33 34#define TEMPCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" 35#define NUM_CHARS (sizeof(TEMPCHARS) - 1) 36#define MIN_X 6 37 38#ifndef nitems 39#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) 40#endif 41 42static int 43mktemp_internal(char *path, int slen, int mode) 44{ 45 char *start, *cp, *ep; 46 const char *tempchars = TEMPCHARS; 47 unsigned int tries; 48 struct stat sb; 49 size_t len; 50 int fd; 51 52 len = strlen(path); 53 if (len < MIN_X || slen < 0 || (size_t)slen > len - MIN_X) { 54 errno = EINVAL; 55 return(-1); 56 } 57 ep = path + len - slen; 58 59 for (start = ep; start > path && start[-1] == 'X'; start--) 60 ; 61 if (ep - start < MIN_X) { 62 errno = EINVAL; 63 return(-1); 64 } 65 66 tries = INT_MAX; 67 do { 68 cp = start; 69 do { 70 unsigned short rbuf[16]; 71 unsigned int i; 72 73 /* 74 * Avoid lots of arc4random() calls by using 75 * a buffer sized for up to 16 Xs at a time. 76 */ 77 arc4random_buf(rbuf, sizeof(rbuf)); 78 for (i = 0; i < nitems(rbuf) && cp != ep; i++) 79 *cp++ = tempchars[rbuf[i] % NUM_CHARS]; 80 } while (cp != ep); 81 82 switch (mode) { 83 case MKTEMP_NAME: 84 if (lstat(path, &sb) != 0) 85 return(errno == ENOENT ? 0 : -1); 86 break; 87 case MKTEMP_FILE: 88 fd = open(path, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR); 89 if (fd != -1 || errno != EEXIST) 90 return(fd); 91 break; 92 case MKTEMP_DIR: 93 if (mkdir(path, S_IRUSR|S_IWUSR|S_IXUSR) == 0) 94 return(0); 95 if (errno != EEXIST) 96 return(-1); 97 break; 98 } 99 } while (--tries); 100 101 errno = EEXIST; 102 return(-1); 103} 104 105char *_mktemp(char *); 106 107char * 108_mktemp(char *path) 109{ 110 if (mktemp_internal(path, 0, MKTEMP_NAME) == -1) 111 return(NULL); 112 return(path); 113} 114 115__warn_references(mktemp, 116 "warning: mktemp() possibly used unsafely; consider using mkstemp()"); 117 118char * 119mktemp(char *path) 120{ 121 return(_mktemp(path)); 122} 123 124int 125mkstemp(char *path) 126{ 127 return(mktemp_internal(path, 0, MKTEMP_FILE)); 128} 129 130int 131mkstemps(char *path, int slen) 132{ 133 return(mktemp_internal(path, slen, MKTEMP_FILE)); 134} 135 136char * 137mkdtemp(char *path) 138{ 139 int error; 140 141 error = mktemp_internal(path, 0, MKTEMP_DIR); 142 return(error ? NULL : path); 143} 144