xref: /original-bsd/old/athena/ksu/ksu.c (revision d2620545)
146f2fea7Skfall /*
246f2fea7Skfall  * $Source: /mit/kerberos/src/kuser/RCS/ksu.c,v $
346f2fea7Skfall  * $Author: jtkohl $
446f2fea7Skfall  */
546f2fea7Skfall 
646f2fea7Skfall /*
746f2fea7Skfall  * Copyright (c) 1988 The Regents of the University of California.
846f2fea7Skfall  * All rights reserved.
946f2fea7Skfall  *
1046f2fea7Skfall  * Redistribution and use in source and binary forms are permitted
1146f2fea7Skfall  * provided that the above copyright notice and this paragraph are
1246f2fea7Skfall  * duplicated in all such forms and that any documentation,
1346f2fea7Skfall  * advertising materials, and other materials related to such
1446f2fea7Skfall  * distribution and use acknowledge that the software was developed
1546f2fea7Skfall  * by the University of California, Berkeley.  The name of the
1646f2fea7Skfall  * University may not be used to endorse or promote products derived
1746f2fea7Skfall  * from this software without specific prior written permission.
1846f2fea7Skfall  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1946f2fea7Skfall  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
2046f2fea7Skfall  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2146f2fea7Skfall  */
2246f2fea7Skfall 
2346f2fea7Skfall /*
2446f2fea7Skfall  * Kerberos additions Copyright 1987, 1988 by the Massachusetts Institute
2546f2fea7Skfall  * of Technology. For copying and distribution information, please see
2646f2fea7Skfall  * the file <mit-copyright.h>.
2746f2fea7Skfall  */
2846f2fea7Skfall 
2946f2fea7Skfall #ifndef lint
3046f2fea7Skfall static char rcsid_ksu_c[] =
3146f2fea7Skfall "$Header: ksu.c,v 4.0 89/01/23 10:00:28 jtkohl Exp $";
3246f2fea7Skfall #endif lint
3346f2fea7Skfall 
3446f2fea7Skfall #ifndef lint
3546f2fea7Skfall char copyright[] =
3646f2fea7Skfall "@(#) Copyright (c) 1988 The Regents of the University of California.\n\
3746f2fea7Skfall  All rights reserved.\n";
3846f2fea7Skfall #endif /* not lint */
3946f2fea7Skfall 
4046f2fea7Skfall #ifndef lint
4146f2fea7Skfall static char sccsid[] = "@(#)su.c	5.11 (Berkeley) 12/7/88";
4246f2fea7Skfall #endif /* not lint */
4346f2fea7Skfall 
44*d2620545Skfall #include <kerberos/mit-copyright.h>
4546f2fea7Skfall #include <sys/param.h>
4646f2fea7Skfall #include <sys/time.h>
4746f2fea7Skfall #include <sys/resource.h>
4846f2fea7Skfall #include <syslog.h>
4946f2fea7Skfall #include <stdio.h>
5046f2fea7Skfall #include <pwd.h>
5146f2fea7Skfall #include <grp.h>
52*d2620545Skfall #include <kerberos/krb.h>
5346f2fea7Skfall #include <netdb.h>
5446f2fea7Skfall #include <sys/ioctl.h>
5546f2fea7Skfall 
5646f2fea7Skfall #ifndef LOG_AUTH
5746f2fea7Skfall #define LOG_AUTH 0
5846f2fea7Skfall #endif /* LOG_AUTH */
5946f2fea7Skfall 
6046f2fea7Skfall /* for Ultrix and friends ... */
6146f2fea7Skfall #ifndef MAXHOSTNAMELEN
6246f2fea7Skfall #define MAXHOSTNAMELEN 64
6346f2fea7Skfall #endif
6446f2fea7Skfall 
6546f2fea7Skfall extern char *krb_err_txt[];
6646f2fea7Skfall int     kerno;
6746f2fea7Skfall char    lrealm[REALM_SZ];
6846f2fea7Skfall char    krbtkfile[128];
6946f2fea7Skfall 
7046f2fea7Skfall #define MAXPWSIZE	128	/* Biggest string we accept for a password
7146f2fea7Skfall 				   (includes space for null terminator) */
7246f2fea7Skfall 
main(argc,argv)7346f2fea7Skfall main(argc, argv)
7446f2fea7Skfall 	int argc;
7546f2fea7Skfall 	char **argv;
7646f2fea7Skfall {
7746f2fea7Skfall 	extern char **environ;
7846f2fea7Skfall 	extern int errno, optind;
7946f2fea7Skfall 	register struct passwd *pwd;
8046f2fea7Skfall 	register char *p, **g;
8146f2fea7Skfall 	struct group *gr;
8246f2fea7Skfall 	uid_t ruid, getuid();
8346f2fea7Skfall #ifdef NO_GETUSERSHELL
8446f2fea7Skfall 	int ch, fulllogin, fastlogin, prio;
8546f2fea7Skfall #else
8646f2fea7Skfall 	int asme, ch, fulllogin, fastlogin, prio;
8746f2fea7Skfall #endif /* NO_GETUSERSHELL */
8846f2fea7Skfall 	enum { UNSET, YES, NO } iscsh = UNSET;
8946f2fea7Skfall 	char *user, *shell, *username, *cleanenv[2], *nargv[4], **np;
9046f2fea7Skfall 	char namebuf[50], shellbuf[MAXPATHLEN];
9146f2fea7Skfall 	char *crypt(), *getpass(), *getenv(), *getlogin(), *rindex(), *strcpy();
9246f2fea7Skfall #ifdef NOENCRYPTION
9346f2fea7Skfall #define read_long_pw_string placebo_read_pw_string
9446f2fea7Skfall #else
9546f2fea7Skfall #define read_long_pw_string des_read_pw_string
9646f2fea7Skfall #endif
9746f2fea7Skfall 	int read_long_pw_string();
9846f2fea7Skfall 	char pw_buf[MAXPWSIZE];
9946f2fea7Skfall 	char   *mytty;
10046f2fea7Skfall 
10146f2fea7Skfall 	mytty = isatty(2) ? (char *) ttyname(2) : "(no tty)";
10246f2fea7Skfall 
10346f2fea7Skfall 	np = &nargv[3];
10446f2fea7Skfall 	*np-- = NULL;
10546f2fea7Skfall #ifdef NO_GETUSERSHELL
10646f2fea7Skfall 	fulllogin = fastlogin = 0;
10746f2fea7Skfall #define GETOPTARG "-flm"
10846f2fea7Skfall #else
10946f2fea7Skfall 	asme = fulllogin = fastlogin = 0;
11046f2fea7Skfall #define	GETOPTARG "-fl"
11146f2fea7Skfall #endif
11246f2fea7Skfall 	while ((ch = getopt(argc, argv, GETOPTARG)) != EOF)
11346f2fea7Skfall 		switch((char)ch) {
11446f2fea7Skfall 		case 'f':
11546f2fea7Skfall 			fastlogin = 1;
11646f2fea7Skfall 			break;
11746f2fea7Skfall 		case '-':
11846f2fea7Skfall 		case 'l':
11946f2fea7Skfall 			fulllogin = 1;
12046f2fea7Skfall 			break;
12146f2fea7Skfall #ifndef NO_GETUSERSHELL
12246f2fea7Skfall 		case 'm':
12346f2fea7Skfall 			asme = 1;
12446f2fea7Skfall 			break;
12546f2fea7Skfall #endif
12646f2fea7Skfall 		case '?':
12746f2fea7Skfall 		default:
12846f2fea7Skfall #ifdef NO_GETUSERSHELL
12946f2fea7Skfall 			fprintf(stderr, "usage: ksu [-fl] [login]\n");
13046f2fea7Skfall #else
13146f2fea7Skfall 			fprintf(stderr, "usage: ksu [-flm] [login]\n");
13246f2fea7Skfall #endif /* NO_GETUSERSHELL */
13346f2fea7Skfall 			exit(1);
13446f2fea7Skfall 		}
13546f2fea7Skfall 	argv += optind;
13646f2fea7Skfall 
13746f2fea7Skfall 	errno = 0;
13846f2fea7Skfall 	prio = getpriority(PRIO_PROCESS, 0);
13946f2fea7Skfall 	if (errno)
14046f2fea7Skfall 		prio = 0;
14146f2fea7Skfall 	(void)setpriority(PRIO_PROCESS, 0, -2);
14246f2fea7Skfall 
14346f2fea7Skfall 	/* get current login name and shell */
14446f2fea7Skfall 	if ((pwd = getpwuid(ruid = getuid())) == NULL) {
14546f2fea7Skfall 		fprintf(stderr, "ksu: who are you?\n");
14646f2fea7Skfall 		exit(1);
14746f2fea7Skfall 	}
14846f2fea7Skfall 	username = strcpy(namebuf, pwd->pw_name);
14946f2fea7Skfall #ifndef NO_GETUSERSHELL
15046f2fea7Skfall 	if (asme)
15146f2fea7Skfall 		if (pwd->pw_shell && *pwd->pw_shell)
15246f2fea7Skfall 			shell = strcpy(shellbuf,  pwd->pw_shell);
15346f2fea7Skfall 		else {
15446f2fea7Skfall 			shell = "/bin/sh";
15546f2fea7Skfall 			iscsh = NO;
15646f2fea7Skfall 		}
15746f2fea7Skfall #endif
15846f2fea7Skfall 
15946f2fea7Skfall 	/* get target login information */
16046f2fea7Skfall 	user = *argv ? *argv : "root";
16146f2fea7Skfall 	if ((pwd = getpwnam(user)) == NULL) {
16246f2fea7Skfall 		fprintf(stderr, "ksu: unknown login %s\n", user);
16346f2fea7Skfall 		exit(1);
16446f2fea7Skfall 	}
16546f2fea7Skfall 
16646f2fea7Skfall 	/*
16746f2fea7Skfall 	 * Only allow those with kerberos root instances in the /.klogin
16846f2fea7Skfall 	 * file to su to root.
16946f2fea7Skfall 	 */
17046f2fea7Skfall 	if (pwd->pw_uid == 0) {
17146f2fea7Skfall 	    KTEXT_ST ticket;
17246f2fea7Skfall 	    AUTH_DAT authdata;
17346f2fea7Skfall 	    char hostname[MAXHOSTNAMELEN], savehost[MAXHOSTNAMELEN];
17446f2fea7Skfall 	    unsigned long faddr;
17546f2fea7Skfall 	    struct hostent *hp;
17646f2fea7Skfall 
17746f2fea7Skfall 	    /* First lets see if he has a chance! */
17846f2fea7Skfall 	    if (krb_get_lrealm(lrealm, 1) != KSUCCESS) {
17946f2fea7Skfall 		fprintf(stderr,"Unable to get local realm\n");
18046f2fea7Skfall 		exit(1);
18146f2fea7Skfall 	    }
18246f2fea7Skfall 	    if (koktologin(username, lrealm)) {
18346f2fea7Skfall 		fprintf(stderr,"You are not allowed to ksu to root\n");
18446f2fea7Skfall 		exit(1);
18546f2fea7Skfall 	    }
18646f2fea7Skfall 	    sprintf(krbtkfile, "/tmp/tkt_root_%d", getuid());
18746f2fea7Skfall 	    setuid(0);		/* so ticket file has good protection */
18846f2fea7Skfall 	    if (read_long_pw_string(pw_buf, sizeof(pw_buf)-1,
18946f2fea7Skfall 				   "Your root instance password: ", 0)) {
19046f2fea7Skfall 		fprintf(stderr,"Error reading password.\n");
19146f2fea7Skfall 		exit(1);
19246f2fea7Skfall 	    }
19346f2fea7Skfall 	    p = pw_buf;
19446f2fea7Skfall 	    setenv("KRBTKFILE", krbtkfile, 1);
19546f2fea7Skfall 	    kerno = krb_get_pw_in_tkt(username, "root", lrealm, "krbtgt",
19646f2fea7Skfall 				      lrealm, 2, p);
19746f2fea7Skfall 	    bzero(p, strlen(p));
19846f2fea7Skfall 	    if (kerno != KSUCCESS) {
19946f2fea7Skfall 		printf("Unable to ksu: %s\n", krb_err_txt[kerno]);
20046f2fea7Skfall 		syslog(LOG_NOTICE|LOG_AUTH, "ksu: BAD SU %s on %s: %s",
20146f2fea7Skfall 		       username, mytty, krb_err_txt[kerno]);
20246f2fea7Skfall 		exit(1);
20346f2fea7Skfall 	    }
20446f2fea7Skfall 	    setpriority(PRIO_PROCESS, 0, -2);
20546f2fea7Skfall 	    /*
20646f2fea7Skfall 	     * Now use the ticket for something useful, to make sure
20746f2fea7Skfall 	     * it is valid.
20846f2fea7Skfall 	     */
20946f2fea7Skfall 	    if (gethostname(hostname, sizeof(hostname)) == -1) {
21046f2fea7Skfall 		perror("cannot retrieve hostname");
21146f2fea7Skfall 		dest_tkt();
21246f2fea7Skfall 		exit(1);
21346f2fea7Skfall 	    }
21446f2fea7Skfall 	    (void) strncpy(savehost, krb_get_phost(hostname),
21546f2fea7Skfall 			   sizeof(savehost));
21646f2fea7Skfall 	    savehost[sizeof(savehost)-1] = 0;
21746f2fea7Skfall 
21846f2fea7Skfall 	    kerno = krb_mk_req(&ticket, "rcmd", savehost, lrealm, 33);
21946f2fea7Skfall 	    if (kerno == KDC_PR_UNKNOWN) {
22046f2fea7Skfall 		printf("Warning: tgt not verified\n");
22146f2fea7Skfall 		syslog(LOG_NOTICE|LOG_AUTH, "ksu: %s on %s: tgt not verified",
22246f2fea7Skfall 		       username, mytty);
22346f2fea7Skfall 	    } else if (kerno != KSUCCESS) {
22446f2fea7Skfall 		printf("Unable to use tgt: %s\n", krb_err_txt[kerno]);
22546f2fea7Skfall 		syslog(LOG_NOTICE|LOG_AUTH, "ksu: failed su: %s on %s: %s",
22646f2fea7Skfall 		       username, mytty, krb_err_txt[kerno]);
22746f2fea7Skfall 		dest_tkt();
22846f2fea7Skfall 		exit(1);
22946f2fea7Skfall 	    } else {
23046f2fea7Skfall 		if (!(hp = gethostbyname(hostname))) {
23146f2fea7Skfall 		    printf("Unable to get address of %s\n",hostname);
23246f2fea7Skfall 		    dest_tkt();
23346f2fea7Skfall 		    exit(1);
23446f2fea7Skfall 		}
23546f2fea7Skfall 		bcopy((char *)hp->h_addr, (char *) &faddr, sizeof(faddr));
23646f2fea7Skfall 		if ((kerno = krb_rd_req(&ticket, "rcmd", savehost,
23746f2fea7Skfall 					faddr, &authdata, "")) != KSUCCESS) {
23846f2fea7Skfall 		    printf("Unable to verify rcmd ticket: %s\n",
23946f2fea7Skfall 			   krb_err_txt[kerno]);
24046f2fea7Skfall 		    syslog(LOG_NOTICE|LOG_AUTH, "ksu: failed su: %s on %s: %s",
24146f2fea7Skfall 			   username, mytty, krb_err_txt[kerno]);
24246f2fea7Skfall 		    dest_tkt();
24346f2fea7Skfall 		    exit(1);
24446f2fea7Skfall 		}
24546f2fea7Skfall 	    }
24646f2fea7Skfall 	    printf("Don't forget to kdestroy before exiting the root shell.\n");
24746f2fea7Skfall 	} else
24846f2fea7Skfall 	/* if target requires a password, verify it */
24946f2fea7Skfall 	if (ruid && *pwd->pw_passwd) {
25046f2fea7Skfall 		p = getpass("Password:");
25146f2fea7Skfall 		if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) {
25246f2fea7Skfall 			fprintf(stderr, "Sorry\n");
25346f2fea7Skfall 			if (pwd->pw_uid == 0)
25446f2fea7Skfall 				syslog(LOG_CRIT|LOG_AUTH, "ksu: BAD SU %s on %s", username, mytty);
25546f2fea7Skfall 			exit(1);
25646f2fea7Skfall 		}
25746f2fea7Skfall 	}
25846f2fea7Skfall 
25946f2fea7Skfall #ifndef NO_GETUSERSHELL
26046f2fea7Skfall 	if (asme) {
26146f2fea7Skfall 		/* if asme and non-standard target shell, must be root */
26246f2fea7Skfall 		if (!chshell(pwd->pw_shell) && ruid) {
26346f2fea7Skfall 			fprintf(stderr, "ksu: Permission denied.\n");
26446f2fea7Skfall 			dest_tkt();
26546f2fea7Skfall 			exit(1);
26646f2fea7Skfall 		}
26746f2fea7Skfall 	}
26846f2fea7Skfall 	else
26946f2fea7Skfall #endif
27046f2fea7Skfall 	if (pwd->pw_shell && *pwd->pw_shell) {
27146f2fea7Skfall 		shell = pwd->pw_shell;
27246f2fea7Skfall 		iscsh = UNSET;
27346f2fea7Skfall 	} else {
27446f2fea7Skfall 		shell = "/bin/sh";
27546f2fea7Skfall 		iscsh = NO;
27646f2fea7Skfall 	}
27746f2fea7Skfall 
27846f2fea7Skfall 	/* if we're forking a csh, we want to slightly muck the args */
27946f2fea7Skfall 	if (iscsh == UNSET) {
28046f2fea7Skfall 		if (p = rindex(shell, '/'))
28146f2fea7Skfall 			++p;
28246f2fea7Skfall 		else
28346f2fea7Skfall 			p = shell;
28446f2fea7Skfall 		iscsh = strcmp(p, "csh") ? NO : YES;
28546f2fea7Skfall 	}
28646f2fea7Skfall 
28746f2fea7Skfall 	/* set permissions */
28846f2fea7Skfall 	if (setgid(pwd->pw_gid) < 0) {
28946f2fea7Skfall 		perror("ksu: setgid");
29046f2fea7Skfall 		dest_tkt();
29146f2fea7Skfall 		exit(1);
29246f2fea7Skfall 	}
29346f2fea7Skfall 	if (initgroups(user, pwd->pw_gid)) {
29446f2fea7Skfall 		fprintf(stderr, "ksu: initgroups failed\n");
29546f2fea7Skfall 		dest_tkt();
29646f2fea7Skfall 		exit(1);
29746f2fea7Skfall 	}
29846f2fea7Skfall 	if (setuid(pwd->pw_uid) < 0) {
29946f2fea7Skfall 		perror("ksu: setuid");
30046f2fea7Skfall 		dest_tkt();
30146f2fea7Skfall 		exit(1);
30246f2fea7Skfall 	}
30346f2fea7Skfall 
30446f2fea7Skfall #ifndef NO_GETUSERSHELL
30546f2fea7Skfall 	if (!asme) {
30646f2fea7Skfall #endif
30746f2fea7Skfall 		if (fulllogin) {
30846f2fea7Skfall 			p = getenv("TERM");
30946f2fea7Skfall 			cleanenv[0] = "PATH=:/usr/ucb:/bin:/usr/bin";
31046f2fea7Skfall 			cleanenv[1] = NULL;
31146f2fea7Skfall 			environ = cleanenv;
31246f2fea7Skfall 			(void)setenv("TERM", p, 1);
31346f2fea7Skfall 			if (chdir(pwd->pw_dir) < 0) {
31446f2fea7Skfall 				fprintf(stderr, "ksu: no directory\n");
31546f2fea7Skfall 				dest_tkt();
31646f2fea7Skfall 				exit(1);
31746f2fea7Skfall 			}
31846f2fea7Skfall 		}
31946f2fea7Skfall 		if (fulllogin || pwd->pw_uid)
32046f2fea7Skfall 			(void)setenv("USER", pwd->pw_name, 1);
32146f2fea7Skfall 		(void)setenv("HOME", pwd->pw_dir, 1);
32246f2fea7Skfall 		(void)setenv("SHELL", shell, 1);
32346f2fea7Skfall #ifndef NO_GETUSERSHELL
32446f2fea7Skfall 	}
32546f2fea7Skfall #endif
32646f2fea7Skfall 
32746f2fea7Skfall 	if (iscsh == YES) {
32846f2fea7Skfall 		if (fastlogin)
32946f2fea7Skfall 			*np-- = "-f";
33046f2fea7Skfall #ifndef NO_GETUSERSHELL
33146f2fea7Skfall 		if (asme)
33246f2fea7Skfall 			*np-- = "-m";
33346f2fea7Skfall #endif
33446f2fea7Skfall 	}
33546f2fea7Skfall 
33646f2fea7Skfall 	/* csh strips the first character... */
33746f2fea7Skfall 	*np = fulllogin ? "-ksu" : iscsh == YES ? "_ksu" : "ksu";
33846f2fea7Skfall 
33946f2fea7Skfall 	if (pwd->pw_uid == 0)
34046f2fea7Skfall 		syslog(LOG_NOTICE|LOG_AUTH, "ksu: %s on %s",
34146f2fea7Skfall 		    username, mytty);
34246f2fea7Skfall 
34346f2fea7Skfall 	(void)setpriority(PRIO_PROCESS, 0, prio);
34446f2fea7Skfall 
34546f2fea7Skfall 	execv(shell, np);
34646f2fea7Skfall 	fprintf(stderr, "ksu: no shell.\n");
34746f2fea7Skfall 	dest_tkt();
34846f2fea7Skfall 	exit(1);
34946f2fea7Skfall }
35046f2fea7Skfall 
35146f2fea7Skfall #ifndef NO_GETUSERSHELL
chshell(sh)35246f2fea7Skfall chshell(sh)
35346f2fea7Skfall 	char *sh;
35446f2fea7Skfall {
35546f2fea7Skfall 	char *cp, *getusershell();
35646f2fea7Skfall 
35746f2fea7Skfall 	while ((cp = getusershell()) != NULL)
35846f2fea7Skfall 		if (!strcmp(cp, sh))
35946f2fea7Skfall 			return(1);
36046f2fea7Skfall 	return(0);
36146f2fea7Skfall }
36246f2fea7Skfall #endif /* NO_GETUSERSHELL */
36346f2fea7Skfall 
koktologin(name,realm)36446f2fea7Skfall koktologin(name, realm)
36546f2fea7Skfall     char   *name;
36646f2fea7Skfall     char   *realm;
36746f2fea7Skfall {
36846f2fea7Skfall     struct auth_dat kdata_st;
36946f2fea7Skfall     AUTH_DAT *kdata = &kdata_st;
37046f2fea7Skfall     /* Cons together an AUTH_DAT structure for kuserok */
37146f2fea7Skfall     bzero((caddr_t) kdata, sizeof(*kdata));
37246f2fea7Skfall     strcpy(kdata->pname, name);
37346f2fea7Skfall     strcpy(kdata->pinst, "root");
37446f2fea7Skfall     strcpy(kdata->prealm, realm);
37546f2fea7Skfall     return (kuserok(kdata, "root"));
37646f2fea7Skfall }
377