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