xref: /original-bsd/old/athena/ksu/ksu.c (revision 07d71086)
1 /*
2  * $Source: /mit/kerberos/src/kuser/RCS/ksu.c,v $
3  * $Author: jtkohl $
4  */
5 
6 /*
7  * Copyright (c) 1988 The Regents of the University of California.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms are permitted
11  * provided that the above copyright notice and this paragraph are
12  * duplicated in all such forms and that any documentation,
13  * advertising materials, and other materials related to such
14  * distribution and use acknowledge that the software was developed
15  * by the University of California, Berkeley.  The name of the
16  * University may not be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21  */
22 
23 /*
24  * Kerberos additions Copyright 1987, 1988 by the Massachusetts Institute
25  * of Technology. For copying and distribution information, please see
26  * the file <mit-copyright.h>.
27  */
28 
29 #ifndef lint
30 static char rcsid_ksu_c[] =
31 "$Header: ksu.c,v 4.0 89/01/23 10:00:28 jtkohl Exp $";
32 #endif lint
33 
34 #ifndef lint
35 char copyright[] =
36 "@(#) Copyright (c) 1988 The Regents of the University of California.\n\
37  All rights reserved.\n";
38 #endif /* not lint */
39 
40 #ifndef lint
41 static char sccsid[] = "@(#)su.c	5.11 (Berkeley) 12/7/88";
42 #endif /* not lint */
43 
44 #include <kerberos/mit-copyright.h>
45 #include <sys/param.h>
46 #include <sys/time.h>
47 #include <sys/resource.h>
48 #include <syslog.h>
49 #include <stdio.h>
50 #include <pwd.h>
51 #include <grp.h>
52 #include <kerberos/krb.h>
53 #include <netdb.h>
54 #include <sys/ioctl.h>
55 
56 #ifndef LOG_AUTH
57 #define LOG_AUTH 0
58 #endif /* LOG_AUTH */
59 
60 /* for Ultrix and friends ... */
61 #ifndef MAXHOSTNAMELEN
62 #define MAXHOSTNAMELEN 64
63 #endif
64 
65 extern char *krb_err_txt[];
66 int     kerno;
67 char    lrealm[REALM_SZ];
68 char    krbtkfile[128];
69 
70 #define MAXPWSIZE	128	/* Biggest string we accept for a password
71 				   (includes space for null terminator) */
72 
73 main(argc, argv)
74 	int argc;
75 	char **argv;
76 {
77 	extern char **environ;
78 	extern int errno, optind;
79 	register struct passwd *pwd;
80 	register char *p, **g;
81 	struct group *gr;
82 	uid_t ruid, getuid();
83 #ifdef NO_GETUSERSHELL
84 	int ch, fulllogin, fastlogin, prio;
85 #else
86 	int asme, ch, fulllogin, fastlogin, prio;
87 #endif /* NO_GETUSERSHELL */
88 	enum { UNSET, YES, NO } iscsh = UNSET;
89 	char *user, *shell, *username, *cleanenv[2], *nargv[4], **np;
90 	char namebuf[50], shellbuf[MAXPATHLEN];
91 	char *crypt(), *getpass(), *getenv(), *getlogin(), *rindex(), *strcpy();
92 #ifdef NOENCRYPTION
93 #define read_long_pw_string placebo_read_pw_string
94 #else
95 #define read_long_pw_string des_read_pw_string
96 #endif
97 	int read_long_pw_string();
98 	char pw_buf[MAXPWSIZE];
99 	char   *mytty;
100 
101 	mytty = isatty(2) ? (char *) ttyname(2) : "(no tty)";
102 
103 	np = &nargv[3];
104 	*np-- = NULL;
105 #ifdef NO_GETUSERSHELL
106 	fulllogin = fastlogin = 0;
107 #define GETOPTARG "-flm"
108 #else
109 	asme = fulllogin = fastlogin = 0;
110 #define	GETOPTARG "-fl"
111 #endif
112 	while ((ch = getopt(argc, argv, GETOPTARG)) != EOF)
113 		switch((char)ch) {
114 		case 'f':
115 			fastlogin = 1;
116 			break;
117 		case '-':
118 		case 'l':
119 			fulllogin = 1;
120 			break;
121 #ifndef NO_GETUSERSHELL
122 		case 'm':
123 			asme = 1;
124 			break;
125 #endif
126 		case '?':
127 		default:
128 #ifdef NO_GETUSERSHELL
129 			fprintf(stderr, "usage: ksu [-fl] [login]\n");
130 #else
131 			fprintf(stderr, "usage: ksu [-flm] [login]\n");
132 #endif /* NO_GETUSERSHELL */
133 			exit(1);
134 		}
135 	argv += optind;
136 
137 	errno = 0;
138 	prio = getpriority(PRIO_PROCESS, 0);
139 	if (errno)
140 		prio = 0;
141 	(void)setpriority(PRIO_PROCESS, 0, -2);
142 
143 	/* get current login name and shell */
144 	if ((pwd = getpwuid(ruid = getuid())) == NULL) {
145 		fprintf(stderr, "ksu: who are you?\n");
146 		exit(1);
147 	}
148 	username = strcpy(namebuf, pwd->pw_name);
149 #ifndef NO_GETUSERSHELL
150 	if (asme)
151 		if (pwd->pw_shell && *pwd->pw_shell)
152 			shell = strcpy(shellbuf,  pwd->pw_shell);
153 		else {
154 			shell = "/bin/sh";
155 			iscsh = NO;
156 		}
157 #endif
158 
159 	/* get target login information */
160 	user = *argv ? *argv : "root";
161 	if ((pwd = getpwnam(user)) == NULL) {
162 		fprintf(stderr, "ksu: unknown login %s\n", user);
163 		exit(1);
164 	}
165 
166 	/*
167 	 * Only allow those with kerberos root instances in the /.klogin
168 	 * file to su to root.
169 	 */
170 	if (pwd->pw_uid == 0) {
171 	    KTEXT_ST ticket;
172 	    AUTH_DAT authdata;
173 	    char hostname[MAXHOSTNAMELEN], savehost[MAXHOSTNAMELEN];
174 	    unsigned long faddr;
175 	    struct hostent *hp;
176 
177 	    /* First lets see if he has a chance! */
178 	    if (krb_get_lrealm(lrealm, 1) != KSUCCESS) {
179 		fprintf(stderr,"Unable to get local realm\n");
180 		exit(1);
181 	    }
182 	    if (koktologin(username, lrealm)) {
183 		fprintf(stderr,"You are not allowed to ksu to root\n");
184 		exit(1);
185 	    }
186 	    sprintf(krbtkfile, "/tmp/tkt_root_%d", getuid());
187 	    setuid(0);		/* so ticket file has good protection */
188 	    if (read_long_pw_string(pw_buf, sizeof(pw_buf)-1,
189 				   "Your root instance password: ", 0)) {
190 		fprintf(stderr,"Error reading password.\n");
191 		exit(1);
192 	    }
193 	    p = pw_buf;
194 	    setenv("KRBTKFILE", krbtkfile, 1);
195 	    kerno = krb_get_pw_in_tkt(username, "root", lrealm, "krbtgt",
196 				      lrealm, 2, p);
197 	    bzero(p, strlen(p));
198 	    if (kerno != KSUCCESS) {
199 		printf("Unable to ksu: %s\n", krb_err_txt[kerno]);
200 		syslog(LOG_NOTICE|LOG_AUTH, "ksu: BAD SU %s on %s: %s",
201 		       username, mytty, krb_err_txt[kerno]);
202 		exit(1);
203 	    }
204 	    setpriority(PRIO_PROCESS, 0, -2);
205 	    /*
206 	     * Now use the ticket for something useful, to make sure
207 	     * it is valid.
208 	     */
209 	    if (gethostname(hostname, sizeof(hostname)) == -1) {
210 		perror("cannot retrieve hostname");
211 		dest_tkt();
212 		exit(1);
213 	    }
214 	    (void) strncpy(savehost, krb_get_phost(hostname),
215 			   sizeof(savehost));
216 	    savehost[sizeof(savehost)-1] = 0;
217 
218 	    kerno = krb_mk_req(&ticket, "rcmd", savehost, lrealm, 33);
219 	    if (kerno == KDC_PR_UNKNOWN) {
220 		printf("Warning: tgt not verified\n");
221 		syslog(LOG_NOTICE|LOG_AUTH, "ksu: %s on %s: tgt not verified",
222 		       username, mytty);
223 	    } else if (kerno != KSUCCESS) {
224 		printf("Unable to use tgt: %s\n", krb_err_txt[kerno]);
225 		syslog(LOG_NOTICE|LOG_AUTH, "ksu: failed su: %s on %s: %s",
226 		       username, mytty, krb_err_txt[kerno]);
227 		dest_tkt();
228 		exit(1);
229 	    } else {
230 		if (!(hp = gethostbyname(hostname))) {
231 		    printf("Unable to get address of %s\n",hostname);
232 		    dest_tkt();
233 		    exit(1);
234 		}
235 		bcopy((char *)hp->h_addr, (char *) &faddr, sizeof(faddr));
236 		if ((kerno = krb_rd_req(&ticket, "rcmd", savehost,
237 					faddr, &authdata, "")) != KSUCCESS) {
238 		    printf("Unable to verify rcmd ticket: %s\n",
239 			   krb_err_txt[kerno]);
240 		    syslog(LOG_NOTICE|LOG_AUTH, "ksu: failed su: %s on %s: %s",
241 			   username, mytty, krb_err_txt[kerno]);
242 		    dest_tkt();
243 		    exit(1);
244 		}
245 	    }
246 	    printf("Don't forget to kdestroy before exiting the root shell.\n");
247 	} else
248 	/* if target requires a password, verify it */
249 	if (ruid && *pwd->pw_passwd) {
250 		p = getpass("Password:");
251 		if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) {
252 			fprintf(stderr, "Sorry\n");
253 			if (pwd->pw_uid == 0)
254 				syslog(LOG_CRIT|LOG_AUTH, "ksu: BAD SU %s on %s", username, mytty);
255 			exit(1);
256 		}
257 	}
258 
259 #ifndef NO_GETUSERSHELL
260 	if (asme) {
261 		/* if asme and non-standard target shell, must be root */
262 		if (!chshell(pwd->pw_shell) && ruid) {
263 			fprintf(stderr, "ksu: Permission denied.\n");
264 			dest_tkt();
265 			exit(1);
266 		}
267 	}
268 	else
269 #endif
270 	if (pwd->pw_shell && *pwd->pw_shell) {
271 		shell = pwd->pw_shell;
272 		iscsh = UNSET;
273 	} else {
274 		shell = "/bin/sh";
275 		iscsh = NO;
276 	}
277 
278 	/* if we're forking a csh, we want to slightly muck the args */
279 	if (iscsh == UNSET) {
280 		if (p = rindex(shell, '/'))
281 			++p;
282 		else
283 			p = shell;
284 		iscsh = strcmp(p, "csh") ? NO : YES;
285 	}
286 
287 	/* set permissions */
288 	if (setgid(pwd->pw_gid) < 0) {
289 		perror("ksu: setgid");
290 		dest_tkt();
291 		exit(1);
292 	}
293 	if (initgroups(user, pwd->pw_gid)) {
294 		fprintf(stderr, "ksu: initgroups failed\n");
295 		dest_tkt();
296 		exit(1);
297 	}
298 	if (setuid(pwd->pw_uid) < 0) {
299 		perror("ksu: setuid");
300 		dest_tkt();
301 		exit(1);
302 	}
303 
304 #ifndef NO_GETUSERSHELL
305 	if (!asme) {
306 #endif
307 		if (fulllogin) {
308 			p = getenv("TERM");
309 			cleanenv[0] = "PATH=:/usr/ucb:/bin:/usr/bin";
310 			cleanenv[1] = NULL;
311 			environ = cleanenv;
312 			(void)setenv("TERM", p, 1);
313 			if (chdir(pwd->pw_dir) < 0) {
314 				fprintf(stderr, "ksu: no directory\n");
315 				dest_tkt();
316 				exit(1);
317 			}
318 		}
319 		if (fulllogin || pwd->pw_uid)
320 			(void)setenv("USER", pwd->pw_name, 1);
321 		(void)setenv("HOME", pwd->pw_dir, 1);
322 		(void)setenv("SHELL", shell, 1);
323 #ifndef NO_GETUSERSHELL
324 	}
325 #endif
326 
327 	if (iscsh == YES) {
328 		if (fastlogin)
329 			*np-- = "-f";
330 #ifndef NO_GETUSERSHELL
331 		if (asme)
332 			*np-- = "-m";
333 #endif
334 	}
335 
336 	/* csh strips the first character... */
337 	*np = fulllogin ? "-ksu" : iscsh == YES ? "_ksu" : "ksu";
338 
339 	if (pwd->pw_uid == 0)
340 		syslog(LOG_NOTICE|LOG_AUTH, "ksu: %s on %s",
341 		    username, mytty);
342 
343 	(void)setpriority(PRIO_PROCESS, 0, prio);
344 
345 	execv(shell, np);
346 	fprintf(stderr, "ksu: no shell.\n");
347 	dest_tkt();
348 	exit(1);
349 }
350 
351 #ifndef NO_GETUSERSHELL
352 chshell(sh)
353 	char *sh;
354 {
355 	char *cp, *getusershell();
356 
357 	while ((cp = getusershell()) != NULL)
358 		if (!strcmp(cp, sh))
359 			return(1);
360 	return(0);
361 }
362 #endif /* NO_GETUSERSHELL */
363 
364 koktologin(name, realm)
365     char   *name;
366     char   *realm;
367 {
368     struct auth_dat kdata_st;
369     AUTH_DAT *kdata = &kdata_st;
370     /* Cons together an AUTH_DAT structure for kuserok */
371     bzero((caddr_t) kdata, sizeof(*kdata));
372     strcpy(kdata->pname, name);
373     strcpy(kdata->pinst, "root");
374     strcpy(kdata->prealm, realm);
375     return (kuserok(kdata, "root"));
376 }
377