Home | History | Annotate | Line # | Download | only in libldap
      1 /*	$NetBSD: util-int.c,v 1.4 2025/09/05 21:16:22 christos Exp $	*/
      2 
      3 /* $OpenLDAP$ */
      4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      5  *
      6  * Copyright 1998-2024 The OpenLDAP Foundation.
      7  * Portions Copyright 1998 A. Hartgers.
      8  * All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted only as authorized by the OpenLDAP
     12  * Public License.
     13  *
     14  * A copy of this license is available in the file LICENSE in the
     15  * top-level directory of the distribution or, alternatively, at
     16  * <http://www.OpenLDAP.org/license.html>.
     17  */
     18 /* ACKNOWLEDGEMENTS:
     19  * This work was initially developed by Bart Hartgers for inclusion in
     20  * OpenLDAP Software.
     21  */
     22 
     23 /*
     24  * util-int.c	Various functions to replace missing threadsafe ones.
     25  *				Without the real *_r funcs, things will
     26  *				work, but might not be threadsafe.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __RCSID("$NetBSD: util-int.c,v 1.4 2025/09/05 21:16:22 christos Exp $");
     31 
     32 #include "portable.h"
     33 
     34 #include <ac/stdlib.h>
     35 
     36 #include <ac/errno.h>
     37 #include <ac/socket.h>
     38 #include <ac/string.h>
     39 #include <ac/time.h>
     40 #include <ac/unistd.h>
     41 
     42 #include "ldap-int.h"
     43 
     44 #ifndef h_errno
     45 /* newer systems declare this in <netdb.h> for you, older ones don't.
     46  * harmless to declare it again (unless defined by a macro).
     47  */
     48 extern int h_errno;
     49 #endif
     50 
     51 #ifdef HAVE_HSTRERROR
     52 # define HSTRERROR(e)	hstrerror(e)
     53 #else
     54 # define HSTRERROR(e)	hp_strerror(e)
     55 #endif
     56 
     57 #ifndef LDAP_R_COMPILE
     58 # undef HAVE_REENTRANT_FUNCTIONS
     59 # undef HAVE_CTIME_R
     60 # undef HAVE_GETHOSTBYNAME_R
     61 # undef HAVE_GETHOSTBYADDR_R
     62 
     63 #else
     64 # include <ldap_pvt_thread.h>
     65   ldap_pvt_thread_mutex_t ldap_int_resolv_mutex;
     66   ldap_pvt_thread_mutex_t ldap_int_hostname_mutex;
     67   static ldap_pvt_thread_mutex_t ldap_int_gettime_mutex;
     68 
     69 # if (defined( HAVE_CTIME_R ) || defined( HAVE_REENTRANT_FUNCTIONS)) \
     70 	 && defined( CTIME_R_NARGS )
     71 #   define USE_CTIME_R
     72 # else
     73 	static ldap_pvt_thread_mutex_t ldap_int_ctime_mutex;
     74 # endif
     75 
     76 /* USE_GMTIME_R and USE_LOCALTIME_R defined in ldap_pvt.h */
     77 
     78 #if !defined( USE_GMTIME_R ) || !defined( USE_LOCALTIME_R )
     79 	/* we use the same mutex for gmtime(3) and localtime(3)
     80 	 * because implementations may use the same buffer
     81 	 * for both functions */
     82 	static ldap_pvt_thread_mutex_t ldap_int_gmtime_mutex;
     83 #endif
     84 
     85 # if defined(HAVE_GETHOSTBYNAME_R) && \
     86 	(GETHOSTBYNAME_R_NARGS < 5) || (6 < GETHOSTBYNAME_R_NARGS)
     87 	/* Don't know how to handle this version, pretend it's not there */
     88 #	undef HAVE_GETHOSTBYNAME_R
     89 # endif
     90 # if defined(HAVE_GETHOSTBYADDR_R) && \
     91 	(GETHOSTBYADDR_R_NARGS < 7) || (8 < GETHOSTBYADDR_R_NARGS)
     92 	/* Don't know how to handle this version, pretend it's not there */
     93 #	undef HAVE_GETHOSTBYADDR_R
     94 # endif
     95 #endif /* LDAP_R_COMPILE */
     96 
     97 char *ldap_pvt_ctime( const time_t *tp, char *buf )
     98 {
     99 #ifdef USE_CTIME_R
    100 # if (CTIME_R_NARGS > 3) || (CTIME_R_NARGS < 2)
    101 #	error "CTIME_R_NARGS should be 2 or 3"
    102 # elif CTIME_R_NARGS > 2 && defined(CTIME_R_RETURNS_INT)
    103 	return( ctime_r(tp,buf,26) < 0 ? 0 : buf );
    104 # elif CTIME_R_NARGS > 2
    105 	return ctime_r(tp,buf,26);
    106 # else
    107 	return ctime_r(tp,buf);
    108 # endif
    109 
    110 #else
    111 
    112 	LDAP_MUTEX_LOCK( &ldap_int_ctime_mutex );
    113 	AC_MEMCPY( buf, ctime(tp), 26 );
    114 	LDAP_MUTEX_UNLOCK( &ldap_int_ctime_mutex );
    115 
    116 	return buf;
    117 #endif
    118 }
    119 
    120 #if !defined( USE_GMTIME_R ) || !defined( USE_LOCALTIME_R )
    121 int
    122 ldap_pvt_gmtime_lock( void )
    123 {
    124 # ifndef LDAP_R_COMPILE
    125 	return 0;
    126 # else /* LDAP_R_COMPILE */
    127 	return ldap_pvt_thread_mutex_lock( &ldap_int_gmtime_mutex );
    128 # endif /* LDAP_R_COMPILE */
    129 }
    130 
    131 int
    132 ldap_pvt_gmtime_unlock( void )
    133 {
    134 # ifndef LDAP_R_COMPILE
    135 	return 0;
    136 # else /* LDAP_R_COMPILE */
    137 	return ldap_pvt_thread_mutex_unlock( &ldap_int_gmtime_mutex );
    138 # endif /* LDAP_R_COMPILE */
    139 }
    140 #endif /* !USE_GMTIME_R || !USE_LOCALTIME_R */
    141 
    142 #ifndef USE_GMTIME_R
    143 struct tm *
    144 ldap_pvt_gmtime( const time_t *timep, struct tm *result )
    145 {
    146 	struct tm *tm_ptr;
    147 
    148 	LDAP_MUTEX_LOCK( &ldap_int_gmtime_mutex );
    149 	tm_ptr = gmtime( timep );
    150 	if ( tm_ptr == NULL ) {
    151 		result = NULL;
    152 
    153 	} else {
    154 		*result = *tm_ptr;
    155 	}
    156 	LDAP_MUTEX_UNLOCK( &ldap_int_gmtime_mutex );
    157 
    158 	return result;
    159 }
    160 #endif /* !USE_GMTIME_R */
    161 
    162 #ifndef USE_LOCALTIME_R
    163 struct tm *
    164 ldap_pvt_localtime( const time_t *timep, struct tm *result )
    165 {
    166 	struct tm *tm_ptr;
    167 
    168 	LDAP_MUTEX_LOCK( &ldap_int_gmtime_mutex );
    169 	tm_ptr = localtime( timep );
    170 	if ( tm_ptr == NULL ) {
    171 		result = NULL;
    172 
    173 	} else {
    174 		*result = *tm_ptr;
    175 	}
    176 	LDAP_MUTEX_UNLOCK( &ldap_int_gmtime_mutex );
    177 
    178 	return result;
    179 }
    180 #endif /* !USE_LOCALTIME_R */
    181 
    182 static int _ldap_pvt_gt_subs;
    183 
    184 #ifdef _WIN32
    185 /* Windows SYSTEMTIME only has 10 millisecond resolution, so we
    186  * also need to use a high resolution timer to get nanoseconds.
    187  * This is pretty clunky.
    188  */
    189 static LARGE_INTEGER _ldap_pvt_gt_freq;
    190 static LARGE_INTEGER _ldap_pvt_gt_start_count;
    191 static long _ldap_pvt_gt_start_sec;
    192 static long _ldap_pvt_gt_start_nsec;
    193 static double _ldap_pvt_gt_nanoticks;
    194 
    195 #define SEC_TO_UNIX_EPOCH 11644473600LL
    196 #define TICKS_PER_SECOND 10000000
    197 #define BILLION	1000000000L
    198 
    199 static int
    200 ldap_pvt_gettimensec(long *sec)
    201 {
    202 	LARGE_INTEGER count;
    203 	LARGE_INTEGER freq;
    204 	int nsec;
    205 
    206 	QueryPerformanceFrequency( &freq );
    207 	/* We assume Windows has at least a vague idea of
    208 	 * when a second begins. So we align our nanosecond count
    209 	 * with the Windows millisecond count.
    210 	 */
    211 	if ( freq.QuadPart != _ldap_pvt_gt_freq.QuadPart ) {
    212 		ULARGE_INTEGER ut;
    213 		FILETIME ft0, ft1;
    214 		/* initialize */
    215 		LDAP_MUTEX_LOCK( &ldap_int_gettime_mutex );
    216 		/* Wait for a tick of the system time: 10-15ms */
    217 		GetSystemTimeAsFileTime( &ft0 );
    218 		do {
    219 			GetSystemTimeAsFileTime( &ft1 );
    220 		} while ( ft1.dwLowDateTime == ft0.dwLowDateTime );
    221 		QueryPerformanceCounter( &_ldap_pvt_gt_start_count );
    222 
    223 		ut.LowPart = ft1.dwLowDateTime;
    224 		ut.HighPart = ft1.dwHighDateTime;
    225 		_ldap_pvt_gt_start_nsec = ut.QuadPart % TICKS_PER_SECOND * 100;
    226 		_ldap_pvt_gt_start_sec = ut.QuadPart / TICKS_PER_SECOND - SEC_TO_UNIX_EPOCH;
    227 		_ldap_pvt_gt_freq = freq;
    228 		_ldap_pvt_gt_nanoticks = (double)BILLION / freq.QuadPart;
    229 		LDAP_MUTEX_UNLOCK( &ldap_int_gettime_mutex );
    230 	}
    231 	QueryPerformanceCounter( &count );
    232 	count.QuadPart -= _ldap_pvt_gt_start_count.QuadPart;
    233 	*sec = _ldap_pvt_gt_start_sec + count.QuadPart / freq.QuadPart;
    234 	nsec = _ldap_pvt_gt_start_nsec + (double)(count.QuadPart % freq.QuadPart) * _ldap_pvt_gt_nanoticks;
    235 	if ( nsec > BILLION) {
    236 		nsec -= BILLION;
    237 		(*sec)++;
    238 	}
    239 	return nsec;
    240 }
    241 
    242 /* emulate POSIX clock_gettime */
    243 int
    244 ldap_pvt_clock_gettime( int clk_id, struct timespec *tv )
    245 {
    246 	long sec;
    247 	tv->tv_nsec = ldap_pvt_gettimensec( &sec );
    248 	tv->tv_sec = sec;
    249 	return 0;
    250 }
    251 
    252 /* emulate POSIX gettimeofday */
    253 int
    254 ldap_pvt_gettimeofday( struct timeval *tv, void *unused )
    255 {
    256 	struct timespec ts;
    257 	ldap_pvt_clock_gettime( 0, &ts );
    258 	tv->tv_sec = ts.tv_sec;
    259 	tv->tv_usec = ts.tv_nsec / 1000;
    260 	return 0;
    261 }
    262 
    263 static long _ldap_pvt_gt_prevsec;
    264 static int _ldap_pvt_gt_prevnsec;
    265 
    266 /* return a broken out time, with nanoseconds
    267  */
    268 void
    269 ldap_pvt_gettime( struct lutil_tm *tm )
    270 {
    271 	SYSTEMTIME st;
    272 	LARGE_INTEGER ft;
    273 	long sec;
    274 
    275 	/* Convert sec/nsec to Windows FILETIME,
    276 	 * then turn that into broken out SYSTEMTIME */
    277 	tm->tm_nsec = ldap_pvt_gettimensec(&sec);
    278 	ft.QuadPart = sec;
    279 	ft.QuadPart += SEC_TO_UNIX_EPOCH;
    280 	ft.QuadPart *= TICKS_PER_SECOND;
    281 	ft.QuadPart += tm->tm_nsec / 100;
    282 	FileTimeToSystemTime( (FILETIME *)&ft, &st );
    283 
    284 	tm->tm_sec = st.wSecond;
    285 	tm->tm_min = st.wMinute;
    286 	tm->tm_hour = st.wHour;
    287 	tm->tm_mday = st.wDay;
    288 	tm->tm_mon = st.wMonth - 1;
    289 	tm->tm_year = st.wYear - 1900;
    290 
    291 	LDAP_MUTEX_LOCK( &ldap_int_gettime_mutex );
    292 	if ( tm->tm_sec < _ldap_pvt_gt_prevsec
    293 		|| ( tm->tm_sec == _ldap_pvt_gt_prevsec
    294 		&& tm->tm_nsec <= _ldap_pvt_gt_prevnsec )) {
    295 		_ldap_pvt_gt_subs++;
    296 	} else {
    297 		_ldap_pvt_gt_subs = 0;
    298 		_ldap_pvt_gt_prevsec = sec;
    299 		_ldap_pvt_gt_prevnsec = tm->tm_nsec;
    300 	}
    301 	LDAP_MUTEX_UNLOCK( &ldap_int_gettime_mutex );
    302 	tm->tm_usub = _ldap_pvt_gt_subs;
    303 }
    304 #else
    305 
    306 #ifdef HAVE_CLOCK_GETTIME
    307 static struct timespec _ldap_pvt_gt_prevTv;
    308 #else
    309 static struct timeval _ldap_pvt_gt_prevTv;
    310 #endif
    311 
    312 void
    313 ldap_pvt_gettime( struct lutil_tm *ltm )
    314 {
    315 	struct tm tm;
    316 	time_t t;
    317 #ifdef HAVE_CLOCK_GETTIME
    318 #define	FRAC	tv_nsec
    319 #define	NSECS(x)	x
    320 	struct timespec tv;
    321 
    322 	clock_gettime( CLOCK_REALTIME, &tv );
    323 #else
    324 #define	FRAC	tv_usec
    325 #define	NSECS(x)	x * 1000
    326 	struct timeval tv;
    327 
    328 	gettimeofday( &tv, NULL );
    329 #endif
    330 	t = tv.tv_sec;
    331 
    332 	LDAP_MUTEX_LOCK( &ldap_int_gettime_mutex );
    333 	if ( tv.tv_sec < _ldap_pvt_gt_prevTv.tv_sec
    334 		|| ( tv.tv_sec == _ldap_pvt_gt_prevTv.tv_sec
    335 		&& tv.FRAC <= _ldap_pvt_gt_prevTv.FRAC )) {
    336 		_ldap_pvt_gt_subs++;
    337 	} else {
    338 		_ldap_pvt_gt_subs = 0;
    339 		_ldap_pvt_gt_prevTv = tv;
    340 	}
    341 	LDAP_MUTEX_UNLOCK( &ldap_int_gettime_mutex );
    342 
    343 	ltm->tm_usub = _ldap_pvt_gt_subs;
    344 
    345 	ldap_pvt_gmtime( &t, &tm );
    346 
    347 	ltm->tm_sec = tm.tm_sec;
    348 	ltm->tm_min = tm.tm_min;
    349 	ltm->tm_hour = tm.tm_hour;
    350 	ltm->tm_mday = tm.tm_mday;
    351 	ltm->tm_mon = tm.tm_mon;
    352 	ltm->tm_year = tm.tm_year;
    353 	ltm->tm_nsec = NSECS(tv.FRAC);
    354 }
    355 #endif
    356 
    357 size_t
    358 ldap_pvt_csnstr(char *buf, size_t len, unsigned int replica, unsigned int mod)
    359 {
    360 	struct lutil_tm tm;
    361 	int n;
    362 
    363 	ldap_pvt_gettime( &tm );
    364 
    365 	n = snprintf( buf, len,
    366 		"%4d%02d%02d%02d%02d%02d.%06dZ#%06x#%03x#%06x",
    367 		tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
    368 		tm.tm_min, tm.tm_sec, tm.tm_nsec / 1000, tm.tm_usub, replica, mod );
    369 
    370 	if( n < 0 ) return 0;
    371 	return ( (size_t) n < len ) ? n : 0;
    372 }
    373 
    374 #define BUFSTART (1024-32)
    375 #define BUFMAX (32*1024-32)
    376 
    377 #if defined(LDAP_R_COMPILE)
    378 static char *safe_realloc( char **buf, int len );
    379 
    380 #if !(defined(HAVE_GETHOSTBYNAME_R) && defined(HAVE_GETHOSTBYADDR_R))
    381 static int copy_hostent( struct hostent *res,
    382 	char **buf, struct hostent * src );
    383 #endif
    384 #endif
    385 
    386 int ldap_pvt_gethostbyname_a(
    387 	const char *name,
    388 	struct hostent *resbuf,
    389 	char **buf,
    390 	struct hostent **result,
    391 	int *herrno_ptr )
    392 {
    393 #if defined( HAVE_GETHOSTBYNAME_R )
    394 
    395 # define NEED_SAFE_REALLOC 1
    396 	int r=-1;
    397 	int buflen=BUFSTART;
    398 	*buf = NULL;
    399 	for(;buflen<BUFMAX;) {
    400 		if (safe_realloc( buf, buflen )==NULL)
    401 			return r;
    402 
    403 #if (GETHOSTBYNAME_R_NARGS < 6)
    404 		*result=gethostbyname_r( name, resbuf, *buf, buflen, herrno_ptr );
    405 		r = (*result == NULL) ?  -1 : 0;
    406 #else
    407 		while((r = gethostbyname_r( name, resbuf, *buf, buflen, result, herrno_ptr )) == ERANGE) {
    408 			/* Increase the buffer */
    409 			buflen*=2;
    410 			if (safe_realloc(buf, buflen) == NULL)
    411 				return -1;
    412 		}
    413 #endif
    414 
    415 		Debug2( LDAP_DEBUG_TRACE, "ldap_pvt_gethostbyname_a: host=%s, r=%d\n",
    416 		       name, r );
    417 
    418 #ifdef NETDB_INTERNAL
    419 		if ((r<0) &&
    420 			(*herrno_ptr==NETDB_INTERNAL) &&
    421 			(errno==ERANGE))
    422 		{
    423 			buflen*=2;
    424 			continue;
    425 	 	}
    426 #endif
    427 		return r;
    428 	}
    429 	return -1;
    430 #elif defined( LDAP_R_COMPILE )
    431 # define NEED_COPY_HOSTENT
    432 	struct hostent *he;
    433 	int	retval;
    434 	*buf = NULL;
    435 
    436 	LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
    437 
    438 	he = gethostbyname( name );
    439 
    440 	if (he==NULL) {
    441 		*herrno_ptr = h_errno;
    442 		retval = -1;
    443 	} else if (copy_hostent( resbuf, buf, he )<0) {
    444 		*herrno_ptr = -1;
    445 		retval = -1;
    446 	} else {
    447 		*result = resbuf;
    448 		retval = 0;
    449 	}
    450 
    451 	LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
    452 
    453 	return retval;
    454 #else
    455 	*buf = NULL;
    456 	*result = gethostbyname( name );
    457 
    458 	if (*result!=NULL) {
    459 		return 0;
    460 	}
    461 
    462 	*herrno_ptr = h_errno;
    463 
    464 	return -1;
    465 #endif
    466 }
    467 
    468 #if !defined( HAVE_GETNAMEINFO ) && !defined( HAVE_HSTRERROR )
    469 static const char *
    470 hp_strerror( int err )
    471 {
    472 	switch (err) {
    473 	case HOST_NOT_FOUND:	return _("Host not found (authoritative)");
    474 	case TRY_AGAIN:			return _("Host not found (server fail?)");
    475 	case NO_RECOVERY:		return _("Non-recoverable failure");
    476 	case NO_DATA:			return _("No data of requested type");
    477 #ifdef NETDB_INTERNAL
    478 	case NETDB_INTERNAL:	return STRERROR( errno );
    479 #endif
    480 	}
    481 	return _("Unknown resolver error");
    482 }
    483 #endif
    484 
    485 int ldap_pvt_get_hname(
    486 	const struct sockaddr *sa,
    487 	int len,
    488 	char *name,
    489 	int namelen,
    490 	char **err )
    491 {
    492 	int rc;
    493 #if defined( HAVE_GETNAMEINFO )
    494 
    495 	LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
    496 	rc = getnameinfo( sa, len, name, namelen, NULL, 0, 0 );
    497 	LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
    498 	if ( rc ) *err = (char *)AC_GAI_STRERROR( rc );
    499 	return rc;
    500 
    501 #else /* !HAVE_GETNAMEINFO */
    502 	char *addr;
    503 	int alen;
    504 	struct hostent *hp = NULL;
    505 #ifdef HAVE_GETHOSTBYADDR_R
    506 	struct hostent hb;
    507 	int buflen=BUFSTART, h_errno;
    508 	char *buf=NULL;
    509 #endif
    510 
    511 #ifdef LDAP_PF_INET6
    512 	if (sa->sa_family == AF_INET6) {
    513 		struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa;
    514 		addr = (char *)&sin->sin6_addr;
    515 		alen = sizeof(sin->sin6_addr);
    516 	} else
    517 #endif
    518 	if (sa->sa_family == AF_INET) {
    519 		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
    520 		addr = (char *)&sin->sin_addr;
    521 		alen = sizeof(sin->sin_addr);
    522 	} else {
    523 		rc = NO_RECOVERY;
    524 		*err = (char *)HSTRERROR( rc );
    525 		return rc;
    526 	}
    527 #if defined( HAVE_GETHOSTBYADDR_R )
    528 	for(;buflen<BUFMAX;) {
    529 		if (safe_realloc( &buf, buflen )==NULL) {
    530 			*err = (char *)STRERROR( ENOMEM );
    531 			return ENOMEM;
    532 		}
    533 #if (GETHOSTBYADDR_R_NARGS < 8)
    534 		hp=gethostbyaddr_r( addr, alen, sa->sa_family,
    535 			&hb, buf, buflen, &h_errno );
    536 		rc = (hp == NULL) ? -1 : 0;
    537 #else
    538 		rc = gethostbyaddr_r( addr, alen, sa->sa_family,
    539 			&hb, buf, buflen,
    540 			&hp, &h_errno );
    541 #endif
    542 #ifdef NETDB_INTERNAL
    543 		if ((rc<0) &&
    544 			(h_errno==NETDB_INTERNAL) &&
    545 			(errno==ERANGE))
    546 		{
    547 			buflen*=2;
    548 			continue;
    549 		}
    550 #endif
    551 		break;
    552 	}
    553 	if (hp) {
    554 		strncpy( name, hp->h_name, namelen );
    555 	} else {
    556 		*err = (char *)HSTRERROR( h_errno );
    557 	}
    558 	LDAP_FREE(buf);
    559 #else /* HAVE_GETHOSTBYADDR_R */
    560 
    561 	LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
    562 	hp = gethostbyaddr( addr, alen, sa->sa_family );
    563 	if (hp) {
    564 		strncpy( name, hp->h_name, namelen );
    565 		rc = 0;
    566 	} else {
    567 		rc = h_errno;
    568 		*err = (char *)HSTRERROR( h_errno );
    569 	}
    570 	LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
    571 
    572 #endif	/* !HAVE_GETHOSTBYADDR_R */
    573 	return rc;
    574 #endif	/* !HAVE_GETNAMEINFO */
    575 }
    576 
    577 int ldap_pvt_gethostbyaddr_a(
    578 	const char *addr,
    579 	int len,
    580 	int type,
    581 	struct hostent *resbuf,
    582 	char **buf,
    583 	struct hostent **result,
    584 	int *herrno_ptr )
    585 {
    586 #if defined( HAVE_GETHOSTBYADDR_R )
    587 
    588 # undef NEED_SAFE_REALLOC
    589 # define NEED_SAFE_REALLOC
    590 	int r=-1;
    591 	int buflen=BUFSTART;
    592 	*buf = NULL;
    593 	for(;buflen<BUFMAX;) {
    594 		if (safe_realloc( buf, buflen )==NULL)
    595 			return r;
    596 #if (GETHOSTBYADDR_R_NARGS < 8)
    597 		*result=gethostbyaddr_r( addr, len, type,
    598 			resbuf, *buf, buflen, herrno_ptr );
    599 		r = (*result == NULL) ? -1 : 0;
    600 #else
    601 		r = gethostbyaddr_r( addr, len, type,
    602 			resbuf, *buf, buflen,
    603 			result, herrno_ptr );
    604 #endif
    605 
    606 #ifdef NETDB_INTERNAL
    607 		if ((r<0) &&
    608 			(*herrno_ptr==NETDB_INTERNAL) &&
    609 			(errno==ERANGE))
    610 		{
    611 			buflen*=2;
    612 			continue;
    613 		}
    614 #endif
    615 		return r;
    616 	}
    617 	return -1;
    618 #elif defined( LDAP_R_COMPILE )
    619 # undef NEED_COPY_HOSTENT
    620 # define NEED_COPY_HOSTENT
    621 	struct hostent *he;
    622 	int	retval;
    623 	*buf = NULL;
    624 
    625 	LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
    626 	he = gethostbyaddr( addr, len, type );
    627 
    628 	if (he==NULL) {
    629 		*herrno_ptr = h_errno;
    630 		retval = -1;
    631 	} else if (copy_hostent( resbuf, buf, he )<0) {
    632 		*herrno_ptr = -1;
    633 		retval = -1;
    634 	} else {
    635 		*result = resbuf;
    636 		retval = 0;
    637 	}
    638 	LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
    639 
    640 	return retval;
    641 
    642 #else /* gethostbyaddr() */
    643 	*buf = NULL;
    644 	*result = gethostbyaddr( addr, len, type );
    645 
    646 	if (*result!=NULL) {
    647 		return 0;
    648 	}
    649 	return -1;
    650 #endif
    651 }
    652 /*
    653  * ldap_int_utils_init() should be called before any other function.
    654  */
    655 
    656 void ldap_int_utils_init( void )
    657 {
    658 	static int done=0;
    659 	if (done)
    660 	  return;
    661 	done=1;
    662 
    663 #ifdef LDAP_R_COMPILE
    664 #if !defined( USE_CTIME_R ) && !defined( HAVE_REENTRANT_FUNCTIONS )
    665 	ldap_pvt_thread_mutex_init( &ldap_int_ctime_mutex );
    666 #endif
    667 #if !defined( USE_GMTIME_R ) && !defined( USE_LOCALTIME_R )
    668 	ldap_pvt_thread_mutex_init( &ldap_int_gmtime_mutex );
    669 #endif
    670 	ldap_pvt_thread_mutex_init( &ldap_int_resolv_mutex );
    671 
    672 	ldap_pvt_thread_mutex_init( &ldap_int_hostname_mutex );
    673 
    674 	ldap_pvt_thread_mutex_init( &ldap_int_gettime_mutex );
    675 
    676 #ifdef HAVE_GSSAPI
    677 	ldap_pvt_thread_mutex_init( &ldap_int_gssapi_mutex );
    678 #endif
    679 #endif
    680 
    681 	/* call other module init functions here... */
    682 }
    683 
    684 #if defined( NEED_COPY_HOSTENT )
    685 # undef NEED_SAFE_REALLOC
    686 #define NEED_SAFE_REALLOC
    687 
    688 static char *cpy_aliases(
    689 	char ***tgtio,
    690 	char *buf,
    691 	char **src )
    692 {
    693 	int len;
    694 	char **tgt=*tgtio;
    695 	for( ; (*src) ; src++ ) {
    696 		len = strlen( *src ) + 1;
    697 		AC_MEMCPY( buf, *src, len );
    698 		*tgt++=buf;
    699 		buf+=len;
    700 	}
    701 	*tgtio=tgt;
    702 	return buf;
    703 }
    704 
    705 static char *cpy_addresses(
    706 	char ***tgtio,
    707 	char *buf,
    708 	char **src,
    709 	int len )
    710 {
    711    	char **tgt=*tgtio;
    712 	for( ; (*src) ; src++ ) {
    713 		AC_MEMCPY( buf, *src, len );
    714 		*tgt++=buf;
    715 		buf+=len;
    716 	}
    717 	*tgtio=tgt;
    718 	return buf;
    719 }
    720 
    721 static int copy_hostent(
    722 	struct hostent *res,
    723 	char **buf,
    724 	struct hostent * src )
    725 {
    726 	char	**p;
    727 	char	**tp;
    728 	char	*tbuf;
    729 	int	name_len;
    730 	int	n_alias=0;
    731 	int	total_alias_len=0;
    732 	int	n_addr=0;
    733 	int	total_addr_len=0;
    734 	int	total_len;
    735 
    736 	/* calculate the size needed for the buffer */
    737 	name_len = strlen( src->h_name ) + 1;
    738 
    739 	if( src->h_aliases != NULL ) {
    740 		for( p = src->h_aliases; (*p) != NULL; p++ ) {
    741 			total_alias_len += strlen( *p ) + 1;
    742 			n_alias++;
    743 		}
    744 	}
    745 
    746 	if( src->h_addr_list != NULL ) {
    747 		for( p = src->h_addr_list; (*p) != NULL; p++ ) {
    748 			n_addr++;
    749 		}
    750 		total_addr_len = n_addr * src->h_length;
    751 	}
    752 
    753 	total_len = (n_alias + n_addr + 2) * sizeof( char * ) +
    754 		total_addr_len + total_alias_len + name_len;
    755 
    756 	if (safe_realloc( buf, total_len )) {
    757 		tp = (char **) *buf;
    758 		tbuf = *buf + (n_alias + n_addr + 2) * sizeof( char * );
    759 		AC_MEMCPY( res, src, sizeof( struct hostent ) );
    760 		/* first the name... */
    761 		AC_MEMCPY( tbuf, src->h_name, name_len );
    762 		res->h_name = tbuf; tbuf+=name_len;
    763 		/* now the aliases */
    764 		res->h_aliases = tp;
    765 		if ( src->h_aliases != NULL ) {
    766 			tbuf = cpy_aliases( &tp, tbuf, src->h_aliases );
    767 		}
    768 		*tp++=NULL;
    769 		/* finally the addresses */
    770 		res->h_addr_list = tp;
    771 		if ( src->h_addr_list != NULL ) {
    772 			tbuf = cpy_addresses( &tp, tbuf, src->h_addr_list, src->h_length );
    773 		}
    774 		*tp++=NULL;
    775 		return 0;
    776 	}
    777 	return -1;
    778 }
    779 #endif
    780 
    781 #if defined( NEED_SAFE_REALLOC )
    782 static char *safe_realloc( char **buf, int len )
    783 {
    784 	char *tmpbuf;
    785 	tmpbuf = LDAP_REALLOC( *buf, len );
    786 	if (tmpbuf) {
    787 		*buf=tmpbuf;
    788 	}
    789 	return tmpbuf;
    790 }
    791 #endif
    792 
    793 char * ldap_pvt_get_fqdn( char *name )
    794 {
    795 #ifdef HAVE_GETADDRINFO
    796 	struct addrinfo hints, *res;
    797 #else
    798 	char *ha_buf;
    799 	struct hostent *hp, he_buf;
    800 	int local_h_errno;
    801 #endif
    802 	int rc;
    803 	char *fqdn, hostbuf[MAXHOSTNAMELEN+1];
    804 
    805 	if( name == NULL ) {
    806 		if( gethostname( hostbuf, MAXHOSTNAMELEN ) == 0 ) {
    807 			hostbuf[MAXHOSTNAMELEN] = '\0';
    808 			name = hostbuf;
    809 		} else {
    810 			name = "localhost";
    811 		}
    812 	}
    813 
    814 #ifdef HAVE_GETADDRINFO
    815 	memset( &hints, 0, sizeof( hints ));
    816 	hints.ai_family = AF_UNSPEC;
    817 	hints.ai_flags = AI_CANONNAME;
    818 
    819 	LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
    820 	rc = getaddrinfo( name, NULL, &hints, &res );
    821 	LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
    822 	if ( rc == 0 && res->ai_canonname ) {
    823 		fqdn = LDAP_STRDUP( res->ai_canonname );
    824 	} else {
    825 		fqdn = LDAP_STRDUP( name );
    826 	}
    827 	if ( rc == 0 )
    828 		freeaddrinfo( res );
    829 #else
    830 	rc = ldap_pvt_gethostbyname_a( name,
    831 		&he_buf, &ha_buf, &hp, &local_h_errno );
    832 
    833 	if( rc < 0 || hp == NULL || hp->h_name == NULL ) {
    834 		fqdn = LDAP_STRDUP( name );
    835 	} else {
    836 		fqdn = LDAP_STRDUP( hp->h_name );
    837 	}
    838 
    839 	LDAP_FREE( ha_buf );
    840 #endif
    841 	return fqdn;
    842 }
    843 
    844 #if ( defined( HAVE_GETADDRINFO ) || defined( HAVE_GETNAMEINFO ) ) \
    845 	&& !defined( HAVE_GAI_STRERROR )
    846 char *ldap_pvt_gai_strerror (int code) {
    847 	static struct {
    848 		int code;
    849 		const char *msg;
    850 	} values[] = {
    851 #ifdef EAI_ADDRFAMILY
    852 		{ EAI_ADDRFAMILY, N_("Address family for hostname not supported") },
    853 #endif
    854 		{ EAI_AGAIN, N_("Temporary failure in name resolution") },
    855 		{ EAI_BADFLAGS, N_("Bad value for ai_flags") },
    856 		{ EAI_FAIL, N_("Non-recoverable failure in name resolution") },
    857 		{ EAI_FAMILY, N_("ai_family not supported") },
    858 		{ EAI_MEMORY, N_("Memory allocation failure") },
    859 #ifdef EAI_NODATA
    860 		{ EAI_NODATA, N_("No address associated with hostname") },
    861 #endif
    862 		{ EAI_NONAME, N_("Name or service not known") },
    863 		{ EAI_SERVICE, N_("Servname not supported for ai_socktype") },
    864 		{ EAI_SOCKTYPE, N_("ai_socktype not supported") },
    865 #ifdef EAI_SYSTEM
    866 		{ EAI_SYSTEM, N_("System error") },
    867 #endif
    868 		{ 0, NULL }
    869 	};
    870 
    871 	int i;
    872 
    873 	for ( i = 0; values[i].msg != NULL; i++ ) {
    874 		if ( values[i].code == code ) {
    875 			return (char *) _(values[i].msg);
    876 		}
    877 	}
    878 
    879 	return _("Unknown error");
    880 }
    881 #endif
    882 
    883 /* format a socket address as a string */
    884 
    885 #ifdef HAVE_TCPD
    886 # include <tcpd.h>
    887 # define SOCKADDR_STRING_UNKNOWN	STRING_UNKNOWN
    888 #else /* ! TCP Wrappers */
    889 # define SOCKADDR_STRING_UNKNOWN	"unknown"
    890 #endif /* ! TCP Wrappers */
    891 
    892 void
    893 ldap_pvt_sockaddrstr( Sockaddr *sa, struct berval *addrbuf )
    894 {
    895 	char *addr;
    896 	switch( sa->sa_addr.sa_family ) {
    897 #ifdef LDAP_PF_LOCAL
    898 	case AF_LOCAL:
    899 		addrbuf->bv_len = snprintf( addrbuf->bv_val, addrbuf->bv_len,
    900 			"PATH=%s", sa->sa_un_addr.sun_path );
    901 		break;
    902 #endif
    903 #ifdef LDAP_PF_INET6
    904 	case AF_INET6:
    905 		strcpy(addrbuf->bv_val, "IP=");
    906 		if ( IN6_IS_ADDR_V4MAPPED(&sa->sa_in6_addr.sin6_addr) ) {
    907 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
    908 			addr = (char *)inet_ntop( AF_INET,
    909 			   ((struct in_addr *)&sa->sa_in6_addr.sin6_addr.s6_addr[12]),
    910 			   addrbuf->bv_val+3, addrbuf->bv_len-3 );
    911 #else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
    912 			addr = inet_ntoa( *((struct in_addr *)
    913 					&sa->sa_in6_addr.sin6_addr.s6_addr[12]) );
    914 #endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
    915 			if ( !addr ) addr = SOCKADDR_STRING_UNKNOWN;
    916 			if ( addr != addrbuf->bv_val+3 ) {
    917 				addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "%s:%d", addr,
    918 				 (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + 3;
    919 			} else {
    920 				int len = strlen( addr );
    921 				addrbuf->bv_len = sprintf( addr+len, ":%d",
    922 				 (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + len + 3;
    923 			}
    924 		} else {
    925 			addr = (char *)inet_ntop( AF_INET6,
    926 				      &sa->sa_in6_addr.sin6_addr,
    927 				      addrbuf->bv_val+4, addrbuf->bv_len-4 );
    928 			if ( !addr ) addr = SOCKADDR_STRING_UNKNOWN;
    929 			if ( addr != addrbuf->bv_val+4 ) {
    930 				addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "[%s]:%d", addr,
    931 				 (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + 3;
    932 			} else {
    933 				int len = strlen( addr );
    934 				addrbuf->bv_val[3] = '[';
    935 				addrbuf->bv_len = sprintf( addr+len, "]:%d",
    936 				 (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + len + 4;
    937 			}
    938 		}
    939 		break;
    940 #endif /* LDAP_PF_INET6 */
    941 	case AF_INET:
    942 		strcpy(addrbuf->bv_val, "IP=");
    943 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
    944 		addr = (char *)inet_ntop( AF_INET, &sa->sa_in_addr.sin_addr,
    945 			   addrbuf->bv_val+3, addrbuf->bv_len-3 );
    946 #else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
    947 		addr = inet_ntoa( sa->sa_in_addr.sin_addr );
    948 #endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
    949 		if ( !addr ) addr = SOCKADDR_STRING_UNKNOWN;
    950 		if ( addr != addrbuf->bv_val+3 ) {
    951 			addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "%s:%d", addr,
    952 			 (unsigned) ntohs( sa->sa_in_addr.sin_port ) ) + 3;
    953 		} else {
    954 			int len = strlen( addr );
    955 			addrbuf->bv_len = sprintf( addr+len, ":%d",
    956 			 (unsigned) ntohs( sa->sa_in_addr.sin_port ) ) + len + 3;
    957 		}
    958 		break;
    959 	default:
    960 		addrbuf->bv_val[0] = '\0';
    961 	}
    962 }
    963