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