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