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
41static unsigned int get_random __P((void));
42static 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
51int
52mkstemps(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
107static void
108seed_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
122static unsigned int
123get_random()
124{
125	static int initialized;
126
127	if (!initialized) {
128		seed_random();
129		initialized = 1;
130	}
131
132	return RAND() & 0xffffffff;
133}
134