165935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes/*	$OpenBSD: mktemp.c,v 1.33 2014/05/06 22:55:27 millert Exp $ */
265935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes/*
365935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes * Copyright (c) 1996-1998, 2008 Theo de Raadt
465935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes * Copyright (c) 1997, 2008-2009 Todd C. Miller
565935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes *
665935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes * Permission to use, copy, modify, and distribute this software for any
765935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes * purpose with or without fee is hereby granted, provided that the above
865935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes * copyright notice and this permission notice appear in all copies.
965935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes *
1065935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1165935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1265935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1365935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1465935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1565935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1665935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1765935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes */
1865935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes
1965935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes#include <sys/types.h>
2065935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes#include <sys/stat.h>
2165935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes#include <errno.h>
2265935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes#include <fcntl.h>
2365935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes#include <limits.h>
2465935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes#include <stdio.h>
2565935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes#include <stdlib.h>
2665935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes#include <string.h>
2765935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes#include <ctype.h>
2865935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes#include <unistd.h>
2965935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes
3065935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes#define MKTEMP_NAME	0
3165935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes#define MKTEMP_FILE	1
3265935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes#define MKTEMP_DIR	2
3365935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes
3465935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes#define TEMPCHARS	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
3565935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes#define NUM_CHARS	(sizeof(TEMPCHARS) - 1)
3665935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes#define MIN_X		6
3765935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes
3865935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes#ifndef nitems
3965935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes#define nitems(_a)	(sizeof((_a)) / sizeof((_a)[0]))
4065935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes#endif
4165935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes
4265935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughesstatic int
4365935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughesmktemp_internal(char *path, int slen, int mode)
4465935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes{
4565935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	char *start, *cp, *ep;
4665935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	const char *tempchars = TEMPCHARS;
4765935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	unsigned int tries;
4865935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	struct stat sb;
4965935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	size_t len;
5065935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	int fd;
5165935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes
5265935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	len = strlen(path);
5365935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	if (len < MIN_X || slen < 0 || (size_t)slen > len - MIN_X) {
5465935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes		errno = EINVAL;
5565935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes		return(-1);
5665935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	}
5765935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	ep = path + len - slen;
5865935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes
5965935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	for (start = ep; start > path && start[-1] == 'X'; start--)
6065935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes		;
6165935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	if (ep - start < MIN_X) {
6265935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes		errno = EINVAL;
6365935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes		return(-1);
6465935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	}
6565935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes
6665935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	tries = INT_MAX;
6765935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	do {
6865935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes		cp = start;
6965935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes		do {
7065935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes			unsigned short rbuf[16];
7165935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes			unsigned int i;
7265935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes
7365935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes			/*
7465935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes			 * Avoid lots of arc4random() calls by using
7565935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes			 * a buffer sized for up to 16 Xs at a time.
7665935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes			 */
7765935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes			arc4random_buf(rbuf, sizeof(rbuf));
7865935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes			for (i = 0; i < nitems(rbuf) && cp != ep; i++)
7965935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes				*cp++ = tempchars[rbuf[i] % NUM_CHARS];
8065935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes		} while (cp != ep);
8165935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes
8265935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes		switch (mode) {
8365935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes		case MKTEMP_NAME:
8465935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes			if (lstat(path, &sb) != 0)
8565935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes				return(errno == ENOENT ? 0 : -1);
8665935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes			break;
8765935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes		case MKTEMP_FILE:
8865935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes			fd = open(path, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
8965935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes			if (fd != -1 || errno != EEXIST)
9065935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes				return(fd);
9165935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes			break;
9265935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes		case MKTEMP_DIR:
9365935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes			if (mkdir(path, S_IRUSR|S_IWUSR|S_IXUSR) == 0)
9465935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes				return(0);
9565935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes			if (errno != EEXIST)
9665935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes				return(-1);
9765935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes			break;
9865935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes		}
9965935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	} while (--tries);
10065935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes
10165935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	errno = EEXIST;
10265935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	return(-1);
10365935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes}
10465935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes
10565935979311373f2c7fa27cbfc189f49b188ca3aElliott Hugheschar *_mktemp(char *);
10665935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes
10765935979311373f2c7fa27cbfc189f49b188ca3aElliott Hugheschar *
10865935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes_mktemp(char *path)
10965935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes{
11065935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	if (mktemp_internal(path, 0, MKTEMP_NAME) == -1)
11165935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes		return(NULL);
11265935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	return(path);
11365935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes}
11465935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes
11565935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes__warn_references(mktemp,
11665935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes    "warning: mktemp() possibly used unsafely; consider using mkstemp()");
11765935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes
11865935979311373f2c7fa27cbfc189f49b188ca3aElliott Hugheschar *
11965935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughesmktemp(char *path)
12065935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes{
12165935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	return(_mktemp(path));
12265935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes}
12365935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes
12465935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughesint
12565935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughesmkstemp(char *path)
12665935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes{
12765935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	return(mktemp_internal(path, 0, MKTEMP_FILE));
12865935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes}
12965935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes
13065935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughesint
13165935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughesmkstemps(char *path, int slen)
13265935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes{
13365935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	return(mktemp_internal(path, slen, MKTEMP_FILE));
13465935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes}
13565935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes
13665935979311373f2c7fa27cbfc189f49b188ca3aElliott Hugheschar *
13765935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughesmkdtemp(char *path)
13865935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes{
13965935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	int error;
14065935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes
14165935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	error = mktemp_internal(path, 0, MKTEMP_DIR);
14265935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes	return(error ? NULL : path);
14365935979311373f2c7fa27cbfc189f49b188ca3aElliott Hughes}
144