1 /* $OpenLDAP: pkg/ldap/libraries/libldap/util-int.c,v 1.57.2.3 2008/02/11 23:26:41 kurt Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2008 The OpenLDAP Foundation.
5 * Portions Copyright 1998 A. Hartgers.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
17 * This work was initially developed by Bart Hartgers for inclusion in
22 * util-int.c Various functions to replace missing threadsafe ones.
23 * Without the real *_r funcs, things will
24 * work, but might not be threadsafe.
29 #include <ac/stdlib.h>
32 #include <ac/socket.h>
33 #include <ac/string.h>
35 #include <ac/unistd.h>
40 /* newer systems declare this in <netdb.h> for you, older ones don't.
41 * harmless to declare it again (unless defined by a macro).
47 # define HSTRERROR(e) hstrerror(e)
49 # define HSTRERROR(e) hp_strerror(e)
52 #ifndef LDAP_R_COMPILE
53 # undef HAVE_REENTRANT_FUNCTIONS
55 # undef HAVE_GETHOSTBYNAME_R
56 # undef HAVE_GETHOSTBYADDR_R
59 # include <ldap_pvt_thread.h>
60 ldap_pvt_thread_mutex_t ldap_int_resolv_mutex
;
62 # if (defined( HAVE_CTIME_R ) || defined( HAVE_REENTRANT_FUNCTIONS)) \
63 && defined( CTIME_R_NARGS )
66 static ldap_pvt_thread_mutex_t ldap_int_ctime_mutex
;
69 # if defined(HAVE_GETHOSTBYNAME_R) && \
70 (GETHOSTBYNAME_R_NARGS < 5) || (6 < GETHOSTBYNAME_R_NARGS)
71 /* Don't know how to handle this version, pretend it's not there */
72 # undef HAVE_GETHOSTBYNAME_R
74 # if defined(HAVE_GETHOSTBYADDR_R) && \
75 (GETHOSTBYADDR_R_NARGS < 7) || (8 < GETHOSTBYADDR_R_NARGS)
76 /* Don't know how to handle this version, pretend it's not there */
77 # undef HAVE_GETHOSTBYADDR_R
79 #endif /* LDAP_R_COMPILE */
81 char *ldap_pvt_ctime( const time_t *tp
, char *buf
)
84 # if (CTIME_R_NARGS > 3) || (CTIME_R_NARGS < 2)
85 # error "CTIME_R_NARGS should be 2 or 3"
86 # elif CTIME_R_NARGS > 2 && defined(CTIME_R_RETURNS_INT)
87 return( ctime_r(tp
,buf
,26) < 0 ? 0 : buf
);
88 # elif CTIME_R_NARGS > 2
89 return ctime_r(tp
,buf
,26);
91 return ctime_r(tp
,buf
);
96 # ifdef LDAP_R_COMPILE
97 ldap_pvt_thread_mutex_lock( &ldap_int_ctime_mutex
);
100 AC_MEMCPY( buf
, ctime(tp
), 26 );
102 # ifdef LDAP_R_COMPILE
103 ldap_pvt_thread_mutex_unlock( &ldap_int_ctime_mutex
);
110 #define BUFSTART (1024-32)
111 #define BUFMAX (32*1024-32)
113 #if defined(LDAP_R_COMPILE)
114 static char *safe_realloc( char **buf
, int len
);
116 #if !(defined(HAVE_GETHOSTBYNAME_R) && defined(HAVE_GETHOSTBYADDR_R))
117 static int copy_hostent( struct hostent
*res
,
118 char **buf
, struct hostent
* src
);
122 int ldap_pvt_gethostbyname_a(
124 struct hostent
*resbuf
,
126 struct hostent
**result
,
129 #if defined( HAVE_GETHOSTBYNAME_R )
131 # define NEED_SAFE_REALLOC 1
135 for(;buflen
<BUFMAX
;) {
136 if (safe_realloc( buf
, buflen
)==NULL
)
139 #if (GETHOSTBYNAME_R_NARGS < 6)
140 *result
=gethostbyname_r( name
, resbuf
, *buf
, buflen
, herrno_ptr
);
141 r
= (*result
== NULL
) ? -1 : 0;
143 r
= gethostbyname_r( name
, resbuf
, *buf
,
144 buflen
, result
, herrno_ptr
);
147 Debug( LDAP_DEBUG_TRACE
, "ldap_pvt_gethostbyname_a: host=%s, r=%d\n",
150 #ifdef NETDB_INTERNAL
152 (*herrno_ptr
==NETDB_INTERNAL
) &&
162 #elif defined( LDAP_R_COMPILE )
163 # define NEED_COPY_HOSTENT
168 ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex
);
170 he
= gethostbyname( name
);
173 *herrno_ptr
= h_errno
;
175 } else if (copy_hostent( resbuf
, buf
, he
)<0) {
183 ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex
);
188 *result
= gethostbyname( name
);
194 *herrno_ptr
= h_errno
;
200 #if !defined( HAVE_GETNAMEINFO ) && !defined( HAVE_HSTRERROR )
202 hp_strerror( int err
)
205 case HOST_NOT_FOUND
: return _("Host not found (authoritative)");
206 case TRY_AGAIN
: return _("Host not found (server fail?)");
207 case NO_RECOVERY
: return _("Non-recoverable failure");
208 case NO_DATA
: return _("No data of requested type");
209 #ifdef NETDB_INTERNAL
210 case NETDB_INTERNAL
: return STRERROR( errno
);
213 return _("Unknown resolver error");
217 int ldap_pvt_get_hname(
218 const struct sockaddr
*sa
,
225 #if defined( HAVE_GETNAMEINFO )
227 #if defined( LDAP_R_COMPILE )
228 ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex
);
230 rc
= getnameinfo( sa
, len
, name
, namelen
, NULL
, 0, 0 );
231 #if defined( LDAP_R_COMPILE )
232 ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex
);
234 if ( rc
) *err
= (char *)AC_GAI_STRERROR( rc
);
237 #else /* !HAVE_GETNAMEINFO */
240 struct hostent
*hp
= NULL
;
241 #ifdef HAVE_GETHOSTBYADDR_R
243 int buflen
=BUFSTART
, h_errno
;
248 if (sa
->sa_family
== AF_INET6
) {
249 struct sockaddr_in6
*sin
= (struct sockaddr_in6
*)sa
;
250 addr
= (char *)&sin
->sin6_addr
;
251 alen
= sizeof(sin
->sin6_addr
);
254 if (sa
->sa_family
== AF_INET
) {
255 struct sockaddr_in
*sin
= (struct sockaddr_in
*)sa
;
256 addr
= (char *)&sin
->sin_addr
;
257 alen
= sizeof(sin
->sin_addr
);
260 *err
= (char *)HSTRERROR( rc
);
263 #if defined( HAVE_GETHOSTBYADDR_R )
264 for(;buflen
<BUFMAX
;) {
265 if (safe_realloc( &buf
, buflen
)==NULL
) {
266 *err
= (char *)STRERROR( ENOMEM
);
269 #if (GETHOSTBYADDR_R_NARGS < 8)
270 hp
=gethostbyaddr_r( addr
, alen
, sa
->sa_family
,
271 &hb
, buf
, buflen
, &h_errno
);
272 rc
= (hp
== NULL
) ? -1 : 0;
274 rc
= gethostbyaddr_r( addr
, alen
, sa
->sa_family
,
278 #ifdef NETDB_INTERNAL
280 (h_errno
==NETDB_INTERNAL
) &&
290 strncpy( name
, hp
->h_name
, namelen
);
292 *err
= (char *)HSTRERROR( h_errno
);
295 #else /* HAVE_GETHOSTBYADDR_R */
297 #if defined( LDAP_R_COMPILE )
298 ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex
);
300 hp
= gethostbyaddr( addr
, alen
, sa
->sa_family
);
302 strncpy( name
, hp
->h_name
, namelen
);
306 *err
= (char *)HSTRERROR( h_errno
);
308 #if defined( LDAP_R_COMPILE )
309 ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex
);
312 #endif /* !HAVE_GETHOSTBYADDR_R */
314 #endif /* !HAVE_GETNAMEINFO */
317 int ldap_pvt_gethostbyaddr_a(
321 struct hostent
*resbuf
,
323 struct hostent
**result
,
326 #if defined( HAVE_GETHOSTBYADDR_R )
328 # undef NEED_SAFE_REALLOC
329 # define NEED_SAFE_REALLOC
333 for(;buflen
<BUFMAX
;) {
334 if (safe_realloc( buf
, buflen
)==NULL
)
336 #if (GETHOSTBYADDR_R_NARGS < 8)
337 *result
=gethostbyaddr_r( addr
, len
, type
,
338 resbuf
, *buf
, buflen
, herrno_ptr
);
339 r
= (*result
== NULL
) ? -1 : 0;
341 r
= gethostbyaddr_r( addr
, len
, type
,
342 resbuf
, *buf
, buflen
,
343 result
, herrno_ptr
);
346 #ifdef NETDB_INTERNAL
348 (*herrno_ptr
==NETDB_INTERNAL
) &&
358 #elif defined( LDAP_R_COMPILE )
359 # undef NEED_COPY_HOSTENT
360 # define NEED_COPY_HOSTENT
365 ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex
);
367 he
= gethostbyaddr( addr
, len
, type
);
370 *herrno_ptr
= h_errno
;
372 } else if (copy_hostent( resbuf
, buf
, he
)<0) {
380 ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex
);
384 #else /* gethostbyaddr() */
386 *result
= gethostbyaddr( addr
, len
, type
);
395 * ldap_int_utils_init() should be called before any other function.
398 void ldap_int_utils_init( void )
405 #ifdef LDAP_R_COMPILE
406 #if !defined( USE_CTIME_R ) && !defined( HAVE_REENTRANT_FUNCTIONS )
407 ldap_pvt_thread_mutex_init( &ldap_int_ctime_mutex
);
409 ldap_pvt_thread_mutex_init( &ldap_int_resolv_mutex
);
411 #ifdef HAVE_CYRUS_SASL
412 ldap_pvt_thread_mutex_init( &ldap_int_sasl_mutex
);
416 /* call other module init functions here... */
419 #if defined( NEED_COPY_HOSTENT )
420 # undef NEED_SAFE_REALLOC
421 #define NEED_SAFE_REALLOC
423 static char *cpy_aliases(
430 for( ; (*src
) ; src
++ ) {
431 len
= strlen( *src
) + 1;
432 AC_MEMCPY( buf
, *src
, len
);
440 static char *cpy_addresses(
447 for( ; (*src
) ; src
++ ) {
448 AC_MEMCPY( buf
, *src
, len
);
456 static int copy_hostent(
459 struct hostent
* src
)
466 int total_alias_len
=0;
468 int total_addr_len
=0;
471 /* calculate the size needed for the buffer */
472 name_len
= strlen( src
->h_name
) + 1;
474 if( src
->h_aliases
!= NULL
) {
475 for( p
= src
->h_aliases
; (*p
) != NULL
; p
++ ) {
476 total_alias_len
+= strlen( *p
) + 1;
481 if( src
->h_addr_list
!= NULL
) {
482 for( p
= src
->h_addr_list
; (*p
) != NULL
; p
++ ) {
485 total_addr_len
= n_addr
* src
->h_length
;
488 total_len
= (n_alias
+ n_addr
+ 2) * sizeof( char * ) +
489 total_addr_len
+ total_alias_len
+ name_len
;
491 if (safe_realloc( buf
, total_len
)) {
493 tbuf
= *buf
+ (n_alias
+ n_addr
+ 2) * sizeof( char * );
494 AC_MEMCPY( res
, src
, sizeof( struct hostent
) );
495 /* first the name... */
496 AC_MEMCPY( tbuf
, src
->h_name
, name_len
);
497 res
->h_name
= tbuf
; tbuf
+=name_len
;
498 /* now the aliases */
500 if ( src
->h_aliases
!= NULL
) {
501 tbuf
= cpy_aliases( &tp
, tbuf
, src
->h_aliases
);
504 /* finally the addresses */
505 res
->h_addr_list
= tp
;
506 if ( src
->h_addr_list
!= NULL
) {
507 tbuf
= cpy_addresses( &tp
, tbuf
, src
->h_addr_list
, src
->h_length
);
516 #if defined( NEED_SAFE_REALLOC )
517 static char *safe_realloc( char **buf
, int len
)
520 tmpbuf
= LDAP_REALLOC( *buf
, len
);
528 char * ldap_pvt_get_fqdn( char *name
)
531 char hostbuf
[MAXHOSTNAMELEN
+1];
532 struct hostent
*hp
, he_buf
;
533 int rc
, local_h_errno
;
536 if( gethostname( hostbuf
, MAXHOSTNAMELEN
) == 0 ) {
537 hostbuf
[MAXHOSTNAMELEN
] = '\0';
544 rc
= ldap_pvt_gethostbyname_a( name
,
545 &he_buf
, &ha_buf
, &hp
, &local_h_errno
);
547 if( rc
< 0 || hp
== NULL
|| hp
->h_name
== NULL
) {
548 fqdn
= LDAP_STRDUP( name
);
550 fqdn
= LDAP_STRDUP( hp
->h_name
);
557 #if ( defined( HAVE_GETADDRINFO ) || defined( HAVE_GETNAMEINFO ) ) \
558 && !defined( HAVE_GAI_STRERROR )
559 char *ldap_pvt_gai_strerror (int code
) {
564 #ifdef EAI_ADDRFAMILY
565 { EAI_ADDRFAMILY
, N_("Address family for hostname not supported") },
567 { EAI_AGAIN
, N_("Temporary failure in name resolution") },
568 { EAI_BADFLAGS
, N_("Bad value for ai_flags") },
569 { EAI_FAIL
, N_("Non-recoverable failure in name resolution") },
570 { EAI_FAMILY
, N_("ai_family not supported") },
571 { EAI_MEMORY
, N_("Memory allocation failure") },
573 { EAI_NODATA
, N_("No address associated with hostname") },
575 { EAI_NONAME
, N_("Name or service not known") },
576 { EAI_SERVICE
, N_("Servname not supported for ai_socktype") },
577 { EAI_SOCKTYPE
, N_("ai_socktype not supported") },
578 { EAI_SYSTEM
, N_("System error") },
584 for ( i
= 0; values
[i
].msg
!= NULL
; i
++ ) {
585 if ( values
[i
].code
== code
) {
586 return (char *) _(values
[i
].msg
);
590 return _("Unknown error");