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