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 #ifdef mkstemp 38 #undef mkstemp 39 #endif 40 int mkstemp(char *); 41 42 /* 43 * From glibc man page: 'In glibc versions 2.06 and earlier, the file is 44 * created with permissions 0666, that is, read and write for all users.' 45 * Provide a wrapper to make sure the mask is reasonable (POSIX requires 46 * mode 0600, so mask off any other bits). 47 */ 48 int 49 _ssh_mkstemp(char *template) 50 { 51 mode_t mask; 52 int ret; 53 54 mask = umask(0177); 55 ret = mkstemp(template); 56 (void)umask(mask); 57 return ret; 58 } 59 60 #if !defined(HAVE_MKDTEMP) 61 62 #define MKTEMP_NAME 0 63 #define MKTEMP_FILE 1 64 #define MKTEMP_DIR 2 65 66 #define TEMPCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" 67 #define NUM_CHARS (sizeof(TEMPCHARS) - 1) 68 69 static int 70 mktemp_internal(char *path, int slen, int mode) 71 { 72 char *start, *cp, *ep; 73 const char *tempchars = TEMPCHARS; 74 unsigned int r, tries; 75 struct stat sb; 76 size_t len; 77 int fd; 78 79 len = strlen(path); 80 if (len == 0 || slen < 0 || (size_t)slen >= len) { 81 errno = EINVAL; 82 return(-1); 83 } 84 ep = path + len - slen; 85 86 tries = 1; 87 for (start = ep; start > path && start[-1] == 'X'; start--) { 88 if (tries < INT_MAX / NUM_CHARS) 89 tries *= NUM_CHARS; 90 } 91 tries *= 2; 92 93 do { 94 for (cp = start; cp != ep; cp++) { 95 r = arc4random_uniform(NUM_CHARS); 96 *cp = tempchars[r]; 97 } 98 99 switch (mode) { 100 case MKTEMP_NAME: 101 if (lstat(path, &sb) != 0) 102 return(errno == ENOENT ? 0 : -1); 103 break; 104 case MKTEMP_FILE: 105 fd = open(path, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR); 106 if (fd != -1 || errno != EEXIST) 107 return(fd); 108 break; 109 case MKTEMP_DIR: 110 if (mkdir(path, S_IRUSR|S_IWUSR|S_IXUSR) == 0) 111 return(0); 112 if (errno != EEXIST) 113 return(-1); 114 break; 115 } 116 } while (--tries); 117 118 errno = EEXIST; 119 return(-1); 120 } 121 122 #if 0 123 char *_mktemp(char *); 124 125 char * 126 _mktemp(char *path) 127 { 128 if (mktemp_internal(path, 0, MKTEMP_NAME) == -1) 129 return(NULL); 130 return(path); 131 } 132 133 __warn_references(mktemp, 134 "warning: mktemp() possibly used unsafely; consider using mkstemp()"); 135 136 char * 137 mktemp(char *path) 138 { 139 return(_mktemp(path)); 140 } 141 #endif 142 143 int 144 mkstemp(char *path) 145 { 146 return(mktemp_internal(path, 0, MKTEMP_FILE)); 147 } 148 149 int 150 mkstemps(char *path, int slen) 151 { 152 return(mktemp_internal(path, slen, MKTEMP_FILE)); 153 } 154 155 char * 156 mkdtemp(char *path) 157 { 158 int error; 159 160 error = mktemp_internal(path, 0, MKTEMP_DIR); 161 return(error ? NULL : path); 162 } 163 164 #endif /* !defined(HAVE_MKDTEMP) */ 165