Home | History | Annotate | Download | only in support
      1 /*
      2  * Copyright (C) 2001,2002,2003,2004,2005,2006 by the Massachusetts Institute of Technology,
      3  * Cambridge, MA, USA.  All Rights Reserved.
      4  *
      5  * This software is being provided to you, the LICENSEE, by the
      6  * Massachusetts Institute of Technology (M.I.T.) under the following
      7  * license.  By obtaining, using and/or copying this software, you agree
      8  * that you have read, understood, and will comply with these terms and
      9  * conditions:
     10  *
     11  * Export of this software from the United States of America may
     12  * require a specific license from the United States Government.
     13  * It is the responsibility of any person or organization contemplating
     14  * export to obtain such a license before exporting.
     15  *
     16  * WITHIN THAT CONSTRAINT, permission to use, copy, modify and distribute
     17  * this software and its documentation for any purpose and without fee or
     18  * royalty is hereby granted, provided that you agree to comply with the
     19  * following copyright notice and statements, including the disclaimer, and
     20  * that the same appear on ALL copies of the software and documentation,
     21  * including modifications that you make for internal use or for
     22  * distribution:
     23  *
     24  * THIS SOFTWARE IS PROVIDED "AS IS", AND M.I.T. MAKES NO REPRESENTATIONS
     25  * OR WARRANTIES, EXPRESS OR IMPLIED.  By way of example, but not
     26  * limitation, M.I.T. MAKES NO REPRESENTATIONS OR WARRANTIES OF
     27  * MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF
     28  * THE LICENSED SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY THIRD PARTY
     29  * PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
     30  *
     31  * The name of the Massachusetts Institute of Technology or M.I.T. may NOT
     32  * be used in advertising or publicity pertaining to distribution of the
     33  * software.  Title to copyright in this software and any associated
     34  * documentation shall at all times remain with M.I.T., and USER agrees to
     35  * preserve same.
     36  *
     37  * Furthermore if you modify this software you must label
     38  * your software as modified software and not distribute it in such a
     39  * fashion that it might be confused with the original M.I.T. software.
     40  */
     41 
     42 /* Approach overview:
     43 
     44    If a system version is available but buggy, save handles to it,
     45    redefine the names to refer to static functions defined here, and
     46    in those functions, call the system versions and fix up the
     47    returned data.  Use the native data structures and flag values.
     48 
     49    If no system version exists, use gethostby* and fake it.  Define
     50    the data structures and flag values locally.
     51 
     52 
     53    On Mac OS X, getaddrinfo results aren't cached (though
     54    gethostbyname results are), so we need to build a cache here.  Now
     55    things are getting really messy.  Because the cache is in use, we
     56    use getservbyname, and throw away thread safety.  (Not that the
     57    cache is thread safe, but when we get locking support, that'll be
     58    dealt with.)  This code needs tearing down and rebuilding, soon.
     59 
     60 
     61    Note that recent Windows developers' code has an interesting hack:
     62    When you include the right header files, with the right set of
     63    macros indicating system versions, you'll get an inline function
     64    that looks for getaddrinfo (or whatever) in the system library, and
     65    calls it if it's there.  If it's not there, it fakes it with
     66    gethostby* calls.
     67 
     68    We're taking a simpler approach: A system provides these routines or
     69    it does not.
     70 
     71    Someday, we may want to take into account different versions (say,
     72    different revs of GNU libc) where some are broken in one way, and
     73    some work or are broken in another way.  Cross that bridge when we
     74    come to it.  */
     75 
     76 /* To do, maybe:
     77 
     78    + For AIX 4.3.3, using the RFC 2133 definition: Implement
     79      AI_NUMERICHOST.  It's not defined in the header file.
     80 
     81      For certain (old?) versions of GNU libc, AI_NUMERICHOST is
     82      defined but not implemented.
     83 
     84    + Use gethostbyname2, inet_aton and other IPv6 or thread-safe
     85      functions if available.  But, see
     86      http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=135182 for one
     87      gethostbyname2 problem on Linux.  And besides, if a platform is
     88      supporting IPv6 at all, they really should be doing getaddrinfo
     89      by now.
     90 
     91    + inet_ntop, inet_pton
     92 
     93    + Conditionally export/import the function definitions, so a
     94      library can have a single copy instead of multiple.
     95 
     96    + Upgrade host requirements to include working implementations of
     97      these functions, and throw all this away.  Pleeease?  :-)  */
     98 
     99 #include "port-sockets.h"
    100 #include "socket-utils.h"
    101 #include "k5-platform.h"
    102 #include "k5-thread.h"
    103 #include "supp-int.h"
    104 
    105 #include <stdio.h>		/* for sprintf */
    106 #include <errno.h>
    107 
    108 #define IMPLEMENT_FAKE_GETADDRINFO
    109 #include "fake-addrinfo.h"
    110 
    111 #ifdef S_SPLINT_S
    112 /*@-incondefs@*/
    113 extern int
    114 getaddrinfo (/*@in@*/ /*@null@*/ const char *,
    115 	     /*@in@*/ /*@null@*/ const char *,
    116 	     /*@in@*/ /*@null@*/ const struct addrinfo *,
    117 	     /*@out@*/ struct addrinfo **)
    118     ;
    119 extern void
    120 freeaddrinfo (/*@only@*/ /*@out@*/ struct addrinfo *)
    121     ;
    122 extern int
    123 getnameinfo (const struct sockaddr *addr, socklen_t addrsz,
    124 	     /*@out@*/ /*@null@*/ char *h, socklen_t hsz,
    125 	     /*@out@*/ /*@null@*/ char *s, socklen_t ssz,
    126 	     int flags)
    127     /*@requires (maxSet(h)+1) >= hsz /\ (maxSet(s)+1) >= ssz @*/
    128     /* too hard: maxRead(addr) >= (addrsz-1) */
    129     /*@modifies *h, *s@*/;
    130 extern /*@dependent@*/ char *gai_strerror (int code) /*@*/;
    131 /*@=incondefs@*/
    132 #endif
    133 
    134 
    135 #include "cache-addrinfo.h"
    136 
    137 #if (defined (__linux__) && defined(HAVE_GETADDRINFO)) || defined (_AIX)
    138 /* See comments below.  */
    139 #  define WRAP_GETADDRINFO
    140 #endif
    141 
    142 #if defined (__linux__) && defined(HAVE_GETADDRINFO)
    143 # define COPY_FIRST_CANONNAME
    144 #endif
    145 
    146 #ifdef _AIX
    147 # define NUMERIC_SERVICE_BROKEN
    148 # define COPY_FIRST_CANONNAME
    149 #endif
    150 
    151 
    152 #ifdef COPY_FIRST_CANONNAME
    153 # include <string.h>
    154 #endif
    155 
    156 #ifdef NUMERIC_SERVICE_BROKEN
    157 # include <ctype.h>		/* isdigit */
    158 # include <stdlib.h>		/* strtoul */
    159 #endif
    160 
    161 
    162 /* Do we actually have *any* systems we care about that don't provide
    163    either getaddrinfo or one of these two flavors of
    164    gethostbyname_r?  */
    165 #if !defined(HAVE_GETHOSTBYNAME_R) || defined(THREADSAFE_GETHOSTBYNAME)
    166 typedef struct hostent *GET_HOST_TMP;
    167 #define GET_HOST_BY_NAME(NAME, HP, ERR, TMP) \
    168     { TMP = gethostbyname (NAME); (ERR) = h_errno; (HP) = TMP; }
    169 #define GET_HOST_BY_ADDR(ADDR, ADDRLEN, FAMILY, HP, ERR, TMP) \
    170     { TMP = gethostbyaddr ((ADDR), (ADDRLEN), (FAMILY)); (ERR) = h_errno; (HP) = TMP; }
    171 #else
    172 #ifdef _AIX /* XXX should have a feature test! */
    173 typedef struct {
    174     struct hostent ent;
    175     struct hostent_data data;
    176 } GET_HOST_TMP;
    177 #define GET_HOST_BY_NAME(NAME, HP, ERR, TMP) \
    178     {								\
    179 	(HP) = (gethostbyname_r((NAME), &TMP.ent, &TMP.data)	\
    180 		? 0						\
    181 		: &TMP.ent);					\
    182 	(ERR) = h_errno;					\
    183     }
    184 /*
    185 #define GET_HOST_BY_ADDR(ADDR, ADDRLEN, FAMILY, HP, ERR) \
    186     {									\
    187 	struct hostent my_h_ent;					\
    188 	struct hostent_data my_h_ent_data;				\
    189 	(HP) = (gethostbyaddr_r((ADDR), (ADDRLEN), (FAMILY), &my_h_ent,	\
    190 				&my_h_ent_data)				\
    191 		? 0							\
    192 		: &my_h_ent);						\
    193 	(ERR) = my_h_err;						\
    194     }
    195 */
    196 #else
    197 #ifdef GETHOSTBYNAME_R_RETURNS_INT
    198 typedef struct {
    199     struct hostent ent;
    200     char buf[8192];
    201 } GET_HOST_TMP;
    202 #define GET_HOST_BY_NAME(NAME, HP, ERR, TMP) \
    203     {									\
    204 	struct hostent *my_hp = NULL;					\
    205 	int my_h_err, my_ret;						\
    206 	my_ret = gethostbyname_r((NAME), &TMP.ent,			\
    207 				 TMP.buf, sizeof (TMP.buf), &my_hp,	\
    208 				 &my_h_err);				\
    209 	(HP) = (((my_ret != 0) || (my_hp != &TMP.ent))			\
    210 		? 0							\
    211 		: &TMP.ent);						\
    212 	(ERR) = my_h_err;						\
    213     }
    214 #define GET_HOST_BY_ADDR(ADDR, ADDRLEN, FAMILY, HP, ERR, TMP) \
    215     {									\
    216 	struct hostent *my_hp;						\
    217 	int my_h_err, my_ret;						\
    218 	my_ret = gethostbyaddr_r((ADDR), (ADDRLEN), (FAMILY), &TMP.ent,	\
    219 				 TMP.buf, sizeof (TMP.buf), &my_hp,	\
    220 				 &my_h_err);				\
    221 	(HP) = (((my_ret != 0) || (my_hp != &TMP.ent))			\
    222 		? 0							\
    223 		: &TMP.ent);						\
    224 	(ERR) = my_h_err;						\
    225     }
    226 #else
    227 typedef struct {
    228     struct hostent ent;
    229     char buf[8192];
    230 } GET_HOST_TMP;
    231 #define GET_HOST_BY_NAME(NAME, HP, ERR, TMP) \
    232     {									\
    233 	int my_h_err;							\
    234 	(HP) = gethostbyname_r((NAME), &TMP.ent,			\
    235 			       TMP.buf, sizeof (TMP.buf), &my_h_err);	\
    236 	(ERR) = my_h_err;						\
    237     }
    238 #define GET_HOST_BY_ADDR(ADDR, ADDRLEN, FAMILY, HP, ERR, TMP) \
    239     {									\
    240 	int my_h_err;							\
    241 	(HP) = gethostbyaddr_r((ADDR), (ADDRLEN), (FAMILY), &TMP.ent,	\
    242 			       TMP.buf, sizeof (TMP.buf), &my_h_err);	\
    243 	(ERR) = my_h_err;						\
    244     }
    245 #endif /* returns int? */
    246 #endif /* _AIX */
    247 #endif
    248 
    249 /* Now do the same for getservby* functions.  */
    250 #ifndef HAVE_GETSERVBYNAME_R
    251 typedef struct servent *GET_SERV_TMP;
    252 #define GET_SERV_BY_NAME(NAME, PROTO, SP, ERR, TMP) \
    253     (TMP = getservbyname (NAME, PROTO), (SP) = TMP, (ERR) = (SP) ? 0 : -1)
    254 #define GET_SERV_BY_PORT(PORT, PROTO, SP, ERR, TMP) \
    255     (TMP = getservbyport (PORT, PROTO), (SP) = TMP, (ERR) = (SP) ? 0 : -1)
    256 #else
    257 #ifdef GETSERVBYNAME_R_RETURNS_INT
    258 typedef struct {
    259     struct servent ent;
    260     char buf[8192];
    261 } GET_SERV_TMP;
    262 #define GET_SERV_BY_NAME(NAME, PROTO, SP, ERR, TMP) \
    263     {									\
    264 	struct servent *my_sp;						\
    265 	int my_s_err;							\
    266 	(SP) = (getservbyname_r((NAME), (PROTO), &TMP.ent,		\
    267 				TMP.buf, sizeof (TMP.buf), &my_sp,	\
    268 				&my_s_err)				\
    269 		? 0							\
    270 		: &TMP.ent);						\
    271 	(ERR) = my_s_err;						\
    272     }
    273 #define GET_SERV_BY_PORT(PORT, PROTO, SP, ERR, TMP) \
    274     {									\
    275 	struct servent *my_sp;						\
    276 	int my_s_err;							\
    277 	(SP) = (getservbyport_r((PORT), (PROTO), &TMP.ent,		\
    278 				TMP.buf, sizeof (TMP.buf), &my_sp,	\
    279 				&my_s_err)				\
    280 		? 0							\
    281 		: &TMP.ent);						\
    282 	(ERR) = my_s_err;						\
    283     }
    284 #else
    285 /* returns ptr -- IRIX? */
    286 typedef struct {
    287     struct servent ent;
    288     char buf[8192];
    289 } GET_SERV_TMP;
    290 #define GET_SERV_BY_NAME(NAME, PROTO, SP, ERR, TMP) \
    291     {									\
    292 	(SP) = getservbyname_r((NAME), (PROTO), &TMP.ent,		\
    293 			       TMP.buf, sizeof (TMP.buf));		\
    294 	(ERR) = (SP) == NULL;						\
    295     }
    296 
    297 #define GET_SERV_BY_PORT(PORT, PROTO, SP, ERR, TMP) \
    298     {									\
    299 	struct servent *my_sp;						\
    300 	my_sp = getservbyport_r((PORT), (PROTO), &TMP.ent,		\
    301 				TMP.buf, sizeof (TMP.buf));		\
    302 	(SP) = my_sp;							\
    303 	(ERR) = my_sp == 0;						\
    304 	(ERR) = (ERR);	/* avoid "unused" warning */			\
    305     }
    306 #endif
    307 #endif
    308 
    309 #if defined(WRAP_GETADDRINFO) || defined(FAI_CACHE)
    310 static inline int
    311 system_getaddrinfo (const char *name, const char *serv,
    312 		    const struct addrinfo *hint,
    313 		    struct addrinfo **res)
    314 {
    315     return getaddrinfo(name, serv, hint, res);
    316 }
    317 
    318 static inline void
    319 system_freeaddrinfo (struct addrinfo *ai)
    320 {
    321     freeaddrinfo(ai);
    322 }
    323 
    324 /* Note: Implementations written to RFC 2133 use size_t, while RFC
    325    2553 implementations use socklen_t, for the second parameter.
    326 
    327    Mac OS X (10.2) and AIX 4.3.3 appear to be in the RFC 2133 camp,
    328    but we don't have an autoconf test for that right now.  */
    329 static inline int
    330 system_getnameinfo (const struct sockaddr *sa, socklen_t salen,
    331 		    char *host, size_t hostlen, char *serv, size_t servlen,
    332 		    int flags)
    333 {
    334     return getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
    335 }
    336 #endif
    337 
    338 #if !defined (HAVE_GETADDRINFO) || defined(WRAP_GETADDRINFO) || defined(FAI_CACHE)
    339 
    340 #undef  getaddrinfo
    341 #define getaddrinfo	my_fake_getaddrinfo
    342 #undef  freeaddrinfo
    343 #define freeaddrinfo	my_fake_freeaddrinfo
    344 
    345 #endif
    346 
    347 #if !defined (HAVE_GETADDRINFO)
    348 
    349 #undef  gai_strerror
    350 #define gai_strerror	my_fake_gai_strerror
    351 
    352 #endif /* ! HAVE_GETADDRINFO */
    353 
    354 #if (!defined (HAVE_GETADDRINFO) || defined (WRAP_GETADDRINFO)) && defined(DEBUG_ADDRINFO)
    355 /* Some debug routines.  */
    356 
    357 static const char *protoname (int p, char *buf) {
    358 #define X(N) if (p == IPPROTO_ ## N) return #N
    359 
    360     X(TCP);
    361     X(UDP);
    362     X(ICMP);
    363     X(IPV6);
    364 #ifdef IPPROTO_GRE
    365     X(GRE);
    366 #endif
    367     X(NONE);
    368     X(RAW);
    369 #ifdef IPPROTO_COMP
    370     X(COMP);
    371 #endif
    372 #ifdef IPPROTO_IGMP
    373     X(IGMP);
    374 #endif
    375 
    376     sprintf(buf, " %-2d", p);
    377     return buf;
    378 }
    379 
    380 static const char *socktypename (int t, char *buf) {
    381     switch (t) {
    382     case SOCK_DGRAM: return "DGRAM";
    383     case SOCK_STREAM: return "STREAM";
    384     case SOCK_RAW: return "RAW";
    385     case SOCK_RDM: return "RDM";
    386     case SOCK_SEQPACKET: return "SEQPACKET";
    387     }
    388     sprintf(buf, " %-2d", t);
    389     return buf;
    390 }
    391 
    392 static const char *familyname (int f, char *buf) {
    393     switch (f) {
    394     default:
    395 	sprintf(buf, "AF %d", f);
    396 	return buf;
    397     case AF_INET: return "AF_INET";
    398     case AF_INET6: return "AF_INET6";
    399 #ifdef AF_UNIX
    400     case AF_UNIX: return "AF_UNIX";
    401 #endif
    402     }
    403 }
    404 
    405 static void debug_dump_getaddrinfo_args (const char *name, const char *serv,
    406 					 const struct addrinfo *hint)
    407 {
    408     const char *sep;
    409     fprintf(stderr,
    410 	    "getaddrinfo(hostname %s, service %s,\n"
    411 	    "            hints { ",
    412 	    name ? name : "(null)", serv ? serv : "(null)");
    413     if (hint) {
    414 	char buf[30];
    415 	sep = "";
    416 #define Z(FLAG) if (hint->ai_flags & AI_##FLAG) fprintf(stderr, "%s%s", sep, #FLAG), sep = "|"
    417 	Z(CANONNAME);
    418 	Z(PASSIVE);
    419 #ifdef AI_NUMERICHOST
    420 	Z(NUMERICHOST);
    421 #endif
    422 	if (sep[0] == 0)
    423 	    fprintf(stderr, "no-flags");
    424 	if (hint->ai_family)
    425 	    fprintf(stderr, " %s", familyname(hint->ai_family, buf));
    426 	if (hint->ai_socktype)
    427 	    fprintf(stderr, " SOCK_%s", socktypename(hint->ai_socktype, buf));
    428 	if (hint->ai_protocol)
    429 	    fprintf(stderr, " IPPROTO_%s", protoname(hint->ai_protocol, buf));
    430     } else
    431 	fprintf(stderr, "(null)");
    432     fprintf(stderr, " }):\n");
    433 }
    434 
    435 static void debug_dump_error (int err)
    436 {
    437     fprintf(stderr, "error %d: %s\n", err, gai_strerror(err));
    438 }
    439 
    440 static void debug_dump_addrinfos (const struct addrinfo *ai)
    441 {
    442     int count = 0;
    443     char buf[10];
    444     fprintf(stderr, "addrinfos returned:\n");
    445     while (ai) {
    446 	fprintf(stderr, "%p...", ai);
    447 	fprintf(stderr, " socktype=%s", socktypename(ai->ai_socktype, buf));
    448 	fprintf(stderr, " ai_family=%s", familyname(ai->ai_family, buf));
    449 	if (ai->ai_family != ai->ai_addr->sa_family)
    450 	    fprintf(stderr, " sa_family=%s",
    451 		    familyname(ai->ai_addr->sa_family, buf));
    452 	fprintf(stderr, "\n");
    453 	ai = ai->ai_next;
    454 	count++;
    455     }
    456     fprintf(stderr, "end addrinfos returned (%d)\n");
    457 }
    458 
    459 #endif
    460 
    461 #if !defined (HAVE_GETADDRINFO) || defined (WRAP_GETADDRINFO)
    462 
    463 static
    464 int getaddrinfo (const char *name, const char *serv,
    465 		 const struct addrinfo *hint, struct addrinfo **result);
    466 
    467 static
    468 void freeaddrinfo (struct addrinfo *ai);
    469 
    470 #endif
    471 
    472 #if !defined (HAVE_GETADDRINFO)
    473 
    474 #define HAVE_FAKE_GETADDRINFO /* was not originally HAVE_GETADDRINFO */
    475 #define HAVE_GETADDRINFO
    476 #define NEED_FAKE_GETNAMEINFO
    477 #undef  HAVE_GETNAMEINFO
    478 #define HAVE_GETNAMEINFO 1
    479 
    480 #undef  getnameinfo
    481 #define getnameinfo	my_fake_getnameinfo
    482 
    483 static
    484 char *gai_strerror (int code);
    485 
    486 #endif
    487 
    488 #if !defined (HAVE_GETADDRINFO)
    489 static
    490 int getnameinfo (const struct sockaddr *addr, socklen_t len,
    491 		 char *host, socklen_t hostlen,
    492 		 char *service, socklen_t servicelen,
    493 		 int flags);
    494 #endif
    495 
    496 /* Fudge things on older gai implementations.  */
    497 /* AIX 4.3.3 is based on RFC 2133; no AI_NUMERICHOST.  */
    498 #ifndef AI_NUMERICHOST
    499 # define AI_NUMERICHOST 0
    500 #endif
    501 /* Partial RFC 2553 implementations may not have AI_ADDRCONFIG and
    502    friends, which RFC 3493 says are now part of the getaddrinfo
    503    interface, and we'll want to use.  */
    504 #ifndef AI_ADDRCONFIG
    505 # define AI_ADDRCONFIG 0
    506 #endif
    507 #ifndef AI_V4MAPPED
    508 # define AI_V4MAPPED 0
    509 #endif
    510 #ifndef AI_ALL
    511 # define AI_ALL 0
    512 #endif
    513 #ifndef AI_DEFAULT
    514 # define AI_DEFAULT (AI_ADDRCONFIG|AI_V4MAPPED)
    515 #endif
    516 
    517 #if defined(HAVE_FAKE_GETADDRINFO) || defined(FAI_CACHE)
    518 #define NEED_FAKE_GETADDRINFO
    519 #endif
    520 
    521 #if defined(NEED_FAKE_GETADDRINFO) || defined(WRAP_GETADDRINFO)
    522 #include <stdlib.h>
    523 #endif
    524 
    525 #ifdef NEED_FAKE_GETADDRINFO
    526 #include <string.h> /* for strspn */
    527 
    528 static inline int translate_h_errno (int h);
    529 
    530 static inline int fai_add_entry (struct addrinfo **result, void *addr,
    531 				 int port, const struct addrinfo *template)
    532 {
    533     struct addrinfo *n = malloc (sizeof (struct addrinfo));
    534     if (n == 0)
    535 	return EAI_MEMORY;
    536     if (template->ai_family != AF_INET
    537 #ifdef KRB5_USE_INET6
    538 	&& template->ai_family != AF_INET6
    539 #endif
    540 	)
    541 	return EAI_FAMILY;
    542     *n = *template;
    543     if (template->ai_family == AF_INET) {
    544 	struct sockaddr_in *sin4;
    545 	sin4 = malloc (sizeof (struct sockaddr_in));
    546 	if (sin4 == 0)
    547 	    return EAI_MEMORY;
    548         memset (sin4, 0, sizeof (struct sockaddr_in)); /* for sin_zero */
    549 	n->ai_addr = (struct sockaddr *) sin4;
    550 	sin4->sin_family = AF_INET;
    551 	sin4->sin_addr = *(struct in_addr *)addr;
    552 	sin4->sin_port = port;
    553 #ifdef HAVE_SA_LEN
    554 	sin4->sin_len = sizeof (struct sockaddr_in);
    555 #endif
    556     }
    557 #ifdef KRB5_USE_INET6
    558     if (template->ai_family == AF_INET6) {
    559 	struct sockaddr_in6 *sin6;
    560 	sin6 = malloc (sizeof (struct sockaddr_in6));
    561 	if (sin6 == 0)
    562 	    return EAI_MEMORY;
    563         memset (sin6, 0, sizeof (struct sockaddr_in6)); /* for sin_zero */
    564 	n->ai_addr = (struct sockaddr *) sin6;
    565 	sin6->sin6_family = AF_INET6;
    566 	sin6->sin6_addr = *(struct in6_addr *)addr;
    567 	sin6->sin6_port = port;
    568 #ifdef HAVE_SA_LEN
    569 	sin6->sin6_len = sizeof (struct sockaddr_in6);
    570 #endif
    571     }
    572 #endif
    573     n->ai_next = *result;
    574     *result = n;
    575     return 0;
    576 }
    577 
    578 #ifdef FAI_CACHE
    579 /* fake addrinfo cache entries */
    580 #define CACHE_ENTRY_LIFETIME	15 /* seconds */
    581 
    582 static void plant_face (const char *name, struct face *entry)
    583 {
    584     entry->name = strdup(name);
    585     if (entry->name == NULL)
    586 	/* @@ Wastes memory.  */
    587 	return;
    588     k5_mutex_assert_locked(&krb5int_fac.lock);
    589     entry->next = krb5int_fac.data;
    590     entry->expiration = time(0) + CACHE_ENTRY_LIFETIME;
    591     krb5int_fac.data = entry;
    592 #ifdef DEBUG_ADDRINFO
    593     printf("added cache entry '%s' at %p: %d ipv4, %d ipv6; expire %d\n",
    594 	   name, entry, entry->naddrs4, entry->naddrs6, entry->expiration);
    595 #endif
    596 }
    597 
    598 static int find_face (const char *name, struct face **entry)
    599 {
    600     struct face *fp, **fpp;
    601     time_t now = time(0);
    602 
    603     /* First, scan for expired entries and free them.
    604        (Future improvement: Integrate these two loops.)  */
    605 #ifdef DEBUG_ADDRINFO
    606     printf("scanning cache at %d for '%s'...\n", now, name);
    607 #endif
    608     k5_mutex_assert_locked(&krb5int_fac.lock);
    609     for (fpp = &krb5int_fac.data; *fpp; ) {
    610 	fp = *fpp;
    611 #ifdef DEBUG_ADDRINFO
    612 	printf("  checking expiration time of @%p: %d\n",
    613 	       fp, fp->expiration);
    614 #endif
    615 	if (fp->expiration < now) {
    616 #ifdef DEBUG_ADDRINFO
    617 	    printf("\texpiring cache entry\n");
    618 #endif
    619 	    free(fp->name);
    620 	    free(fp->canonname);
    621 	    free(fp->addrs4);
    622 	    free(fp->addrs6);
    623 	    *fpp = fp->next;
    624 	    free(fp);
    625 	    /* Stay at this point in the list, and check again.  */
    626 	} else
    627 	    /* Move forward.  */
    628 	    fpp = &(*fpp)->next;
    629     }
    630 
    631     for (fp = krb5int_fac.data; fp; fp = fp->next) {
    632 #ifdef DEBUG_ADDRINFO
    633 	printf("  comparing entry @%p\n", fp);
    634 #endif
    635 	if (!strcasecmp(fp->name, name)) {
    636 #ifdef DEBUG_ADDRINFO
    637 	    printf("\tMATCH!\n");
    638 #endif
    639 	    *entry = fp;
    640 	    return 1;
    641 	}
    642     }
    643     return 0;
    644 }
    645 
    646 #endif
    647 
    648 static int krb5int_lock_fac(void), krb5int_unlock_fac(void);
    649 
    650 static inline int fai_add_hosts_by_name (const char *name,
    651 					 struct addrinfo *template,
    652 					 int portnum, int flags,
    653 					 struct addrinfo **result)
    654 {
    655 #ifdef FAI_CACHE
    656 
    657     struct face *ce;
    658     int i, r, err;
    659 
    660     err = krb5int_lock_fac();
    661     if (err) {
    662 	errno = err;
    663 	return EAI_SYSTEM;
    664     }
    665     if (!find_face(name, &ce)) {
    666 	struct addrinfo myhints = { 0 }, *ai, *ai2;
    667 	int i4, i6, aierr;
    668 
    669 #ifdef DEBUG_ADDRINFO
    670 	printf("looking up new data for '%s'...\n", name);
    671 #endif
    672 	myhints.ai_socktype = SOCK_STREAM;
    673 	myhints.ai_flags = AI_CANONNAME;
    674 	/* Don't set ai_family -- we want to cache all address types,
    675 	   because the next lookup may not use the same constraints as
    676 	   the current one.  We *could* cache them separately, so that
    677 	   we never have to look up an IPv6 address if we are always
    678 	   asked for IPv4 only, but let's deal with that later, if we
    679 	   have to.  */
    680 	/* Try NULL for the service for now.
    681 
    682 	   It would be nice to use the requested service name, and not
    683 	   have to patch things up, but then we'd be doing multiple
    684 	   queries for the same host when we get different services.
    685 	   We were using "telnet" for a little more confidence that
    686 	   getaddrinfo would heed the hints to only give us stream
    687 	   socket types (with no socket type and null service name, we
    688 	   might get stream *and* dgram *and* raw, for each address,
    689 	   or only raw).  The RFC 3493 description of ai_socktype
    690 	   sometimes associates it with the specified service,
    691 	   sometimes not.
    692 
    693 	   But on Mac OS X (10.3, 10.4) they've "extended" getaddrinfo
    694 	   to make SRV RR queries.  (Please, somebody, show me
    695 	   something in the specs that actually supports this?  RFC
    696 	   3493 says nothing about it, but it does say getaddrinfo is
    697 	   the new way to look up hostnames.  RFC 2782 says SRV
    698 	   records should *not* be used unless the application
    699 	   protocol spec says to do so.  The Telnet spec does not say
    700 	   to do it.)  And then they complain when our code
    701 	   "unexpectedly" seems to use this "extension" in cases where
    702 	   they don't want it to be used.
    703 
    704 	   Fortunately, it appears that if we specify ai_socktype as
    705 	   SOCK_STREAM and use a null service name, we only get one
    706 	   copy of each address on all the platforms I've tried,
    707 	   although it may not have ai_socktype filled in properly.
    708 	   So, we'll fudge it with that for now.  */
    709 	aierr = system_getaddrinfo(name, NULL, &myhints, &ai);
    710 	if (aierr) {
    711 	    krb5int_unlock_fac();
    712 	    return aierr;
    713 	}
    714 	ce = malloc(sizeof(struct face));
    715 	memset(ce, 0, sizeof(*ce));
    716 	ce->expiration = time(0) + 30;
    717 	for (ai2 = ai; ai2; ai2 = ai2->ai_next) {
    718 #ifdef DEBUG_ADDRINFO
    719 	    printf("  found an address in family %d...\n", ai2->ai_family);
    720 #endif
    721 	    switch (ai2->ai_family) {
    722 	    case AF_INET:
    723 		ce->naddrs4++;
    724 		break;
    725 	    case AF_INET6:
    726 		ce->naddrs6++;
    727 		break;
    728 	    default:
    729 		break;
    730 	    }
    731 	}
    732 	ce->addrs4 = calloc(ce->naddrs4, sizeof(*ce->addrs4));
    733 	if (ce->addrs4 == NULL && ce->naddrs4 != 0) {
    734 	    krb5int_unlock_fac();
    735 	    system_freeaddrinfo(ai);
    736 	    return EAI_MEMORY;
    737 	}
    738 	ce->addrs6 = calloc(ce->naddrs6, sizeof(*ce->addrs6));
    739 	if (ce->addrs6 == NULL && ce->naddrs6 != 0) {
    740 	    krb5int_unlock_fac();
    741 	    free(ce->addrs4);
    742 	    system_freeaddrinfo(ai);
    743 	    return EAI_MEMORY;
    744 	}
    745 	for (ai2 = ai, i4 = i6 = 0; ai2; ai2 = ai2->ai_next) {
    746 	    switch (ai2->ai_family) {
    747 	    case AF_INET:
    748 		ce->addrs4[i4++] = ((struct sockaddr_in *)ai2->ai_addr)->sin_addr;
    749 		break;
    750 	    case AF_INET6:
    751 		ce->addrs6[i6++] = ((struct sockaddr_in6 *)ai2->ai_addr)->sin6_addr;
    752 		break;
    753 	    default:
    754 		break;
    755 	    }
    756 	}
    757 	ce->canonname = ai->ai_canonname ? strdup(ai->ai_canonname) : 0;
    758 	system_freeaddrinfo(ai);
    759 	plant_face(name, ce);
    760     }
    761     template->ai_family = AF_INET6;
    762     template->ai_addrlen = sizeof(struct sockaddr_in6);
    763     for (i = 0; i < ce->naddrs6; i++) {
    764 	r = fai_add_entry (result, &ce->addrs6[i], portnum, template);
    765 	if (r) {
    766 	    krb5int_unlock_fac();
    767 	    return r;
    768 	}
    769     }
    770     template->ai_family = AF_INET;
    771     template->ai_addrlen = sizeof(struct sockaddr_in);
    772     for (i = 0; i < ce->naddrs4; i++) {
    773 	r = fai_add_entry (result, &ce->addrs4[i], portnum, template);
    774 	if (r) {
    775 	    krb5int_unlock_fac();
    776 	    return r;
    777 	}
    778     }
    779     if (*result && (flags & AI_CANONNAME))
    780 	(*result)->ai_canonname = (ce->canonname
    781 				   ? strdup(ce->canonname)
    782 				   : NULL);
    783     krb5int_unlock_fac();
    784     return 0;
    785 
    786 #else
    787 
    788     struct hostent *hp;
    789     int i, r;
    790     int herr;
    791     GET_HOST_TMP htmp;
    792 
    793     GET_HOST_BY_NAME (name, hp, herr, htmp);
    794     if (hp == 0)
    795 	return translate_h_errno (herr);
    796     for (i = 0; hp->h_addr_list[i]; i++) {
    797 	r = fai_add_entry (result, hp->h_addr_list[i], portnum, template);
    798 	if (r)
    799 	    return r;
    800     }
    801     if (*result && (flags & AI_CANONNAME))
    802 	(*result)->ai_canonname = strdup (hp->h_name);
    803     return 0;
    804 
    805 #endif
    806 }
    807 
    808 static inline void
    809 fake_freeaddrinfo (struct addrinfo *ai)
    810 {
    811     struct addrinfo *next;
    812     while (ai) {
    813 	next = ai->ai_next;
    814 	if (ai->ai_canonname)
    815 	  free (ai->ai_canonname);
    816 	if (ai->ai_addr)
    817 	  free (ai->ai_addr);
    818 	free (ai);
    819 	ai = next;
    820     }
    821 }
    822 
    823 static inline int
    824 fake_getaddrinfo (const char *name, const char *serv,
    825 		  const struct addrinfo *hint, struct addrinfo **result)
    826 {
    827     struct addrinfo *res = 0;
    828     int ret;
    829     int port = 0, socktype;
    830     int flags;
    831     struct addrinfo template;
    832 
    833 #ifdef DEBUG_ADDRINFO
    834     debug_dump_getaddrinfo_args(name, serv, hint);
    835 #endif
    836 
    837     if (hint != 0) {
    838 	if (hint->ai_family != 0 && hint->ai_family != AF_INET)
    839 	    return EAI_NODATA;
    840 	socktype = hint->ai_socktype;
    841 	flags = hint->ai_flags;
    842     } else {
    843 	socktype = 0;
    844 	flags = 0;
    845     }
    846 
    847     if (serv) {
    848 	size_t numlen = strspn (serv, "0123456789");
    849 	if (serv[numlen] == '\0') {
    850 	    /* pure numeric */
    851 	    unsigned long p = strtoul (serv, 0, 10);
    852 	    if (p == 0 || p > 65535)
    853 		return EAI_NONAME;
    854 	    port = htons (p);
    855 	} else {
    856 	    struct servent *sp;
    857 	    int try_dgram_too = 0, s_err;
    858 	    GET_SERV_TMP stmp;
    859 
    860 	    if (socktype == 0) {
    861 		try_dgram_too = 1;
    862 		socktype = SOCK_STREAM;
    863 	    }
    864 	try_service_lookup:
    865 	    GET_SERV_BY_NAME(serv, socktype == SOCK_STREAM ? "tcp" : "udp",
    866 			     sp, s_err, stmp);
    867 	    if (sp == 0) {
    868 		if (try_dgram_too) {
    869 		    socktype = SOCK_DGRAM;
    870 		    goto try_service_lookup;
    871 		}
    872 		return EAI_SERVICE;
    873 	    }
    874 	    port = sp->s_port;
    875 	}
    876     }
    877 
    878     if (name == 0) {
    879 	name = (flags & AI_PASSIVE) ? "0.0.0.0" : "127.0.0.1";
    880 	flags |= AI_NUMERICHOST;
    881     }
    882 
    883     template.ai_family = AF_INET;
    884     template.ai_addrlen = sizeof (struct sockaddr_in);
    885     template.ai_socktype = socktype;
    886     template.ai_protocol = 0;
    887     template.ai_flags = 0;
    888     template.ai_canonname = 0;
    889     template.ai_next = 0;
    890     template.ai_addr = 0;
    891 
    892     /* If NUMERICHOST is set, parse a numeric address.
    893        If it's not set, don't accept such names.  */
    894     if (flags & AI_NUMERICHOST) {
    895 	struct in_addr addr4;
    896 #if 0
    897 	ret = inet_aton (name, &addr4);
    898 	if (ret)
    899 	    return EAI_NONAME;
    900 #else
    901 	addr4.s_addr = inet_addr (name);
    902 	if (addr4.s_addr == 0xffffffff || addr4.s_addr == -1)
    903 	    /* 255.255.255.255 or parse error, both bad */
    904 	    return EAI_NONAME;
    905 #endif
    906 	ret = fai_add_entry (&res, &addr4, port, &template);
    907     } else {
    908 	ret = fai_add_hosts_by_name (name, &template, port, flags,
    909 				     &res);
    910     }
    911 
    912     if (ret && ret != NO_ADDRESS) {
    913 	fake_freeaddrinfo (res);
    914 	return ret;
    915     }
    916     if (res == 0)
    917 	return NO_ADDRESS;
    918     *result = res;
    919     return 0;
    920 }
    921 
    922 #ifdef NEED_FAKE_GETNAMEINFO
    923 static inline int
    924 fake_getnameinfo (const struct sockaddr *sa, socklen_t len,
    925 		  char *host, socklen_t hostlen,
    926 		  char *service, socklen_t servicelen,
    927 		  int flags)
    928 {
    929     struct hostent *hp;
    930     const struct sockaddr_in *sinp;
    931     struct servent *sp;
    932     size_t hlen, slen;
    933 
    934     if (sa->sa_family != AF_INET) {
    935 	return EAI_FAMILY;
    936     }
    937     sinp = (const struct sockaddr_in *) sa;
    938 
    939     hlen = hostlen;
    940     if (hostlen < 0 || hlen != hostlen) {
    941 	errno = EINVAL;
    942 	return EAI_SYSTEM;
    943     }
    944     slen = servicelen;
    945     if (servicelen < 0 || slen != servicelen) {
    946 	errno = EINVAL;
    947 	return EAI_SYSTEM;
    948     }
    949 
    950     if (host) {
    951 	if (flags & NI_NUMERICHOST) {
    952 #if (defined(__GNUC__) && defined(__mips__)) || 1 /* thread safety always */
    953 	    /* The inet_ntoa call, passing a struct, fails on IRIX 6.5
    954 	       using gcc 2.95; we get back "0.0.0.0".  Since this in a
    955 	       configuration still important at Athena, here's the
    956 	       workaround, which also happens to be thread-safe....  */
    957 	    const unsigned char *uc;
    958 	    char tmpbuf[20];
    959 	numeric_host:
    960 	    uc = (const unsigned char *) &sinp->sin_addr;
    961 	    sprintf(tmpbuf, "%d.%d.%d.%d", uc[0], uc[1], uc[2], uc[3]);
    962 	    strncpy(host, tmpbuf, hlen);
    963 #else
    964 	    char *p;
    965 	numeric_host:
    966 	    p = inet_ntoa (sinp->sin_addr);
    967 	    strncpy (host, p, hlen);
    968 #endif
    969 	} else {
    970 	    int herr;
    971 	    GET_HOST_TMP htmp;
    972 
    973 	    GET_HOST_BY_ADDR((const char *) &sinp->sin_addr,
    974 			     sizeof (struct in_addr),
    975 			     sa->sa_family, hp, herr, htmp);
    976 	    if (hp == 0) {
    977 		if (herr == NO_ADDRESS && !(flags & NI_NAMEREQD)) /* ??? */
    978 		    goto numeric_host;
    979 		return translate_h_errno (herr);
    980 	    }
    981 	    /* According to the Open Group spec, getnameinfo can
    982 	       silently truncate, but must still return a
    983 	       null-terminated string.  */
    984 	    strncpy (host, hp->h_name, hlen);
    985 	}
    986 	host[hostlen-1] = 0;
    987     }
    988 
    989     if (service) {
    990 	if (flags & NI_NUMERICSERV) {
    991 	    char numbuf[10];
    992 	    int port;
    993 	numeric_service:
    994 	    port = ntohs (sinp->sin_port);
    995 	    if (port < 0 || port > 65535)
    996 		return EAI_FAIL;
    997 	    sprintf (numbuf, "%d", port);
    998 	    strncpy (service, numbuf, slen);
    999 	} else {
   1000 	    int serr;
   1001 	    GET_SERV_TMP stmp;
   1002 
   1003 	    GET_SERV_BY_PORT(sinp->sin_port,
   1004 			     (flags & NI_DGRAM) ? "udp" : "tcp",
   1005 			     sp, serr, stmp);
   1006 	    if (sp == 0)
   1007 		goto numeric_service;
   1008 	    strncpy (service, sp->s_name, slen);
   1009 	}
   1010 	service[servicelen-1] = 0;
   1011     }
   1012 
   1013     return 0;
   1014 }
   1015 #endif
   1016 
   1017 #if defined(HAVE_FAKE_GETADDRINFO) || defined(NEED_FAKE_GETNAMEINFO)
   1018 
   1019 static inline
   1020 char *gai_strerror (int code)
   1021 {
   1022     switch (code) {
   1023     case EAI_ADDRFAMILY: return "address family for nodename not supported";
   1024     case EAI_AGAIN:	return "temporary failure in name resolution";
   1025     case EAI_BADFLAGS:	return "bad flags to getaddrinfo/getnameinfo";
   1026     case EAI_FAIL:	return "non-recoverable failure in name resolution";
   1027     case EAI_FAMILY:	return "ai_family not supported";
   1028     case EAI_MEMORY:	return "out of memory";
   1029     case EAI_NODATA:	return "no address associated with hostname";
   1030     case EAI_NONAME:	return "name does not exist";
   1031     case EAI_SERVICE:	return "service name not supported for specified socket type";
   1032     case EAI_SOCKTYPE:	return "ai_socktype not supported";
   1033     case EAI_SYSTEM:	return strerror (errno);
   1034     default:		return "bogus getaddrinfo error?";
   1035     }
   1036 }
   1037 #endif
   1038 
   1039 static inline int translate_h_errno (int h)
   1040 {
   1041     switch (h) {
   1042     case 0:
   1043 	return 0;
   1044 #ifdef NETDB_INTERNAL
   1045     case NETDB_INTERNAL:
   1046 	if (errno == ENOMEM)
   1047 	    return EAI_MEMORY;
   1048 	return EAI_SYSTEM;
   1049 #endif
   1050     case HOST_NOT_FOUND:
   1051 	return EAI_NONAME;
   1052     case TRY_AGAIN:
   1053 	return EAI_AGAIN;
   1054     case NO_RECOVERY:
   1055 	return EAI_FAIL;
   1056     case NO_DATA:
   1057 #if NO_DATA != NO_ADDRESS
   1058     case NO_ADDRESS:
   1059 #endif
   1060 	return EAI_NODATA;
   1061     default:
   1062 	return EAI_SYSTEM;
   1063     }
   1064 }
   1065 
   1066 #if defined(HAVE_FAKE_GETADDRINFO) || defined(FAI_CACHE)
   1067 static inline
   1068 int getaddrinfo (const char *name, const char *serv,
   1069 		 const struct addrinfo *hint, struct addrinfo **result)
   1070 {
   1071     return fake_getaddrinfo(name, serv, hint, result);
   1072 }
   1073 
   1074 static inline
   1075 void freeaddrinfo (struct addrinfo *ai)
   1076 {
   1077     fake_freeaddrinfo(ai);
   1078 }
   1079 
   1080 #ifdef NEED_FAKE_GETNAMEINFO
   1081 static inline
   1082 int getnameinfo (const struct sockaddr *sa, socklen_t len,
   1083 		 char *host, socklen_t hostlen,
   1084 		 char *service, socklen_t servicelen,
   1085 		 int flags)
   1086 {
   1087     return fake_getnameinfo(sa, len, host, hostlen, service, servicelen,
   1088 			    flags);
   1089 }
   1090 #endif /* NEED_FAKE_GETNAMEINFO */
   1091 #endif /* HAVE_FAKE_GETADDRINFO */
   1092 #endif /* NEED_FAKE_GETADDRINFO */
   1093 
   1094 
   1095 #ifdef WRAP_GETADDRINFO
   1096 
   1097 static inline
   1098 int
   1099 getaddrinfo (const char *name, const char *serv, const struct addrinfo *hint,
   1100 	     struct addrinfo **result)
   1101 {
   1102     int aierr;
   1103 #if defined(_AIX) || defined(COPY_FIRST_CANONNAME)
   1104     struct addrinfo *ai;
   1105 #endif
   1106 #ifdef NUMERIC_SERVICE_BROKEN
   1107     int service_is_numeric = 0;
   1108     int service_port = 0;
   1109     int socket_type = 0;
   1110 #endif
   1111 
   1112 #ifdef DEBUG_ADDRINFO
   1113     debug_dump_getaddrinfo_args(name, serv, hint);
   1114 #endif
   1115 
   1116 #ifdef NUMERIC_SERVICE_BROKEN
   1117     /* AIX 4.3.3 is broken.  (Or perhaps out of date?)
   1118 
   1119        If a numeric service is provided, and it doesn't correspond to
   1120        a known service name for tcp or udp (as appropriate), an error
   1121        code (for "host not found") is returned.  If the port maps to a
   1122        known service for both udp and tcp, all is well.  */
   1123     if (serv && serv[0] && isdigit(serv[0])) {
   1124 	unsigned long lport;
   1125 	char *end;
   1126 	lport = strtoul(serv, &end, 10);
   1127 	if (!*end) {
   1128 	    if (lport > 65535)
   1129 		return EAI_SOCKTYPE;
   1130 	    service_is_numeric = 1;
   1131 	    service_port = htons(lport);
   1132 #ifdef AI_NUMERICSERV
   1133 	    if (hint && hint->ai_flags & AI_NUMERICSERV)
   1134 		serv = "9";
   1135 	    else
   1136 #endif
   1137 		serv = "discard";	/* defined for both udp and tcp */
   1138 	    if (hint)
   1139 		socket_type = hint->ai_socktype;
   1140 	}
   1141     }
   1142 #endif
   1143 
   1144     aierr = system_getaddrinfo (name, serv, hint, result);
   1145     if (aierr || *result == 0) {
   1146 #ifdef DEBUG_ADDRINFO
   1147 	debug_dump_error(aierr);
   1148 #endif
   1149 	return aierr;
   1150     }
   1151 
   1152     /* Linux libc version 6 (libc-2.2.4.so on Debian) is broken.
   1153 
   1154        RFC 2553 says that when AI_CANONNAME is set, the ai_canonname
   1155        flag of the first returned structure has the canonical name of
   1156        the host.  Instead, GNU libc sets ai_canonname in each returned
   1157        structure to the name that the corresponding address maps to,
   1158        if any, or a printable numeric form.
   1159 
   1160        RFC 2553 bis and the new Open Group spec say that field will be
   1161        the canonical name if it can be determined, otherwise, the
   1162        provided hostname or a copy of it.
   1163 
   1164        IMNSHO, "canonical name" means CNAME processing and not PTR
   1165        processing, but I can see arguing it.  Using the numeric form
   1166        when that's not the form provided is just wrong.  So, let's fix
   1167        it.
   1168 
   1169        The glibc 2.2.5 sources indicate that the canonical name is
   1170        *not* allocated separately, it's just some extra storage tacked
   1171        on the end of the addrinfo structure.  So, let's try this
   1172        approach: If getaddrinfo sets ai_canonname, we'll replace the
   1173        *first* one with allocated storage, and free up that pointer in
   1174        freeaddrinfo if it's set; the other ai_canonname fields will be
   1175        left untouched.  And we'll just pray that the application code
   1176        won't mess around with the list structure; if we start doing
   1177        that, we'll have to start replacing and freeing all of the
   1178        ai_canonname fields.
   1179 
   1180        Ref: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=133668 .
   1181 
   1182        Since it's dependent on the target hostname, it's hard to check
   1183        for at configure time.  Always do it on Linux for now.  When
   1184        they get around to fixing it, add a compile-time or run-time
   1185        check for the glibc version in use.
   1186 
   1187        Some Windows documentation says that even when AI_CANONNAME is
   1188        set, the returned ai_canonname field can be null.  The NetBSD
   1189        1.5 implementation also does this, if the input hostname is a
   1190        numeric host address string.  That case isn't handled well at
   1191        the moment.
   1192 
   1193        Libc version 5 didn't have getaddrinfo at all.  */
   1194 
   1195 #ifdef COPY_FIRST_CANONNAME
   1196     /*
   1197      * This code must *always* return an error, return a null
   1198      * ai_canonname, or return an ai_canonname allocated here using
   1199      * malloc, so that freeaddrinfo can always free a non-null
   1200      * ai_canonname.  Note that it really doesn't matter if the
   1201      * AI_CANONNAME flag was set.
   1202      */
   1203     ai = *result;
   1204     if (ai->ai_canonname) {
   1205 	struct hostent *hp;
   1206 	const char *name2 = 0;
   1207 	int i, herr;
   1208 	GET_HOST_TMP htmp;
   1209 
   1210 	/*
   1211 	 * Current versions of GET_HOST_BY_NAME will fail if the
   1212 	 * target hostname has IPv6 addresses only.  Make sure it
   1213 	 * fails fairly cleanly.
   1214 	 */
   1215 	GET_HOST_BY_NAME (name, hp, herr, htmp);
   1216 	if (hp == 0) {
   1217 	    /*
   1218 	     * This case probably means it's an IPv6-only name.  If
   1219 	     * ai_canonname is a numeric address, get rid of it.
   1220 	     */
   1221 	    if (ai->ai_canonname && strchr(ai->ai_canonname, ':'))
   1222 		ai->ai_canonname = 0;
   1223 	    name2 = ai->ai_canonname ? ai->ai_canonname : name;
   1224 	} else {
   1225 	    /* Sometimes gethostbyname will be directed to /etc/hosts
   1226 	       first, and sometimes that file will have entries with
   1227 	       the unqualified name first.  So take the first entry
   1228 	       that looks like it could be a FQDN.  */
   1229 	    for (i = 0; hp->h_aliases[i]; i++) {
   1230 		if (strchr(hp->h_aliases[i], '.') != 0) {
   1231 		    name2 = hp->h_aliases[i];
   1232 		    break;
   1233 		}
   1234 	    }
   1235 	    /* Give up, just use the first name (h_name ==
   1236 	       h_aliases[0] on all systems I've seen).  */
   1237 	    if (hp->h_aliases[i] == 0)
   1238 		name2 = hp->h_name;
   1239 	}
   1240 
   1241 	ai->ai_canonname = strdup(name2);
   1242 	if (name2 != 0 && ai->ai_canonname == 0) {
   1243 	    system_freeaddrinfo(ai);
   1244 	    *result = 0;
   1245 #ifdef DEBUG_ADDRINFO
   1246 	    debug_dump_error(EAI_MEMORY);
   1247 #endif
   1248 	    return EAI_MEMORY;
   1249 	}
   1250 	/* Zap the remaining ai_canonname fields glibc fills in, in
   1251 	   case the application messes around with the list
   1252 	   structure.  */
   1253 	while ((ai = ai->ai_next) != NULL)
   1254 	    ai->ai_canonname = 0;
   1255     }
   1256 #endif
   1257 
   1258 #ifdef NUMERIC_SERVICE_BROKEN
   1259     if (service_port != 0) {
   1260 	for (ai = *result; ai; ai = ai->ai_next) {
   1261 	    if (socket_type != 0 && ai->ai_socktype == 0)
   1262 		/* Is this check actually needed?  */
   1263 		ai->ai_socktype = socket_type;
   1264 	    switch (ai->ai_family) {
   1265 	    case AF_INET:
   1266 		((struct sockaddr_in *)ai->ai_addr)->sin_port = service_port;
   1267 		break;
   1268 	    case AF_INET6:
   1269 		((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = service_port;
   1270 		break;
   1271 	    }
   1272 	}
   1273     }
   1274 #endif
   1275 
   1276 #ifdef _AIX
   1277     for (ai = *result; ai; ai = ai->ai_next) {
   1278 	/* AIX 4.3.3 libc is broken.  It doesn't set the family or len
   1279 	   fields of the sockaddr structures.  Usually, sa_family is
   1280 	   zero, but I've seen it set to 1 in some cases also (maybe
   1281 	   just leftover from previous contents of the memory
   1282 	   block?).  So, always override what libc returned.  */
   1283 	ai->ai_addr->sa_family = ai->ai_family;
   1284 #ifdef HAVE_SA_LEN /* always true on AIX, actually */
   1285 	ai->ai_addr->sa_len = ai->ai_addrlen;
   1286 #endif
   1287     }
   1288 #endif
   1289 
   1290     /* Not dealt with currently:
   1291 
   1292        - Some versions of GNU libc can lose some IPv4 addresses in
   1293 	 certain cases when multiple IPv4 and IPv6 addresses are
   1294 	 available.  */
   1295 
   1296 #ifdef DEBUG_ADDRINFO
   1297     debug_dump_addrinfos(*result);
   1298 #endif
   1299 
   1300     return 0;
   1301 }
   1302 
   1303 static inline
   1304 void freeaddrinfo (struct addrinfo *ai)
   1305 {
   1306 #ifdef COPY_FIRST_CANONNAME
   1307     if (ai) {
   1308       free(ai->ai_canonname);
   1309 	ai->ai_canonname = 0;
   1310 	system_freeaddrinfo(ai);
   1311     }
   1312 #else
   1313     system_freeaddrinfo(ai);
   1314 #endif
   1315 }
   1316 #endif /* WRAP_GETADDRINFO */
   1317 
   1318 static int krb5int_lock_fac (void)
   1319 {
   1320     int err;
   1321     err = krb5int_call_thread_support_init();
   1322     if (err)
   1323 	return err;
   1324     return k5_mutex_lock(&krb5int_fac.lock);
   1325 }
   1326 
   1327 static int krb5int_unlock_fac (void)
   1328 {
   1329     return k5_mutex_unlock(&krb5int_fac.lock);
   1330 }
   1331 
   1332 /* Some systems don't define in6addr_any.  */
   1333 const struct in6_addr krb5int_in6addr_any = IN6ADDR_ANY_INIT;
   1334 
   1335 int krb5int_getaddrinfo (const char *node, const char *service,
   1336 			 const struct addrinfo *hints,
   1337 			 struct addrinfo **aip)
   1338 {
   1339     return getaddrinfo(node, service, hints, aip);
   1340 }
   1341 
   1342 void krb5int_freeaddrinfo (struct addrinfo *ai)
   1343 {
   1344     freeaddrinfo(ai);
   1345 }
   1346 
   1347 const char *krb5int_gai_strerror(int err)
   1348 {
   1349     return gai_strerror(err);
   1350 }
   1351 
   1352 int krb5int_getnameinfo (const struct sockaddr *sa, socklen_t salen,
   1353 			 char *hbuf, size_t hbuflen,
   1354 			 char *sbuf, size_t sbuflen,
   1355 			 int flags)
   1356 {
   1357     return getnameinfo(sa, salen, hbuf, hbuflen, sbuf, sbuflen, flags);
   1358 }
   1359