]> git.gag.com Git - debian/sudo/blob - compat/mktemp.c
Imported Upstream version 1.8.7
[debian/sudo] / compat / mktemp.c
1 /*
2  * Copyright (c) 2001, 2003, 2004, 2008-2011, 2013
3  *      Todd C. Miller <Todd.Miller@courtesan.com>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 #include <config.h>
19
20 #if !defined(HAVE_MKSTEMPS) || !defined(HAVE_MKDTEMP)
21
22 #include <sys/types.h>
23 #include <sys/time.h>
24 #include <sys/stat.h>
25
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <limits.h>
29 #include <stdio.h>
30 #ifdef HAVE_STDLIB_H
31 # include <stdlib.h>
32 #endif /* HAVE_STDLIB_H */
33 #include <ctype.h>
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif /* HAVE_UNISTD_H */
37 #if TIME_WITH_SYS_TIME
38 # include <time.h>
39 #endif
40
41 #include "missing.h"
42
43 #define MKTEMP_FILE     1
44 #define MKTEMP_DIR      2
45
46 #define TEMPCHARS       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
47 #define NUM_CHARS       (sizeof(TEMPCHARS) - 1)
48
49 #ifndef INT_MAX
50 #define INT_MAX 0x7fffffff
51 #endif
52
53 #ifdef HAVE_RANDOM
54 # define RAND           random
55 # define SRAND          srandom
56 # define SEED_T         unsigned int
57 #else
58 # ifdef HAVE_LRAND48
59 #  define RAND          lrand48
60 #  define SRAND         srand48
61 #  define SEED_T        long
62 # else
63 #  define RAND          rand
64 #  define SRAND         srand
65 #  define SEED_T        unsigned int
66 # endif
67 #endif
68
69 static void
70 seed_random(void)
71 {
72         SEED_T seed;
73         struct timeval tv;
74
75         /*
76          * Seed from time of day and process id multiplied by small primes.
77          */
78         (void) gettimeofday(&tv, NULL);
79         seed = (tv.tv_sec % 10000) * 523 + tv.tv_usec * 13 +
80             (getpid() % 1000) * 983;
81         SRAND(seed);
82 }
83
84 static unsigned int
85 get_random(void)
86 {
87         static int initialized;
88
89         if (!initialized) {
90                 seed_random();
91                 initialized = 1;
92         }
93
94         return RAND() & 0xffffffff;
95 }
96
97 static int
98 mktemp_internal(char *path, int slen, int mode)
99 {
100         char *start, *cp, *ep;
101         const char *tempchars = TEMPCHARS;
102         unsigned int r, tries;
103         int fd;
104
105         for (ep = path; *ep; ep++)
106                 ;
107         if (path + slen >= ep) {
108                 errno = EINVAL;
109                 return -1;
110         }
111         ep -= slen;
112
113         tries = 1;
114         for (start = ep; start > path && start[-1] == 'X'; start--) {
115                 if (tries < INT_MAX / NUM_CHARS)
116                         tries *= NUM_CHARS;
117         }
118         tries *= 2;
119
120         do {
121                 for (cp = start; *cp; cp++) {
122                         r = get_random() % NUM_CHARS;
123                         *cp = tempchars[r];
124                 }
125
126                 switch (mode) {
127                 case MKTEMP_FILE:
128                         fd = open(path, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
129                         if (fd != -1 || errno != EEXIST)
130                                 return fd;
131                         break;
132                 case MKTEMP_DIR:
133                         if (mkdir(path, S_IRWXU) == 0)
134                                 return 0;
135                         if (errno != EEXIST)
136                                 return -1;
137                         break;
138                 }
139         } while (--tries);
140
141         errno = EEXIST;
142         return -1;
143 }
144
145 #ifndef HAVE_MKSTEMPS
146 int
147 mkstemps(char *path, int slen)
148 {
149         return mktemp_internal(path, slen, MKTEMP_FILE);
150 }
151 #endif /* HAVE_MKSTEMPS */
152
153 #ifndef HAVE_MKDTEMP
154 char *
155 mkdtemp(char *path)
156 {
157         if (mktemp_internal(path, 0, MKTEMP_DIR) == -1)
158                 return NULL;
159         return path;
160 }
161 #endif /* HAVE_MKDTEMP */
162 #endif /* !HAVE_MKSTEMPS || !HAVE_MKDTEMP */