~ubuntu-branches/ubuntu/maverick/krb5/maverick

« back to all changes in this revision

Viewing changes to src/util/support/fake-addrinfo.c

  • Committer: Bazaar Package Importer
  • Author(s): Sam Hartman, Russ Allbery, Sam Hartman
  • Date: 2008-08-21 10:41:41 UTC
  • mfrom: (11.1.15 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080821104141-a0f9c4o4cpo8xd0o
Tags: 1.6.dfsg.4~beta1-4
[ Russ Allbery ]
* Translation updates:
  - Swedish, thanks Martin Bagge.  (Closes: #487669, #491774)
  - Italian, thanks Luca Monducci.  (Closes: #493962)

[ Sam Hartman ]
* Translation Updates:
    - Dutch, Thanks Vincent Zweije, Closes: #495733

Show diffs side-by-side

added added

removed removed

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