198937Sdes/* THIS FILE HAS BEEN MODIFIED FROM THE ORIGINAL OPENBSD SOURCE */
298937Sdes/* Changes: Removed mktemp */
398937Sdes
4247485Sdes/*	$OpenBSD: mktemp.c,v 1.30 2010/03/21 23:09:30 schwarze Exp $ */
598937Sdes/*
6247485Sdes * Copyright (c) 1996-1998, 2008 Theo de Raadt
7247485Sdes * Copyright (c) 1997, 2008-2009 Todd C. Miller
898937Sdes *
9247485Sdes * Permission to use, copy, modify, and distribute this software for any
10247485Sdes * purpose with or without fee is hereby granted, provided that the above
11247485Sdes * copyright notice and this permission notice appear in all copies.
1298937Sdes *
13247485Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14247485Sdes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15247485Sdes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16247485Sdes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17247485Sdes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18247485Sdes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19247485Sdes * 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>
28247485Sdes#include <errno.h>
29162852Sdes#include <fcntl.h>
30247485Sdes#include <limits.h>
31247485Sdes#include <stdio.h>
32247485Sdes#include <stdlib.h>
33247485Sdes#include <string.h>
34162852Sdes#include <ctype.h>
35162852Sdes#include <unistd.h>
36162852Sdes
37113908Sdes#if !defined(HAVE_MKDTEMP) || defined(HAVE_STRICT_MKSTEMP)
3898937Sdes
39247485Sdes#define MKTEMP_NAME	0
40247485Sdes#define MKTEMP_FILE	1
41247485Sdes#define MKTEMP_DIR	2
4298937Sdes
43247485Sdes#define TEMPCHARS	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
44247485Sdes#define NUM_CHARS	(sizeof(TEMPCHARS) - 1)
45247485Sdes
46247485Sdesstatic int
47247485Sdesmktemp_internal(char *path, int slen, int mode)
4898937Sdes{
49247485Sdes	char *start, *cp, *ep;
50247485Sdes	const char *tempchars = TEMPCHARS;
51247485Sdes	unsigned int r, tries;
52247485Sdes	struct stat sb;
53247485Sdes	size_t len;
5498937Sdes	int fd;
5598937Sdes
56247485Sdes	len = strlen(path);
57247485Sdes	if (len == 0 || slen < 0 || (size_t)slen >= len) {
58247485Sdes		errno = EINVAL;
59247485Sdes		return(-1);
60247485Sdes	}
61247485Sdes	ep = path + len - slen;
62247485Sdes
63247485Sdes	tries = 1;
64247485Sdes	for (start = ep; start > path && start[-1] == 'X'; start--) {
65247485Sdes		if (tries < INT_MAX / NUM_CHARS)
66247485Sdes			tries *= NUM_CHARS;
67247485Sdes	}
68247485Sdes	tries *= 2;
69247485Sdes
70247485Sdes	do {
71247485Sdes		for (cp = start; cp != ep; cp++) {
72247485Sdes			r = arc4random_uniform(NUM_CHARS);
73247485Sdes			*cp = tempchars[r];
74247485Sdes		}
75247485Sdes
76247485Sdes		switch (mode) {
77247485Sdes		case MKTEMP_NAME:
78247485Sdes			if (lstat(path, &sb) != 0)
79247485Sdes				return(errno == ENOENT ? 0 : -1);
80247485Sdes			break;
81247485Sdes		case MKTEMP_FILE:
82247485Sdes			fd = open(path, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
83247485Sdes			if (fd != -1 || errno != EEXIST)
84247485Sdes				return(fd);
85247485Sdes			break;
86247485Sdes		case MKTEMP_DIR:
87247485Sdes			if (mkdir(path, S_IRUSR|S_IWUSR|S_IXUSR) == 0)
88247485Sdes				return(0);
89247485Sdes			if (errno != EEXIST)
90247485Sdes				return(-1);
91247485Sdes			break;
92247485Sdes		}
93247485Sdes	} while (--tries);
94247485Sdes
95247485Sdes	errno = EEXIST;
96247485Sdes	return(-1);
9798937Sdes}
9898937Sdes
99247485Sdes#if 0
100247485Sdeschar *_mktemp(char *);
101247485Sdes
102247485Sdeschar *
103247485Sdes_mktemp(char *path)
10498937Sdes{
105247485Sdes	if (mktemp_internal(path, 0, MKTEMP_NAME) == -1)
106247485Sdes		return(NULL);
107247485Sdes	return(path);
10898937Sdes}
10998937Sdes
110247485Sdes__warn_references(mktemp,
111247485Sdes    "warning: mktemp() possibly used unsafely; consider using mkstemp()");
112247485Sdes
11398937Sdeschar *
114247485Sdesmktemp(char *path)
11598937Sdes{
116247485Sdes	return(_mktemp(path));
11798937Sdes}
118247485Sdes#endif
11998937Sdes
120247485Sdesint
121247485Sdesmkstemp(char *path)
12298937Sdes{
123247485Sdes	return(mktemp_internal(path, 0, MKTEMP_FILE));
124247485Sdes}
12598937Sdes
126247485Sdesint
127247485Sdesmkstemps(char *path, int slen)
128247485Sdes{
129247485Sdes	return(mktemp_internal(path, slen, MKTEMP_FILE));
130247485Sdes}
13198937Sdes
132247485Sdeschar *
133247485Sdesmkdtemp(char *path)
134247485Sdes{
135247485Sdes	int error;
13698937Sdes
137247485Sdes	error = mktemp_internal(path, 0, MKTEMP_DIR);
138247485Sdes	return(error ? NULL : path);
13998937Sdes}
14098937Sdes
141113908Sdes#endif /* !defined(HAVE_MKDTEMP) || defined(HAVE_STRICT_MKSTEMP) */
142