SRI-NOSC/s2/su.c

Compare this file to the similar file:
Show the results in this format:

/*
Module Name:
	su.c -- the su command -- execute a command as the super-user

Installation:
	if $1x = newerx goto newer
	if $1e = finale goto finale
	cc su.c
	if ! -r a.out exit
	if -r su.new rm -f su.new makeme.new
	mv a.out su.new
	ln su.new makeme.new
	chmod 4555 su.new
	su chown root su.new
	exit
: newer
	if ! { newer su.c /bin/su } exit
	echo s2/su.c:
: finale
	cc -O -s su.c
	if ! -r a.out exit
	if -r su.new rm -f su.new makeme.new
	if ! -r /usr/sys/s2/su.c goto same
	if { cmp -s su.c /usr/sys/s2/su.c } goto same
	su cp su.c /usr/sys/s2/su.c
	rm -f su.c
: same
	/bin/su sh -
	rm -f /bin/su /usr/bin/makeme
	cp a.out /bin/su
	rm -f a.out
	chmod 4555 /bin/su
	chown root /bin/su
	chgrp bin /bin/su
	ln /bin/su /usr/bin/makeme

Synopsis:
	su [command [arguments]]
	-- or --
	makeme <name> [command [arguments]]

Description:
	The UID of the current real user is compared against a list of
	"trusted" users; if the user is NOT on this list, an attempt is
	made to get the password of the root from the standard input.
	If the standard input is not a tty, or if the password is not
	given correctly, the command is aborted.  Otherwise, command
	(including any arguments) is executed with the UID set to the
	super-user for the su command or to the specified user for the
	makeme version.  If no command is given, the shell is assumed,
	making its actions identical to the original su command.

	The list of "trusted" users are those users authorized to use
	group zero (the "system" group) in /etc/group.

Bugs:
	This program also doesn't know about the Yale shell's user bin
	directories, although it's not obvious which bin directory it
	should search, if any.

Module History:
	Creation Nov 1977 by Greg Noel, based upon the original su plus nohup
	Revised 6 Dec 77 by Greg Noel to execute shell files correctly
	Revised 26 June 78 by Greg Noel to add makeme variation.  Also changed
	    all useages of printf to write.
	Revised 17 April 79 by Greg Noel to use the system group (GID zero) as
	    the list of authorized users.
*/
char	string[100] {"/usr/bin/"};
char	password[100];
char	pwbuf[100];

main(argc, argv)
int argc;
char *argv[];
{
	register char *strp, *p;
	register i;

	ckpw();		/* go check authorization */
	setuid(0);	/* become the super-user */
	if(str_comp(argv[0], "makeme") == 0) {
		if(argc < 2  ||  !makeme(*++argv)) oops("Makeme who?\n");
		argc--;
	}
	for(i = 3; i < 15; i++) close(i);
	if(argc < 2) {	/* if no command, execute the shell */
		execl("/bin/sh", "-su", 0);
		oops("Couldn't get shell!\n");
	}
	argv[argc] = 0;	/* set end-of-list marker correctly for execv */
	argv++;
	execute(argv[0], argv);	/* try current directory */
	strp = &string[9];
	p = *argv;
	while(*strp++ = *p++);	/* make up potential system program names */
	execute(string+4, argv);	/* try /bin directory */
	execute(string, argv);	/* try /usr/bin directory */
	for(p = argv[0]; *p;) write(1, p++, 1);
	oops(": not found\n");
}

ckpw()
{
	register char *p, *q;
	int ttybuf[4];

	if((q = getuid()&0377) == 0) return;	/* super-user is authorized! */
	if(!getpw(q, pwbuf) && is_sys(pwbuf))
		return;		/* in authorized list */

		/* not in authorized list, see if they know password */

	if(getpw(0, pwbuf))
		goto badpw;
	p = pwbuf;
	while(*p != ':')
		if(*p++ == '\0')
			goto badpw;
	if(*++p == ':')	/* null password -- let anybody in */
		return;
	if(gtty(0, ttybuf) < 0) {	/* input must be from tty */
		oops("Sorry -- need TTY for password\n");
	}
	ttybuf[4] = ttybuf[2];
	ttybuf[2] =& ~010;
	stty(0, ttybuf);
	write(1, "Password: ", 10);
	q = password;
	while((*q = getchar()) != '\n')
		if(*q++ == '\0')
			exit();
	*q = '\0';
	ttybuf[2] = ttybuf[4];
	stty(0, ttybuf);
	write(1, "\n", 1);
	q = crypt(password);
	while(*q++ == *p++);
	if(*--q == '\0' && *--p == ':')
		return;

		/* Access not permitted, tell them and quit */
	oops("Sorry\n");

badpw:
	oops("Bad password file\n");
}

is_sys(name)
char *name;
{
	register int c;
	register char *p;
	int _file_[259];

	if(fopen("/etc/group", _file_) < 0) return 0;

	for(;;) {
		if((c = getc(_file_)) < 0) {
	nope:		close(*_file_);
			return 0;
		}
		while(c != ':') c = getc(_file_);
		while((c = getc(_file_)) != ':');
		if(getc(_file_) == '0' && getc(_file_) == ':') for(;;) {
			for(p = name; (c = getc(_file_)) == *p++;);
			if(*--p == ':' && (c == ',' || c == '\n')) {
				close(*_file_);
				return 1;
			}
			while(c != ',') {
				if(c == '\n') goto nope;
				c = getc(_file_);
			}
		}
		while(getc(_file_) != '\n');
	}
}

makeme(name)
char *name;
{
	register uid;

	if(*name >= '0'  &&  *name <= '9')
		uid = atoi(name);
	else
	if((uid = getnam(name, pwbuf)) < 0)
		return 0;	/* failure */
	setuid(uid);
	return 1;
}

execute(name, parms)
char *name, **parms;
{
	extern int errno;
	register char *n, **p;

	n = name;  p = parms;
	execv(n, p);
	if(errno==8/*ENOEXEC*/) {
		*p = n;
		*--p = "-su";
		execv("/bin/sh", p);
		oops("Can't get Shell!\n");
	}
}

str_comp(a, b)
char *a, *b;
{
	register char  *p, *q, c;

	p = a; q = b;	/* for speed and space */
	while((c = *p++) == *q++ && c);
	return *--p - *--q;
}

oops(msg)
char *msg;
{
	register char *p;

	for(p = msg; *p++;);
	write(1, msg, p-msg-1);
	exit();
}

/*  This really should be a system utility, located in /lib/libc.a  */

getnam(name, buf)
char *name;
char buf[];
{
	auto pbuf[259];
	static pwf;
	register char *n;
	register c;
	register char *bp;

	if(pwf == 0)
		pwf = open("/etc/passwd", 0);
	if(pwf < 0)
		return(-1);
	seek(pwf, 0, 0);
	pbuf[0] = pwf;
	pbuf[1] = 0;
	pbuf[2] = 0;

	for (;;) {
		bp = buf;
		while((c=getc(pbuf)) != '\n') {
			if(c <= 0)
				return(-1);
			*bp++ = c;
		}
		*bp++ = '\0';
		bp = buf;
		n = name;
		while(*n++ == *bp++);
		if(*--n != '\0'  ||  bp[-1] != ':')
			continue;
		while(*bp++ != ':');
		n = 0;
		while((c = *bp++) != ':') {
			if(c<'0' || c>'9')
				continue;
			n = n*10+c-'0';
		}
		return(n);
	}
	return(-1);
}