From hhui@disperse.arcfour.com  Thu Jan 16 11:05:01 1997
Received: from disperse.arcfour.com (disperse.arcfour.com [207.176.50.17])
          by freefall.freebsd.org (8.8.4/8.8.4) with ESMTP id LAA06767
          for <FreeBSD-gnats-submit@freebsd.org>; Thu, 16 Jan 1997 11:05:00 -0800 (PST)
Received: (from hhui@localhost)
  by disperse.arcfour.com (ArcFour-8.8.3) id OAA11986;
  ; Thu, 16 Jan 1997 14:04:42 -0500 (EST)
Message-Id: <199701161904.OAA11986@disperse.arcfour.com>
Date: Thu, 16 Jan 1997 14:04:42 -0500 (EST)
From: Hui-Hui Hu <hhui@bluemountainarts.com>
Reply-To: hhui@bluemountainarts.com
To: FreeBSD-gnats-submit@freebsd.org
Subject: kerberos does not support multihomed hosts
X-Send-Pr-Version: 3.2

>Number:         2508
>Category:       bin
>Synopsis:       kerberos does not support multihomed hosts
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Jan 16 11:10:04 PST 1997
>Closed-Date:    Sun May 31 12:21:23 PDT 1998
>Last-Modified:  Sun May 31 12:22:13 PDT 1998
>Originator:     Hui-Hui Hu
>Release:        FreeBSD 2.2-ALPHA i386
>Organization:
Arc Four
>Environment:

	kerberos IV / eBones  (by the way, I tried 3.0-current krb libs also)
        server is running two IP addresses

>Description:

	a ticket read request will often fail over a multihomed
        server host because kerberos will check the ticket address 
        and if the first interface address the system returns is
        different from the outgoing packet then it will generate a 
        "Incorrect network address" (RD_AP_BADD). this is contrary to
        the specification, which says:

'Incorrect network address' 
      The address in the ticket does not match the address you sent the 
      request from. This happens on systems with more than one network 
      address, either physically or logically. You can list addresses which
      should be considered equal in `/etc/krb.equiv' on your servers. 

        the line in rd_req.c (libkrb.a) is:

    if (from_addr && (ad->address != from_addr))

        which does not take in account more than one interface.

>How-To-Repeat:

        configure two interfaces, with the non-default interface
        ("internal lan") being the first one that the kernel will return.
        then try to authenticate yourself.

>Fix:
	
	a very bad fix is to comment out the line return (RD_AP_BADD)
        in rd_req.c. Obviously this kind of destroys a lot of authentication.
        The proper solution would be to implement a krb.equiv file
        for multihomed server hosts. That would be really, really appreciated.
        Maybe I'll work on it if I get bored some day. :)
 
>Release-Note:
>Audit-Trail:

From: Hui-Hui Hu <hhui@arcfour.com>
To: FreeBSD-gnats@freefall.freebsd.org, freebsd-bugs@freefall.freebsd.org
Cc:  Subject: Re: bin/2508: kerberos does not support multihomed hosts 
Date: Thu, 16 Jan 1997 15:28:06 -0500

 Sorry to follow up on my own message. But I have a context diff that will
 patch eBones to utilize the "krb.equiv" file. I can't claim credit for the
 source code, just for backporting it into the existing distribution.
 It's based on the Kerberos port at KTH, Sweden
 (http://www.pdc.kth.se/kth-krb) version 0.9.
 
 krb.equiv is a file listing equivalent IPs e.g. 192.23.45.6 205.23.45.6
 
 Would be great if this could be merged into the distribution (or something
 equivalent).
 
 Thanks.
 
 -Tung-Hui Hu
 hhui@arcfour.com
 
 *** old/include/krb.h	Sun Feb 11 04:41:57 1996
 --- new/include/krb.h	Thu Jan 16 14:39:49 1997
 ***************
 *** 62,70 ****
   
   #define		KRB_CONF	"/etc/kerberosIV/krb.conf"
   #define		KRB_RLM_TRANS	"/etc/kerberosIV/krb.realms"
   #define		KRB_MASTER	"kerberos"
   #define		KRB_HOST	KRB_MASTER
   #define		KRB_REALM	"ATHENA.MIT.EDU"
   
   /* The maximum sizes for aname, realm, sname, and instance +1 */
   #define 	ANAME_SZ	40
 --- 62,71 ----
   
   #define		KRB_CONF	"/etc/kerberosIV/krb.conf"
   #define		KRB_RLM_TRANS	"/etc/kerberosIV/krb.realms"
 + #define		KRB_EQUIV	"/etc/kerberosIV/krb.equiv"
   #define		KRB_MASTER	"kerberos"
   #define		KRB_HOST	KRB_MASTER
   #define		KRB_REALM	"ATHENA.MIT.EDU"
   
   /* The maximum sizes for aname, realm, sname, and instance +1 */
   #define 	ANAME_SZ	40
 ***************
 *** 494,499 ****
 --- 495,501 ----
   int k_isrealm __P((char *s));
   int k_isname __P((char *s));
   int k_gethostname __P((char *name, int namelen));
 + int krb_equiv __P((u_long, u_long));
   int kerb_init __P((void));
   void kerb_fini __P((void));
   int kerb_db_set_name __P((char *name));
 *** old/lib/libkrb/rd_req.c	Thu Sep  7 17:38:26 1995
 --- new/lib/libkrb/rd_req.c	Thu Jan 16 15:14:19 1997
 ***************
 *** 298,304 ****
   
       if (krb_ap_req_debug)
           log("Address: %d %d",ad->address,from_addr);
 !     if (from_addr && (ad->address != from_addr))
           return(RD_AP_BADD);
   
       (void) gettimeofday(&t_local,(struct timezone *) 0);
 --- 298,304 ----
   
       if (krb_ap_req_debug)
           log("Address: %d %d",ad->address,from_addr);
 !     if (from_addr && (!krb_equiv(ad->address, from_addr))) 
           return(RD_AP_BADD);
   
       (void) gettimeofday(&t_local,(struct timezone *) 0);
 *** old/lib/libkrb/rd_safe.c	Thu Sep  7 17:38:27 1995
 --- new/lib/libkrb/rd_safe.c	Thu Jan 16 15:16:50 1997
 ***************
 *** 126,132 ****
       /* don't swap, net order always */
       p += sizeof(src_addr);
   
 !     if (src_addr != (u_long) sender->sin_addr.s_addr)
           return RD_AP_MODIFIED;
   
       /* safely get time_sec */
 --- 126,132 ----
       /* don't swap, net order always */
       p += sizeof(src_addr);
   
 !     if (!krb_equiv(src_addr, sender->sin_addr.s_addr))
           return RD_AP_MODIFIED;
   
       /* safely get time_sec */
 *** old/lib/libkrb/rd_priv.c	Thu Sep  7 17:38:26 1995
 --- new/lib/libkrb/rd_priv.c	Thu Jan 16 15:17:14 1997
 ***************
 *** 146,152 ****
       /* don't swap, net order always */
       p += sizeof(src_addr);
   
 !     if (src_addr != (u_long) sender->sin_addr.s_addr)
   	return RD_AP_MODIFIED;
   
       /* safely get time_sec */
 --- 146,152 ----
       /* don't swap, net order always */
       p += sizeof(src_addr);
   
 !     if (!krb_equiv(src_addr, sender->sin_addr.s_addr))
   	return RD_AP_MODIFIED;
   
       /* safely get time_sec */
 diff -c -N old/lib/libkrb/Makefile new/lib/libkrb/Makefile
 *** old/lib/libkrb/Makefile	Thu Jan 16 15:20:12 1997
 --- new/lib/libkrb/Makefile	Thu Jan 16 15:14:51 1997
 ***************
 *** 10,16 ****
   	get_admhst.c get_cred.c get_in_tkt.c get_krbhst.c get_krbrlm.c \
   	get_phost.c get_pw_tkt.c get_request.c get_svc_in_tkt.c \
   	get_tf_fullname.c get_tf_realm.c getrealm.c getst.c in_tkt.c \
 ! 	k_gethostname.c klog.c kname_parse.c kntoln.c kparse.c \
   	krb_err_txt.c krb_get_in_tkt.c kuserok.c log.c mk_err.c \
   	mk_priv.c mk_req.c mk_safe.c month_sname.c \
   	netread.c netwrite.c one.c pkt_cipher.c pkt_clen.c rd_err.c \
 --- 10,16 ----
   	get_admhst.c get_cred.c get_in_tkt.c get_krbhst.c get_krbrlm.c \
   	get_phost.c get_pw_tkt.c get_request.c get_svc_in_tkt.c \
   	get_tf_fullname.c get_tf_realm.c getrealm.c getst.c in_tkt.c \
 ! 	k_gethostname.c krb_equiv.c klog.c kname_parse.c kntoln.c kparse.c \
   	krb_err_txt.c krb_get_in_tkt.c kuserok.c log.c mk_err.c \
   	mk_priv.c mk_req.c mk_safe.c month_sname.c \
   	netread.c netwrite.c one.c pkt_cipher.c pkt_clen.c rd_err.c \
 diff -c -N old/lib/libkrb/krb_equiv.c new/lib/libkrb/krb_equiv.c
 *** old/lib/libkrb/krb_equiv.c	Wed Dec 31 19:00:00 1969
 --- new/lib/libkrb/krb_equiv.c	Thu Jan 16 15:18:24 1997
 ***************
 *** 0 ****
 --- 1,116 ----
 + /*
 +  * int krb_equiv(u_int32_t ipaddr_a, u_int32_t ipaddr_b);
 +  *
 +  * Given two IP adresses return true if they match
 +  * or are considered to belong to the same host.
 +  *
 +  * For example if /etc/krb.equiv looks like
 +  *
 +  *    130.237.223.3   192.16.126.3    # alv alv1
 +  *    130.237.223.4   192.16.126.4    # byse byse1
 +  *    130.237.228.152 192.16.126.9    # topsy topsy1
 +  *
 +  * krb_equiv(alv, alv1) would return true but
 +  * krb_equiv(alv, byse1) would not.
 +  *
 +  * A comment starts with an '#' and ends with '\n'.
 +  *
 +  */
 + #if 0
 + #ifndef lint
 + static char rcsid[] =
 + "$Id: krb_equiv.c,v 1.9 1996/03/25 13:09:37 bg Exp $";
 + #endif  lint
 + #endif
 + 
 + #include <stdlib.h>
 + #include <stdio.h>
 + #include <sys/types.h>
 + #include <krb.h>
 + #include <string.h>
 + 
 + 
 + int krb_ignore_ip_address = 0;
 + 
 + int
 + krb_equiv(u_long a, u_long b)
 + {
 +   FILE *fil;
 +   char line[256];
 +   int hit_a, hit_b;
 +   int iscomment;
 +   
 +   if (a == b)			/* trivial match, also the common case */
 +     return 1;
 +   
 +   if (krb_ignore_ip_address)
 +     return 1;			/* if we have decided not to compare */
 + 
 +   a = ntohl(a);
 +   b = ntohl(b);
 + 
 +   fil = fopen(KRB_EQUIV, "r");
 +   if (fil == NULL)		/* open failed */
 +     return 0;
 +   
 +   hit_a = hit_b = 0;
 +   iscomment = 0;
 +   while (fgets(line, sizeof(line)-1, fil) != NULL) /* for each line */
 +     {
 +       char *t = line;
 +       int len = strlen(t);
 +       
 +       /* for each item on this line */
 +       while (*t != 0)		/* more addresses on this line? */
 + 	if (*t == '\n') {
 + 	  iscomment = hit_a = hit_b = 0;
 + 	  break;
 + 	} else if (iscomment)
 + 	  t = line + len - 1;
 + 	else if (*t == '#') {		/* rest is comment */
 + 	  iscomment = 1;
 + 	  ++t;
 + 	} else if (*t == '\\' ) /* continuation */
 + 	  break;
 + 	else if (isspace(*t))	/* skip space */
 + 	  t++;
 + 	else if (isdigit(*t))	/* an address? */
 + 	  {
 + 	    u_int32_t tmp;
 + 	    u_int32_t tmpa, tmpb, tmpc, tmpd;
 + 	    
 + 	    sscanf(t, "%d.%d.%d.%d", &tmpa, &tmpb, &tmpc, &tmpd);
 + 	    tmp = (tmpa << 24) | (tmpb << 16) | (tmpc << 8) | tmpd;
 + 
 + 	    while (*t == '.' || isdigit(*t)) /* done with this address */
 + 	      t++;
 + 
 + 	    if (tmp != -1) {	/* an address (and not broadcast) */
 + 	      u_long mask = ~0;
 + 
 + 	      if (*t == '/') {
 + 		++t;
 + 		mask <<= 32 - atoi(t);
 + 
 + 		while(isdigit(*t))
 + 		  ++t;
 + 	      }
 + 
 + 	      if ((tmp & mask) == (a & mask))
 + 		hit_a = 1;
 + 	      if ((tmp & mask) == (b & mask))
 + 		hit_b = 1;
 + 	      if (hit_a && hit_b) {
 + 		fclose(fil);
 + 		return 1;
 + 	      }
 + 	    }
 + 	  }
 + 	else
 + 	  ++t;		/* garbage on this line, skip it */
 + 
 +     }
 + 
 +   fclose(fil);
 +   return 0;
 + }
 
State-Changed-From-To: open->closed 
State-Changed-By: steve 
State-Changed-When: Sun May 31 12:21:23 PDT 1998 
State-Changed-Why:  
This was fixed by Mark Murray in one of his recent batches 
of commits. 
>Unformatted:
