xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/util-int.c (revision ba65fde2d7fefa7d39838fa5fa855e62bd606b5e)
1 /*	$NetBSD: util-int.c,v 1.1.1.3 2010/12/12 15:21:41 adam Exp $	*/
2 
3 /* OpenLDAP: pkg/ldap/libraries/libldap/util-int.c,v 1.57.2.7 2010/04/19 16:53:01 quanah Exp */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2010 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 "portable.h"
30 
31 #include <ac/stdlib.h>
32 
33 #include <ac/errno.h>
34 #include <ac/socket.h>
35 #include <ac/string.h>
36 #include <ac/time.h>
37 #include <ac/unistd.h>
38 
39 #include "ldap-int.h"
40 
41 #ifndef h_errno
42 /* newer systems declare this in <netdb.h> for you, older ones don't.
43  * harmless to declare it again (unless defined by a macro).
44  */
45 extern int h_errno;
46 #endif
47 
48 #ifdef HAVE_HSTRERROR
49 # define HSTRERROR(e)	hstrerror(e)
50 #else
51 # define HSTRERROR(e)	hp_strerror(e)
52 #endif
53 
54 #ifndef LDAP_R_COMPILE
55 # undef HAVE_REENTRANT_FUNCTIONS
56 # undef HAVE_CTIME_R
57 # undef HAVE_GETHOSTBYNAME_R
58 # undef HAVE_GETHOSTBYADDR_R
59 
60 #else
61 # include <ldap_pvt_thread.h>
62   ldap_pvt_thread_mutex_t ldap_int_resolv_mutex;
63 
64 # if (defined( HAVE_CTIME_R ) || defined( HAVE_REENTRANT_FUNCTIONS)) \
65 	 && defined( CTIME_R_NARGS )
66 #   define USE_CTIME_R
67 # else
68 	static ldap_pvt_thread_mutex_t ldap_int_ctime_mutex;
69 # endif
70 
71 /* USE_GMTIME_R and USE_LOCALTIME_R defined in ldap_pvt.h */
72 
73 #ifdef LDAP_DEVEL
74 	/* to be released with 2.5 */
75 #if !defined( USE_GMTIME_R ) || !defined( USE_LOCALTIME_R )
76 	/* we use the same mutex for gmtime(3) and localtime(3)
77 	 * because implementations may use the same buffer
78 	 * for both functions */
79 	static ldap_pvt_thread_mutex_t ldap_int_gmtime_mutex;
80 #endif
81 #else /* ! LDAP_DEVEL */
82 	ldap_pvt_thread_mutex_t ldap_int_gmtime_mutex;
83 #endif /* ! LDAP_DEVEL */
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 # ifdef LDAP_R_COMPILE
113 	ldap_pvt_thread_mutex_lock( &ldap_int_ctime_mutex );
114 # endif
115 
116 	AC_MEMCPY( buf, ctime(tp), 26 );
117 
118 # ifdef LDAP_R_COMPILE
119 	ldap_pvt_thread_mutex_unlock( &ldap_int_ctime_mutex );
120 # endif
121 
122 	return buf;
123 #endif
124 }
125 
126 #if !defined( USE_GMTIME_R ) || !defined( USE_LOCALTIME_R )
127 int
128 ldap_pvt_gmtime_lock( void )
129 {
130 # ifndef LDAP_R_COMPILE
131 	return 0;
132 # else /* LDAP_R_COMPILE */
133 	return ldap_pvt_thread_mutex_lock( &ldap_int_gmtime_mutex );
134 # endif /* LDAP_R_COMPILE */
135 }
136 
137 int
138 ldap_pvt_gmtime_unlock( void )
139 {
140 # ifndef LDAP_R_COMPILE
141 	return 0;
142 # else /* LDAP_R_COMPILE */
143 	return ldap_pvt_thread_mutex_unlock( &ldap_int_gmtime_mutex );
144 # endif /* LDAP_R_COMPILE */
145 }
146 #endif /* !USE_GMTIME_R || !USE_LOCALTIME_R */
147 
148 #ifndef USE_GMTIME_R
149 struct tm *
150 ldap_pvt_gmtime( const time_t *timep, struct tm *result )
151 {
152 	struct tm *tm_ptr;
153 
154 # ifdef LDAP_R_COMPILE
155 	ldap_pvt_thread_mutex_lock( &ldap_int_gmtime_mutex );
156 # endif /* LDAP_R_COMPILE */
157 
158 	tm_ptr = gmtime( timep );
159 	if ( tm_ptr == NULL ) {
160 		result = NULL;
161 
162 	} else {
163 		*result = *tm_ptr;
164 	}
165 
166 # ifdef LDAP_R_COMPILE
167 	ldap_pvt_thread_mutex_unlock( &ldap_int_gmtime_mutex );
168 # endif /* LDAP_R_COMPILE */
169 
170 	return result;
171 }
172 #endif /* !USE_GMTIME_R */
173 
174 #ifndef USE_LOCALTIME_R
175 struct tm *
176 ldap_pvt_localtime( const time_t *timep, struct tm *result )
177 {
178 	struct tm *tm_ptr;
179 
180 # ifdef LDAP_R_COMPILE
181 	ldap_pvt_thread_mutex_lock( &ldap_int_gmtime_mutex );
182 # endif /* LDAP_R_COMPILE */
183 
184 	tm_ptr = localtime( timep );
185 	if ( tm_ptr == NULL ) {
186 		result = NULL;
187 
188 	} else {
189 		*result = *tm_ptr;
190 	}
191 
192 # ifdef LDAP_R_COMPILE
193 	ldap_pvt_thread_mutex_unlock( &ldap_int_gmtime_mutex );
194 # endif /* LDAP_R_COMPILE */
195 
196 	return result;
197 }
198 #endif /* !USE_LOCALTIME_R */
199 
200 /* return a broken out time, with microseconds
201  * Must be mutex-protected.
202  */
203 #ifdef _WIN32
204 /* Windows SYSTEMTIME only has 10 millisecond resolution, so we
205  * also need to use a high resolution timer to get microseconds.
206  * This is pretty clunky.
207  */
208 void
209 ldap_pvt_gettime( struct lutil_tm *tm )
210 {
211 	static LARGE_INTEGER cFreq;
212 	static LARGE_INTEGER prevCount;
213 	static int subs;
214 	static int offset;
215 	LARGE_INTEGER count;
216 	SYSTEMTIME st;
217 
218 	GetSystemTime( &st );
219 	QueryPerformanceCounter( &count );
220 
221 	/* It shouldn't ever go backwards, but multiple CPUs might
222 	 * be able to hit in the same tick.
223 	 */
224 	if ( count.QuadPart <= prevCount.QuadPart ) {
225 		subs++;
226 	} else {
227 		subs = 0;
228 		prevCount = count;
229 	}
230 
231 	/* We assume Windows has at least a vague idea of
232 	 * when a second begins. So we align our microsecond count
233 	 * with the Windows millisecond count using this offset.
234 	 * We retain the submillisecond portion of our own count.
235 	 *
236 	 * Note - this also assumes that the relationship between
237 	 * the PerformanceCouunter and SystemTime stays constant;
238 	 * that assumption breaks if the SystemTime is adjusted by
239 	 * an external action.
240 	 */
241 	if ( !cFreq.QuadPart ) {
242 		long long t;
243 		int usec;
244 		QueryPerformanceFrequency( &cFreq );
245 
246 		/* just get sub-second portion of counter */
247 		t = count.QuadPart % cFreq.QuadPart;
248 
249 		/* convert to microseconds */
250 		t *= 1000000;
251 		usec = t / cFreq.QuadPart;
252 
253 		offset = usec - st.wMilliseconds * 1000;
254 	}
255 
256 	tm->tm_usub = subs;
257 
258 	/* convert to microseconds */
259 	count.QuadPart %= cFreq.QuadPart;
260 	count.QuadPart *= 1000000;
261 	count.QuadPart /= cFreq.QuadPart;
262 	count.QuadPart -= offset;
263 
264 	tm->tm_usec = count.QuadPart % 1000000;
265 	if ( tm->tm_usec < 0 )
266 		tm->tm_usec += 1000000;
267 
268 	/* any difference larger than microseconds is
269 	 * already reflected in st
270 	 */
271 
272 	tm->tm_sec = st.wSecond;
273 	tm->tm_min = st.wMinute;
274 	tm->tm_hour = st.wHour;
275 	tm->tm_mday = st.wDay;
276 	tm->tm_mon = st.wMonth - 1;
277 	tm->tm_year = st.wYear - 1900;
278 }
279 #else
280 void
281 ldap_pvt_gettime( struct lutil_tm *ltm )
282 {
283 	struct timeval tv;
284 	static struct timeval prevTv;
285 	static int subs;
286 
287 	struct tm tm;
288 	time_t t;
289 
290 	gettimeofday( &tv, NULL );
291 	t = tv.tv_sec;
292 
293 	if ( tv.tv_sec < prevTv.tv_sec
294 		|| ( tv.tv_sec == prevTv.tv_sec && tv.tv_usec == prevTv.tv_usec )) {
295 		subs++;
296 	} else {
297 		subs = 0;
298 		prevTv = tv;
299 	}
300 
301 	ltm->tm_usub = subs;
302 
303 	ldap_pvt_gmtime( &t, &tm );
304 
305 	ltm->tm_sec = tm.tm_sec;
306 	ltm->tm_min = tm.tm_min;
307 	ltm->tm_hour = tm.tm_hour;
308 	ltm->tm_mday = tm.tm_mday;
309 	ltm->tm_mon = tm.tm_mon;
310 	ltm->tm_year = tm.tm_year;
311 	ltm->tm_usec = tv.tv_usec;
312 }
313 #endif
314 
315 size_t
316 ldap_pvt_csnstr(char *buf, size_t len, unsigned int replica, unsigned int mod)
317 {
318 	struct lutil_tm tm;
319 	int n;
320 
321 	ldap_pvt_gettime( &tm );
322 
323 	n = snprintf( buf, len,
324 		"%4d%02d%02d%02d%02d%02d.%06dZ#%06x#%03x#%06x",
325 		tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
326 		tm.tm_min, tm.tm_sec, tm.tm_usec, tm.tm_usub, replica, mod );
327 
328 	if( n < 0 ) return 0;
329 	return ( (size_t) n < len ) ? n : 0;
330 }
331 
332 #define BUFSTART (1024-32)
333 #define BUFMAX (32*1024-32)
334 
335 #if defined(LDAP_R_COMPILE)
336 static char *safe_realloc( char **buf, int len );
337 
338 #if !(defined(HAVE_GETHOSTBYNAME_R) && defined(HAVE_GETHOSTBYADDR_R))
339 static int copy_hostent( struct hostent *res,
340 	char **buf, struct hostent * src );
341 #endif
342 #endif
343 
344 int ldap_pvt_gethostbyname_a(
345 	const char *name,
346 	struct hostent *resbuf,
347 	char **buf,
348 	struct hostent **result,
349 	int *herrno_ptr )
350 {
351 #if defined( HAVE_GETHOSTBYNAME_R )
352 
353 # define NEED_SAFE_REALLOC 1
354 	int r=-1;
355 	int buflen=BUFSTART;
356 	*buf = NULL;
357 	for(;buflen<BUFMAX;) {
358 		if (safe_realloc( buf, buflen )==NULL)
359 			return r;
360 
361 #if (GETHOSTBYNAME_R_NARGS < 6)
362 		*result=gethostbyname_r( name, resbuf, *buf, buflen, herrno_ptr );
363 		r = (*result == NULL) ?  -1 : 0;
364 #else
365 		r = gethostbyname_r( name, resbuf, *buf,
366 			buflen, result, herrno_ptr );
367 #endif
368 
369 		Debug( LDAP_DEBUG_TRACE, "ldap_pvt_gethostbyname_a: host=%s, r=%d\n",
370 		       name, r, 0 );
371 
372 #ifdef NETDB_INTERNAL
373 		if ((r<0) &&
374 			(*herrno_ptr==NETDB_INTERNAL) &&
375 			(errno==ERANGE))
376 		{
377 			buflen*=2;
378 			continue;
379 	 	}
380 #endif
381 		return r;
382 	}
383 	return -1;
384 #elif defined( LDAP_R_COMPILE )
385 # define NEED_COPY_HOSTENT
386 	struct hostent *he;
387 	int	retval;
388 	*buf = NULL;
389 
390 	ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
391 
392 	he = gethostbyname( name );
393 
394 	if (he==NULL) {
395 		*herrno_ptr = h_errno;
396 		retval = -1;
397 	} else if (copy_hostent( resbuf, buf, he )<0) {
398 		*herrno_ptr = -1;
399 		retval = -1;
400 	} else {
401 		*result = resbuf;
402 		retval = 0;
403 	}
404 
405 	ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
406 
407 	return retval;
408 #else
409 	*buf = NULL;
410 	*result = gethostbyname( name );
411 
412 	if (*result!=NULL) {
413 		return 0;
414 	}
415 
416 	*herrno_ptr = h_errno;
417 
418 	return -1;
419 #endif
420 }
421 
422 #if !defined( HAVE_GETNAMEINFO ) && !defined( HAVE_HSTRERROR )
423 static const char *
424 hp_strerror( int err )
425 {
426 	switch (err) {
427 	case HOST_NOT_FOUND:	return _("Host not found (authoritative)");
428 	case TRY_AGAIN:			return _("Host not found (server fail?)");
429 	case NO_RECOVERY:		return _("Non-recoverable failure");
430 	case NO_DATA:			return _("No data of requested type");
431 #ifdef NETDB_INTERNAL
432 	case NETDB_INTERNAL:	return STRERROR( errno );
433 #endif
434 	}
435 	return _("Unknown resolver error");
436 }
437 #endif
438 
439 int ldap_pvt_get_hname(
440 	const struct sockaddr *sa,
441 	int len,
442 	char *name,
443 	int namelen,
444 	char **err )
445 {
446 	int rc;
447 #if defined( HAVE_GETNAMEINFO )
448 
449 #if defined( LDAP_R_COMPILE )
450 	ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
451 #endif
452 	rc = getnameinfo( sa, len, name, namelen, NULL, 0, 0 );
453 #if defined( LDAP_R_COMPILE )
454 	ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
455 #endif
456 	if ( rc ) *err = (char *)AC_GAI_STRERROR( rc );
457 	return rc;
458 
459 #else /* !HAVE_GETNAMEINFO */
460 	char *addr;
461 	int alen;
462 	struct hostent *hp = NULL;
463 #ifdef HAVE_GETHOSTBYADDR_R
464 	struct hostent hb;
465 	int buflen=BUFSTART, h_errno;
466 	char *buf=NULL;
467 #endif
468 
469 #ifdef LDAP_PF_INET6
470 	if (sa->sa_family == AF_INET6) {
471 		struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa;
472 		addr = (char *)&sin->sin6_addr;
473 		alen = sizeof(sin->sin6_addr);
474 	} else
475 #endif
476 	if (sa->sa_family == AF_INET) {
477 		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
478 		addr = (char *)&sin->sin_addr;
479 		alen = sizeof(sin->sin_addr);
480 	} else {
481 		rc = NO_RECOVERY;
482 		*err = (char *)HSTRERROR( rc );
483 		return rc;
484 	}
485 #if defined( HAVE_GETHOSTBYADDR_R )
486 	for(;buflen<BUFMAX;) {
487 		if (safe_realloc( &buf, buflen )==NULL) {
488 			*err = (char *)STRERROR( ENOMEM );
489 			return ENOMEM;
490 		}
491 #if (GETHOSTBYADDR_R_NARGS < 8)
492 		hp=gethostbyaddr_r( addr, alen, sa->sa_family,
493 			&hb, buf, buflen, &h_errno );
494 		rc = (hp == NULL) ? -1 : 0;
495 #else
496 		rc = gethostbyaddr_r( addr, alen, sa->sa_family,
497 			&hb, buf, buflen,
498 			&hp, &h_errno );
499 #endif
500 #ifdef NETDB_INTERNAL
501 		if ((rc<0) &&
502 			(h_errno==NETDB_INTERNAL) &&
503 			(errno==ERANGE))
504 		{
505 			buflen*=2;
506 			continue;
507 		}
508 #endif
509 		break;
510 	}
511 	if (hp) {
512 		strncpy( name, hp->h_name, namelen );
513 	} else {
514 		*err = (char *)HSTRERROR( h_errno );
515 	}
516 	LDAP_FREE(buf);
517 #else /* HAVE_GETHOSTBYADDR_R */
518 
519 #if defined( LDAP_R_COMPILE )
520 	ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
521 #endif
522 	hp = gethostbyaddr( addr, alen, sa->sa_family );
523 	if (hp) {
524 		strncpy( name, hp->h_name, namelen );
525 		rc = 0;
526 	} else {
527 		rc = h_errno;
528 		*err = (char *)HSTRERROR( h_errno );
529 	}
530 #if defined( LDAP_R_COMPILE )
531 	ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
532 #endif
533 
534 #endif	/* !HAVE_GETHOSTBYADDR_R */
535 	return rc;
536 #endif	/* !HAVE_GETNAMEINFO */
537 }
538 
539 int ldap_pvt_gethostbyaddr_a(
540 	const char *addr,
541 	int len,
542 	int type,
543 	struct hostent *resbuf,
544 	char **buf,
545 	struct hostent **result,
546 	int *herrno_ptr )
547 {
548 #if defined( HAVE_GETHOSTBYADDR_R )
549 
550 # undef NEED_SAFE_REALLOC
551 # define NEED_SAFE_REALLOC
552 	int r=-1;
553 	int buflen=BUFSTART;
554 	*buf = NULL;
555 	for(;buflen<BUFMAX;) {
556 		if (safe_realloc( buf, buflen )==NULL)
557 			return r;
558 #if (GETHOSTBYADDR_R_NARGS < 8)
559 		*result=gethostbyaddr_r( addr, len, type,
560 			resbuf, *buf, buflen, herrno_ptr );
561 		r = (*result == NULL) ? -1 : 0;
562 #else
563 		r = gethostbyaddr_r( addr, len, type,
564 			resbuf, *buf, buflen,
565 			result, herrno_ptr );
566 #endif
567 
568 #ifdef NETDB_INTERNAL
569 		if ((r<0) &&
570 			(*herrno_ptr==NETDB_INTERNAL) &&
571 			(errno==ERANGE))
572 		{
573 			buflen*=2;
574 			continue;
575 		}
576 #endif
577 		return r;
578 	}
579 	return -1;
580 #elif defined( LDAP_R_COMPILE )
581 # undef NEED_COPY_HOSTENT
582 # define NEED_COPY_HOSTENT
583 	struct hostent *he;
584 	int	retval;
585 	*buf = NULL;
586 
587 	ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex );
588 
589 	he = gethostbyaddr( addr, len, type );
590 
591 	if (he==NULL) {
592 		*herrno_ptr = h_errno;
593 		retval = -1;
594 	} else if (copy_hostent( resbuf, buf, he )<0) {
595 		*herrno_ptr = -1;
596 		retval = -1;
597 	} else {
598 		*result = resbuf;
599 		retval = 0;
600 	}
601 
602 	ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex );
603 
604 	return retval;
605 
606 #else /* gethostbyaddr() */
607 	*buf = NULL;
608 	*result = gethostbyaddr( addr, len, type );
609 
610 	if (*result!=NULL) {
611 		return 0;
612 	}
613 	return -1;
614 #endif
615 }
616 /*
617  * ldap_int_utils_init() should be called before any other function.
618  */
619 
620 void ldap_int_utils_init( void )
621 {
622 	static int done=0;
623 	if (done)
624 	  return;
625 	done=1;
626 
627 #ifdef LDAP_R_COMPILE
628 #if !defined( USE_CTIME_R ) && !defined( HAVE_REENTRANT_FUNCTIONS )
629 	ldap_pvt_thread_mutex_init( &ldap_int_ctime_mutex );
630 #endif
631 #if !defined( USE_GMTIME_R ) && !defined( USE_LOCALTIME_R )
632 	ldap_pvt_thread_mutex_init( &ldap_int_gmtime_mutex );
633 #endif
634 	ldap_pvt_thread_mutex_init( &ldap_int_resolv_mutex );
635 
636 #ifdef HAVE_CYRUS_SASL
637 	ldap_pvt_thread_mutex_init( &ldap_int_sasl_mutex );
638 #endif
639 #ifdef HAVE_GSSAPI
640 	ldap_pvt_thread_mutex_init( &ldap_int_gssapi_mutex );
641 #endif
642 #endif
643 
644 	/* call other module init functions here... */
645 }
646 
647 #if defined( NEED_COPY_HOSTENT )
648 # undef NEED_SAFE_REALLOC
649 #define NEED_SAFE_REALLOC
650 
651 static char *cpy_aliases(
652 	char ***tgtio,
653 	char *buf,
654 	char **src )
655 {
656 	int len;
657 	char **tgt=*tgtio;
658 	for( ; (*src) ; src++ ) {
659 		len = strlen( *src ) + 1;
660 		AC_MEMCPY( buf, *src, len );
661 		*tgt++=buf;
662 		buf+=len;
663 	}
664 	*tgtio=tgt;
665 	return buf;
666 }
667 
668 static char *cpy_addresses(
669 	char ***tgtio,
670 	char *buf,
671 	char **src,
672 	int len )
673 {
674    	char **tgt=*tgtio;
675 	for( ; (*src) ; src++ ) {
676 		AC_MEMCPY( buf, *src, len );
677 		*tgt++=buf;
678 		buf+=len;
679 	}
680 	*tgtio=tgt;
681 	return buf;
682 }
683 
684 static int copy_hostent(
685 	struct hostent *res,
686 	char **buf,
687 	struct hostent * src )
688 {
689 	char	**p;
690 	char	**tp;
691 	char	*tbuf;
692 	int	name_len;
693 	int	n_alias=0;
694 	int	total_alias_len=0;
695 	int	n_addr=0;
696 	int	total_addr_len=0;
697 	int	total_len;
698 
699 	/* calculate the size needed for the buffer */
700 	name_len = strlen( src->h_name ) + 1;
701 
702 	if( src->h_aliases != NULL ) {
703 		for( p = src->h_aliases; (*p) != NULL; p++ ) {
704 			total_alias_len += strlen( *p ) + 1;
705 			n_alias++;
706 		}
707 	}
708 
709 	if( src->h_addr_list != NULL ) {
710 		for( p = src->h_addr_list; (*p) != NULL; p++ ) {
711 			n_addr++;
712 		}
713 		total_addr_len = n_addr * src->h_length;
714 	}
715 
716 	total_len = (n_alias + n_addr + 2) * sizeof( char * ) +
717 		total_addr_len + total_alias_len + name_len;
718 
719 	if (safe_realloc( buf, total_len )) {
720 		tp = (char **) *buf;
721 		tbuf = *buf + (n_alias + n_addr + 2) * sizeof( char * );
722 		AC_MEMCPY( res, src, sizeof( struct hostent ) );
723 		/* first the name... */
724 		AC_MEMCPY( tbuf, src->h_name, name_len );
725 		res->h_name = tbuf; tbuf+=name_len;
726 		/* now the aliases */
727 		res->h_aliases = tp;
728 		if ( src->h_aliases != NULL ) {
729 			tbuf = cpy_aliases( &tp, tbuf, src->h_aliases );
730 		}
731 		*tp++=NULL;
732 		/* finally the addresses */
733 		res->h_addr_list = tp;
734 		if ( src->h_addr_list != NULL ) {
735 			tbuf = cpy_addresses( &tp, tbuf, src->h_addr_list, src->h_length );
736 		}
737 		*tp++=NULL;
738 		return 0;
739 	}
740 	return -1;
741 }
742 #endif
743 
744 #if defined( NEED_SAFE_REALLOC )
745 static char *safe_realloc( char **buf, int len )
746 {
747 	char *tmpbuf;
748 	tmpbuf = LDAP_REALLOC( *buf, len );
749 	if (tmpbuf) {
750 		*buf=tmpbuf;
751 	}
752 	return tmpbuf;
753 }
754 #endif
755 
756 char * ldap_pvt_get_fqdn( char *name )
757 {
758 	char *fqdn, *ha_buf;
759 	char hostbuf[MAXHOSTNAMELEN+1];
760 	struct hostent *hp, he_buf;
761 	int rc, local_h_errno;
762 
763 	if( name == NULL ) {
764 		if( gethostname( hostbuf, MAXHOSTNAMELEN ) == 0 ) {
765 			hostbuf[MAXHOSTNAMELEN] = '\0';
766 			name = hostbuf;
767 		} else {
768 			name = "localhost";
769 		}
770 	}
771 
772 	rc = ldap_pvt_gethostbyname_a( name,
773 		&he_buf, &ha_buf, &hp, &local_h_errno );
774 
775 	if( rc < 0 || hp == NULL || hp->h_name == NULL ) {
776 		fqdn = LDAP_STRDUP( name );
777 	} else {
778 		fqdn = LDAP_STRDUP( hp->h_name );
779 	}
780 
781 	LDAP_FREE( ha_buf );
782 	return fqdn;
783 }
784 
785 #if ( defined( HAVE_GETADDRINFO ) || defined( HAVE_GETNAMEINFO ) ) \
786 	&& !defined( HAVE_GAI_STRERROR )
787 char *ldap_pvt_gai_strerror (int code) {
788 	static struct {
789 		int code;
790 		const char *msg;
791 	} values[] = {
792 #ifdef EAI_ADDRFAMILY
793 		{ EAI_ADDRFAMILY, N_("Address family for hostname not supported") },
794 #endif
795 		{ EAI_AGAIN, N_("Temporary failure in name resolution") },
796 		{ EAI_BADFLAGS, N_("Bad value for ai_flags") },
797 		{ EAI_FAIL, N_("Non-recoverable failure in name resolution") },
798 		{ EAI_FAMILY, N_("ai_family not supported") },
799 		{ EAI_MEMORY, N_("Memory allocation failure") },
800 #ifdef EAI_NODATA
801 		{ EAI_NODATA, N_("No address associated with hostname") },
802 #endif
803 		{ EAI_NONAME, N_("Name or service not known") },
804 		{ EAI_SERVICE, N_("Servname not supported for ai_socktype") },
805 		{ EAI_SOCKTYPE, N_("ai_socktype not supported") },
806 		{ EAI_SYSTEM, N_("System error") },
807 		{ 0, NULL }
808 	};
809 
810 	int i;
811 
812 	for ( i = 0; values[i].msg != NULL; i++ ) {
813 		if ( values[i].code == code ) {
814 			return (char *) _(values[i].msg);
815 		}
816 	}
817 
818 	return _("Unknown error");
819 }
820 #endif
821