[comp.bugs.2bsd] V1.09

bostic@OKEEFFE.BERKELEY.EDU (Keith Bostic) (10/20/87)

Subject: mktemp is broken
Index: lib/libc/gen/mktemp.c 2.10BSD

Description:
	mktemp(3), as distributed with 2.10BSD will fail if used
	with setuid programs.
Repeat-By:
	Try to create a temporary file in a directory that is writeable
	not by the user, but by the setuid program.
Fix:
	Unshar the attached file and replace lib/libc/gen/mktemp.c.

echo x - mktemp.c
sed 's/^X//' >mktemp.c << 'END-of-mktemp.c'
X/*
X * Copyright (c) 1987 Regents of the University of California.
X * All rights reserved.  The Berkeley software License Agreement
X * specifies the terms and conditions for redistribution.
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic char sccsid[] = "@(#)mktemp.c	5.4 (Berkeley) 9/14/87";
X#endif LIBC_SCCS and not lint
X
X#include <sys/types.h>
X#include <sys/file.h>
X#include <sys/stat.h>
X#include <errno.h>
X#include <stdio.h>
X#include <ctype.h>
X
X#define	YES	1
X#define	NO	0
X
Xmkstemp(as)
X	char	*as;
X{
X	int	fd;
X
X	return (_gettemp(as, &fd) ? fd : -1);
X}
X
Xchar *
Xmktemp(as)
X	char	*as;
X{
X	return(_gettemp(as, (int *)NULL) ? as : (char *)NULL);
X}
X
Xstatic
X_gettemp(as, doopen)
X	char	*as;
X	register int	*doopen;
X{
X	extern int	errno;
X	register char	*start, *trv;
X	struct stat	sbuf;
X	u_int	pid;
X
X	pid = getpid();
X
X	/* extra X's get set to 0's */
X	for (trv = as; *trv; ++trv);
X	while (*--trv == 'X') {
X		*trv = (pid % 10) + '0';
X		pid /= 10;
X	}
X
X	/*
X	 * check for write permission on target directory; if you have
X	 * six X's and you can't write the directory, this will run for
X	 * a *very* long time.
X	 */
X	for (start = ++trv; trv > as && *trv != '/'; --trv);
X	if (*trv == '/') {
X		*trv = '\0';
X		if (stat(as, &sbuf) || !(sbuf.st_mode & S_IFDIR))
X			return(NO);
X		*trv = '/';
X	}
X	else if (stat(".", &sbuf) == -1)
X		return(NO);
X
X	for (;;) {
X		if (doopen) {
X		    if ((*doopen = open(as, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
X			return(YES);
X		    if (errno != EEXIST)
X			return(NO);
X		}
X		else if (stat(as, &sbuf))
X			return(errno == ENOENT ? YES : NO);
X
X		/* tricky little algorithm for backward compatibility */
X		for (trv = start;;) {
X			if (!*trv)
X				return(NO);
X			if (*trv == 'z')
X				*trv++ = 'a';
X			else {
X				if (isdigit(*trv))
X					*trv = 'a';
X				else
X					++*trv;
X				break;
X			}
X		}
X	}
X	/*NOTREACHED*/
X}
END-of-mktemp.c
exit