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