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