Index: login.c
===================================================================
RCS file: /mit/krb5/.cvsroot/src/appl/bsd/login.c,v
retrieving revision 5.44
diff -u -r5.44 login.c
--- login.c	1996/01/19 01:31:57	5.44
+++ login.c	1996/01/19 16:07:05
@@ -36,10 +36,10 @@
  *			 allows preauthenticated login as root)
  * login -e name	(for pre-authenticated encrypted, must do term
  *			 negotiation)
- * ifdef KRB4
+ * ifdef KRB4_KLOGIN
  * login -k hostname (for Kerberos V4 rlogind with password access)
  * login -K hostname (for Kerberos V4 rlogind with restricted access)
- * endif KRB4 
+ * endif KRB4_KLOGIN
  *
  * only one of: -r -f -e -k -K -F
  * only one of: -r -h -k -K
@@ -94,6 +94,16 @@
 #include <shadow.h>
 #endif
 
+#ifdef KRB4_KLOGIN
+/* support for running under v4 klogind, -k -K flags */
+#define KRB4
+#endif
+
+#ifdef KRB4_GET_TICKETS
+/* support for prompting for v4 initial tickets */
+#define KRB4
+#endif
+
 #ifdef KRB4
 #include <krb.h>
 #include <netdb.h>
@@ -164,6 +174,11 @@
 #define	UT_NAMESIZE	sizeof(((struct utmp *)0)->ut_name)
 #endif
 
+#ifndef HAVE_SETPRIORITY
+/* if we don't have it, punt it cleanly */
+#define setpriority(which,who,prio)
+#endif /* HAVE_SETPRIORITY */
+
 #define MAXENVIRON	32
 
 /*
@@ -189,7 +204,7 @@
 };
 #endif
 
-#ifdef KRB4
+#ifdef KRB4_GET_TICKETS
 #define KRB_ENVIRON	"KRBTKFILE"	/* Ticket file environment variable */
 #define KRB_TK_DIR	"/tmp/tkt_"	/* Where to put the ticket */
 #define MAXPWSIZE	128		/* Biggest string accepted for KRB4
@@ -198,11 +213,12 @@
 AUTH_DAT *kdata = (AUTH_DAT *) NULL;
 KTEXT ticket = (KTEXT) NULL;
 char tkfile[MAXPATHLEN];
+char ccfile[MAXPATHLEN+6];		/* FILE:path+\0 */
 int krbflag = 0;			/* set if tickets have been obtained */
 #ifdef SETPAG
 int pagflag = 0;			/* true if setpag() has been called */
 #endif /* SETPAG */
-#endif /* KRB4 */
+#endif /* KRB4_GET_TICKETS */
 
 char *getenv();
 void dofork();
@@ -258,8 +274,11 @@
 	char tbuf[MAXPATHLEN + 2];
 	char *ttyname(), *stypeof(), *crypt(), *getpass();
 	time_t login_time;
+	int retval;
+#ifdef KRB5_GET_TICKETS
+	krb5_context kcontext;
+#endif /* KRB5_GET_TICKETS */
 	char *ccname = 0;   /* name of forwarded cache */
-int retval;
 	
 	off_t lseek();
 #ifdef POSIX_TERMIOS
@@ -285,9 +304,7 @@
 	(void)signal(SIGQUIT, SIG_IGN);
 	(void)signal(SIGINT, SIG_IGN);
 #endif
-#ifdef HAVE_SETPRIORITY
-	(void)setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
-#endif
+	setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
 #ifdef OQUOTA
 	(void)quota(Q_SETUID, 0, 0, 0);
 #endif
@@ -356,7 +373,7 @@
 				*p = '\0';
 			hostname = optarg;
 			break;
-#ifdef KRB4
+#ifdef KRB4_KLOGIN
 		case 'k':
 		case 'K':
 			EXCL_AUTH_TEST;
@@ -382,7 +399,7 @@
 				*p = '\0';
 			hostname = optarg;
 			break;
-#endif /* KRB4 */
+#endif /* KRB4_KLOGIN */
 		case 'e':
 			EXCL_AUTH_TEST;
 			if (getuid()) {
@@ -520,19 +537,45 @@
 	openlog("login", LOG_ODELAY, LOG_AUTH);
 #endif /* 4.2 syslog */
 
+/******* begin askpw *******/
+	/* overall:
+	   ask for username if we don't have it already
+	   look it up in local pw or shadow file (to get crypt string)
+	   ask for password
+	   try and get v4, v5 tickets with it
+	   try and use the tickets against the local srvtab
+	   if the password matches, always let them in
+	   if the ticket decrypts, let them in.
+	   v5 needs to work, does v4?
+	   */
+#ifdef KRB5_GET_TICKETS
+	krb5_init_context(&kcontext);
+	krb5_init_ets(kcontext);
+#endif /* KRB5_GET_TICKETS */
 	for (cnt = 0;; username = NULL) {
-#ifdef KRB4
-		char pp[9], pp2[MAXPWSIZE], *namep;
+#ifdef KRB5_GET_TICKETS
+		int kpass_ok,lpass_ok;
 		int krbval;
+		char user_pwcopy[9], user_pwstring[MAXPWSIZE], *namep;
+		int pwsize;
+		krb5_ccache ccache;
+#ifdef KRB4_GET_TICKETS
 		char realm[REALM_SZ];
-		int kpass_ok,lpass_ok;
-#ifdef NOENCRYPTION
-#define read_long_pw_string placebo_read_pw_string
-#else
-#define read_long_pw_string des_read_pw_string
-#endif
-		int read_long_pw_string();
-#endif /* KRB4 */
+
+		/* Set up the ticket file environment variable */
+		strncpy(tkfile, KRB_TK_DIR, sizeof(tkfile));
+		strncat(tkfile, strrchr(ttyn, '/')+1,
+			sizeof(tkfile) - strlen(tkfile));
+		(void) unlink (tkfile);
+		setenv(KRB_ENVIRON, tkfile, 1);
+
+#endif /* KRB4_GET_TICKETS */
+		/* Set up the credential cache environment variable */
+		sprintf(ccfile, "FILE:/tmp/krb5cc_%s", strrchr(ttyn, '/')+1);
+		unlink(ccfile+strlen("FILE:"));
+		setenv(KRB5_ENV_CCNAME, ccfile, 1);
+
+#endif /* KRB5_GET_TICKETS */
 #if defined(TIOCSETD)&&(!defined(POSIX_TERMIOS))
 		ioctlval = 0;
 		(void)ioctl(0, TIOCSETD, (char *)&ioctlval);
@@ -583,93 +626,152 @@
 		if (!passwd_req) break;
 #ifdef HAVE_SHADOW
 		if (spwd) {
-		    if (!*(spwd->sp_pwdp)) break;
+			if (!*(spwd->sp_pwdp)) break;
 		} else
 #endif
-		    if (pwd && !*(pwd->pw_passwd))
-			break;
+			if (pwd && !*(pwd->pw_passwd))
+				break;
 
-#ifdef KRB4
+		/* we have several sets of code:
+		   1) get v5 tickets alone -DKRB5_GET_TICKETS
+		   2) get v4 tickets alone [** don't! only get them *with* v5 **]
+		   3) get both tickets -DKRB5_GET_TICKETS -DKRB4_GET_TICKETS
+		   3a) use krb524 calls to get the v4 tickets -DKRB4_USE_524 plus (3).
+		   4) get no tickets and use the password file (none of thes defined.)
+		   
+		   Likewise we need to (optionally?) test these tickets against local srvtabs.
+		   */
+#ifdef KRB5_GET_TICKETS
+		/* rename these to something more verbose */
 		kpass_ok = 0;
 		lpass_ok = 0;
 
-#ifdef HAVE_SETPRIORITY
-		(void) setpriority(PRIO_PROCESS, 0, -4 + PRIO_OFFSET);
-#endif
-		if (read_long_pw_string(pp2, sizeof(pp2)-1, "Password: ", 0)) {
-		    /* reading password failed... */
-#ifdef HAVE_SETPRIORITY
-		    (void) setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
-#endif
-		    goto bad_login;
+		{
+			char prompt[255];			
+			sprintf(prompt,"Password for %s: ", username);
+			pwsize = sizeof(user_pwstring);
+
+			/* reduce opportunities to be swapped out */
+			setpriority(PRIO_PROCESS, 0, -4 + PRIO_OFFSET);
+			code = krb5_read_password(kcontext, prompt, 0, 
+						  user_pwstring, &pwsize);
+			if (code || pwsize == 0) {
+				/* password unreadable, so we can relax */
+				setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
+				fprintf(stderr, "Error while reading password for '%s'\n",
+					username);
+				/* reading password failed... */
+				goto bad_login;
+			}
 		}
-		if (!pwd)		/* avoid doing useless work */
-		    goto bad_login;
 
-		/* Modifications for Kerberos authentication -- asp */
-		(void) strncpy(pp, pp2, sizeof(pp));
-		pp[8]='\0';
-		namep = crypt(pp, salt);
-		memset (pp, 0, sizeof(pp));	/* To the best of my recollection, Senator... */
+		/* now that we have the password, we've obscured things
+		   sufficiently, and can avoid trying tickets */
+		if (!pwd)
+			goto bad_login;
+
+		/* copy the first 8 chars of the password for unix crypt */
+		strncpy(user_pwcopy, user_pwstring, sizeof(user_pwcopy));
+		user_pwcopy[8]='\0';
+		namep = crypt(user_pwcopy, salt);
+		memset (user_pwcopy, 0, sizeof(user_pwcopy));
+		/* ... and wipe the copy now that we have the string */
 
+		/* verify the local password string */
 #ifdef HAVE_SHADOW
 		if (spwd)
-		    lpass_ok = !strcmp(namep, spwd->sp_pwdp);
+			lpass_ok = !strcmp(namep, spwd->sp_pwdp);
 		else
 #endif
 		    lpass_ok = !strcmp (namep, pwd->pw_passwd);
 		
 		if (pwd->pw_uid != 0) { /* Don't get tickets for root */
-
-		    if (krb_get_lrealm(realm, 1) != KSUCCESS) {
-			(void) strncpy(realm, KRB_REALM, sizeof(realm));
-		    }
+			if (krb_get_lrealm(realm, 1) != KSUCCESS) {
+				strncpy(realm, KRB_REALM, sizeof(realm));
+			}
 #ifdef BIND_HACK
-		    /* Set name server timeout to be reasonable,
-		       so that people don't take 5 minutes to
-		       log in.  Can you say abstraction violation? */
-		    _res.retrans = 1;
+			/* Set name server timeout to be reasonable,
+			   so that people don't take 5 minutes to
+			   log in.  Can you say abstraction violation? */
+			_res.retrans = 1;
 #endif /* BIND_HACK */
 
-		    krbval = krb_get_pw_in_tkt(username, "", realm, "krbtgt",
-					       realm, DEFAULT_TKT_LIFE, pp2);
-		    memset (pp2, 0, sizeof(pp2));
-#ifdef HAVE_SETPRIORITY
-		    (void) setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
-#endif
-		    switch (krbval) {
-		    case INTK_OK:
-			kpass_ok = 1;
-			krbflag = 1;
-			strcpy(tkfile, tkt_string());
-			(void) chown(tkfile, pwd->pw_uid, pwd->pw_gid);
-			break;	
-
-		    /* These errors should be silent */
-		    /* So the Kerberos database can't be probed */
-		    case KDC_NULL_KEY:
-		    case KDC_PR_UNKNOWN:
-		    case INTK_BADPW:
-		    case KDC_PR_N_UNIQUE:
-		    case -1:
-			break;
-		    /* These should be printed but are not fatal */
-		    case INTK_W_NOTALL:
-			krbflag = 1;
-			kpass_ok = 1;
-			fprintf(stderr, "Kerberos error: %s\n",
-				krb_err_txt[krbval]);
-			break;
-		    default:
-			fprintf(stderr, "Kerberos error: %s\n",
-				krb_err_txt[krbval]);
-			break;
-		    }
+			/* set up credential cache -- obeying KRB5_ENV_CCNAME 
+			   set earlier */
+			/* (KRB5_ENV_CCNAME == "KRB5CCNAME" via osconf.h) */
+			if (code = krb5_cc_default(c, &ccache)) {
+				com_err("login", code,
+					"while getting default ccache");
+				goto bad_login;
+			}
+			code = krb5_get_in_tkt_with_password(kcontext, options,
+							     0, NULL, preauth,
+							     user_pwstring,
+							     ccache,
+							     &my_creds, 0);
+
+#ifdef KRB4_GET_TICKETS
+#ifdef KRB4_USE_524
+			/* or do this directly with krb524_convert_creds_kdc */
+#else /* !KRB4_USE_524 */
+			krbval = krb_get_pw_in_tkt(username, "", realm,
+						   "krbtgt", realm, 
+						   DEFAULT_TKT_LIFE,
+						   user_pwstring);
+#endif /* !KRB4_USE_524 */
+#endif /* KRB4_GET_TICKETS */
+			memset (user_pwstring, 0, sizeof(user_pwstring));
+			/* password wiped, so we can relax */
+			setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
+			if (code) {
+				if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY)
+					fprintf (stderr,
+						 "%s: Password incorrect\n", 
+						 argv[0]);
+				else
+					com_err (argv[0], code,
+						 "while getting initial credentials");
+			} else {
+				kpass_ok = 1;
+				krbflag = 1;
+				/* get_name pulls out just the name not the
+				   type */
+				strcpy(tkfile, krb5_cc_get_name(kcontext, ccache));
+				(void) chown(tkfile, pwd->pw_uid, pwd->pw_gid);
+			}
+
+#ifdef KRB4_GET_TICKETS
+			switch (krbval) {
+			case INTK_OK:
+				kpass_ok = 1;
+				krbflag = 1;
+				strcpy(tkfile, tkt_string());
+				(void) chown(tkfile, pwd->pw_uid, pwd->pw_gid);
+				break;	
+				/* These errors should be silent */
+				/* So the Kerberos database can't be probed */
+			case KDC_NULL_KEY:
+			case KDC_PR_UNKNOWN:
+			case INTK_BADPW:
+			case KDC_PR_N_UNIQUE:
+			case -1:
+				break;
+				/* These should be printed but are not fatal */
+			case INTK_W_NOTALL:
+				krbflag = 1;
+				kpass_ok = 1;
+				fprintf(stderr, "Kerberos error: %s\n",
+					krb_get_err_text(krbval));
+				break;
+			default:
+				fprintf(stderr, "Kerberos error: %s\n",
+					krb_get_err_text(krbval));
+				break;
+			}
+#endif /* KRB4_GET_TICKETS */
 		} else {
-		    (void) memset (pp2, 0, sizeof(pp2));
-#ifdef HAVE_SETPRIORITY
-		    (void) setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
-#endif
+			memset (user_pwstring, 0, sizeof(user_pwstring));
+			setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
 		}
 
 		/* Policy: If local password is good, user is good.
@@ -682,52 +784,60 @@
 		   if (kpass_ok)
 		   */
 		if (lpass_ok)
-		    break;
-bad_login:
+			break;
+		switch (verify_krb_v5_tgt(realm)) {
+		case 1:
+			break;
+		}
+#ifdef KRB4_GET_TICKETS
+		switch (verify_krb_v4_tgt(realm)) {
+		case 1:
+			break;
+		}
+#endif /* KRB4_GET_TICKETS */
+	bad_login:
 		if (krbflag)
-		    dest_tkt();		/* clean up tickets if login fails */
-#else /* !KRB4 */
-#ifdef HAVE_SETPRIORITY
-		(void) setpriority(PRIO_PROCESS, 0, -4 + PRIO_OFFSET);
-#endif
+			dest_tkt(); /* clean up tickets if login fails */
+
+#endif /* KRB5_GET_TICKETS */
+		/* conventional password only */
+		setpriority(PRIO_PROCESS, 0, -4 + PRIO_OFFSET);
 		p = crypt(getpass("Password:"), salt);
-#ifdef HAVE_SETPRIORITY
-		(void) setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
-#endif
+		setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
 #ifdef HAVE_SHADOW
 		if (spwd && !strcmp(p, spwd->sp_pwdp))
-		    break;
+			break;
 		else
 #endif
-		    if (pwd && !strcmp(p, pwd->pw_passwd))
-			break;
-#endif /* KRB4 */
+			if (pwd && !strcmp(p, pwd->pw_passwd))
+				break;
+#endif /* !defined(KRB4_GET_TICKETS) && !defined(KRB5_GET_TICKETS) */
 
 		printf("Login incorrect\n");
 		if (++cnt >= 5) {
 			if (hostname)
 #ifdef UT_HOSTSIZE
-			    syslog(LOG_ERR,
-				"REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s",
-				tty, UT_HOSTSIZE, hostname, UT_NAMESIZE,
-				username);
-#else
-			    syslog(LOG_ERR,
-				"REPEATED LOGIN FAILURES ON %s FROM %s, %.*s",
-				tty, hostname, UT_NAMESIZE,
-				username);
+				syslog(LOG_ERR,
+				       "REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s",
+				       tty, UT_HOSTSIZE, hostname, UT_NAMESIZE,
+				       username);
+#else
+				syslog(LOG_ERR,
+				       "REPEATED LOGIN FAILURES ON %s FROM %s, %.*s",
+				       tty, hostname, UT_NAMESIZE,
+				       username);
 #endif
 			else
-			    syslog(LOG_ERR,
-				"REPEATED LOGIN FAILURES ON %s, %.*s",
-				tty, UT_NAMESIZE, username);
+				syslog(LOG_ERR,
+				       "REPEATED LOGIN FAILURES ON %s, %.*s",
+				       tty, UT_NAMESIZE, username);
 /* irix has no tichpcl */
 #ifdef TIOCHPCL
 			(void)ioctl(0, TIOCHPCL, (char *)0);
 #endif
 			sleepexit(1);
 		}
-	}
+	} /* end of password retry loop */
 
 	/* committed to login -- turn off timeout */
 	(void)alarm((u_int)0);
@@ -801,7 +911,7 @@
 	    (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
 
 	(void)chmod(ttyn, 0620);
-#ifdef KRB4
+#ifdef KRB4_GET_TICKETS
 #ifdef SETPAG
 	if (pwd->pw_uid) {
 	    /* Only reset the pag for non-root users. */
@@ -812,6 +922,7 @@
 #endif
 	/* Fork so that we can call kdestroy */
 	dofork();
+#endif /* KRB4_GET_TICKETS */
 
 /* If the user's shell does not do job control we should put it in a
    different process group than than us, and set the tty process group
@@ -947,11 +1058,16 @@
 	if (term[0] == '\0')
 		(void) strncpy(term, stypeof(tty), sizeof(term));
 	(void)setenv("TERM", term, 0);
-#ifdef KRB4
+#ifdef KRB4_GET_TICKETS
 	/* tkfile[0] is only set if we got tickets above */
 	if (tkfile[0])
 	    (void) setenv(KRB_ENVIRON, tkfile, 1);
-#endif /* KRB4 */
+#endif /* KRB4_GET_TICKETS */
+#ifdef KRB5_GET_TICKETS
+	/* ccfile[0] is only set if we got tickets above */
+	if (ccfile[0])
+	    (void) setenv(KRB5_ENV_CCNAME, ccfile, 1);
+#endif /* KRB5_GET_TICKETS */
 
 #if 0
 	strcpy(wgfile, "/tmp/wg.XXXXXX");
@@ -963,7 +1079,7 @@
 		syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
 	if (pwd->pw_uid == 0)
 		if (hostname)
-#ifdef KRB4
+#ifdef KRB4_KLOGIN
 			if (kdata) {
 			    /* @*$&@#*($)#@$ syslog doesn't handle very
 			       many arguments */
@@ -983,7 +1099,7 @@
 #endif
 			    syslog(LOG_NOTICE, "%s", buf);
 		        } else {
-#endif /* KRB4 */
+#endif /* KRB4_KLOGIN */
 #ifdef UT_HOSTSIZE
 			syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s",
 			    tty, UT_HOSTSIZE, hostname);
@@ -991,7 +1107,7 @@
 			syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %s",
 			    tty, hostname);
 #endif
-#ifdef KRB4
+#ifdef KRB4_KLOGIN
 			}
   		else 
 			if (kdata) {
@@ -1001,17 +1117,17 @@
 				   kdata->pname, kdata->pinst,
 				   kdata->prealm);
 			} 
-#endif /* KRB4 */
+#endif /* KRB4_KLOGIN */
 		else
 			syslog(LOG_NOTICE, "ROOT LOGIN %s", tty);
 
 	if (!quietlog) {
 		struct stat st;
 
-#ifdef KRB4
+#ifdef KRB4_KLOGIN
 		if (!krbflag && !fflag && !Fflag && !eflag )
 		    printf("\nWarning: No Kerberos tickets obtained.\n\n");
-#endif /* KRB4 */
+#endif /* KRB4_KLOGIN */
 #ifndef NO_MOTD
 		motd();
 #endif
@@ -1230,7 +1346,7 @@
 	return(ruserok(host, (pwd->pw_uid == 0), rusername, username));
 }
 
-#ifdef KRB4
+#ifdef KRB4_KLOGIN
 int do_krb_login(host, strict)
 	char *host;
 	int strict;
@@ -1276,7 +1392,7 @@
 			    instance, &sin,
 			    (struct sockaddr_in *)0,
 			    kdata, "", (bit_64 *) 0, version))) {
-		printf("Kerberos rlogin failed: %s\r\n",krb_err_txt[rc]);
+		printf("Kerberos rlogin failed: %s\r\n",krb_get_err_text(rc));
 		if (strict) {
 paranoid:
 			/*
@@ -1322,7 +1438,7 @@
 	}
 	return(0);
 }
-#endif /* KRB4 */
+#endif /* KRB4_KLOGIN */
 
 void lgetstr(buf, cnt, err)
 	char *buf, *err;
@@ -1408,15 +1524,15 @@
 void sleepexit(eval)
 	int eval;
 {
-#ifdef KRB4
+#ifdef KRB4_GET_TICKETS
 	if (krbflag)
 	    (void) dest_tkt();
-#endif /* KRB4 */
+#endif /* KRB4_GET_TICKETS */
 	sleep((u_int)5);
 	exit(eval);
 }
 
-#ifdef KRB4
+#ifdef KRB4_GET_TICKETS
 /*
  * This routine handles cleanup stuff, and the like.
  * It exits only in the child process.
@@ -1477,7 +1593,7 @@
     /* Leave */
     exit(0);
 }
-#endif /* KRB4 */
+#endif /* KRB4_GET_TICKETS */
 
 
 #ifndef HAVE_STRSAVE
@@ -1530,3 +1646,180 @@
     enduserdb();
 }
 #endif
+
+#ifdef KRB4_GET_TICKETS
+/*
+ * Verify the Kerberos ticket-granting ticket just retrieved for the
+ * user.  If the Kerberos server doesn't respond, assume the user is
+ * trying to fake us out (since we DID just get a TGT from what is
+ * supposedly our KDC).  If the rcmd.<host> service is unknown (i.e.,
+ * the local srvtab doesn't have it), let her in.
+ *
+ * Returns 1 for confirmation, -1 for failure, 0 for uncertainty.
+ */
+int verify_krb_v4_tgt (realm)
+    char *realm;
+{
+    char hostname[MAXHOSTNAMELEN], phost[BUFSIZ];
+    struct hostent *hp;
+    KTEXT_ST ticket;
+    AUTH_DAT authdata;
+    unsigned long addr;
+    static /*const*/ char rcmd[] = "rcmd";
+    char key[8];
+    int krbval, retval, have_keys;
+
+    if (gethostname(hostname, sizeof(hostname)) == -1) {
+	perror ("cannot retrieve local hostname");
+	return -1;
+    }
+    strncpy (phost, krb_get_phost (hostname), sizeof (phost));
+    phost[sizeof(phost)-1] = 0;
+    hp = gethostbyname (hostname);
+    if (!hp) {
+	perror ("cannot retrieve local host address");
+	return -1;
+    }
+    memcpy ((char *) &addr, (char *)hp->h_addr, sizeof (addr));
+    /* Do we have rcmd.<host> keys? */
+    have_keys = read_service_key (rcmd, phost, realm, 0, KEYFILE, key)
+	? 0 : 1;
+    krbval = krb_mk_req (&ticket, rcmd, phost, realm, 0);
+    if (krbval == KDC_PR_UNKNOWN) {
+	/*
+	 * Our rcmd.<host> principal isn't known -- just assume valid
+	 * for now?  This is one case that the user _could_ fake out.
+	 */
+	if (have_keys)
+	    return -1;
+	else
+	    return 0;
+    }
+    else if (krbval != KSUCCESS) {
+	printf ("Unable to verify Kerberos TGT: %s\n", 
+		krb_get_err_text(krbval));
+#ifndef SYSLOG42
+	syslog (LOG_NOTICE|LOG_AUTH, "Kerberos TGT bad: %s",
+		krb_get_err_text(krbval));
+#endif
+	return -1;
+    }
+    /* got ticket, try to use it */
+    krbval = krb_rd_req (&ticket, rcmd, phost, addr, &authdata, "");
+    if (krbval != KSUCCESS) {
+	if (krbval == RD_AP_UNDEC && !have_keys)
+	    retval = 0;
+	else {
+	    retval = -1;
+	    printf ("Unable to verify `rcmd' ticket: %s\n",
+		    krb_get_err_text(krbval));
+	}
+#ifndef SYSLOG42
+	syslog (LOG_NOTICE|LOG_AUTH, "can't verify rcmd ticket: %s;%s\n",
+		krb_get_err_text(krbval),
+		retval
+		? "srvtab found, assuming failure"
+		: "no srvtab found, assuming success");
+#endif
+	goto EGRESS;
+    }
+    /*
+     * The rcmd.<host> ticket has been received _and_ verified.
+     */
+    retval = 1;
+    /* do cleanup and return */
+EGRESS:
+    memset (&ticket, 0, sizeof (ticket));
+    memset (&authdata, 0, sizeof (authdata));
+    return retval;
+}
+#endif /* KRB4_GET_TICKETS */
+
+#ifdef /* KRB5_GET_TICKETS */
+int verify_krb_v5_tgt (c, realm)
+    krb5_context c;
+    char *realm;
+{
+    char hostname[MAXHOSTNAMELEN], phost[BUFSIZ];
+    struct hostent *hp;
+    krb5_ccache ccdef;
+    AUTH_DAT authdata;
+    unsigned long addr;
+    int retval, have_keys;
+    krb5_principal princ;
+    krb5_keyblock *kb;
+    krb5_error_code krbval;
+    krb5_data packet;
+    krb5_auth_context auth_context = NULL;
+
+    /* get the server principal for the local host */
+    /* (use defaults of "host" and canonicalized local name) */
+    krbval = krb5_sname_to_principal(c, 0, 0, KRB5_NT_SRV_HST, &princ);
+    if (krbval) {
+	    com_err ("login", krbval, "constructing local service name");
+	    return -1;
+    }
+
+    /* Do we have host/<host> keys? */
+    /* (use default keytab, kvno IGNORE_VNO to get the first match,
+       and keytype is currently ignored anyhow.) */
+    krbval = krb5_kt_read_service_key (c, NULL, princ, 0, KEYTYPE_DES, &kb);
+    /* any failure means we don't have keys at all. */
+    have_keys = krbval ? 0 : 1;
+
+    /* set up credential cache -- obeying KRB5_ENV_CCNAME set earlier */
+    /* (KRB5_ENV_CCNAME == "KRB5CCNAME" via osconf.h) */
+    if (krbval = krb5_cc_default(c, &ccdef)) {
+	com_err("login", krbval, "while getting default ccache");
+	exit(1);
+    }
+    /* */
+    krbval = krb5_mk_req(c, &auth_context, 0, "host", phost,
+			 0, ccdef, &packet);
+    if (krbval == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) {
+	    /* we have a service key, so something should be 
+	       in the database, therefore this error packet could
+	       have come from an attacker. */
+	    if (have_keys) return -1;
+	    /* but if it is unknown and we've got no key, we don't
+	       have any security anyhow, so it is ok. */
+	    else return 0;
+    }
+    else if (krbval) {
+	    com_err("login", krbval, "Unable to verify Kerberos V5 TGT");
+#ifndef SYSLOG42
+	    syslog (LOG_NOTICE|LOG_AUTH, "Kerberos TGT bad: %d", krbval);
+#endif
+	    return -1;
+    }
+    /* got ticket, try to use it */
+    krbval = krb5_rd_req(c, &auth_context, &packet, 
+			 princ, NULL, NULL, &ticket);
+    if (krbval) {
+	if (krbval == RD_AP_UNDEC && !have_keys)
+	    retval = 0;
+	else {
+	    retval = -1;
+	    printf ("Unable to verify `rcmd' ticket: %s\n",
+		    krb_get_err_text(krbval));
+	}
+#ifndef SYSLOG42
+	syslog (LOG_NOTICE|LOG_AUTH, "can't verify rcmd ticket: %s;%s\n",
+		krb_get_err_text(krbval),
+		retval
+		? "srvtab found, assuming failure"
+		: "no srvtab found, assuming success");
+#endif
+	goto EGRESS;
+    }
+    /*
+     * The host/<host> ticket has been received _and_ verified.
+     */
+    retval = 1;
+    /* do cleanup and return */
+EGRESS:
+    memset (&ticket, 0, sizeof (ticket));
+    memset (&authdata, 0, sizeof (authdata));
+    return retval;
+}
+#endif /* KRB5_GET_TICKETS */
