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