xref: /original-bsd/usr.bin/su/su.c (revision ec7df300)
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.2 (Berkeley) 06/07/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 again:
50 	if (argc > 1 && strcmp(argv[1], "-f") == 0) {
51 		fastlogin++;
52 		argc--, argv++;
53 		goto again;
54 	}
55 	if (argc > 1 && strcmp(argv[1], "-") == 0) {
56 		fulllogin++;
57 		argc--, argv++;
58 		goto again;
59 	}
60 	if (argc > 1 && argv[1][0] != '-') {
61 		user = argv[1];
62 		argc--, argv++;
63 	}
64 	if ((pwd = getpwuid(getuid())) == NULL) {
65 		fprintf(stderr, "Who are you?\n");
66 		exit(1);
67 	}
68 	strcpy(buf, pwd->pw_name);
69 	if ((pwd = getpwnam(user)) == NULL) {
70 		fprintf(stderr, "Unknown login: %s\n", user);
71 		exit(1);
72 	}
73 	/*
74 	 * Only allow those in group zero to su to root.
75 	 */
76 	if (pwd->pw_uid == 0) {
77 		struct	group *gr;
78 		int i;
79 
80 		if ((gr = getgrgid(0)) != NULL) {
81 			for (i = 0; gr->gr_mem[i] != NULL; i++)
82 				if (strcmp(buf, gr->gr_mem[i]) == 0)
83 					goto userok;
84 			fprintf(stderr, "You do not have permission to su %s\n",
85 				user);
86 			exit(1);
87 		}
88 	userok:
89 		setpriority(PRIO_PROCESS, 0, -2);
90 	}
91 
92 	if (pwd->pw_passwd[0] == '\0' || getuid() == 0)
93 		goto ok;
94 	password = getpass("Password:");
95 	if (strcmp(pwd->pw_passwd, crypt(password, pwd->pw_passwd)) != 0) {
96 		fprintf(stderr, "Sorry\n");
97 		if (pwd->pw_uid == 0) {
98 			openlog("su", 0, 0);
99 			syslog(LOG_SECURITY, "BAD SU %s on %s",
100 					getlogin(), ttyname(2));
101 		}
102 		exit(2);
103 	}
104 ok:
105 	endpwent();
106 	if (pwd->pw_uid == 0) {
107 		openlog("su", 0, 0);
108 		syslog(LOG_SECURITY, "%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