198937Sdes/* THIS FILE HAS BEEN MODIFIED FROM THE ORIGINAL OPENBSD SOURCE */
298937Sdes/* Changes: Removed mktemp */
398937Sdes
4240075Sdes/*	$OpenBSD: mktemp.c,v 1.30 2010/03/21 23:09:30 schwarze Exp $ */
598937Sdes/*
6240075Sdes * Copyright (c) 1996-1998, 2008 Theo de Raadt
7240075Sdes * Copyright (c) 1997, 2008-2009 Todd C. Miller
898937Sdes *
9240075Sdes * Permission to use, copy, modify, and distribute this software for any
10240075Sdes * purpose with or without fee is hereby granted, provided that the above
11240075Sdes * copyright notice and this permission notice appear in all copies.
1298937Sdes *
13240075Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14240075Sdes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15240075Sdes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16240075Sdes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17240075Sdes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18240075Sdes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19240075Sdes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2098937Sdes */
2198937Sdes
22157016Sdes/* OPENBSD ORIGINAL: lib/libc/stdio/mktemp.c */
23157016Sdes
2498937Sdes#include "includes.h"
2598937Sdes
26162852Sdes#include <sys/types.h>
27162852Sdes#include <sys/stat.h>
28240075Sdes#include <errno.h>
29162852Sdes#include <fcntl.h>
30240075Sdes#include <limits.h>
31240075Sdes#include <stdio.h>
32240075Sdes#include <stdlib.h>
33240075Sdes#include <string.h>
34162852Sdes#include <ctype.h>
35162852Sdes#include <unistd.h>
36162852Sdes
37113908Sdes#if !defined(HAVE_MKDTEMP) || defined(HAVE_STRICT_MKSTEMP)
3898937Sdes
39240075Sdes#define MKTEMP_NAME	0
40240075Sdes#define MKTEMP_FILE	1
41240075Sdes#define MKTEMP_DIR	2
4298937Sdes
43240075Sdes#define TEMPCHARS	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
44240075Sdes#define NUM_CHARS	(sizeof(TEMPCHARS) - 1)
45240075Sdes
46240075Sdesstatic int
47240075Sdesmktemp_internal(char *path, int slen, int mode)
4898937Sdes{
49240075Sdes	char *start, *cp, *ep;
50240075Sdes	const char *tempchars = TEMPCHARS;
51240075Sdes	unsigned int r, tries;
52240075Sdes	struct stat sb;
53240075Sdes	size_t len;
5498937Sdes	int fd;
5598937Sdes
56240075Sdes	len = strlen(path);
57240075Sdes	if (len == 0 || slen < 0 || (size_t)slen >= len) {
58240075Sdes		errno = EINVAL;
59240075Sdes		return(-1);
60240075Sdes	}
61240075Sdes	ep = path + len - slen;
62240075Sdes
63240075Sdes	tries = 1;
64240075Sdes	for (start = ep; start > path && start[-1] == 'X'; start--) {
65240075Sdes		if (tries < INT_MAX / NUM_CHARS)
66240075Sdes			tries *= NUM_CHARS;
67240075Sdes	}
68240075Sdes	tries *= 2;
69240075Sdes
70240075Sdes	do {
71240075Sdes		for (cp = start; cp != ep; cp++) {
72240075Sdes			r = arc4random_uniform(NUM_CHARS);
73240075Sdes			*cp = tempchars[r];
74240075Sdes		}
75240075Sdes
76240075Sdes		switch (mode) {
77240075Sdes		case MKTEMP_NAME:
78240075Sdes			if (lstat(path, &sb) != 0)
79240075Sdes				return(errno == ENOENT ? 0 : -1);
80240075Sdes			break;
81240075Sdes		case MKTEMP_FILE:
82240075Sdes			fd = open(path, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
83240075Sdes			if (fd != -1 || errno != EEXIST)
84240075Sdes				return(fd);
85240075Sdes			break;
86240075Sdes		case MKTEMP_DIR:
87240075Sdes			if (mkdir(path, S_IRUSR|S_IWUSR|S_IXUSR) == 0)
88240075Sdes				return(0);
89240075Sdes			if (errno != EEXIST)
90240075Sdes				return(-1);
91240075Sdes			break;
92240075Sdes		}
93240075Sdes	} while (--tries);
94240075Sdes
95240075Sdes	errno = EEXIST;
96240075Sdes	return(-1);
9798937Sdes}
9898937Sdes
99240075Sdes#if 0
100240075Sdeschar *_mktemp(char *);
101240075Sdes
102240075Sdeschar *
103240075Sdes_mktemp(char *path)
10498937Sdes{
105240075Sdes	if (mktemp_internal(path, 0, MKTEMP_NAME) == -1)
106240075Sdes		return(NULL);
107240075Sdes	return(path);
10898937Sdes}
10998937Sdes
110240075Sdes__warn_references(mktemp,
111240075Sdes    "warning: mktemp() possibly used unsafely; consider using mkstemp()");
112240075Sdes
11398937Sdeschar *
114240075Sdesmktemp(char *path)
11598937Sdes{
116240075Sdes	return(_mktemp(path));
11798937Sdes}
118240075Sdes#endif
11998937Sdes
120240075Sdesint
121240075Sdesmkstemp(char *path)
12298937Sdes{
123240075Sdes	return(mktemp_internal(path, 0, MKTEMP_FILE));
124240075Sdes}
12598937Sdes
126240075Sdesint
127240075Sdesmkstemps(char *path, int slen)
128240075Sdes{
129240075Sdes	return(mktemp_internal(path, slen, MKTEMP_FILE));
130240075Sdes}
13198937Sdes
132240075Sdeschar *
133240075Sdesmkdtemp(char *path)
134240075Sdes{
135240075Sdes	int error;
13698937Sdes
137240075Sdes	error = mktemp_internal(path, 0, MKTEMP_DIR);
138240075Sdes	return(error ? NULL : path);
13998937Sdes}
14098937Sdes
141113908Sdes#endif /* !defined(HAVE_MKDTEMP) || defined(HAVE_STRICT_MKSTEMP) */
142