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