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