xref: /csrg-svn/old/athena/ksu/ksu.c (revision 38059)
136660Skfall /*
236660Skfall  * $Source: /mit/kerberos/src/kuser/RCS/ksu.c,v $
336660Skfall  * $Author: jtkohl $
436660Skfall  */
536660Skfall 
636660Skfall /*
736660Skfall  * Copyright (c) 1988 The Regents of the University of California.
836660Skfall  * All rights reserved.
936660Skfall  *
1036660Skfall  * Redistribution and use in source and binary forms are permitted
1136660Skfall  * provided that the above copyright notice and this paragraph are
1236660Skfall  * duplicated in all such forms and that any documentation,
1336660Skfall  * advertising materials, and other materials related to such
1436660Skfall  * distribution and use acknowledge that the software was developed
1536660Skfall  * by the University of California, Berkeley.  The name of the
1636660Skfall  * University may not be used to endorse or promote products derived
1736660Skfall  * from this software without specific prior written permission.
1836660Skfall  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1936660Skfall  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
2036660Skfall  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2136660Skfall  */
2236660Skfall 
2336660Skfall /*
2436660Skfall  * Kerberos additions Copyright 1987, 1988 by the Massachusetts Institute
2536660Skfall  * of Technology. For copying and distribution information, please see
2636660Skfall  * the file <mit-copyright.h>.
2736660Skfall  */
2836660Skfall 
2936660Skfall #ifndef lint
3036660Skfall static char rcsid_ksu_c[] =
3136660Skfall "$Header: ksu.c,v 4.0 89/01/23 10:00:28 jtkohl Exp $";
3236660Skfall #endif lint
3336660Skfall 
3436660Skfall #ifndef lint
3536660Skfall char copyright[] =
3636660Skfall "@(#) Copyright (c) 1988 The Regents of the University of California.\n\
3736660Skfall  All rights reserved.\n";
3836660Skfall #endif /* not lint */
3936660Skfall 
4036660Skfall #ifndef lint
4136660Skfall static char sccsid[] = "@(#)su.c	5.11 (Berkeley) 12/7/88";
4236660Skfall #endif /* not lint */
4336660Skfall 
44*38035Skfall #include <kerberos/mit-copyright.h>
4536660Skfall #include <sys/param.h>
4636660Skfall #include <sys/time.h>
4736660Skfall #include <sys/resource.h>
4836660Skfall #include <syslog.h>
4936660Skfall #include <stdio.h>
5036660Skfall #include <pwd.h>
5136660Skfall #include <grp.h>
52*38035Skfall #include <kerberos/krb.h>
5336660Skfall #include <netdb.h>
5436660Skfall #include <sys/ioctl.h>
5536660Skfall 
5636660Skfall #ifndef LOG_AUTH
5736660Skfall #define LOG_AUTH 0
5836660Skfall #endif /* LOG_AUTH */
5936660Skfall 
6036660Skfall /* for Ultrix and friends ... */
6136660Skfall #ifndef MAXHOSTNAMELEN
6236660Skfall #define MAXHOSTNAMELEN 64
6336660Skfall #endif
6436660Skfall 
6536660Skfall extern char *krb_err_txt[];
6636660Skfall int     kerno;
6736660Skfall char    lrealm[REALM_SZ];
6836660Skfall char    krbtkfile[128];
6936660Skfall 
7036660Skfall #define MAXPWSIZE	128	/* Biggest string we accept for a password
7136660Skfall 				   (includes space for null terminator) */
7236660Skfall 
main(argc,argv)7336660Skfall main(argc, argv)
7436660Skfall 	int argc;
7536660Skfall 	char **argv;
7636660Skfall {
7736660Skfall 	extern char **environ;
7836660Skfall 	extern int errno, optind;
7936660Skfall 	register struct passwd *pwd;
8036660Skfall 	register char *p, **g;
8136660Skfall 	struct group *gr;
8236660Skfall 	uid_t ruid, getuid();
8336660Skfall #ifdef NO_GETUSERSHELL
8436660Skfall 	int ch, fulllogin, fastlogin, prio;
8536660Skfall #else
8636660Skfall 	int asme, ch, fulllogin, fastlogin, prio;
8736660Skfall #endif /* NO_GETUSERSHELL */
8836660Skfall 	enum { UNSET, YES, NO } iscsh = UNSET;
8936660Skfall 	char *user, *shell, *username, *cleanenv[2], *nargv[4], **np;
9036660Skfall 	char namebuf[50], shellbuf[MAXPATHLEN];
9136660Skfall 	char *crypt(), *getpass(), *getenv(), *getlogin(), *rindex(), *strcpy();
9236660Skfall #ifdef NOENCRYPTION
9336660Skfall #define read_long_pw_string placebo_read_pw_string
9436660Skfall #else
9536660Skfall #define read_long_pw_string des_read_pw_string
9636660Skfall #endif
9736660Skfall 	int read_long_pw_string();
9836660Skfall 	char pw_buf[MAXPWSIZE];
9936660Skfall 	char   *mytty;
10036660Skfall 
10136660Skfall 	mytty = isatty(2) ? (char *) ttyname(2) : "(no tty)";
10236660Skfall 
10336660Skfall 	np = &nargv[3];
10436660Skfall 	*np-- = NULL;
10536660Skfall #ifdef NO_GETUSERSHELL
10636660Skfall 	fulllogin = fastlogin = 0;
10736660Skfall #define GETOPTARG "-flm"
10836660Skfall #else
10936660Skfall 	asme = fulllogin = fastlogin = 0;
11036660Skfall #define	GETOPTARG "-fl"
11136660Skfall #endif
11236660Skfall 	while ((ch = getopt(argc, argv, GETOPTARG)) != EOF)
11336660Skfall 		switch((char)ch) {
11436660Skfall 		case 'f':
11536660Skfall 			fastlogin = 1;
11636660Skfall 			break;
11736660Skfall 		case '-':
11836660Skfall 		case 'l':
11936660Skfall 			fulllogin = 1;
12036660Skfall 			break;
12136660Skfall #ifndef NO_GETUSERSHELL
12236660Skfall 		case 'm':
12336660Skfall 			asme = 1;
12436660Skfall 			break;
12536660Skfall #endif
12636660Skfall 		case '?':
12736660Skfall 		default:
12836660Skfall #ifdef NO_GETUSERSHELL
12936660Skfall 			fprintf(stderr, "usage: ksu [-fl] [login]\n");
13036660Skfall #else
13136660Skfall 			fprintf(stderr, "usage: ksu [-flm] [login]\n");
13236660Skfall #endif /* NO_GETUSERSHELL */
13336660Skfall 			exit(1);
13436660Skfall 		}
13536660Skfall 	argv += optind;
13636660Skfall 
13736660Skfall 	errno = 0;
13836660Skfall 	prio = getpriority(PRIO_PROCESS, 0);
13936660Skfall 	if (errno)
14036660Skfall 		prio = 0;
14136660Skfall 	(void)setpriority(PRIO_PROCESS, 0, -2);
14236660Skfall 
14336660Skfall 	/* get current login name and shell */
14436660Skfall 	if ((pwd = getpwuid(ruid = getuid())) == NULL) {
14536660Skfall 		fprintf(stderr, "ksu: who are you?\n");
14636660Skfall 		exit(1);
14736660Skfall 	}
14836660Skfall 	username = strcpy(namebuf, pwd->pw_name);
14936660Skfall #ifndef NO_GETUSERSHELL
15036660Skfall 	if (asme)
15136660Skfall 		if (pwd->pw_shell && *pwd->pw_shell)
15236660Skfall 			shell = strcpy(shellbuf,  pwd->pw_shell);
15336660Skfall 		else {
15436660Skfall 			shell = "/bin/sh";
15536660Skfall 			iscsh = NO;
15636660Skfall 		}
15736660Skfall #endif
15836660Skfall 
15936660Skfall 	/* get target login information */
16036660Skfall 	user = *argv ? *argv : "root";
16136660Skfall 	if ((pwd = getpwnam(user)) == NULL) {
16236660Skfall 		fprintf(stderr, "ksu: unknown login %s\n", user);
16336660Skfall 		exit(1);
16436660Skfall 	}
16536660Skfall 
16636660Skfall 	/*
16736660Skfall 	 * Only allow those with kerberos root instances in the /.klogin
16836660Skfall 	 * file to su to root.
16936660Skfall 	 */
17036660Skfall 	if (pwd->pw_uid == 0) {
17136660Skfall 	    KTEXT_ST ticket;
17236660Skfall 	    AUTH_DAT authdata;
17336660Skfall 	    char hostname[MAXHOSTNAMELEN], savehost[MAXHOSTNAMELEN];
17436660Skfall 	    unsigned long faddr;
17536660Skfall 	    struct hostent *hp;
17636660Skfall 
17736660Skfall 	    /* First lets see if he has a chance! */
17836660Skfall 	    if (krb_get_lrealm(lrealm, 1) != KSUCCESS) {
17936660Skfall 		fprintf(stderr,"Unable to get local realm\n");
18036660Skfall 		exit(1);
18136660Skfall 	    }
18236660Skfall 	    if (koktologin(username, lrealm)) {
18336660Skfall 		fprintf(stderr,"You are not allowed to ksu to root\n");
18436660Skfall 		exit(1);
18536660Skfall 	    }
18636660Skfall 	    sprintf(krbtkfile, "/tmp/tkt_root_%d", getuid());
18736660Skfall 	    setuid(0);		/* so ticket file has good protection */
18836660Skfall 	    if (read_long_pw_string(pw_buf, sizeof(pw_buf)-1,
18936660Skfall 				   "Your root instance password: ", 0)) {
19036660Skfall 		fprintf(stderr,"Error reading password.\n");
19136660Skfall 		exit(1);
19236660Skfall 	    }
19336660Skfall 	    p = pw_buf;
19436660Skfall 	    setenv("KRBTKFILE", krbtkfile, 1);
19536660Skfall 	    kerno = krb_get_pw_in_tkt(username, "root", lrealm, "krbtgt",
19636660Skfall 				      lrealm, 2, p);
19736660Skfall 	    bzero(p, strlen(p));
19836660Skfall 	    if (kerno != KSUCCESS) {
19936660Skfall 		printf("Unable to ksu: %s\n", krb_err_txt[kerno]);
20036660Skfall 		syslog(LOG_NOTICE|LOG_AUTH, "ksu: BAD SU %s on %s: %s",
20136660Skfall 		       username, mytty, krb_err_txt[kerno]);
20236660Skfall 		exit(1);
20336660Skfall 	    }
20436660Skfall 	    setpriority(PRIO_PROCESS, 0, -2);
20536660Skfall 	    /*
20636660Skfall 	     * Now use the ticket for something useful, to make sure
20736660Skfall 	     * it is valid.
20836660Skfall 	     */
20936660Skfall 	    if (gethostname(hostname, sizeof(hostname)) == -1) {
21036660Skfall 		perror("cannot retrieve hostname");
21136660Skfall 		dest_tkt();
21236660Skfall 		exit(1);
21336660Skfall 	    }
21436660Skfall 	    (void) strncpy(savehost, krb_get_phost(hostname),
21536660Skfall 			   sizeof(savehost));
21636660Skfall 	    savehost[sizeof(savehost)-1] = 0;
21736660Skfall 
21836660Skfall 	    kerno = krb_mk_req(&ticket, "rcmd", savehost, lrealm, 33);
21936660Skfall 	    if (kerno == KDC_PR_UNKNOWN) {
22036660Skfall 		printf("Warning: tgt not verified\n");
22136660Skfall 		syslog(LOG_NOTICE|LOG_AUTH, "ksu: %s on %s: tgt not verified",
22236660Skfall 		       username, mytty);
22336660Skfall 	    } else if (kerno != KSUCCESS) {
22436660Skfall 		printf("Unable to use tgt: %s\n", krb_err_txt[kerno]);
22536660Skfall 		syslog(LOG_NOTICE|LOG_AUTH, "ksu: failed su: %s on %s: %s",
22636660Skfall 		       username, mytty, krb_err_txt[kerno]);
22736660Skfall 		dest_tkt();
22836660Skfall 		exit(1);
22936660Skfall 	    } else {
23036660Skfall 		if (!(hp = gethostbyname(hostname))) {
23136660Skfall 		    printf("Unable to get address of %s\n",hostname);
23236660Skfall 		    dest_tkt();
23336660Skfall 		    exit(1);
23436660Skfall 		}
23536660Skfall 		bcopy((char *)hp->h_addr, (char *) &faddr, sizeof(faddr));
23636660Skfall 		if ((kerno = krb_rd_req(&ticket, "rcmd", savehost,
23736660Skfall 					faddr, &authdata, "")) != KSUCCESS) {
23836660Skfall 		    printf("Unable to verify rcmd ticket: %s\n",
23936660Skfall 			   krb_err_txt[kerno]);
24036660Skfall 		    syslog(LOG_NOTICE|LOG_AUTH, "ksu: failed su: %s on %s: %s",
24136660Skfall 			   username, mytty, krb_err_txt[kerno]);
24236660Skfall 		    dest_tkt();
24336660Skfall 		    exit(1);
24436660Skfall 		}
24536660Skfall 	    }
24636660Skfall 	    printf("Don't forget to kdestroy before exiting the root shell.\n");
24736660Skfall 	} else
24836660Skfall 	/* if target requires a password, verify it */
24936660Skfall 	if (ruid && *pwd->pw_passwd) {
25036660Skfall 		p = getpass("Password:");
25136660Skfall 		if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) {
25236660Skfall 			fprintf(stderr, "Sorry\n");
25336660Skfall 			if (pwd->pw_uid == 0)
25436660Skfall 				syslog(LOG_CRIT|LOG_AUTH, "ksu: BAD SU %s on %s", username, mytty);
25536660Skfall 			exit(1);
25636660Skfall 		}
25736660Skfall 	}
25836660Skfall 
25936660Skfall #ifndef NO_GETUSERSHELL
26036660Skfall 	if (asme) {
26136660Skfall 		/* if asme and non-standard target shell, must be root */
26236660Skfall 		if (!chshell(pwd->pw_shell) && ruid) {
26336660Skfall 			fprintf(stderr, "ksu: Permission denied.\n");
26436660Skfall 			dest_tkt();
26536660Skfall 			exit(1);
26636660Skfall 		}
26736660Skfall 	}
26836660Skfall 	else
26936660Skfall #endif
27036660Skfall 	if (pwd->pw_shell && *pwd->pw_shell) {
27136660Skfall 		shell = pwd->pw_shell;
27236660Skfall 		iscsh = UNSET;
27336660Skfall 	} else {
27436660Skfall 		shell = "/bin/sh";
27536660Skfall 		iscsh = NO;
27636660Skfall 	}
27736660Skfall 
27836660Skfall 	/* if we're forking a csh, we want to slightly muck the args */
27936660Skfall 	if (iscsh == UNSET) {
28036660Skfall 		if (p = rindex(shell, '/'))
28136660Skfall 			++p;
28236660Skfall 		else
28336660Skfall 			p = shell;
28436660Skfall 		iscsh = strcmp(p, "csh") ? NO : YES;
28536660Skfall 	}
28636660Skfall 
28736660Skfall 	/* set permissions */
28836660Skfall 	if (setgid(pwd->pw_gid) < 0) {
28936660Skfall 		perror("ksu: setgid");
29036660Skfall 		dest_tkt();
29136660Skfall 		exit(1);
29236660Skfall 	}
29336660Skfall 	if (initgroups(user, pwd->pw_gid)) {
29436660Skfall 		fprintf(stderr, "ksu: initgroups failed\n");
29536660Skfall 		dest_tkt();
29636660Skfall 		exit(1);
29736660Skfall 	}
29836660Skfall 	if (setuid(pwd->pw_uid) < 0) {
29936660Skfall 		perror("ksu: setuid");
30036660Skfall 		dest_tkt();
30136660Skfall 		exit(1);
30236660Skfall 	}
30336660Skfall 
30436660Skfall #ifndef NO_GETUSERSHELL
30536660Skfall 	if (!asme) {
30636660Skfall #endif
30736660Skfall 		if (fulllogin) {
30836660Skfall 			p = getenv("TERM");
30936660Skfall 			cleanenv[0] = "PATH=:/usr/ucb:/bin:/usr/bin";
31036660Skfall 			cleanenv[1] = NULL;
31136660Skfall 			environ = cleanenv;
31236660Skfall 			(void)setenv("TERM", p, 1);
31336660Skfall 			if (chdir(pwd->pw_dir) < 0) {
31436660Skfall 				fprintf(stderr, "ksu: no directory\n");
31536660Skfall 				dest_tkt();
31636660Skfall 				exit(1);
31736660Skfall 			}
31836660Skfall 		}
31936660Skfall 		if (fulllogin || pwd->pw_uid)
32036660Skfall 			(void)setenv("USER", pwd->pw_name, 1);
32136660Skfall 		(void)setenv("HOME", pwd->pw_dir, 1);
32236660Skfall 		(void)setenv("SHELL", shell, 1);
32336660Skfall #ifndef NO_GETUSERSHELL
32436660Skfall 	}
32536660Skfall #endif
32636660Skfall 
32736660Skfall 	if (iscsh == YES) {
32836660Skfall 		if (fastlogin)
32936660Skfall 			*np-- = "-f";
33036660Skfall #ifndef NO_GETUSERSHELL
33136660Skfall 		if (asme)
33236660Skfall 			*np-- = "-m";
33336660Skfall #endif
33436660Skfall 	}
33536660Skfall 
33636660Skfall 	/* csh strips the first character... */
33736660Skfall 	*np = fulllogin ? "-ksu" : iscsh == YES ? "_ksu" : "ksu";
33836660Skfall 
33936660Skfall 	if (pwd->pw_uid == 0)
34036660Skfall 		syslog(LOG_NOTICE|LOG_AUTH, "ksu: %s on %s",
34136660Skfall 		    username, mytty);
34236660Skfall 
34336660Skfall 	(void)setpriority(PRIO_PROCESS, 0, prio);
34436660Skfall 
34536660Skfall 	execv(shell, np);
34636660Skfall 	fprintf(stderr, "ksu: no shell.\n");
34736660Skfall 	dest_tkt();
34836660Skfall 	exit(1);
34936660Skfall }
35036660Skfall 
35136660Skfall #ifndef NO_GETUSERSHELL
chshell(sh)35236660Skfall chshell(sh)
35336660Skfall 	char *sh;
35436660Skfall {
35536660Skfall 	char *cp, *getusershell();
35636660Skfall 
35736660Skfall 	while ((cp = getusershell()) != NULL)
35836660Skfall 		if (!strcmp(cp, sh))
35936660Skfall 			return(1);
36036660Skfall 	return(0);
36136660Skfall }
36236660Skfall #endif /* NO_GETUSERSHELL */
36336660Skfall 
koktologin(name,realm)36436660Skfall koktologin(name, realm)
36536660Skfall     char   *name;
36636660Skfall     char   *realm;
36736660Skfall {
36836660Skfall     struct auth_dat kdata_st;
36936660Skfall     AUTH_DAT *kdata = &kdata_st;
37036660Skfall     /* Cons together an AUTH_DAT structure for kuserok */
37136660Skfall     bzero((caddr_t) kdata, sizeof(*kdata));
37236660Skfall     strcpy(kdata->pname, name);
37336660Skfall     strcpy(kdata->pinst, "root");
37436660Skfall     strcpy(kdata->prealm, realm);
37536660Skfall     return (kuserok(kdata, "root"));
37636660Skfall }
377