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