17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
5*1da57d55SToomas Soome 
67c478bd9Sstevel@tonic-gate /*
77c478bd9Sstevel@tonic-gate  * include/foreachaddr.c
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * Copyright 1990,1991,2000,2001,2002 by the Massachusetts Institute of Technology.
107c478bd9Sstevel@tonic-gate  * All Rights Reserved.
117c478bd9Sstevel@tonic-gate  *
127c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
137c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
147c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
157c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
16*1da57d55SToomas Soome  *
177c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
187c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
197c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
207c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
217c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
227c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
237c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
247c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
257c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
267c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
277c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
287c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
297c478bd9Sstevel@tonic-gate  * or implied warranty.
30*1da57d55SToomas Soome  *
317c478bd9Sstevel@tonic-gate  *
327c478bd9Sstevel@tonic-gate  * Iterate over the protocol addresses supported by this host, invoking
337c478bd9Sstevel@tonic-gate  * a callback function or three supplied by the caller.
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  * XNS support is untested, but "should just work".  (Hah!)
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /* This is the primary "export" of this file.  It's a static function,
397c478bd9Sstevel@tonic-gate    so this file must be #included in the .c file containing the
407c478bd9Sstevel@tonic-gate    caller.
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate    This function iterates over all the addresses it can find for the
437c478bd9Sstevel@tonic-gate    local system, in one or two passes.  In each pass, and between the
447c478bd9Sstevel@tonic-gate    two, it can invoke callback functions supplied by the caller.  The
457c478bd9Sstevel@tonic-gate    two passes should operate on the same information, though not
467c478bd9Sstevel@tonic-gate    necessarily in the same order each time.  Duplicate and local
477c478bd9Sstevel@tonic-gate    addresses should be eliminated.  Storage passed to callback
487c478bd9Sstevel@tonic-gate    functions should not be assumed to be valid after foreach_localaddr
497c478bd9Sstevel@tonic-gate    returns.
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate    The int return value is an errno value (XXX or krb5_error_code
527c478bd9Sstevel@tonic-gate    returned for a socket error) if something internal to
537c478bd9Sstevel@tonic-gate    foreach_localaddr fails.  If one of the callback functions wants to
547c478bd9Sstevel@tonic-gate    indicate an error, it should store something via the 'data' handle.
557c478bd9Sstevel@tonic-gate    If any callback function returns a non-zero value,
567c478bd9Sstevel@tonic-gate    foreach_localaddr will clean up and return immediately.
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate    Multiple definitions are provided below, dependent on various
597c478bd9Sstevel@tonic-gate    system facilities for extracting the necessary information.  */
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate /* Solaris Kerberos: changing foreach_localaddr to non-static as it's called in
627c478bd9Sstevel@tonic-gate  * a couple places.
637c478bd9Sstevel@tonic-gate  */
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate #ifdef TEST
667c478bd9Sstevel@tonic-gate # define Tprintf(X) printf X
677c478bd9Sstevel@tonic-gate # define Tperror(X) perror(X)
687c478bd9Sstevel@tonic-gate #else
697c478bd9Sstevel@tonic-gate # define Tprintf(X) (void) X
707c478bd9Sstevel@tonic-gate # define Tperror(X) (void)(X)
717c478bd9Sstevel@tonic-gate #endif
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate  * The SIOCGIF* ioctls require a socket.
757c478bd9Sstevel@tonic-gate  * It doesn't matter *what* kind of socket they use, but it has to be
767c478bd9Sstevel@tonic-gate  * a socket.
777c478bd9Sstevel@tonic-gate  *
787c478bd9Sstevel@tonic-gate  * Of course, you can't just ask the kernel for a socket of arbitrary
797c478bd9Sstevel@tonic-gate  * type; you have to ask for one with a valid type.
807c478bd9Sstevel@tonic-gate  *
817c478bd9Sstevel@tonic-gate  */
827c478bd9Sstevel@tonic-gate #ifdef HAVE_NETINET_IN_H
837c478bd9Sstevel@tonic-gate #include <netinet/in.h>
847c478bd9Sstevel@tonic-gate #ifndef USE_AF
857c478bd9Sstevel@tonic-gate #define USE_AF AF_INET
867c478bd9Sstevel@tonic-gate #define USE_TYPE SOCK_DGRAM
877c478bd9Sstevel@tonic-gate #define USE_PROTO 0
887c478bd9Sstevel@tonic-gate #endif
897c478bd9Sstevel@tonic-gate #endif
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate #ifdef KRB5_USE_NS
927c478bd9Sstevel@tonic-gate #include <netns/ns.h>
937c478bd9Sstevel@tonic-gate #ifndef USE_AF
947c478bd9Sstevel@tonic-gate #define USE_AF AF_NS
957c478bd9Sstevel@tonic-gate #define USE_TYPE SOCK_DGRAM
967c478bd9Sstevel@tonic-gate #define USE_PROTO 0		/* guess */
977c478bd9Sstevel@tonic-gate #endif
987c478bd9Sstevel@tonic-gate #endif
997c478bd9Sstevel@tonic-gate /*
1007c478bd9Sstevel@tonic-gate  * Add more address families here.
1017c478bd9Sstevel@tonic-gate  */
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate #include <errno.h>
1047c478bd9Sstevel@tonic-gate #include <fake-addrinfo.h>
1057c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
1067c478bd9Sstevel@tonic-gate #include <k5-int.h>
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate /*
1097c478bd9Sstevel@tonic-gate  * Return all the protocol addresses of this host.
1107c478bd9Sstevel@tonic-gate  *
1117c478bd9Sstevel@tonic-gate  * We could kludge up something to return all addresses, assuming that
1127c478bd9Sstevel@tonic-gate  * they're valid kerberos protocol addresses, but we wouldn't know the
1137c478bd9Sstevel@tonic-gate  * real size of the sockaddr or know which part of it was actually the
1147c478bd9Sstevel@tonic-gate  * host part.
1157c478bd9Sstevel@tonic-gate  *
1167c478bd9Sstevel@tonic-gate  * This uses the SIOCGIFCONF, SIOCGIFFLAGS, and SIOCGIFADDR ioctl's.
1177c478bd9Sstevel@tonic-gate  */
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate /*
1207c478bd9Sstevel@tonic-gate  * BSD 4.4 defines the size of an ifreq to be
1217c478bd9Sstevel@tonic-gate  * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
122*1da57d55SToomas Soome  * However, under earlier systems, sa_len isn't present, so the size is
1237c478bd9Sstevel@tonic-gate  * just sizeof(struct ifreq).
1247c478bd9Sstevel@tonic-gate  */
1257c478bd9Sstevel@tonic-gate #ifdef HAVE_SA_LEN
1267c478bd9Sstevel@tonic-gate #ifndef max
1277c478bd9Sstevel@tonic-gate #define max(a,b) ((a) > (b) ? (a) : (b))
1287c478bd9Sstevel@tonic-gate #endif
1297c478bd9Sstevel@tonic-gate #define ifreq_size(i) max(sizeof(struct ifreq),\
1307c478bd9Sstevel@tonic-gate      sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
1317c478bd9Sstevel@tonic-gate #else
1327c478bd9Sstevel@tonic-gate #define ifreq_size(i) sizeof(struct ifreq)
1337c478bd9Sstevel@tonic-gate #endif /* HAVE_SA_LEN*/
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate #ifdef SIOCGLIFCONF /* Solaris */
1377c478bd9Sstevel@tonic-gate static int
get_lifconf(int af,int s,size_t * lenp,char * buf)1387c478bd9Sstevel@tonic-gate get_lifconf (int af, int s, size_t *lenp, char *buf)
1397c478bd9Sstevel@tonic-gate     /*@modifies *buf,*lenp@*/
1407c478bd9Sstevel@tonic-gate {
1417c478bd9Sstevel@tonic-gate     int ret;
1427c478bd9Sstevel@tonic-gate     struct lifconf lifc;
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate     lifc.lifc_family = af;
1457c478bd9Sstevel@tonic-gate     lifc.lifc_flags = 0;
1467c478bd9Sstevel@tonic-gate     lifc.lifc_len = *lenp;
1477c478bd9Sstevel@tonic-gate     lifc.lifc_buf = buf;
1487c478bd9Sstevel@tonic-gate     memset(buf, 0, *lenp);
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate     ret = ioctl (s, SIOCGLIFCONF, (char *)&lifc);
1517c478bd9Sstevel@tonic-gate     if (ret)
1527c478bd9Sstevel@tonic-gate 	Tperror ("SIOCGLIFCONF");
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate     *lenp = lifc.lifc_len;
1557c478bd9Sstevel@tonic-gate     return ret;
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate #endif
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate /* Return value is errno if internal stuff failed, otherwise zero,
1607c478bd9Sstevel@tonic-gate    even in the case where a called function terminated the iteration.
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate    If one of the callback functions wants to pass back an error
1637c478bd9Sstevel@tonic-gate    indication, it should do it via some field pointed to by the DATA
1647c478bd9Sstevel@tonic-gate    argument.  */
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate int
foreach_localaddr(void * data,int (* pass1fn)(void *,struct sockaddr *),int (* betweenfn)(void *),int (* pass2fn)(void *,struct sockaddr *))1677c478bd9Sstevel@tonic-gate foreach_localaddr (void *data,
1687c478bd9Sstevel@tonic-gate 		   int (*pass1fn) (void *, struct sockaddr *),
1697c478bd9Sstevel@tonic-gate 		   int (*betweenfn) (void *),
1707c478bd9Sstevel@tonic-gate 		   int (*pass2fn) (void *, struct sockaddr *))
1717c478bd9Sstevel@tonic-gate {
1727c478bd9Sstevel@tonic-gate     /* Okay, this is kind of odd.  We have to use each of the address
1737c478bd9Sstevel@tonic-gate        families we care about, because with an AF_INET socket, extra
1747c478bd9Sstevel@tonic-gate        interfaces like hme0:1 that have only AF_INET6 addresses will
1757c478bd9Sstevel@tonic-gate        cause errors.  Similarly, if hme0 has more AF_INET addresses
1767c478bd9Sstevel@tonic-gate        than AF_INET6 addresses, we won't be able to retrieve all of
1777c478bd9Sstevel@tonic-gate        the AF_INET addresses if we use an AF_INET6 socket.  Since
1787c478bd9Sstevel@tonic-gate        neither family is guaranteed to have the greater number of
1797c478bd9Sstevel@tonic-gate        addresses, we should use both.
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate        If it weren't for this little quirk, we could use one socket of
1827c478bd9Sstevel@tonic-gate        any type, and ask for addresses of all types.  At least, it
1837c478bd9Sstevel@tonic-gate        seems to work that way.  */
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate     /* Solaris kerberos: avoid using AF_NS if no define */
1867c478bd9Sstevel@tonic-gate #if defined (KRB5_USE_INET6) && defined (KRB5_USE_NS)
1877c478bd9Sstevel@tonic-gate     static const int afs[] = { AF_INET, AF_NS, AF_INET6 };
1887c478bd9Sstevel@tonic-gate #elif defined (KRB5_USE_INET6)
1897c478bd9Sstevel@tonic-gate     static const int afs[] = { AF_INET, AF_INET6 };
1907c478bd9Sstevel@tonic-gate #else
1917c478bd9Sstevel@tonic-gate     static const int afs[] = { AF_INET };
1927c478bd9Sstevel@tonic-gate #endif
193*1da57d55SToomas Soome 
1947c478bd9Sstevel@tonic-gate #define N_AFS (sizeof (afs) / sizeof (afs[0]))
1957c478bd9Sstevel@tonic-gate     struct {
1967c478bd9Sstevel@tonic-gate 	int af;
1977c478bd9Sstevel@tonic-gate 	int sock;
1987c478bd9Sstevel@tonic-gate 	void *buf;
1997c478bd9Sstevel@tonic-gate 	size_t buf_size;
2007c478bd9Sstevel@tonic-gate 	struct lifnum lifnum;
2017c478bd9Sstevel@tonic-gate     } afp[N_AFS];
2027c478bd9Sstevel@tonic-gate     int code, i, j;
2037c478bd9Sstevel@tonic-gate     int retval = 0, afidx;
2047c478bd9Sstevel@tonic-gate     krb5_error_code sock_err = 0;
2057c478bd9Sstevel@tonic-gate     struct lifreq *lifr, lifreq, *lifr2;
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate #define FOREACH_AF() for (afidx = 0; afidx < N_AFS; afidx++)
2087c478bd9Sstevel@tonic-gate #define P (afp[afidx])
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate     KRB5_LOG0(KRB5_INFO, "foreach_localaddr() start");
2117c478bd9Sstevel@tonic-gate     /* init */
2127c478bd9Sstevel@tonic-gate     FOREACH_AF () {
2137c478bd9Sstevel@tonic-gate 	P.af = afs[afidx];
2147c478bd9Sstevel@tonic-gate 	P.sock = -1;
2157c478bd9Sstevel@tonic-gate 	P.buf = 0;
2167c478bd9Sstevel@tonic-gate     }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate     /* first pass: get raw data, discard uninteresting addresses, callback */
2197c478bd9Sstevel@tonic-gate     FOREACH_AF () {
2207c478bd9Sstevel@tonic-gate 	KRB5_LOG (KRB5_INFO, "foreach_localaddr() trying af %d", P.af);
2217c478bd9Sstevel@tonic-gate 	P.sock = socket (P.af, USE_TYPE, USE_PROTO);
2227c478bd9Sstevel@tonic-gate 	if (P.sock < 0) {
2237c478bd9Sstevel@tonic-gate 	    sock_err = SOCKET_ERROR;
2247c478bd9Sstevel@tonic-gate 	    Tperror ("socket");
2257c478bd9Sstevel@tonic-gate 	    continue;
2267c478bd9Sstevel@tonic-gate 	}
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	P.lifnum.lifn_family = P.af;
2297c478bd9Sstevel@tonic-gate 	P.lifnum.lifn_flags = 0;
2307c478bd9Sstevel@tonic-gate 	P.lifnum.lifn_count = 0;
2317c478bd9Sstevel@tonic-gate 	code = ioctl (P.sock, SIOCGLIFNUM, &P.lifnum);
2327c478bd9Sstevel@tonic-gate 	if (code) {
2337c478bd9Sstevel@tonic-gate 	    Tperror ("ioctl(SIOCGLIFNUM)");
2347c478bd9Sstevel@tonic-gate 	    retval = errno;
2357c478bd9Sstevel@tonic-gate 	    goto punt;
2367c478bd9Sstevel@tonic-gate 	}
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	KRB5_LOG (KRB5_INFO, "foreach_localaddr() lifn_count %d",
2397c478bd9Sstevel@tonic-gate 		P.lifnum.lifn_count);
2407c478bd9Sstevel@tonic-gate 	P.buf_size = P.lifnum.lifn_count * sizeof (struct lifreq) * 2;
2417c478bd9Sstevel@tonic-gate 	P.buf = malloc (P.buf_size);
2427c478bd9Sstevel@tonic-gate 	if (P.buf == NULL) {
2437c478bd9Sstevel@tonic-gate 	    retval = errno;
2447c478bd9Sstevel@tonic-gate 	    goto punt;
2457c478bd9Sstevel@tonic-gate 	}
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	code = get_lifconf (P.af, P.sock, &P.buf_size, P.buf);
2487c478bd9Sstevel@tonic-gate 	if (code < 0) {
2497c478bd9Sstevel@tonic-gate 	    retval = errno;
2507c478bd9Sstevel@tonic-gate 	    goto punt;
2517c478bd9Sstevel@tonic-gate 	}
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	for (i = 0; i < P.buf_size; i+= sizeof (*lifr)) {
2547c478bd9Sstevel@tonic-gate 	    /*LINTED*/
2557c478bd9Sstevel@tonic-gate 	    lifr = (struct lifreq *)((caddr_t) P.buf+i);
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	    strncpy(lifreq.lifr_name, lifr->lifr_name,
2587c478bd9Sstevel@tonic-gate 		    sizeof (lifreq.lifr_name));
2597c478bd9Sstevel@tonic-gate 	    KRB5_LOG (KRB5_INFO, "foreach_localaddr() interface %s",
2607c478bd9Sstevel@tonic-gate 		    lifreq.lifr_name);
2617c478bd9Sstevel@tonic-gate 	    /* ioctl unknown to lclint */
2627c478bd9Sstevel@tonic-gate 	    if (ioctl (P.sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) {
2637c478bd9Sstevel@tonic-gate 		Tperror ("ioctl(SIOCGLIFFLAGS)");
2647c478bd9Sstevel@tonic-gate 	    skip:
265*1da57d55SToomas Soome 		KRB5_LOG (KRB5_INFO,
2667c478bd9Sstevel@tonic-gate 			"foreach_localaddr() skipping interface %s",
2677c478bd9Sstevel@tonic-gate 			lifr->lifr_name);
2687c478bd9Sstevel@tonic-gate 		/* mark for next pass */
2697c478bd9Sstevel@tonic-gate 		lifr->lifr_name[0] = '\0';
2707c478bd9Sstevel@tonic-gate 		continue;
2717c478bd9Sstevel@tonic-gate 	    }
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate #ifdef IFF_LOOPBACK
2747c478bd9Sstevel@tonic-gate 	    /* None of the current callers want loopback addresses.  */
2757c478bd9Sstevel@tonic-gate 	    if (lifreq.lifr_flags & IFF_LOOPBACK) {
2767c478bd9Sstevel@tonic-gate 		Tprintf (("  loopback\n"));
2777c478bd9Sstevel@tonic-gate 		goto skip;
2787c478bd9Sstevel@tonic-gate 	    }
2797c478bd9Sstevel@tonic-gate #endif
2807c478bd9Sstevel@tonic-gate 	    /* Ignore interfaces that are down.  */
2817c478bd9Sstevel@tonic-gate 	    if ((lifreq.lifr_flags & IFF_UP) == 0) {
2827c478bd9Sstevel@tonic-gate 		Tprintf (("  down\n"));
2837c478bd9Sstevel@tonic-gate 		goto skip;
2847c478bd9Sstevel@tonic-gate 	    }
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	    /* Make sure we didn't process this address already.  */
2877c478bd9Sstevel@tonic-gate 	    for (j = 0; j < i; j += sizeof (*lifr2)) {
2887c478bd9Sstevel@tonic-gate 		/*LINTED*/
2897c478bd9Sstevel@tonic-gate 		lifr2 = (struct lifreq *)((caddr_t) P.buf+j);
2907c478bd9Sstevel@tonic-gate 		if (lifr2->lifr_name[0] == '\0')
2917c478bd9Sstevel@tonic-gate 		    continue;
2927c478bd9Sstevel@tonic-gate 		if (lifr2->lifr_addr.ss_family == lifr->lifr_addr.ss_family
2937c478bd9Sstevel@tonic-gate 		    /* Compare address info.  If this isn't good enough --
2947c478bd9Sstevel@tonic-gate 		       i.e., if random padding bytes turn out to differ
2957c478bd9Sstevel@tonic-gate 		       when the addresses are the same -- then we'll have
2967c478bd9Sstevel@tonic-gate 		       to do it on a per address family basis.  */
2977c478bd9Sstevel@tonic-gate 		    && !memcmp (&lifr2->lifr_addr, &lifr->lifr_addr,
2987c478bd9Sstevel@tonic-gate 				sizeof (*lifr))) {
2997c478bd9Sstevel@tonic-gate 		    Tprintf (("  duplicate addr\n"));
3007c478bd9Sstevel@tonic-gate 		    KRB5_LOG0 (KRB5_INFO, "foreach_localaddr() dup addr");
3017c478bd9Sstevel@tonic-gate 		    goto skip;
3027c478bd9Sstevel@tonic-gate 		}
3037c478bd9Sstevel@tonic-gate 	    }
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	    if ((*pass1fn) (data, ss2sa (&lifr->lifr_addr)))
3067c478bd9Sstevel@tonic-gate 		goto punt;
3077c478bd9Sstevel@tonic-gate 	}
3087c478bd9Sstevel@tonic-gate     }
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate     /* Did we actually get any working sockets?  */
3117c478bd9Sstevel@tonic-gate     FOREACH_AF ()
3127c478bd9Sstevel@tonic-gate 	if (P.sock != -1)
3137c478bd9Sstevel@tonic-gate 	    goto have_working_socket;
3147c478bd9Sstevel@tonic-gate     retval = sock_err;
3157c478bd9Sstevel@tonic-gate     goto punt;
3167c478bd9Sstevel@tonic-gate have_working_socket:
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate     if (betweenfn != NULL && (*betweenfn)(data))
3197c478bd9Sstevel@tonic-gate 	goto punt;
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate     if (pass2fn)
3227c478bd9Sstevel@tonic-gate 	FOREACH_AF ()
3237c478bd9Sstevel@tonic-gate 	    if (P.sock >= 0) {
3247c478bd9Sstevel@tonic-gate 		for (i = 0; i < P.buf_size; i+= sizeof (*lifr)) {
3257c478bd9Sstevel@tonic-gate 		    /*LINTED*/
3267c478bd9Sstevel@tonic-gate 		    lifr = (struct lifreq *)((caddr_t) P.buf+i);
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 		    if (lifr->lifr_name[0] == '\0')
3297c478bd9Sstevel@tonic-gate 			/* Marked in first pass to be ignored.  */
3307c478bd9Sstevel@tonic-gate 			continue;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 		    KRB5_LOG (KRB5_INFO,
3337c478bd9Sstevel@tonic-gate 			    "foreach_localaddr() doing pass2fn i = %d",
3347c478bd9Sstevel@tonic-gate 			    i);
3357c478bd9Sstevel@tonic-gate 		    if ((*pass2fn) (data, ss2sa (&lifr->lifr_addr)))
3367c478bd9Sstevel@tonic-gate 			goto punt;
3377c478bd9Sstevel@tonic-gate 		}
3387c478bd9Sstevel@tonic-gate 	    }
3397c478bd9Sstevel@tonic-gate punt:
3407c478bd9Sstevel@tonic-gate     FOREACH_AF () {
3417c478bd9Sstevel@tonic-gate 	closesocket(P.sock);
3427c478bd9Sstevel@tonic-gate 	free (P.buf);
3437c478bd9Sstevel@tonic-gate     }
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate     return retval;
3467c478bd9Sstevel@tonic-gate }
347