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