su.c revision 36391
11556Srgrimes/*
21556Srgrimes * Copyright (c) 1988, 1993, 1994
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * Redistribution and use in source and binary forms, with or without
61556Srgrimes * modification, are permitted provided that the following conditions
71556Srgrimes * are met:
81556Srgrimes * 1. Redistributions of source code must retain the above copyright
91556Srgrimes *    notice, this list of conditions and the following disclaimer.
101556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111556Srgrimes *    notice, this list of conditions and the following disclaimer in the
121556Srgrimes *    documentation and/or other materials provided with the distribution.
131556Srgrimes * 3. All advertising materials mentioning features or use of this software
141556Srgrimes *    must display the following acknowledgement:
151556Srgrimes *	This product includes software developed by the University of
161556Srgrimes *	California, Berkeley and its contributors.
171556Srgrimes * 4. Neither the name of the University nor the names of its contributors
181556Srgrimes *    may be used to endorse or promote products derived from this software
191556Srgrimes *    without specific prior written permission.
201556Srgrimes *
211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311556Srgrimes * SUCH DAMAGE.
321556Srgrimes */
331556Srgrimes
341556Srgrimes#ifndef lint
351556Srgrimesstatic const char copyright[] =
361556Srgrimes"@(#) Copyright (c) 1988, 1993, 1994\n\
371556Srgrimes	The Regents of the University of California.  All rights reserved.\n";
381556Srgrimes#endif /* not lint */
3936049Scharnier
4036049Scharnier#ifndef lint
4136049Scharnier#if 0
4236049Scharnierstatic char sccsid[] = "@(#)su.c	8.3 (Berkeley) 4/2/94";
4350471Speter#endif
441556Srgrimesstatic const char rcsid[] =
451556Srgrimes	"$Id: su.c,v 1.26 1998/05/25 03:34:52 steve Exp $";
461556Srgrimes#endif /* not lint */
471556Srgrimes
481556Srgrimes#include <sys/param.h>
491556Srgrimes#include <sys/time.h>
501556Srgrimes#include <sys/resource.h>
511556Srgrimes
521556Srgrimes#include <err.h>
531556Srgrimes#include <errno.h>
541556Srgrimes#include <grp.h>
551556Srgrimes#include <paths.h>
561556Srgrimes#include <pwd.h>
571556Srgrimes#include <stdio.h>
581556Srgrimes#include <stdlib.h>
591556Srgrimes#include <string.h>
601556Srgrimes#include <syslog.h>
611556Srgrimes#include <unistd.h>
621556Srgrimes
631556Srgrimes#ifdef LOGIN_CAP
641556Srgrimes#include <login_cap.h>
651556Srgrimes#ifdef LOGIN_CAP_AUTH
661556Srgrimes#undef SKEY
671556Srgrimes#undef KERBEROS
681556Srgrimes#endif
691556Srgrimes#endif
701556Srgrimes
711556Srgrimes#ifdef	SKEY
721556Srgrimes#include <skey.h>
731556Srgrimes#endif
741556Srgrimes
751556Srgrimes#ifdef KERBEROS
761556Srgrimes#include <des.h>
771556Srgrimes#include <krb.h>
7876017Skris#include <netdb.h>
791556Srgrimes
801556Srgrimes#ifdef LOGIN_CAP
811556Srgrimes#define	ARGSTR	"-Kflmc:"
821556Srgrimes#else
831556Srgrimes#define	ARGSTR	"-Kflm"
841556Srgrimes#endif
851556Srgrimes
861556Srgrimesstatic int kerberos(char *username, char *user, int uid, char *pword);
871556Srgrimesstatic int koktologin(char *name, char *toname);
881556Srgrimes
891556Srgrimesint use_kerberos = 1;
901556Srgrimes#else /* !KERBEROS */
911556Srgrimes#ifdef LOGIN_CAP
921556Srgrimes#define	ARGSTR	"-flmc:"
931556Srgrimes#else
941556Srgrimes#define	ARGSTR	"-flm"
951556Srgrimes#endif
961556Srgrimes#endif /* KERBEROS */
9746684Skris
981556Srgrimeschar   *ontty __P((void));
991556Srgrimesint	chshell __P((char *));
1001556Srgrimesstatic void usage __P((void));
1011556Srgrimes
1021556Srgrimesint
1031556Srgrimesmain(argc, argv)
1041556Srgrimes	int argc;
1051556Srgrimes	char **argv;
1061556Srgrimes{
1071556Srgrimes	extern char **environ;
1081556Srgrimes	struct passwd *pwd;
1091556Srgrimes#ifdef WHEELSU
1101556Srgrimes	char *targetpass;
1111556Srgrimes	int iswheelsu;
1121556Srgrimes#endif /* WHEELSU */
1131556Srgrimes	char *p, **g, *user, *shell=NULL, *username, **cleanenv, **nargv, **np;
1141556Srgrimes	struct group *gr;
1151556Srgrimes	uid_t ruid;
1161556Srgrimes	gid_t gid;
1171556Srgrimes	int asme, ch, asthem, fastlogin, prio, i;
1181556Srgrimes	enum { UNSET, YES, NO } iscsh = UNSET;
1191556Srgrimes#ifdef LOGIN_CAP
1201556Srgrimes	login_cap_t *lc;
1211556Srgrimes	char *class=NULL;
1221556Srgrimes	int setwhat;
1231556Srgrimes#ifdef LOGIN_CAP_AUTH
1241556Srgrimes	char *style, *approvep, *auth_method = NULL;
1251556Srgrimes#endif
12676017Skris#endif
1271556Srgrimes#ifdef KERBEROS
1281556Srgrimes	char *k;
1291556Srgrimes#endif
1301556Srgrimes	char shellbuf[MAXPATHLEN];
1311556Srgrimes
1321556Srgrimes#ifdef WHEELSU
1331556Srgrimes	iswheelsu =
1341556Srgrimes#endif /* WHEELSU */
1351556Srgrimes	asme = asthem = fastlogin = 0;
1361556Srgrimes	user = "root";
1371556Srgrimes	while(optind < argc)
1381556Srgrimes	    if((ch = getopt(argc, argv, ARGSTR)) != -1)
1391556Srgrimes		switch((char)ch) {
1401556Srgrimes#ifdef KERBEROS
14176017Skris		case 'K':
1421556Srgrimes			use_kerberos = 0;
1431556Srgrimes			break;
1441556Srgrimes#endif
1451556Srgrimes		case 'f':
1461556Srgrimes			fastlogin = 1;
1471556Srgrimes			break;
1481556Srgrimes		case '-':
1491556Srgrimes		case 'l':
1501556Srgrimes			asme = 0;
1511556Srgrimes			asthem = 1;
1521556Srgrimes			break;
1531556Srgrimes		case 'm':
1541556Srgrimes			asme = 1;
1551556Srgrimes			asthem = 0;
15676017Skris			break;
1571556Srgrimes#ifdef LOGIN_CAP
1581556Srgrimes		case 'c':
1591556Srgrimes			class = optarg;
1601556Srgrimes			break;
1611556Srgrimes#endif
1628855Srgrimes		case '?':
1631556Srgrimes		default:
1641556Srgrimes			usage();
1651556Srgrimes		}
1661556Srgrimes	    else
1671556Srgrimes	    {
1681556Srgrimes		user = argv[optind++];
1691556Srgrimes		break;
1701556Srgrimes	    }
1711556Srgrimes
1721556Srgrimes	if (strlen(user) > MAXLOGNAME - 1) {
1731556Srgrimes		(void)fprintf(stderr, "su: username too long.\n");
1741556Srgrimes		exit(1);
1751556Srgrimes	}
1761556Srgrimes
1771556Srgrimes	if (user == NULL)
1781556Srgrimes		usage();
1791556Srgrimes
1801556Srgrimes	if ((nargv = malloc (sizeof (char *) * (argc + 4))) == NULL) {
1811556Srgrimes	    errx(1, "malloc failure");
1821556Srgrimes	}
1838855Srgrimes
1841556Srgrimes	nargv[argc + 3] = NULL;
1851556Srgrimes	for (i = argc; i >= optind; i--)
1861556Srgrimes	    nargv[i + 3] = argv[i];
1871556Srgrimes	np = &nargv[i + 3];
18876017Skris
1891556Srgrimes	argv += optind;
1901556Srgrimes
1911556Srgrimes	errno = 0;
1921556Srgrimes	prio = getpriority(PRIO_PROCESS, 0);
1931556Srgrimes	if (errno)
1941556Srgrimes		prio = 0;
1951556Srgrimes	(void)setpriority(PRIO_PROCESS, 0, -2);
1961556Srgrimes	openlog("su", LOG_CONS, 0);
1971556Srgrimes
1981556Srgrimes	/* get current login name and shell */
1991556Srgrimes	ruid = getuid();
2001556Srgrimes	username = getlogin();
2011556Srgrimes	if (username == NULL || (pwd = getpwnam(username)) == NULL ||
2021556Srgrimes	    pwd->pw_uid != ruid)
2031556Srgrimes		pwd = getpwuid(ruid);
20476017Skris	if (pwd == NULL)
2051556Srgrimes		errx(1, "who are you?");
2061556Srgrimes	username = strdup(pwd->pw_name);
2071556Srgrimes	gid = pwd->pw_gid;
2081556Srgrimes	if (username == NULL)
2091556Srgrimes		err(1, NULL);
21076017Skris	if (asme) {
2111556Srgrimes		if (pwd->pw_shell != NULL && *pwd->pw_shell != '\0') {
2121556Srgrimes			/* copy: pwd memory is recycled */
2131556Srgrimes			shell = strncpy(shellbuf,  pwd->pw_shell, sizeof shellbuf);
2141556Srgrimes			shellbuf[sizeof shellbuf - 1] = '\0';
2151556Srgrimes		} else {
2161556Srgrimes			shell = _PATH_BSHELL;
2171556Srgrimes			iscsh = NO;
2181556Srgrimes		}
2191556Srgrimes	}
2201556Srgrimes
22176017Skris#ifdef LOGIN_CAP_AUTH
2221556Srgrimes	if (auth_method = strchr(user, ':')) {
2231556Srgrimes		*auth_method = '\0';
2241556Srgrimes		auth_method++;
2251556Srgrimes		if (*auth_method == '\0')
2261556Srgrimes			auth_method = NULL;
2271556Srgrimes	}
22876017Skris#endif /* !LOGIN_CAP_AUTH */
2291556Srgrimes
2301556Srgrimes	/* get target login information, default to root */
2311556Srgrimes	if ((pwd = getpwnam(user)) == NULL) {
2321556Srgrimes		errx(1, "unknown login: %s", user);
2331556Srgrimes	}
2341556Srgrimes#ifdef LOGIN_CAP
2351556Srgrimes	if (class==NULL) {
2361556Srgrimes		lc = login_getpwclass(pwd);
2371556Srgrimes	} else {
23846684Skris		if (ruid)
2391556Srgrimes			errx(1, "only root may use -c");
2401556Srgrimes		lc = login_getclass(class);
2411556Srgrimes		if (lc == NULL)
2421556Srgrimes			errx(1, "unknown class: %s", class);
2431556Srgrimes	}
2441556Srgrimes#endif
2451556Srgrimes
2461556Srgrimes#ifdef WHEELSU
2471556Srgrimes	targetpass = strdup(pwd->pw_passwd);
2481556Srgrimes#endif /* WHEELSU */
2491556Srgrimes
2501556Srgrimes	if (ruid) {
2511556Srgrimes#ifdef KERBEROS
2521556Srgrimes		if (use_kerberos && koktologin(username, user)
2531556Srgrimes		    && !pwd->pw_uid) {
2541556Srgrimes			warnx("kerberos: not in %s's ACL.", user);
2551556Srgrimes			use_kerberos = 0;
2561556Srgrimes		}
2571556Srgrimes#endif
25876017Skris		{
2591556Srgrimes			/*
2601556Srgrimes			 * Only allow those with pw_gid==0 or those listed in
2611556Srgrimes			 * group zero to su to root.  If group zero entry is
2621556Srgrimes			 * missing or empty, then allow anyone to su to root.
2631556Srgrimes			 * iswheelsu will only be set if the user is EXPLICITLY
2641556Srgrimes			 * listed in group zero.
2651556Srgrimes			 */
2661556Srgrimes			if (pwd->pw_uid == 0 && (gr = getgrgid((gid_t)0)) &&
2671556Srgrimes			    gr->gr_mem && *(gr->gr_mem))
2681556Srgrimes				for (g = gr->gr_mem;; ++g) {
2698855Srgrimes					if (!*g)
2701556Srgrimes						if (gid == 0)
2711556Srgrimes							break;
2721556Srgrimes						else
2731556Srgrimes							errx(1, "you are not in the correct group to su %s.", user);
2741556Srgrimes					if (strcmp(username, *g) == 0) {
2751556Srgrimes#ifdef WHEELSU
2761556Srgrimes						iswheelsu = 1;
2771556Srgrimes#endif /* WHEELSU */
2781556Srgrimes						break;
2791556Srgrimes					}
2801556Srgrimes				}
2811556Srgrimes		}
28276017Skris		/* if target requires a password, verify it */
2831556Srgrimes		if (*pwd->pw_passwd) {
2841556Srgrimes#ifdef LOGIN_CAP_AUTH
2851556Srgrimes		/*
2861556Srgrimes		 * This hands off authorisation to an authorisation program,
2871556Srgrimes		 * depending on the styles available for the "auth-su",
2881556Srgrimes		 * authorisation styles.
2891556Srgrimes		 */
2901556Srgrimes		if ((style = login_getstyle(lc, auth_method, "su")) == NULL)
2911556Srgrimes			errx(1, "auth method available for su.\n");
2921556Srgrimes		if (authenticate(user, lc ? lc->lc_class : "default", style, "su") != 0) {
2931556Srgrimes#ifdef WHEELSU
2941556Srgrimes			if (!iswheelsu || authenticate(username, lc ? lc->lc_class : "default", style, "su") != 0) {
2951556Srgrimes#endif /* WHEELSU */
2961556Srgrimes			{
2971556Srgrimes			fprintf(stderr, "Sorry\n");
2981556Srgrimes			syslog(LOG_AUTH|LOG_WARNING,"BAD SU %s to %s%s", username, user, ontty());
2991556Srgrimes			exit(1);
3001556Srgrimes			}
30176017Skris		}
3021556Srgrimes
3031556Srgrimes		/*
3041556Srgrimes		 * If authentication succeeds, run any approval
3051556Srgrimes		 * program, if applicable for this class.
3061556Srgrimes		 */
3071556Srgrimes		approvep = login_getcapstr(lc, "approve", NULL, NULL);
3081556Srgrimes		if (approvep==NULL || auth_script(approvep, approvep, username, lc->lc_class, 0) == 0) {
3091556Srgrimes			int     r = auth_scan(AUTH_OKAY);
3101556Srgrimes			/* See what the authorise program says */
3111556Srgrimes			if (!(r & AUTH_ROOTOKAY) && pwd->pw_uid == 0) {
3121556Srgrimes				fprintf(stderr, "Sorry\n");
3131556Srgrimes				syslog(LOG_AUTH|LOG_WARNING,"UNAPPROVED ROOT SU %s%s", user, ontty());
3141556Srgrimes				exit(1);
3151556Srgrimes			}
3161556Srgrimes		}
3171556Srgrimes#else /* !LOGIN_CAP_AUTH */
3181556Srgrimes#ifdef	SKEY
3191556Srgrimes#ifdef WHEELSU
3201556Srgrimes			if (iswheelsu) {
3211556Srgrimes				pwd = getpwnam(username);
3221556Srgrimes			}
3231556Srgrimes#endif /* WHEELSU */
3241556Srgrimes			p = skey_getpass("Password:", pwd, 1);
3251556Srgrimes			if (!(!strcmp(pwd->pw_passwd, skey_crypt(p, pwd->pw_passwd, pwd, 1))
3261556Srgrimes#ifdef WHEELSU
3271556Srgrimes			      || (iswheelsu && !strcmp(targetpass, crypt(p,targetpass)))
3281556Srgrimes#endif /* WHEELSU */
32976017Skris			      )) {
3301556Srgrimes#else
3311556Srgrimes			p = getpass("Password:");
3321556Srgrimes			if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) {
3331556Srgrimes#endif
3341556Srgrimes#ifdef KERBEROS
3351556Srgrimes	    			if (!use_kerberos || (use_kerberos && kerberos(username, user, pwd->pw_uid, p)))
3361556Srgrimes#endif
3371556Srgrimes					{
33876017Skris					fprintf(stderr, "Sorry\n");
3391556Srgrimes					syslog(LOG_AUTH|LOG_WARNING, "BAD SU %s to %s%s", username, user, ontty());
3401556Srgrimes					exit(1);
3411556Srgrimes				}
3421556Srgrimes			}
34376017Skris#ifdef WHEELSU
3441556Srgrimes			if (iswheelsu) {
3451556Srgrimes				pwd = getpwnam(user);
3461556Srgrimes			}
3471556Srgrimes#endif /* WHEELSU */
3481556Srgrimes#endif /* LOGIN_CAP_AUTH */
3491556Srgrimes		}
3501556Srgrimes		if (pwd->pw_expire && time(NULL) >= pwd->pw_expire) {
3511556Srgrimes			fprintf(stderr, "Sorry - account expired\n");
3521556Srgrimes			syslog(LOG_AUTH|LOG_WARNING,
3531556Srgrimes				"BAD SU %s to %s%s", username,
3541556Srgrimes				user, ontty());
3551556Srgrimes			exit(1);
3561556Srgrimes		}
3571556Srgrimes	}
3581556Srgrimes
3591556Srgrimes	if (asme) {
3601556Srgrimes		/* if asme and non-standard target shell, must be root */
3611556Srgrimes		if (!chshell(pwd->pw_shell) && ruid)
36276017Skris			errx(1, "permission denied (shell).");
3631556Srgrimes	} else if (pwd->pw_shell && *pwd->pw_shell) {
3641556Srgrimes		shell = pwd->pw_shell;
3651556Srgrimes		iscsh = UNSET;
3661556Srgrimes	} else {
3671556Srgrimes		shell = _PATH_BSHELL;
3681556Srgrimes		iscsh = NO;
3691556Srgrimes	}
3701556Srgrimes
3711556Srgrimes	/* if we're forking a csh, we want to slightly muck the args */
3721556Srgrimes	if (iscsh == UNSET) {
3731556Srgrimes		p = strrchr(shell, '/');
3741556Srgrimes		if (p)
3751556Srgrimes			++p;
3761556Srgrimes		else
3771556Srgrimes			p = shell;
3781556Srgrimes		if ((iscsh = strcmp(p, "csh") ? NO : YES) == NO)
3791556Srgrimes		    iscsh = strcmp(p, "tcsh") ? NO : YES;
3801556Srgrimes	}
3811556Srgrimes
3821556Srgrimes	(void)setpriority(PRIO_PROCESS, 0, prio);
38376017Skris
3841556Srgrimes#ifdef LOGIN_CAP
3851556Srgrimes	/* Set everything now except the environment & umask */
3861556Srgrimes	setwhat = LOGIN_SETUSER|LOGIN_SETGROUP|LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
3871556Srgrimes	/*
3881556Srgrimes	 * Don't touch resource/priority settings if -m has been
3891556Srgrimes	 * used or -l and -c hasn't, and we're not su'ing to root.
3901556Srgrimes	 */
3911556Srgrimes        if ((asme || (!asthem && class == NULL)) && pwd->pw_uid)
3921556Srgrimes		setwhat &= ~(LOGIN_SETPRIORITY|LOGIN_SETRESOURCES);
3931556Srgrimes	if (setusercontext(lc, pwd, pwd->pw_uid, setwhat) < 0)
3941556Srgrimes		err(1, "setusercontext");
3951556Srgrimes#else
3961556Srgrimes	/* set permissions */
3971556Srgrimes	if (setgid(pwd->pw_gid) < 0)
3981556Srgrimes		err(1, "setgid");
3991556Srgrimes	if (initgroups(user, pwd->pw_gid))
4001556Srgrimes		errx(1, "initgroups failed");
4011556Srgrimes	if (setuid(pwd->pw_uid) < 0)
4021556Srgrimes		err(1, "setuid");
4031556Srgrimes#endif
4041556Srgrimes
4051556Srgrimes	if (!asme) {
4061556Srgrimes		if (asthem) {
4071556Srgrimes			p = getenv("TERM");
4081556Srgrimes#ifdef KERBEROS
4091556Srgrimes			k = getenv("KRBTKFILE");
4101556Srgrimes#endif
4111556Srgrimes			if ((cleanenv = calloc(20, sizeof(char*))) == NULL)
4121556Srgrimes				errx(1, "calloc");
4131556Srgrimes			cleanenv[0] = NULL;
4141556Srgrimes			environ = cleanenv;
4151556Srgrimes#ifdef LOGIN_CAP
4161556Srgrimes			/* set the su'd user's environment & umask */
4171556Srgrimes			setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETPATH|LOGIN_SETUMASK|LOGIN_SETENV);
4181556Srgrimes#else
4191556Srgrimes			(void)setenv("PATH", _PATH_DEFPATH, 1);
4201556Srgrimes#endif
4211556Srgrimes			if (p)
4221556Srgrimes				(void)setenv("TERM", p, 1);
4231556Srgrimes#ifdef KERBEROS
4241556Srgrimes			if (k)
4251556Srgrimes				(void)setenv("KRBTKFILE", k, 1);
4261556Srgrimes#endif
4271556Srgrimes			if (chdir(pwd->pw_dir) < 0)
4281556Srgrimes				errx(1, "no directory");
42976017Skris		}
4301556Srgrimes		if (asthem || pwd->pw_uid)
4311556Srgrimes			(void)setenv("USER", pwd->pw_name, 1);
4321556Srgrimes		(void)setenv("HOME", pwd->pw_dir, 1);
4331556Srgrimes		(void)setenv("SHELL", shell, 1);
4341556Srgrimes	}
4351556Srgrimes	if (iscsh == YES) {
4361556Srgrimes		if (fastlogin)
4371556Srgrimes			*np-- = "-f";
4381556Srgrimes		if (asme)
4391556Srgrimes			*np-- = "-m";
4401556Srgrimes	}
4411556Srgrimes
4421556Srgrimes	/* csh strips the first character... */
4431556Srgrimes	*np = asthem ? "-su" : iscsh == YES ? "_su" : "su";
4441556Srgrimes
44576017Skris	if (ruid != 0)
4461556Srgrimes		syslog(LOG_NOTICE|LOG_AUTH, "%s to %s%s",
4471556Srgrimes		    username, user, ontty());
4481556Srgrimes
4491556Srgrimes	login_close(lc);
4501556Srgrimes
4511556Srgrimes	execv(shell, np);
4521556Srgrimes	err(1, "%s", shell);
4531556Srgrimes}
4541556Srgrimes
4551556Srgrimesstatic void
4561556Srgrimesusage()
4571556Srgrimes{
4581556Srgrimes	(void)fprintf(stderr, "usage: su [%s] [login [args]]\n", ARGSTR);
4591556Srgrimes	exit(1);
4601556Srgrimes}
4611556Srgrimes
4621556Srgrimesint
4631556Srgrimeschshell(sh)
4641556Srgrimes	char *sh;
4651556Srgrimes{
4661556Srgrimes	int  r = 0;
4671556Srgrimes	char *cp;
4681556Srgrimes
46976017Skris	setusershell();
4701556Srgrimes	while (!r && (cp = getusershell()) != NULL)
4711556Srgrimes		r = strcmp(cp, sh) == 0;
4721556Srgrimes	endusershell();
4731556Srgrimes	return r;
4741556Srgrimes}
4751556Srgrimes
4761556Srgrimeschar *
4771556Srgrimesontty()
4781556Srgrimes{
4791556Srgrimes	char *p;
4801556Srgrimes	static char buf[MAXPATHLEN + 4];
4811556Srgrimes
4821556Srgrimes	buf[0] = 0;
4831556Srgrimes	p = ttyname(STDERR_FILENO);
4841556Srgrimes	if (p)
4851556Srgrimes		snprintf(buf, sizeof(buf), " on %s", p);
4861556Srgrimes	return (buf);
4871556Srgrimes}
4881556Srgrimes
4891556Srgrimes#ifdef KERBEROS
4901556Srgrimesint
4911556Srgrimeskerberos(username, user, uid, pword)
4921556Srgrimes	char *username, *user;
4931556Srgrimes	int uid;
4941556Srgrimes	char *pword;
4951556Srgrimes{
4961556Srgrimes	KTEXT_ST ticket;
4971556Srgrimes	AUTH_DAT authdata;
4981556Srgrimes	int kerno;
4991556Srgrimes	u_long faddr;
5001556Srgrimes	char lrealm[REALM_SZ], krbtkfile[MAXPATHLEN];
5011556Srgrimes	char hostname[MAXHOSTNAMELEN], savehost[MAXHOSTNAMELEN];
5021556Srgrimes	char *krb_get_phost();
5031556Srgrimes	struct hostent *hp;
50476017Skris
5051556Srgrimes	if (krb_get_lrealm(lrealm, 1) != KSUCCESS)
5061556Srgrimes		return (1);
5071556Srgrimes	(void)sprintf(krbtkfile, "%s_%s_%lu", TKT_ROOT, user,
5081556Srgrimes	    (unsigned long)getuid());
5091556Srgrimes
5101556Srgrimes	(void)setenv("KRBTKFILE", krbtkfile, 1);
5111556Srgrimes	(void)krb_set_tkt_string(krbtkfile);
5121556Srgrimes	/*
5131556Srgrimes	 * Set real as well as effective ID to 0 for the moment,
5141556Srgrimes	 * to make the kerberos library do the right thing.
5151556Srgrimes	 */
5161556Srgrimes	if (setuid(0) < 0) {
5171556Srgrimes		warn("setuid");
5181556Srgrimes		return (1);
5191556Srgrimes	}
5201556Srgrimes
5211556Srgrimes	/*
5221556Srgrimes	 * Little trick here -- if we are su'ing to root,
5231556Srgrimes	 * we need to get a ticket for "xxx.root", where xxx represents
5241556Srgrimes	 * the name of the person su'ing.  Otherwise (non-root case),
5251556Srgrimes	 * we need to get a ticket for "yyy.", where yyy represents
5261556Srgrimes	 * the name of the person being su'd to, and the instance is null
5271556Srgrimes	 *
5281556Srgrimes	 * We should have a way to set the ticket lifetime,
5291556Srgrimes	 * with a system default for root.
5301556Srgrimes	 */
5311556Srgrimes	kerno = krb_get_pw_in_tkt((uid == 0 ? username : user),
5321556Srgrimes		(uid == 0 ? "root" : ""), lrealm,
5331556Srgrimes	    	"krbtgt", lrealm, DEFAULT_TKT_LIFE, pword);
5341556Srgrimes
5351556Srgrimes	if (kerno != KSUCCESS) {
5361556Srgrimes		if (kerno == KDC_PR_UNKNOWN) {
5371556Srgrimes			warnx("kerberos: principal unknown: %s.%s@%s",
5381556Srgrimes				(uid == 0 ? username : user),
5391556Srgrimes				(uid == 0 ? "root" : ""), lrealm);
5401556Srgrimes			return (1);
5411556Srgrimes		}
5421556Srgrimes		warnx("kerberos: unable to su: %s", krb_err_txt[kerno]);
5431556Srgrimes		syslog(LOG_NOTICE|LOG_AUTH,
5441556Srgrimes		    "BAD Kerberos SU: %s to %s%s: %s",
5451556Srgrimes		    username, user, ontty(), krb_err_txt[kerno]);
54676017Skris		return (1);
5471556Srgrimes	}
5481556Srgrimes
5491556Srgrimes	if (chown(krbtkfile, uid, -1) < 0) {
5501556Srgrimes		warn("chown");
5511556Srgrimes		(void)unlink(krbtkfile);
5521556Srgrimes		return (1);
5531556Srgrimes	}
5541556Srgrimes
5551556Srgrimes	(void)setpriority(PRIO_PROCESS, 0, -2);
5561556Srgrimes
5571556Srgrimes	if (gethostname(hostname, sizeof(hostname)) == -1) {
5581556Srgrimes		warn("gethostname");
5591556Srgrimes		dest_tkt();
5601556Srgrimes		return (1);
5611556Srgrimes	}
5621556Srgrimes
5631556Srgrimes	(void)strncpy(savehost, krb_get_phost(hostname), sizeof(savehost));
5641556Srgrimes	savehost[sizeof(savehost) - 1] = '\0';
5651556Srgrimes
5661556Srgrimes	kerno = krb_mk_req(&ticket, "rcmd", savehost, lrealm, 33);
5671556Srgrimes
5681556Srgrimes	if (kerno == KDC_PR_UNKNOWN) {
5691556Srgrimes		warnx("Warning: TGT not verified.");
5701556Srgrimes		syslog(LOG_NOTICE|LOG_AUTH,
5711556Srgrimes		    "%s to %s%s, TGT not verified (%s); %s.%s not registered?",
5721556Srgrimes		    username, user, ontty(), krb_err_txt[kerno],
5738855Srgrimes		    "rcmd", savehost);
57476017Skris	} else if (kerno != KSUCCESS) {
5751556Srgrimes		warnx("Unable to use TGT: %s", krb_err_txt[kerno]);
5761556Srgrimes		syslog(LOG_NOTICE|LOG_AUTH, "failed su: %s to %s%s: %s",
5771556Srgrimes		    username, user, ontty(), krb_err_txt[kerno]);
5781556Srgrimes		dest_tkt();
5791556Srgrimes		return (1);
5801556Srgrimes	} else {
5811556Srgrimes		if (!(hp = gethostbyname(hostname))) {
5821556Srgrimes			warnx("can't get addr of %s", hostname);
5831556Srgrimes			dest_tkt();
58476017Skris			return (1);
5851556Srgrimes		}
5861556Srgrimes		memmove((char *)&faddr, (char *)hp->h_addr, sizeof(faddr));
5871556Srgrimes
5881556Srgrimes		if ((kerno = krb_rd_req(&ticket, "rcmd", savehost, faddr,
5891556Srgrimes		    &authdata, "")) != KSUCCESS) {
5901556Srgrimes			warnx("kerberos: unable to verify rcmd ticket: %s\n",
5911556Srgrimes			    krb_err_txt[kerno]);
5921556Srgrimes			syslog(LOG_NOTICE|LOG_AUTH,
5931556Srgrimes			    "failed su: %s to %s%s: %s", username,
5941556Srgrimes			     user, ontty(), krb_err_txt[kerno]);
5951556Srgrimes			dest_tkt();
5961556Srgrimes			return (1);
5971556Srgrimes		}
5981556Srgrimes	}
5991556Srgrimes	return (0);
6001556Srgrimes}
6011556Srgrimes
6021556Srgrimesint
6031556Srgrimeskoktologin(name, toname)
60476017Skris	char *name, *toname;
6051556Srgrimes{
6061556Srgrimes	AUTH_DAT *kdata;
6071556Srgrimes	AUTH_DAT kdata_st;
6081556Srgrimes	char realm[REALM_SZ];
6091556Srgrimes
6101556Srgrimes	if (krb_get_lrealm(realm, 1) != KSUCCESS)
6111556Srgrimes		return (1);
6121556Srgrimes	kdata = &kdata_st;
6131556Srgrimes	memset((char *)kdata, 0, sizeof(*kdata));
6141556Srgrimes	(void)strncpy(kdata->pname, name, sizeof kdata->pname - 1);
6151556Srgrimes	(void)strncpy(kdata->pinst,
6161556Srgrimes	    ((strcmp(toname, "root") == 0) ? "root" : ""), sizeof kdata->pinst - 1);
6171556Srgrimes	(void)strncpy(kdata->prealm, realm, sizeof kdata->prealm - 1);
6181556Srgrimes	return (kuserok(kdata, toname));
6191556Srgrimes}
6201556Srgrimes#endif
6211556Srgrimes