fix typo in changelog
[debian/sudo] / mkstemp.c
1 /*      $OpenBSD: mktemp.c,v 1.19 2005/08/08 08:05:36 espie Exp $       */
2
3 /*
4  * Copyright (c) 2000, 2001, 2005 Todd C. Miller <Todd.Miller@courtesan.com>
5  * Copyright (c) 1987, 1993
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 #include "config.h"
34
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #if defined(TIME_WITH_SYS_TIME) || defined(HAVE_SYS_TIME_H)
38 # include <sys/time.h>
39 #endif
40 #include <fcntl.h>
41 #include <errno.h>
42 #include <stdio.h>
43 #ifdef HAVE_STDLIB_H
44 # include <stdlib.h>
45 #endif /* HAVE_STDLIB_H */
46 #include <ctype.h>
47 #ifdef HAVE_UNISTD_H
48 # include <unistd.h>
49 #endif /* HAVE_UNISTD_H */
50
51 #include "sudo.h"
52
53 #ifndef lint
54 static const char rcsid[] = "$Sudo: mkstemp.c,v 1.1.2.1 2007/06/12 17:06:20 millert Exp $";
55 #endif /* not lint */
56
57 static unsigned int get_random __P((void));
58 static void seed_random __P((void));
59
60 int
61 mkstemp(path)
62         char *path;
63 {
64         char *start, *trv;
65         struct stat sbuf;
66         int fd, rval;
67         pid_t pid;
68         char *alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
69
70         if (*path == '\0') {
71                 errno = EINVAL;
72                 return (-1);            /* zero length path */
73         }
74         pid = getpid();
75         for (trv = path; *trv; ++trv)
76                 ;
77         --trv;
78         while (trv >= path && *trv == 'X' && pid != 0) {
79                 *trv-- = (pid % 10) + '0';
80                 pid /= 10;
81         }
82         while (trv >= path && *trv == 'X') {
83                 char c;
84
85                 /* assumes pid_t is at least 16 bits */
86                 pid = (get_random() & 0xffff) % (26 + 26);
87                 c = alphabet[pid];
88                 *trv-- = c;
89         }
90         start = trv + 1;
91
92         /*
93          * check the target directory; if you have six X's and it
94          * doesn't exist this runs for a *very* long time.
95          */
96         for (;; --trv) {
97                 if (trv <= path)
98                         break;
99                 if (*trv == '/') {
100                         *trv = '\0';
101                         rval = stat(path, &sbuf);
102                         *trv = '/';
103                         if (rval != 0)
104                                 return (-1);
105                         if (!S_ISDIR(sbuf.st_mode)) {
106                                 errno = ENOTDIR;
107                                 return (-1);
108                         }
109                         break;
110                 }
111         }
112
113         for (;;) {
114                 if ((fd = open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
115                         return (fd);
116                 if (errno != EEXIST)
117                         return (-1);
118
119                 /* tricky little algorithm for backward compatibility */
120                 for (trv = start;;) {
121                         if (!*trv)
122                                 return (-1);
123                         if (*trv == 'Z')
124                                 *trv++ = 'a';
125                         else {
126                                 if (isdigit((unsigned char)(*trv)))
127                                         *trv = 'a';
128                                 else if (*trv == 'z')   /* wrap from z to A */
129                                         *trv = 'A';
130                                 else {
131 #ifdef HAVE_EBCDIC
132                                         switch(*trv) {
133                                         case 'i':
134                                                 *trv = 'j';
135                                                 break;
136                                         case 'r':
137                                                 *trv = 's';
138                                                 break;
139                                         case 'I':
140                                                 *trv = 'J';
141                                                 break;
142                                         case 'R':
143                                                 *trv = 'S';
144                                                 break;
145                                         default:
146                                                 ++*trv;
147                                                 break;
148                                         }
149 #else
150                                         ++*trv;
151 #endif
152                                 }
153                                 break;
154                         }
155                 }
156         }
157         /*NOTREACHED*/
158 }
159
160 #ifdef HAVE_RANDOM
161 # define RAND           random
162 # define SRAND          srandom
163 # define SEED_T         unsigned int
164 #else
165 # ifdef HAVE_LRAND48
166 #  define RAND          lrand48
167 #  define SRAND         srand48
168 #  define SEED_T        long
169 # else
170 #  define RAND          rand
171 #  define SRAND         srand
172 #  define SEED_T        unsigned int
173 # endif
174 #endif
175
176 static void
177 seed_random()
178 {
179         SEED_T seed;
180         struct timespec ts;
181
182         /*
183          * Seed from time of day and process id multiplied by small primes.
184          */
185         (void) gettime(&ts);
186         seed = (ts.tv_sec % 10000) * 523 + ts.tv_nsec / 1000 * 13 +
187             (getpid() % 1000) * 983;
188         SRAND(seed);
189 }
190
191 static unsigned int
192 get_random()
193 {
194         static int initialized;
195
196         if (!initialized) {
197                 seed_random();
198                 initialized = 1;
199         }
200
201         return(RAND() & 0xffffffff);
202 }