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 */
45extern 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
97char *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 )
127int
128ldap_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
137int
138ldap_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
149struct tm *
150ldap_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
175struct tm *
176ldap_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 */
208void
209ldap_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
280void
281ldap_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
315size_t
316ldap_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)
336static char *safe_realloc( char **buf, int len );
337
338#if !(defined(HAVE_GETHOSTBYNAME_R) && defined(HAVE_GETHOSTBYADDR_R))
339static int copy_hostent( struct hostent *res,
340	char **buf, struct hostent * src );
341#endif
342#endif
343
344int 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 )
423static const char *
424hp_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
439int 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
539int 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
620void 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
651static 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
668static 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
684static 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 )
745static 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
756char * 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 )
787char *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