[6419] in Kerberos

home help back first fref pref prev next nref lref last post

Re: Kerberos 5-B4-pl3 bug report (lib/krb5/os/localaddr.c)

daemon@ATHENA.MIT.EDU (Craig Leres)
Tue Jan 2 01:24:38 1996

To: kerberos@MIT.EDU
Date: 2 Jan 1996 06:12:13 GMT
From: leres@ell.ee.lbl.gov (Craig Leres)

------- Forwarded Message

Date: Mon, 01 Jan 96 22:08:57 PST
From: Craig Leres <leres>
Subject: Kerberos 5-B4-pl3 bug report (lib/krb5/os/localaddr.c)
To: krb5-bugs@athena.mit.edu

The routine krb5_os_localaddr() returns only one address when running
under 4.4 BSD or BSDI; if the first interface is not configured, it
return no addresses. I ran into the latter case which caused k5init to
fail with "Incorrect net address while getting initial credentials."

I imported some code from our libpcap package that works under BSDI 2
and SunOS 4. It behaves the same as the old code for most systems but
handles the variable length addresses found in newer 4 BSD based systems.

The new localaddr.c source is appended.

		Craig
------
/*
 * lib/krb5/os/localaddr.c
 *
 * Copyright 1990,1991 by the Massachusetts Institute of Technology.
 * All Rights Reserved.
 *
 * Export of this software from the United States of America may
 *   require a specific license from the United States Government.
 *   It is the responsibility of any person or organization contemplating
 *   export to obtain such a license before exporting.
 * 
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 * distribute this software and its documentation for any purpose and
 * without fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation, and that
 * the name of M.I.T. not be used in advertising or publicity pertaining
 * to distribution of the software without specific, written prior
 * permission.  M.I.T. makes no representations about the suitability of
 * this software for any purpose.  It is provided "as is" without express
 * or implied warranty.
 * 
 *
 * Return the protocol addresses supported by this host.
 *
 * XNS support is untested, but "Should just work".
 */


#include <krb5/krb5.h>
#include <krb5/osconf.h>

#include <krb5/ext-proto.h>

/* needed for solaris, harmless elsewhere... */
#define BSD_COMP
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <net/route.h>
#ifndef SOLARIS
#include <sys/mbuf.h>
#endif
#include <net/if.h>
#include <errno.h>

/*
 * The SIOCGIF* ioctls require a socket.
 * It doesn't matter *what* kind of socket they use, but it has to be
 * a socket.
 *
 * Of course, you can't just ask the kernel for a socket of arbitrary
 * type; you have to ask for one with a valid type.
 *
 */
#ifdef KRB5_USE_INET

#include <netinet/in.h>

#ifndef USE_AF
#define USE_AF AF_INET
#define USE_TYPE SOCK_DGRAM
#define USE_PROTO 0
#endif

#endif

#ifdef KRB5_USE_NS

#include <netns/ns.h>

#ifndef USE_AF
#define USE_AF AF_NS
#define USE_TYPE SOCK_DGRAM
#define USE_PROTO 0		/* guess */
#endif

#endif
/*
 * Add more address families here.
 */

extern int errno;

/*
 * Return all the protocol addresses of this host.
 *
 * We could kludge up something to return all addresses, assuming that
 * they're valid kerberos protocol addresses, but we wouldn't know the
 * real size of the sockaddr or know which part of it was actually the
 * host part.
 *
 * This uses the SIOCGIFCONF, SIOCGIFFLAGS, and SIOCGIFADDR ioctl's.
 */

krb5_error_code krb5_os_localaddr(addr)
    krb5_address ***addr;
{
    register struct ifreq *ifr, *ifend, *ifnext;
    struct ifconf ifc;
    int s, code, n, i;
    char buf[1024];
    krb5_address *addr_temp[sizeof(buf) / sizeof(struct ifreq)];
    int n_found;
    int mem_err = 0;
    
    ifc.ifc_len = sizeof(buf);
    ifc.ifc_buf = buf;

    s = socket (USE_AF, USE_TYPE, USE_PROTO);
    if (s < 0)
	return errno;

    code = ioctl (s, SIOCGIFCONF, (char *)&ifc);
    if (code < 0) {
	int retval = errno;
	close(s);
	return retval;
    }
    
    ifr = (struct ifreq *)buf;
    ifend = (struct ifreq *)(buf + ifc.ifc_len);
    for (n_found=0; ifr < ifend && !mem_err; ifr = ifnext) {
	krb5_address *address;

#if BSD - 0 >= 199006
	n = ifr->ifr_addr.sa_len + sizeof(ifr->ifr_name);
	if (n < sizeof(*ifr))
	    ifnext = ifr + 1;
	else
	    ifnext = (struct ifreq *)((char *)ifr + n);
#else
	ifnext = ifr + 1;
#endif

	if (ioctl (s, SIOCGIFFLAGS, (char *)ifr) < 0)
	    continue;

#ifdef IFF_LOOPBACK
	if (ifr->ifr_flags & IFF_LOOPBACK) 
	    continue;
#endif

	if (!(ifr->ifr_flags & IFF_UP)) 
	    /* interface is down; skip */
	    continue;

	if (ioctl (s, SIOCGIFADDR, (char *)ifr) < 0)
	    /* can't get address */
	    continue;

	/* ifr->ifr_addr has what we want! */
	switch (ifr->ifr_addr.sa_family) {
#ifdef KRB5_USE_INET
	case AF_INET:
	    {
		struct sockaddr_in *in =
		    (struct sockaddr_in *)&ifr->ifr_addr;
		
		address = (krb5_address *)
		    malloc (sizeof(krb5_address));
		if (address) {
		    address->addrtype = ADDRTYPE_INET;
		    address->length = sizeof(struct in_addr);
		    address->contents = (unsigned char *)malloc(address->length
);
		    if (!address->contents) {
			krb5_xfree(address);
			address = 0;
			mem_err++;
		    } else {
			memcpy ((char *)address->contents,
				(char *)&in->sin_addr, 
				address->length);
			break;
		    }
		} else mem_err++;
	    }
#endif
#ifdef KRB5_USE_NS
	    case AF_XNS:
	    {  
		struct sockaddr_ns *ns =
		    (struct sockaddr_ns *)&ifr->ifr_addr;		    
		address = (krb5_address *)
		    malloc (sizeof (krb5_address) + sizeof (struct ns_addr));
		if (address) {
		    address->addrtype = ADDRTYPE_XNS; 

		    /* XXX should we perhaps use ns_host instead? */

		    address->length = sizeof(struct ns_addr);
		    address->contents = (unsigned char *)malloc(address->length
);
		    if (!address->contents) {
			krb5_xfree(address);
			address = 0;
			mem_err++;
		    } else {
			memcpy ((char *)address->contents,
				(char *)&ns->sns_addr,
				address->length);
			break;
		    }
		} else mem_err++;
		break;
	    }
#endif
	/*
	 * Add more address families here..
	 */
	default:
	    continue;
	}
	if (address)
	    addr_temp[n_found++] = address;
	address = 0;
    }
    close(s);

    *addr = (krb5_address **)malloc (sizeof (krb5_address *) * (n_found+1));
    if (*addr == 0)
	mem_err++;
    
    if (mem_err) {
	for (i=0; i<n_found; i++) {
	    krb5_xfree(addr_temp[i]);
	    addr_temp[i] = 0;
	}
	return ENOMEM;
    }
    
    for (i=0; i<n_found; i++) {
	(*addr)[i] = addr_temp[i];
    }
    (*addr)[n_found] = 0;
    return 0;
}

------- End of Forwarded Message

home help back first fref pref prev next nref lref last post