1331722Seadler/*
21573Srgrimes * Copyright (c) 1987, 1993
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * Redistribution and use in source and binary forms, with or without
61573Srgrimes * modification, are permitted provided that the following conditions
71573Srgrimes * are met:
81573Srgrimes * 1. Redistributions of source code must retain the above copyright
91573Srgrimes *    notice, this list of conditions and the following disclaimer.
101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111573Srgrimes *    notice, this list of conditions and the following disclaimer in the
121573Srgrimes *    documentation and/or other materials provided with the distribution.
13249808Semaste * 3. Neither the name of the University nor the names of its contributors
141573Srgrimes *    may be used to endorse or promote products derived from this software
151573Srgrimes *    without specific prior written permission.
161573Srgrimes *
171573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271573Srgrimes * SUCH DAMAGE.
281573Srgrimes */
291573Srgrimes
301573Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
311573Srgrimesstatic char sccsid[] = "@(#)mktemp.c	8.1 (Berkeley) 6/4/93";
321573Srgrimes#endif /* LIBC_SCCS and not lint */
3392986Sobrien#include <sys/cdefs.h>
3492986Sobrien__FBSDID("$FreeBSD$");
351573Srgrimes
36111010Snectar#include "namespace.h"
37180938Sjhb#include <sys/param.h>
381573Srgrimes#include <sys/stat.h>
391573Srgrimes#include <fcntl.h>
401573Srgrimes#include <errno.h>
411573Srgrimes#include <stdio.h>
4233295Simp#include <stdlib.h>
4368590Skris#include <string.h>
4416586Sjraynard#include <ctype.h>
4511667Sphk#include <unistd.h>
46111010Snectar#include "un-namespace.h"
471573Srgrimes
4892905Sobrienchar *_mktemp(char *);
491573Srgrimes
50254151Sjillesstatic int _gettemp(char *, int *, int, int, int);
5134016Sbde
5268590Skrisstatic const unsigned char padchar[] =
5368590Skris"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
5468590Skris
5516586Sjraynardint
56254151Sjillesmkostemps(char *path, int slen, int oflags)
57254151Sjilles{
58254151Sjilles	int fd;
59254151Sjilles
60254151Sjilles	return (_gettemp(path, &fd, 0, slen, oflags) ? fd : -1);
61254151Sjilles}
62254151Sjilles
63254151Sjillesint
64249810Semastemkstemps(char *path, int slen)
6545303Simp{
6645303Simp	int fd;
6745303Simp
68254151Sjilles	return (_gettemp(path, &fd, 0, slen, 0) ? fd : -1);
6945303Simp}
7045303Simp
7145303Simpint
72254151Sjillesmkostemp(char *path, int oflags)
73254151Sjilles{
74254151Sjilles	int fd;
75254151Sjilles
76254151Sjilles	return (_gettemp(path, &fd, 0, 0, oflags) ? fd : -1);
77254151Sjilles}
78254151Sjilles
79254151Sjillesint
80249810Semastemkstemp(char *path)
811573Srgrimes{
8240540Speter	int fd;
831573Srgrimes
84254151Sjilles	return (_gettemp(path, &fd, 0, 0, 0) ? fd : -1);
851573Srgrimes}
861573Srgrimes
871573Srgrimeschar *
88249810Semastemkdtemp(char *path)
8933295Simp{
90254151Sjilles	return (_gettemp(path, (int *)NULL, 1, 0, 0) ? path : (char *)NULL);
9133295Simp}
9233295Simp
9333295Simpchar *
94249810Semaste_mktemp(char *path)
9533295Simp{
96254151Sjilles	return (_gettemp(path, (int *)NULL, 0, 0, 0) ? path : (char *)NULL);
9733295Simp}
9833295Simp
9933295Simp__warn_references(mktemp,
10033295Simp    "warning: mktemp() possibly used unsafely; consider using mkstemp()");
10133295Simp
10233295Simpchar *
103249810Semastemktemp(char *path)
1041573Srgrimes{
10597345Srobert	return (_mktemp(path));
1061573Srgrimes}
1071573Srgrimes
10816586Sjraynardstatic int
109254151Sjilles_gettemp(char *path, int *doopen, int domkdir, int slen, int oflags)
1101573Srgrimes{
111180938Sjhb	char *start, *trv, *suffp, *carryp;
11268590Skris	char *pad;
1131573Srgrimes	struct stat sbuf;
11468590Skris	int rval;
11568590Skris	uint32_t rand;
116180938Sjhb	char carrybuf[MAXPATHLEN];
1171573Srgrimes
118254151Sjilles	if ((doopen != NULL && domkdir) || slen < 0 ||
119254151Sjilles	    (oflags & ~(O_APPEND | O_DIRECT | O_SHLOCK | O_EXLOCK | O_SYNC |
120254151Sjilles	    O_CLOEXEC)) != 0) {
12133295Simp		errno = EINVAL;
12297345Srobert		return (0);
12333295Simp	}
12433295Simp
12597345Srobert	for (trv = path; *trv != '\0'; ++trv)
12633295Simp		;
127204447Sjh	if (trv - path >= MAXPATHLEN) {
128204447Sjh		errno = ENAMETOOLONG;
129204447Sjh		return (0);
130204447Sjh	}
13145303Simp	trv -= slen;
13245303Simp	suffp = trv;
13333295Simp	--trv;
134180938Sjhb	if (trv < path || NULL != strchr(suffp, '/')) {
13545303Simp		errno = EINVAL;
13645303Simp		return (0);
13745303Simp	}
13868590Skris
13968590Skris	/* Fill space with random characters */
14097168Srobert	while (trv >= path && *trv == 'X') {
141180696Sache		rand = arc4random_uniform(sizeof(padchar) - 1);
14268590Skris		*trv-- = padchar[rand];
14333295Simp	}
14434016Sbde	start = trv + 1;
14533295Simp
146180938Sjhb	/* save first combination of random characters */
147180938Sjhb	memcpy(carrybuf, start, suffp - start);
148180938Sjhb
1491573Srgrimes	/*
15068590Skris	 * check the target directory.
1511573Srgrimes	 */
15297345Srobert	if (doopen != NULL || domkdir) {
15397345Srobert		for (; trv > path; --trv) {
15433295Simp			if (*trv == '/') {
15533295Simp				*trv = '\0';
15633295Simp				rval = stat(path, &sbuf);
15733295Simp				*trv = '/';
15833295Simp				if (rval != 0)
15997345Srobert					return (0);
16033295Simp				if (!S_ISDIR(sbuf.st_mode)) {
16133295Simp					errno = ENOTDIR;
16297345Srobert					return (0);
16333295Simp				}
16433295Simp				break;
1651573Srgrimes			}
1661573Srgrimes		}
1671573Srgrimes	}
1681573Srgrimes
1691573Srgrimes	for (;;) {
1701573Srgrimes		if (doopen) {
1711573Srgrimes			if ((*doopen =
172254151Sjilles			    _open(path, O_CREAT|O_EXCL|O_RDWR|oflags, 0600)) >=
173254151Sjilles			    0)
17497345Srobert				return (1);
1751573Srgrimes			if (errno != EEXIST)
17697345Srobert				return (0);
17733295Simp		} else if (domkdir) {
17833295Simp			if (mkdir(path, 0700) == 0)
17997345Srobert				return (1);
18033295Simp			if (errno != EEXIST)
18197345Srobert				return (0);
18233295Simp		} else if (lstat(path, &sbuf))
18397345Srobert			return (errno == ENOENT);
1841573Srgrimes
18568590Skris		/* If we have a collision, cycle through the space of filenames */
186180938Sjhb		for (trv = start, carryp = carrybuf;;) {
187180938Sjhb			/* have we tried all possible permutations? */
188180938Sjhb			if (trv == suffp)
189180938Sjhb				return (0); /* yes - exit with EEXIST */
190180938Sjhb			pad = strchr(padchar, *trv);
191180938Sjhb			if (pad == NULL) {
192180938Sjhb				/* this should never happen */
193180938Sjhb				errno = EIO;
19497345Srobert				return (0);
195180938Sjhb			}
196180938Sjhb			/* increment character */
197180938Sjhb			*trv = (*++pad == '\0') ? padchar[0] : *pad;
198180938Sjhb			/* carry to next position? */
199180938Sjhb			if (*trv == *carryp) {
200180938Sjhb				/* increment position and loop */
201180938Sjhb				++trv;
202180938Sjhb				++carryp;
203180938Sjhb			} else {
204180938Sjhb				/* try with new name */
2051573Srgrimes				break;
2061573Srgrimes			}
2071573Srgrimes		}
2081573Srgrimes	}
2091573Srgrimes	/*NOTREACHED*/
2101573Srgrimes}
211