| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 | /* Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc.   This file is part of the GNU C Library.   The GNU C Library is free software; you can redistribute it and/or   modify it under the terms of the GNU Library General Public License as   published by the Free Software Foundation; either version 2 of the   License, or (at your option) any later version.   The GNU C Library is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   Library General Public License for more details.   You should have received a copy of the GNU Library General Public   License along with the GNU C Library; see the file COPYING.LIB.  If not,   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,   Boston, MA 02111-1307, USA.  *//* March 11, 2002       Manuel Novoa III * * Modify code to remove dependency on libgcc long long arith support funcs. *//* June 6, 2004       Erik Andersen * * Don't use brain damaged getpid() based randomness. *//* April 15, 2005     Mike Frysinger * * Use brain damaged getpid() if real random fails. */#include <stddef.h>#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <fcntl.h>#include <unistd.h>#include <assert.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/time.h>#include "tempname.h"libc_hidden_proto(strlen)libc_hidden_proto(strcmp)libc_hidden_proto(sprintf)libc_hidden_proto(mkdir)libc_hidden_proto(open)#ifdef __UCLIBC_HAS_LFS__libc_hidden_proto(open64)#endiflibc_hidden_proto(read)libc_hidden_proto(close)libc_hidden_proto(getpid)libc_hidden_proto(stat)libc_hidden_proto(gettimeofday)/* Return nonzero if DIR is an existent directory.  */static int direxists (const char *dir){    struct stat buf;    return stat(dir, &buf) == 0 && S_ISDIR (buf.st_mode);}/* Path search algorithm, for tmpnam, tmpfile, etc.  If DIR is   non-null and exists, uses it; otherwise uses the first of $TMPDIR,   P_tmpdir, /tmp that exists.  Copies into TMPL a template suitable   for use with mk[s]temp.  Will fail (-1) if DIR is non-null and   doesn't exist, none of the searched dirs exists, or there's not   enough space in TMPL. */int attribute_hidden ___path_search (char *tmpl, size_t tmpl_len, const char *dir,	const char *pfx /*, int try_tmpdir*/){    //const char *d;    size_t dlen, plen;    if (!pfx || !pfx[0])    {	pfx = "file";	plen = 4;    }    else    {	plen = strlen (pfx);	if (plen > 5)	    plen = 5;    }    /* Disable support for $TMPDIR */#if 0    if (try_tmpdir)    {	d = __secure_getenv ("TMPDIR");	if (d != NULL && direxists (d))	    dir = d;	else if (dir != NULL && direxists (dir))	    /* nothing */ ;	else	    dir = NULL;    }#endif    if (dir == NULL)    {	if (direxists (P_tmpdir))	    dir = P_tmpdir;	else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp"))	    dir = "/tmp";	else	{	    __set_errno (ENOENT);	    return -1;	}    }    dlen = strlen (dir);    while (dlen > 1 && dir[dlen - 1] == '/')	dlen--;			/* remove trailing slashes */    /* check we have room for "${dir}/${pfx}XXXXXX\0" */    if (tmpl_len < dlen + 1 + plen + 6 + 1)    {	__set_errno (EINVAL);	return -1;    }    sprintf (tmpl, "%.*s/%.*sXXXXXX", dlen, dir, plen, pfx);    return 0;}/* These are the characters used in temporary filenames.  */static const char letters[] ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";#define NUM_LETTERS (62)static unsigned int fillrand(unsigned char *buf, unsigned int len){    int fd;    unsigned int result = -1;    fd = open("/dev/urandom", O_RDONLY);    if (fd < 0) {	fd = open("/dev/random", O_RDONLY | O_NONBLOCK);    }    if (fd >= 0) {	result = read(fd, buf, len);	close(fd);    }    return result;}static void brain_damaged_fillrand(unsigned char *buf, unsigned int len){	unsigned int i, k;	struct timeval tv;	uint32_t high, low, rh;	static uint64_t value;	gettimeofday(&tv, NULL);	value += ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid();	low = value & UINT32_MAX;	high = value >> 32;	for (i = 0; i < len; ++i) {		rh = high % NUM_LETTERS;		high /= NUM_LETTERS;#define L ((UINT32_MAX % NUM_LETTERS + 1) % NUM_LETTERS)		k = (low % NUM_LETTERS) + (L * rh);#undef L#define H ((UINT32_MAX / NUM_LETTERS) + ((UINT32_MAX % NUM_LETTERS + 1) / NUM_LETTERS))		low = (low / NUM_LETTERS) + (H * rh) + (k / NUM_LETTERS);#undef H		k %= NUM_LETTERS;		buf[i] = letters[k];	}}/* Generate a temporary file name based on TMPL.  TMPL must match the   rules for mk[s]temp (i.e. end in "XXXXXX").  The name constructed   does not exist at the time of the call to __gen_tempname.  TMPL is   overwritten with the result.   KIND may be one of:   __GT_NOCREATE:       simply verify that the name does not exist                        at the time of the call.   __GT_FILE:           create the file using open(O_CREAT|O_EXCL)                        and return a read-write fd.  The file is mode 0600.   __GT_BIGFILE:        same as __GT_FILE but use open64().   __GT_DIR:            create a directory, which will be mode 0700.*/int attribute_hidden __gen_tempname (char *tmpl, int kind){    char *XXXXXX;    unsigned int i;    int fd, save_errno = errno;    unsigned char randomness[6];    size_t len;    len = strlen (tmpl);    /* This is where the Xs start.  */    XXXXXX = tmpl + len - 6;    if (len < 6 || strcmp (XXXXXX, "XXXXXX"))    {	__set_errno (EINVAL);	return -1;    }    /* Get some random data.  */    if (fillrand(randomness, sizeof(randomness)) != sizeof(randomness)) {	/* if random device nodes failed us, lets use the braindamaged ver */	brain_damaged_fillrand(randomness, sizeof(randomness));    }    for (i = 0; i < sizeof(randomness); ++i)	XXXXXX[i] = letters[(randomness[i]) % NUM_LETTERS];    for (i = 0; i < TMP_MAX; ++i) {	switch(kind) {	    case __GT_NOCREATE:		{		    struct stat st;		    if (stat (tmpl, &st) < 0) {			if (errno == ENOENT) {			    fd = 0;			    goto restore_and_ret;			} else			    /* Give up now. */			    return -1;		    } else			fd = 0;		}	    case __GT_FILE:		fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);		break;#if defined __UCLIBC_HAS_LFS__	    case __GT_BIGFILE:		fd = open64 (tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);		break;#endif	    case __GT_DIR:		fd = mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR);		break;	    default:		fd = -1;		assert (! "invalid KIND in __gen_tempname");	}	if (fd >= 0) {restore_and_ret:	    __set_errno (save_errno);	    return fd;	}	else if (errno != EEXIST)	    /* Any other error will apply also to other names we might	       try, and there are 2^32 or so of them, so give up now. */	    return -1;    }    /* We got out of the loop because we ran out of combinations to try.  */    __set_errno (EEXIST);    return -1;}
 |