xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/util-int.c (revision 53d1339bf7f9c7367b35a9e1ebe693f9b047a47b)
1 /*	$NetBSD: util-int.c,v 1.2 2020/08/11 13:15:38 christos Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2020 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.2 2020/08/11 13:15:38 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 #ifdef LDAP_DEVEL
79 	/* to be released with 2.5 */
80 #if !defined( USE_GMTIME_R ) || !defined( USE_LOCALTIME_R )
81 	/* we use the same mutex for gmtime(3) and localtime(3)
82 	 * because implementations may use the same buffer
83 	 * for both functions */
84 	static ldap_pvt_thread_mutex_t ldap_int_gmtime_mutex;
85 #endif
86 #else /* ! LDAP_DEVEL */
87 	ldap_pvt_thread_mutex_t ldap_int_gmtime_mutex;
88 #endif /* ! LDAP_DEVEL */
89 
90 # if defined(HAVE_GETHOSTBYNAME_R) && \
91 	(GETHOSTBYNAME_R_NARGS < 5) || (6 < GETHOSTBYNAME_R_NARGS)
92 	/* Don't know how to handle this version, pretend it's not there */
93 #	undef HAVE_GETHOSTBYNAME_R
94 # endif
95 # if defined(HAVE_GETHOSTBYADDR_R) && \
96 	(GETHOSTBYADDR_R_NARGS < 7) || (8 < GETHOSTBYADDR_R_NARGS)
97 	/* Don't know how to handle this version, pretend it's not there */
98 #	undef HAVE_GETHOSTBYADDR_R
99 # endif
100 #endif /* LDAP_R_COMPILE */
101 
102 char *ldap_pvt_ctime( const time_t *tp, char *buf )
103 {
104 #ifdef USE_CTIME_R
105 # if (CTIME_R_NARGS > 3) || (CTIME_R_NARGS < 2)
106 #	error "CTIME_R_NARGS should be 2 or 3"
107 # elif CTIME_R_NARGS > 2 && defined(CTIME_R_RETURNS_INT)
108 	return( ctime_r(tp,buf,26) < 0 ? 0 : buf );
109 # elif CTIME_R_NARGS > 2
110 	return ctime_r(tp,buf,26);
111 # else
112 	return ctime_r(tp,buf);
113 # endif
114 
115 #else
116 
117 	LDAP_MUTEX_LOCK( &ldap_int_ctime_mutex );
118 	AC_MEMCPY( buf, ctime(tp), 26 );
119 	LDAP_MUTEX_UNLOCK( &ldap_int_ctime_mutex );
120 
121 	return buf;
122 #endif
123 }
124 
125 #if !defined( USE_GMTIME_R ) || !defined( USE_LOCALTIME_R )
126 int
127 ldap_pvt_gmtime_lock( void )
128 {
129 # ifndef LDAP_R_COMPILE
130 	return 0;
131 # else /* LDAP_R_COMPILE */
132 	return ldap_pvt_thread_mutex_lock( &ldap_int_gmtime_mutex );
133 # endif /* LDAP_R_COMPILE */
134 }
135 
136 int
137 ldap_pvt_gmtime_unlock( void )
138 {
139 # ifndef LDAP_R_COMPILE
140 	return 0;
141 # else /* LDAP_R_COMPILE */
142 	return ldap_pvt_thread_mutex_unlock( &ldap_int_gmtime_mutex );
143 # endif /* LDAP_R_COMPILE */
144 }
145 #endif /* !USE_GMTIME_R || !USE_LOCALTIME_R */
146 
147 #ifndef USE_GMTIME_R
148 struct tm *
149 ldap_pvt_gmtime( const time_t *timep, struct tm *result )
150 {
151 	struct tm *tm_ptr;
152 
153 	LDAP_MUTEX_LOCK( &ldap_int_gmtime_mutex );
154 	tm_ptr = gmtime( timep );
155 	if ( tm_ptr == NULL ) {
156 		result = NULL;
157 
158 	} else {
159 		*result = *tm_ptr;
160 	}
161 	LDAP_MUTEX_UNLOCK( &ldap_int_gmtime_mutex );
162 
163 	return result;
164 }
165 #endif /* !USE_GMTIME_R */
166 
167 #ifndef USE_LOCALTIME_R
168 struct tm *
169 ldap_pvt_localtime( const time_t *timep, struct tm *result )
170 {
171 	struct tm *tm_ptr;
172 
173 	LDAP_MUTEX_LOCK( &ldap_int_gmtime_mutex );
174 	tm_ptr = localtime( timep );
175 	if ( tm_ptr == NULL ) {
176 		result = NULL;
177 
178 	} else {
179 		*result = *tm_ptr;
180 	}
181 	LDAP_MUTEX_UNLOCK( &ldap_int_gmtime_mutex );
182 
183 	return result;
184 }
185 #endif /* !USE_LOCALTIME_R */
186 
187 static int _ldap_pvt_gt_subs;
188 
189 #ifdef _WIN32
190 /* Windows SYSTEMTIME only has 10 millisecond resolution, so we
191  * also need to use a high resolution timer to get microseconds.
192  * This is pretty clunky.
193  */
194 static LARGE_INTEGER _ldap_pvt_gt_freq;
195 static LARGE_INTEGER _ldap_pvt_gt_prev;
196 static int _ldap_pvt_gt_offset;
197 
198 #define SEC_TO_UNIX_EPOCH 11644473600LL
199 #define TICKS_PER_SECOND 10000000
200 
201 static int
202 ldap_pvt_gettimeusec(int *sec)
203 {
204 	LARGE_INTEGER count;
205 
206 	QueryPerformanceCounter( &count );
207 
208 	/* It shouldn't ever go backwards, but multiple CPUs might
209 	 * be able to hit in the same tick.
210 	 */
211 	LDAP_MUTEX_LOCK( &ldap_int_gettime_mutex );
212 	/* We assume Windows has at least a vague idea of
213 	 * when a second begins. So we align our microsecond count
214 	 * with the Windows millisecond count using this offset.
215 	 * We retain the submillisecond portion of our own count.
216 	 *
217 	 * Note - this also assumes that the relationship between
218 	 * the PerformanceCounter and SystemTime stays constant;
219 	 * that assumption breaks if the SystemTime is adjusted by
220 	 * an external action.
221 	 */
222 	if ( !_ldap_pvt_gt_freq.QuadPart ) {
223 		LARGE_INTEGER c2;
224 		ULARGE_INTEGER ut;
225 		FILETIME ft0, ft1;
226 		long long t;
227 		int usec;
228 
229 		/* Initialize our offset */
230 		QueryPerformanceFrequency( &_ldap_pvt_gt_freq );
231 
232 		/* Wait for a tick of the system time: 10-15ms */
233 		GetSystemTimeAsFileTime( &ft0 );
234 		do {
235 			GetSystemTimeAsFileTime( &ft1 );
236 		} while ( ft1.dwLowDateTime == ft0.dwLowDateTime );
237 
238 		ut.LowPart = ft1.dwLowDateTime;
239 		ut.HighPart = ft1.dwHighDateTime;
240 		QueryPerformanceCounter( &c2 );
241 
242 		/* get second and fraction portion of counter */
243 		t = c2.QuadPart % (_ldap_pvt_gt_freq.QuadPart*10);
244 
245 		/* convert to microseconds */
246 		t *= 1000000;
247 		usec = t / _ldap_pvt_gt_freq.QuadPart;
248 
249 		ut.QuadPart /= 10;
250 		ut.QuadPart %= 10000000;
251 		_ldap_pvt_gt_offset = usec - ut.QuadPart;
252 		count = c2;
253 	}
254 	if ( count.QuadPart <= _ldap_pvt_gt_prev.QuadPart ) {
255 		_ldap_pvt_gt_subs++;
256 	} else {
257 		_ldap_pvt_gt_subs = 0;
258 		_ldap_pvt_gt_prev = count;
259 	}
260 	LDAP_MUTEX_UNLOCK( &ldap_int_gettime_mutex );
261 
262 	/* convert to microseconds */
263 	count.QuadPart %= _ldap_pvt_gt_freq.QuadPart*10;
264 	count.QuadPart *= 1000000;
265 	count.QuadPart /= _ldap_pvt_gt_freq.QuadPart;
266 	count.QuadPart -= _ldap_pvt_gt_offset;
267 
268 	/* We've extracted the 1s and microseconds.
269 	 * The 1sec digit is used to detect wraparound in microsecnds.
270 	 */
271 	if (count.QuadPart < 0)
272 		count.QuadPart += 10000000;
273 	else if (count.QuadPart >= 10000000)
274 		count.QuadPart -= 10000000;
275 
276 	*sec = count.QuadPart / 1000000;
277 	return count.QuadPart % 1000000;
278 }
279 
280 
281 /* emulate POSIX gettimeofday */
282 int
283 ldap_pvt_gettimeofday( struct timeval *tv, void *unused )
284 {
285 	FILETIME ft;
286 	ULARGE_INTEGER ut;
287 	int sec, sec0;
288 
289 	GetSystemTimeAsFileTime( &ft );
290 	ut.LowPart = ft.dwLowDateTime;
291 	ut.HighPart = ft.dwHighDateTime;
292 
293 	/* convert to usec */
294 	ut.QuadPart /= (TICKS_PER_SECOND / 1000000);
295 
296 	tv->tv_usec = ldap_pvt_gettimeusec(&sec);
297 	tv->tv_sec = ut.QuadPart / 1000000 - SEC_TO_UNIX_EPOCH;
298 
299 	/* check for carry from microseconds */
300 	sec0 = tv->tv_sec % 10;
301 	if (sec0 < sec || (sec0 == 9 && !sec))
302 		tv->tv_sec++;
303 
304 	return 0;
305 }
306 
307 /* return a broken out time, with microseconds
308  */
309 void
310 ldap_pvt_gettime( struct lutil_tm *tm )
311 {
312 	SYSTEMTIME st;
313 	int sec, sec0;
314 	static const char daysPerMonth[] = {
315 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
316 
317 	GetSystemTime( &st );
318 	tm->tm_usec = ldap_pvt_gettimeusec(&sec);
319 	tm->tm_usub = _ldap_pvt_gt_subs;
320 
321 	/* any difference larger than microseconds is
322 	 * already reflected in st
323 	 */
324 	tm->tm_sec = st.wSecond;
325 	tm->tm_min = st.wMinute;
326 	tm->tm_hour = st.wHour;
327 	tm->tm_mday = st.wDay;
328 	tm->tm_mon = st.wMonth - 1;
329 	tm->tm_year = st.wYear - 1900;
330 
331 	/* check for carry from microseconds */
332 	sec0 = tm->tm_sec % 10;
333 	if (sec0 < sec || (sec0 == 9 && !sec)) {
334 		tm->tm_sec++;
335 		/* FIXME: we don't handle leap seconds */
336 		if (tm->tm_sec > 59) {
337 			tm->tm_sec = 0;
338 			tm->tm_min++;
339 			if (tm->tm_min > 59) {
340 				tm->tm_min = 0;
341 				tm->tm_hour++;
342 				if (tm->tm_hour > 23) {
343 					int days = daysPerMonth[tm->tm_mon];
344 					tm->tm_hour = 0;
345 					tm->tm_mday++;
346 
347 					/* if it's February of a leap year,
348 					 * add 1 day to this month
349 					 */
350 					if (tm->tm_mon == 1 &&
351 						((!(st.wYear % 4) && (st.wYear % 100)) ||
352 						!(st.wYear % 400)))
353 						days++;
354 
355 					if (tm->tm_mday > days) {
356 						tm->tm_mday = 1;
357 						tm->tm_mon++;
358 						if (tm->tm_mon > 11) {
359 							tm->tm_mon = 0;
360 							tm->tm_year++;
361 						}
362 					}
363 				}
364 			}
365 		}
366 	}
367 }
368 #else
369 
370 static struct timeval _ldap_pvt_gt_prevTv;
371 
372 void
373 ldap_pvt_gettime( struct lutil_tm *ltm )
374 {
375 	struct timeval tv;
376 
377 	struct tm tm;
378 	time_t t;
379 
380 	gettimeofday( &tv, NULL );
381 	t = tv.tv_sec;
382 
383 	LDAP_MUTEX_LOCK( &ldap_int_gettime_mutex );
384 	if ( tv.tv_sec < _ldap_pvt_gt_prevTv.tv_sec
385 		|| ( tv.tv_sec == _ldap_pvt_gt_prevTv.tv_sec
386 		&& tv.tv_usec <= _ldap_pvt_gt_prevTv.tv_usec )) {
387 		_ldap_pvt_gt_subs++;
388 	} else {
389 		_ldap_pvt_gt_subs = 0;
390 		_ldap_pvt_gt_prevTv = tv;
391 	}
392 	LDAP_MUTEX_UNLOCK( &ldap_int_gettime_mutex );
393 
394 	ltm->tm_usub = _ldap_pvt_gt_subs;
395 
396 	ldap_pvt_gmtime( &t, &tm );
397 
398 	ltm->tm_sec = tm.tm_sec;
399 	ltm->tm_min = tm.tm_min;
400 	ltm->tm_hour = tm.tm_hour;
401 	ltm->tm_mday = tm.tm_mday;
402 	ltm->tm_mon = tm.tm_mon;
403 	ltm->tm_year = tm.tm_year;
404 	ltm->tm_usec = tv.tv_usec;
405 }
406 #endif
407 
408 size_t
409 ldap_pvt_csnstr(char *buf, size_t len, unsigned int replica, unsigned int mod)
410 {
411 	struct lutil_tm tm;
412 	int n;
413 
414 	ldap_pvt_gettime( &tm );
415 
416 	n = snprintf( buf, len,
417 		"%4d%02d%02d%02d%02d%02d.%06dZ#%06x#%03x#%06x",
418 		tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
419 		tm.tm_min, tm.tm_sec, tm.tm_usec, tm.tm_usub, replica, mod );
420 
421 	if( n < 0 ) return 0;
422 	return ( (size_t) n < len ) ? n : 0;
423 }
424 
425 #define BUFSTART (1024-32)
426 #define BUFMAX (32*1024-32)
427 
428 #if defined(LDAP_R_COMPILE)
429 static char *safe_realloc( char **buf, int len );
430 
431 #if !(defined(HAVE_GETHOSTBYNAME_R) && defined(HAVE_GETHOSTBYADDR_R))
432 static int copy_hostent( struct hostent *res,
433 	char **buf, struct hostent * src );
434 #endif
435 #endif
436 
437 int ldap_pvt_gethostbyname_a(
438 	const char *name,
439 	struct hostent *resbuf,
440 	char **buf,
441 	struct hostent **result,
442 	int *herrno_ptr )
443 {
444 #if defined( HAVE_GETHOSTBYNAME_R )
445 
446 # define NEED_SAFE_REALLOC 1
447 	int r=-1;
448 	int buflen=BUFSTART;
449 	*buf = NULL;
450 	for(;buflen<BUFMAX;) {
451 		if (safe_realloc( buf, buflen )==NULL)
452 			return r;
453 
454 #if (GETHOSTBYNAME_R_NARGS < 6)
455 		*result=gethostbyname_r( name, resbuf, *buf, buflen, herrno_ptr );
456 		r = (*result == NULL) ?  -1 : 0;
457 #else
458 		r = gethostbyname_r( name, resbuf, *buf,
459 			buflen, result, herrno_ptr );
460 #endif
461 
462 		Debug( LDAP_DEBUG_TRACE, "ldap_pvt_gethostbyname_a: host=%s, r=%d\n",
463 		       name, r, 0 );
464 
465 #ifdef NETDB_INTERNAL
466 		if ((r<0) &&
467 			(*herrno_ptr==NETDB_INTERNAL) &&
468 			(errno==ERANGE))
469 		{
470 			buflen*=2;
471 			continue;
472 	 	}
473 #endif
474 		return r;
475 	}
476 	return -1;
477 #elif defined( LDAP_R_COMPILE )
478 # define NEED_COPY_HOSTENT
479 	struct hostent *he;
480 	int	retval;
481 	*buf = NULL;
482 
483 	LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
484 
485 	he = gethostbyname( name );
486 
487 	if (he==NULL) {
488 		*herrno_ptr = h_errno;
489 		retval = -1;
490 	} else if (copy_hostent( resbuf, buf, he )<0) {
491 		*herrno_ptr = -1;
492 		retval = -1;
493 	} else {
494 		*result = resbuf;
495 		retval = 0;
496 	}
497 
498 	LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
499 
500 	return retval;
501 #else
502 	*buf = NULL;
503 	*result = gethostbyname( name );
504 
505 	if (*result!=NULL) {
506 		return 0;
507 	}
508 
509 	*herrno_ptr = h_errno;
510 
511 	return -1;
512 #endif
513 }
514 
515 #if !defined( HAVE_GETNAMEINFO ) && !defined( HAVE_HSTRERROR )
516 static const char *
517 hp_strerror( int err )
518 {
519 	switch (err) {
520 	case HOST_NOT_FOUND:	return _("Host not found (authoritative)");
521 	case TRY_AGAIN:			return _("Host not found (server fail?)");
522 	case NO_RECOVERY:		return _("Non-recoverable failure");
523 	case NO_DATA:			return _("No data of requested type");
524 #ifdef NETDB_INTERNAL
525 	case NETDB_INTERNAL:	return STRERROR( errno );
526 #endif
527 	}
528 	return _("Unknown resolver error");
529 }
530 #endif
531 
532 int ldap_pvt_get_hname(
533 	const struct sockaddr *sa,
534 	int len,
535 	char *name,
536 	int namelen,
537 	char **err )
538 {
539 	int rc;
540 #if defined( HAVE_GETNAMEINFO )
541 
542 	LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
543 	rc = getnameinfo( sa, len, name, namelen, NULL, 0, 0 );
544 	LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
545 	if ( rc ) *err = (char *)AC_GAI_STRERROR( rc );
546 	return rc;
547 
548 #else /* !HAVE_GETNAMEINFO */
549 	char *addr;
550 	int alen;
551 	struct hostent *hp = NULL;
552 #ifdef HAVE_GETHOSTBYADDR_R
553 	struct hostent hb;
554 	int buflen=BUFSTART, h_errno;
555 	char *buf=NULL;
556 #endif
557 
558 #ifdef LDAP_PF_INET6
559 	if (sa->sa_family == AF_INET6) {
560 		struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa;
561 		addr = (char *)&sin->sin6_addr;
562 		alen = sizeof(sin->sin6_addr);
563 	} else
564 #endif
565 	if (sa->sa_family == AF_INET) {
566 		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
567 		addr = (char *)&sin->sin_addr;
568 		alen = sizeof(sin->sin_addr);
569 	} else {
570 		rc = NO_RECOVERY;
571 		*err = (char *)HSTRERROR( rc );
572 		return rc;
573 	}
574 #if defined( HAVE_GETHOSTBYADDR_R )
575 	for(;buflen<BUFMAX;) {
576 		if (safe_realloc( &buf, buflen )==NULL) {
577 			*err = (char *)STRERROR( ENOMEM );
578 			return ENOMEM;
579 		}
580 #if (GETHOSTBYADDR_R_NARGS < 8)
581 		hp=gethostbyaddr_r( addr, alen, sa->sa_family,
582 			&hb, buf, buflen, &h_errno );
583 		rc = (hp == NULL) ? -1 : 0;
584 #else
585 		rc = gethostbyaddr_r( addr, alen, sa->sa_family,
586 			&hb, buf, buflen,
587 			&hp, &h_errno );
588 #endif
589 #ifdef NETDB_INTERNAL
590 		if ((rc<0) &&
591 			(h_errno==NETDB_INTERNAL) &&
592 			(errno==ERANGE))
593 		{
594 			buflen*=2;
595 			continue;
596 		}
597 #endif
598 		break;
599 	}
600 	if (hp) {
601 		strncpy( name, hp->h_name, namelen );
602 	} else {
603 		*err = (char *)HSTRERROR( h_errno );
604 	}
605 	LDAP_FREE(buf);
606 #else /* HAVE_GETHOSTBYADDR_R */
607 
608 	LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
609 	hp = gethostbyaddr( addr, alen, sa->sa_family );
610 	if (hp) {
611 		strncpy( name, hp->h_name, namelen );
612 		rc = 0;
613 	} else {
614 		rc = h_errno;
615 		*err = (char *)HSTRERROR( h_errno );
616 	}
617 	LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
618 
619 #endif	/* !HAVE_GETHOSTBYADDR_R */
620 	return rc;
621 #endif	/* !HAVE_GETNAMEINFO */
622 }
623 
624 int ldap_pvt_gethostbyaddr_a(
625 	const char *addr,
626 	int len,
627 	int type,
628 	struct hostent *resbuf,
629 	char **buf,
630 	struct hostent **result,
631 	int *herrno_ptr )
632 {
633 #if defined( HAVE_GETHOSTBYADDR_R )
634 
635 # undef NEED_SAFE_REALLOC
636 # define NEED_SAFE_REALLOC
637 	int r=-1;
638 	int buflen=BUFSTART;
639 	*buf = NULL;
640 	for(;buflen<BUFMAX;) {
641 		if (safe_realloc( buf, buflen )==NULL)
642 			return r;
643 #if (GETHOSTBYADDR_R_NARGS < 8)
644 		*result=gethostbyaddr_r( addr, len, type,
645 			resbuf, *buf, buflen, herrno_ptr );
646 		r = (*result == NULL) ? -1 : 0;
647 #else
648 		r = gethostbyaddr_r( addr, len, type,
649 			resbuf, *buf, buflen,
650 			result, herrno_ptr );
651 #endif
652 
653 #ifdef NETDB_INTERNAL
654 		if ((r<0) &&
655 			(*herrno_ptr==NETDB_INTERNAL) &&
656 			(errno==ERANGE))
657 		{
658 			buflen*=2;
659 			continue;
660 		}
661 #endif
662 		return r;
663 	}
664 	return -1;
665 #elif defined( LDAP_R_COMPILE )
666 # undef NEED_COPY_HOSTENT
667 # define NEED_COPY_HOSTENT
668 	struct hostent *he;
669 	int	retval;
670 	*buf = NULL;
671 
672 	LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
673 	he = gethostbyaddr( addr, len, type );
674 
675 	if (he==NULL) {
676 		*herrno_ptr = h_errno;
677 		retval = -1;
678 	} else if (copy_hostent( resbuf, buf, he )<0) {
679 		*herrno_ptr = -1;
680 		retval = -1;
681 	} else {
682 		*result = resbuf;
683 		retval = 0;
684 	}
685 	LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
686 
687 	return retval;
688 
689 #else /* gethostbyaddr() */
690 	*buf = NULL;
691 	*result = gethostbyaddr( addr, len, type );
692 
693 	if (*result!=NULL) {
694 		return 0;
695 	}
696 	return -1;
697 #endif
698 }
699 /*
700  * ldap_int_utils_init() should be called before any other function.
701  */
702 
703 void ldap_int_utils_init( void )
704 {
705 	static int done=0;
706 	if (done)
707 	  return;
708 	done=1;
709 
710 #ifdef LDAP_R_COMPILE
711 #if !defined( USE_CTIME_R ) && !defined( HAVE_REENTRANT_FUNCTIONS )
712 	ldap_pvt_thread_mutex_init( &ldap_int_ctime_mutex );
713 #endif
714 #if !defined( USE_GMTIME_R ) && !defined( USE_LOCALTIME_R )
715 	ldap_pvt_thread_mutex_init( &ldap_int_gmtime_mutex );
716 #endif
717 	ldap_pvt_thread_mutex_init( &ldap_int_resolv_mutex );
718 
719 	ldap_pvt_thread_mutex_init( &ldap_int_hostname_mutex );
720 
721 	ldap_pvt_thread_mutex_init( &ldap_int_gettime_mutex );
722 
723 #ifdef HAVE_GSSAPI
724 	ldap_pvt_thread_mutex_init( &ldap_int_gssapi_mutex );
725 #endif
726 #endif
727 
728 	/* call other module init functions here... */
729 }
730 
731 #if defined( NEED_COPY_HOSTENT )
732 # undef NEED_SAFE_REALLOC
733 #define NEED_SAFE_REALLOC
734 
735 static char *cpy_aliases(
736 	char ***tgtio,
737 	char *buf,
738 	char **src )
739 {
740 	int len;
741 	char **tgt=*tgtio;
742 	for( ; (*src) ; src++ ) {
743 		len = strlen( *src ) + 1;
744 		AC_MEMCPY( buf, *src, len );
745 		*tgt++=buf;
746 		buf+=len;
747 	}
748 	*tgtio=tgt;
749 	return buf;
750 }
751 
752 static char *cpy_addresses(
753 	char ***tgtio,
754 	char *buf,
755 	char **src,
756 	int len )
757 {
758    	char **tgt=*tgtio;
759 	for( ; (*src) ; src++ ) {
760 		AC_MEMCPY( buf, *src, len );
761 		*tgt++=buf;
762 		buf+=len;
763 	}
764 	*tgtio=tgt;
765 	return buf;
766 }
767 
768 static int copy_hostent(
769 	struct hostent *res,
770 	char **buf,
771 	struct hostent * src )
772 {
773 	char	**p;
774 	char	**tp;
775 	char	*tbuf;
776 	int	name_len;
777 	int	n_alias=0;
778 	int	total_alias_len=0;
779 	int	n_addr=0;
780 	int	total_addr_len=0;
781 	int	total_len;
782 
783 	/* calculate the size needed for the buffer */
784 	name_len = strlen( src->h_name ) + 1;
785 
786 	if( src->h_aliases != NULL ) {
787 		for( p = src->h_aliases; (*p) != NULL; p++ ) {
788 			total_alias_len += strlen( *p ) + 1;
789 			n_alias++;
790 		}
791 	}
792 
793 	if( src->h_addr_list != NULL ) {
794 		for( p = src->h_addr_list; (*p) != NULL; p++ ) {
795 			n_addr++;
796 		}
797 		total_addr_len = n_addr * src->h_length;
798 	}
799 
800 	total_len = (n_alias + n_addr + 2) * sizeof( char * ) +
801 		total_addr_len + total_alias_len + name_len;
802 
803 	if (safe_realloc( buf, total_len )) {
804 		tp = (char **) *buf;
805 		tbuf = *buf + (n_alias + n_addr + 2) * sizeof( char * );
806 		AC_MEMCPY( res, src, sizeof( struct hostent ) );
807 		/* first the name... */
808 		AC_MEMCPY( tbuf, src->h_name, name_len );
809 		res->h_name = tbuf; tbuf+=name_len;
810 		/* now the aliases */
811 		res->h_aliases = tp;
812 		if ( src->h_aliases != NULL ) {
813 			tbuf = cpy_aliases( &tp, tbuf, src->h_aliases );
814 		}
815 		*tp++=NULL;
816 		/* finally the addresses */
817 		res->h_addr_list = tp;
818 		if ( src->h_addr_list != NULL ) {
819 			tbuf = cpy_addresses( &tp, tbuf, src->h_addr_list, src->h_length );
820 		}
821 		*tp++=NULL;
822 		return 0;
823 	}
824 	return -1;
825 }
826 #endif
827 
828 #if defined( NEED_SAFE_REALLOC )
829 static char *safe_realloc( char **buf, int len )
830 {
831 	char *tmpbuf;
832 	tmpbuf = LDAP_REALLOC( *buf, len );
833 	if (tmpbuf) {
834 		*buf=tmpbuf;
835 	}
836 	return tmpbuf;
837 }
838 #endif
839 
840 char * ldap_pvt_get_fqdn( char *name )
841 {
842 	char *fqdn, *ha_buf;
843 	char hostbuf[MAXHOSTNAMELEN+1];
844 	struct hostent *hp, he_buf;
845 	int rc, local_h_errno;
846 
847 	if( name == NULL ) {
848 		if( gethostname( hostbuf, MAXHOSTNAMELEN ) == 0 ) {
849 			hostbuf[MAXHOSTNAMELEN] = '\0';
850 			name = hostbuf;
851 		} else {
852 			name = "localhost";
853 		}
854 	}
855 
856 	rc = ldap_pvt_gethostbyname_a( name,
857 		&he_buf, &ha_buf, &hp, &local_h_errno );
858 
859 	if( rc < 0 || hp == NULL || hp->h_name == NULL ) {
860 		fqdn = LDAP_STRDUP( name );
861 	} else {
862 		fqdn = LDAP_STRDUP( hp->h_name );
863 	}
864 
865 	LDAP_FREE( ha_buf );
866 	return fqdn;
867 }
868 
869 #if ( defined( HAVE_GETADDRINFO ) || defined( HAVE_GETNAMEINFO ) ) \
870 	&& !defined( HAVE_GAI_STRERROR )
871 char *ldap_pvt_gai_strerror (int code) {
872 	static struct {
873 		int code;
874 		const char *msg;
875 	} values[] = {
876 #ifdef EAI_ADDRFAMILY
877 		{ EAI_ADDRFAMILY, N_("Address family for hostname not supported") },
878 #endif
879 		{ EAI_AGAIN, N_("Temporary failure in name resolution") },
880 		{ EAI_BADFLAGS, N_("Bad value for ai_flags") },
881 		{ EAI_FAIL, N_("Non-recoverable failure in name resolution") },
882 		{ EAI_FAMILY, N_("ai_family not supported") },
883 		{ EAI_MEMORY, N_("Memory allocation failure") },
884 #ifdef EAI_NODATA
885 		{ EAI_NODATA, N_("No address associated with hostname") },
886 #endif
887 		{ EAI_NONAME, N_("Name or service not known") },
888 		{ EAI_SERVICE, N_("Servname not supported for ai_socktype") },
889 		{ EAI_SOCKTYPE, N_("ai_socktype not supported") },
890 #ifdef EAI_SYSTEM
891 		{ EAI_SYSTEM, N_("System error") },
892 #endif
893 		{ 0, NULL }
894 	};
895 
896 	int i;
897 
898 	for ( i = 0; values[i].msg != NULL; i++ ) {
899 		if ( values[i].code == code ) {
900 			return (char *) _(values[i].msg);
901 		}
902 	}
903 
904 	return _("Unknown error");
905 }
906 #endif
907