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