Merge commit 'upstream/1.7.2p2'
[debian/sudo] / mkstemp.c
1 /*
2  * Copyright (c) 2001, 2003, 2008 Todd C. Miller <Todd.Miller@courtesan.com>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include "config.h"
18
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #ifdef HAVE_STDLIB_H
25 # include <stdlib.h>
26 #endif /* HAVE_STDLIB_H */
27 #include <ctype.h>
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif /* HAVE_UNISTD_H */
31
32 #include "sudo.h"
33
34 #ifndef lint
35 static const char rcsid[] = "$Sudo: mkstemp.c,v 1.2 2008/08/20 11:40:15 millert Exp $";
36 #endif /* not lint */
37
38 static unsigned int get_random __P((void));
39 static void seed_random __P((void));
40
41 int
42 mkstemp(path)
43         char *path;
44 {
45         char *start, *cp;
46         int fd, r;
47         char *alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
48
49         if (*path == '\0') {
50                 errno = EINVAL;
51                 return(0);
52         }
53
54         for (cp = path; *cp; cp++)
55                 ;
56         do {
57                 cp--;
58         } while (cp >= path && *cp == 'X');
59         start = cp + 1;
60
61         for (;;) {
62                 for (cp = start; *cp; cp++) {
63                         r = get_random % (26 + 26);
64                         *cp = alphabet[r];
65                 }
66
67                 fd = open(path, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
68                 if (fd != -1 || errno != EEXIST)
69                         return(fd);
70         }
71         /*NOTREACHED*/
72 }
73
74 #ifdef HAVE_RANDOM
75 # define RAND           random
76 # define SRAND          srandom
77 # define SEED_T         unsigned int
78 #else
79 # ifdef HAVE_LRAND48
80 #  define RAND          lrand48
81 #  define SRAND         srand48
82 #  define SEED_T        long
83 # else
84 #  define RAND          rand
85 #  define SRAND         srand
86 #  define SEED_T        unsigned int
87 # endif
88 #endif
89
90 static void
91 seed_random()
92 {
93         SEED_T seed;
94         struct timespec ts;
95
96         /*
97          * Seed from time of day and process id multiplied by small primes.
98          */
99         (void) gettime(&ts);
100         seed = (ts.tv_sec % 10000) * 523 + ts.tv_nsec / 1000 * 13 +
101             (getpid() % 1000) * 983;
102         SRAND(seed);
103 }
104
105 static unsigned int
106 get_random()
107 {
108         static int initialized;
109
110         if (!initialized) {
111                 seed_random();
112                 initialized = 1;
113         }
114
115         return(RAND() & 0xffffffff);
116 }