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