10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * lib/krb5/os/localaddr.c
30Sstevel@tonic-gate *
4*781Sgtb * Copyright 1990,1991,2000,2001,2002,2004 by the Massachusetts Institute of Technology.
50Sstevel@tonic-gate * All Rights Reserved.
60Sstevel@tonic-gate *
70Sstevel@tonic-gate * Export of this software from the United States of America may
80Sstevel@tonic-gate * require a specific license from the United States Government.
90Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating
100Sstevel@tonic-gate * export to obtain such a license before exporting.
110Sstevel@tonic-gate *
120Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
130Sstevel@tonic-gate * distribute this software and its documentation for any purpose and
140Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright
150Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and
160Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that
170Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining
180Sstevel@tonic-gate * to distribution of the software without specific, written prior
190Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label
200Sstevel@tonic-gate * your software as modified software and not distribute it in such a
210Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software.
220Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of
230Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express
240Sstevel@tonic-gate * or implied warranty.
250Sstevel@tonic-gate *
260Sstevel@tonic-gate *
270Sstevel@tonic-gate * Return the protocol addresses supported by this host.
28*781Sgtb * Exports from this file:
29*781Sgtb * krb5int_foreach_localaddr (does callbacks)
30*781Sgtb * krb5int_local_addresses (includes krb5.conf extra_addresses)
31*781Sgtb * krb5_os_localaddr (doesn't)
320Sstevel@tonic-gate *
330Sstevel@tonic-gate * XNS support is untested, but "Should just work". (Hah!)
340Sstevel@tonic-gate */
350Sstevel@tonic-gate
36*781Sgtb #include "k5-int.h"
37*781Sgtb
38*781Sgtb #if !defined(_WIN32)
390Sstevel@tonic-gate
400Sstevel@tonic-gate /* needed for solaris, harmless elsewhere... */
410Sstevel@tonic-gate #define BSD_COMP
420Sstevel@tonic-gate #include <sys/ioctl.h>
430Sstevel@tonic-gate #include <sys/time.h>
440Sstevel@tonic-gate #include <errno.h>
450Sstevel@tonic-gate #include <stddef.h>
460Sstevel@tonic-gate #include <ctype.h>
470Sstevel@tonic-gate
48*781Sgtb #if defined(TEST) || defined(DEBUG)
49*781Sgtb # include "fake-addrinfo.h"
50*781Sgtb #endif
51*781Sgtb
52*781Sgtb #include "foreachaddr.h"
53*781Sgtb
54*781Sgtb /* Note: foreach_localaddr is exported from the library through
55*781Sgtb krb5int_accessor, for the KDC to use.
56*781Sgtb
57*781Sgtb This function iterates over all the addresses it can find for the
58*781Sgtb local system, in one or two passes. In each pass, and between the
59*781Sgtb two, it can invoke callback functions supplied by the caller. The
60*781Sgtb two passes should operate on the same information, though not
61*781Sgtb necessarily in the same order each time. Duplicate and local
62*781Sgtb addresses should be eliminated. Storage passed to callback
63*781Sgtb functions should not be assumed to be valid after foreach_localaddr
64*781Sgtb returns.
65*781Sgtb
66*781Sgtb The int return value is an errno value (XXX or krb5_error_code
67*781Sgtb returned for a socket error) if something internal to
68*781Sgtb foreach_localaddr fails. If one of the callback functions wants to
69*781Sgtb indicate an error, it should store something via the 'data' handle.
70*781Sgtb If any callback function returns a non-zero value,
71*781Sgtb foreach_localaddr will clean up and return immediately.
72*781Sgtb
73*781Sgtb Multiple definitions are provided below, dependent on various
74*781Sgtb system facilities for extracting the necessary information. */
75*781Sgtb
76*781Sgtb /* Now, on to the implementations, and heaps of debugging code. */
77*781Sgtb
78*781Sgtb #ifdef TEST
79*781Sgtb # define Tprintf(X) printf X
80*781Sgtb # define Tperror(X) perror(X)
81*781Sgtb #else
82*781Sgtb # define Tprintf(X) (void) X
83*781Sgtb # define Tperror(X) (void)(X)
84*781Sgtb #endif
85*781Sgtb
86*781Sgtb /*
87*781Sgtb * The SIOCGIF* ioctls require a socket.
88*781Sgtb * It doesn't matter *what* kind of socket they use, but it has to be
89*781Sgtb * a socket.
90*781Sgtb *
91*781Sgtb * Of course, you can't just ask the kernel for a socket of arbitrary
92*781Sgtb * type; you have to ask for one with a valid type.
93*781Sgtb *
94*781Sgtb */
95*781Sgtb #ifdef HAVE_NETINET_IN_H
96*781Sgtb #include <netinet/in.h>
97*781Sgtb #ifndef USE_AF
98*781Sgtb #define USE_AF AF_INET
99*781Sgtb #define USE_TYPE SOCK_DGRAM
100*781Sgtb #define USE_PROTO 0
101*781Sgtb #endif
102*781Sgtb #endif
103*781Sgtb
104*781Sgtb #ifdef KRB5_USE_NS
105*781Sgtb #include <netns/ns.h>
106*781Sgtb #ifndef USE_AF
107*781Sgtb #define USE_AF AF_NS
108*781Sgtb #define USE_TYPE SOCK_DGRAM
109*781Sgtb #define USE_PROTO 0 /* guess */
110*781Sgtb #endif
111*781Sgtb #endif
112*781Sgtb /*
113*781Sgtb * Add more address families here.
114*781Sgtb */
115*781Sgtb
116*781Sgtb
117*781Sgtb #if defined(__linux__) && defined(KRB5_USE_INET6) && !defined(HAVE_IFADDRS_H)
118*781Sgtb #define LINUX_IPV6_HACK
119*781Sgtb #endif
120*781Sgtb
121*781Sgtb #include <errno.h>
122*781Sgtb
123*781Sgtb /*
124*781Sgtb * Return all the protocol addresses of this host.
125*781Sgtb *
126*781Sgtb * We could kludge up something to return all addresses, assuming that
127*781Sgtb * they're valid kerberos protocol addresses, but we wouldn't know the
128*781Sgtb * real size of the sockaddr or know which part of it was actually the
129*781Sgtb * host part.
130*781Sgtb *
131*781Sgtb * This uses the SIOCGIFCONF, SIOCGIFFLAGS, and SIOCGIFADDR ioctl's.
132*781Sgtb */
133*781Sgtb
134*781Sgtb /*
135*781Sgtb * BSD 4.4 defines the size of an ifreq to be
136*781Sgtb * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
137*781Sgtb * However, under earlier systems, sa_len isn't present, so the size is
138*781Sgtb * just sizeof(struct ifreq).
139*781Sgtb */
140*781Sgtb #ifdef HAVE_SA_LEN
141*781Sgtb #ifndef max
142*781Sgtb #define max(a,b) ((a) > (b) ? (a) : (b))
143*781Sgtb #endif
144*781Sgtb #define ifreq_size(i) max(sizeof(struct ifreq),\
145*781Sgtb sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
146*781Sgtb #else
147*781Sgtb #define ifreq_size(i) sizeof(struct ifreq)
148*781Sgtb #endif /* HAVE_SA_LEN*/
149*781Sgtb
150*781Sgtb #if defined(DEBUG) || defined(TEST)
151*781Sgtb #include <netinet/in.h>
152*781Sgtb #include <net/if.h>
153*781Sgtb
154*781Sgtb #include "socket-utils.h"
155*781Sgtb #include "fake-addrinfo.h"
156*781Sgtb
157*781Sgtb void printaddr (struct sockaddr *);
158*781Sgtb
printaddr(struct sockaddr * sa)159*781Sgtb void printaddr (struct sockaddr *sa)
160*781Sgtb /*@modifies fileSystem@*/
161*781Sgtb {
162*781Sgtb char buf[NI_MAXHOST];
163*781Sgtb int err;
164*781Sgtb
165*781Sgtb printf ("%p ", (void *) sa);
166*781Sgtb err = getnameinfo (sa, socklen (sa), buf, sizeof (buf), 0, 0,
167*781Sgtb NI_NUMERICHOST);
168*781Sgtb if (err)
169*781Sgtb printf ("<getnameinfo error %d: %s> family=%d",
170*781Sgtb err, gai_strerror (err),
171*781Sgtb sa->sa_family);
172*781Sgtb else
173*781Sgtb printf ("%s", buf);
174*781Sgtb }
175*781Sgtb #endif
176*781Sgtb
177*781Sgtb #ifdef HAVE_IFADDRS_H
178*781Sgtb #include <ifaddrs.h>
179*781Sgtb
180*781Sgtb #ifdef DEBUG
printifaddr(struct ifaddrs * ifp)181*781Sgtb void printifaddr (struct ifaddrs *ifp)
182*781Sgtb {
183*781Sgtb printf ("%p={\n", ifp);
184*781Sgtb /* printf ("\tnext=%p\n", ifp->ifa_next); */
185*781Sgtb printf ("\tname=%s\n", ifp->ifa_name);
186*781Sgtb printf ("\tflags=");
187*781Sgtb {
188*781Sgtb int ch, flags = ifp->ifa_flags;
189*781Sgtb printf ("%x", flags);
190*781Sgtb ch = '<';
191*781Sgtb #define X(F) if (flags & IFF_##F) { printf ("%c%s", ch, #F); flags &= ~IFF_##F; ch = ','; }
192*781Sgtb X (UP); X (BROADCAST); X (DEBUG); X (LOOPBACK); X (POINTOPOINT);
193*781Sgtb X (NOTRAILERS); X (RUNNING); X (NOARP); X (PROMISC); X (ALLMULTI);
194*781Sgtb #ifdef IFF_OACTIVE
195*781Sgtb X (OACTIVE);
196*781Sgtb #endif
197*781Sgtb #ifdef IFF_SIMPLE
198*781Sgtb X (SIMPLEX);
199*781Sgtb #endif
200*781Sgtb X (MULTICAST);
201*781Sgtb printf (">");
202*781Sgtb #undef X
203*781Sgtb }
204*781Sgtb if (ifp->ifa_addr)
205*781Sgtb printf ("\n\taddr="), printaddr (ifp->ifa_addr);
206*781Sgtb if (ifp->ifa_netmask)
207*781Sgtb printf ("\n\tnetmask="), printaddr (ifp->ifa_netmask);
208*781Sgtb if (ifp->ifa_broadaddr)
209*781Sgtb printf ("\n\tbroadaddr="), printaddr (ifp->ifa_broadaddr);
210*781Sgtb if (ifp->ifa_dstaddr)
211*781Sgtb printf ("\n\tdstaddr="), printaddr (ifp->ifa_dstaddr);
212*781Sgtb if (ifp->ifa_data)
213*781Sgtb printf ("\n\tdata=%p", ifp->ifa_data);
214*781Sgtb printf ("\n}\n");
215*781Sgtb }
216*781Sgtb #endif /* DEBUG */
217*781Sgtb
218*781Sgtb #include <string.h>
219*781Sgtb #include <stdlib.h>
220*781Sgtb
221*781Sgtb static int
addr_eq(const struct sockaddr * s1,const struct sockaddr * s2)222*781Sgtb addr_eq (const struct sockaddr *s1, const struct sockaddr *s2)
223*781Sgtb {
224*781Sgtb if (s1->sa_family != s2->sa_family)
225*781Sgtb return 0;
226*781Sgtb #ifdef HAVE_SA_LEN
227*781Sgtb if (s1->sa_len != s2->sa_len)
228*781Sgtb return 0;
229*781Sgtb return !memcmp (s1, s2, s1->sa_len);
230*781Sgtb #else
231*781Sgtb #define CMPTYPE(T,F) (!memcmp(&((const T*)s1)->F,&((const T*)s2)->F,sizeof(((const T*)s1)->F)))
232*781Sgtb switch (s1->sa_family) {
233*781Sgtb case AF_INET:
234*781Sgtb return CMPTYPE (struct sockaddr_in, sin_addr);
235*781Sgtb case AF_INET6:
236*781Sgtb return CMPTYPE (struct sockaddr_in6, sin6_addr);
237*781Sgtb default:
238*781Sgtb /* Err on side of duplicate listings. */
239*781Sgtb return 0;
240*781Sgtb }
241*781Sgtb #endif
242*781Sgtb }
243*781Sgtb #endif
244*781Sgtb
245*781Sgtb #ifndef HAVE_IFADDRS_H
246*781Sgtb /*@-usereleased@*/ /* lclint doesn't understand realloc */
247*781Sgtb static /*@null@*/ void *
grow_or_free(void * ptr,size_t newsize)248*781Sgtb grow_or_free (/*@only@*/ void *ptr, size_t newsize)
249*781Sgtb /*@*/
250*781Sgtb {
251*781Sgtb void *newptr;
252*781Sgtb newptr = realloc (ptr, newsize);
253*781Sgtb if (newptr == NULL && newsize != 0) {
254*781Sgtb free (ptr); /* lclint complains but this is right */
255*781Sgtb return NULL;
256*781Sgtb }
257*781Sgtb return newptr;
258*781Sgtb }
259*781Sgtb /*@=usereleased@*/
260*781Sgtb
261*781Sgtb static int
get_ifconf(int s,size_t * lenp,char * buf)262*781Sgtb get_ifconf (int s, size_t *lenp, /*@out@*/ char *buf)
263*781Sgtb /*@modifies *buf,*lenp@*/
264*781Sgtb {
265*781Sgtb int ret;
266*781Sgtb struct ifconf ifc;
267*781Sgtb
268*781Sgtb /*@+matchanyintegral@*/
269*781Sgtb ifc.ifc_len = *lenp;
270*781Sgtb /*@=matchanyintegral@*/
271*781Sgtb ifc.ifc_buf = buf;
272*781Sgtb memset(buf, 0, *lenp);
273*781Sgtb /*@-moduncon@*/
274*781Sgtb ret = ioctl (s, SIOCGIFCONF, (char *)&ifc);
275*781Sgtb /*@=moduncon@*/
276*781Sgtb /*@+matchanyintegral@*/
277*781Sgtb *lenp = ifc.ifc_len;
278*781Sgtb /*@=matchanyintegral@*/
279*781Sgtb return ret;
280*781Sgtb }
281*781Sgtb
282*781Sgtb /* Solaris uses SIOCGLIFCONF to return struct lifconf which is just
283*781Sgtb an extended version of struct ifconf.
284*781Sgtb
285*781Sgtb HP-UX 11 also appears to have SIOCGLIFCONF, but uses struct
286*781Sgtb if_laddrconf, and struct if_laddrreq to be used with
287*781Sgtb SIOCGLIFADDR. */
288*781Sgtb #if defined(SIOCGLIFCONF) && defined(HAVE_STRUCT_LIFCONF)
289*781Sgtb static int
get_lifconf(int af,int s,size_t * lenp,char * buf)290*781Sgtb get_lifconf (int af, int s, size_t *lenp, /*@out@*/ char *buf)
291*781Sgtb /*@modifies *buf,*lenp@*/
292*781Sgtb {
293*781Sgtb int ret;
294*781Sgtb struct lifconf lifc;
295*781Sgtb
296*781Sgtb lifc.lifc_family = af;
297*781Sgtb lifc.lifc_flags = 0;
298*781Sgtb /*@+matchanyintegral@*/
299*781Sgtb lifc.lifc_len = *lenp;
300*781Sgtb /*@=matchanyintegral@*/
301*781Sgtb lifc.lifc_buf = buf;
302*781Sgtb memset(buf, 0, *lenp);
303*781Sgtb /*@-moduncon@*/
304*781Sgtb ret = ioctl (s, SIOCGLIFCONF, (char *)&lifc);
305*781Sgtb if (ret)
306*781Sgtb Tperror ("SIOCGLIFCONF");
307*781Sgtb /*@=moduncon@*/
308*781Sgtb /*@+matchanyintegral@*/
309*781Sgtb *lenp = lifc.lifc_len;
310*781Sgtb /*@=matchanyintegral@*/
311*781Sgtb return ret;
312*781Sgtb }
313*781Sgtb #endif
314*781Sgtb #if defined(SIOCGLIFCONF) && defined(HAVE_STRUCT_IF_LADDRCONF) && 0
315*781Sgtb /* I'm not sure if this is needed or if net/if.h will pull it in. */
316*781Sgtb /* #include <net/if6.h> */
317*781Sgtb static int
get_if_laddrconf(int af,int s,size_t * lenp,char * buf)318*781Sgtb get_if_laddrconf (int af, int s, size_t *lenp, /*@out@*/ char *buf)
319*781Sgtb /*@modifies *buf,*lenp@*/
320*781Sgtb {
321*781Sgtb int ret;
322*781Sgtb struct if_laddrconf iflc;
323*781Sgtb
324*781Sgtb /*@+matchanyintegral@*/
325*781Sgtb iflc.iflc_len = *lenp;
326*781Sgtb /*@=matchanyintegral@*/
327*781Sgtb iflc.iflc_buf = buf;
328*781Sgtb memset(buf, 0, *lenp);
329*781Sgtb /*@-moduncon@*/
330*781Sgtb ret = ioctl (s, SIOCGLIFCONF, (char *)&iflc);
331*781Sgtb if (ret)
332*781Sgtb Tperror ("SIOCGLIFCONF");
333*781Sgtb /*@=moduncon@*/
334*781Sgtb /*@+matchanyintegral@*/
335*781Sgtb *lenp = iflc.iflc_len;
336*781Sgtb /*@=matchanyintegral@*/
337*781Sgtb return ret;
338*781Sgtb }
339*781Sgtb #endif
340*781Sgtb #endif /* ! HAVE_IFADDRS_H */
341*781Sgtb
342*781Sgtb #ifdef LINUX_IPV6_HACK
343*781Sgtb #include <stdio.h>
344*781Sgtb /* Read IPv6 addresses out of /proc/net/if_inet6, since there isn't
345*781Sgtb (currently) any ioctl to return them. */
346*781Sgtb struct linux_ipv6_addr_list {
347*781Sgtb struct sockaddr_in6 addr;
348*781Sgtb struct linux_ipv6_addr_list *next;
349*781Sgtb };
350*781Sgtb static struct linux_ipv6_addr_list *
get_linux_ipv6_addrs()351*781Sgtb get_linux_ipv6_addrs ()
352*781Sgtb {
353*781Sgtb struct linux_ipv6_addr_list *lst = 0;
354*781Sgtb FILE *f;
355*781Sgtb
356*781Sgtb /* _PATH_PROCNET_IFINET6 */
357*781Sgtb f = fopen("/proc/net/if_inet6", "r");
358*781Sgtb if (f) {
359*781Sgtb char ifname[21];
360*781Sgtb unsigned int idx, pfxlen, scope, dadstat;
361*781Sgtb struct in6_addr a6;
362*781Sgtb struct linux_ipv6_addr_list *nw;
363*781Sgtb int i;
364*781Sgtb unsigned int addrbyte[16];
365*781Sgtb
366*781Sgtb while (fscanf(f,
367*781Sgtb "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x"
368*781Sgtb " %2x %2x %2x %2x %20s\n",
369*781Sgtb &addrbyte[0], &addrbyte[1], &addrbyte[2], &addrbyte[3],
370*781Sgtb &addrbyte[4], &addrbyte[5], &addrbyte[6], &addrbyte[7],
371*781Sgtb &addrbyte[8], &addrbyte[9], &addrbyte[10], &addrbyte[11],
372*781Sgtb &addrbyte[12], &addrbyte[13], &addrbyte[14],
373*781Sgtb &addrbyte[15],
374*781Sgtb &idx, &pfxlen, &scope, &dadstat, ifname) != EOF) {
375*781Sgtb for (i = 0; i < 16; i++)
376*781Sgtb a6.s6_addr[i] = addrbyte[i];
377*781Sgtb if (scope != 0)
378*781Sgtb continue;
379*781Sgtb #if 0 /* These symbol names are as used by ifconfig, but none of the
380*781Sgtb system header files export them. Dig up the kernel versions
381*781Sgtb someday and see if they're exported. */
382*781Sgtb switch (scope) {
383*781Sgtb case 0:
384*781Sgtb default:
385*781Sgtb break;
386*781Sgtb case IPV6_ADDR_LINKLOCAL:
387*781Sgtb case IPV6_ADDR_SITELOCAL:
388*781Sgtb case IPV6_ADDR_COMPATv4:
389*781Sgtb case IPV6_ADDR_LOOPBACK:
390*781Sgtb continue;
391*781Sgtb }
392*781Sgtb #endif
393*781Sgtb nw = malloc (sizeof (struct linux_ipv6_addr_list));
394*781Sgtb if (nw == 0)
395*781Sgtb continue;
396*781Sgtb memset (nw, 0, sizeof (*nw));
397*781Sgtb nw->addr.sin6_addr = a6;
398*781Sgtb nw->addr.sin6_family = AF_INET6;
399*781Sgtb /* Ignore other fields, we don't actually use them here. */
400*781Sgtb nw->next = lst;
401*781Sgtb lst = nw;
402*781Sgtb }
403*781Sgtb fclose (f);
404*781Sgtb }
405*781Sgtb return lst;
406*781Sgtb }
407*781Sgtb #endif
408*781Sgtb
409*781Sgtb /* Return value is errno if internal stuff failed, otherwise zero,
410*781Sgtb even in the case where a called function terminated the iteration.
411*781Sgtb
412*781Sgtb If one of the callback functions wants to pass back an error
413*781Sgtb indication, it should do it via some field pointed to by the DATA
414*781Sgtb argument. */
415*781Sgtb
416*781Sgtb #ifdef HAVE_IFADDRS_H
417*781Sgtb
418*781Sgtb int
foreach_localaddr(void * data,int (* pass1fn)(void *,struct sockaddr *),int (* betweenfn)(void *),int (* pass2fn)(void *,struct sockaddr *))419*781Sgtb foreach_localaddr (/*@null@*/ void *data,
420*781Sgtb int (*pass1fn) (/*@null@*/ void *, struct sockaddr *) /*@*/,
421*781Sgtb /*@null@*/ int (*betweenfn) (/*@null@*/ void *) /*@*/,
422*781Sgtb /*@null@*/ int (*pass2fn) (/*@null@*/ void *,
423*781Sgtb struct sockaddr *) /*@*/)
424*781Sgtb #if defined(DEBUG) || defined(TEST)
425*781Sgtb /*@modifies fileSystem@*/
426*781Sgtb #endif
427*781Sgtb {
428*781Sgtb struct ifaddrs *ifp_head, *ifp, *ifp2;
429*781Sgtb int match;
430*781Sgtb
431*781Sgtb if (getifaddrs (&ifp_head) < 0)
432*781Sgtb return errno;
433*781Sgtb for (ifp = ifp_head; ifp; ifp = ifp->ifa_next) {
434*781Sgtb #ifdef DEBUG
435*781Sgtb printifaddr (ifp);
436*781Sgtb #endif
437*781Sgtb if ((ifp->ifa_flags & IFF_UP) == 0)
438*781Sgtb continue;
439*781Sgtb if (ifp->ifa_flags & IFF_LOOPBACK) {
440*781Sgtb /* Pretend it's not up, so the second pass will skip
441*781Sgtb it. */
442*781Sgtb ifp->ifa_flags &= ~IFF_UP;
443*781Sgtb continue;
444*781Sgtb }
445*781Sgtb if (ifp->ifa_addr == NULL) {
446*781Sgtb /* Can't use an interface without an address. Linux
447*781Sgtb apparently does this sometimes. [RT ticket 1770 from
448*781Sgtb Maurice Massar, also Debian bug 206851, shows the
449*781Sgtb problem with a PPP link on a newer kernel than I'm
450*781Sgtb running.]
451*781Sgtb
452*781Sgtb Pretend it's not up, so the second pass will skip
453*781Sgtb it. */
454*781Sgtb ifp->ifa_flags &= ~IFF_UP;
455*781Sgtb continue;
456*781Sgtb }
457*781Sgtb /* If this address is a duplicate, punt. */
458*781Sgtb match = 0;
459*781Sgtb for (ifp2 = ifp_head; ifp2 && ifp2 != ifp; ifp2 = ifp2->ifa_next) {
460*781Sgtb if ((ifp2->ifa_flags & IFF_UP) == 0)
461*781Sgtb continue;
462*781Sgtb if (ifp2->ifa_flags & IFF_LOOPBACK)
463*781Sgtb continue;
464*781Sgtb if (addr_eq (ifp->ifa_addr, ifp2->ifa_addr)) {
465*781Sgtb match = 1;
466*781Sgtb ifp->ifa_flags &= ~IFF_UP;
467*781Sgtb break;
468*781Sgtb }
469*781Sgtb }
470*781Sgtb if (match)
471*781Sgtb continue;
472*781Sgtb if ((*pass1fn) (data, ifp->ifa_addr))
473*781Sgtb goto punt;
474*781Sgtb }
475*781Sgtb if (betweenfn && (*betweenfn)(data))
476*781Sgtb goto punt;
477*781Sgtb if (pass2fn)
478*781Sgtb for (ifp = ifp_head; ifp; ifp = ifp->ifa_next) {
479*781Sgtb if (ifp->ifa_flags & IFF_UP)
480*781Sgtb if ((*pass2fn) (data, ifp->ifa_addr))
481*781Sgtb goto punt;
482*781Sgtb }
483*781Sgtb punt:
484*781Sgtb freeifaddrs (ifp_head);
485*781Sgtb return 0;
486*781Sgtb }
487*781Sgtb
488*781Sgtb #elif defined (SIOCGLIFNUM) && defined(HAVE_STRUCT_LIFCONF) /* Solaris 8 and later; Sol 7? */
489*781Sgtb
490*781Sgtb int
foreach_localaddr(void * data,int (* pass1fn)(void *,struct sockaddr *),int (* betweenfn)(void *),int (* pass2fn)(void *,struct sockaddr *))491*781Sgtb foreach_localaddr (/*@null@*/ void *data,
492*781Sgtb int (*pass1fn) (/*@null@*/ void *, struct sockaddr *) /*@*/,
493*781Sgtb /*@null@*/ int (*betweenfn) (/*@null@*/ void *) /*@*/,
494*781Sgtb /*@null@*/ int (*pass2fn) (/*@null@*/ void *,
495*781Sgtb struct sockaddr *) /*@*/)
496*781Sgtb #if defined(DEBUG) || defined(TEST)
497*781Sgtb /*@modifies fileSystem@*/
498*781Sgtb #endif
499*781Sgtb {
500*781Sgtb /* Okay, this is kind of odd. We have to use each of the address
501*781Sgtb families we care about, because with an AF_INET socket, extra
502*781Sgtb interfaces like hme0:1 that have only AF_INET6 addresses will
503*781Sgtb cause errors. Similarly, if hme0 has more AF_INET addresses
504*781Sgtb than AF_INET6 addresses, we won't be able to retrieve all of
505*781Sgtb the AF_INET addresses if we use an AF_INET6 socket. Since
506*781Sgtb neither family is guaranteed to have the greater number of
507*781Sgtb addresses, we should use both.
508*781Sgtb
509*781Sgtb If it weren't for this little quirk, we could use one socket of
510*781Sgtb any type, and ask for addresses of all types. At least, it
511*781Sgtb seems to work that way. */
512*781Sgtb
513*781Sgtb static const int afs[] = { AF_INET, AF_NS, AF_INET6 };
514*781Sgtb #define N_AFS (sizeof (afs) / sizeof (afs[0]))
515*781Sgtb struct {
516*781Sgtb int af;
517*781Sgtb int sock;
518*781Sgtb void *buf;
519*781Sgtb size_t buf_size;
520*781Sgtb struct lifnum lifnum;
521*781Sgtb } afp[N_AFS];
522*781Sgtb int code, i, j;
523*781Sgtb int retval = 0, afidx;
524*781Sgtb krb5_error_code sock_err = 0;
525*781Sgtb struct lifreq *lifr, lifreq, *lifr2;
526*781Sgtb
527*781Sgtb #define FOREACH_AF() for (afidx = 0; afidx < N_AFS; afidx++)
528*781Sgtb #define P (afp[afidx])
529*781Sgtb
530*781Sgtb /* init */
531*781Sgtb FOREACH_AF () {
532*781Sgtb P.af = afs[afidx];
533*781Sgtb P.sock = -1;
534*781Sgtb P.buf = 0;
535*781Sgtb }
536*781Sgtb
537*781Sgtb /* first pass: get raw data, discard uninteresting addresses, callback */
538*781Sgtb FOREACH_AF () {
539*781Sgtb Tprintf (("trying af %d...\n", P.af));
540*781Sgtb P.sock = socket (P.af, USE_TYPE, USE_PROTO);
541*781Sgtb if (P.sock < 0) {
542*781Sgtb sock_err = SOCKET_ERROR;
543*781Sgtb Tperror ("socket");
544*781Sgtb continue;
545*781Sgtb }
546*781Sgtb
547*781Sgtb P.lifnum.lifn_family = P.af;
548*781Sgtb P.lifnum.lifn_flags = 0;
549*781Sgtb P.lifnum.lifn_count = 0;
550*781Sgtb code = ioctl (P.sock, SIOCGLIFNUM, &P.lifnum);
551*781Sgtb if (code) {
552*781Sgtb Tperror ("ioctl(SIOCGLIFNUM)");
553*781Sgtb retval = errno;
554*781Sgtb goto punt;
555*781Sgtb }
556*781Sgtb
557*781Sgtb P.buf_size = P.lifnum.lifn_count * sizeof (struct lifreq) * 2;
558*781Sgtb P.buf = malloc (P.buf_size);
559*781Sgtb if (P.buf == NULL) {
560*781Sgtb retval = errno;
561*781Sgtb goto punt;
562*781Sgtb }
563*781Sgtb
564*781Sgtb code = get_lifconf (P.af, P.sock, &P.buf_size, P.buf);
565*781Sgtb if (code < 0) {
566*781Sgtb retval = errno;
567*781Sgtb goto punt;
568*781Sgtb }
569*781Sgtb
570*781Sgtb for (i = 0; i + sizeof(*lifr) <= P.buf_size; i+= sizeof (*lifr)) {
571*781Sgtb lifr = (struct lifreq *)((caddr_t) P.buf+i);
572*781Sgtb
573*781Sgtb strncpy(lifreq.lifr_name, lifr->lifr_name,
574*781Sgtb sizeof (lifreq.lifr_name));
575*781Sgtb Tprintf (("interface %s\n", lifreq.lifr_name));
576*781Sgtb /*@-moduncon@*/ /* ioctl unknown to lclint */
577*781Sgtb if (ioctl (P.sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) {
578*781Sgtb Tperror ("ioctl(SIOCGLIFFLAGS)");
579*781Sgtb skip:
580*781Sgtb /* mark for next pass */
581*781Sgtb lifr->lifr_name[0] = '\0';
582*781Sgtb continue;
583*781Sgtb }
584*781Sgtb /*@=moduncon@*/
585*781Sgtb
586*781Sgtb #ifdef IFF_LOOPBACK
587*781Sgtb /* None of the current callers want loopback addresses. */
588*781Sgtb if (lifreq.lifr_flags & IFF_LOOPBACK) {
589*781Sgtb Tprintf ((" loopback\n"));
590*781Sgtb goto skip;
591*781Sgtb }
592*781Sgtb #endif
593*781Sgtb /* Ignore interfaces that are down. */
594*781Sgtb if ((lifreq.lifr_flags & IFF_UP) == 0) {
595*781Sgtb Tprintf ((" down\n"));
596*781Sgtb goto skip;
597*781Sgtb }
598*781Sgtb
599*781Sgtb /* Make sure we didn't process this address already. */
600*781Sgtb for (j = 0; j < i; j += sizeof (*lifr2)) {
601*781Sgtb lifr2 = (struct lifreq *)((caddr_t) P.buf+j);
602*781Sgtb if (lifr2->lifr_name[0] == '\0')
603*781Sgtb continue;
604*781Sgtb if (lifr2->lifr_addr.ss_family == lifr->lifr_addr.ss_family
605*781Sgtb /* Compare address info. If this isn't good enough --
606*781Sgtb i.e., if random padding bytes turn out to differ
607*781Sgtb when the addresses are the same -- then we'll have
608*781Sgtb to do it on a per address family basis. */
609*781Sgtb && !memcmp (&lifr2->lifr_addr, &lifr->lifr_addr,
610*781Sgtb sizeof (*lifr))) {
611*781Sgtb Tprintf ((" duplicate addr\n"));
612*781Sgtb goto skip;
613*781Sgtb }
614*781Sgtb }
615*781Sgtb
616*781Sgtb /*@-moduncon@*/
617*781Sgtb if ((*pass1fn) (data, ss2sa (&lifr->lifr_addr)))
618*781Sgtb goto punt;
619*781Sgtb /*@=moduncon@*/
620*781Sgtb }
621*781Sgtb }
622*781Sgtb
623*781Sgtb /* Did we actually get any working sockets? */
624*781Sgtb FOREACH_AF ()
625*781Sgtb if (P.sock != -1)
626*781Sgtb goto have_working_socket;
627*781Sgtb retval = sock_err;
628*781Sgtb goto punt;
629*781Sgtb have_working_socket:
630*781Sgtb
631*781Sgtb /*@-moduncon@*/
632*781Sgtb if (betweenfn != NULL && (*betweenfn)(data))
633*781Sgtb goto punt;
634*781Sgtb /*@=moduncon@*/
635*781Sgtb
636*781Sgtb if (pass2fn)
637*781Sgtb FOREACH_AF ()
638*781Sgtb if (P.sock >= 0) {
639*781Sgtb for (i = 0; i + sizeof (*lifr) <= P.buf_size; i+= sizeof (*lifr)) {
640*781Sgtb lifr = (struct lifreq *)((caddr_t) P.buf+i);
641*781Sgtb
642*781Sgtb if (lifr->lifr_name[0] == '\0')
643*781Sgtb /* Marked in first pass to be ignored. */
644*781Sgtb continue;
645*781Sgtb
646*781Sgtb /*@-moduncon@*/
647*781Sgtb if ((*pass2fn) (data, ss2sa (&lifr->lifr_addr)))
648*781Sgtb goto punt;
649*781Sgtb /*@=moduncon@*/
650*781Sgtb }
651*781Sgtb }
652*781Sgtb punt:
653*781Sgtb FOREACH_AF () {
654*781Sgtb /*@-moduncon@*/
655*781Sgtb closesocket(P.sock);
656*781Sgtb /*@=moduncon@*/
657*781Sgtb free (P.buf);
658*781Sgtb }
659*781Sgtb
660*781Sgtb return retval;
661*781Sgtb }
662*781Sgtb
663*781Sgtb #elif defined (SIOCGLIFNUM) && defined(HAVE_STRUCT_IF_LADDRCONF) && 0 /* HP-UX 11 support being debugged */
664*781Sgtb
665*781Sgtb int
foreach_localaddr(void * data,int (* pass1fn)(void *,struct sockaddr *),int (* betweenfn)(void *),int (* pass2fn)(void *,struct sockaddr *))666*781Sgtb foreach_localaddr (/*@null@*/ void *data,
667*781Sgtb int (*pass1fn) (/*@null@*/ void *, struct sockaddr *) /*@*/,
668*781Sgtb /*@null@*/ int (*betweenfn) (/*@null@*/ void *) /*@*/,
669*781Sgtb /*@null@*/ int (*pass2fn) (/*@null@*/ void *,
670*781Sgtb struct sockaddr *) /*@*/)
671*781Sgtb #if defined(DEBUG) || defined(TEST)
672*781Sgtb /*@modifies fileSystem@*/
673*781Sgtb #endif
674*781Sgtb {
675*781Sgtb /* Okay, this is kind of odd. We have to use each of the address
676*781Sgtb families we care about, because with an AF_INET socket, extra
677*781Sgtb interfaces like hme0:1 that have only AF_INET6 addresses will
678*781Sgtb cause errors. Similarly, if hme0 has more AF_INET addresses
679*781Sgtb than AF_INET6 addresses, we won't be able to retrieve all of
680*781Sgtb the AF_INET addresses if we use an AF_INET6 socket. Since
681*781Sgtb neither family is guaranteed to have the greater number of
682*781Sgtb addresses, we should use both.
683*781Sgtb
684*781Sgtb If it weren't for this little quirk, we could use one socket of
685*781Sgtb any type, and ask for addresses of all types. At least, it
686*781Sgtb seems to work that way. */
687*781Sgtb
688*781Sgtb static const int afs[] = { AF_INET, AF_NS, AF_INET6 };
689*781Sgtb #define N_AFS (sizeof (afs) / sizeof (afs[0]))
690*781Sgtb struct {
691*781Sgtb int af;
692*781Sgtb int sock;
693*781Sgtb void *buf;
694*781Sgtb size_t buf_size;
695*781Sgtb int if_num;
696*781Sgtb } afp[N_AFS];
697*781Sgtb int code, i, j;
698*781Sgtb int retval = 0, afidx;
699*781Sgtb krb5_error_code sock_err = 0;
700*781Sgtb struct if_laddrreq *lifr, lifreq, *lifr2;
701*781Sgtb
702*781Sgtb #define FOREACH_AF() for (afidx = 0; afidx < N_AFS; afidx++)
703*781Sgtb #define P (afp[afidx])
704*781Sgtb
705*781Sgtb /* init */
706*781Sgtb FOREACH_AF () {
707*781Sgtb P.af = afs[afidx];
708*781Sgtb P.sock = -1;
709*781Sgtb P.buf = 0;
710*781Sgtb }
711*781Sgtb
712*781Sgtb /* first pass: get raw data, discard uninteresting addresses, callback */
713*781Sgtb FOREACH_AF () {
714*781Sgtb Tprintf (("trying af %d...\n", P.af));
715*781Sgtb P.sock = socket (P.af, USE_TYPE, USE_PROTO);
716*781Sgtb if (P.sock < 0) {
717*781Sgtb sock_err = SOCKET_ERROR;
718*781Sgtb Tperror ("socket");
719*781Sgtb continue;
720*781Sgtb }
721*781Sgtb
722*781Sgtb code = ioctl (P.sock, SIOCGLIFNUM, &P.if_num);
723*781Sgtb if (code) {
724*781Sgtb Tperror ("ioctl(SIOCGLIFNUM)");
725*781Sgtb retval = errno;
726*781Sgtb goto punt;
727*781Sgtb }
728*781Sgtb
729*781Sgtb P.buf_size = P.if_num * sizeof (struct if_laddrreq) * 2;
730*781Sgtb P.buf = malloc (P.buf_size);
731*781Sgtb if (P.buf == NULL) {
732*781Sgtb retval = errno;
733*781Sgtb goto punt;
734*781Sgtb }
735*781Sgtb
736*781Sgtb code = get_if_laddrconf (P.af, P.sock, &P.buf_size, P.buf);
737*781Sgtb if (code < 0) {
738*781Sgtb retval = errno;
739*781Sgtb goto punt;
740*781Sgtb }
741*781Sgtb
742*781Sgtb for (i = 0; i + sizeof(*lifr) <= P.buf_size; i+= sizeof (*lifr)) {
743*781Sgtb lifr = (struct if_laddrreq *)((caddr_t) P.buf+i);
744*781Sgtb
745*781Sgtb strncpy(lifreq.iflr_name, lifr->iflr_name,
746*781Sgtb sizeof (lifreq.iflr_name));
747*781Sgtb Tprintf (("interface %s\n", lifreq.iflr_name));
748*781Sgtb /*@-moduncon@*/ /* ioctl unknown to lclint */
749*781Sgtb if (ioctl (P.sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) {
750*781Sgtb Tperror ("ioctl(SIOCGLIFFLAGS)");
751*781Sgtb skip:
752*781Sgtb /* mark for next pass */
753*781Sgtb lifr->iflr_name[0] = '\0';
754*781Sgtb continue;
755*781Sgtb }
756*781Sgtb /*@=moduncon@*/
757*781Sgtb
758*781Sgtb #ifdef IFF_LOOPBACK
759*781Sgtb /* None of the current callers want loopback addresses. */
760*781Sgtb if (lifreq.iflr_flags & IFF_LOOPBACK) {
761*781Sgtb Tprintf ((" loopback\n"));
762*781Sgtb goto skip;
763*781Sgtb }
764*781Sgtb #endif
765*781Sgtb /* Ignore interfaces that are down. */
766*781Sgtb if ((lifreq.iflr_flags & IFF_UP) == 0) {
767*781Sgtb Tprintf ((" down\n"));
768*781Sgtb goto skip;
769*781Sgtb }
770*781Sgtb
771*781Sgtb /* Make sure we didn't process this address already. */
772*781Sgtb for (j = 0; j < i; j += sizeof (*lifr2)) {
773*781Sgtb lifr2 = (struct if_laddrreq *)((caddr_t) P.buf+j);
774*781Sgtb if (lifr2->iflr_name[0] == '\0')
775*781Sgtb continue;
776*781Sgtb if (lifr2->iflr_addr.sa_family == lifr->iflr_addr.sa_family
777*781Sgtb /* Compare address info. If this isn't good enough --
778*781Sgtb i.e., if random padding bytes turn out to differ
779*781Sgtb when the addresses are the same -- then we'll have
780*781Sgtb to do it on a per address family basis. */
781*781Sgtb && !memcmp (&lifr2->iflr_addr, &lifr->iflr_addr,
782*781Sgtb sizeof (*lifr))) {
783*781Sgtb Tprintf ((" duplicate addr\n"));
784*781Sgtb goto skip;
785*781Sgtb }
786*781Sgtb }
787*781Sgtb
788*781Sgtb /*@-moduncon@*/
789*781Sgtb if ((*pass1fn) (data, ss2sa (&lifr->iflr_addr)))
790*781Sgtb goto punt;
791*781Sgtb /*@=moduncon@*/
792*781Sgtb }
793*781Sgtb }
794*781Sgtb
795*781Sgtb /* Did we actually get any working sockets? */
796*781Sgtb FOREACH_AF ()
797*781Sgtb if (P.sock != -1)
798*781Sgtb goto have_working_socket;
799*781Sgtb retval = sock_err;
800*781Sgtb goto punt;
801*781Sgtb have_working_socket:
802*781Sgtb
803*781Sgtb /*@-moduncon@*/
804*781Sgtb if (betweenfn != NULL && (*betweenfn)(data))
805*781Sgtb goto punt;
806*781Sgtb /*@=moduncon@*/
807*781Sgtb
808*781Sgtb if (pass2fn)
809*781Sgtb FOREACH_AF ()
810*781Sgtb if (P.sock >= 0) {
811*781Sgtb for (i = 0; i + sizeof(*lifr) <= P.buf_size; i+= sizeof (*lifr)) {
812*781Sgtb lifr = (struct if_laddrreq *)((caddr_t) P.buf+i);
813*781Sgtb
814*781Sgtb if (lifr->iflr_name[0] == '\0')
815*781Sgtb /* Marked in first pass to be ignored. */
816*781Sgtb continue;
817*781Sgtb
818*781Sgtb /*@-moduncon@*/
819*781Sgtb if ((*pass2fn) (data, ss2sa (&lifr->iflr_addr)))
820*781Sgtb goto punt;
821*781Sgtb /*@=moduncon@*/
822*781Sgtb }
823*781Sgtb }
824*781Sgtb punt:
825*781Sgtb FOREACH_AF () {
826*781Sgtb /*@-moduncon@*/
827*781Sgtb closesocket(P.sock);
828*781Sgtb /*@=moduncon@*/
829*781Sgtb free (P.buf);
830*781Sgtb }
831*781Sgtb
832*781Sgtb return retval;
833*781Sgtb }
834*781Sgtb
835*781Sgtb #else /* not defined (SIOCGLIFNUM) */
836*781Sgtb
837*781Sgtb #define SLOP (sizeof (struct ifreq) + 128)
838*781Sgtb
839*781Sgtb static int
get_ifreq_array(char ** bufp,size_t * np,int s)840*781Sgtb get_ifreq_array(char **bufp, size_t *np, int s)
841*781Sgtb {
842*781Sgtb int code;
843*781Sgtb int est_if_count = 8;
844*781Sgtb size_t est_ifreq_size;
845*781Sgtb char *buf = 0;
846*781Sgtb size_t current_buf_size = 0, size, n;
847*781Sgtb #ifdef SIOCGSIZIFCONF
848*781Sgtb int ifconfsize = -1;
849*781Sgtb #endif
850*781Sgtb #ifdef SIOCGIFNUM
851*781Sgtb int numifs = -1;
852*781Sgtb #endif
853*781Sgtb
854*781Sgtb /* At least on NetBSD, an ifreq can hold an IPv4 address, but
855*781Sgtb isn't big enough for an IPv6 or ethernet address. So add a
856*781Sgtb little more space. */
857*781Sgtb est_ifreq_size = sizeof (struct ifreq) + 8;
858*781Sgtb #ifdef SIOCGSIZIFCONF
859*781Sgtb code = ioctl (s, SIOCGSIZIFCONF, &ifconfsize);
860*781Sgtb if (!code) {
861*781Sgtb current_buf_size = ifconfsize;
862*781Sgtb est_if_count = ifconfsize / est_ifreq_size;
863*781Sgtb }
864*781Sgtb #elif defined (SIOCGIFNUM)
865*781Sgtb code = ioctl (s, SIOCGIFNUM, &numifs);
866*781Sgtb if (!code && numifs > 0)
867*781Sgtb est_if_count = numifs;
868*781Sgtb #endif
869*781Sgtb if (current_buf_size == 0)
870*781Sgtb current_buf_size = est_ifreq_size * est_if_count + SLOP;
871*781Sgtb buf = malloc (current_buf_size);
872*781Sgtb if (buf == NULL)
873*781Sgtb return errno;
874*781Sgtb
875*781Sgtb ask_again:
876*781Sgtb size = current_buf_size;
877*781Sgtb code = get_ifconf (s, &size, buf);
878*781Sgtb if (code < 0) {
879*781Sgtb code = errno;
880*781Sgtb free (buf);
881*781Sgtb return code;
882*781Sgtb }
883*781Sgtb /* Test that the buffer was big enough that another ifreq could've
884*781Sgtb fit easily, if the OS wanted to provide one. That seems to be
885*781Sgtb the only indication we get, complicated by the fact that the
886*781Sgtb associated address may make the required storage a little
887*781Sgtb bigger than the size of an ifreq. */
888*781Sgtb if (current_buf_size - size < SLOP
889*781Sgtb #ifdef SIOCGSIZIFCONF
890*781Sgtb /* Unless we hear SIOCGSIZIFCONF is broken somewhere, let's
891*781Sgtb trust the value it returns. */
892*781Sgtb && ifconfsize <= 0
893*781Sgtb #elif defined (SIOCGIFNUM)
894*781Sgtb && numifs <= 0
895*781Sgtb #endif
896*781Sgtb /* And we need *some* sort of bounds. */
897*781Sgtb && current_buf_size <= 100000
898*781Sgtb ) {
899*781Sgtb size_t new_size;
900*781Sgtb
901*781Sgtb est_if_count *= 2;
902*781Sgtb new_size = est_ifreq_size * est_if_count + SLOP;
903*781Sgtb buf = grow_or_free (buf, new_size);
904*781Sgtb if (buf == 0)
905*781Sgtb return errno;
906*781Sgtb current_buf_size = new_size;
907*781Sgtb goto ask_again;
908*781Sgtb }
909*781Sgtb
910*781Sgtb n = size;
911*781Sgtb if (n > current_buf_size)
912*781Sgtb n = current_buf_size;
913*781Sgtb
914*781Sgtb *bufp = buf;
915*781Sgtb *np = n;
916*781Sgtb return 0;
917*781Sgtb }
918*781Sgtb
919*781Sgtb int
foreach_localaddr(void * data,int (* pass1fn)(void *,struct sockaddr *),int (* betweenfn)(void *),int (* pass2fn)(void *,struct sockaddr *))920*781Sgtb foreach_localaddr (/*@null@*/ void *data,
921*781Sgtb int (*pass1fn) (/*@null@*/ void *, struct sockaddr *) /*@*/,
922*781Sgtb /*@null@*/ int (*betweenfn) (/*@null@*/ void *) /*@*/,
923*781Sgtb /*@null@*/ int (*pass2fn) (/*@null@*/ void *,
924*781Sgtb struct sockaddr *) /*@*/)
925*781Sgtb #if defined(DEBUG) || defined(TEST)
926*781Sgtb /*@modifies fileSystem@*/
927*781Sgtb #endif
928*781Sgtb {
929*781Sgtb struct ifreq *ifr, ifreq, *ifr2;
930*781Sgtb int s, code;
931*781Sgtb char *buf = 0;
932*781Sgtb size_t size, n, i, j;
933*781Sgtb int retval = 0;
934*781Sgtb #ifdef LINUX_IPV6_HACK
935*781Sgtb struct linux_ipv6_addr_list *linux_ipv6_addrs = get_linux_ipv6_addrs ();
936*781Sgtb struct linux_ipv6_addr_list *lx_v6;
937*781Sgtb #endif
938*781Sgtb
939*781Sgtb s = socket (USE_AF, USE_TYPE, USE_PROTO);
940*781Sgtb if (s < 0)
941*781Sgtb return SOCKET_ERRNO;
942*781Sgtb
943*781Sgtb retval = get_ifreq_array(&buf, &n, s);
944*781Sgtb if (retval) {
945*781Sgtb /*@-moduncon@*/ /* close() unknown to lclint */
946*781Sgtb closesocket(s);
947*781Sgtb /*@=moduncon@*/
948*781Sgtb return retval;
949*781Sgtb }
950*781Sgtb
951*781Sgtb /* Note: Apparently some systems put the size (used or wanted?)
952*781Sgtb into the start of the buffer, just none that I'm actually
953*781Sgtb using. Fix this when there's such a test system available.
954*781Sgtb The Samba mailing list archives mention that NTP looks for the
955*781Sgtb size on these systems: *-fujitsu-uxp* *-ncr-sysv4*
956*781Sgtb *-univel-sysv*. */
957*781Sgtb for (i = 0; i + sizeof(struct ifreq) <= n; i+= ifreq_size(*ifr) ) {
958*781Sgtb ifr = (struct ifreq *)((caddr_t) buf+i);
959*781Sgtb /* In case ifreq_size is more than sizeof(). */
960*781Sgtb if (i + ifreq_size(*ifr) > n)
961*781Sgtb break;
962*781Sgtb
963*781Sgtb strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof (ifreq.ifr_name));
964*781Sgtb Tprintf (("interface %s\n", ifreq.ifr_name));
965*781Sgtb /*@-moduncon@*/ /* ioctl unknown to lclint */
966*781Sgtb if (ioctl (s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
967*781Sgtb skip:
968*781Sgtb /* mark for next pass */
969*781Sgtb ifr->ifr_name[0] = '\0';
970*781Sgtb continue;
971*781Sgtb }
972*781Sgtb /*@=moduncon@*/
973*781Sgtb
974*781Sgtb #ifdef IFF_LOOPBACK
975*781Sgtb /* None of the current callers want loopback addresses. */
976*781Sgtb if (ifreq.ifr_flags & IFF_LOOPBACK) {
977*781Sgtb Tprintf ((" loopback\n"));
978*781Sgtb goto skip;
979*781Sgtb }
980*781Sgtb #endif
981*781Sgtb /* Ignore interfaces that are down. */
982*781Sgtb if ((ifreq.ifr_flags & IFF_UP) == 0) {
983*781Sgtb Tprintf ((" down\n"));
984*781Sgtb goto skip;
985*781Sgtb }
986*781Sgtb
987*781Sgtb /* Make sure we didn't process this address already. */
988*781Sgtb for (j = 0; j < i; j += ifreq_size(*ifr2)) {
989*781Sgtb ifr2 = (struct ifreq *)((caddr_t) buf+j);
990*781Sgtb if (ifr2->ifr_name[0] == '\0')
991*781Sgtb continue;
992*781Sgtb if (ifr2->ifr_addr.sa_family == ifr->ifr_addr.sa_family
993*781Sgtb && ifreq_size (*ifr) == ifreq_size (*ifr2)
994*781Sgtb /* Compare address info. If this isn't good enough --
995*781Sgtb i.e., if random padding bytes turn out to differ
996*781Sgtb when the addresses are the same -- then we'll have
997*781Sgtb to do it on a per address family basis. */
998*781Sgtb && !memcmp (&ifr2->ifr_addr.sa_data, &ifr->ifr_addr.sa_data,
999*781Sgtb (ifreq_size (*ifr)
1000*781Sgtb - offsetof (struct ifreq, ifr_addr.sa_data)))) {
1001*781Sgtb Tprintf ((" duplicate addr\n"));
1002*781Sgtb goto skip;
1003*781Sgtb }
1004*781Sgtb }
1005*781Sgtb
1006*781Sgtb /*@-moduncon@*/
1007*781Sgtb if ((*pass1fn) (data, &ifr->ifr_addr))
1008*781Sgtb goto punt;
1009*781Sgtb /*@=moduncon@*/
1010*781Sgtb }
1011*781Sgtb
1012*781Sgtb #ifdef LINUX_IPV6_HACK
1013*781Sgtb for (lx_v6 = linux_ipv6_addrs; lx_v6; lx_v6 = lx_v6->next)
1014*781Sgtb if ((*pass1fn) (data, (struct sockaddr *) &lx_v6->addr))
1015*781Sgtb goto punt;
1016*781Sgtb #endif
1017*781Sgtb
1018*781Sgtb /*@-moduncon@*/
1019*781Sgtb if (betweenfn != NULL && (*betweenfn)(data))
1020*781Sgtb goto punt;
1021*781Sgtb /*@=moduncon@*/
1022*781Sgtb
1023*781Sgtb if (pass2fn) {
1024*781Sgtb for (i = 0; i + sizeof(struct ifreq) <= n; i+= ifreq_size(*ifr) ) {
1025*781Sgtb ifr = (struct ifreq *)((caddr_t) buf+i);
1026*781Sgtb
1027*781Sgtb if (ifr->ifr_name[0] == '\0')
1028*781Sgtb /* Marked in first pass to be ignored. */
1029*781Sgtb continue;
1030*781Sgtb
1031*781Sgtb /*@-moduncon@*/
1032*781Sgtb if ((*pass2fn) (data, &ifr->ifr_addr))
1033*781Sgtb goto punt;
1034*781Sgtb /*@=moduncon@*/
1035*781Sgtb }
1036*781Sgtb #ifdef LINUX_IPV6_HACK
1037*781Sgtb for (lx_v6 = linux_ipv6_addrs; lx_v6; lx_v6 = lx_v6->next)
1038*781Sgtb if ((*pass2fn) (data, (struct sockaddr *) &lx_v6->addr))
1039*781Sgtb goto punt;
1040*781Sgtb #endif
1041*781Sgtb }
1042*781Sgtb punt:
1043*781Sgtb /*@-moduncon@*/
1044*781Sgtb closesocket(s);
1045*781Sgtb /*@=moduncon@*/
1046*781Sgtb free (buf);
1047*781Sgtb #ifdef LINUX_IPV6_HACK
1048*781Sgtb while (linux_ipv6_addrs) {
1049*781Sgtb lx_v6 = linux_ipv6_addrs->next;
1050*781Sgtb free (linux_ipv6_addrs);
1051*781Sgtb linux_ipv6_addrs = lx_v6;
1052*781Sgtb }
1053*781Sgtb #endif
1054*781Sgtb
1055*781Sgtb return retval;
1056*781Sgtb }
1057*781Sgtb
1058*781Sgtb #endif /* not HAVE_IFADDRS_H and not SIOCGLIFNUM */
1059*781Sgtb
10600Sstevel@tonic-gate static krb5_error_code
10610Sstevel@tonic-gate get_localaddrs (krb5_context context, krb5_address ***addr, int use_profile);
10620Sstevel@tonic-gate
1063*781Sgtb #ifdef TEST
1064*781Sgtb
print_addr(void * dataptr,struct sockaddr * sa)1065*781Sgtb static int print_addr (/*@unused@*/ void *dataptr, struct sockaddr *sa)
1066*781Sgtb /*@modifies fileSystem@*/
1067*781Sgtb {
1068*781Sgtb char hostbuf[NI_MAXHOST];
1069*781Sgtb int err;
1070*781Sgtb socklen_t len;
1071*781Sgtb
1072*781Sgtb printf (" --> family %2d ", sa->sa_family);
1073*781Sgtb len = socklen (sa);
1074*781Sgtb err = getnameinfo (sa, len, hostbuf, (socklen_t) sizeof (hostbuf),
1075*781Sgtb (char *) NULL, 0, NI_NUMERICHOST);
1076*781Sgtb if (err) {
1077*781Sgtb int e = errno;
1078*781Sgtb printf ("<getnameinfo error %d: %s>\n", err, gai_strerror (err));
1079*781Sgtb if (err == EAI_SYSTEM)
1080*781Sgtb printf ("\t\t<errno is %d: %s>\n", e, strerror(e));
1081*781Sgtb } else
1082*781Sgtb printf ("addr %s\n", hostbuf);
1083*781Sgtb return 0;
1084*781Sgtb }
1085*781Sgtb
main()1086*781Sgtb int main ()
1087*781Sgtb {
1088*781Sgtb int r;
1089*781Sgtb
1090*781Sgtb (void) setvbuf (stdout, (char *)NULL, _IONBF, 0);
1091*781Sgtb r = foreach_localaddr (0, print_addr, NULL, NULL);
1092*781Sgtb printf ("return value = %d\n", r);
1093*781Sgtb return 0;
1094*781Sgtb }
1095*781Sgtb
1096*781Sgtb #else /* not TESTing */
1097*781Sgtb
10980Sstevel@tonic-gate struct localaddr_data {
10990Sstevel@tonic-gate int count, mem_err, cur_idx, cur_size;
11000Sstevel@tonic-gate krb5_address **addr_temp;
11010Sstevel@tonic-gate };
11020Sstevel@tonic-gate
11030Sstevel@tonic-gate static int
count_addrs(void * P_data,struct sockaddr * a)11040Sstevel@tonic-gate count_addrs (void *P_data, struct sockaddr *a)
11050Sstevel@tonic-gate /*@*/
11060Sstevel@tonic-gate {
11070Sstevel@tonic-gate struct localaddr_data *data = P_data;
11080Sstevel@tonic-gate switch (a->sa_family) {
11090Sstevel@tonic-gate case AF_INET:
11100Sstevel@tonic-gate #ifdef KRB5_USE_INET6
11110Sstevel@tonic-gate case AF_INET6:
11120Sstevel@tonic-gate #endif
11130Sstevel@tonic-gate #ifdef KRB5_USE_NS
11140Sstevel@tonic-gate case AF_XNS:
11150Sstevel@tonic-gate #endif
11160Sstevel@tonic-gate data->count++;
11170Sstevel@tonic-gate break;
11180Sstevel@tonic-gate default:
11190Sstevel@tonic-gate break;
11200Sstevel@tonic-gate }
11210Sstevel@tonic-gate return 0;
11220Sstevel@tonic-gate }
11230Sstevel@tonic-gate
11240Sstevel@tonic-gate static int
allocate(void * P_data)11250Sstevel@tonic-gate allocate (void *P_data)
1126*781Sgtb /*@*/
11270Sstevel@tonic-gate {
11280Sstevel@tonic-gate struct localaddr_data *data = P_data;
11290Sstevel@tonic-gate int i;
11300Sstevel@tonic-gate void *n;
11310Sstevel@tonic-gate
11320Sstevel@tonic-gate n = realloc (data->addr_temp,
11330Sstevel@tonic-gate (1 + data->count + data->cur_idx) * sizeof (krb5_address *));
11340Sstevel@tonic-gate if (n == 0) {
11350Sstevel@tonic-gate data->mem_err++;
11360Sstevel@tonic-gate return 1;
11370Sstevel@tonic-gate }
11380Sstevel@tonic-gate data->addr_temp = n;
11390Sstevel@tonic-gate data->cur_size = 1 + data->count + data->cur_idx;
11400Sstevel@tonic-gate for (i = data->cur_idx; i <= data->count + data->cur_idx; i++)
11410Sstevel@tonic-gate data->addr_temp[i] = 0;
11420Sstevel@tonic-gate return 0;
11430Sstevel@tonic-gate }
11440Sstevel@tonic-gate
1145*781Sgtb static /*@null@*/ krb5_address *
make_addr(int type,size_t length,const void * contents)11460Sstevel@tonic-gate make_addr (int type, size_t length, const void *contents)
1147*781Sgtb /*@*/
11480Sstevel@tonic-gate {
11490Sstevel@tonic-gate krb5_address *a;
11500Sstevel@tonic-gate void *data;
11510Sstevel@tonic-gate
11520Sstevel@tonic-gate data = malloc (length);
11530Sstevel@tonic-gate if (data == NULL)
11540Sstevel@tonic-gate return NULL;
11550Sstevel@tonic-gate a = malloc (sizeof (krb5_address));
11560Sstevel@tonic-gate if (a == NULL) {
11570Sstevel@tonic-gate free (data);
11580Sstevel@tonic-gate return NULL;
11590Sstevel@tonic-gate }
11600Sstevel@tonic-gate memcpy (data, contents, length);
11610Sstevel@tonic-gate a->magic = KV5M_ADDRESS;
11620Sstevel@tonic-gate a->addrtype = type;
11630Sstevel@tonic-gate a->length = length;
11640Sstevel@tonic-gate a->contents = data;
11650Sstevel@tonic-gate return a;
11660Sstevel@tonic-gate }
11670Sstevel@tonic-gate
11680Sstevel@tonic-gate static int
add_addr(void * P_data,struct sockaddr * a)11690Sstevel@tonic-gate add_addr (void *P_data, struct sockaddr *a)
11700Sstevel@tonic-gate /*@modifies *P_data@*/
11710Sstevel@tonic-gate {
11720Sstevel@tonic-gate struct localaddr_data *data = P_data;
1173*781Sgtb /*@null@*/ krb5_address *address = 0;
11740Sstevel@tonic-gate
11750Sstevel@tonic-gate switch (a->sa_family) {
11760Sstevel@tonic-gate #ifdef HAVE_NETINET_IN_H
11770Sstevel@tonic-gate case AF_INET:
11780Sstevel@tonic-gate address = make_addr (ADDRTYPE_INET, sizeof (struct in_addr),
11790Sstevel@tonic-gate &((const struct sockaddr_in *) a)->sin_addr);
11800Sstevel@tonic-gate if (address == NULL)
11810Sstevel@tonic-gate data->mem_err++;
11820Sstevel@tonic-gate break;
11830Sstevel@tonic-gate
11840Sstevel@tonic-gate #ifdef KRB5_USE_INET6
11850Sstevel@tonic-gate case AF_INET6:
11860Sstevel@tonic-gate {
11870Sstevel@tonic-gate const struct sockaddr_in6 *in = (const struct sockaddr_in6 *) a;
11880Sstevel@tonic-gate
1189*781Sgtb if (IN6_IS_ADDR_LINKLOCAL (&in->sin6_addr))
11900Sstevel@tonic-gate break;
11910Sstevel@tonic-gate
11920Sstevel@tonic-gate address = make_addr (ADDRTYPE_INET6, sizeof (struct in6_addr),
11930Sstevel@tonic-gate &in->sin6_addr);
11940Sstevel@tonic-gate if (address == NULL)
11950Sstevel@tonic-gate data->mem_err++;
11960Sstevel@tonic-gate break;
11970Sstevel@tonic-gate }
11980Sstevel@tonic-gate #endif /* KRB5_USE_INET6 */
11990Sstevel@tonic-gate #endif /* netinet/in.h */
12000Sstevel@tonic-gate
12010Sstevel@tonic-gate #ifdef KRB5_USE_NS
12020Sstevel@tonic-gate case AF_XNS:
12030Sstevel@tonic-gate address = make_addr (ADDRTYPE_XNS, sizeof (struct ns_addr),
12040Sstevel@tonic-gate &((const struct sockaddr_ns *)a)->sns_addr);
12050Sstevel@tonic-gate if (address == NULL)
12060Sstevel@tonic-gate data->mem_err++;
12070Sstevel@tonic-gate break;
12080Sstevel@tonic-gate #endif
12090Sstevel@tonic-gate
12100Sstevel@tonic-gate #ifdef AF_LINK
12110Sstevel@tonic-gate /* Some BSD-based systems (e.g. NetBSD 1.5) and AIX will
12120Sstevel@tonic-gate include the ethernet address, but we don't want that, at
12130Sstevel@tonic-gate least for now. */
12140Sstevel@tonic-gate case AF_LINK:
12150Sstevel@tonic-gate break;
12160Sstevel@tonic-gate #endif
12170Sstevel@tonic-gate /*
12180Sstevel@tonic-gate * Add more address families here..
12190Sstevel@tonic-gate */
12200Sstevel@tonic-gate default:
12210Sstevel@tonic-gate break;
12220Sstevel@tonic-gate }
12230Sstevel@tonic-gate #ifdef __LCLINT__
12240Sstevel@tonic-gate /* Redundant but unconditional store un-confuses lclint. */
12250Sstevel@tonic-gate data->addr_temp[data->cur_idx] = address;
12260Sstevel@tonic-gate #endif
12270Sstevel@tonic-gate if (address) {
12280Sstevel@tonic-gate data->addr_temp[data->cur_idx++] = address;
12290Sstevel@tonic-gate }
12300Sstevel@tonic-gate
12310Sstevel@tonic-gate return data->mem_err;
12320Sstevel@tonic-gate }
12330Sstevel@tonic-gate
12340Sstevel@tonic-gate static krb5_error_code
krb5_os_localaddr_profile(krb5_context context,struct localaddr_data * datap)12350Sstevel@tonic-gate krb5_os_localaddr_profile (krb5_context context, struct localaddr_data *datap)
12360Sstevel@tonic-gate {
12370Sstevel@tonic-gate krb5_error_code err;
1238*781Sgtb static const char *const profile_name[] = {
12390Sstevel@tonic-gate "libdefaults", "extra_addresses", 0
12400Sstevel@tonic-gate };
12410Sstevel@tonic-gate char **values;
12420Sstevel@tonic-gate char **iter;
12430Sstevel@tonic-gate krb5_address **newaddrs;
12440Sstevel@tonic-gate
1245*781Sgtb #ifdef DEBUG
1246*781Sgtb fprintf (stderr, "looking up extra_addresses foo\n");
1247*781Sgtb #endif
1248*781Sgtb
12490Sstevel@tonic-gate err = profile_get_values (context->profile, profile_name, &values);
12500Sstevel@tonic-gate /* Ignore all errors for now? */
12510Sstevel@tonic-gate if (err)
12520Sstevel@tonic-gate return 0;
12530Sstevel@tonic-gate
12540Sstevel@tonic-gate for (iter = values; *iter; iter++) {
12550Sstevel@tonic-gate char *cp = *iter, *next, *current;
12560Sstevel@tonic-gate int i, count;
12570Sstevel@tonic-gate
1258*781Sgtb #ifdef DEBUG
1259*781Sgtb fprintf (stderr, " found line: '%s'\n", cp);
1260*781Sgtb #endif
1261*781Sgtb
12620Sstevel@tonic-gate for (cp = *iter, next = 0; *cp; cp = next) {
12630Sstevel@tonic-gate while (isspace ((int) *cp) || *cp == ',')
12640Sstevel@tonic-gate cp++;
12650Sstevel@tonic-gate if (*cp == 0)
12660Sstevel@tonic-gate break;
12670Sstevel@tonic-gate /* Start of an address. */
1268*781Sgtb #ifdef DEBUG
1269*781Sgtb fprintf (stderr, " addr found in '%s'\n", cp);
1270*781Sgtb #endif
12710Sstevel@tonic-gate current = cp;
12720Sstevel@tonic-gate while (*cp != 0 && !isspace((int) *cp) && *cp != ',')
12730Sstevel@tonic-gate cp++;
12740Sstevel@tonic-gate if (*cp != 0) {
12750Sstevel@tonic-gate next = cp + 1;
12760Sstevel@tonic-gate *cp = 0;
12770Sstevel@tonic-gate } else
12780Sstevel@tonic-gate next = cp;
12790Sstevel@tonic-gate /* Got a single address, process it. */
1280*781Sgtb #ifdef DEBUG
1281*781Sgtb fprintf (stderr, " processing '%s'\n", current);
1282*781Sgtb #endif
12830Sstevel@tonic-gate newaddrs = 0;
12840Sstevel@tonic-gate err = krb5_os_hostaddr (context, current, &newaddrs);
12850Sstevel@tonic-gate if (err)
12860Sstevel@tonic-gate continue;
12870Sstevel@tonic-gate for (i = 0; newaddrs[i]; i++) {
1288*781Sgtb #ifdef DEBUG
1289*781Sgtb fprintf (stderr, " %d: family %d", i,
1290*781Sgtb newaddrs[i]->addrtype);
1291*781Sgtb fprintf (stderr, "\n");
1292*781Sgtb #endif
12930Sstevel@tonic-gate }
12940Sstevel@tonic-gate count = i;
1295*781Sgtb #ifdef DEBUG
1296*781Sgtb fprintf (stderr, " %d addresses\n", count);
1297*781Sgtb #endif
12980Sstevel@tonic-gate if (datap->cur_idx + count >= datap->cur_size) {
12990Sstevel@tonic-gate krb5_address **bigger;
13000Sstevel@tonic-gate bigger = realloc (datap->addr_temp,
13010Sstevel@tonic-gate sizeof (krb5_address *) * (datap->cur_idx + count));
13020Sstevel@tonic-gate if (bigger) {
13030Sstevel@tonic-gate datap->addr_temp = bigger;
13040Sstevel@tonic-gate datap->cur_size = datap->cur_idx + count;
13050Sstevel@tonic-gate }
13060Sstevel@tonic-gate }
13070Sstevel@tonic-gate for (i = 0; i < count; i++) {
13080Sstevel@tonic-gate if (datap->cur_idx < datap->cur_size)
13090Sstevel@tonic-gate datap->addr_temp[datap->cur_idx++] = newaddrs[i];
13100Sstevel@tonic-gate else
13110Sstevel@tonic-gate free (newaddrs[i]->contents), free (newaddrs[i]);
13120Sstevel@tonic-gate }
13130Sstevel@tonic-gate free (newaddrs);
13140Sstevel@tonic-gate }
13150Sstevel@tonic-gate }
13160Sstevel@tonic-gate return 0;
13170Sstevel@tonic-gate }
13180Sstevel@tonic-gate
13190Sstevel@tonic-gate krb5_error_code KRB5_CALLCONV
krb5_os_localaddr(krb5_context context,krb5_address *** addr)13200Sstevel@tonic-gate krb5_os_localaddr(krb5_context context, krb5_address ***addr)
13210Sstevel@tonic-gate {
13220Sstevel@tonic-gate return get_localaddrs(context, addr, 1);
13230Sstevel@tonic-gate }
13240Sstevel@tonic-gate
13250Sstevel@tonic-gate krb5_error_code
krb5int_local_addresses(krb5_context context,krb5_address *** addr)13260Sstevel@tonic-gate krb5int_local_addresses(krb5_context context, krb5_address ***addr)
13270Sstevel@tonic-gate {
13280Sstevel@tonic-gate return get_localaddrs(context, addr, 0);
13290Sstevel@tonic-gate }
13300Sstevel@tonic-gate
13310Sstevel@tonic-gate static krb5_error_code
get_localaddrs(krb5_context context,krb5_address *** addr,int use_profile)13320Sstevel@tonic-gate get_localaddrs (krb5_context context, krb5_address ***addr, int use_profile)
13330Sstevel@tonic-gate {
13340Sstevel@tonic-gate struct localaddr_data data = { 0 };
13350Sstevel@tonic-gate int r;
1336*781Sgtb krb5_error_code err;
13370Sstevel@tonic-gate
13380Sstevel@tonic-gate if (use_profile) {
1339*781Sgtb err = krb5_os_localaddr_profile (context, &data);
13400Sstevel@tonic-gate /* ignore err for now */
13410Sstevel@tonic-gate }
13420Sstevel@tonic-gate
13430Sstevel@tonic-gate r = foreach_localaddr (&data, count_addrs, allocate, add_addr);
13440Sstevel@tonic-gate if (r != 0) {
13450Sstevel@tonic-gate int i;
13460Sstevel@tonic-gate if (data.addr_temp) {
13470Sstevel@tonic-gate for (i = 0; i < data.count; i++)
13480Sstevel@tonic-gate krb5_xfree (data.addr_temp[i]);
13490Sstevel@tonic-gate free (data.addr_temp);
13500Sstevel@tonic-gate }
13510Sstevel@tonic-gate if (data.mem_err)
13520Sstevel@tonic-gate return ENOMEM;
13530Sstevel@tonic-gate else
13540Sstevel@tonic-gate return r;
13550Sstevel@tonic-gate }
13560Sstevel@tonic-gate
13570Sstevel@tonic-gate data.cur_idx++; /* null termination */
13580Sstevel@tonic-gate if (data.mem_err)
13590Sstevel@tonic-gate return ENOMEM;
13600Sstevel@tonic-gate else if (data.cur_idx == data.count)
13610Sstevel@tonic-gate *addr = data.addr_temp;
13620Sstevel@tonic-gate else {
13630Sstevel@tonic-gate /* This can easily happen if we have IPv6 link-local
13640Sstevel@tonic-gate addresses. Just shorten the array. */
13650Sstevel@tonic-gate *addr = (krb5_address **) realloc (data.addr_temp,
13660Sstevel@tonic-gate (sizeof (krb5_address *)
13670Sstevel@tonic-gate * data.cur_idx));
13680Sstevel@tonic-gate if (*addr == 0)
13690Sstevel@tonic-gate /* Okay, shortening failed, but the original should still
13700Sstevel@tonic-gate be intact. */
13710Sstevel@tonic-gate *addr = data.addr_temp;
13720Sstevel@tonic-gate }
13730Sstevel@tonic-gate
1374*781Sgtb #ifdef DEBUG
1375*781Sgtb {
1376*781Sgtb int j;
1377*781Sgtb fprintf (stderr, "addresses:\n");
1378*781Sgtb for (j = 0; addr[0][j]; j++) {
1379*781Sgtb struct sockaddr_storage ss;
1380*781Sgtb int err2;
1381*781Sgtb char namebuf[NI_MAXHOST];
1382*781Sgtb void *addrp = 0;
1383*781Sgtb
1384*781Sgtb fprintf (stderr, "%2d: ", j);
1385*781Sgtb fprintf (stderr, "addrtype %2d, length %2d", addr[0][j]->addrtype,
1386*781Sgtb addr[0][j]->length);
1387*781Sgtb memset (&ss, 0, sizeof (ss));
1388*781Sgtb switch (addr[0][j]->addrtype) {
1389*781Sgtb case ADDRTYPE_INET:
1390*781Sgtb {
1391*781Sgtb struct sockaddr_in *sinp = ss2sin (&ss);
1392*781Sgtb sinp->sin_family = AF_INET;
1393*781Sgtb addrp = &sinp->sin_addr;
1394*781Sgtb #ifdef HAVE_SA_LEN
1395*781Sgtb sinp->sin_len = sizeof (struct sockaddr_in);
1396*781Sgtb #endif
1397*781Sgtb break;
1398*781Sgtb }
1399*781Sgtb #ifdef KRB5_USE_INET6
1400*781Sgtb case ADDRTYPE_INET6:
1401*781Sgtb {
1402*781Sgtb struct sockaddr_in6 *sin6p = ss2sin6 (&ss);
1403*781Sgtb sin6p->sin6_family = AF_INET6;
1404*781Sgtb addrp = &sin6p->sin6_addr;
1405*781Sgtb #ifdef HAVE_SA_LEN
1406*781Sgtb sin6p->sin6_len = sizeof (struct sockaddr_in6);
1407*781Sgtb #endif
1408*781Sgtb break;
1409*781Sgtb }
1410*781Sgtb #endif
1411*781Sgtb default:
1412*781Sgtb ss2sa(&ss)->sa_family = 0;
1413*781Sgtb break;
1414*781Sgtb }
1415*781Sgtb if (addrp)
1416*781Sgtb memcpy (addrp, addr[0][j]->contents, addr[0][j]->length);
1417*781Sgtb err2 = getnameinfo (ss2sa(&ss), socklen (ss2sa (&ss)),
1418*781Sgtb namebuf, sizeof (namebuf), 0, 0,
1419*781Sgtb NI_NUMERICHOST);
1420*781Sgtb if (err2 == 0)
1421*781Sgtb fprintf (stderr, ": addr %s\n", namebuf);
1422*781Sgtb else
1423*781Sgtb fprintf (stderr, ": getnameinfo error %d\n", err2);
1424*781Sgtb }
1425*781Sgtb }
1426*781Sgtb #endif
1427*781Sgtb
14280Sstevel@tonic-gate return 0;
14290Sstevel@tonic-gate }
14300Sstevel@tonic-gate
1431*781Sgtb #endif /* not TESTing */
1432*781Sgtb
1433*781Sgtb #else /* Windows/Mac version */
1434*781Sgtb
1435*781Sgtb /*
1436*781Sgtb * Hold on to your lunch! Backup kludge method of obtaining your
1437*781Sgtb * local IP address, courtesy of Windows Socket Network Programming,
1438*781Sgtb * by Robert Quinn
1439*781Sgtb */
1440*781Sgtb #if defined(_WIN32)
local_addr_fallback_kludge()1441*781Sgtb static struct hostent *local_addr_fallback_kludge()
1442*781Sgtb {
1443*781Sgtb static struct hostent host;
1444*781Sgtb static SOCKADDR_IN addr;
1445*781Sgtb static char * ip_ptrs[2];
1446*781Sgtb SOCKET sock;
1447*781Sgtb int size = sizeof(SOCKADDR);
1448*781Sgtb int err;
1449*781Sgtb
1450*781Sgtb sock = socket(AF_INET, SOCK_DGRAM, 0);
1451*781Sgtb if (sock == INVALID_SOCKET)
1452*781Sgtb return NULL;
1453*781Sgtb
1454*781Sgtb /* connect to arbitrary port and address (NOT loopback) */
1455*781Sgtb addr.sin_family = AF_INET;
1456*781Sgtb addr.sin_port = htons(IPPORT_ECHO);
1457*781Sgtb addr.sin_addr.s_addr = inet_addr("204.137.220.51");
1458*781Sgtb
1459*781Sgtb err = connect(sock, (LPSOCKADDR) &addr, sizeof(SOCKADDR));
1460*781Sgtb if (err == SOCKET_ERROR)
1461*781Sgtb return NULL;
1462*781Sgtb
1463*781Sgtb err = getsockname(sock, (LPSOCKADDR) &addr, (int *) size);
1464*781Sgtb if (err == SOCKET_ERROR)
1465*781Sgtb return NULL;
1466*781Sgtb
1467*781Sgtb closesocket(sock);
1468*781Sgtb
1469*781Sgtb host.h_name = 0;
1470*781Sgtb host.h_aliases = 0;
1471*781Sgtb host.h_addrtype = AF_INET;
1472*781Sgtb host.h_length = 4;
1473*781Sgtb host.h_addr_list = ip_ptrs;
1474*781Sgtb ip_ptrs[0] = (char *) &addr.sin_addr.s_addr;
1475*781Sgtb ip_ptrs[1] = NULL;
1476*781Sgtb
1477*781Sgtb return &host;
1478*781Sgtb }
1479*781Sgtb #endif
1480*781Sgtb
1481*781Sgtb /* No ioctls in winsock so we just assume there is only one networking
1482*781Sgtb * card per machine, so gethostent is good enough.
1483*781Sgtb */
1484*781Sgtb krb5_error_code KRB5_CALLCONV
krb5_os_localaddr(krb5_context context,krb5_address *** addr)1485*781Sgtb krb5_os_localaddr (krb5_context context, krb5_address ***addr) {
1486*781Sgtb char host[64]; /* Name of local machine */
1487*781Sgtb struct hostent *hostrec;
1488*781Sgtb int err, count, i;
1489*781Sgtb krb5_address ** paddr;
1490*781Sgtb
1491*781Sgtb *addr = 0;
1492*781Sgtb paddr = 0;
1493*781Sgtb err = 0;
1494*781Sgtb
1495*781Sgtb if (gethostname (host, sizeof(host))) {
1496*781Sgtb err = SOCKET_ERRNO;
1497*781Sgtb }
1498*781Sgtb
1499*781Sgtb if (!err) {
1500*781Sgtb hostrec = gethostbyname (host);
1501*781Sgtb if (hostrec == NULL) {
1502*781Sgtb err = SOCKET_ERRNO;
1503*781Sgtb }
1504*781Sgtb }
1505*781Sgtb
1506*781Sgtb if (err) {
1507*781Sgtb hostrec = local_addr_fallback_kludge();
1508*781Sgtb if (!hostrec)
1509*781Sgtb return err;
1510*781Sgtb else
1511*781Sgtb err = 0; /* otherwise we will die at cleanup */
1512*781Sgtb }
1513*781Sgtb
1514*781Sgtb for (count = 0; hostrec->h_addr_list[count]; count++);
1515*781Sgtb
1516*781Sgtb
1517*781Sgtb paddr = (krb5_address **)malloc(sizeof(krb5_address *) * (count+1));
1518*781Sgtb if (!paddr) {
1519*781Sgtb err = ENOMEM;
1520*781Sgtb goto cleanup;
1521*781Sgtb }
1522*781Sgtb
1523*781Sgtb memset(paddr, 0, sizeof(krb5_address *) * (count+1));
1524*781Sgtb
1525*781Sgtb for (i = 0; i < count; i++)
1526*781Sgtb {
1527*781Sgtb paddr[i] = (krb5_address *)malloc(sizeof(krb5_address));
1528*781Sgtb if (paddr[i] == NULL) {
1529*781Sgtb err = ENOMEM;
1530*781Sgtb goto cleanup;
1531*781Sgtb }
1532*781Sgtb
1533*781Sgtb paddr[i]->magic = KV5M_ADDRESS;
1534*781Sgtb paddr[i]->addrtype = hostrec->h_addrtype;
1535*781Sgtb paddr[i]->length = hostrec->h_length;
1536*781Sgtb paddr[i]->contents = (unsigned char *)malloc(paddr[i]->length);
1537*781Sgtb if (!paddr[i]->contents) {
1538*781Sgtb err = ENOMEM;
1539*781Sgtb goto cleanup;
1540*781Sgtb }
1541*781Sgtb memcpy(paddr[i]->contents,
1542*781Sgtb hostrec->h_addr_list[i],
1543*781Sgtb paddr[i]->length);
1544*781Sgtb }
1545*781Sgtb
1546*781Sgtb cleanup:
1547*781Sgtb if (err) {
1548*781Sgtb if (paddr) {
1549*781Sgtb for (i = 0; i < count; i++)
1550*781Sgtb {
1551*781Sgtb if (paddr[i]) {
1552*781Sgtb if (paddr[i]->contents)
1553*781Sgtb free(paddr[i]->contents);
1554*781Sgtb free(paddr[i]);
1555*781Sgtb }
1556*781Sgtb }
1557*781Sgtb free(paddr);
1558*781Sgtb }
1559*781Sgtb }
1560*781Sgtb else
1561*781Sgtb *addr = paddr;
1562*781Sgtb
1563*781Sgtb return(err);
1564*781Sgtb }
1565*781Sgtb #endif
1566