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