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