xref: /csrg-svn/usr.bin/su/su.c (revision 35716)
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*35716Sbostic static char sccsid[] = "@(#)su.c	5.7 (Berkeley) 09/26/88";
2635489Sbostic #endif /* not lint */
2719908Sdist 
28*35716Sbostic #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;
45*35716Sbostic 	uid_t ruid, getuid();
4635489Sbostic 	int ch, fulllogin, fastlogin, prio;
47*35716Sbostic 	enum { UNSET, YES, NO } iscsh = UNSET;
48*35716Sbostic 	char *user, *shell, *username, *cleanenv[2];
49*35716Sbostic 	char namebuf[50], shellbuf[MAXPATHLEN];
50*35716Sbostic 	char *crypt(), *getpass(), *getenv(), *getlogin(), *rindex(), *strcpy();
511109Sbill 
5235489Sbostic 	fulllogin = fastlogin = 0;
5335489Sbostic 	while ((ch = getopt(argc, argv, "-fl")) != EOF)
5435489Sbostic 		switch((char)ch) {
55*35716Sbostic 		case 'f':
56*35716Sbostic 			fastlogin = 1;
57*35716Sbostic 			break;
5835489Sbostic 		case '-':
5935489Sbostic 		case 'l':
6035489Sbostic 			fulllogin = 1;
6135489Sbostic 			break;
6235489Sbostic 		case '?':
6335489Sbostic 		default:
6435489Sbostic 			fprintf(stderr, "usage: su [-fl] [login]\n");
6535489Sbostic 			exit(1);
6635489Sbostic 		}
6735489Sbostic 	argv += optind;
6835489Sbostic 
69*35716Sbostic 	if ((pwd = getpwuid(ruid = getuid())) == NULL) {
7035489Sbostic 		fprintf(stderr, "su: who are you?\n");
7116216Sralph 		exit(1);
7216216Sralph 	}
73*35716Sbostic 	username = strcpy(namebuf, pwd->pw_name);
74*35716Sbostic 	if (!fulllogin)
75*35716Sbostic 		if (pwd->pw_shell && *pwd->pw_shell)
76*35716Sbostic 			shell = strcpy(shellbuf,  pwd->pw_shell);
77*35716Sbostic 		else {
78*35716Sbostic 			shell = "/bin/sh";
79*35716Sbostic 			iscsh = NO;
80*35716Sbostic 		}
8135489Sbostic 
82*35716Sbostic 	user = *argv ? *argv++ : "root";
8316216Sralph 	if ((pwd = getpwnam(user)) == NULL) {
8435489Sbostic 		fprintf(stderr, "su: unknown login %s\n", user);
8516216Sralph 		exit(1);
8616216Sralph 	}
8715914Sralph 
8835489Sbostic 	/* only allow those in group zero to su to root. */
89*35716Sbostic 	if (pwd->pw_uid == 0 && (gr = getgrgid((gid_t)0)))
9035489Sbostic 		for (g = gr->gr_mem;; ++g) {
9135489Sbostic 			if (!*g) {
9235489Sbostic 				fprintf(stderr, "su: you are not in the correct group to su %s.\n", user);
9335489Sbostic 				exit(1);
9435489Sbostic 			}
9535489Sbostic 			if (!strcmp(username, *g))
9635489Sbostic 				break;
9715897Sralph 		}
9815897Sralph 
9935489Sbostic 	errno = 0;
10035489Sbostic 	prio = getpriority(PRIO_PROCESS, 0);
10135489Sbostic 	if (errno)
10235489Sbostic 		prio = 0;
10335489Sbostic 	(void)setpriority(PRIO_PROCESS, 0, -2);
10435489Sbostic 
10535489Sbostic 	if ((p = getlogin()) && *p)
10635489Sbostic 		username = p;
10735489Sbostic 
108*35716Sbostic 	if (*pwd->pw_passwd && ruid) {
10935489Sbostic 		p = getpass("Password:");
11035489Sbostic 		if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) {
11135489Sbostic 			fprintf(stderr, "Sorry\n");
11235489Sbostic 			if (pwd->pw_uid == 0)
113*35716Sbostic 				syslog(LOG_CRIT|LOG_AUTH, "su: BAD SU %s on %s",
114*35716Sbostic 				    username, ttyname(2));
11535489Sbostic 			exit(1);
1161109Sbill 		}
1171109Sbill 	}
118*35716Sbostic 
119*35716Sbostic 	/* if target user has no password, or fulllogin, use their shell */
120*35716Sbostic 	if (!*pwd->pw_passwd || fulllogin)
121*35716Sbostic 		if (pwd->pw_shell && *pwd->pw_shell) {
122*35716Sbostic 			shell = pwd->pw_shell;
123*35716Sbostic 			iscsh = UNSET;
124*35716Sbostic 		} else {
125*35716Sbostic 			shell = "/bin/sh";
126*35716Sbostic 			iscsh = NO;
127*35716Sbostic 		}
128*35716Sbostic 
129*35716Sbostic 	if (iscsh == UNSET) {
130*35716Sbostic 		if (p = rindex(shell, '/'))
131*35716Sbostic 			++p;
132*35716Sbostic 		else
133*35716Sbostic 			p = shell;
134*35716Sbostic 		iscsh = strcmp(p, "csh") ? NO : YES;
135*35716Sbostic 	}
136*35716Sbostic 
13710045Ssam 	if (setgid(pwd->pw_gid) < 0) {
13810045Ssam 		perror("su: setgid");
13935489Sbostic 		exit(1);
14010045Ssam 	}
14112696Ssam 	if (initgroups(user, pwd->pw_gid)) {
14210045Ssam 		fprintf(stderr, "su: initgroups failed\n");
14335489Sbostic 		exit(1);
14410045Ssam 	}
14510045Ssam 	if (setuid(pwd->pw_uid) < 0) {
14610045Ssam 		perror("su: setuid");
14735489Sbostic 		exit(1);
14810045Ssam 	}
14912696Ssam 	if (fulllogin) {
15035489Sbostic 		p = getenv("TERM");
15135489Sbostic 		cleanenv[0] = "PATH=:/usr/ucb:/bin:/usr/bin";
15235489Sbostic 		cleanenv[1] = NULL;
15312696Ssam 		environ = cleanenv;
154*35716Sbostic 		(void)setenv("HOME", pwd->pw_dir, 1);
155*35716Sbostic 		(void)setenv("SHELL", shell, 1);
15635489Sbostic 		(void)setenv("TERM", p, 1);
157*35716Sbostic 		(void)setenv("USER", pwd->pw_name, 1);
15812696Ssam 		if (chdir(pwd->pw_dir) < 0) {
15935489Sbostic 			fprintf(stderr, "su: no directory\n");
16035489Sbostic 			exit(1);
16112696Ssam 		}
16235489Sbostic 	}
1631109Sbill 
164*35716Sbostic 	if (fastlogin && iscsh == YES)
165*35716Sbostic 		*--argv = "-f";
1661109Sbill 
167*35716Sbostic 	/* csh strips the first character... */
168*35716Sbostic 	*--argv = fulllogin ? "-su" : iscsh == YES ? "_su" : "su";
169*35716Sbostic 
17035489Sbostic 	if (pwd->pw_uid == 0)
171*35716Sbostic 		syslog(LOG_NOTICE|LOG_AUTH, "su: %s on %s",
172*35716Sbostic 		    username, ttyname(2));
1731109Sbill 
17435489Sbostic 	(void)setpriority(PRIO_PROCESS, 0, prio);
1751109Sbill 
17635489Sbostic 	execv(shell, argv);
177*35716Sbostic 	fprintf(stderr, "su: no shell.\n");
17835489Sbostic 	exit(1);
1791109Sbill }
180