xref: /original-bsd/usr.bin/su/su.c (revision 9c06e5c6)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 char copyright[] =
9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)su.c	5.3 (Berkeley) 09/17/85";
15 #endif not lint
16 
17 #include <stdio.h>
18 #include <pwd.h>
19 #include <grp.h>
20 #include <syslog.h>
21 #include <sys/types.h>
22 #include <sys/time.h>
23 #include <sys/resource.h>
24 
25 char	userbuf[16]	= "USER=";
26 char	homebuf[128]	= "HOME=";
27 char	shellbuf[128]	= "SHELL=";
28 char	pathbuf[128]	= "PATH=:/usr/ucb:/bin:/usr/bin";
29 char	*cleanenv[] = { userbuf, homebuf, shellbuf, pathbuf, 0, 0 };
30 char	*user = "root";
31 char	*shell = "/bin/sh";
32 int	fulllogin;
33 int	fastlogin;
34 
35 extern char	**environ;
36 struct	passwd *pwd;
37 char	*crypt();
38 char	*getpass();
39 char	*getenv();
40 
41 main(argc,argv)
42 	int argc;
43 	char *argv[];
44 {
45 	char *password;
46 	char buf[1000];
47 	FILE *fp;
48 
49 	openlog("su", LOG_ODELAY, LOG_AUTH);
50 
51 again:
52 	if (argc > 1 && strcmp(argv[1], "-f") == 0) {
53 		fastlogin++;
54 		argc--, argv++;
55 		goto again;
56 	}
57 	if (argc > 1 && strcmp(argv[1], "-") == 0) {
58 		fulllogin++;
59 		argc--, argv++;
60 		goto again;
61 	}
62 	if (argc > 1 && argv[1][0] != '-') {
63 		user = argv[1];
64 		argc--, argv++;
65 	}
66 	if ((pwd = getpwuid(getuid())) == NULL) {
67 		fprintf(stderr, "Who are you?\n");
68 		exit(1);
69 	}
70 	strcpy(buf, pwd->pw_name);
71 	if ((pwd = getpwnam(user)) == NULL) {
72 		fprintf(stderr, "Unknown login: %s\n", user);
73 		exit(1);
74 	}
75 	/*
76 	 * Only allow those in group zero to su to root.
77 	 */
78 	if (pwd->pw_uid == 0) {
79 		struct	group *gr;
80 		int i;
81 
82 		if ((gr = getgrgid(0)) != NULL) {
83 			for (i = 0; gr->gr_mem[i] != NULL; i++)
84 				if (strcmp(buf, gr->gr_mem[i]) == 0)
85 					goto userok;
86 			fprintf(stderr, "You do not have permission to su %s\n",
87 				user);
88 			exit(1);
89 		}
90 	userok:
91 		setpriority(PRIO_PROCESS, 0, -2);
92 	}
93 
94 	if (pwd->pw_passwd[0] == '\0' || getuid() == 0)
95 		goto ok;
96 	password = getpass("Password:");
97 	if (strcmp(pwd->pw_passwd, crypt(password, pwd->pw_passwd)) != 0) {
98 		fprintf(stderr, "Sorry\n");
99 		if (pwd->pw_uid == 0) {
100 			syslog(LOG_CRIT, "BAD SU %s on %s",
101 					getlogin(), ttyname(2));
102 		}
103 		exit(2);
104 	}
105 ok:
106 	endpwent();
107 	if (pwd->pw_uid == 0) {
108 		syslog(LOG_NOTICE, "%s on %s", getlogin(), ttyname(2));
109 		closelog();
110 	}
111 	if (setgid(pwd->pw_gid) < 0) {
112 		perror("su: setgid");
113 		exit(3);
114 	}
115 	if (initgroups(user, pwd->pw_gid)) {
116 		fprintf(stderr, "su: initgroups failed\n");
117 		exit(4);
118 	}
119 	if (setuid(pwd->pw_uid) < 0) {
120 		perror("su: setuid");
121 		exit(5);
122 	}
123 	if (pwd->pw_shell && *pwd->pw_shell)
124 		shell = pwd->pw_shell;
125 	if (fulllogin) {
126 		cleanenv[4] = getenv("TERM");
127 		environ = cleanenv;
128 	}
129 	if (strcmp(user, "root"))
130 		setenv("USER", pwd->pw_name, userbuf);
131 	setenv("SHELL", shell, shellbuf);
132 	setenv("HOME", pwd->pw_dir, homebuf);
133 	setpriority(PRIO_PROCESS, 0, 0);
134 	if (fastlogin) {
135 		*argv-- = "-f";
136 		*argv = "su";
137 	} else if (fulllogin) {
138 		if (chdir(pwd->pw_dir) < 0) {
139 			fprintf(stderr, "No directory\n");
140 			exit(6);
141 		}
142 		*argv = "-su";
143 	} else
144 		*argv = "su";
145 	execv(shell, argv);
146 	fprintf(stderr, "No shell\n");
147 	exit(7);
148 }
149 
150 setenv(ename, eval, buf)
151 	char *ename, *eval, *buf;
152 {
153 	register char *cp, *dp;
154 	register char **ep = environ;
155 
156 	/*
157 	 * this assumes an environment variable "ename" already exists
158 	 */
159 	while (dp = *ep++) {
160 		for (cp = ename; *cp == *dp && *cp; cp++, dp++)
161 			continue;
162 		if (*cp == 0 && (*dp == '=' || *dp == 0)) {
163 			strcat(buf, eval);
164 			*--ep = buf;
165 			return;
166 		}
167 	}
168 }
169 
170 char *
171 getenv(ename)
172 	char *ename;
173 {
174 	register char *cp, *dp;
175 	register char **ep = environ;
176 
177 	while (dp = *ep++) {
178 		for (cp = ename; *cp == *dp && *cp; cp++, dp++)
179 			continue;
180 		if (*cp == 0 && (*dp == '=' || *dp == 0))
181 			return (*--ep);
182 	}
183 	return ((char *)0);
184 }
185