From prms-admin@cygnus.com  Tue Jun 27 16:11:27 1995
Received: from inet-smtp-gw-1.us.oracle.com (inet-smtp-gw-1.us.oracle.com [192.86.155.81]) by cygnus.com (8.6.12/8.6.9) with ESMTP id QAA24730 for <bugs@cygnus.com>; Tue, 27 Jun 1995 16:11:25 -0700
Received: from teal.us.oracle.com by inet-smtp-gw-1.us.oracle.com with ESMTP (8.6.12/37.7)
	id QAA03436; Tue, 27 Jun 1995 16:11:23 -0700
Received: from localhost by teal.us.oracle.com with SMTP (8.6.9/37.8)
	id QAA00445; Tue, 27 Jun 1995 16:11:00 -0700
Message-Id: <199506272311.QAA00445@teal.us.oracle.com>
Date: Tue, 27 Jun 1995 16:11:00 -0700
From: Dave Morrison <dmorriso@us.oracle.com>
To: bugs@cygnus.com
Cc: jhanley@us.oracle.com
Subject: Kerberos v4 jumbo patches for additional SNK functionality

>Number:         7327
>Category:       kerberos
>Synopsis:       Kerberos v4 jumbo patches for additional SNK functionality
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    eichin
>State:          analyzed
>Class:          change-request
>Customer-Id:    oracle
>Arrival-Date:   Tue Jun 27 16:20:01 1995
>Last-Modified:
>Originator:     Dave Morrison (415 506 2914)
>Organization:
 dmorriso@us.oracle.com
 Internet Services, HQ Data Center, Oracle Corporation
>Release:        cns-95q1
>Environment:
all, but in particular, SunOS 4.1.X and Alpha OSF 3.X

System: SunOS 4.1.X
Architecture: Alpha

>Description:
	Some major functionality was missing from cns-95q1 release which
	prevented us from doing wide integration and deployment of SNKs
	using a Kerberos backend.
>How-To-Repeat:
	Try to deploy a large (> 150 people) data center using cns-95q1
	and SNKs.  Note problems which come up. :)
>Fix:
	The following patches are used interally at Oracle, and have now
	passed their alpha test phase.

Hi, Mark!

Features added/changed:

telnetd:
	Added -E flag which sets the environment variables REMOTEHOST_IP
and REMOTEHOST_NAME to be the values of the incoming socket's IP address
and if succesfully obtained, claimed name.  If Kerberos v4
authentication is used, it also sets the environment variable AUTHNAME
to be the prinicpal of the authorizing user if that authentication is
used for login.
	These allow more robust and accurate logging.  Should have no
security impact.  A potential con is that it contributes to "environment
variable polution" which is why it is off by default.

telnet:
	Added -h flag which allows tickets (with krb4, rmcd.authost) to
be obtained for a host other than than the telnet desination.
	This is useful for when the destination is an IP address, and
cases when the authentication is done through a proxy, where the
destiation is not the host to which you desire authentication.
	Should have no security impact.

telnetd:
	Added -z and -Z flags which are passed to login, if used.  This
is to enable SNK based login.
	Should have no security impact.

libkrb:
	Alpha 3.X porting fixes.  See Kerberos/7298.
	Should have no security impact.

libkrb/kinit:
	kinit code used to get/decode a SNK method TGT moved to libkrb.
This allows other areas to use the code (login, ksu, etc.).
	Should have no security impact.

Single challenge SNK authorization changes:
	Ok, here's a biggie - but first, a short :) philosophy discussion....
	Currently, I'm working in an environment where I've got security
holes you could ship an aircraft carrier through.  For a significant,
but buy-off-able cost, I can reduce them to holes you can drive a truck
through.  The fixes to reduce them to the size you can slip a needle
through are too high to do.
	SNKs have several deficiencies, pehaps some of them even design.
Perhaps the most basic, is that they are not generally used as true "one
time passwords".  To avoid predictability in the challenge, which is
usually a good thing, challenges are random.  But this makes the
passwords no longer one-time as there is a chance it will be used again,
and futher you must worry about manipulations to make challenges
non-random.  So, you can wind up believing you have one time passwords,
but in order to reduce the holes to the size you can slip a needle
through, you need to to solve all the old problems you had to solve with
regular passwords with a few new problems added (like a ridiculously low
response space).  Ugh.
	Some work in OTP (one time passworsd) for krb v5 looks somewhat
promising, but that's not here now in a nice product I can neatly
implement in the near term time frame without buying off a major support
cost and issues relating to systems which don't implement v5.  The
givens I'm working with are that I use SNKs as the OTP mechanism, have a
single challenge method (users are ready to riot over just having SNKs,
adding a double challenge would seiously jepardize their deployment at
all).  The current software is a straight "auth" type protocol, "->I'm
foo" "<-chal xyz" "->resp abc" "<-[yes|no]" (puke).
	I recognize two major problems with single challenge methods,
well identified and handled by Cygus in their original design.  Both
stem from the fact, that by iteration alone, it is possible to break an
SNK response used as the sole seed for an encryption.  The actual time
required to do so depends on the time required to determine if a
decryption is successful, but estimates are that an hour is not
unreasonable to break open a TGT encrypted with a seed off a single
response (~26 or 32 bits).  The first is that a broken TGT lets the
breaker run around and attack the universe for the rest of the ticket
life, generally 9 (10 (start life) - 1 (time to break)) hours.  The
second is that a broken ticket gives the attacker the response for a
challenge, a problem owing to the non-true one time nature of the SNK
mentioned above.
	The solution I have for single challenges definitely addresses
the first problem, but does not fully address the second.
	On the server end, the same challenege method is the same,
however if the ticket lifetime requested is zero, a single challenge
will be issued.  This allows clients to authenticate for a service, such
as rcmd.foo for su/login, or some other service, and use a single
challenge.  There is no ticket life as the ticket is only good for
verification by the service which requested the ticket, so the first
issue (stolen/broken tickets) is moot.  The second issue, regarding
stolen challenge/response pairs is not addressed, but that issue is
still around if someone wants to use an SNK over sniffed channels in any
case.
	However, it does open up a hole which you can drive a truck
through, the issue of offline attacks.  An attacker can now request many
zero lifetime SNK TGT, and break them one by one.  The attacker saves a
copy of the results of each, and procedes to build a challenge/response
library.  In perhaps a month, given the 1 hour/break assumption, an
attacker will have 800 (round to 1000) or so pairs, if done serially.
An attacker will most likely attack offline using parallel methods, so
having > 10% of the pairs within a month does not seem unreasonable.
This rides a bit far beyond the edge of what is safe.
	Here are some possible solutions:
 1	Add state with each SNK Kerberos entry, so that challenges are
not reused (store two large co-primes p1<p2 < challenge max, and a base,
challenge is p1**(base + i++) mod p2).  After i > p2, the SNK must be
returned for re-seeding.  This returns the SNK to the true "one time"
state.  This has other issues.  Among them, there's now denial of
service attacks ("use up" someone elses SNK).  An attacker may be able
to determine future challenges but successfully determining base, p1 and
p2.  This might not be a problem, but more thinking is required before
I'd be will to say that I'm sure of that.  It denies the client the
ability to participate in determining the challenge (leaving open the
current attack where Kerberos can be spoofed if the attacker knows a
single challenge/response pair, because Kerberos solely determines the
challenge).
 2	Setup encryptions before authentication in a method similar to
how SMB described in the 5th Usenix UNIX security procedings.  This
leaves open the issue of challenge-response pairs being valuable but
solves both the ticket breaking and offline attack problems.  It opens
the issue of fundamentally modifying the Kerberos protocol.  Just go to
v5?  heh.
 3	Ditch SNKs and design a better OTP scheme (and I don't mean
SecurID or S/KEY).  Ooops, that violates the given.  Blech.

	QED... Now I've successfully proven life sucks.  I'm not
thrilled with the issues this presents, but they are better than issues
with I'm stuck with now.  There is a stopgap method of thwarting the
offline attacks in that if the logs show an abnormally high number of
requests for any SNK based principle via zero lifetime ticket, someone's
knocking on your door.  I've live with that one (annoying, true), given
that I now solve most of the remaining problems preventing me from
eliminating that very ugly "auth" protocol.

	The mods are:

libkrb:
	Added v_pw_in_tkt.c (zero lifetime verify).
	Modularity mods in rd_req.c to allow verify a ticket without
complaining that the lifetime is zero.
Kerberos.c:
	If requested ticket lifetime is zero, only use one challenge.
This should probably #ifdef'ed better, and warning logging about too
many requests of these kinds of tickets done.

login.krb:
	Added -z and -Z flags.  The perform login using a local srvtab
verified TGT ticket obtained via the normal double challenge (-Z) or
single krb approved challenge (-z).

ksu.c:
	Added -s flag.  If -s is specified, use single krb verified
challenge method.  Allows people to su to root over insecure channels
(which would otherwise compromise your root instance password.)
Instance 'root+SNK4' tickets are required, and that principal must be
authorized in /.klogin for the su to succeed.  No TG tickets are
actually obtained.

Without further chattering, here's the patch, it's against cns-95q1:

----------------------------------------------------------------------
diff -cr cns-95q1.dist/usr/kerberos/src/src/appl/bsd/login.c cns-95q1.test/usr/kerberos/src/src/appl/bsd/login.c
*** cns-95q1.dist/usr/kerberos/src/src/appl/bsd/login.c	Mon Feb 13 08:46:14 1995
--- cns-95q1.test/usr/kerberos/src/src/appl/bsd/login.c	Mon Jun 26 01:28:40 1995
***************
*** 41,46 ****
--- 41,48 ----
   * login -K hostname (for Kerberos rlogind with restricted access)
   *   either -k or -K may be preceded by -s srvtab to set the name of
   *   the srvtab to use; the default is KEYFILE, normally /etc/krb-srvtab
+  * login -z             (for SNK challange)
+  * login -Z             (for SNK double challange which gets tickets)
   * endif KERBEROS */
  
  #include "conf.h"
***************
*** 244,249 ****
--- 246,260 ----
  time_t time();
  #endif /* KERBEROS */
  
+ #ifdef KERBEROS
+ int snk_login();
+ int snk_login_err();
+ #define KRB_SNK_OK 0
+ #define KRB_SNK_BAD 1
+ #define KRB_SNK_FATAL 2
+ #endif /* KERBEROS */
+ 
+ 
  #define EXCL_TEST if (rflag || kflag || Kflag || eflag || hflag) { \
  				fprintf(stderr, \
  				    "login: only one of -r, -k, -K, -e and -h allowed.\n"); \
***************
*** 262,268 ****
  	register int ch, i;
  	register char *p;
  	int fflag, hflag, pflag, rflag, cnt;
! 	int kflag, Kflag, eflag;
  	int quietlog, passwd_req, ioctlval;
  	sigtype timedout();
  	char *domain, *salt, **envinit, *ttyn, *tty, *ktty, *tz;
--- 273,279 ----
  	register int ch, i;
  	register char *p;
  	int fflag, hflag, pflag, rflag, cnt;
! 	int kflag, Kflag, eflag, snkflag;
  	int quietlog, passwd_req, ioctlval;
  	sigtype timedout();
  	char *domain, *salt, **envinit, *ttyn, *tty, *ktty, *tz;
***************
*** 298,310 ****
  	 *   either -k or -K may be preceded by -s srvtab to set the
  	 *   name of the srvtab to use; the default is KEYFILE,
  	 *   normally /etc/krb-srvtab
  	 */
  	(void)gethostname(tbuf, sizeof(tbuf));
  	domain = strchr(tbuf, '.');
  
! 	fflag = hflag = pflag = rflag = kflag = Kflag = eflag = 0;
  	passwd_req = 1;
! 	while ((ch = getopt(argc, argv, "fe:h:pr:k:K:s:")) != EOF)
  		switch (ch) {
  		case 'f':
  			/* Do not disallow -f and other options (-h)! */
--- 309,322 ----
  	 *   either -k or -K may be preceded by -s srvtab to set the
  	 *   name of the srvtab to use; the default is KEYFILE,
  	 *   normally /etc/krb-srvtab
+ 	 * -z is used to require SNK validated tickets for login
  	 */
  	(void)gethostname(tbuf, sizeof(tbuf));
  	domain = strchr(tbuf, '.');
  
! 	fflag = hflag = pflag = rflag = kflag = Kflag = eflag = snkflag = 0;
  	passwd_req = 1;
! 	while ((ch = getopt(argc, argv, "fe:h:pr:k:K:s:zZ")) != EOF)
  		switch (ch) {
  		case 'f':
  			/* Do not disallow -f and other options (-h)! */
***************
*** 394,399 ****
--- 406,417 ----
  		case 's':
  			srvtab = optarg;
  			break;
+ 		case 'z':
+ 			snkflag = 1;
+ 			break;
+ 		case 'Z':
+ 			snkflag = 2;
+ 			break;
  #endif /* KERBEROS */
  		case '?':
  		default:
***************
*** 570,575 ****
--- 588,594 ----
  #ifndef NO_SETPRIORITY
  		(void) setpriority(PRIO_PROCESS, 0, -4 + PRIO_OFFSET);
  #endif
+            if (! snkflag) {
  		if (read_long_pw_string(pp2, sizeof(pp2)-1, "Password: ", 0)) {
  		    /* reading password failed... */
  #ifndef NO_SETPRIORITY
***************
*** 580,686 ****
  		if (!pwd)		/* avoid doing useless work */
  		    goto bad_login;
  
  #ifdef __SCO__
  		cnt = 7;
  		goto sco_lose;
  #else
  		/* Modifications for Kerberos authentication -- asp */
  		(void) strncpy(pp, pp2, sizeof(pp));
  		pp[8]='\0';
  		namep = crypt(pp, pwd->pw_passwd);
  		memset (pp, 0, sizeof(pp));	/* To the best of my recollection, Senator... */
  		lpass_ok = !strcmp (namep, pwd->pw_passwd);
  		
! 		/* This code used to get Kerberos tickets using the
! 		   login password.  However, this is no longer useful,
! 		   because when invoked by rlogin this code won't be
! 		   asking for a password anyhow.  Also, using the same
! 		   password for both Kerberos and Unix is risky when
! 		   non-authenticated logins are permitted to some
! 		   systems.  */
! #if 0
! 		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));
! 		    }
! #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;
! #endif
! 		    /* Set up the ticket file environment variable */
! 		    strncpy(tkfile, KRB_TK_DIR, sizeof(tkfile));
! 		    strncat(tkfile, ktty,
! 			    sizeof(tkfile) - strlen(tkfile) - 1);
! 		    (void) setenv(KRB_ENVIRON, tkfile, 1);
! 		    krb_set_tkt_string(tkfile);
! 		    if (setreuid(pwd->pw_uid, -1) < 0) {
! 			/* can't set ruid to user! */
! 			krbval = -1;
! 			fprintf(stderr,
! 				"login: Can't set ruid for ticket file.\n");
! 		    } else
! 		    krbval = krb_get_pw_in_tkt(username, "",
! 					       realm, "krbtgt",
! 					       realm,
! 					       DEFAULT_TKT_LIFE, pp2);
! 		    memset (pp2, 0, sizeof(pp2));
! #ifndef NO_SETPRIORITY
! 		    (void) setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
! #endif
! 		    switch (krbval) {
! 		    case INTK_OK:
! 			kpass_ok = 1;
! 			krbflag = 1;
! 			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;
! 		    }
! 		} else {
! 		    (void) memset (pp2, 0, sizeof(pp2));
! #ifndef NO_SETPRIORITY
! 		    (void) setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
! #endif
! 		}
! #endif /* 0 */
  
- 		(void) memset (pp2, 0, sizeof(pp2));
  #ifndef NO_SETPRIORITY
! 		(void) setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
  #endif
  
! #endif
  
! 		/* Policy: If local password is good, user is good.
! 		   We really can't trust the Kerberos password,
! 		   because somebody on the net could spoof the
! 		   Kerberos server (not easy, but possible).
! 		   Some sites might want to use it anyways, in
! 		   which case they should change this line
! 		   to:
! 		   if (kpass_ok)
  		   */
! 		if (lpass_ok)
  		    break;
  bad_login:
  		if (krbflag)
--- 599,654 ----
  		if (!pwd)		/* avoid doing useless work */
  		    goto bad_login;
  
+              }                
+ 
  #ifdef __SCO__
  		cnt = 7;
  		goto sco_lose;
  #else
  		/* Modifications for Kerberos authentication -- asp */
+            if (! snkflag) {
  		(void) strncpy(pp, pp2, sizeof(pp));
  		pp[8]='\0';
  		namep = crypt(pp, pwd->pw_passwd);
  		memset (pp, 0, sizeof(pp));	/* To the best of my recollection, Senator... */
  		lpass_ok = !strcmp (namep, pwd->pw_passwd);
+              }
  		
! #ifdef KERBEROS
! 		/* Finally, a good kerberos login. */
!                 if (snkflag && (pwd->pw_uid != 0)) {
!                    /* won't work for root */
!                       
!                    switch (snk_login(snkflag, username, ktty)) {
!                    case KRB_SNK_OK:
!                       krbflag = 1;
!                       kpass_ok = 1;
!                       break;
!                    case KRB_SNK_BAD:
!                       goto bad_login;
!                       /* NOTREACHED */
!                       break;
!                    case KRB_SNK_FATAL:
!                       sleepexit(1);
!                       /* NOTREACHED */
!                       break;
!                    }
!                 }
! #endif /* KERBEROS */
  
  #ifndef NO_SETPRIORITY
!                 (void) setpriority(PRIO_PROCESS, 0, 0 + PRIO_OFFSET);
  #endif
  
! #endif /* __SCO__ */
  
! 		/* Policy:
!                    If local password is good, user is good.
!                    If kerberos password is good, and it's done with the SNK
!                    code, user is good (as the password has been verified
!                    against the srvtab).
  		   */
! 		if (lpass_ok || (snkflag && kpass_ok))
  		    break;
  bad_login:
  		if (krbflag)
***************
*** 1511,1513 ****
--- 1479,1639 ----
  }
  
  #endif /* RIOS */
+ 
+ 
+ #ifdef KERBEROS
+ 
+ /* some silly OS's don't declare sys_errlist in errno.h */
+ extern char *sys_errlist[];
+ 
+ /* 
+    return codes:
+ 
+    0 - all cool, procede to login, user is authed
+    1 - login failed, temporary login error, e.g. bad password
+    2 - login failed, fatal login error, e.g. no srvtab
+ 
+    self logging
+  */
+ 
+ int
+ snk_login(method, pname, ktty)
+ int method;  /* 1 => no ticket obtained, 2 => ticket obtained */
+ char *pname; /* principal name */
+ char *ktty;
+ {
+    KTEXT_ST ticket;
+    AUTH_DAT authdata;
+    char lhostname[MAXHOSTNAMELEN], savehost[MAXHOSTNAMELEN];
+    unsigned KRB_INT32 faddr;
+    struct hostent *hp;
+    char realm[REALM_SZ+1];
+    int kerrno;
+    
+    /* Get hostname for snk validation */
+    if (gethostname(lhostname, sizeof(lhostname)) == -1) {
+       fprintf(stderr, "Failure getting local hostname: %s\n",
+               sys_errlist[errno]);
+       syslog(LOG_ERR|LOG_AUTH, "gethostname() failure: %s",
+              sys_errlist[errno]);
+       return(KRB_SNK_FATAL);
+    }
+ 
+    (void) strncpy(savehost, krb_get_phost(lhostname),
+                   sizeof(savehost));
+    savehost[sizeof(savehost)-1] = 0;
+ 
+    if (krb_get_lrealm(realm, 1) != KSUCCESS) {
+       (void) strncpy(realm, KRB_REALM, sizeof(realm));
+    }
+ 
+    if (method == 1)
+    {
+       /* Nice, one stop shopping version. */
+       kerrno = krb_snk_vfy_pw_in_tkt(username, "+SNK4",
+                                      realm, "rcmd", savehost);
+                       
+       return(snk_login_err(kerrno, username, savehost));
+ 
+    } else if (method == 2) {
+       /* Painful, do it yourself version (but it gets TG tickets).
+          Maybe this functionality should be in a library routine (duh!). */
+ 
+       strncpy(tkfile, KRB_TK_DIR, sizeof(tkfile));
+       strncat(tkfile, ktty,
+               sizeof(tkfile) - strlen(tkfile) - 1);
+       (void) setenv(KRB_ENVIRON, tkfile, 1);
+       krb_set_tkt_string(tkfile);
+       if (setreuid(pwd->pw_uid, -1) < 0) {
+          /* can't set ruid to user! */
+          fprintf(stderr,
+                  "login: Can't set ruid for ticket file.\n");
+          syslog(LOG_ERR|LOG_AUTH, "setreuid() failure: %s",
+                 sys_errlist[errno]);
+          return(KRB_SNK_FATAL);
+       }
+       
+       kerrno = krb_snk_get_pw_in_tkt(username, "+SNK4",
+                                      realm, "krbtgt",
+                                      realm, DEFAULT_TKT_LIFE);
+ 
+       if (kerrno = snk_login_err(kerrno, username, savehost))
+          return(kerrno);
+ 
+       kerrno = krb_mk_req(&ticket, "rcmd", savehost, realm, 33);
+       if (kerrno != KSUCCESS) {
+          fprintf(stderr, "Unable to use tgt: %s\n",
+                  krb_get_err_text (kerrno));
+          syslog(LOG_ERR|LOG_AUTH,
+                 "failed login obtaining %s.%s ticket for %s: %s",
+                 "rcmd", savehost, username, krb_get_err_text (kerrno));
+          dest_tkt();
+          return(KRB_SNK_FATAL);
+       }
+ 
+       if (!(hp = gethostbyname(lhostname))) {
+          fprintf(stderr, "Unable to get address of %s\n",
+                  lhostname);
+          syslog(LOG_ERR|LOG_AUTH,
+                 "failed login obtaining IP address for %s",
+                 lhostname);
+          dest_tkt();
+          return(KRB_SNK_FATAL);
+       }
+ 
+       memcpy((char *) &faddr, (char *)hp->h_addr, sizeof(faddr));
+       if ((kerrno = krb_rd_req(&ticket, "rcmd", savehost,
+                                faddr, &authdata, "")) != KSUCCESS) {
+          fprintf(stderr, "Unable to verify rcmd ticket: %s\n",
+                  krb_get_err_text (kerrno));
+          syslog(LOG_ERR|LOG_AUTH,
+                 "failed login verifying rcmd ticket between %s and %s.%s: %s",
+                 username, "rcmd", savehost, krb_get_err_text (kerrno));
+          dest_tkt();
+          return(KRB_SNK_FATAL);
+       }		
+ 
+       return(KRB_SNK_OK);
+ 
+    } else {
+       syslog(LOG_ERR|LOG_AUTH,
+              "login: Unknown SNK login method: %s",
+              method);
+       return(KRB_SNK_FATAL);
+    }
+ }
+ 
+ int
+ snk_login_err(kerrno, username)
+ int kerrno;
+ char *username;
+ {
+       switch (kerrno) {
+       case INTK_OK:
+          return(KRB_SNK_OK);
+          /* NOTREACHED */
+          break;
+       case KDC_NULL_KEY:
+       case KDC_PR_UNKNOWN:
+       case INTK_BADPW:
+       case KDC_PR_N_UNIQUE:
+       case -1:
+          fprintf(stderr, "bad login\n");
+          syslog(LOG_INFO|LOG_AUTH,
+                 "failed login attempt for %s: %s",
+                 username, krb_get_err_text (kerrno));
+          return(KRB_SNK_BAD);
+          /* NOTREACHED */
+          break;
+       default:
+          fprintf(stderr, "Kerberos error: %s\n",
+                  krb_get_err_text (kerrno));
+          syslog(LOG_ERR|LOG_AUTH,
+                 "failed login %s: %s",
+                 username, krb_get_err_text (kerrno));
+          return(KRB_SNK_FATAL);
+          /* NOTREACHED */
+          break;
+       }
+ }
+ #endif
diff -cr cns-95q1.dist/usr/kerberos/src/src/appl/telnet/libtelnet/auth-proto.h cns-95q1.test/usr/kerberos/src/src/appl/telnet/libtelnet/auth-proto.h
*** cns-95q1.dist/usr/kerberos/src/src/appl/telnet/libtelnet/auth-proto.h	Mon Feb 13 08:51:17 1995
--- cns-95q1.test/usr/kerberos/src/src/appl/telnet/libtelnet/auth-proto.h	Sun Jun 25 21:53:12 1995
***************
*** 75,80 ****
--- 75,81 ----
  int auth_wait P((char *));
  void auth_disable_name P((char *));
  void auth_gen_printsub P((unsigned char *, int, unsigned char *, int));
+ int auth_printname P((unsigned char *, unsigned char *, int));
  
  #ifdef	KRB4
  int kerberos4_init P((Authenticator *, int));
***************
*** 83,88 ****
--- 84,90 ----
  void kerberos4_reply P((Authenticator *, unsigned char *, int));
  int kerberos4_status P((Authenticator *, char *, int));
  void kerberos4_printsub P((unsigned char *, int, unsigned char *, int));
+ int kerberos4_printname P((unsigned char *, int));
  #endif
  
  #ifdef	KRB5
diff -cr cns-95q1.dist/usr/kerberos/src/src/appl/telnet/libtelnet/auth.c cns-95q1.test/usr/kerberos/src/src/appl/telnet/libtelnet/auth.c
*** cns-95q1.dist/usr/kerberos/src/src/appl/telnet/libtelnet/auth.c	Mon Feb 13 08:51:20 1995
--- cns-95q1.test/usr/kerberos/src/src/appl/telnet/libtelnet/auth.c	Sun Jun 25 21:53:13 1995
***************
*** 116,129 ****
  				spx_is,
  				spx_reply,
  				spx_status,
! 				spx_printsub },
  	{ AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
  				spx_init,
  				spx_send,
  				spx_is,
  				spx_reply,
  				spx_status,
! 				spx_printsub },
  #endif
  #ifdef	KRB5
  # ifdef	ENCRYPTION
--- 116,131 ----
  				spx_is,
  				spx_reply,
  				spx_status,
! 				spx_printsub,
! 				0 },
  	{ AUTHTYPE_SPX, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
  				spx_init,
  				spx_send,
  				spx_is,
  				spx_reply,
  				spx_status,
! 				spx_printsub,
! 				0 },
  #endif
  #ifdef	KRB5
  # ifdef	ENCRYPTION
***************
*** 133,139 ****
  				kerberos5_is,
  				kerberos5_reply,
  				kerberos5_status,
! 				kerberos5_printsub },
  # endif	/* ENCRYPTION */
  	{ AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
  				kerberos5_init,
--- 135,142 ----
  				kerberos5_is,
  				kerberos5_reply,
  				kerberos5_status,
! 				kerberos5_printsub,
! 				0 },
  # endif	/* ENCRYPTION */
  	{ AUTHTYPE_KERBEROS_V5, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
  				kerberos5_init,
***************
*** 141,147 ****
  				kerberos5_is,
  				kerberos5_reply,
  				kerberos5_status,
! 				kerberos5_printsub },
  #endif
  #ifdef	KRB4
  # ifdef ENCRYPTION
--- 144,151 ----
  				kerberos5_is,
  				kerberos5_reply,
  				kerberos5_status,
! 				kerberos5_printsub,
! 				0 },
  #endif
  #ifdef	KRB4
  # ifdef ENCRYPTION
***************
*** 151,157 ****
  				kerberos4_is,
  				kerberos4_reply,
  				kerberos4_status,
! 				kerberos4_printsub },
  # endif	/* ENCRYPTION */
  	{ AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
  				kerberos4_init,
--- 155,162 ----
  				kerberos4_is,
  				kerberos4_reply,
  				kerberos4_status,
! 				kerberos4_printsub,
! 				kerberos4_printname },
  # endif	/* ENCRYPTION */
  	{ AUTHTYPE_KERBEROS_V4, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
  				kerberos4_init,
***************
*** 159,165 ****
  				kerberos4_is,
  				kerberos4_reply,
  				kerberos4_status,
! 				kerberos4_printsub },
  #endif
  #ifdef	KRB4_ENCPWD
  	{ AUTHTYPE_KRB4_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
--- 164,171 ----
  				kerberos4_is,
  				kerberos4_reply,
  				kerberos4_status,
! 				kerberos4_printsub,
! 				kerberos4_printname },
  #endif
  #ifdef	KRB4_ENCPWD
  	{ AUTHTYPE_KRB4_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_MUTUAL,
***************
*** 168,174 ****
  				krb4encpwd_is,
  				krb4encpwd_reply,
  				krb4encpwd_status,
! 				krb4encpwd_printsub },
  #endif
  #ifdef	RSA_ENCPWD
  	{ AUTHTYPE_RSA_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
--- 174,181 ----
  				krb4encpwd_is,
  				krb4encpwd_reply,
  				krb4encpwd_status,
! 				krb4encpwd_printsub,
! 				0 },
  #endif
  #ifdef	RSA_ENCPWD
  	{ AUTHTYPE_RSA_ENCPWD, AUTH_WHO_CLIENT|AUTH_HOW_ONE_WAY,
***************
*** 177,183 ****
  				rsaencpwd_is,
  				rsaencpwd_reply,
  				rsaencpwd_status,
! 				rsaencpwd_printsub },
  #endif
  	{ 0, },
  };
--- 184,191 ----
  				rsaencpwd_is,
  				rsaencpwd_reply,
  				rsaencpwd_status,
! 				rsaencpwd_printsub,
! 				0 },
  #endif
  	{ 0, },
  };
***************
*** 641,646 ****
--- 649,667 ----
  		(*ap->printsub)(data, cnt, buf, buflen);
  	else
  		auth_gen_printsub(data, cnt, buf, buflen);
+ }
+ 
+ 	int
+ auth_printname(data, buf, buflen)
+ 	unsigned char *data, *buf;
+ 	int buflen;
+ {
+ 	Authenticator *ap;
+ 
+ 	if ((ap = findauthenticator(data[0], data[1])) && ap->printname)
+ 		return (*ap->printname)(buf, buflen);
+ 	else
+ 		return(-1);
  }
  
  	void
diff -cr cns-95q1.dist/usr/kerberos/src/src/appl/telnet/libtelnet/auth.h cns-95q1.test/usr/kerberos/src/src/appl/telnet/libtelnet/auth.h
*** cns-95q1.dist/usr/kerberos/src/src/appl/telnet/libtelnet/auth.h	Mon Feb 13 08:51:21 1995
--- cns-95q1.test/usr/kerberos/src/src/appl/telnet/libtelnet/auth.h	Sun Jun 25 21:53:13 1995
***************
*** 79,84 ****
--- 79,85 ----
  	void	(*reply) P((struct XauthP *, unsigned char *, int));
  	int	(*status) P((struct XauthP *, char *, int));
  	void	(*printsub) P((unsigned char *, int, unsigned char *, int));
+ 	int	(*printname) P((unsigned char *, int));
  } Authenticator;
  
  #include "auth-proto.h"
diff -cr cns-95q1.dist/usr/kerberos/src/src/appl/telnet/libtelnet/kerberos.c cns-95q1.test/usr/kerberos/src/src/appl/telnet/libtelnet/kerberos.c
*** cns-95q1.dist/usr/kerberos/src/src/appl/telnet/libtelnet/kerberos.c	Mon Feb 13 08:51:37 1995
--- cns-95q1.test/usr/kerberos/src/src/appl/telnet/libtelnet/kerberos.c	Sun Jun 25 22:04:30 1995
***************
*** 209,214 ****
--- 209,215 ----
  	Block enckey;
  #endif	/* ENCRYPTION */
  	char instance[INST_SZ];
+ 	char *inst;
  	char *realm;
  	char *krb_realmofhost();
  	char *krb_get_phost();
***************
*** 225,246 ****
  
  	memset(instance, 0, sizeof(instance));
  
! 	if (realm = krb_get_phost(RemoteHostName))
! 		strncpy(instance, realm, sizeof(instance));
! 
! 	instance[sizeof(instance)-1] = '\0';
  
  	realm = dest_realm ? dest_realm : krb_realmofhost(RemoteHostName);
  
  	if (!realm) {
  		printf("Kerberos V4: no realm for %s\r\n", RemoteHostName);
  		return(0);
  	}
! 	if (r = krb_mk_req(&auth, KRB_SERVICE_NAME, instance, realm, 0L)) {
  		printf("mk_req failed: %s\r\n", krb_get_err_text(r));
  		return(0);
  	}
! 	if (r = krb_get_cred(KRB_SERVICE_NAME, instance, realm, &cred)) {
  		printf("get_cred failed: %s\r\n", krb_get_err_text(r));
  		return(0);
  	}
--- 226,257 ----
  
  	memset(instance, 0, sizeof(instance));
  
! 	if (AuthHostName && *AuthHostName) {
! 		inst = AuthHostName;
! 	} else {
! 		if (inst = krb_get_phost(RemoteHostName))
! 			strncpy(instance, inst, sizeof(instance));
!            
! 		instance[sizeof(instance)-1] = '\0';
! 		inst = instance;
!         }
  
  	realm = dest_realm ? dest_realm : krb_realmofhost(RemoteHostName);
  
+ 	if (auth_debug_mode) {
+ 		printf ("Using %s.%s@%s as service principal\n",
+ 			KRB_SERVICE_NAME, inst, realm);
+ 	}
+ 
  	if (!realm) {
  		printf("Kerberos V4: no realm for %s\r\n", RemoteHostName);
  		return(0);
  	}
! 	if (r = krb_mk_req(&auth, KRB_SERVICE_NAME, inst, realm, 0L)) {
  		printf("mk_req failed: %s\r\n", krb_get_err_text(r));
  		return(0);
  	}
! 	if (r = krb_get_cred(KRB_SERVICE_NAME, inst, realm, &cred)) {
  		printf("get_cred failed: %s\r\n", krb_get_err_text(r));
  		return(0);
  	}
***************
*** 544,549 ****
--- 555,582 ----
  		break;
  	}
  }
+ 
+ 	int
+ kerberos4_printname(buf, buflen)
+ 	unsigned char *buf;
+ 	int buflen;
+ {
+ 
+ 	if ((!adat.pname) || (!adat.pinst) || (!adat.prealm))
+ 		return(-1);
+ 
+ 	if ((strlen(adat.pinst) + strlen(adat.pinst) +
+ 		strlen(adat.prealm) + 2) > buflen)
+ 		return(-1);
+ 
+ 	sprintf(buf, "%s%s%s@%s",
+ 		adat.pname,
+ 		*(adat.pinst) ? "." : "",
+ 		adat.pinst, adat.prealm);
+ 
+         return(0);
+ }
+ 
  
  	int
  kerberos4_cksum(d, n)
diff -cr cns-95q1.dist/usr/kerberos/src/src/appl/telnet/libtelnet/misc.c cns-95q1.test/usr/kerberos/src/src/appl/telnet/libtelnet/misc.c
*** cns-95q1.dist/usr/kerberos/src/src/appl/telnet/libtelnet/misc.c	Mon Feb 13 08:52:05 1995
--- cns-95q1.test/usr/kerberos/src/src/appl/telnet/libtelnet/misc.c	Sun Jun 25 21:53:14 1995
***************
*** 36,54 ****
  #include "misc.h"
  #include <stdio.h>
  
  char *RemoteHostName;
  char *LocalHostName;
  char *UserNameRequested = 0;
  int ConnectedCount = 0;
  
  	void
  auth_encrypt_init(local, remote, name, server)
  	char *local;
  	char *remote;
  	char *name;
  	int server;
  {
! 	RemoteHostName = remote;
  	LocalHostName = local;
  #if	defined(AUTHENTICATION)
  	auth_init(name, server);
--- 36,65 ----
  #include "misc.h"
  #include <stdio.h>
  
+ char *AuthHostName;
  char *RemoteHostName;
  char *LocalHostName;
  char *UserNameRequested = 0;
  int ConnectedCount = 0;
  
  	void
+ set_auth_hostname(remote)
+ 	char *remote;
+ {
+ 	AuthHostName = remote;
+ }
+ 
+ 	void
  auth_encrypt_init(local, remote, name, server)
  	char *local;
  	char *remote;
  	char *name;
  	int server;
  {
! 	if (AuthHostName && *AuthHostName)
! 		RemoteHostName = AuthHostName;
! 	else
! 		RemoteHostName = remote;
  	LocalHostName = local;
  #if	defined(AUTHENTICATION)
  	auth_init(name, server);
diff -cr cns-95q1.dist/usr/kerberos/src/src/appl/telnet/libtelnet/misc.h cns-95q1.test/usr/kerberos/src/src/appl/telnet/libtelnet/misc.h
*** cns-95q1.dist/usr/kerberos/src/src/appl/telnet/libtelnet/misc.h	Mon Feb 13 08:52:06 1995
--- cns-95q1.test/usr/kerberos/src/src/appl/telnet/libtelnet/misc.h	Sun Jun 25 21:53:14 1995
***************
*** 36,41 ****
--- 36,42 ----
  extern char *UserNameRequested;
  extern char *LocalHostName;
  extern char *RemoteHostName;
+ extern char *AuthHostName;
  extern int ConnectedCount;
  extern int ReservedPort;
  
diff -cr cns-95q1.dist/usr/kerberos/src/src/appl/telnet/telnet/main.c cns-95q1.test/usr/kerberos/src/src/appl/telnet/telnet/main.c
*** cns-95q1.dist/usr/kerberos/src/src/appl/telnet/telnet/main.c	Mon Feb 13 08:52:40 1995
--- cns-95q1.test/usr/kerberos/src/src/appl/telnet/telnet/main.c	Sun Jun 25 21:53:14 1995
***************
*** 80,86 ****
  	    prompt,
  #ifdef	AUTHENTICATION
  	    " [-8] [-E] [-K] [-L] [-X atype] [-a] [-d] [-e char] [-k realm]",
! 	    "\n\t[-l user] [-f/-F] [-n tracefile] ",
  #else
  	    " [-8] [-E] [-L] [-a] [-d] [-e char] [-l user] [-n tracefile]",
  	    "\n\t",
--- 80,86 ----
  	    prompt,
  #ifdef	AUTHENTICATION
  	    " [-8] [-E] [-K] [-L] [-X atype] [-a] [-d] [-e char] [-k realm]",
! 	    "\n\t[-l user] [-f/-F] [-n tracefile] [-h authhost]",
  #else
  	    " [-8] [-E] [-L] [-a] [-d] [-e char] [-l user] [-n tracefile]",
  	    "\n\t",
***************
*** 137,143 ****
  	rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE;
  	autologin = -1;
  
! 	while ((ch = getopt(argc, argv, "8EKLS:X:acde:fFk:l:n:rt:x")) != EOF) {
  		switch(ch) {
  		case '8':
  			eight = 3;	/* binary output and input */
--- 137,143 ----
  	rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE;
  	autologin = -1;
  
! 	while ((ch = getopt(argc, argv, "8EKLS:X:acde:fFh:k:l:n:rt:x")) != EOF) {
  		switch(ch) {
  		case '8':
  			eight = 3;	/* binary output and input */
***************
*** 174,179 ****
--- 174,182 ----
  #ifdef	AUTHENTICATION
  			auth_disable_name(optarg);
  #endif
+ 			break;
+ 		case 'h':
+ 			set_auth_hostname(optarg);
  			break;
  		case 'a':
  			autologin = 1;
diff -cr cns-95q1.dist/usr/kerberos/src/src/appl/telnet/telnetd/state.c cns-95q1.test/usr/kerberos/src/src/appl/telnet/telnetd/state.c
*** cns-95q1.dist/usr/kerberos/src/src/appl/telnet/telnetd/state.c	Mon Feb 13 08:54:21 1995
--- cns-95q1.test/usr/kerberos/src/src/appl/telnet/telnetd/state.c	Sun Jun 25 21:53:14 1995
***************
*** 36,41 ****
--- 36,42 ----
  #include "telnetd.h"
  #if	defined(AUTHENTICATION)
  #include <libtelnet/auth.h>
+ extern int envflag;
  #endif
  
  unsigned char	doopt[] = { IAC, DO, '%', 'c', 0 };
***************
*** 1455,1460 ****
--- 1456,1467 ----
  		break;
  	case TELQUAL_IS:
  		auth_is(subpointer, SB_LEN());
+                 if (envflag)
+                 {
+                    char buf[1024];
+                    if (! auth_printname(subpointer, buf, sizeof(buf)))
+                       setenv("AUTHNAME", buf, 1);
+                 }
  		break;
  	case TELQUAL_NAME:
  		auth_name(subpointer, SB_LEN());
diff -cr cns-95q1.dist/usr/kerberos/src/src/appl/telnet/telnetd/sys_term.c cns-95q1.test/usr/kerberos/src/src/appl/telnet/telnetd/sys_term.c
*** cns-95q1.dist/usr/kerberos/src/src/appl/telnet/telnetd/sys_term.c	Mon Feb 13 08:54:33 1995
--- cns-95q1.test/usr/kerberos/src/src/appl/telnet/telnetd/sys_term.c	Sun Jun 25 21:53:15 1995
***************
*** 48,53 ****
--- 48,55 ----
  #include <krb5/osconf.h>
  #endif
  
+ extern int zflag;
+ 
  #if defined(CRAY) || defined(__hpux)
  # define PARENT_DOES_UTMP
  #endif
***************
*** 1591,1596 ****
--- 1593,1603 ----
  	 * -f : force this login, he has already been authenticated
  	 */
  	argv = addarg(0, "login");
+ 
+ 	if (zflag == 1)
+ 		argv = addarg(argv, "-z");
+ 	if (zflag == 2)
+ 		argv = addarg(argv, "-Z");
  
  #if	!defined(NO_LOGIN_H)
  
diff -cr cns-95q1.dist/usr/kerberos/src/src/appl/telnet/telnetd/telnetd.c cns-95q1.test/usr/kerberos/src/src/appl/telnet/telnetd/telnetd.c
*** cns-95q1.dist/usr/kerberos/src/src/appl/telnet/telnetd/telnetd.c	Mon Feb 13 08:54:43 1995
--- cns-95q1.test/usr/kerberos/src/src/appl/telnet/telnetd/telnetd.c	Sun Jun 25 21:53:16 1995
***************
*** 76,81 ****
--- 76,84 ----
  int	require_SecurID = 0;
  #endif
  
+ int     envflag = 0;
+ int     zflag = 0;
+ 
  extern	int utmp_len;
  int	registerd_host_only = 0;
  
***************
*** 145,151 ****
   * passed off to getopt().
   */
  char valid_opts[] = {
! 	'd', ':', 'h', 'k', 'L', ':', 'n', 'S', ':', 'u', ':', 'U',
  #ifdef	AUTHENTICATION
  	'a', ':', 'X', ':',
  #endif
--- 148,154 ----
   * passed off to getopt().
   */
  char valid_opts[] = {
! 	'd', ':', 'E', 'h', 'k', 'L', ':', 'n', 'S', ':', 'u', ':', 'U',
  #ifdef	AUTHENTICATION
  	'a', ':', 'X', ':',
  #endif
***************
*** 173,178 ****
--- 176,182 ----
  #ifdef KRB4
  	'R', ':', 't', ':',
  #endif
+ 	'z', 'Z',
  	'\0'
  };
  
***************
*** 286,291 ****
--- 290,299 ----
  			break;
  #endif	/* ENCRYPTION */
  
+ 		case 'E':
+ 			envflag = 1;
+ 			break;
+ 
  		case 'h':
  			hostinfo = 0;
  			break;
***************
*** 401,406 ****
--- 409,422 ----
  			break;
  #endif	/* AUTHENTICATION */
  
+ 		/* Use SNKs for login (arg passwd to login) */
+ 		case 'z':
+ 			zflag = 1;
+ 			break;
+ 		case 'Z':
+ 			zflag = 2;
+ 			break;
+ 
  		default:
  			fprintf(stderr, "telnetd: %c: unknown option\n", ch);
  			/* FALLTHROUGH */
***************
*** 583,589 ****
  #ifdef	AUTHENTICATION
  	fprintf(stderr, " [-edebug]");
  #endif
! 	fprintf(stderr, " [-h]");
  #if	defined(CRAY) && defined(NEWINIT)
  	fprintf(stderr, " [-Iinitid]");
  #endif
--- 599,605 ----
  #ifdef	AUTHENTICATION
  	fprintf(stderr, " [-edebug]");
  #endif
! 	fprintf(stderr, " [-E] [-h]");
  #if	defined(CRAY) && defined(NEWINIT)
  	fprintf(stderr, " [-Iinitid]");
  #endif
***************
*** 615,620 ****
--- 631,637 ----
  	fprintf(stderr, " [-X auth-type]");
  #endif
  	fprintf(stderr, " [-u utmp_hostname_length] [-U]");
+ 	fprintf(stderr, " [-z] [-Z]\n\t");
  	fprintf(stderr, " [port]\n");
  	exit(1);
  }
***************
*** 857,862 ****
--- 874,881 ----
  	}
  #endif
  
+ 	init_env();
+ 
  #if	defined(_SC_CRAY_SECURE_SYS)
  	/*
  	 *	set ttyp line security label 
***************
*** 877,882 ****
--- 896,903 ----
  	hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
  		who->sin_family);
  
+ 	if (envflag)
+ 		setenv("REMOTEHOST_IP", inet_ntoa(who->sin_addr));
  	if (hp == NULL && registerd_host_only) {
  		fatal(net, "Couldn't resolve your address into a host name.\r\n\
           Please contact your net administrator");
***************
*** 886,891 ****
--- 907,921 ----
  	} else {
  		host = inet_ntoa(who->sin_addr);
  	}
+ 	if (envflag)
+ 	{
+ 		if (hp) 
+ 		{
+ 			setenv("REMOTEHOST_NAME", hp->h_name);
+ 		} else {
+ 			setenv("REMOTEHOST_NAME", inet_ntoa(who->sin_addr));
+ 		}
+ 	}
  	/*
  	 * We must make a copy because Kerberos is probably going
  	 * to also do a gethost* and overwrite the static data...
***************
*** 901,907 ****
  	auth_encrypt_init(hostname, host, "TELNETD", 1);
  #endif
  
- 	init_env();
  
  	if (realm_file != NULL)
  		setenv("KRB_CONF", realm_file, 1);
--- 931,936 ----
diff -cr cns-95q1.dist/usr/kerberos/src/src/config/mt-alpha cns-95q1.test/usr/kerberos/src/src/config/mt-alpha
*** cns-95q1.dist/usr/kerberos/src/src/config/mt-alpha	Mon Feb 13 08:57:19 1995
--- cns-95q1.test/usr/kerberos/src/src/config/mt-alpha	Sun Jun 25 21:53:16 1995
***************
*** 8,12 ****
  
  RPROGS= -DRPROGS_IN_USR_BIN
  TARGET_CDEFS= -DBSD42 -DATHENA -DHAVE_VSPRINTF -DPOSIX \
! 	-DHAS_STRDUP -DUIDGID_T -DWAIT_USES_INT -DHAS_DIRENT -DSTDARG
  BSDLIB=$(RESOLV)
--- 8,17 ----
  
  RPROGS= -DRPROGS_IN_USR_BIN
  TARGET_CDEFS= -DBSD42 -DATHENA -DHAVE_VSPRINTF -DPOSIX \
! 	-DHAS_STRDUP -DUIDGID_T -DWAIT_USES_INT -DHAS_DIRENT -DSTDARG \
! 	-DGETHOSTID_DECLARED
  BSDLIB=$(RESOLV)
+ 
+ CC=cc
+ DBG=-g3 -O -Olimit 1000
+ DBG_LIB=-g3 -O -Olimit 1000
diff -cr cns-95q1.dist/usr/kerberos/src/src/include/cc-unix.h cns-95q1.test/usr/kerberos/src/src/include/cc-unix.h
*** cns-95q1.dist/usr/kerberos/src/src/include/cc-unix.h	Mon Feb 13 08:59:14 1995
--- cns-95q1.test/usr/kerberos/src/src/include/cc-unix.h	Sun Jun 25 21:53:16 1995
***************
*** 73,79 ****
--- 73,83 ----
  /* extern int getpid();	 -- this will default, and some systems explicitly
  				declare pid_t rather than int (sigh).  */
  
+ /* Some systems, notably DEC's OSF (3.X at least) declare this in netdb.h
+    as an int.  longs are 64 bits on this OS. */
+ #ifndef GETHOSTID_DECLARED
  extern long gethostid();
+ #endif
  
  /*
   * Compatability with WinSock calls on MS-Windows...
diff -cr cns-95q1.dist/usr/kerberos/src/src/include/kerberos.h cns-95q1.test/usr/kerberos/src/src/include/kerberos.h
*** cns-95q1.dist/usr/kerberos/src/src/include/kerberos.h	Mon Feb 13 08:59:18 1995
--- cns-95q1.test/usr/kerberos/src/src/include/kerberos.h	Sun Jun 25 21:53:16 1995
***************
*** 285,290 ****
--- 285,298 ----
  		char FAR *, char FAR *, int, char FAR *));
  
  extern int INTERFACE
+ krb_snk_get_pw_in_tkt PROTOTYPE ((char FAR *, char FAR *, char FAR *,
+ 		char FAR *, char FAR *, int));
+ 
+ extern int INTERFACE
+ krb_snk_vfy_pw_in_tkt PROTOTYPE ((char FAR *, char FAR *, char FAR *,
+ 		char FAR *, char FAR *));
+ 
+ extern int INTERFACE
  krb_get_pw_in_tkt_preauth PROTOTYPE ((char FAR *, char FAR *, char FAR *,
  		char FAR *, char FAR *, int, char FAR *));
  
***************
*** 343,350 ****
  			struct sockaddr_in FAR *, MSG_DAT FAR *));
  
  	extern int INTERFACE
! 	krb_rd_req PROTOTYPE ((KTEXT, char FAR *, char FAR *, long,
! 		AUTH_DAT FAR *, char FAR *));
  
  	extern long INTERFACE
  	krb_rd_safe PROTOTYPE ((unsigned char FAR *, unsigned KRB_INT32,
--- 351,358 ----
  			struct sockaddr_in FAR *, MSG_DAT FAR *));
  
  	extern int INTERFACE
! 	krb_rd_req PROTOTYPE ((KTEXT, char FAR *, char FAR *,
! 		unsigned KRB_INT32, AUTH_DAT FAR *, char FAR *));
  
  	extern long INTERFACE
  	krb_rd_safe PROTOTYPE ((unsigned char FAR *, unsigned KRB_INT32,
diff -cr cns-95q1.dist/usr/kerberos/src/src/include/krb-sed.h cns-95q1.test/usr/kerberos/src/src/include/krb-sed.h
*** cns-95q1.dist/usr/kerberos/src/src/include/krb-sed.h	Mon Feb 13 08:59:33 1995
--- cns-95q1.test/usr/kerberos/src/src/include/krb-sed.h	Sun Jun 25 21:53:17 1995
***************
*** 194,200 ****
   */
  
  #define     swap_u_16(x) {\
!  unsigned long   _krb_swap_tmp[4];\
   swab(((char *) x) +0, ((char *)  _krb_swap_tmp) +14 ,2); \
   swab(((char *) x) +2, ((char *)  _krb_swap_tmp) +12 ,2); \
   swab(((char *) x) +4, ((char *)  _krb_swap_tmp) +10 ,2); \
--- 194,200 ----
   */
  
  #define     swap_u_16(x) {\
!  unsigned KRB_INT32   _krb_swap_tmp[4];\
   swab(((char *) x) +0, ((char *)  _krb_swap_tmp) +14 ,2); \
   swab(((char *) x) +2, ((char *)  _krb_swap_tmp) +12 ,2); \
   swab(((char *) x) +4, ((char *)  _krb_swap_tmp) +10 ,2); \
***************
*** 207,213 ****
                              }
  
  #define     swap_u_12(x) {\
!  unsigned long   _krb_swap_tmp[4];\
   swab(( char *) x,     ((char *)  _krb_swap_tmp) +10 ,2); \
   swab(((char *) x) +2, ((char *)  _krb_swap_tmp) +8 ,2); \
   swab(((char *) x) +4, ((char *)  _krb_swap_tmp) +6 ,2); \
--- 207,213 ----
                              }
  
  #define     swap_u_12(x) {\
!  unsigned KRB_INT32   _krb_swap_tmp[4];\
   swab(( char *) x,     ((char *)  _krb_swap_tmp) +10 ,2); \
   swab(((char *) x) +2, ((char *)  _krb_swap_tmp) +8 ,2); \
   swab(((char *) x) +4, ((char *)  _krb_swap_tmp) +6 ,2); \
***************
*** 218,224 ****
                              }
  
  #define     swap_C_Block(x) {\
!  unsigned long   _krb_swap_tmp[4];\
   swab(( char *) x,    ((char *)  _krb_swap_tmp) +6 ,2); \
   swab(((char *) x) +2,((char *)  _krb_swap_tmp) +4 ,2); \
   swab(((char *) x) +4,((char *)  _krb_swap_tmp) +2 ,2); \
--- 218,224 ----
                              }
  
  #define     swap_C_Block(x) {\
!  unsigned KRB_INT32   _krb_swap_tmp[4];\
   swab(( char *) x,    ((char *)  _krb_swap_tmp) +6 ,2); \
   swab(((char *) x) +2,((char *)  _krb_swap_tmp) +4 ,2); \
   swab(((char *) x) +4,((char *)  _krb_swap_tmp) +2 ,2); \
***************
*** 226,232 ****
   memcpy((char *)x,(char *)_krb_swap_tmp,8);\
                              }
  #define     swap_u_quad(x) {\
!  unsigned long   _krb_swap_tmp[4];\
   swab(( char *) &x,    ((char *)  _krb_swap_tmp) +6 ,2); \
   swab(((char *) &x) +2,((char *)  _krb_swap_tmp) +4 ,2); \
   swab(((char *) &x) +4,((char *)  _krb_swap_tmp) +2 ,2); \
--- 226,232 ----
   memcpy((char *)x,(char *)_krb_swap_tmp,8);\
                              }
  #define     swap_u_quad(x) {\
!  unsigned KRB_INT32   _krb_swap_tmp[4];\
   swab(( char *) &x,    ((char *)  _krb_swap_tmp) +6 ,2); \
   swab(((char *) &x) +2,((char *)  _krb_swap_tmp) +4 ,2); \
   swab(((char *) &x) +4,((char *)  _krb_swap_tmp) +2 ,2); \
***************
*** 235,241 ****
                              }
  
  #define     swap_u_long(x) {\
!  unsigned long   _krb_swap_tmp[4];\
   swab((char *)  &x,    ((char *)  _krb_swap_tmp) +2 ,2); \
   swab(((char *) &x) +2,((char *)  _krb_swap_tmp),2); \
   x = _krb_swap_tmp[0];   \
--- 235,241 ----
                              }
  
  #define     swap_u_long(x) {\
!  unsigned KRB_INT32   _krb_swap_tmp[4];\
   swab((char *)  &x,    ((char *)  _krb_swap_tmp) +2 ,2); \
   swab(((char *) &x) +2,((char *)  _krb_swap_tmp),2); \
   x = _krb_swap_tmp[0];   \
diff -cr cns-95q1.dist/usr/kerberos/src/src/kuser/kinit.c cns-95q1.test/usr/kerberos/src/src/kuser/kinit.c
*** cns-95q1.dist/usr/kerberos/src/src/kuser/kinit.c	Mon Feb 13 09:03:18 1995
--- cns-95q1.test/usr/kerberos/src/src/kuser/kinit.c	Sun Jun 25 21:53:17 1995
***************
*** 42,89 ****
  		*p = '\0';
  }
  
- 
- static char
- hex_scan_nybble(c)
-      char c;
- {
-   if (c >= '0' && c <= '9')
-     return c - '0';
-   if (c >= 'A' && c <= 'F')
-     return c - 'A' + 10;
-   if (c >= 'a' && c <= 'f')
-     return c - 'a' + 10;
-   return -1;
- }
- 
- /* returns: NULL for ok, pointer to error string for bad input */
- static char*
- hex_scan_four_bytes(out, in)
-      char *out;
-      char *in;
- {
-   int i;
-   char c, c1;
-   for (i=0; i<8; i++) {
-     if(!in[i]) return "not enough input";
-     c = hex_scan_nybble(in[i]);
-     if(c<0) return "invalid digit";
-     c1 = c; i++;
-     if(!in[i]) return "not enough input";
-     c = hex_scan_nybble(in[i]);
-     if(c<0) return "invalid digit";
-     *out++ = (c1 << 4) + c;
-   }
-   switch(in[i]) {
-   case 0:
-   case '\r':
-   case '\n':
-     return 0;
-   default:
-     return "extra characters at end of input";
-   }
- }
- 
  int 
  main(argc, argv)
      int     argc;
--- 42,47 ----
***************
*** 240,251 ****
  				  lifetime, password[0]? password: (char *)0);
      }
      } else { /* sflag is set, so we do snk4 support instead */
-       /* for the SNK4 we have to get the ticket explicitly. */
  
-       KTEXT_ST cip_st;
-       KTEXT cip = &cip_st;	/* Returned Ciphertext */
-       KTEXT_ST cip2_st;
-       KTEXT cip2 = &cip2_st;	/* Returned Ciphertext */
        /* preauth is impossible in this context */
        if (pflag)
  	{
--- 198,204 ----
***************
*** 253,329 ****
  	  exit(1);
  	}
  
-       /* flag the instance to get the right tickets */
        strcat(inst, "+SNK4");
  
!       if (k_errno = krb_mk_in_tkt_preauth(aname, inst, realm, 
! 					  "krbtgt", realm,
! 					  lifetime, (char*)0, 0, cip))
! 	{
! 	    fprintf(stderr, "%s: %s for principal %s%s%s@%s\n", progname,
! 		    krb_get_err_text(k_errno), aname, inst[0]?".":"", inst,
! 		    realm);
! 	    exit(1);
! 	}
! 
!       /* here we've got the response. Pull off the challenge. */
!       /* decrypt_tkt (user, instance, realm, arg, key_proc, &cip); */
!       {
! 	static char version[] = "cnssnk01";
! 	des_cblock key1, key2;
! 	char challenge1[8], challenge2[8];
! 	char resp1[128], resp2[128];
! 	des_key_schedule ks;
! 	char *complain;
! 
! 	if (memcmp (cip->dat, version, 8)) {
! 	  /* perhaps try the normal decrypt in this case? */
! 	  fprintf(stderr, "%s: not an SNK response packet\n", progname);
! 	  exit(1);
! 	}
! 	memcpy(challenge1, cip->dat+8, 8);
! 	memcpy(challenge2, cip->dat+16, 8);
! 	
! 	/* add input checks */
! 	if (memcmp (challenge1, challenge2, 8)) {
! 	  complain = NULL;
! 	  do {
! 	    if(complain) printf("Bad input: %s\n", complain);
! 	    printf("Challenge #1: %s\nResponse #1:", challenge1);
! 	    get_input(resp1, sizeof(resp1), stdin);
! 	  } while(complain = hex_scan_four_bytes((char*)&key1, resp1));
! 	  complain = NULL;
! 	  do {
! 	    if(complain) printf("Bad input: %s\n", complain);
! 	    printf("Challenge #2: %s\nResponse #2:", challenge2);
! 	    get_input(resp2, sizeof(resp2), stdin);
! 	  } while(complain = hex_scan_four_bytes(4+(char*)&key1, resp2));
! 	} else {
! 	  complain = NULL;
! 	  do {
! 	    if(complain) printf("Bad input: %s\n", complain);
! 	    printf("Challenge: %s\nResponse:", challenge1);
! 	    get_input(resp1, sizeof(resp1), stdin);
! 	  } while(complain = hex_scan_four_bytes((char*)&key1, resp1));
! 	  memcpy(4+(char*)&key1, (char*)&key1, 4);
! 	  strcpy(resp2, resp1);
! 	}
! 	des_fixup_key_parity(key1);
! 	des_key_sched(key1, ks);
! 	des_ecb_encrypt(&key1, &key2, ks, 1);
! 	des_fixup_key_parity(key2);
! 
! 	des_key_sched(key2,ks);
! 	pcbc_encrypt((C_Block *)(cip->dat+24),(C_Block *)cip2->dat,
! 		     (long) (cip->length-24),ks,(C_Block *)&key2,0);
! 	cip2->length = cip->length-24;
! 
!       }
!     
!       /* if this fails, perhaps the user should get another chance
! 	 at the input? */
!       if (k_errno = krb_parse_in_tkt(aname, inst, realm, 
! 				     "krbtgt", realm, lifetime, cip2))
  	{
  	  fprintf(stderr, "%s: %s\n", progname, krb_get_err_text(k_errno));
  	  exit(1);
--- 206,215 ----
  	  exit(1);
  	}
  
        strcat(inst, "+SNK4");
  
!       if (k_errno = krb_snk_get_pw_in_tkt(aname, inst, realm, 
!                                           "krbtgt", realm, lifetime))
  	{
  	  fprintf(stderr, "%s: %s\n", progname, krb_get_err_text(k_errno));
  	  exit(1);
diff -cr cns-95q1.dist/usr/kerberos/src/src/kuser/ksu.c cns-95q1.test/usr/kerberos/src/src/kuser/ksu.c
*** cns-95q1.dist/usr/kerberos/src/src/kuser/ksu.c	Mon Feb 13 09:03:24 1995
--- cns-95q1.test/usr/kerberos/src/src/kuser/ksu.c	Sun Jun 25 22:17:49 1995
***************
*** 81,86 ****
--- 81,87 ----
  	int asme, ch, fulllogin, fastlogin, prio;
  #endif /* NO_GETUSERSHELL */
  	int use_preauth = 0;
+ 	int use_snk = 0;
  	enum { UNSET, YES, NO } iscsh = UNSET;
  	char *user, *shell, *username, *cleanenv[2], *nargv[4], **np;
  	char namebuf[50], shellbuf[MAXPATHLEN];
***************
*** 100,109 ****
  	*np-- = NULL;
  #ifdef NO_GETUSERSHELL
  	fulllogin = fastlogin = 0;
! #define	GETOPTARG "-flp"
  #else
  	asme = fulllogin = fastlogin = 0;
! #define GETOPTARG "-flmp"
  #endif
  	while ((ch = getopt(argc, argv, GETOPTARG)) != EOF)
  		switch((char)ch) {
--- 101,110 ----
  	*np-- = NULL;
  #ifdef NO_GETUSERSHELL
  	fulllogin = fastlogin = 0;
! #define	GETOPTARG "-flps"
  #else
  	asme = fulllogin = fastlogin = 0;
! #define GETOPTARG "-flmps"
  #endif
  	while ((ch = getopt(argc, argv, GETOPTARG)) != EOF)
  		switch((char)ch) {
***************
*** 113,118 ****
--- 114,122 ----
  		case 'p':
  			use_preauth = 1;
  			break;
+ 		case 's':
+ 			use_snk = 1;
+ 			break;
  		case '-':
  		case 'l':
  			fulllogin = 1;
***************
*** 180,205 ****
  		fprintf(stderr,"Unable to get local realm\n");
  		exit(1);
  	    }
! 	    if (koktologin(username, lrealm)) {
  		fprintf(stderr,"You are not allowed to ksu to root\n");
  		exit(1);
  	    }
! 	    sprintf(krbtkfile, "/tmp/tkt_root_%d", getuid());
! 	    setuid(0);		/* so ticket file has good protection */
! 	    if (read_long_pw_string(pw_buf, sizeof(pw_buf)-1,
! 				   "Your root instance password: ", 0)) {
! 		fprintf(stderr,"Error reading password.\n");
  		exit(1);
  	    }
! 	    p = pw_buf;
! 	    setenv("KRBTKFILE", krbtkfile, 1);
! 	    if (use_preauth)
! 		kerno = krb_get_pw_in_tkt_preauth(username, "root", lrealm, "krbtgt",
! 						  lrealm, 2, p);
! 	    else
! 		kerno = krb_get_pw_in_tkt(username, "root", lrealm, "krbtgt",
! 				 	  lrealm, 2, p);
! 	    memset(p, 0, strlen(p));
  	    if (kerno != KSUCCESS) {
  		printf("Unable to ksu: %s\n", krb_get_err_text (kerno));
  		syslog(LOG_NOTICE|LOG_AUTH, "ksu: BAD SU %s on %s: %s",
--- 184,227 ----
  		fprintf(stderr,"Unable to get local realm\n");
  		exit(1);
  	    }
! 	    if (koktologin(username, lrealm, use_snk)) {
  		fprintf(stderr,"You are not allowed to ksu to root\n");
  		exit(1);
  	    }
! 
!             /* hostname is needed now to obtain correct tickets in case of
!                SNK style verification. */
! 	    if (gethostname(hostname, sizeof(hostname)) == -1) {
! 		perror("cannot retrieve hostname");
  		exit(1);
  	    }
! 	    (void) strncpy(savehost, krb_get_phost(hostname),
! 			   sizeof(savehost));
! 	    savehost[sizeof(savehost)-1] = 0;
! 
! 	    sprintf(krbtkfile, "/tmp/tkt_root_%d", getuid());
! 	    setuid(0);		/* so ticket file has good protection */
!             if (use_snk)
!             {
!                /* SNK ticket style uses zero ticket lifetime method */
!                kerno = krb_snk_vfy_pw_in_tkt(username, "root+SNK4", lrealm,
!                                              "rcmd", savehost);
!             } else {
!                setenv("KRBTKFILE", krbtkfile, 1);
!                if (read_long_pw_string(pw_buf, sizeof(pw_buf)-1,
!                                        "Your root instance password: ", 0)) {
!                   fprintf(stderr,"Error reading password.\n");
!                   exit(1);
!                }
!                p = pw_buf;
!                if (use_preauth)
!                   kerno = krb_get_pw_in_tkt_preauth(username, "root", lrealm, "krbtgt",
!                                                     lrealm, 2, p);
!                else
!                   kerno = krb_get_pw_in_tkt(username, "root", lrealm, "krbtgt",
!                                             lrealm, 2, p);
!                memset(p, 0, strlen(p));
!             }
  	    if (kerno != KSUCCESS) {
  		printf("Unable to ksu: %s\n", krb_get_err_text (kerno));
  		syslog(LOG_NOTICE|LOG_AUTH, "ksu: BAD SU %s on %s: %s",
***************
*** 213,226 ****
  	     * Now use the ticket for something useful, to make sure
  	     * it is valid.
  	     */
! 	    if (gethostname(hostname, sizeof(hostname)) == -1) {
! 		perror("cannot retrieve hostname");
! 		dest_tkt();
! 		exit(1);
! 	    }
! 	    (void) strncpy(savehost, krb_get_phost(hostname),
! 			   sizeof(savehost));
! 	    savehost[sizeof(savehost)-1] = 0;
  
  	    kerno = krb_mk_req(&ticket, "rcmd", savehost, lrealm, 33);
  	    if (kerno == KDC_PR_UNKNOWN) {
--- 235,242 ----
  	     * Now use the ticket for something useful, to make sure
  	     * it is valid.
  	     */
!              /* SNK method has already verified the tickets. */
!           if (!use_snk) {
  
  	    kerno = krb_mk_req(&ticket, "rcmd", savehost, lrealm, 33);
  	    if (kerno == KDC_PR_UNKNOWN) {
***************
*** 251,256 ****
--- 267,273 ----
  		}		
  	    }
  	    printf("Don't forget to kdestroy before exiting the root shell.\n");
+          }
  	} else
  	/* if target requires a password, verify it */
  	if (ruid && *pwd->pw_passwd) {
***************
*** 375,390 ****
  }
  #endif /* NO_GETUSERSHELL */
  
! koktologin(name, realm)
      char   *name;
      char   *realm;
  {
      struct auth_dat kdata_st;
      AUTH_DAT *kdata = &kdata_st;
      /* Cons together an AUTH_DAT structure for kuserok */
      memset((caddr_t) kdata, 0, sizeof(*kdata));
      strcpy(kdata->pname, name);
!     strcpy(kdata->pinst, "root");
      strcpy(kdata->prealm, realm);
      return (kuserok(kdata, "root"));
  }
--- 392,411 ----
  }
  #endif /* NO_GETUSERSHELL */
  
! koktologin(name, realm, snk)
      char   *name;
      char   *realm;
+     int    snk;
  {
      struct auth_dat kdata_st;
      AUTH_DAT *kdata = &kdata_st;
      /* Cons together an AUTH_DAT structure for kuserok */
      memset((caddr_t) kdata, 0, sizeof(*kdata));
      strcpy(kdata->pname, name);
!     if (snk)
!        strcpy(kdata->pinst, "root+SNK4");
!     else
!        strcpy(kdata->pinst, "root");
      strcpy(kdata->prealm, realm);
      return (kuserok(kdata, "root"));
  }
diff -cr cns-95q1.dist/usr/kerberos/src/src/lib/krb/Makefile.in cns-95q1.test/usr/kerberos/src/src/lib/krb/Makefile.in
*** cns-95q1.dist/usr/kerberos/src/src/lib/krb/Makefile.in	Mon Feb 13 09:04:44 1995
--- cns-95q1.test/usr/kerberos/src/src/lib/krb/Makefile.in	Sun Jun 25 21:53:18 1995
***************
*** 11,16 ****
--- 11,17 ----
  	debug.c \
  	decomp_tkt.c \
  	g_ad_tkt.c \
+ 	v_pw_in_tkt.c \
  	g_pw_in_tkt.c \
  	g_phost.c \
  	g_pw_tkt.c \
***************
*** 49,54 ****
--- 50,56 ----
  	g_ad_tkt.$(OBJEXT) \
  	g_in_tkt.$(OBJEXT) \
  	g_phost.$(OBJEXT) \
+ 	v_pw_in_tkt.$(OBJEXT) \
  	g_pw_in_tkt.$(OBJEXT) \
  	g_pw_tkt.$(OBJEXT) \
  	g_tkt_svc.$(OBJEXT) \
diff -cr cns-95q1.dist/usr/kerberos/src/src/lib/krb/g_in_tkt.c cns-95q1.test/usr/kerberos/src/src/lib/krb/g_in_tkt.c
*** cns-95q1.dist/usr/kerberos/src/src/lib/krb/g_in_tkt.c	Mon Feb 13 09:05:17 1995
--- cns-95q1.test/usr/kerberos/src/src/lib/krb/g_in_tkt.c	Sun Jun 25 21:53:18 1995
***************
*** 232,239 ****
  }
  
  
  int
! krb_parse_in_tkt(user, instance, realm, service, sinstance, life, cip)
      char *user;
      char *instance;
      char *realm;
--- 232,250 ----
  }
  
  
+ /* Insert complaint about modularity of functionality.
+    krb_parse_in_tkt should be named krb_parse_and_save_in_tkt.  Now that I
+    *don't* want to store the ticket, I've got to go to a bunch of confusing
+    extra work, which makes the interface look ugly.
+ 
+    Warning to users of krb_parse_only_in_tkt:  Make sure your argument's
+    pointers are good.  This function isn't very NULL pointer/core dump
+    proof.
+    */
+ 
  int
! krb_parse_only_in_tkt(user, instance, realm, service, sinstance, life, cip,
!                       ses, lifetime, kvno, tkt, t_local)
      char *user;
      char *instance;
      char *realm;
***************
*** 241,260 ****
      char *sinstance;
      int life;
      KTEXT cip;
  {
      char *ptr;
-     C_Block ses;                /* Session key for tkt */
-     int kvno;			/* Kvno for session key */
      char s_name[SNAME_SZ];
      char s_instance[INST_SZ];
      char rlm[REALM_SZ];
-     KTEXT_ST tkt_st;
-     KTEXT tkt = &tkt_st;	/* Current ticket */
      unsigned long kdc_time;   /* KDC time */
-     unsigned KRB_INT32 t_local;	/* Must be 4 bytes long for memcpy below! */
      KRB_INT32 t_diff;	/* Difference between timestamps */
      int kerror;
-     int lifetime;
  
      ptr = (char *) cip->dat;
  
--- 252,272 ----
      char *sinstance;
      int life;
      KTEXT cip;
+    /* hmm, how to declare */
+     des_cblock ses;
+     int *lifetime;
+     int *kvno;
+     KTEXT tkt;
+    /* Must be 4 bytes long for memcpy below! */
+     unsigned KRB_INT32 *t_local;
  {
      char *ptr;
      char s_name[SNAME_SZ];
      char s_instance[INST_SZ];
      char rlm[REALM_SZ];
      unsigned long kdc_time;   /* KDC time */
      KRB_INT32 t_diff;	/* Difference between timestamps */
      int kerror;
  
      ptr = (char *) cip->dat;
  
***************
*** 288,295 ****
  
      /* extract ticket lifetime, server key version, ticket length */
      /* be sure to avoid sign extension on lifetime! */
!     lifetime = (unsigned char) ptr[0];
!     kvno = (unsigned char) ptr[1];
      tkt->length = (unsigned char) ptr[2];
      ptr += 3;
      
--- 300,307 ----
  
      /* extract ticket lifetime, server key version, ticket length */
      /* be sure to avoid sign extension on lifetime! */
!     *lifetime = (unsigned char) ptr[0];
!     *kvno = (unsigned char) ptr[1];
      tkt->length = (unsigned char) ptr[2];
      ptr += 3;
      
***************
*** 311,330 ****
  
      ptr += 4;
  
!     t_local = TIME_GMT_UNIXSEC;
!     t_diff = t_local - kdc_time;
      if (t_diff < 0) t_diff = -t_diff;	/* Absolute value of difference */
      if (t_diff > CLOCK_SKEW) {
          return(RD_AP_TIME);		/* XXX should probably be better
  					   code */
      }
  
      /* initialize ticket cache */
      if (in_tkt(user,instance) != KSUCCESS)
  	return(INTK_ERR);
  
      /* stash ticket, session key, etc. for future use */
!     if (kerror = krb_save_credentials(s_name, s_instance, rlm, ses,
  				      lifetime, kvno, tkt, t_local))
  	return(kerror);
  
--- 323,367 ----
  
      ptr += 4;
  
!     *t_local = TIME_GMT_UNIXSEC;
!     t_diff = *t_local - kdc_time;
      if (t_diff < 0) t_diff = -t_diff;	/* Absolute value of difference */
      if (t_diff > CLOCK_SKEW) {
          return(RD_AP_TIME);		/* XXX should probably be better
  					   code */
      }
  
+     return(INTK_OK);
+ }
+ 
+ int
+ krb_parse_in_tkt(user, instance, realm, service, sinstance, life, cip)
+     char *user;
+     char *instance;
+     char *realm;
+     char *service;
+     char *sinstance;
+     int life;
+     KTEXT cip;
+ {
+     int kerror, lifetime, kvno;
+     unsigned KRB_INT32 t_local;	/* Must be 4 bytes long for memcpy below! */
+     des_cblock ses;                /* Session key for tkt */
+     KTEXT_ST tkt_st;
+     KTEXT tkt = &tkt_st;	/* Current ticket */
+ 
+     /* Parse the ticket */
+     if (kerror = krb_parse_only_in_tkt(user, instance, realm, service,
+                                        sinstance, life, cip, ses, &lifetime,
+                                        &kvno, tkt, &t_local))
+         return(kerror);
+ 
      /* initialize ticket cache */
      if (in_tkt(user,instance) != KSUCCESS)
  	return(INTK_ERR);
  
      /* stash ticket, session key, etc. for future use */
!     if (kerror = krb_save_credentials(service, sinstance, realm, ses,
  				      lifetime, kvno, tkt, t_local))
  	return(kerror);
  
diff -cr cns-95q1.dist/usr/kerberos/src/src/lib/krb/g_pw_in_tkt.c cns-95q1.test/usr/kerberos/src/src/lib/krb/g_pw_in_tkt.c
*** cns-95q1.dist/usr/kerberos/src/src/lib/krb/g_pw_in_tkt.c	Mon Feb 13 09:05:23 1995
--- cns-95q1.test/usr/kerberos/src/src/lib/krb/g_pw_in_tkt.c	Sun Jun 25 21:53:18 1995
***************
*** 11,16 ****
--- 11,19 ----
  #include "krb.h"
  #include "prot.h"
  
+ #include <stdio.h>
+ #include <string.h>
+ 
  #ifndef NULL
  #define NULL 0
  #endif
***************
*** 62,67 ****
--- 65,171 ----
      return (0);
  }
  
+ #ifndef NOENCRYPTION
+ static void
+ get_input(s, size, stream)
+ char *s;
+ int size;
+ FILE *stream;
+ {
+ 	char *p;
+ 
+ 	if (fgets(s, size, stream) == NULL)
+ 	  exit(1);
+ 	if ( (p = strchr(s, '\n')) != NULL)
+ 		*p = '\0';
+ }
+ 
+ 
+ static char
+ hex_scan_nybble(c)
+      char c;
+ {
+   if (c >= '0' && c <= '9')
+     return c - '0';
+   if (c >= 'A' && c <= 'F')
+     return c - 'A' + 10;
+   if (c >= 'a' && c <= 'f')
+     return c - 'a' + 10;
+   return -1;
+ }
+ 
+ 
+ static char*
+ hex_scan_four_bytes(out, in)
+      char *out;
+      char *in;
+ {
+   int i;
+   char c, c1;
+   for (i=0; i<8; i++) {
+     if(!in[i]) return "not enough input";
+     c = hex_scan_nybble(in[i]);
+     if(c<0) return "invalid digit";
+     c1 = c; i++;
+     if(!in[i]) return "not enough input";
+     c = hex_scan_nybble(in[i]);
+     if(c<0) return "invalid digit";
+     *out++ = (c1 << 4) + c;
+   }
+   switch(in[i]) {
+   case 0:
+   case '\r':
+   case '\n':
+     return 0;
+   default:
+     return "extra characters at end of input";
+   }
+ }
+ 
+ int
+ snk_passwd_to_key(user,instance,realm,challenge1,challenge2,key,ks)
+     char *user, *instance, *realm, *challenge1, *challenge2;
+     des_cblock *key;
+     des_key_schedule *ks;
+ {
+    des_cblock key1, key2;
+    char *complain;
+    char resp1[128], resp2[128];
+ 
+    /* need add input checks */
+    if (memcmp (challenge1, challenge2, 8)) {
+       complain = NULL;
+       do {
+          if(complain) printf("Bad input: %s\n", complain);
+          printf("Challenge #1: %s\nResponse #1:", challenge1);
+          get_input(resp1, sizeof(resp1), stdin);
+       } while(complain = hex_scan_four_bytes((char*)&key1, resp1));
+       complain = NULL;
+       do {
+          if(complain) printf("Bad input: %s\n", complain);
+          printf("Challenge #2: %s\nResponse #2:", challenge2);
+          get_input(resp2, sizeof(resp2), stdin);
+       } while(complain = hex_scan_four_bytes(4+(char*)&key1, resp2));
+    } else {
+       complain = NULL;
+       do {
+          if(complain) printf("Bad input: %s\n", complain);
+          printf("Challenge: %s\nResponse:", challenge1);
+          get_input(resp1, sizeof(resp1), stdin);
+       } while(complain = hex_scan_four_bytes((char*)&key1, resp1));
+       memcpy(4+(char*)&key1, (char*)&key1, 4);
+    }
+    des_fixup_key_parity(key1);
+    des_key_sched(key1, *ks);
+    des_ecb_encrypt(&key1, &key2, *ks, 1);
+    des_fixup_key_parity(key2);
+ 
+    memcpy((char *) *key, (char *) key2, sizeof(des_cblock));
+ 
+    return (0);
+ }
+ #endif /* NOENCRYPTION */
+ 
  /*
   * krb_get_pw_in_tkt() takes the name of the server for which the initial
   * ticket is to be obtained, the name of the principal the ticket is
***************
*** 151,156 ****
--- 255,357 ----
  
     krb_free_preauth(preauth_p, preauth_len);
     return ret_st;
+ }
+ 
+ int INTERFACE
+ krb_snk_get_pw_in_tkt(user,instance,realm,service,sinstance,life)
+     char *user;
+     char *instance;
+     char *realm; 
+     char *service;
+     char *sinstance;
+     int life;
+ {
+    return
+       (krb_snk_get_pw_in_tkt_tkt(user, instance, realm, service, sinstance,
+                                  life, 0, (unsigned char *) 0, (int *) 0, 
+                                  (int *) 0, (KTEXT) 0,
+                                  (unsigned KRB_INT32 *) 0));
+ }
+ 
+ int INTERFACE
+ krb_snk_get_pw_in_tkt_tkt(user,instance,realm,service,sinstance,life,
+                           nostore_flag, ses, lifetime, kvno, tkt, t_local)
+     char *user, *instance, *realm, *service, *sinstance;
+     int life;
+     int nostore_flag;
+     des_cblock ses;
+     int *lifetime;
+     int *kvno;
+     KTEXT tkt;
+     unsigned KRB_INT32 *t_local;
+ {
+    KTEXT_ST cip_st;
+    KTEXT cip = &cip_st;	/* Returned Ciphertext */
+    KTEXT_ST cip2_st;
+    KTEXT cip2 = &cip2_st;	/* Returned Ciphertext */
+    int k_errno;
+    static char version[] = "cnssnk01";
+    des_cblock key;
+    des_key_schedule ks;
+    char challenge1[8], challenge2[8];
+ 
+    /* Instance requested must end in +SNK4 */
+    /* Need better error to return */
+    if (strncmp(instance + (strlen(instance) - 5),
+                "+SNK4",
+                5))
+       return(INTK_ERR);
+ 
+    /* Get the ticket */
+    if (k_errno = krb_mk_in_tkt_preauth(user, instance, realm, 
+                                        service, sinstance,
+                                        life, (char*)0, 0, cip))
+    {
+       return(k_errno);
+    }
+    
+    if (memcmp (cip->dat, version, 8)) {
+       /* perhaps try the normal decrypt in this case? */
+       return(GT_PW_PROT);
+    }
+ 
+    /* Get the two challenges */
+    memcpy(challenge1, cip->dat+8, 8);
+    memcpy(challenge2, cip->dat+16, 8);
+ 
+    /* For the time being, dance around the get_in_tkt callbacks (which would
+       cause conflicts if used, due to snk_passwd_to_key interface change)
+ 
+       Just do the whole bit in this call.
+       */
+ 
+    snk_passwd_to_key(user,instance,realm,challenge1,challenge2,&key,&ks);
+ 
+    /* snk_decrypt_tkt */
+    des_key_sched(key,ks);
+    pcbc_encrypt((C_Block *)(cip->dat+24),(C_Block *)cip2->dat,
+                 (long) (cip->length-24),ks,(C_Block *)&key,0);
+    cip2->length = cip->length-24;
+ 
+    /* if this fails, perhaps the user should get another chance
+       at the input? */
+    if (nostore_flag)
+    {
+       /* Do not store the ticket, rather parse it, and return the result */
+       if (k_errno = krb_parse_only_in_tkt(user, instance, realm, service,
+                                           sinstance, life, cip2, ses,
+                                           &lifetime, &kvno, tkt, &t_local))
+         return(k_errno);
+    } else {
+       /* No ticket location supplied, just parse/store ticket as normal */
+       if (k_errno = krb_parse_in_tkt(user, instance, realm,
+                                      service, sinstance, life, cip2))
+       {
+          return(k_errno);
+       }
+    }
+ 
+    return(GT_PW_OK);
  }
  
  /* FIXME!  This routine belongs in the krb library and should simply
diff -cr cns-95q1.dist/usr/kerberos/src/src/lib/krb/rd_req.c cns-95q1.test/usr/kerberos/src/src/lib/krb/rd_req.c
*** cns-95q1.dist/usr/kerberos/src/src/lib/krb/rd_req.c	Mon Feb 13 09:06:01 1995
--- cns-95q1.test/usr/kerberos/src/src/lib/krb/rd_req.c	Sun Jun 25 21:53:18 1995
***************
*** 124,132 ****
      register KTEXT authent;	/* The received message */
      char *service;		/* Service name */
      char *instance;		/* Service instance */
!     long from_addr;		/* Net address of originating host */
      AUTH_DAT *ad;		/* Structure to be filled in */
      char *fn;			/* Filename to get keys from */
  {
      KTEXT_ST ticket;		/* Temp storage for ticket */
      KTEXT tkt = &ticket;
--- 124,146 ----
      register KTEXT authent;	/* The received message */
      char *service;		/* Service name */
      char *instance;		/* Service instance */
!     unsigned KRB_INT32 from_addr;	/* Net address of originating host */
      AUTH_DAT *ad;		/* Structure to be filled in */
      char *fn;			/* Filename to get keys from */
+ {
+     return
+ 	(krb_rd_req_zlifechk(authent,service,instance,from_addr,ad,fn,0));
+ }
+ 
+ int INTERFACE
+ krb_rd_req_zlifechk(authent,service,instance,from_addr,ad,fn,zflag)
+     register KTEXT authent;	/* The received message */
+     char *service;		/* Service name */
+     char *instance;		/* Service instance */
+     unsigned KRB_INT32 from_addr;	/* Net address of originating host */
+     AUTH_DAT *ad;		/* Structure to be filled in */
+     char *fn;			/* Filename to get keys from */
+     int zflag;			/* Zero lifetime is ok */
  {
      KTEXT_ST ticket;		/* Temp storage for ticket */
      KTEXT tkt = &ticket;
diff -cr cns-95q1.dist/usr/kerberos/src/src/lib/krb/rd_safe.c cns-95q1.test/usr/kerberos/src/src/lib/krb/rd_safe.c
*** cns-95q1.dist/usr/kerberos/src/src/lib/krb/rd_safe.c	Mon Feb 13 09:06:02 1995
--- cns-95q1.test/usr/kerberos/src/src/lib/krb/rd_safe.c	Sun Jun 25 21:53:19 1995
***************
*** 115,121 ****
      /* don't swap, net order always */
      p += sizeof(src_addr);
  
!     if (!krb_ignore_ip_address && src_addr != (u_long) sender->sin_addr.s_addr)
          return RD_AP_MODIFIED;
  
      /* safely get time_sec */
--- 115,122 ----
      /* don't swap, net order always */
      p += sizeof(src_addr);
  
!     if (!krb_ignore_ip_address &&
! 	src_addr != (unsigned KRB_INT32) sender->sin_addr.s_addr)
          return RD_AP_MODIFIED;
  
      /* safely get time_sec */
***************
*** 168,175 ****
      memcpy((char *)big_cksum, (char *)p, sizeof(big_cksum));
      if (swap_bytes) {
        /* swap_u_16(big_cksum); */
!       unsigned long tt, *bb;
!       bb = (unsigned long*)big_cksum;
        tt = bb[0]; swap_u_long(tt); bb[0] = tt;
        tt = bb[1]; swap_u_long(tt); bb[1] = tt;
        tt = bb[2]; swap_u_long(tt); bb[2] = tt;
--- 169,176 ----
      memcpy((char *)big_cksum, (char *)p, sizeof(big_cksum));
      if (swap_bytes) {
        /* swap_u_16(big_cksum); */
!       unsigned KRB_INT32 tt, *bb;
!       bb = (unsigned KRB_INT32 *)big_cksum;
        tt = bb[0]; swap_u_long(tt); bb[0] = tt;
        tt = bb[1]; swap_u_long(tt); bb[1] = tt;
        tt = bb[2]; swap_u_long(tt); bb[2] = tt;
diff -cr cns-95q1.dist/usr/kerberos/src/src/server/kerberos.c cns-95q1.test/usr/kerberos/src/src/server/kerberos.c
*** cns-95q1.dist/usr/kerberos/src/src/server/kerberos.c	Mon Feb 13 09:09:24 1995
--- cns-95q1.test/usr/kerberos/src/src/server/kerberos.c	Sun Jun 25 21:53:19 1995
***************
*** 552,557 ****
--- 552,559 ----
  		chall[1] %= 1000000;
  	      } while (chall[0] == chall[1]);
  
+ 	      if (lifetime == 0) chall[1] = chall[0];
+ 
  	      for (i = 0; i<2; i++) {
  		/* 6 digits, a zero, and the trailing zero make 8 */
  		sprintf(challenge[i], "%6.6u%c", chall[i], 0);
diff -c /dev/null cns-95q1.test/usr/kerberos/src/src/lib/krb/v_pw_in_tkt.c
*** /dev/null	Sun Jun 25 22:33:37 1995
--- cns-95q1.test/usr/kerberos/src/src/lib/krb/v_pw_in_tkt.c	Sun Jun 25 21:57:41 1995
***************
*** 0 ****
--- 1,116 ----
+ /*
+  * v_pw_in_tkt.c
+  *
+  */
+ 
+ #include "mit-copyright.h"
+ #include "krb.h"
+ #include "prot.h"
+ 
+ #include <string.h>
+ 
+ /* This routine verifies a password as good proven via kerberos.
+ 
+      Sometimes I have several users coming from non-kerberos systems.  The
+      wish to authenticate, but it is only for the purpose of using the
+      service on that machine.  Tickets, especially a kerberos ticket
+      granting ticket, slows down processing.  It also either creates
+      contention for a ticket file, or requires cleverness in avoiding using
+      a ticket file.
+ 
+      There are cases where I'd like to use zero lifetime tickets, in order
+      to have a single challenge/response be adequate for an SNK
+      authentication.
+ 
+      There are also times, when I'd just as soon not have tickets after a
+      ksu, as I'm not going to be doing anything with them.  Of course, I
+      could just kdestroy after every ksu, but that seems inefficient to
+      store something just for it to be deleted.  Skip the storing step.
+ 
+      This is done by:
+ 
+      obtain tickets (zero lifetime) for given service
+       do not save credentials, rather only use them for next step
+      do the equivalent of krb_rd_req, but not worrying about the expiry
+       (the times are still checked, so no one's going to be reusing tickets
+       becuase of this)
+      */
+ 
+ int krb_snk_vfy_pw_in_tkt(user,instance,realm,service,sinstance)
+     char *user, *instance, *realm, *service, *sinstance;
+ {
+    int k_errno;
+    AUTH_DAT ad;
+    KTEXT_ST tkt_st;
+    KTEXT tkt = &tkt_st;
+    des_cblock ses;
+    int lifetime;
+    int kvno = 0;
+    unsigned KRB_INT32 t_local;
+    KRB_INT32 delta_t;      	/* Time in authenticator minus local time */
+    unsigned char skey[KKEY_SZ]; /* Session key from ticket */
+    des_cblock ky;
+    Key_schedule ks;
+    char tkt_service[SNAME_SZ];
+    char tkt_instance[INST_SZ];
+ 
+    /* Step one: user.instance@realm into authenticator for
+                 service.sintance@realm with 0 lifetime */
+ 
+    /* We'll be comparing the time kerberos gives us with the local time
+       later.  The time kerberos gives out is the time of the request
+       response.  The user will be dallying around with the password/SNK
+       response for a minute or two, which is why we get the time for
+       comparison now.
+       */
+ 
+    t_local = TIME_GMT_UNIXSEC;
+ 
+    if (k_errno = krb_snk_get_pw_in_tkt_tkt(user, instance, realm, service,
+                                            sinstance, (int) 0,
+                                            1, ses, &lifetime, &kvno, tkt,
+                                            &t_local))
+       return(k_errno);
+    
+ 
+    /* Step two: check if authenticator matches what's on this server.
+        This prevents kerberos spoofage.
+        Zero lifetime is ok on this request.  */
+ 
+    /* Get local service key. */
+ #ifndef NOENCRYPTION
+    if (read_service_key(service,sinstance,realm,(int) kvno,
+                         KEYFILE, (char *) ky))
+       return(RD_AP_UNDEC);
+    des_key_sched(ky, ks);
+    if (decomp_ticket(tkt,&ad.k_flags,ad.pname,ad.pinst,ad.prealm,
+                      &(ad.address),ad.session, &(ad.life),
+                      &(ad.time_sec),
+                      tkt_service, tkt_instance,
+                      ky,ks)) {
+       return(RD_AP_UNDEC);
+    }
+ #endif /* !NOENCRYPTION */
+ 
+    /* Verify that the bits in the authenticator are what they should be. */
+    if (strcmp(ad.pname, user) || strcmp(ad.pinst, instance) ||
+        strcmp(ad.prealm, realm) || (ad.life != 0))
+       return(INTK_ERR);
+ 
+    /* check the time integrity of the msg */
+    delta_t = t_local - ad.time_sec;
+    if (delta_t < 0) delta_t = -delta_t;  /* Absolute value of difference */
+    if (delta_t > CLOCK_SKEW) {
+         return(RD_AP_TIME);
+     }
+ 
+    /* Do not check expiry, as this is a zero lifetime ticket we just
+       obtained.  If this ticket is attempted to be reused on us, the times
+       won't match above.  The zero ticket lifetime makes this ticket useless
+       if cracked.  */
+ 
+    /* Also not checking IP addr, as we made the request right here. */
+    /*  any value in checking in case someone tries to play games ? */
+ 
+    return(INTK_OK);
+ }

>Audit-Trail:

Responsible-Changed-From-To: prms-admin->eichin
Responsible-Changed-By: brendan
Responsible-Changed-When: Tue Jun 27 16:20:07 1995
Responsible-Changed-Why:
Kerberos

State-Changed-From-To: open-analyzed
State-Changed-By: eichin
State-Changed-When: Tue Jun 27 19:39:41 1995
State-Changed-Why:

Very interesting set of changes, in particular the changes to
ksu. Thank you in particular for the detailed explanation of the
reasoning behind them; that simplifies my evaluation greatly.

I believe the alpha-specific problems have already been addressed in
our sources, in the same way you've suggested (using unsigned
KRB_INT32 in the interface.)

I'll have further comments later.

>Unformatted:
