xref: /netbsd-src/external/bsd/openldap/dist/libraries/libldap/util-int.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1*549b59edSchristos /*	$NetBSD: util-int.c,v 1.3 2021/08/14 16:14:56 christos Exp $	*/
24e6df137Slukem 
3d11b170bStron /* $OpenLDAP$ */
42de962bdSlukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
52de962bdSlukem  *
6*549b59edSchristos  * Copyright 1998-2021 The OpenLDAP Foundation.
72de962bdSlukem  * Portions Copyright 1998 A. Hartgers.
82de962bdSlukem  * All rights reserved.
92de962bdSlukem  *
102de962bdSlukem  * Redistribution and use in source and binary forms, with or without
112de962bdSlukem  * modification, are permitted only as authorized by the OpenLDAP
122de962bdSlukem  * Public License.
132de962bdSlukem  *
142de962bdSlukem  * A copy of this license is available in the file LICENSE in the
152de962bdSlukem  * top-level directory of the distribution or, alternatively, at
162de962bdSlukem  * <http://www.OpenLDAP.org/license.html>.
172de962bdSlukem  */
182de962bdSlukem /* ACKNOWLEDGEMENTS:
192de962bdSlukem  * This work was initially developed by Bart Hartgers for inclusion in
202de962bdSlukem  * OpenLDAP Software.
212de962bdSlukem  */
222de962bdSlukem 
232de962bdSlukem /*
242de962bdSlukem  * util-int.c	Various functions to replace missing threadsafe ones.
252de962bdSlukem  *				Without the real *_r funcs, things will
262de962bdSlukem  *				work, but might not be threadsafe.
272de962bdSlukem  */
282de962bdSlukem 
29376af7d7Schristos #include <sys/cdefs.h>
30*549b59edSchristos __RCSID("$NetBSD: util-int.c,v 1.3 2021/08/14 16:14:56 christos Exp $");
31376af7d7Schristos 
322de962bdSlukem #include "portable.h"
332de962bdSlukem 
342de962bdSlukem #include <ac/stdlib.h>
352de962bdSlukem 
362de962bdSlukem #include <ac/errno.h>
372de962bdSlukem #include <ac/socket.h>
382de962bdSlukem #include <ac/string.h>
392de962bdSlukem #include <ac/time.h>
402de962bdSlukem #include <ac/unistd.h>
412de962bdSlukem 
422de962bdSlukem #include "ldap-int.h"
432de962bdSlukem 
442de962bdSlukem #ifndef h_errno
452de962bdSlukem /* newer systems declare this in <netdb.h> for you, older ones don't.
462de962bdSlukem  * harmless to declare it again (unless defined by a macro).
472de962bdSlukem  */
482de962bdSlukem extern int h_errno;
492de962bdSlukem #endif
502de962bdSlukem 
512de962bdSlukem #ifdef HAVE_HSTRERROR
522de962bdSlukem # define HSTRERROR(e)	hstrerror(e)
532de962bdSlukem #else
542de962bdSlukem # define HSTRERROR(e)	hp_strerror(e)
552de962bdSlukem #endif
562de962bdSlukem 
572de962bdSlukem #ifndef LDAP_R_COMPILE
582de962bdSlukem # undef HAVE_REENTRANT_FUNCTIONS
592de962bdSlukem # undef HAVE_CTIME_R
602de962bdSlukem # undef HAVE_GETHOSTBYNAME_R
612de962bdSlukem # undef HAVE_GETHOSTBYADDR_R
622de962bdSlukem 
632de962bdSlukem #else
642de962bdSlukem # include <ldap_pvt_thread.h>
652de962bdSlukem   ldap_pvt_thread_mutex_t ldap_int_resolv_mutex;
66d11b170bStron   ldap_pvt_thread_mutex_t ldap_int_hostname_mutex;
67d11b170bStron   static ldap_pvt_thread_mutex_t ldap_int_gettime_mutex;
682de962bdSlukem 
692de962bdSlukem # if (defined( HAVE_CTIME_R ) || defined( HAVE_REENTRANT_FUNCTIONS)) \
702de962bdSlukem 	 && defined( CTIME_R_NARGS )
712de962bdSlukem #   define USE_CTIME_R
722de962bdSlukem # else
732de962bdSlukem 	static ldap_pvt_thread_mutex_t ldap_int_ctime_mutex;
742de962bdSlukem # endif
752de962bdSlukem 
76ef2f90d3Sadam /* USE_GMTIME_R and USE_LOCALTIME_R defined in ldap_pvt.h */
77ef2f90d3Sadam 
78ef2f90d3Sadam #if !defined( USE_GMTIME_R ) || !defined( USE_LOCALTIME_R )
79ef2f90d3Sadam 	/* we use the same mutex for gmtime(3) and localtime(3)
80ef2f90d3Sadam 	 * because implementations may use the same buffer
81ef2f90d3Sadam 	 * for both functions */
82ef2f90d3Sadam 	static ldap_pvt_thread_mutex_t ldap_int_gmtime_mutex;
83ef2f90d3Sadam #endif
84ef2f90d3Sadam 
852de962bdSlukem # if defined(HAVE_GETHOSTBYNAME_R) && \
862de962bdSlukem 	(GETHOSTBYNAME_R_NARGS < 5) || (6 < GETHOSTBYNAME_R_NARGS)
872de962bdSlukem 	/* Don't know how to handle this version, pretend it's not there */
882de962bdSlukem #	undef HAVE_GETHOSTBYNAME_R
892de962bdSlukem # endif
902de962bdSlukem # if defined(HAVE_GETHOSTBYADDR_R) && \
912de962bdSlukem 	(GETHOSTBYADDR_R_NARGS < 7) || (8 < GETHOSTBYADDR_R_NARGS)
922de962bdSlukem 	/* Don't know how to handle this version, pretend it's not there */
932de962bdSlukem #	undef HAVE_GETHOSTBYADDR_R
942de962bdSlukem # endif
952de962bdSlukem #endif /* LDAP_R_COMPILE */
962de962bdSlukem 
ldap_pvt_ctime(const time_t * tp,char * buf)972de962bdSlukem char *ldap_pvt_ctime( const time_t *tp, char *buf )
982de962bdSlukem {
992de962bdSlukem #ifdef USE_CTIME_R
1002de962bdSlukem # if (CTIME_R_NARGS > 3) || (CTIME_R_NARGS < 2)
1012de962bdSlukem #	error "CTIME_R_NARGS should be 2 or 3"
1022de962bdSlukem # elif CTIME_R_NARGS > 2 && defined(CTIME_R_RETURNS_INT)
1032de962bdSlukem 	return( ctime_r(tp,buf,26) < 0 ? 0 : buf );
1042de962bdSlukem # elif CTIME_R_NARGS > 2
1052de962bdSlukem 	return ctime_r(tp,buf,26);
1062de962bdSlukem # else
1072de962bdSlukem 	return ctime_r(tp,buf);
1082de962bdSlukem # endif
1092de962bdSlukem 
1102de962bdSlukem #else
1112de962bdSlukem 
112d11b170bStron 	LDAP_MUTEX_LOCK( &ldap_int_ctime_mutex );
1132de962bdSlukem 	AC_MEMCPY( buf, ctime(tp), 26 );
114d11b170bStron 	LDAP_MUTEX_UNLOCK( &ldap_int_ctime_mutex );
1152de962bdSlukem 
1162de962bdSlukem 	return buf;
1172de962bdSlukem #endif
1182de962bdSlukem }
1192de962bdSlukem 
120ef2f90d3Sadam #if !defined( USE_GMTIME_R ) || !defined( USE_LOCALTIME_R )
121ef2f90d3Sadam int
ldap_pvt_gmtime_lock(void)122ef2f90d3Sadam ldap_pvt_gmtime_lock( void )
123ef2f90d3Sadam {
124ef2f90d3Sadam # ifndef LDAP_R_COMPILE
125ef2f90d3Sadam 	return 0;
126ef2f90d3Sadam # else /* LDAP_R_COMPILE */
127ef2f90d3Sadam 	return ldap_pvt_thread_mutex_lock( &ldap_int_gmtime_mutex );
128ef2f90d3Sadam # endif /* LDAP_R_COMPILE */
129ef2f90d3Sadam }
130ef2f90d3Sadam 
131ef2f90d3Sadam int
ldap_pvt_gmtime_unlock(void)132ef2f90d3Sadam ldap_pvt_gmtime_unlock( void )
133ef2f90d3Sadam {
134ef2f90d3Sadam # ifndef LDAP_R_COMPILE
135ef2f90d3Sadam 	return 0;
136ef2f90d3Sadam # else /* LDAP_R_COMPILE */
137ef2f90d3Sadam 	return ldap_pvt_thread_mutex_unlock( &ldap_int_gmtime_mutex );
138ef2f90d3Sadam # endif /* LDAP_R_COMPILE */
139ef2f90d3Sadam }
140ef2f90d3Sadam #endif /* !USE_GMTIME_R || !USE_LOCALTIME_R */
141ef2f90d3Sadam 
142ef2f90d3Sadam #ifndef USE_GMTIME_R
143ef2f90d3Sadam struct tm *
ldap_pvt_gmtime(const time_t * timep,struct tm * result)144ef2f90d3Sadam ldap_pvt_gmtime( const time_t *timep, struct tm *result )
145ef2f90d3Sadam {
146ef2f90d3Sadam 	struct tm *tm_ptr;
147ef2f90d3Sadam 
148d11b170bStron 	LDAP_MUTEX_LOCK( &ldap_int_gmtime_mutex );
149ef2f90d3Sadam 	tm_ptr = gmtime( timep );
150ef2f90d3Sadam 	if ( tm_ptr == NULL ) {
151ef2f90d3Sadam 		result = NULL;
152ef2f90d3Sadam 
153ef2f90d3Sadam 	} else {
154ef2f90d3Sadam 		*result = *tm_ptr;
155ef2f90d3Sadam 	}
156d11b170bStron 	LDAP_MUTEX_UNLOCK( &ldap_int_gmtime_mutex );
157ef2f90d3Sadam 
158ef2f90d3Sadam 	return result;
159ef2f90d3Sadam }
160ef2f90d3Sadam #endif /* !USE_GMTIME_R */
161ef2f90d3Sadam 
162ef2f90d3Sadam #ifndef USE_LOCALTIME_R
163ef2f90d3Sadam struct tm *
ldap_pvt_localtime(const time_t * timep,struct tm * result)164ef2f90d3Sadam ldap_pvt_localtime( const time_t *timep, struct tm *result )
165ef2f90d3Sadam {
166ef2f90d3Sadam 	struct tm *tm_ptr;
167ef2f90d3Sadam 
168d11b170bStron 	LDAP_MUTEX_LOCK( &ldap_int_gmtime_mutex );
169ef2f90d3Sadam 	tm_ptr = localtime( timep );
170ef2f90d3Sadam 	if ( tm_ptr == NULL ) {
171ef2f90d3Sadam 		result = NULL;
172ef2f90d3Sadam 
173ef2f90d3Sadam 	} else {
174ef2f90d3Sadam 		*result = *tm_ptr;
175ef2f90d3Sadam 	}
176d11b170bStron 	LDAP_MUTEX_UNLOCK( &ldap_int_gmtime_mutex );
177ef2f90d3Sadam 
178ef2f90d3Sadam 	return result;
179ef2f90d3Sadam }
180ef2f90d3Sadam #endif /* !USE_LOCALTIME_R */
181ef2f90d3Sadam 
182376af7d7Schristos static int _ldap_pvt_gt_subs;
183376af7d7Schristos 
184ef2f90d3Sadam #ifdef _WIN32
185ef2f90d3Sadam /* Windows SYSTEMTIME only has 10 millisecond resolution, so we
186*549b59edSchristos  * also need to use a high resolution timer to get nanoseconds.
187ef2f90d3Sadam  * This is pretty clunky.
188ef2f90d3Sadam  */
189376af7d7Schristos static LARGE_INTEGER _ldap_pvt_gt_freq;
190376af7d7Schristos static LARGE_INTEGER _ldap_pvt_gt_prev;
191376af7d7Schristos static int _ldap_pvt_gt_offset;
192ef2f90d3Sadam 
193376af7d7Schristos #define SEC_TO_UNIX_EPOCH 11644473600LL
194376af7d7Schristos #define TICKS_PER_SECOND 10000000
195*549b59edSchristos #define BILLION	1000000000L
196376af7d7Schristos 
197376af7d7Schristos static int
ldap_pvt_gettimensec(int * sec)198*549b59edSchristos ldap_pvt_gettimensec(int *sec)
199376af7d7Schristos {
200376af7d7Schristos 	LARGE_INTEGER count;
201376af7d7Schristos 
202ef2f90d3Sadam 	QueryPerformanceCounter( &count );
203ef2f90d3Sadam 
204ef2f90d3Sadam 	/* It shouldn't ever go backwards, but multiple CPUs might
205ef2f90d3Sadam 	 * be able to hit in the same tick.
206ef2f90d3Sadam 	 */
207d11b170bStron 	LDAP_MUTEX_LOCK( &ldap_int_gettime_mutex );
208ef2f90d3Sadam 	/* We assume Windows has at least a vague idea of
209*549b59edSchristos 	 * when a second begins. So we align our nanosecond count
210ef2f90d3Sadam 	 * with the Windows millisecond count using this offset.
211ef2f90d3Sadam 	 * We retain the submillisecond portion of our own count.
212ef2f90d3Sadam 	 *
213ef2f90d3Sadam 	 * Note - this also assumes that the relationship between
214376af7d7Schristos 	 * the PerformanceCounter and SystemTime stays constant;
215ef2f90d3Sadam 	 * that assumption breaks if the SystemTime is adjusted by
216ef2f90d3Sadam 	 * an external action.
217ef2f90d3Sadam 	 */
218376af7d7Schristos 	if ( !_ldap_pvt_gt_freq.QuadPart ) {
219376af7d7Schristos 		LARGE_INTEGER c2;
220376af7d7Schristos 		ULARGE_INTEGER ut;
221376af7d7Schristos 		FILETIME ft0, ft1;
222ef2f90d3Sadam 		long long t;
223*549b59edSchristos 		int nsec;
224ef2f90d3Sadam 
225376af7d7Schristos 		/* Initialize our offset */
226376af7d7Schristos 		QueryPerformanceFrequency( &_ldap_pvt_gt_freq );
227376af7d7Schristos 
228376af7d7Schristos 		/* Wait for a tick of the system time: 10-15ms */
229376af7d7Schristos 		GetSystemTimeAsFileTime( &ft0 );
230376af7d7Schristos 		do {
231376af7d7Schristos 			GetSystemTimeAsFileTime( &ft1 );
232376af7d7Schristos 		} while ( ft1.dwLowDateTime == ft0.dwLowDateTime );
233376af7d7Schristos 
234376af7d7Schristos 		ut.LowPart = ft1.dwLowDateTime;
235376af7d7Schristos 		ut.HighPart = ft1.dwHighDateTime;
236376af7d7Schristos 		QueryPerformanceCounter( &c2 );
237376af7d7Schristos 
238376af7d7Schristos 		/* get second and fraction portion of counter */
239376af7d7Schristos 		t = c2.QuadPart % (_ldap_pvt_gt_freq.QuadPart*10);
240ef2f90d3Sadam 
241*549b59edSchristos 		/* convert to nanoseconds */
242*549b59edSchristos 		t *= BILLION;
243*549b59edSchristos 		nsec = t / _ldap_pvt_gt_freq.QuadPart;
244ef2f90d3Sadam 
245376af7d7Schristos 		ut.QuadPart /= 10;
246*549b59edSchristos 		ut.QuadPart %= (10 * BILLION);
247*549b59edSchristos 		_ldap_pvt_gt_offset = nsec - ut.QuadPart;
248376af7d7Schristos 		count = c2;
249ef2f90d3Sadam 	}
250376af7d7Schristos 	if ( count.QuadPart <= _ldap_pvt_gt_prev.QuadPart ) {
251376af7d7Schristos 		_ldap_pvt_gt_subs++;
252376af7d7Schristos 	} else {
253376af7d7Schristos 		_ldap_pvt_gt_subs = 0;
254376af7d7Schristos 		_ldap_pvt_gt_prev = count;
255376af7d7Schristos 	}
256376af7d7Schristos 	LDAP_MUTEX_UNLOCK( &ldap_int_gettime_mutex );
257ef2f90d3Sadam 
258*549b59edSchristos 	/* convert to nanoseconds */
259376af7d7Schristos 	count.QuadPart %= _ldap_pvt_gt_freq.QuadPart*10;
260*549b59edSchristos 	count.QuadPart *= BILLION;
261376af7d7Schristos 	count.QuadPart /= _ldap_pvt_gt_freq.QuadPart;
262376af7d7Schristos 	count.QuadPart -= _ldap_pvt_gt_offset;
263ef2f90d3Sadam 
264*549b59edSchristos 	/* We've extracted the 1s and nanoseconds.
265*549b59edSchristos 	 * The 1sec digit is used to detect wraparound in nanosecnds.
266376af7d7Schristos 	 */
267376af7d7Schristos 	if (count.QuadPart < 0)
268*549b59edSchristos 		count.QuadPart += (10 * BILLION);
269*549b59edSchristos 	else if (count.QuadPart >= (10 * BILLION))
270*549b59edSchristos 		count.QuadPart -= (10 * BILLION);
271376af7d7Schristos 
272*549b59edSchristos 	*sec = count.QuadPart / BILLION;
273*549b59edSchristos 	return count.QuadPart % BILLION;
274376af7d7Schristos }
275376af7d7Schristos 
276376af7d7Schristos 
277*549b59edSchristos /* emulate POSIX clock_gettime */
278376af7d7Schristos int
ldap_pvt_clock_gettime(int clk_id,struct timespec * tv)279*549b59edSchristos ldap_pvt_clock_gettime( int clk_id, struct timespec *tv )
280376af7d7Schristos {
281376af7d7Schristos 	FILETIME ft;
282376af7d7Schristos 	ULARGE_INTEGER ut;
283376af7d7Schristos 	int sec, sec0;
284376af7d7Schristos 
285376af7d7Schristos 	GetSystemTimeAsFileTime( &ft );
286376af7d7Schristos 	ut.LowPart = ft.dwLowDateTime;
287376af7d7Schristos 	ut.HighPart = ft.dwHighDateTime;
288376af7d7Schristos 
289*549b59edSchristos 	/* convert to sec */
290*549b59edSchristos 	ut.QuadPart /= TICKS_PER_SECOND;
291376af7d7Schristos 
292*549b59edSchristos 	tv->tv_nsec = ldap_pvt_gettimensec(&sec);
293*549b59edSchristos 	tv->tv_sec = ut.QuadPart - SEC_TO_UNIX_EPOCH;
294376af7d7Schristos 
295376af7d7Schristos 	/* check for carry from microseconds */
296376af7d7Schristos 	sec0 = tv->tv_sec % 10;
297376af7d7Schristos 	if (sec0 < sec || (sec0 == 9 && !sec))
298376af7d7Schristos 		tv->tv_sec++;
299376af7d7Schristos 
300376af7d7Schristos 	return 0;
301376af7d7Schristos }
302376af7d7Schristos 
303*549b59edSchristos /* emulate POSIX gettimeofday */
304*549b59edSchristos int
ldap_pvt_gettimeofday(struct timeval * tv,void * unused)305*549b59edSchristos ldap_pvt_gettimeofday( struct timeval *tv, void *unused )
306*549b59edSchristos {
307*549b59edSchristos 	struct timespec ts;
308*549b59edSchristos 	ldap_pvt_clock_gettime( 0, &ts );
309*549b59edSchristos 	tv->tv_sec = ts.tv_sec;
310*549b59edSchristos 	tv->tv_usec = ts.tv_nsec / 1000;
311*549b59edSchristos 	return 0;
312*549b59edSchristos }
313*549b59edSchristos 
314*549b59edSchristos 
315*549b59edSchristos /* return a broken out time, with nanoseconds
316376af7d7Schristos  */
317376af7d7Schristos void
ldap_pvt_gettime(struct lutil_tm * tm)318376af7d7Schristos ldap_pvt_gettime( struct lutil_tm *tm )
319376af7d7Schristos {
320376af7d7Schristos 	SYSTEMTIME st;
321376af7d7Schristos 	int sec, sec0;
322376af7d7Schristos 	static const char daysPerMonth[] = {
323376af7d7Schristos 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
324376af7d7Schristos 
325376af7d7Schristos 	GetSystemTime( &st );
326*549b59edSchristos 	tm->tm_nsec = ldap_pvt_gettimensec(&sec);
327376af7d7Schristos 	tm->tm_usub = _ldap_pvt_gt_subs;
328ef2f90d3Sadam 
329*549b59edSchristos 	/* any difference larger than nanoseconds is
330ef2f90d3Sadam 	 * already reflected in st
331ef2f90d3Sadam 	 */
332ef2f90d3Sadam 	tm->tm_sec = st.wSecond;
333ef2f90d3Sadam 	tm->tm_min = st.wMinute;
334ef2f90d3Sadam 	tm->tm_hour = st.wHour;
335ef2f90d3Sadam 	tm->tm_mday = st.wDay;
336ef2f90d3Sadam 	tm->tm_mon = st.wMonth - 1;
337ef2f90d3Sadam 	tm->tm_year = st.wYear - 1900;
338376af7d7Schristos 
339*549b59edSchristos 	/* check for carry from nanoseconds */
340376af7d7Schristos 	sec0 = tm->tm_sec % 10;
341376af7d7Schristos 	if (sec0 < sec || (sec0 == 9 && !sec)) {
342376af7d7Schristos 		tm->tm_sec++;
343376af7d7Schristos 		/* FIXME: we don't handle leap seconds */
344376af7d7Schristos 		if (tm->tm_sec > 59) {
345376af7d7Schristos 			tm->tm_sec = 0;
346376af7d7Schristos 			tm->tm_min++;
347376af7d7Schristos 			if (tm->tm_min > 59) {
348376af7d7Schristos 				tm->tm_min = 0;
349376af7d7Schristos 				tm->tm_hour++;
350376af7d7Schristos 				if (tm->tm_hour > 23) {
351376af7d7Schristos 					int days = daysPerMonth[tm->tm_mon];
352376af7d7Schristos 					tm->tm_hour = 0;
353376af7d7Schristos 					tm->tm_mday++;
354376af7d7Schristos 
355376af7d7Schristos 					/* if it's February of a leap year,
356376af7d7Schristos 					 * add 1 day to this month
357376af7d7Schristos 					 */
358376af7d7Schristos 					if (tm->tm_mon == 1 &&
359376af7d7Schristos 						((!(st.wYear % 4) && (st.wYear % 100)) ||
360376af7d7Schristos 						!(st.wYear % 400)))
361376af7d7Schristos 						days++;
362376af7d7Schristos 
363376af7d7Schristos 					if (tm->tm_mday > days) {
364376af7d7Schristos 						tm->tm_mday = 1;
365376af7d7Schristos 						tm->tm_mon++;
366376af7d7Schristos 						if (tm->tm_mon > 11) {
367376af7d7Schristos 							tm->tm_mon = 0;
368376af7d7Schristos 							tm->tm_year++;
369376af7d7Schristos 						}
370376af7d7Schristos 					}
371376af7d7Schristos 				}
372376af7d7Schristos 			}
373376af7d7Schristos 		}
374376af7d7Schristos 	}
375ef2f90d3Sadam }
376ef2f90d3Sadam #else
377376af7d7Schristos 
378*549b59edSchristos #ifdef HAVE_CLOCK_GETTIME
379*549b59edSchristos static struct timespec _ldap_pvt_gt_prevTv;
380*549b59edSchristos #else
381376af7d7Schristos static struct timeval _ldap_pvt_gt_prevTv;
382*549b59edSchristos #endif
383376af7d7Schristos 
384ef2f90d3Sadam void
ldap_pvt_gettime(struct lutil_tm * ltm)385ef2f90d3Sadam ldap_pvt_gettime( struct lutil_tm *ltm )
386ef2f90d3Sadam {
387ef2f90d3Sadam 	struct tm tm;
388ef2f90d3Sadam 	time_t t;
389*549b59edSchristos #ifdef HAVE_CLOCK_GETTIME
390*549b59edSchristos #define	FRAC	tv_nsec
391*549b59edSchristos #define	NSECS(x)	x
392*549b59edSchristos 	struct timespec tv;
393*549b59edSchristos 
394*549b59edSchristos 	clock_gettime( CLOCK_REALTIME, &tv );
395*549b59edSchristos #else
396*549b59edSchristos #define	FRAC	tv_usec
397*549b59edSchristos #define	NSECS(x)	x * 1000
398*549b59edSchristos 	struct timeval tv;
399ef2f90d3Sadam 
400ef2f90d3Sadam 	gettimeofday( &tv, NULL );
401*549b59edSchristos #endif
402ef2f90d3Sadam 	t = tv.tv_sec;
403ef2f90d3Sadam 
404d11b170bStron 	LDAP_MUTEX_LOCK( &ldap_int_gettime_mutex );
405376af7d7Schristos 	if ( tv.tv_sec < _ldap_pvt_gt_prevTv.tv_sec
406376af7d7Schristos 		|| ( tv.tv_sec == _ldap_pvt_gt_prevTv.tv_sec
407*549b59edSchristos 		&& tv.FRAC <= _ldap_pvt_gt_prevTv.FRAC )) {
408376af7d7Schristos 		_ldap_pvt_gt_subs++;
409ef2f90d3Sadam 	} else {
410376af7d7Schristos 		_ldap_pvt_gt_subs = 0;
411376af7d7Schristos 		_ldap_pvt_gt_prevTv = tv;
412ef2f90d3Sadam 	}
413d11b170bStron 	LDAP_MUTEX_UNLOCK( &ldap_int_gettime_mutex );
414ef2f90d3Sadam 
415376af7d7Schristos 	ltm->tm_usub = _ldap_pvt_gt_subs;
416ef2f90d3Sadam 
417ef2f90d3Sadam 	ldap_pvt_gmtime( &t, &tm );
418ef2f90d3Sadam 
419ef2f90d3Sadam 	ltm->tm_sec = tm.tm_sec;
420ef2f90d3Sadam 	ltm->tm_min = tm.tm_min;
421ef2f90d3Sadam 	ltm->tm_hour = tm.tm_hour;
422ef2f90d3Sadam 	ltm->tm_mday = tm.tm_mday;
423ef2f90d3Sadam 	ltm->tm_mon = tm.tm_mon;
424ef2f90d3Sadam 	ltm->tm_year = tm.tm_year;
425*549b59edSchristos 	ltm->tm_nsec = NSECS(tv.FRAC);
426ef2f90d3Sadam }
427ef2f90d3Sadam #endif
428ef2f90d3Sadam 
429ef2f90d3Sadam size_t
ldap_pvt_csnstr(char * buf,size_t len,unsigned int replica,unsigned int mod)430ef2f90d3Sadam ldap_pvt_csnstr(char *buf, size_t len, unsigned int replica, unsigned int mod)
431ef2f90d3Sadam {
432ef2f90d3Sadam 	struct lutil_tm tm;
433ef2f90d3Sadam 	int n;
434ef2f90d3Sadam 
435ef2f90d3Sadam 	ldap_pvt_gettime( &tm );
436ef2f90d3Sadam 
437ef2f90d3Sadam 	n = snprintf( buf, len,
438ef2f90d3Sadam 		"%4d%02d%02d%02d%02d%02d.%06dZ#%06x#%03x#%06x",
439ef2f90d3Sadam 		tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
440*549b59edSchristos 		tm.tm_min, tm.tm_sec, tm.tm_nsec / 1000, tm.tm_usub, replica, mod );
441ef2f90d3Sadam 
442ef2f90d3Sadam 	if( n < 0 ) return 0;
443ef2f90d3Sadam 	return ( (size_t) n < len ) ? n : 0;
444ef2f90d3Sadam }
445ef2f90d3Sadam 
4462de962bdSlukem #define BUFSTART (1024-32)
4472de962bdSlukem #define BUFMAX (32*1024-32)
4482de962bdSlukem 
4492de962bdSlukem #if defined(LDAP_R_COMPILE)
4502de962bdSlukem static char *safe_realloc( char **buf, int len );
4512de962bdSlukem 
4522de962bdSlukem #if !(defined(HAVE_GETHOSTBYNAME_R) && defined(HAVE_GETHOSTBYADDR_R))
4532de962bdSlukem static int copy_hostent( struct hostent *res,
4542de962bdSlukem 	char **buf, struct hostent * src );
4552de962bdSlukem #endif
4562de962bdSlukem #endif
4572de962bdSlukem 
ldap_pvt_gethostbyname_a(const char * name,struct hostent * resbuf,char ** buf,struct hostent ** result,int * herrno_ptr)4582de962bdSlukem int ldap_pvt_gethostbyname_a(
4592de962bdSlukem 	const char *name,
4602de962bdSlukem 	struct hostent *resbuf,
4612de962bdSlukem 	char **buf,
4622de962bdSlukem 	struct hostent **result,
4632de962bdSlukem 	int *herrno_ptr )
4642de962bdSlukem {
4652de962bdSlukem #if defined( HAVE_GETHOSTBYNAME_R )
4662de962bdSlukem 
4672de962bdSlukem # define NEED_SAFE_REALLOC 1
4682de962bdSlukem 	int r=-1;
4692de962bdSlukem 	int buflen=BUFSTART;
4702de962bdSlukem 	*buf = NULL;
4712de962bdSlukem 	for(;buflen<BUFMAX;) {
4722de962bdSlukem 		if (safe_realloc( buf, buflen )==NULL)
4732de962bdSlukem 			return r;
4742de962bdSlukem 
4752de962bdSlukem #if (GETHOSTBYNAME_R_NARGS < 6)
4762de962bdSlukem 		*result=gethostbyname_r( name, resbuf, *buf, buflen, herrno_ptr );
4772de962bdSlukem 		r = (*result == NULL) ?  -1 : 0;
4782de962bdSlukem #else
479*549b59edSchristos 		while((r = gethostbyname_r( name, resbuf, *buf, buflen, result, herrno_ptr )) == ERANGE) {
480*549b59edSchristos 			/* Increase the buffer */
481*549b59edSchristos 			buflen*=2;
482*549b59edSchristos 			if (safe_realloc(buf, buflen) == NULL)
483*549b59edSchristos 				return -1;
484*549b59edSchristos 		}
4852de962bdSlukem #endif
4862de962bdSlukem 
487*549b59edSchristos 		Debug2( LDAP_DEBUG_TRACE, "ldap_pvt_gethostbyname_a: host=%s, r=%d\n",
488*549b59edSchristos 		       name, r );
4892de962bdSlukem 
4902de962bdSlukem #ifdef NETDB_INTERNAL
4912de962bdSlukem 		if ((r<0) &&
4922de962bdSlukem 			(*herrno_ptr==NETDB_INTERNAL) &&
4932de962bdSlukem 			(errno==ERANGE))
4942de962bdSlukem 		{
4952de962bdSlukem 			buflen*=2;
4962de962bdSlukem 			continue;
4972de962bdSlukem 	 	}
4982de962bdSlukem #endif
4992de962bdSlukem 		return r;
5002de962bdSlukem 	}
5012de962bdSlukem 	return -1;
5022de962bdSlukem #elif defined( LDAP_R_COMPILE )
5032de962bdSlukem # define NEED_COPY_HOSTENT
5042de962bdSlukem 	struct hostent *he;
5052de962bdSlukem 	int	retval;
5062de962bdSlukem 	*buf = NULL;
5072de962bdSlukem 
508d11b170bStron 	LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
5092de962bdSlukem 
5102de962bdSlukem 	he = gethostbyname( name );
5112de962bdSlukem 
5122de962bdSlukem 	if (he==NULL) {
5132de962bdSlukem 		*herrno_ptr = h_errno;
5142de962bdSlukem 		retval = -1;
5152de962bdSlukem 	} else if (copy_hostent( resbuf, buf, he )<0) {
5162de962bdSlukem 		*herrno_ptr = -1;
5172de962bdSlukem 		retval = -1;
5182de962bdSlukem 	} else {
5192de962bdSlukem 		*result = resbuf;
5202de962bdSlukem 		retval = 0;
5212de962bdSlukem 	}
5222de962bdSlukem 
523d11b170bStron 	LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
5242de962bdSlukem 
5252de962bdSlukem 	return retval;
5262de962bdSlukem #else
5272de962bdSlukem 	*buf = NULL;
5282de962bdSlukem 	*result = gethostbyname( name );
5292de962bdSlukem 
5302de962bdSlukem 	if (*result!=NULL) {
5312de962bdSlukem 		return 0;
5322de962bdSlukem 	}
5332de962bdSlukem 
5342de962bdSlukem 	*herrno_ptr = h_errno;
5352de962bdSlukem 
5362de962bdSlukem 	return -1;
5372de962bdSlukem #endif
5382de962bdSlukem }
5392de962bdSlukem 
5402de962bdSlukem #if !defined( HAVE_GETNAMEINFO ) && !defined( HAVE_HSTRERROR )
5412de962bdSlukem static const char *
hp_strerror(int err)5422de962bdSlukem hp_strerror( int err )
5432de962bdSlukem {
5442de962bdSlukem 	switch (err) {
5452de962bdSlukem 	case HOST_NOT_FOUND:	return _("Host not found (authoritative)");
5462de962bdSlukem 	case TRY_AGAIN:			return _("Host not found (server fail?)");
5472de962bdSlukem 	case NO_RECOVERY:		return _("Non-recoverable failure");
5482de962bdSlukem 	case NO_DATA:			return _("No data of requested type");
5492de962bdSlukem #ifdef NETDB_INTERNAL
5502de962bdSlukem 	case NETDB_INTERNAL:	return STRERROR( errno );
5512de962bdSlukem #endif
5522de962bdSlukem 	}
5532de962bdSlukem 	return _("Unknown resolver error");
5542de962bdSlukem }
5552de962bdSlukem #endif
5562de962bdSlukem 
ldap_pvt_get_hname(const struct sockaddr * sa,int len,char * name,int namelen,char ** err)5572de962bdSlukem int ldap_pvt_get_hname(
5582de962bdSlukem 	const struct sockaddr *sa,
5592de962bdSlukem 	int len,
5602de962bdSlukem 	char *name,
5612de962bdSlukem 	int namelen,
5622de962bdSlukem 	char **err )
5632de962bdSlukem {
5642de962bdSlukem 	int rc;
5652de962bdSlukem #if defined( HAVE_GETNAMEINFO )
5662de962bdSlukem 
567d11b170bStron 	LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
5682de962bdSlukem 	rc = getnameinfo( sa, len, name, namelen, NULL, 0, 0 );
569d11b170bStron 	LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
5702de962bdSlukem 	if ( rc ) *err = (char *)AC_GAI_STRERROR( rc );
5712de962bdSlukem 	return rc;
5722de962bdSlukem 
5732de962bdSlukem #else /* !HAVE_GETNAMEINFO */
5742de962bdSlukem 	char *addr;
5752de962bdSlukem 	int alen;
5762de962bdSlukem 	struct hostent *hp = NULL;
5772de962bdSlukem #ifdef HAVE_GETHOSTBYADDR_R
5782de962bdSlukem 	struct hostent hb;
5792de962bdSlukem 	int buflen=BUFSTART, h_errno;
5802de962bdSlukem 	char *buf=NULL;
5812de962bdSlukem #endif
5822de962bdSlukem 
5832de962bdSlukem #ifdef LDAP_PF_INET6
5842de962bdSlukem 	if (sa->sa_family == AF_INET6) {
5852de962bdSlukem 		struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa;
5862de962bdSlukem 		addr = (char *)&sin->sin6_addr;
5872de962bdSlukem 		alen = sizeof(sin->sin6_addr);
5882de962bdSlukem 	} else
5892de962bdSlukem #endif
5902de962bdSlukem 	if (sa->sa_family == AF_INET) {
5912de962bdSlukem 		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
5922de962bdSlukem 		addr = (char *)&sin->sin_addr;
5932de962bdSlukem 		alen = sizeof(sin->sin_addr);
5942de962bdSlukem 	} else {
5952de962bdSlukem 		rc = NO_RECOVERY;
5962de962bdSlukem 		*err = (char *)HSTRERROR( rc );
5972de962bdSlukem 		return rc;
5982de962bdSlukem 	}
5992de962bdSlukem #if defined( HAVE_GETHOSTBYADDR_R )
6002de962bdSlukem 	for(;buflen<BUFMAX;) {
6012de962bdSlukem 		if (safe_realloc( &buf, buflen )==NULL) {
6022de962bdSlukem 			*err = (char *)STRERROR( ENOMEM );
6032de962bdSlukem 			return ENOMEM;
6042de962bdSlukem 		}
6052de962bdSlukem #if (GETHOSTBYADDR_R_NARGS < 8)
6062de962bdSlukem 		hp=gethostbyaddr_r( addr, alen, sa->sa_family,
6072de962bdSlukem 			&hb, buf, buflen, &h_errno );
6082de962bdSlukem 		rc = (hp == NULL) ? -1 : 0;
6092de962bdSlukem #else
6102de962bdSlukem 		rc = gethostbyaddr_r( addr, alen, sa->sa_family,
6112de962bdSlukem 			&hb, buf, buflen,
6122de962bdSlukem 			&hp, &h_errno );
6132de962bdSlukem #endif
6142de962bdSlukem #ifdef NETDB_INTERNAL
6152de962bdSlukem 		if ((rc<0) &&
6162de962bdSlukem 			(h_errno==NETDB_INTERNAL) &&
6172de962bdSlukem 			(errno==ERANGE))
6182de962bdSlukem 		{
6192de962bdSlukem 			buflen*=2;
6202de962bdSlukem 			continue;
6212de962bdSlukem 		}
6222de962bdSlukem #endif
6232de962bdSlukem 		break;
6242de962bdSlukem 	}
6252de962bdSlukem 	if (hp) {
6262de962bdSlukem 		strncpy( name, hp->h_name, namelen );
6272de962bdSlukem 	} else {
6282de962bdSlukem 		*err = (char *)HSTRERROR( h_errno );
6292de962bdSlukem 	}
6302de962bdSlukem 	LDAP_FREE(buf);
6312de962bdSlukem #else /* HAVE_GETHOSTBYADDR_R */
6322de962bdSlukem 
633d11b170bStron 	LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
6342de962bdSlukem 	hp = gethostbyaddr( addr, alen, sa->sa_family );
6352de962bdSlukem 	if (hp) {
6362de962bdSlukem 		strncpy( name, hp->h_name, namelen );
6372de962bdSlukem 		rc = 0;
6382de962bdSlukem 	} else {
6392de962bdSlukem 		rc = h_errno;
6402de962bdSlukem 		*err = (char *)HSTRERROR( h_errno );
6412de962bdSlukem 	}
642d11b170bStron 	LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
6432de962bdSlukem 
6442de962bdSlukem #endif	/* !HAVE_GETHOSTBYADDR_R */
6452de962bdSlukem 	return rc;
6462de962bdSlukem #endif	/* !HAVE_GETNAMEINFO */
6472de962bdSlukem }
6482de962bdSlukem 
ldap_pvt_gethostbyaddr_a(const char * addr,int len,int type,struct hostent * resbuf,char ** buf,struct hostent ** result,int * herrno_ptr)6492de962bdSlukem int ldap_pvt_gethostbyaddr_a(
6502de962bdSlukem 	const char *addr,
6512de962bdSlukem 	int len,
6522de962bdSlukem 	int type,
6532de962bdSlukem 	struct hostent *resbuf,
6542de962bdSlukem 	char **buf,
6552de962bdSlukem 	struct hostent **result,
6562de962bdSlukem 	int *herrno_ptr )
6572de962bdSlukem {
6582de962bdSlukem #if defined( HAVE_GETHOSTBYADDR_R )
6592de962bdSlukem 
6602de962bdSlukem # undef NEED_SAFE_REALLOC
6612de962bdSlukem # define NEED_SAFE_REALLOC
6622de962bdSlukem 	int r=-1;
6632de962bdSlukem 	int buflen=BUFSTART;
6642de962bdSlukem 	*buf = NULL;
6652de962bdSlukem 	for(;buflen<BUFMAX;) {
6662de962bdSlukem 		if (safe_realloc( buf, buflen )==NULL)
6672de962bdSlukem 			return r;
6682de962bdSlukem #if (GETHOSTBYADDR_R_NARGS < 8)
6692de962bdSlukem 		*result=gethostbyaddr_r( addr, len, type,
6702de962bdSlukem 			resbuf, *buf, buflen, herrno_ptr );
6712de962bdSlukem 		r = (*result == NULL) ? -1 : 0;
6722de962bdSlukem #else
6732de962bdSlukem 		r = gethostbyaddr_r( addr, len, type,
6742de962bdSlukem 			resbuf, *buf, buflen,
6752de962bdSlukem 			result, herrno_ptr );
6762de962bdSlukem #endif
6772de962bdSlukem 
6782de962bdSlukem #ifdef NETDB_INTERNAL
6792de962bdSlukem 		if ((r<0) &&
6802de962bdSlukem 			(*herrno_ptr==NETDB_INTERNAL) &&
6812de962bdSlukem 			(errno==ERANGE))
6822de962bdSlukem 		{
6832de962bdSlukem 			buflen*=2;
6842de962bdSlukem 			continue;
6852de962bdSlukem 		}
6862de962bdSlukem #endif
6872de962bdSlukem 		return r;
6882de962bdSlukem 	}
6892de962bdSlukem 	return -1;
6902de962bdSlukem #elif defined( LDAP_R_COMPILE )
6912de962bdSlukem # undef NEED_COPY_HOSTENT
6922de962bdSlukem # define NEED_COPY_HOSTENT
6932de962bdSlukem 	struct hostent *he;
6942de962bdSlukem 	int	retval;
6952de962bdSlukem 	*buf = NULL;
6962de962bdSlukem 
697d11b170bStron 	LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
6982de962bdSlukem 	he = gethostbyaddr( addr, len, type );
6992de962bdSlukem 
7002de962bdSlukem 	if (he==NULL) {
7012de962bdSlukem 		*herrno_ptr = h_errno;
7022de962bdSlukem 		retval = -1;
7032de962bdSlukem 	} else if (copy_hostent( resbuf, buf, he )<0) {
7042de962bdSlukem 		*herrno_ptr = -1;
7052de962bdSlukem 		retval = -1;
7062de962bdSlukem 	} else {
7072de962bdSlukem 		*result = resbuf;
7082de962bdSlukem 		retval = 0;
7092de962bdSlukem 	}
710d11b170bStron 	LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
7112de962bdSlukem 
7122de962bdSlukem 	return retval;
7132de962bdSlukem 
7142de962bdSlukem #else /* gethostbyaddr() */
7152de962bdSlukem 	*buf = NULL;
7162de962bdSlukem 	*result = gethostbyaddr( addr, len, type );
7172de962bdSlukem 
7182de962bdSlukem 	if (*result!=NULL) {
7192de962bdSlukem 		return 0;
7202de962bdSlukem 	}
7212de962bdSlukem 	return -1;
7222de962bdSlukem #endif
7232de962bdSlukem }
7242de962bdSlukem /*
7252de962bdSlukem  * ldap_int_utils_init() should be called before any other function.
7262de962bdSlukem  */
7272de962bdSlukem 
ldap_int_utils_init(void)7282de962bdSlukem void ldap_int_utils_init( void )
7292de962bdSlukem {
7302de962bdSlukem 	static int done=0;
7312de962bdSlukem 	if (done)
7322de962bdSlukem 	  return;
7332de962bdSlukem 	done=1;
7342de962bdSlukem 
7352de962bdSlukem #ifdef LDAP_R_COMPILE
7362de962bdSlukem #if !defined( USE_CTIME_R ) && !defined( HAVE_REENTRANT_FUNCTIONS )
7372de962bdSlukem 	ldap_pvt_thread_mutex_init( &ldap_int_ctime_mutex );
7382de962bdSlukem #endif
739ef2f90d3Sadam #if !defined( USE_GMTIME_R ) && !defined( USE_LOCALTIME_R )
740ef2f90d3Sadam 	ldap_pvt_thread_mutex_init( &ldap_int_gmtime_mutex );
741ef2f90d3Sadam #endif
7422de962bdSlukem 	ldap_pvt_thread_mutex_init( &ldap_int_resolv_mutex );
7432de962bdSlukem 
744d11b170bStron 	ldap_pvt_thread_mutex_init( &ldap_int_hostname_mutex );
745d11b170bStron 
746d11b170bStron 	ldap_pvt_thread_mutex_init( &ldap_int_gettime_mutex );
747d11b170bStron 
7484e6df137Slukem #ifdef HAVE_GSSAPI
7494e6df137Slukem 	ldap_pvt_thread_mutex_init( &ldap_int_gssapi_mutex );
7504e6df137Slukem #endif
7512de962bdSlukem #endif
7522de962bdSlukem 
7532de962bdSlukem 	/* call other module init functions here... */
7542de962bdSlukem }
7552de962bdSlukem 
7562de962bdSlukem #if defined( NEED_COPY_HOSTENT )
7572de962bdSlukem # undef NEED_SAFE_REALLOC
7582de962bdSlukem #define NEED_SAFE_REALLOC
7592de962bdSlukem 
cpy_aliases(char *** tgtio,char * buf,char ** src)7602de962bdSlukem static char *cpy_aliases(
7612de962bdSlukem 	char ***tgtio,
7622de962bdSlukem 	char *buf,
7632de962bdSlukem 	char **src )
7642de962bdSlukem {
7652de962bdSlukem 	int len;
7662de962bdSlukem 	char **tgt=*tgtio;
7672de962bdSlukem 	for( ; (*src) ; src++ ) {
7682de962bdSlukem 		len = strlen( *src ) + 1;
7692de962bdSlukem 		AC_MEMCPY( buf, *src, len );
7702de962bdSlukem 		*tgt++=buf;
7712de962bdSlukem 		buf+=len;
7722de962bdSlukem 	}
7732de962bdSlukem 	*tgtio=tgt;
7742de962bdSlukem 	return buf;
7752de962bdSlukem }
7762de962bdSlukem 
cpy_addresses(char *** tgtio,char * buf,char ** src,int len)7772de962bdSlukem static char *cpy_addresses(
7782de962bdSlukem 	char ***tgtio,
7792de962bdSlukem 	char *buf,
7802de962bdSlukem 	char **src,
7812de962bdSlukem 	int len )
7822de962bdSlukem {
7832de962bdSlukem    	char **tgt=*tgtio;
7842de962bdSlukem 	for( ; (*src) ; src++ ) {
7852de962bdSlukem 		AC_MEMCPY( buf, *src, len );
7862de962bdSlukem 		*tgt++=buf;
7872de962bdSlukem 		buf+=len;
7882de962bdSlukem 	}
7892de962bdSlukem 	*tgtio=tgt;
7902de962bdSlukem 	return buf;
7912de962bdSlukem }
7922de962bdSlukem 
copy_hostent(struct hostent * res,char ** buf,struct hostent * src)7932de962bdSlukem static int copy_hostent(
7942de962bdSlukem 	struct hostent *res,
7952de962bdSlukem 	char **buf,
7962de962bdSlukem 	struct hostent * src )
7972de962bdSlukem {
7982de962bdSlukem 	char	**p;
7992de962bdSlukem 	char	**tp;
8002de962bdSlukem 	char	*tbuf;
8012de962bdSlukem 	int	name_len;
8022de962bdSlukem 	int	n_alias=0;
8032de962bdSlukem 	int	total_alias_len=0;
8042de962bdSlukem 	int	n_addr=0;
8052de962bdSlukem 	int	total_addr_len=0;
8062de962bdSlukem 	int	total_len;
8072de962bdSlukem 
8082de962bdSlukem 	/* calculate the size needed for the buffer */
8092de962bdSlukem 	name_len = strlen( src->h_name ) + 1;
8102de962bdSlukem 
8112de962bdSlukem 	if( src->h_aliases != NULL ) {
8122de962bdSlukem 		for( p = src->h_aliases; (*p) != NULL; p++ ) {
8132de962bdSlukem 			total_alias_len += strlen( *p ) + 1;
8142de962bdSlukem 			n_alias++;
8152de962bdSlukem 		}
8162de962bdSlukem 	}
8172de962bdSlukem 
8182de962bdSlukem 	if( src->h_addr_list != NULL ) {
8192de962bdSlukem 		for( p = src->h_addr_list; (*p) != NULL; p++ ) {
8202de962bdSlukem 			n_addr++;
8212de962bdSlukem 		}
8222de962bdSlukem 		total_addr_len = n_addr * src->h_length;
8232de962bdSlukem 	}
8242de962bdSlukem 
8252de962bdSlukem 	total_len = (n_alias + n_addr + 2) * sizeof( char * ) +
8262de962bdSlukem 		total_addr_len + total_alias_len + name_len;
8272de962bdSlukem 
8282de962bdSlukem 	if (safe_realloc( buf, total_len )) {
8292de962bdSlukem 		tp = (char **) *buf;
8302de962bdSlukem 		tbuf = *buf + (n_alias + n_addr + 2) * sizeof( char * );
8312de962bdSlukem 		AC_MEMCPY( res, src, sizeof( struct hostent ) );
8322de962bdSlukem 		/* first the name... */
8332de962bdSlukem 		AC_MEMCPY( tbuf, src->h_name, name_len );
8342de962bdSlukem 		res->h_name = tbuf; tbuf+=name_len;
8352de962bdSlukem 		/* now the aliases */
8362de962bdSlukem 		res->h_aliases = tp;
8372de962bdSlukem 		if ( src->h_aliases != NULL ) {
8382de962bdSlukem 			tbuf = cpy_aliases( &tp, tbuf, src->h_aliases );
8392de962bdSlukem 		}
8402de962bdSlukem 		*tp++=NULL;
8412de962bdSlukem 		/* finally the addresses */
8422de962bdSlukem 		res->h_addr_list = tp;
8432de962bdSlukem 		if ( src->h_addr_list != NULL ) {
8442de962bdSlukem 			tbuf = cpy_addresses( &tp, tbuf, src->h_addr_list, src->h_length );
8452de962bdSlukem 		}
8462de962bdSlukem 		*tp++=NULL;
8472de962bdSlukem 		return 0;
8482de962bdSlukem 	}
8492de962bdSlukem 	return -1;
8502de962bdSlukem }
8512de962bdSlukem #endif
8522de962bdSlukem 
8532de962bdSlukem #if defined( NEED_SAFE_REALLOC )
safe_realloc(char ** buf,int len)8542de962bdSlukem static char *safe_realloc( char **buf, int len )
8552de962bdSlukem {
8562de962bdSlukem 	char *tmpbuf;
8572de962bdSlukem 	tmpbuf = LDAP_REALLOC( *buf, len );
8582de962bdSlukem 	if (tmpbuf) {
8592de962bdSlukem 		*buf=tmpbuf;
8602de962bdSlukem 	}
8612de962bdSlukem 	return tmpbuf;
8622de962bdSlukem }
8632de962bdSlukem #endif
8642de962bdSlukem 
ldap_pvt_get_fqdn(char * name)8652de962bdSlukem char * ldap_pvt_get_fqdn( char *name )
8662de962bdSlukem {
867*549b59edSchristos #ifdef HAVE_GETADDRINFO
868*549b59edSchristos 	struct addrinfo hints, *res;
869*549b59edSchristos #else
870*549b59edSchristos 	char *ha_buf;
8712de962bdSlukem 	struct hostent *hp, he_buf;
872*549b59edSchristos 	int local_h_errno;
873*549b59edSchristos #endif
874*549b59edSchristos 	int rc;
875*549b59edSchristos 	char *fqdn, hostbuf[MAXHOSTNAMELEN+1];
8762de962bdSlukem 
8772de962bdSlukem 	if( name == NULL ) {
8782de962bdSlukem 		if( gethostname( hostbuf, MAXHOSTNAMELEN ) == 0 ) {
8792de962bdSlukem 			hostbuf[MAXHOSTNAMELEN] = '\0';
8802de962bdSlukem 			name = hostbuf;
8812de962bdSlukem 		} else {
8822de962bdSlukem 			name = "localhost";
8832de962bdSlukem 		}
8842de962bdSlukem 	}
8852de962bdSlukem 
886*549b59edSchristos #ifdef HAVE_GETADDRINFO
887*549b59edSchristos 	memset( &hints, 0, sizeof( hints ));
888*549b59edSchristos 	hints.ai_family = AF_UNSPEC;
889*549b59edSchristos 	hints.ai_flags = AI_CANONNAME;
890*549b59edSchristos 
891*549b59edSchristos 	LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
892*549b59edSchristos 	rc = getaddrinfo( name, NULL, &hints, &res );
893*549b59edSchristos 	LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
894*549b59edSchristos 	if ( rc == 0 && res->ai_canonname ) {
895*549b59edSchristos 		fqdn = LDAP_STRDUP( res->ai_canonname );
896*549b59edSchristos 	} else {
897*549b59edSchristos 		fqdn = LDAP_STRDUP( name );
898*549b59edSchristos 	}
899*549b59edSchristos 	if ( rc == 0 )
900*549b59edSchristos 		freeaddrinfo( res );
901*549b59edSchristos #else
9022de962bdSlukem 	rc = ldap_pvt_gethostbyname_a( name,
9032de962bdSlukem 		&he_buf, &ha_buf, &hp, &local_h_errno );
9042de962bdSlukem 
9052de962bdSlukem 	if( rc < 0 || hp == NULL || hp->h_name == NULL ) {
9062de962bdSlukem 		fqdn = LDAP_STRDUP( name );
9072de962bdSlukem 	} else {
9082de962bdSlukem 		fqdn = LDAP_STRDUP( hp->h_name );
9092de962bdSlukem 	}
9102de962bdSlukem 
9112de962bdSlukem 	LDAP_FREE( ha_buf );
912*549b59edSchristos #endif
9132de962bdSlukem 	return fqdn;
9142de962bdSlukem }
9152de962bdSlukem 
9162de962bdSlukem #if ( defined( HAVE_GETADDRINFO ) || defined( HAVE_GETNAMEINFO ) ) \
9172de962bdSlukem 	&& !defined( HAVE_GAI_STRERROR )
ldap_pvt_gai_strerror(int code)9182de962bdSlukem char *ldap_pvt_gai_strerror (int code) {
9192de962bdSlukem 	static struct {
9202de962bdSlukem 		int code;
9212de962bdSlukem 		const char *msg;
9222de962bdSlukem 	} values[] = {
9232de962bdSlukem #ifdef EAI_ADDRFAMILY
9242de962bdSlukem 		{ EAI_ADDRFAMILY, N_("Address family for hostname not supported") },
9252de962bdSlukem #endif
9262de962bdSlukem 		{ EAI_AGAIN, N_("Temporary failure in name resolution") },
9272de962bdSlukem 		{ EAI_BADFLAGS, N_("Bad value for ai_flags") },
9282de962bdSlukem 		{ EAI_FAIL, N_("Non-recoverable failure in name resolution") },
9292de962bdSlukem 		{ EAI_FAMILY, N_("ai_family not supported") },
9302de962bdSlukem 		{ EAI_MEMORY, N_("Memory allocation failure") },
9312de962bdSlukem #ifdef EAI_NODATA
9322de962bdSlukem 		{ EAI_NODATA, N_("No address associated with hostname") },
9332de962bdSlukem #endif
9342de962bdSlukem 		{ EAI_NONAME, N_("Name or service not known") },
9352de962bdSlukem 		{ EAI_SERVICE, N_("Servname not supported for ai_socktype") },
9362de962bdSlukem 		{ EAI_SOCKTYPE, N_("ai_socktype not supported") },
937d11b170bStron #ifdef EAI_SYSTEM
9382de962bdSlukem 		{ EAI_SYSTEM, N_("System error") },
939d11b170bStron #endif
9402de962bdSlukem 		{ 0, NULL }
9412de962bdSlukem 	};
9422de962bdSlukem 
9432de962bdSlukem 	int i;
9442de962bdSlukem 
9452de962bdSlukem 	for ( i = 0; values[i].msg != NULL; i++ ) {
9462de962bdSlukem 		if ( values[i].code == code ) {
9472de962bdSlukem 			return (char *) _(values[i].msg);
9482de962bdSlukem 		}
9492de962bdSlukem 	}
9502de962bdSlukem 
9512de962bdSlukem 	return _("Unknown error");
9522de962bdSlukem }
9532de962bdSlukem #endif
954*549b59edSchristos 
955*549b59edSchristos /* format a socket address as a string */
956*549b59edSchristos 
957*549b59edSchristos #ifdef HAVE_TCPD
958*549b59edSchristos # include <tcpd.h>
959*549b59edSchristos # define SOCKADDR_STRING_UNKNOWN	STRING_UNKNOWN
960*549b59edSchristos #else /* ! TCP Wrappers */
961*549b59edSchristos # define SOCKADDR_STRING_UNKNOWN	"unknown"
962*549b59edSchristos #endif /* ! TCP Wrappers */
963*549b59edSchristos 
964*549b59edSchristos void
ldap_pvt_sockaddrstr(Sockaddr * sa,struct berval * addrbuf)965*549b59edSchristos ldap_pvt_sockaddrstr( Sockaddr *sa, struct berval *addrbuf )
966*549b59edSchristos {
967*549b59edSchristos 	char *addr;
968*549b59edSchristos 	switch( sa->sa_addr.sa_family ) {
969*549b59edSchristos #ifdef LDAP_PF_LOCAL
970*549b59edSchristos 	case AF_LOCAL:
971*549b59edSchristos 		addrbuf->bv_len = snprintf( addrbuf->bv_val, addrbuf->bv_len,
972*549b59edSchristos 			"PATH=%s", sa->sa_un_addr.sun_path );
973*549b59edSchristos 		break;
974*549b59edSchristos #endif
975*549b59edSchristos #ifdef LDAP_PF_INET6
976*549b59edSchristos 	case AF_INET6:
977*549b59edSchristos 		strcpy(addrbuf->bv_val, "IP=");
978*549b59edSchristos 		if ( IN6_IS_ADDR_V4MAPPED(&sa->sa_in6_addr.sin6_addr) ) {
979*549b59edSchristos #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
980*549b59edSchristos 			addr = (char *)inet_ntop( AF_INET,
981*549b59edSchristos 			   ((struct in_addr *)&sa->sa_in6_addr.sin6_addr.s6_addr[12]),
982*549b59edSchristos 			   addrbuf->bv_val+3, addrbuf->bv_len-3 );
983*549b59edSchristos #else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
984*549b59edSchristos 			addr = inet_ntoa( *((struct in_addr *)
985*549b59edSchristos 					&sa->sa_in6_addr.sin6_addr.s6_addr[12]) );
986*549b59edSchristos #endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
987*549b59edSchristos 			if ( !addr ) addr = SOCKADDR_STRING_UNKNOWN;
988*549b59edSchristos 			if ( addr != addrbuf->bv_val+3 ) {
989*549b59edSchristos 				addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "%s:%d", addr,
990*549b59edSchristos 				 (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + 3;
991*549b59edSchristos 			} else {
992*549b59edSchristos 				int len = strlen( addr );
993*549b59edSchristos 				addrbuf->bv_len = sprintf( addr+len, ":%d",
994*549b59edSchristos 				 (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + len + 3;
995*549b59edSchristos 			}
996*549b59edSchristos 		} else {
997*549b59edSchristos 			addr = (char *)inet_ntop( AF_INET6,
998*549b59edSchristos 				      &sa->sa_in6_addr.sin6_addr,
999*549b59edSchristos 				      addrbuf->bv_val+4, addrbuf->bv_len-4 );
1000*549b59edSchristos 			if ( !addr ) addr = SOCKADDR_STRING_UNKNOWN;
1001*549b59edSchristos 			if ( addr != addrbuf->bv_val+4 ) {
1002*549b59edSchristos 				addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "[%s]:%d", addr,
1003*549b59edSchristos 				 (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + 3;
1004*549b59edSchristos 			} else {
1005*549b59edSchristos 				int len = strlen( addr );
1006*549b59edSchristos 				addrbuf->bv_val[3] = '[';
1007*549b59edSchristos 				addrbuf->bv_len = sprintf( addr+len, "]:%d",
1008*549b59edSchristos 				 (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + len + 4;
1009*549b59edSchristos 			}
1010*549b59edSchristos 		}
1011*549b59edSchristos 		break;
1012*549b59edSchristos #endif /* LDAP_PF_INET6 */
1013*549b59edSchristos 	case AF_INET:
1014*549b59edSchristos 		strcpy(addrbuf->bv_val, "IP=");
1015*549b59edSchristos #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
1016*549b59edSchristos 		addr = (char *)inet_ntop( AF_INET, &sa->sa_in_addr.sin_addr,
1017*549b59edSchristos 			   addrbuf->bv_val+3, addrbuf->bv_len-3 );
1018*549b59edSchristos #else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
1019*549b59edSchristos 		addr = inet_ntoa( sa->sa_in_addr.sin_addr );
1020*549b59edSchristos #endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
1021*549b59edSchristos 		if ( !addr ) addr = SOCKADDR_STRING_UNKNOWN;
1022*549b59edSchristos 		if ( addr != addrbuf->bv_val+3 ) {
1023*549b59edSchristos 			addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "%s:%d", addr,
1024*549b59edSchristos 			 (unsigned) ntohs( sa->sa_in_addr.sin_port ) ) + 3;
1025*549b59edSchristos 		} else {
1026*549b59edSchristos 			int len = strlen( addr );
1027*549b59edSchristos 			addrbuf->bv_len = sprintf( addr+len, ":%d",
1028*549b59edSchristos 			 (unsigned) ntohs( sa->sa_in_addr.sin_port ) ) + len + 3;
1029*549b59edSchristos 		}
1030*549b59edSchristos 		break;
1031*549b59edSchristos 	default:
1032*549b59edSchristos 		addrbuf->bv_val[0] = '\0';
1033*549b59edSchristos 	}
1034*549b59edSchristos }
1035