[comp.sources.misc] v13i012: su-someone - switch uid using your own password

wietse@wzv.win.tue.nl (Wietse Z. Venema) (05/28/90)

Posting-number: Volume 13, Issue 12
Submitted-by: wietse@wzv.win.tue.nl (Wietse Z. Venema)
Archive-name: su-someone/part01

[I applied a patch sent by Wietse before posting this.  ++bsa]

At our site, we have a few accounts that are managed by more than one
user.  Instead of giving away the password to an account "foo" we
install a set-[ug]id program, "su-foo", that allows a limited group of
users to work with the "foo" account after they have correctly entered
THEIR OWN password.

This program has been tested with SunOS 4.0.3 and Ultrix 3.0, but it
should also work with most other BSD-like UNIX implementations. The
only System-V variant I have tested with is Microport SV/AT 2.3, a
port of System V Release 2.

#--------------------------------CUT HERE-------------------------------------
#! /bin/sh
#
# This is a shell archive.  Save this into a file, edit it
# and delete all lines above this comment.  Then give this
# file to sh by executing the command "sh file".  The files
# will be extracted into the current directory owned by
# you with default permissions.
#
# The files contained herein are:
#
# -rw-r--r--  1 allbery      1203 May 27 16:31 Makefile
# -rw-r--r--  1 allbery       707 May 27 16:31 README
# -rw-r--r--  1 allbery      1953 May 27 16:57 su-someone.1
# -rw-r--r--  1 allbery      6585 May 27 16:57 su-someone.c
#
echo 'x - Makefile'
if test -f Makefile; then echo 'shar: not overwriting Makefile'; else
sed 's/^X//' << '________This_Is_The_END________' > Makefile
X# @(#) Makefile 1.4 90/05/27 18:53:37
X
X# Usage:
X#	make NAME=name
X#
X#	Produces su-name.c, invokes an editor to edit the table of
X#	authorized users in su-name.c, and compiles the program.
X#	With BSD UNIX, the executable should be installed set-uid 
X#	and set-gid to the desired uid and gid. If you are running 
X#	SYSV the program must be installed set-uid root and NAME 
X#	must be defined in the CFLAGS macro below.
X
X# CFLAGS
X#
X# -DUSE_HER_SHELL	if you want the shell specified in the password data 
X#			base. Otherwise, you will always get /bin/sh.
X#
X# -DNAME=\"$(NAME)\"	if you are running SYSV; this wires the desired user 
X#			ID into the program, and requires that it be installed 
X#			set-uid root.
X#
X# -Drindex=strrchr	if you don't have rindex().
X
XNAME	= $(USER)
XCFLAGS	= -DUSE_HER_SHELL -DNAME=\"$(NAME)\" -Drindex=strrchr
X
XSHELL	= /bin/sh
XFILES	= README su-someone.c Makefile
XKIT	= $(FILES) su-someone.1
X
Xsu-$(NAME): su-$(NAME).c
X	cc $(CFLAGS) -o $@ $?
X
Xsu-$(NAME).c: su-someone.c
X	cp $? $@
X	chmod u+w $@
X	$${EDITOR-vi} +200 $@
X
Xclean:
X	rm -f *.o core nohup.out su-$(NAME)
X
Xsu-someone.1: su-someone.c
X	srctoman $? >$@
X
Xshar:	$(KIT)
X	shar $(KIT)
X
Xarchive: $(FILES)
X	sarch $(FILES)
X	touch archive
________This_Is_The_END________
if test `wc -c < Makefile` -ne 1203; then
	echo 'shar: Makefile was damaged during transit (should have been 1203 bytes)'
fi
fi		; : end of overwriting check
echo 'x - README'
if test -f README; then echo 'shar: not overwriting README'; else
sed 's/^X//' << '________This_Is_The_END________' > README
X@(#) README 1.3 90/05/27 19:29:13
X
Xsu-someone - use your own password to switch to another user ID.
X
XAt our site, we have a few accounts that are managed by more than one
Xuser.  Instead of giving away the password to an account "foo" we
Xinstall a set-[ug]id program, "su-foo", that allows a limited group of
Xusers to work with the "foo" account after they have correctly entered
XTHEIR OWN password.
X
XThis program has been tested with SunOS 4.0.3 and Ultrix 3.0, but it
Xshould also work with most other BSD-like UNIX implementations. The
Xonly System-V variant I have tested with is Microport SV/AT 2.3.
X
XMore details are described in the Makefile and in the man page.
X
X	Wietse Venema (wietse@wzv.win.tue.nl)
________This_Is_The_END________
if test `wc -c < README` -ne 707; then
	echo 'shar: README was damaged during transit (should have been 707 bytes)'
fi
fi		; : end of overwriting check
echo 'x - su-someone.1'
if test -f su-someone.1; then echo 'shar: not overwriting su-someone.1'; else
sed 's/^X//' << '________This_Is_The_END________' > su-someone.1
X.TH SU-SOMEONE 1 
X.ad
X.fi
X.SH NAME
Xsu-someone
X\-
Xuse your own password to switch to another user ID
X.SH SYNOPSIS
X.na
X.nf
Xsu-\fIsomeone\fR [arguments]
X.SH DESCRIPTION
X.ad
X.fi
XThe su-\fIsomeone\fR command allows a limited group of users to
Xwork under a given user id (e.g. \fIsomeone\fR) without having know
Xits password. Users have to enter \fItheir own\fR password in
Xorder to get the privileges of the \fIsomeone\fR account.
X
XAfter successful validation the user is given a shell process
X(default: /bin/sh) with the appropriate uid, gid and with a sane
Xenvironment and umask. Where possible, the shell prompt will reflect
Xthe uid of that process.
X
XAny arguments given to su-\fIsomeone\fR are passed as arguments to the
Xshell process.
X
XOnly authorized users are allowed to use this command; in
Xorder to make cheating a bit more difficult, the table of authorized
Xusers is compiled into the program.
X
XWith BSD-like UNIX implementations, the executable file should be
Xinstalled set-uid and set-gid to the \fIsomeone\fR account.
X
XWith System-V Release 2, the executable should be set-uid root and
Xthe \fIsomeone\fR account name must be wired into the program.
X
XYou can give the executable any name you want, but be sure that
Xonly the owner can overwrite it.
X.SH COMMANDS
X.na
X.nf
X/bin/sh, other login shells.
X.SH FILES
X.na
X.nf
X/dev/tty, to read the password.
X
XShell startup files, but usually no login procedures.
X.SH ENVIRONMENT VARIABLES
X.na
X.nf
XSHELL, PATH, IFS, HOME and PS1 are overwritten.
X.SH SEE ALSO
X.na
X.nf
Xsu(1)
X.SH DIAGNOSTICS
X.ad
X.fi
XThe program prints a diagnostic and terminates with a non-zero
Xexit status if there are problems (authorization, environment
Xupdate, shell startup).
X.SH AUTHOR(S)
X.na
X.nf
XWietse Venema
XEindhoven University of Technology
XDepartment of Mathematics and Computer Science
XDen Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X.SH LAST MODIFICATION
X.na
X.nf
X90/05/27 20:44:51
X.SH VERSION/RELEASE
X.na
X.nf
X1.7
________This_Is_The_END________
if test `wc -c < su-someone.1` -ne 1953; then
	echo 'shar: su-someone.1 was damaged during transit (should have been 1953 bytes)'
fi
fi		; : end of overwriting check
echo 'x - su-someone.c'
if test -f su-someone.c; then echo 'shar: not overwriting su-someone.c'; else
sed 's/^X//' << '________This_Is_The_END________' > su-someone.c
X/*++
X/* NAME
X/*	su-someone 1
X/* SUMMARY
X/*	use your own password to switch to another user ID
X/* SYNOPSIS
X/*	su-\fIsomeone\fR [arguments]
X/* DESCRIPTION
X/*	The su-\fIsomeone\fR command allows a limited group of users to 
X/*	work under a given user id (e.g. \fIsomeone\fR) without having know 
X/*	its password. Users have to enter \fItheir own\fR password in
X/*	order to get the privileges of the \fIsomeone\fR account.
X/*
X/*	After successful validation the user is given a shell process
X/*	(default: /bin/sh) with the appropriate uid, gid and with a sane
X/*	environment and umask. Where possible, the shell prompt will reflect
X/*	the uid of that process.
X/*
X/*	Any arguments given to su-\fIsomeone\fR are passed as arguments to the
X/*	shell process.
X/*
X/*	Only authorized users are allowed to use this command; in
X/*	order to make cheating a bit more difficult, the table of authorized
X/*	users is compiled into the program.
X/*
X/*	With BSD-like UNIX implementations, the executable file should be
X/*	installed set-uid and set-gid to the \fIsomeone\fR account.
X/*
X/*	With System-V Release 2, the executable should be set-uid root and
X/*	the \fIsomeone\fR account name must be wired into the program.
X/*
X/*	You can give the executable any name you want, but be sure that
X/*	only the owner can overwrite it.
X/* COMMANDS
X/*	/bin/sh, other login shells.
X/* FILES
X/*	/dev/tty, to read the password.
X/*
X/*	Shell startup files, but usually no login procedures.
X/* ENVIRONMENT VARIABLES
X/*	SHELL, PATH, IFS, HOME and PS1 are overwritten.
X/* SEE ALSO
X/*	su(1)
X/* DIAGNOSTICS
X/*	The program prints a diagnostic and terminates with a non-zero
X/*	exit status if there are problems (authorization, environment
X/*	update, shell startup).
X/* AUTHOR(S)
X/*	Wietse Venema
X/*	Eindhoven University of Technology
X/*	Department of Mathematics and Computer Science
X/*	Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
X/* LAST MODIFICATION
X/*	90/05/27 20:54:03
X/* VERSION/RELEASE
X/*	1.7
X/*--*/
X
X /*
X  * This program is in the public domain. You can do anything with it as long
X  * as you do not remove the references to the original author.
X  */
X
X#ifndef lint
Xstatic char sccsid[] = "@(#) su-someone.c 1.7 90/05/27 20:54:03";
X#endif
X
X#include <stdio.h>
X#include <pwd.h>
X#include <varargs.h>
X
X /*
X  * The first purpose of the program is to avoid the security problems that
X  * arise when a password has to be known to several people.
X  * 
X  * The second purpose of the program is to set up a decent environment: shell,
X  * umask, path, home and field separators.
X  * 
X  * The default is to invoke the Bourne shell. If you want to use the shell as
X  * specified in the password data base, define USE_HER_SHELL.
X  */
X
X#ifdef	USE_HER_SHELL
X#define SHELL	(*pwd->pw_shell ? pwd->pw_shell : "/bin/sh")
X#else
X#define SHELL	"/bin/sh"
X#endif
X
X#define	UMASK	022
X#define	PATH	"/usr/ucb:/bin:/usr/bin:/usr/local/bin:."
X#define	IFS	" \t\n"
X
X /* Library functions... */
X
Xextern struct passwd *getpwuid();
Xextern struct passwd *getpwnam();
Xextern char *getpass();
Xextern char *crypt();
Xextern void exit();
Xextern void perror();
Xextern char *rindex();
Xextern char *malloc();
X
X /* Local stuff... */
X
Xstatic char *progname;
Xstatic int islegal();
Xstatic void newenv();
Xstatic void giveup();
X
Xint     main(argc, argv)
Xint     argc;
Xchar  **argv;
X{
X    struct passwd *pwd;
X    char    ps1[BUFSIZ];
X    char   *pass;
X
X    progname = *argv;
X
X    /* Validate the user who invoked us. */
X
X    if ((pwd = getpwuid(getuid())) == NULL)
X	giveup("I don't know you");
X    if (!islegal(pwd->pw_name))
X	giveup("You are not authorized to use this program");
X    if ((pass = getpass("Enter YOUR OWN password:")) == 0)
X	giveup("Can't read your password");
X    if (strcmp(pwd->pw_passwd, crypt(pass, pwd->pw_passwd)) != 0)
X	giveup("Sorry");
X
X    /*
X     * Erase the password now that we do not need it anymore. This avoids a
X     * security problem should we ever dump core.
X     */
X
X    while (*pass)
X	*pass++ = 0;
X
X    /*
X     * With BSD-like UNIX, install the program set-uid, set-gid. The program
X     * will deduce the desired uid, gid from the effective uid, gid.
X     * 
X     * With SYSV-like UNIX, install the program set-uid root. The program will
X     * deduce the desired uid, gid from a hard-wired name.
X     */
X
X#ifndef	NAME					/* use effective uid, gid */
X    if ((pwd = getpwuid(geteuid())) == NULL)
X	giveup("I don't know her");
X#else						/* use hard-wired name */
X    if ((pwd = getpwnam(NAME)) == 0)
X	giveup("I don't know '%s'", NAME);
X#endif
X
X    /* Switch to the desired uid, gid. */
X
X    if (setgid(pwd->pw_gid))
X	giveup("setgid(%d) failed", pwd->pw_gid);
X    if (setuid(pwd->pw_uid))
X	giveup("setuid(%d) failed", pwd->pw_uid);
X
X    /*
X     * Set up a sane environment and umask. Abort if we cannot update
X     * some critical environment variables.
X     */
X
X    (void) umask(UMASK);
X    newenv("PATH", PATH);
X    newenv("SHELL", SHELL);
X    newenv("HOME", pwd->pw_dir);
X    newenv("IFS", IFS);
X
X    /*
X     * The following is relevant only for /bin/sh and relatives. Attempt to
X     * change the prompt to reflect the switched uid.
X     */
X
X    (void) sprintf(ps1, "PS1=SU-%s> ", pwd->pw_name);
X    (void) putenv(ps1);
X
X    /*
X     * Ready to invoke a shell. All arguments given to us are passed on to
X     * that shell. 
X     */
X
X    if ((argv[0] = rindex(SHELL, '/')) == 0)
X	argv[0] = SHELL;
X    else
X	argv[0]++;				/* skip '/' character */
X    (void) execv(SHELL, argv);
X    giveup("Can't invoke %s", SHELL);
X    /* NOTREACHED */
X}
X
X/* islegal - check user is in table of legal names */
X
Xstatic int islegal(logname)
Xchar   *logname;
X{
X    char  **cpp;
X    static char *legalname[] = {
X	"wietse",
X	0,				/* TERMINATOR */
X    };
X
X    for (cpp = legalname; *cpp; cpp++) {
X	if (0 == strcmp(logname, *cpp))
X	    return (1);
X    }
X    return (0);
X}
X
X/* newenv - update environment variable; abort in case of problems */
X
Xstatic void newenv(name, value)
Xchar   *name;
Xchar   *value;
X{
X    char   *cp;
X
X    if ((cp = malloc((unsigned) strlen(name) + strlen(value) + 2)) == 0)
X	giveup("Out of memory");
X    (void) sprintf(cp, "%s=%s", name, value);	/* yes this is gross. so what */
X    if (putenv(cp))
X	giveup("Can't update %s environment variable", name);
X}
X
X/* giveup - print diagnostic on the standard error output and terminate */
X
X/* VARARGS */
X
Xstatic void giveup(va_alist) 
Xva_dcl
X{
X    va_list ap;
X    char   *fmt;
X
X    (void) fprintf(stderr, "%s: ", progname);
X    va_start(ap);
X    fmt = va_arg(ap, char *);
X    (void) vfprintf(stderr, fmt, ap);
X    va_end(ap);
X    (void) putc('\n', stderr);
X    exit(1);
X}
________This_Is_The_END________
if test `wc -c < su-someone.c` -ne 6585; then
	echo 'shar: su-someone.c was damaged during transit (should have been 6585 bytes)'
fi
fi		; : end of overwriting check
exit 0