da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/***********************************************************************
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* This software is part of the ast package *
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner* Copyright (c) 1982-2010 AT&T Intellectual Property *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* and is licensed under the *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Common Public License, Version 1.0 *
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin* by AT&T Intellectual Property *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* A copy of the License is available at *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* http://www.opensource.org/licenses/cpl1.0.txt *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Information and Software Systems Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* AT&T Research *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* Florham Park NJ *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* David Korn <dgk@research.att.com> *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin* *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin***********************************************************************/
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#pragma prototyped
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This is a program to execute 'execute only' and suid/sgid shell scripts.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This program must be owned by root and must have the set uid bit set.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * It must not have the set group id bit set. This program must be installed
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * where the define parameter THISPROG indicates to work correctly on system V
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Written by David Korn
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * AT&T Labs
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Enhanced by Rob Stampfli
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/* The file name of the script to execute is argv[0]
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Argv[1] is the program name
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The basic idea is to open the script as standard input, set the effective
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * user and group id correctly, and then exec the shell.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The complicated part is getting the effective uid of the caller and
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * setting the effective uid/gid. The program which execs this program
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * may pass file descriptor FDIN as an open file with mode SPECIAL if
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * the effective user id is not the real user id. The effective
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * user id for authentication purposes will be the owner of this
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * open file. On systems without the setreuid() call, e[ug]id is set
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * by copying this program to a /tmp/file, making it a suid and/or sgid
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * program, and then execing this program.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * A forked version of this program waits until it can unlink the /tmp
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * file and then exits. Actually, we fork() twice so the parent can
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * wait for the child to complete. A pipe is used to guarantee that we
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * do not remove the /tmp file too soon.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <ast.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "FEATURE/externs"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <ls.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sig.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <error.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/wait.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include "version.h"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define SPECIAL 04100 /* setuid execute only by owner */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define FDIN 10 /* must be same as /dev/fd below */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#undef FDSYNC
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define FDSYNC 11 /* used on sys5 to synchronize cleanup */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define FDVERIFY 12 /* used to validate /tmp process */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#undef BLKSIZE
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define BLKSIZE sizeof(char*)*1024
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define THISPROG "/etc/suid_exec"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#define DEFSHELL "/bin/sh"
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic void error_exit(const char*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int in_dir(const char*, const char*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int endsh(const char*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifndef _lib_setregid
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin# undef _lib_setreuid
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifndef _lib_setreuid
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin static void setids(int,uid_t,gid_t);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin static int mycopy(int, int);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin static void maketemp(char*);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin static void setids(int,int,int);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* _lib_setreuid */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic const char version[] = "\n@(#)$Id: suid_exec "SH_RELEASE" $\n";
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic const char badopen[] = "cannot open";
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic const char badexec[] = "cannot exec";
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic const char devfd[] = "/dev/fd/10"; /* must match FDIN above */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic char tmpname[] = "/tmp/SUIDXXXXXX";
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic char **arglist;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic char *shell;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic char *command;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic uid_t ruserid;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic uid_t euserid;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic gid_t rgroupid;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic gid_t egroupid;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic struct stat statb;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint main(int argc,char *argv[])
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int m,n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char *p;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin struct stat statx;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int mode;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin uid_t effuid;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin gid_t effgid;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin NOT_USED(argc);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin arglist = argv;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((command = argv[1]) == 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error_exit(badexec);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ruserid = getuid();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin euserid = geteuid();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin rgroupid = getgid();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin egroupid = getegid();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p = argv[0];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifndef _lib_setreuid
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin maketemp(tmpname);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(strcmp(p,tmpname)==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* At this point, the presumption is that we are the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * version of THISPROG copied into /tmp, with the owner,
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * group, and setuid/gid bits correctly set. This copy of
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * the program is executable by anyone, so we must be careful
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * not to allow just any invocation of it to succeed, since
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * it is setuid/gid. Validate the proper execution by
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * examining the FDVERIFY file descriptor -- if it is owned
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * by root and is mode SPECIAL, then this is proof that it was
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * passed by a program with superuser privileges -- hence we
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * can presume legitimacy. Otherwise, bail out, as we suspect
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * an impostor.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(fstat(FDVERIFY,&statb) < 0 || statb.st_uid != 0 ||
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (statb.st_mode & ~S_IFMT) != SPECIAL || close(FDVERIFY)<0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error_exit(badexec);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* This enables the grandchild to clean up /tmp file */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin close(FDSYNC);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Make sure that this is a valid invocation of the clone.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Perhaps unnecessary, given FDVERIFY, but what the heck...
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(stat(tmpname,&statb) < 0 || statb.st_nlink != 1 ||
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin !S_ISREG(statb.st_mode))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error_exit(badexec);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(ruserid != euserid &&
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ((statb.st_mode & S_ISUID) == 0 || statb.st_uid != euserid))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error_exit(badexec);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin goto exec;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Make sure that this is the real setuid program, not the clone.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * It is possible by clever hacking to get past this point in the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * clone, but it doesn't do the hacker any good that I can see.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(euserid)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error_exit(badexec);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* _lib_setreuid */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Open the script for reading first and then validate it. This
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * prevents someone from pulling a switcheroo while we are validating.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = open(p,0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(n == FDIN)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = dup(n);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin close(FDIN);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(n < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error_exit(badopen);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* validate execution rights to this script */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(fstat(FDIN,&statb) < 0 || (statb.st_mode & ~S_IFMT) != SPECIAL)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin euserid = ruserid;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin euserid = statb.st_uid;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* do it the easy way if you can */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(euserid == ruserid && egroupid == rgroupid)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(access(p,X_OK) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error_exit(badexec);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* have to check access on each component */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(*p++)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(*p == '/' || *p == 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin m = *p;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *p = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(eaccess(argv[0],X_OK) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error_exit(badexec);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *p = m;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p = argv[0];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(fstat(n, &statb) < 0 || !S_ISREG(statb.st_mode))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error_exit(badopen);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(stat(p, &statx) < 0 ||
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin statb.st_ino != statx.st_ino || statb.st_dev != statx.st_dev)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error_exit(badexec);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(stat(THISPROG, &statx) < 0 ||
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin (statb.st_ino == statx.st_ino && statb.st_dev == statx.st_dev))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error_exit(badexec);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin close(FDIN);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(fcntl(n,F_DUPFD,FDIN) != FDIN)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error_exit(badexec);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin close(n);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* compute the desired new effective user and group id */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin effuid = euserid;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin effgid = egroupid;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mode = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(statb.st_mode & S_ISUID)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin effuid = statb.st_uid;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(statb.st_mode & S_ISGID)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin effgid = statb.st_gid;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* see if group needs setting */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(effgid != egroupid)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(effgid != rgroupid || setgid(rgroupid) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mode = S_ISGID;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* now see if the uid needs setting */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(mode)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(effuid != ruserid)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mode |= S_ISUID;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(effuid)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(effuid != ruserid || setuid(ruserid) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mode = S_ISUID;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(mode)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin setids(mode, effuid, effgid);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifndef _lib_setreuid
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinexec:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* _lib_setreuid */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* only use SHELL if file is in trusted directory and ends in sh */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin shell = getenv("SHELL");
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(shell == 0 || !endsh(shell) || (
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin !in_dir("/bin",shell) &&
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin !in_dir("/usr/bin",shell) &&
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin !in_dir("/usr/lbin",shell) &&
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin !in_dir("/usr/local/bin",shell)))
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin shell = DEFSHELL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin argv[0] = command;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin argv[1] = (char*)devfd;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin execv(shell,argv);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error_exit(badexec);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * return true of shell ends in sh of ksh
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int endsh(register const char *shell)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(*shell)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin shell++;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(*--shell != 'h' || *--shell != 's')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(*--shell=='/')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(*shell=='k' && *--shell=='/')
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * return true of shell is in <dir> directory
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int in_dir(register const char *dir,register const char *shell)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(*dir)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(*dir++ != *shell++)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* return true if next character is a '/' */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(*shell=='/');
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic void error_exit(const char *message)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sfprintf(sfstdout,"%s: %s\n",command,message);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin exit(126);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This version of access checks against effective uid and effective gid
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint eaccess(register const char *name, register int mode)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin struct stat statb;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (stat(name, &statb) == 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(euserid == 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(!S_ISREG(statb.st_mode) || mode != 1)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* root needs execute permission for someone */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mode = (S_IXUSR|S_IXGRP|S_IXOTH);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(euserid == statb.st_uid)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mode <<= 6;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(egroupid == statb.st_gid)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mode <<= 3;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef _lib_getgroups
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* on some systems you can be in several groups */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin static int maxgroups;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin gid_t *groups=0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(maxgroups==0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* first time */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((maxgroups=getgroups(0,groups)) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* pre-POSIX system */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin maxgroups=NGROUPS_MAX;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin groups = (gid_t*)malloc((maxgroups+1)*sizeof(gid_t));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n = getgroups(maxgroups,groups);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(--n >= 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(groups[n] == statb.st_gid)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mode <<= 3;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* _lib_getgroups */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(statb.st_mode & mode)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return(-1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef _lib_setreuid
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic void setids(int mode,int owner,int group)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(mode & S_ISGID)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin setregid(rgroupid,group);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* set effective uid even if S_ISUID is not set. This is because
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * we are *really* executing EUID root at this point. Even if S_ISUID
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * is not set, the value for owner that is passsed should be correct.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin setreuid(ruserid,owner);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This version of setids creats a /tmp file and copies itself into it.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * The "clone" file is made executable with appropriate suid/sgid bits.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Finally, the clone is exec'ed. This file is unlinked by a grandchild
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * of this program, who waits around until the text is free.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic void setids(int mode,uid_t owner,gid_t group)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int n,m;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int pv[2];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Create a token to pass to the new program for validation.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * This token can only be procured by someone running with an
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * effective userid of root, and hence gives the clone a way to
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * certify that it was really invoked by THISPROG. Someone who
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * is already root could spoof us, but why would they want to?
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Since we are root here, we must be careful: What if someone
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * linked a valuable file to tmpname?
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin unlink(tmpname); /* should normally fail */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef O_EXCL
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((n = open(tmpname, O_WRONLY | O_CREAT | O_EXCL, SPECIAL)) < 0 ||
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin unlink(tmpname) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((n = open(tmpname, O_WRONLY | O_CREAT ,SPECIAL)) < 0 || unlink(tmpname) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error_exit(badexec);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(n != FDVERIFY)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin close(FDVERIFY);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(fcntl(n,F_DUPFD,FDVERIFY) != FDVERIFY)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error_exit(badexec);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mode |= S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* create a pipe for synchronization */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(pipe(pv) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error_exit(badexec);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((n=fork()) == 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { /* child */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin close(FDVERIFY);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin close(pv[1]);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((n=fork()) == 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin { /* grandchild -- cleans up clone file */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin signal(SIGHUP, SIG_IGN);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin signal(SIGINT, SIG_IGN);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin signal(SIGQUIT, SIG_IGN);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin signal(SIGTERM, SIG_IGN);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin read(pv[0],pv,1); /* wait for clone to close pipe */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(unlink(tmpname) < 0 && errno == ETXTBSY)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sleep(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin exit(0);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(n == -1)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin exit(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Create a set[ug]id file that will become the clone.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * To make this atomic, without need for chown(), the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * child takes on desired user and group. The only
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * downsize of this that I can see is that it may
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * screw up some per- * user accounting.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((m = open(THISPROG, O_RDONLY)) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin exit(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((mode & S_ISGID) && setgid(group) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin exit(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((mode & S_ISUID) && owner && setuid(owner) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin exit(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#ifdef O_EXCL
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((n = open(tmpname,O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, mode)) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin unlink(tmpname);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if((n = open(tmpname,O_WRONLY|O_CREAT|O_TRUNC, mode)) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* O_EXCL */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin exit(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* populate the clone */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin m = mycopy(m,n);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(chmod(tmpname,mode) <0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin exit(1);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin exit(m);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else if(n == -1)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error_exit(badexec);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin else
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin arglist[0] = (char*)tmpname;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin close(pv[0]);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* move write end of pipe into FDSYNC */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(pv[1] != FDSYNC)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin close(FDSYNC);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(fcntl(pv[1],F_DUPFD,FDSYNC) != FDSYNC)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error_exit(badexec);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* wait for child to die */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while((m = wait(0)) != n)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(m == -1 && errno != EINTR)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* Kill any setuid status at this point. That way, if the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * clone is not setuid, we won't exec it as root. Also, don't
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * neglect to consider that someone could have switched the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * clone file on us.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(setuid(ruserid) < 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error_exit(badexec);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin execv(tmpname,arglist);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin error_exit(badexec);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * create a unique name into the <template>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic void maketemp(char *template)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register char *cp = template;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register pid_t n = getpid();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* skip to end of string */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(*++cp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* convert process id to string */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while(n > 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *--cp = (n%10) + '0';
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin n /= 10;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * copy THISPROG into the open file number <fdo> and close <fdo>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinstatic int mycopy(int fdi, int fdo)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char buffer[BLKSIZE];
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin register int n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while((n = read(fdi,buffer,BLKSIZE)) > 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if(write(fdo,buffer,n) != n)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin close(fdi);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin close(fdo);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return n;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#endif /* _lib_setreuid */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin