1/* THIS FILE HAS BEEN MODIFIED FROM THE ORIGINAL OPENBSD SOURCE */
2/* Changes: Removed mktemp */
3
4/*	$OpenBSD: mktemp.c,v 1.30 2010/03/21 23:09:30 schwarze Exp $ */
5/*
6 * Copyright (c) 1996-1998, 2008 Theo de Raadt
7 * Copyright (c) 1997, 2008-2009 Todd C. Miller
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/* OPENBSD ORIGINAL: lib/libc/stdio/mktemp.c */
23
24#include "includes.h"
25
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <limits.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <ctype.h>
35#include <unistd.h>
36
37#if !defined(HAVE_MKDTEMP) || defined(HAVE_STRICT_MKSTEMP)
38
39#define MKTEMP_NAME	0
40#define MKTEMP_FILE	1
41#define MKTEMP_DIR	2
42
43#define TEMPCHARS	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
44#define NUM_CHARS	(sizeof(TEMPCHARS) - 1)
45
46static int
47mktemp_internal(char *path, int slen, int mode)
48{
49	char *start, *cp, *ep;
50	const char *tempchars = TEMPCHARS;
51	unsigned int r, tries;
52	struct stat sb;
53	size_t len;
54	int fd;
55
56	len = strlen(path);
57	if (len == 0 || slen < 0 || (size_t)slen >= len) {
58		errno = EINVAL;
59		return(-1);
60	}
61	ep = path + len - slen;
62
63	tries = 1;
64	for (start = ep; start > path && start[-1] == 'X'; start--) {
65		if (tries < INT_MAX / NUM_CHARS)
66			tries *= NUM_CHARS;
67	}
68	tries *= 2;
69
70	do {
71		for (cp = start; cp != ep; cp++) {
72			r = arc4random_uniform(NUM_CHARS);
73			*cp = tempchars[r];
74		}
75
76		switch (mode) {
77		case MKTEMP_NAME:
78			if (lstat(path, &sb) != 0)
79				return(errno == ENOENT ? 0 : -1);
80			break;
81		case MKTEMP_FILE:
82			fd = open(path, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
83			if (fd != -1 || errno != EEXIST)
84				return(fd);
85			break;
86		case MKTEMP_DIR:
87			if (mkdir(path, S_IRUSR|S_IWUSR|S_IXUSR) == 0)
88				return(0);
89			if (errno != EEXIST)
90				return(-1);
91			break;
92		}
93	} while (--tries);
94
95	errno = EEXIST;
96	return(-1);
97}
98
99#if 0
100char *_mktemp(char *);
101
102char *
103_mktemp(char *path)
104{
105	if (mktemp_internal(path, 0, MKTEMP_NAME) == -1)
106		return(NULL);
107	return(path);
108}
109
110__warn_references(mktemp,
111    "warning: mktemp() possibly used unsafely; consider using mkstemp()");
112
113char *
114mktemp(char *path)
115{
116	return(_mktemp(path));
117}
118#endif
119
120int
121mkstemp(char *path)
122{
123	return(mktemp_internal(path, 0, MKTEMP_FILE));
124}
125
126int
127mkstemps(char *path, int slen)
128{
129	return(mktemp_internal(path, slen, MKTEMP_FILE));
130}
131
132char *
133mkdtemp(char *path)
134{
135	int error;
136
137	error = mktemp_internal(path, 0, MKTEMP_DIR);
138	return(error ? NULL : path);
139}
140
141#endif /* !defined(HAVE_MKDTEMP) || defined(HAVE_STRICT_MKSTEMP) */
142