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