Imported Upstream version 1.7.6p1
[debian/sudo] / mkstemps.c
1 /*
2  * Copyright (c) 2001, 2003, 2004, 2008-2010
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 #include <sys/types.h>
21 #include <sys/time.h>
22 #include <sys/stat.h>
23
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <limits.h>
27 #include <stdio.h>
28 #ifdef HAVE_STDLIB_H
29 # include <stdlib.h>
30 #endif /* HAVE_STDLIB_H */
31 #include <ctype.h>
32 #ifdef HAVE_UNISTD_H
33 # include <unistd.h>
34 #endif /* HAVE_UNISTD_H */
35 #if TIME_WITH_SYS_TIME
36 # include <time.h>
37 #endif
38
39 #include "sudo.h"
40
41 static unsigned int get_random __P((void));
42 static void seed_random __P((void));
43
44 #define TEMPCHARS       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
45 #define NUM_CHARS       (sizeof(TEMPCHARS) - 1)
46
47 #ifndef INT_MAX
48 #define INT_MAX 0x7fffffff
49 #endif
50
51 int
52 mkstemps(path, slen)
53         char *path;
54         int slen;
55 {
56         char *start, *cp, *ep;
57         const char *tempchars = TEMPCHARS;
58         unsigned int r, tries;
59         int fd;
60
61         for (ep = path; *ep; ep++)
62                 ;
63         if (path + slen >= ep) {
64                 errno = EINVAL;
65                 return -1;
66         }
67         ep -= slen;
68
69         tries = 1;
70         for (start = ep; start > path && start[-1] == 'X'; start--) {
71                 if (tries < INT_MAX / NUM_CHARS)
72                         tries *= NUM_CHARS;
73         }
74         tries *= 2;
75
76         do {
77                 for (cp = start; *cp; cp++) {
78                         r = get_random() % NUM_CHARS;
79                         *cp = tempchars[r];
80                 }
81
82                 fd = open(path, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
83                 if (fd != -1 || errno != EEXIST)
84                         return fd;
85         } while (--tries);
86
87         errno = EEXIST;
88         return -1;
89 }
90
91 #ifdef HAVE_RANDOM
92 # define RAND           random
93 # define SRAND          srandom
94 # define SEED_T         unsigned int
95 #else
96 # ifdef HAVE_LRAND48
97 #  define RAND          lrand48
98 #  define SRAND         srand48
99 #  define SEED_T        long
100 # else
101 #  define RAND          rand
102 #  define SRAND         srand
103 #  define SEED_T        unsigned int
104 # endif
105 #endif
106
107 static void
108 seed_random()
109 {
110         SEED_T seed;
111         struct timeval tv;
112
113         /*
114          * Seed from time of day and process id multiplied by small primes.
115          */
116         (void) gettime(&tv);
117         seed = (tv.tv_sec % 10000) * 523 + tv.tv_usec * 13 +
118             (getpid() % 1000) * 983;
119         SRAND(seed);
120 }
121
122 static unsigned int
123 get_random()
124 {
125         static int initialized;
126
127         if (!initialized) {
128                 seed_random();
129                 initialized = 1;
130         }
131
132         return RAND() & 0xffffffff;
133 }