xref: /csrg-svn/usr.bin/su/su.c (revision 36305)
119908Sdist /*
235489Sbostic  * Copyright (c) 1988 The Regents of the University of California.
335489Sbostic  * All rights reserved.
435489Sbostic  *
535489Sbostic  * Redistribution and use in source and binary forms are permitted
635489Sbostic  * provided that the above copyright notice and this paragraph are
735489Sbostic  * duplicated in all such forms and that any documentation,
835489Sbostic  * advertising materials, and other materials related to such
935489Sbostic  * distribution and use acknowledge that the software was developed
1035489Sbostic  * by the University of California, Berkeley.  The name of the
1135489Sbostic  * University may not be used to endorse or promote products derived
1235489Sbostic  * from this software without specific prior written permission.
1335489Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1435489Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1535489Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1619908Sdist  */
1719908Sdist 
1810045Ssam #ifndef lint
1919908Sdist char copyright[] =
2035489Sbostic "@(#) Copyright (c) 1988 The Regents of the University of California.\n\
2119908Sdist  All rights reserved.\n";
2235489Sbostic #endif /* not lint */
2310045Ssam 
2419908Sdist #ifndef lint
25*36305Sbostic static char sccsid[] = "@(#)su.c	5.11 (Berkeley) 12/07/88";
2635489Sbostic #endif /* not lint */
2719908Sdist 
2835716Sbostic #include <sys/param.h>
2935489Sbostic #include <sys/time.h>
3035489Sbostic #include <sys/resource.h>
3135489Sbostic #include <syslog.h>
321109Sbill #include <stdio.h>
331109Sbill #include <pwd.h>
3415914Sralph #include <grp.h>
351109Sbill 
3635489Sbostic main(argc, argv)
3710045Ssam 	int argc;
3835489Sbostic 	char **argv;
391109Sbill {
4035489Sbostic 	extern char **environ;
4135489Sbostic 	extern int errno, optind;
4235489Sbostic 	register struct passwd *pwd;
4335489Sbostic 	register char *p, **g;
4435489Sbostic 	struct group *gr;
4535716Sbostic 	uid_t ruid, getuid();
4635721Sbostic 	int asme, ch, fulllogin, fastlogin, prio;
4735716Sbostic 	enum { UNSET, YES, NO } iscsh = UNSET;
4835721Sbostic 	char *user, *shell, *username, *cleanenv[2], *nargv[4], **np;
4935716Sbostic 	char namebuf[50], shellbuf[MAXPATHLEN];
5035716Sbostic 	char *crypt(), *getpass(), *getenv(), *getlogin(), *rindex(), *strcpy();
511109Sbill 
5235721Sbostic 	np = &nargv[3];
5335721Sbostic 	*np-- = NULL;
5435721Sbostic 	asme = fulllogin = fastlogin = 0;
5535721Sbostic 	while ((ch = getopt(argc, argv, "-flm")) != EOF)
5635489Sbostic 		switch((char)ch) {
5735716Sbostic 		case 'f':
5835716Sbostic 			fastlogin = 1;
5935716Sbostic 			break;
6035489Sbostic 		case '-':
6135489Sbostic 		case 'l':
6235489Sbostic 			fulllogin = 1;
6335489Sbostic 			break;
6435721Sbostic 		case 'm':
6535721Sbostic 			asme = 1;
6635721Sbostic 			break;
6735489Sbostic 		case '?':
6835489Sbostic 		default:
6935815Sbostic 			fprintf(stderr, "usage: su [-flm] [login]\n");
7035489Sbostic 			exit(1);
7135489Sbostic 		}
7235489Sbostic 	argv += optind;
7335489Sbostic 
7435721Sbostic 	errno = 0;
7535721Sbostic 	prio = getpriority(PRIO_PROCESS, 0);
7635721Sbostic 	if (errno)
7735721Sbostic 		prio = 0;
7835721Sbostic 	(void)setpriority(PRIO_PROCESS, 0, -2);
7935721Sbostic 
8035721Sbostic 	/* get current login name and shell */
8135716Sbostic 	if ((pwd = getpwuid(ruid = getuid())) == NULL) {
8235489Sbostic 		fprintf(stderr, "su: who are you?\n");
8316216Sralph 		exit(1);
8416216Sralph 	}
8535716Sbostic 	username = strcpy(namebuf, pwd->pw_name);
8635721Sbostic 	if (asme)
8735716Sbostic 		if (pwd->pw_shell && *pwd->pw_shell)
8835716Sbostic 			shell = strcpy(shellbuf,  pwd->pw_shell);
8935716Sbostic 		else {
9035716Sbostic 			shell = "/bin/sh";
9135716Sbostic 			iscsh = NO;
9235716Sbostic 		}
9335489Sbostic 
9435721Sbostic 	/* get target login information */
9535721Sbostic 	user = *argv ? *argv : "root";
9616216Sralph 	if ((pwd = getpwnam(user)) == NULL) {
9735489Sbostic 		fprintf(stderr, "su: unknown login %s\n", user);
9816216Sralph 		exit(1);
9916216Sralph 	}
10015914Sralph 
10135489Sbostic 	/* only allow those in group zero to su to root. */
10235716Sbostic 	if (pwd->pw_uid == 0 && (gr = getgrgid((gid_t)0)))
10335489Sbostic 		for (g = gr->gr_mem;; ++g) {
10435489Sbostic 			if (!*g) {
10535489Sbostic 				fprintf(stderr, "su: you are not in the correct group to su %s.\n", user);
10635489Sbostic 				exit(1);
10735489Sbostic 			}
10835489Sbostic 			if (!strcmp(username, *g))
10935489Sbostic 				break;
11015897Sralph 		}
11115897Sralph 
11235721Sbostic 	/* if target requires a password, verify it */
11335721Sbostic 	if (ruid && *pwd->pw_passwd) {
11435489Sbostic 		p = getpass("Password:");
11535489Sbostic 		if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) {
11635489Sbostic 			fprintf(stderr, "Sorry\n");
11735489Sbostic 			if (pwd->pw_uid == 0)
11835721Sbostic 				syslog(LOG_CRIT|LOG_AUTH, "su: BAD SU %s on %s", username, ttyname(2));
11935489Sbostic 			exit(1);
1201109Sbill 		}
1211109Sbill 	}
12235716Sbostic 
123*36305Sbostic 	if (asme) {
124*36305Sbostic 		/* if asme and non-standard target shell, must be root */
125*36305Sbostic 		if (!chshell(pwd->pw_shell) && ruid) {
126*36305Sbostic 			fprintf(stderr, "su: Permission denied.\n");
127*36305Sbostic 			exit(1);
12835716Sbostic 		}
129*36305Sbostic 	}
130*36305Sbostic 	else if (pwd->pw_shell && *pwd->pw_shell) {
131*36305Sbostic 		shell = pwd->pw_shell;
132*36305Sbostic 		iscsh = UNSET;
133*36305Sbostic 	} else {
134*36305Sbostic 		shell = "/bin/sh";
135*36305Sbostic 		iscsh = NO;
136*36305Sbostic 	}
13735716Sbostic 
13835721Sbostic 	/* if we're forking a csh, we want to slightly muck the args */
13935716Sbostic 	if (iscsh == UNSET) {
14035716Sbostic 		if (p = rindex(shell, '/'))
14135716Sbostic 			++p;
14235716Sbostic 		else
14335716Sbostic 			p = shell;
14435716Sbostic 		iscsh = strcmp(p, "csh") ? NO : YES;
14535716Sbostic 	}
14635716Sbostic 
14735721Sbostic 	/* set permissions */
14810045Ssam 	if (setgid(pwd->pw_gid) < 0) {
14910045Ssam 		perror("su: setgid");
15035489Sbostic 		exit(1);
15110045Ssam 	}
15212696Ssam 	if (initgroups(user, pwd->pw_gid)) {
15310045Ssam 		fprintf(stderr, "su: initgroups failed\n");
15435489Sbostic 		exit(1);
15510045Ssam 	}
15610045Ssam 	if (setuid(pwd->pw_uid) < 0) {
15710045Ssam 		perror("su: setuid");
15835489Sbostic 		exit(1);
15910045Ssam 	}
16035721Sbostic 
16135721Sbostic 	if (!asme) {
16235721Sbostic 		if (fulllogin) {
16335721Sbostic 			p = getenv("TERM");
16435721Sbostic 			cleanenv[0] = "PATH=:/usr/ucb:/bin:/usr/bin";
16535721Sbostic 			cleanenv[1] = NULL;
16635721Sbostic 			environ = cleanenv;
16735721Sbostic 			(void)setenv("TERM", p, 1);
16835721Sbostic 			if (chdir(pwd->pw_dir) < 0) {
16935721Sbostic 				fprintf(stderr, "su: no directory\n");
17035721Sbostic 				exit(1);
17135721Sbostic 			}
17235721Sbostic 		}
17335721Sbostic 		if (fulllogin || pwd->pw_uid)
17435721Sbostic 			(void)setenv("USER", pwd->pw_name, 1);
17535716Sbostic 		(void)setenv("HOME", pwd->pw_dir, 1);
17635716Sbostic 		(void)setenv("SHELL", shell, 1);
17735489Sbostic 	}
1781109Sbill 
17935721Sbostic 	if (iscsh == YES) {
18035721Sbostic 		if (fastlogin)
18135721Sbostic 			*np-- = "-f";
18235721Sbostic 		if (asme)
18335721Sbostic 			*np-- = "-m";
18435721Sbostic 	}
1851109Sbill 
18635716Sbostic 	/* csh strips the first character... */
18735721Sbostic 	*np = fulllogin ? "-su" : iscsh == YES ? "_su" : "su";
18835716Sbostic 
18935489Sbostic 	if (pwd->pw_uid == 0)
19035716Sbostic 		syslog(LOG_NOTICE|LOG_AUTH, "su: %s on %s",
19135716Sbostic 		    username, ttyname(2));
1921109Sbill 
19335489Sbostic 	(void)setpriority(PRIO_PROCESS, 0, prio);
1941109Sbill 
19535721Sbostic 	execv(shell, np);
19635716Sbostic 	fprintf(stderr, "su: no shell.\n");
19735489Sbostic 	exit(1);
1981109Sbill }
19935722Sbostic 
20035722Sbostic chshell(sh)
20135722Sbostic 	char *sh;
20235722Sbostic {
20335722Sbostic 	char *cp, *getusershell();
20435722Sbostic 
20535722Sbostic 	while ((cp = getusershell()) != NULL)
20635722Sbostic 		if (!strcmp(cp, sh))
20735722Sbostic 			return(1);
20835722Sbostic 	return(0);
20935722Sbostic }
210