trivial pathname changes
[unix-history] / usr / src / usr.bin / su / su.c
CommitLineData
31e00b32 1/*
7d5e1706
KB
2 * Copyright (c) 1988 The Regents of the University of California.
3 * All rights reserved.
4 *
cb956e54 5 * %sccs.include.redist.c%
31e00b32
DF
6 */
7
8#ifndef lint
9char copyright[] =
7d5e1706 10"@(#) Copyright (c) 1988 The Regents of the University of California.\n\
31e00b32 11 All rights reserved.\n";
7d5e1706 12#endif /* not lint */
31e00b32 13
13dd8b1d 14#ifndef lint
58a34b62 15static char sccsid[] = "@(#)su.c 5.21 (Berkeley) %G%";
7d5e1706 16#endif /* not lint */
13dd8b1d 17
a8d8c335 18#include <sys/param.h>
4f4c2c68
SL
19#include <sys/time.h>
20#include <sys/resource.h>
7d5e1706
KB
21#include <syslog.h>
22#include <stdio.h>
23#include <pwd.h>
24#include <grp.h>
d9e13dc0 25#include <string.h>
dbf8133b 26#include <unistd.h>
3a7a366d 27#include "pathnames.h"
3a265c7a 28
d9e13dc0 29#ifdef KERBEROS
302dd6d2 30#include <kerberosIV/des.h>
ba1b9d1d 31#include <kerberosIV/krb.h>
094e5ff2 32#include <netdb.h>
d9e13dc0 33
e5b1d5e7 34#define ARGSTR "-Kflm"
d9e13dc0
KB
35
36int use_kerberos = 1;
094e5ff2
KF
37#else
38#define ARGSTR "-flm"
39#endif
40
7d5e1706 41main(argc, argv)
13dd8b1d 42 int argc;
7d5e1706 43 char **argv;
3a265c7a 44{
7d5e1706
KB
45 extern char **environ;
46 extern int errno, optind;
7d5e1706
KB
47 register struct passwd *pwd;
48 register char *p, **g;
49 struct group *gr;
a8d8c335 50 uid_t ruid, getuid();
e5b1d5e7 51 int asme, ch, asthem, fastlogin, prio;
a8d8c335 52 enum { UNSET, YES, NO } iscsh = UNSET;
6964f298 53 char *user, *shell, *username, *cleanenv[2], *nargv[4], **np;
d9e13dc0 54 char shellbuf[MAXPATHLEN];
dbf8133b 55 char *crypt(), *getpass(), *getenv(), *getlogin(), *mytty();
3a265c7a 56
6964f298
KB
57 np = &nargv[3];
58 *np-- = NULL;
e5b1d5e7 59 asme = asthem = fastlogin = 0;
094e5ff2 60 while ((ch = getopt(argc, argv, ARGSTR)) != EOF)
7d5e1706 61 switch((char)ch) {
e5b1d5e7
KB
62#ifdef KERBEROS
63 case 'K':
64 use_kerberos = 0;
65 break;
66#endif
a8d8c335
KB
67 case 'f':
68 fastlogin = 1;
69 break;
7d5e1706
KB
70 case '-':
71 case 'l':
e5b1d5e7
KB
72 asme = 0;
73 asthem = 1;
7d5e1706 74 break;
6964f298
KB
75 case 'm':
76 asme = 1;
e5b1d5e7 77 asthem = 0;
6964f298 78 break;
7d5e1706
KB
79 case '?':
80 default:
d9e13dc0
KB
81 (void)fprintf(stderr, "usage: su [%s] [login]\n",
82 ARGSTR);
7d5e1706
KB
83 exit(1);
84 }
85 argv += optind;
da31c6da 86
6964f298
KB
87 errno = 0;
88 prio = getpriority(PRIO_PROCESS, 0);
89 if (errno)
90 prio = 0;
91 (void)setpriority(PRIO_PROCESS, 0, -2);
92
93 /* get current login name and shell */
a8d8c335 94 if ((pwd = getpwuid(ruid = getuid())) == NULL) {
7d5e1706 95 fprintf(stderr, "su: who are you?\n");
96f93d9e
RC
96 exit(1);
97 }
d9e13dc0 98 username = strdup(pwd->pw_name);
6964f298 99 if (asme)
a8d8c335
KB
100 if (pwd->pw_shell && *pwd->pw_shell)
101 shell = strcpy(shellbuf, pwd->pw_shell);
102 else {
3a7a366d 103 shell = _PATH_BSHELL;
a8d8c335
KB
104 iscsh = NO;
105 }
7d5e1706 106
094e5ff2 107 /* get target login information, default to root */
6964f298 108 user = *argv ? *argv : "root";
96f93d9e 109 if ((pwd = getpwnam(user)) == NULL) {
7d5e1706 110 fprintf(stderr, "su: unknown login %s\n", user);
96f93d9e
RC
111 exit(1);
112 }
7d5e1706
KB
113
114 /* only allow those in group zero to su to root. */
a8d8c335 115 if (pwd->pw_uid == 0 && (gr = getgrgid((gid_t)0)))
7d5e1706
KB
116 for (g = gr->gr_mem;; ++g) {
117 if (!*g) {
12d409ff
KB
118 (void)fprintf(stderr,
119 "su: you are not in the correct group to su %s.\n", user);
7d5e1706
KB
120 exit(1);
121 }
122 if (!strcmp(username, *g))
123 break;
a8a168db 124 }
12d409ff 125 openlog("su", LOG_CONS, 0);
a8a168db 126
d9e13dc0
KB
127 if (ruid) {
128#ifdef KERBEROS
129 if (!use_kerberos || kerberos(username, user, pwd->pw_uid))
094e5ff2 130#endif
d9e13dc0
KB
131 /* if target requires a password, verify it */
132 if (*pwd->pw_passwd) {
133 p = getpass("Password:");
134 if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) {
135 fprintf(stderr, "Sorry\n");
58a34b62
KF
136 syslog(LOG_AUTH|LOG_CRIT,
137 "BAD SU %s on %s to %s", username,
138 mytty(), user);
d9e13dc0
KB
139 exit(1);
140 }
3a265c7a 141 }
3a265c7a 142 }
a8d8c335 143
6fad2abb
KB
144 if (asme) {
145 /* if asme and non-standard target shell, must be root */
146 if (!chshell(pwd->pw_shell) && ruid) {
58a34b62
KF
147 (void)fprintf(stderr,
148 "su: permission denied (shell).\n");
6fad2abb 149 exit(1);
a8d8c335 150 }
d9e13dc0 151 } else if (pwd->pw_shell && *pwd->pw_shell) {
6fad2abb
KB
152 shell = pwd->pw_shell;
153 iscsh = UNSET;
154 } else {
3a7a366d 155 shell = _PATH_BSHELL;
6fad2abb
KB
156 iscsh = NO;
157 }
a8d8c335 158
6964f298 159 /* if we're forking a csh, we want to slightly muck the args */
a8d8c335
KB
160 if (iscsh == UNSET) {
161 if (p = rindex(shell, '/'))
162 ++p;
163 else
164 p = shell;
165 iscsh = strcmp(p, "csh") ? NO : YES;
166 }
167
6964f298 168 /* set permissions */
13dd8b1d
SL
169 if (setgid(pwd->pw_gid) < 0) {
170 perror("su: setgid");
7d5e1706 171 exit(1);
13dd8b1d 172 }
4f4c2c68 173 if (initgroups(user, pwd->pw_gid)) {
d9e13dc0 174 (void)fprintf(stderr, "su: initgroups failed.\n");
7d5e1706 175 exit(1);
13dd8b1d
SL
176 }
177 if (setuid(pwd->pw_uid) < 0) {
178 perror("su: setuid");
7d5e1706 179 exit(1);
13dd8b1d 180 }
6964f298
KB
181
182 if (!asme) {
e5b1d5e7 183 if (asthem) {
6964f298 184 p = getenv("TERM");
3a7a366d 185 cleanenv[0] = _PATH_SEARCHPATH;
6964f298
KB
186 cleanenv[1] = NULL;
187 environ = cleanenv;
188 (void)setenv("TERM", p, 1);
189 if (chdir(pwd->pw_dir) < 0) {
190 fprintf(stderr, "su: no directory\n");
191 exit(1);
192 }
193 }
e5b1d5e7 194 if (asthem || pwd->pw_uid)
6964f298 195 (void)setenv("USER", pwd->pw_name, 1);
a8d8c335
KB
196 (void)setenv("HOME", pwd->pw_dir, 1);
197 (void)setenv("SHELL", shell, 1);
3a265c7a 198 }
3a265c7a 199
6964f298
KB
200 if (iscsh == YES) {
201 if (fastlogin)
202 *np-- = "-f";
203 if (asme)
204 *np-- = "-m";
205 }
a8d8c335
KB
206
207 /* csh strips the first character... */
e5b1d5e7 208 *np = asthem ? "-su" : iscsh == YES ? "_su" : "su";
7d5e1706 209
58a34b62 210 syslog(LOG_NOTICE|LOG_AUTH, "%s on %s to %s", username, mytty(), user);
7d5e1706
KB
211
212 (void)setpriority(PRIO_PROCESS, 0, prio);
213
6964f298 214 execv(shell, np);
d9e13dc0 215 (void)fprintf(stderr, "su: %s not found.\n", shell);
7d5e1706 216 exit(1);
3a265c7a 217}
7b34c4f8
KB
218
219chshell(sh)
220 char *sh;
221{
d9e13dc0
KB
222 register char *cp;
223 char *getusershell();
7b34c4f8
KB
224
225 while ((cp = getusershell()) != NULL)
226 if (!strcmp(cp, sh))
227 return(1);
228 return(0);
229}
094e5ff2 230
dbf8133b
KB
231char *
232mytty()
233{
234 char *p, *ttyname();
235
236 return((p = ttyname(STDERR_FILENO)) ? p : "UNKNOWN TTY");
237}
238
d9e13dc0
KB
239#ifdef KERBEROS
240kerberos(username, user, uid)
241 char *username, *user;
242 int uid;
243{
244 extern char *krb_err_txt[];
245 KTEXT_ST ticket;
246 AUTH_DAT authdata;
247 struct hostent *hp;
248 register char *p;
249 int kerno;
250 u_long faddr;
58a34b62 251 char lrealm[REALM_SZ], krbtkfile[MAXPATHLEN];
d9e13dc0 252 char hostname[MAXHOSTNAMELEN], savehost[MAXHOSTNAMELEN];
dbf8133b 253 char *mytty();
d9e13dc0
KB
254
255 if (krb_get_lrealm(lrealm, 1) != KSUCCESS) {
256 (void)fprintf(stderr, "su: couldn't get local realm.\n");
257 return(1);
258 }
259 if (koktologin(username, lrealm, user) && !uid) {
260 (void)fprintf(stderr, "kerberos su: not in %s's ACL.\n", user);
261 return(1);
262 }
263 (void)sprintf(krbtkfile, "%s_%s_%d", TKT_ROOT, user, getuid());
d9e13dc0
KB
264
265 (void)setenv("KRBTKFILE", krbtkfile, 1);
d9e13dc0
KB
266 if (setuid(0) < 0) {
267 perror("su: setuid");
268 return(1);
269 }
270 (void)unlink(krbtkfile);
d9e13dc0 271
58a34b62
KF
272 /*
273 * Little trick here -- if we are su'ing to root,
274 * we need to get a ticket for "xxx.root", where xxx represents
275 * the name of the person su'ing. Otherwise (non-root case),
276 * we need to get a ticket for "yyy.", where yyy represents
277 * the name of the person being su'd to, and the instance is null
278 *
279 * Also: POLICY: short ticket lifetime for root
280 */
281 kerno = krb_get_pw_in_tkt((uid == 0 ? username : user),
282 (uid == 0 ? "root" : ""), lrealm,
283 "krbtgt", lrealm, (uid == 0 ? 2 : DEFAULT_TKT_LIFE), 0);
d9e13dc0
KB
284
285 if (kerno != KSUCCESS) {
58a34b62
KF
286 if (kerno == KDC_PR_UNKNOWN) {
287 fprintf(stderr, "principal unknown: %s.%s@%s\n",
288 (uid == 0 ? username : user),
289 (uid == 0 ? "root" : ""), lrealm);
d9e13dc0 290 return(1);
58a34b62 291 }
d9e13dc0
KB
292 (void)printf("su: unable to su: %s\n", krb_err_txt[kerno]);
293 syslog(LOG_NOTICE|LOG_AUTH,
58a34b62
KF
294 "su: BAD Kerberos SU: %s on %s to %s: %s",
295 username, mytty(), user, krb_err_txt[kerno]);
d9e13dc0
KB
296 return(1);
297 }
298
299 if (chown(krbtkfile, uid, -1) < 0) {
300 perror("su: chown:");
301 (void)unlink(krbtkfile);
302 return(1);
303 }
304
305 (void)setpriority(PRIO_PROCESS, 0, -2);
306
307 if (gethostname(hostname, sizeof(hostname)) == -1) {
308 perror("su: hostname");
309 dest_tkt();
310 return(1);
311 }
312
313 (void)strncpy(savehost, krb_get_phost(hostname), sizeof(savehost));
314 savehost[sizeof(savehost) - 1] = '\0';
315
316 kerno = krb_mk_req(&ticket, "rcmd", savehost, lrealm, 33);
317
318 if (kerno == KDC_PR_UNKNOWN) {
319 (void)printf("Warning: tgt not verified.\n");
58a34b62
KF
320 syslog(LOG_NOTICE|LOG_AUTH,
321 "su: %s on %s to %s, TGT not verified",
322 username, mytty(), user);
d9e13dc0 323 } else if (kerno != KSUCCESS) {
58a34b62
KF
324 (void)printf("Unable to use TGT: %s\n", krb_err_txt[kerno]);
325 syslog(LOG_NOTICE|LOG_AUTH, "su: failed su: %s on %s to %s: %s",
326 username, mytty(), user, krb_err_txt[kerno]);
d9e13dc0
KB
327 dest_tkt();
328 return(1);
329 } else {
330 if (!(hp = gethostbyname(hostname))) {
331 (void)printf("su: can't get addr of %s\n", hostname);
332 dest_tkt();
333 return(1);
334 }
335 (void)bcopy((char *)hp->h_addr, (char *)&faddr, sizeof(faddr));
336
337 if ((kerno = krb_rd_req(&ticket, "rcmd", savehost, faddr,
338 &authdata, "")) != KSUCCESS) {
339 (void)printf("su: unable to verify rcmd ticket: %s\n",
340 krb_err_txt[kerno]);
341 syslog(LOG_NOTICE|LOG_AUTH,
58a34b62
KF
342 "su: failed su: %s on %s to %s: %s", username,
343 mytty(), user, krb_err_txt[kerno]);
d9e13dc0
KB
344 dest_tkt();
345 return(1);
346 }
347 }
348 return(0);
349}
350
094e5ff2 351koktologin(name, realm, toname)
d9e13dc0 352 char *name, *realm, *toname;
094e5ff2 353{
d9e13dc0
KB
354 register AUTH_DAT *kdata;
355 AUTH_DAT kdata_st;
094e5ff2 356
d9e13dc0 357 kdata = &kdata_st;
094e5ff2 358 bzero((caddr_t) kdata, sizeof(*kdata));
d9e13dc0
KB
359 (void)strcpy(kdata->pname, name);
360 (void)strcpy(kdata->pinst,
361 ((strcmp(toname, "root") == 0) ? "root" : ""));
362 (void)strcpy(kdata->prealm, realm);
094e5ff2
KF
363 return(kuserok(kdata, toname));
364}
365#endif