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