1 /*	$NetBSD: util-int.c,v 1.3 2021/08/14 16:14:56 christos Exp $	*/
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2021 The OpenLDAP Foundation.
7  * Portions Copyright 1998 A. Hartgers.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 /* ACKNOWLEDGEMENTS:
19  * This work was initially developed by Bart Hartgers for inclusion in
20  * OpenLDAP Software.
21  */
22 
23 /*
24  * util-int.c	Various functions to replace missing threadsafe ones.
25  *				Without the real *_r funcs, things will
26  *				work, but might not be threadsafe.
27  */
28 
29 #include <sys/cdefs.h>
30 __RCSID("$NetBSD: util-int.c,v 1.3 2021/08/14 16:14:56 christos Exp $");
31 
32 #include "portable.h"
33 
34 #include <ac/stdlib.h>
35 
36 #include <ac/errno.h>
37 #include <ac/socket.h>
38 #include <ac/string.h>
39 #include <ac/time.h>
40 #include <ac/unistd.h>
41 
42 #include "ldap-int.h"
43 
44 #ifndef h_errno
45 /* newer systems declare this in <netdb.h> for you, older ones don't.
46  * harmless to declare it again (unless defined by a macro).
47  */
48 extern int h_errno;
49 #endif
50 
51 #ifdef HAVE_HSTRERROR
52 # define HSTRERROR(e)	hstrerror(e)
53 #else
54 # define HSTRERROR(e)	hp_strerror(e)
55 #endif
56 
57 #ifndef LDAP_R_COMPILE
58 # undef HAVE_REENTRANT_FUNCTIONS
59 # undef HAVE_CTIME_R
60 # undef HAVE_GETHOSTBYNAME_R
61 # undef HAVE_GETHOSTBYADDR_R
62 
63 #else
64 # include <ldap_pvt_thread.h>
65   ldap_pvt_thread_mutex_t ldap_int_resolv_mutex;
66   ldap_pvt_thread_mutex_t ldap_int_hostname_mutex;
67   static ldap_pvt_thread_mutex_t ldap_int_gettime_mutex;
68 
69 # if (defined( HAVE_CTIME_R ) || defined( HAVE_REENTRANT_FUNCTIONS)) \
70 	 && defined( CTIME_R_NARGS )
71 #   define USE_CTIME_R
72 # else
73 	static ldap_pvt_thread_mutex_t ldap_int_ctime_mutex;
74 # endif
75 
76 /* USE_GMTIME_R and USE_LOCALTIME_R defined in ldap_pvt.h */
77 
78 #if !defined( USE_GMTIME_R ) || !defined( USE_LOCALTIME_R )
79 	/* we use the same mutex for gmtime(3) and localtime(3)
80 	 * because implementations may use the same buffer
81 	 * for both functions */
82 	static ldap_pvt_thread_mutex_t ldap_int_gmtime_mutex;
83 #endif
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 
ldap_pvt_ctime(const time_t * tp,char * buf)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 	LDAP_MUTEX_LOCK( &ldap_int_ctime_mutex );
113 	AC_MEMCPY( buf, ctime(tp), 26 );
114 	LDAP_MUTEX_UNLOCK( &ldap_int_ctime_mutex );
115 
116 	return buf;
117 #endif
118 }
119 
120 #if !defined( USE_GMTIME_R ) || !defined( USE_LOCALTIME_R )
121 int
ldap_pvt_gmtime_lock(void)122 ldap_pvt_gmtime_lock( void )
123 {
124 # ifndef LDAP_R_COMPILE
125 	return 0;
126 # else /* LDAP_R_COMPILE */
127 	return ldap_pvt_thread_mutex_lock( &ldap_int_gmtime_mutex );
128 # endif /* LDAP_R_COMPILE */
129 }
130 
131 int
ldap_pvt_gmtime_unlock(void)132 ldap_pvt_gmtime_unlock( void )
133 {
134 # ifndef LDAP_R_COMPILE
135 	return 0;
136 # else /* LDAP_R_COMPILE */
137 	return ldap_pvt_thread_mutex_unlock( &ldap_int_gmtime_mutex );
138 # endif /* LDAP_R_COMPILE */
139 }
140 #endif /* !USE_GMTIME_R || !USE_LOCALTIME_R */
141 
142 #ifndef USE_GMTIME_R
143 struct tm *
ldap_pvt_gmtime(const time_t * timep,struct tm * result)144 ldap_pvt_gmtime( const time_t *timep, struct tm *result )
145 {
146 	struct tm *tm_ptr;
147 
148 	LDAP_MUTEX_LOCK( &ldap_int_gmtime_mutex );
149 	tm_ptr = gmtime( timep );
150 	if ( tm_ptr == NULL ) {
151 		result = NULL;
152 
153 	} else {
154 		*result = *tm_ptr;
155 	}
156 	LDAP_MUTEX_UNLOCK( &ldap_int_gmtime_mutex );
157 
158 	return result;
159 }
160 #endif /* !USE_GMTIME_R */
161 
162 #ifndef USE_LOCALTIME_R
163 struct tm *
ldap_pvt_localtime(const time_t * timep,struct tm * result)164 ldap_pvt_localtime( const time_t *timep, struct tm *result )
165 {
166 	struct tm *tm_ptr;
167 
168 	LDAP_MUTEX_LOCK( &ldap_int_gmtime_mutex );
169 	tm_ptr = localtime( timep );
170 	if ( tm_ptr == NULL ) {
171 		result = NULL;
172 
173 	} else {
174 		*result = *tm_ptr;
175 	}
176 	LDAP_MUTEX_UNLOCK( &ldap_int_gmtime_mutex );
177 
178 	return result;
179 }
180 #endif /* !USE_LOCALTIME_R */
181 
182 static int _ldap_pvt_gt_subs;
183 
184 #ifdef _WIN32
185 /* Windows SYSTEMTIME only has 10 millisecond resolution, so we
186  * also need to use a high resolution timer to get nanoseconds.
187  * This is pretty clunky.
188  */
189 static LARGE_INTEGER _ldap_pvt_gt_freq;
190 static LARGE_INTEGER _ldap_pvt_gt_prev;
191 static int _ldap_pvt_gt_offset;
192 
193 #define SEC_TO_UNIX_EPOCH 11644473600LL
194 #define TICKS_PER_SECOND 10000000
195 #define BILLION	1000000000L
196 
197 static int
ldap_pvt_gettimensec(int * sec)198 ldap_pvt_gettimensec(int *sec)
199 {
200 	LARGE_INTEGER count;
201 
202 	QueryPerformanceCounter( &count );
203 
204 	/* It shouldn't ever go backwards, but multiple CPUs might
205 	 * be able to hit in the same tick.
206 	 */
207 	LDAP_MUTEX_LOCK( &ldap_int_gettime_mutex );
208 	/* We assume Windows has at least a vague idea of
209 	 * when a second begins. So we align our nanosecond count
210 	 * with the Windows millisecond count using this offset.
211 	 * We retain the submillisecond portion of our own count.
212 	 *
213 	 * Note - this also assumes that the relationship between
214 	 * the PerformanceCounter and SystemTime stays constant;
215 	 * that assumption breaks if the SystemTime is adjusted by
216 	 * an external action.
217 	 */
218 	if ( !_ldap_pvt_gt_freq.QuadPart ) {
219 		LARGE_INTEGER c2;
220 		ULARGE_INTEGER ut;
221 		FILETIME ft0, ft1;
222 		long long t;
223 		int nsec;
224 
225 		/* Initialize our offset */
226 		QueryPerformanceFrequency( &_ldap_pvt_gt_freq );
227 
228 		/* Wait for a tick of the system time: 10-15ms */
229 		GetSystemTimeAsFileTime( &ft0 );
230 		do {
231 			GetSystemTimeAsFileTime( &ft1 );
232 		} while ( ft1.dwLowDateTime == ft0.dwLowDateTime );
233 
234 		ut.LowPart = ft1.dwLowDateTime;
235 		ut.HighPart = ft1.dwHighDateTime;
236 		QueryPerformanceCounter( &c2 );
237 
238 		/* get second and fraction portion of counter */
239 		t = c2.QuadPart % (_ldap_pvt_gt_freq.QuadPart*10);
240 
241 		/* convert to nanoseconds */
242 		t *= BILLION;
243 		nsec = t / _ldap_pvt_gt_freq.QuadPart;
244 
245 		ut.QuadPart /= 10;
246 		ut.QuadPart %= (10 * BILLION);
247 		_ldap_pvt_gt_offset = nsec - ut.QuadPart;
248 		count = c2;
249 	}
250 	if ( count.QuadPart <= _ldap_pvt_gt_prev.QuadPart ) {
251 		_ldap_pvt_gt_subs++;
252 	} else {
253 		_ldap_pvt_gt_subs = 0;
254 		_ldap_pvt_gt_prev = count;
255 	}
256 	LDAP_MUTEX_UNLOCK( &ldap_int_gettime_mutex );
257 
258 	/* convert to nanoseconds */
259 	count.QuadPart %= _ldap_pvt_gt_freq.QuadPart*10;
260 	count.QuadPart *= BILLION;
261 	count.QuadPart /= _ldap_pvt_gt_freq.QuadPart;
262 	count.QuadPart -= _ldap_pvt_gt_offset;
263 
264 	/* We've extracted the 1s and nanoseconds.
265 	 * The 1sec digit is used to detect wraparound in nanosecnds.
266 	 */
267 	if (count.QuadPart < 0)
268 		count.QuadPart += (10 * BILLION);
269 	else if (count.QuadPart >= (10 * BILLION))
270 		count.QuadPart -= (10 * BILLION);
271 
272 	*sec = count.QuadPart / BILLION;
273 	return count.QuadPart % BILLION;
274 }
275 
276 
277 /* emulate POSIX clock_gettime */
278 int
ldap_pvt_clock_gettime(int clk_id,struct timespec * tv)279 ldap_pvt_clock_gettime( int clk_id, struct timespec *tv )
280 {
281 	FILETIME ft;
282 	ULARGE_INTEGER ut;
283 	int sec, sec0;
284 
285 	GetSystemTimeAsFileTime( &ft );
286 	ut.LowPart = ft.dwLowDateTime;
287 	ut.HighPart = ft.dwHighDateTime;
288 
289 	/* convert to sec */
290 	ut.QuadPart /= TICKS_PER_SECOND;
291 
292 	tv->tv_nsec = ldap_pvt_gettimensec(&sec);
293 	tv->tv_sec = ut.QuadPart - SEC_TO_UNIX_EPOCH;
294 
295 	/* check for carry from microseconds */
296 	sec0 = tv->tv_sec % 10;
297 	if (sec0 < sec || (sec0 == 9 && !sec))
298 		tv->tv_sec++;
299 
300 	return 0;
301 }
302 
303 /* emulate POSIX gettimeofday */
304 int
ldap_pvt_gettimeofday(struct timeval * tv,void * unused)305 ldap_pvt_gettimeofday( struct timeval *tv, void *unused )
306 {
307 	struct timespec ts;
308 	ldap_pvt_clock_gettime( 0, &ts );
309 	tv->tv_sec = ts.tv_sec;
310 	tv->tv_usec = ts.tv_nsec / 1000;
311 	return 0;
312 }
313 
314 
315 /* return a broken out time, with nanoseconds
316  */
317 void
ldap_pvt_gettime(struct lutil_tm * tm)318 ldap_pvt_gettime( struct lutil_tm *tm )
319 {
320 	SYSTEMTIME st;
321 	int sec, sec0;
322 	static const char daysPerMonth[] = {
323 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
324 
325 	GetSystemTime( &st );
326 	tm->tm_nsec = ldap_pvt_gettimensec(&sec);
327 	tm->tm_usub = _ldap_pvt_gt_subs;
328 
329 	/* any difference larger than nanoseconds is
330 	 * already reflected in st
331 	 */
332 	tm->tm_sec = st.wSecond;
333 	tm->tm_min = st.wMinute;
334 	tm->tm_hour = st.wHour;
335 	tm->tm_mday = st.wDay;
336 	tm->tm_mon = st.wMonth - 1;
337 	tm->tm_year = st.wYear - 1900;
338 
339 	/* check for carry from nanoseconds */
340 	sec0 = tm->tm_sec % 10;
341 	if (sec0 < sec || (sec0 == 9 && !sec)) {
342 		tm->tm_sec++;
343 		/* FIXME: we don't handle leap seconds */
344 		if (tm->tm_sec > 59) {
345 			tm->tm_sec = 0;
346 			tm->tm_min++;
347 			if (tm->tm_min > 59) {
348 				tm->tm_min = 0;
349 				tm->tm_hour++;
350 				if (tm->tm_hour > 23) {
351 					int days = daysPerMonth[tm->tm_mon];
352 					tm->tm_hour = 0;
353 					tm->tm_mday++;
354 
355 					/* if it's February of a leap year,
356 					 * add 1 day to this month
357 					 */
358 					if (tm->tm_mon == 1 &&
359 						((!(st.wYear % 4) && (st.wYear % 100)) ||
360 						!(st.wYear % 400)))
361 						days++;
362 
363 					if (tm->tm_mday > days) {
364 						tm->tm_mday = 1;
365 						tm->tm_mon++;
366 						if (tm->tm_mon > 11) {
367 							tm->tm_mon = 0;
368 							tm->tm_year++;
369 						}
370 					}
371 				}
372 			}
373 		}
374 	}
375 }
376 #else
377 
378 #ifdef HAVE_CLOCK_GETTIME
379 static struct timespec _ldap_pvt_gt_prevTv;
380 #else
381 static struct timeval _ldap_pvt_gt_prevTv;
382 #endif
383 
384 void
ldap_pvt_gettime(struct lutil_tm * ltm)385 ldap_pvt_gettime( struct lutil_tm *ltm )
386 {
387 	struct tm tm;
388 	time_t t;
389 #ifdef HAVE_CLOCK_GETTIME
390 #define	FRAC	tv_nsec
391 #define	NSECS(x)	x
392 	struct timespec tv;
393 
394 	clock_gettime( CLOCK_REALTIME, &tv );
395 #else
396 #define	FRAC	tv_usec
397 #define	NSECS(x)	x * 1000
398 	struct timeval tv;
399 
400 	gettimeofday( &tv, NULL );
401 #endif
402 	t = tv.tv_sec;
403 
404 	LDAP_MUTEX_LOCK( &ldap_int_gettime_mutex );
405 	if ( tv.tv_sec < _ldap_pvt_gt_prevTv.tv_sec
406 		|| ( tv.tv_sec == _ldap_pvt_gt_prevTv.tv_sec
407 		&& tv.FRAC <= _ldap_pvt_gt_prevTv.FRAC )) {
408 		_ldap_pvt_gt_subs++;
409 	} else {
410 		_ldap_pvt_gt_subs = 0;
411 		_ldap_pvt_gt_prevTv = tv;
412 	}
413 	LDAP_MUTEX_UNLOCK( &ldap_int_gettime_mutex );
414 
415 	ltm->tm_usub = _ldap_pvt_gt_subs;
416 
417 	ldap_pvt_gmtime( &t, &tm );
418 
419 	ltm->tm_sec = tm.tm_sec;
420 	ltm->tm_min = tm.tm_min;
421 	ltm->tm_hour = tm.tm_hour;
422 	ltm->tm_mday = tm.tm_mday;
423 	ltm->tm_mon = tm.tm_mon;
424 	ltm->tm_year = tm.tm_year;
425 	ltm->tm_nsec = NSECS(tv.FRAC);
426 }
427 #endif
428 
429 size_t
ldap_pvt_csnstr(char * buf,size_t len,unsigned int replica,unsigned int mod)430 ldap_pvt_csnstr(char *buf, size_t len, unsigned int replica, unsigned int mod)
431 {
432 	struct lutil_tm tm;
433 	int n;
434 
435 	ldap_pvt_gettime( &tm );
436 
437 	n = snprintf( buf, len,
438 		"%4d%02d%02d%02d%02d%02d.%06dZ#%06x#%03x#%06x",
439 		tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
440 		tm.tm_min, tm.tm_sec, tm.tm_nsec / 1000, tm.tm_usub, replica, mod );
441 
442 	if( n < 0 ) return 0;
443 	return ( (size_t) n < len ) ? n : 0;
444 }
445 
446 #define BUFSTART (1024-32)
447 #define BUFMAX (32*1024-32)
448 
449 #if defined(LDAP_R_COMPILE)
450 static char *safe_realloc( char **buf, int len );
451 
452 #if !(defined(HAVE_GETHOSTBYNAME_R) && defined(HAVE_GETHOSTBYADDR_R))
453 static int copy_hostent( struct hostent *res,
454 	char **buf, struct hostent * src );
455 #endif
456 #endif
457 
ldap_pvt_gethostbyname_a(const char * name,struct hostent * resbuf,char ** buf,struct hostent ** result,int * herrno_ptr)458 int ldap_pvt_gethostbyname_a(
459 	const char *name,
460 	struct hostent *resbuf,
461 	char **buf,
462 	struct hostent **result,
463 	int *herrno_ptr )
464 {
465 #if defined( HAVE_GETHOSTBYNAME_R )
466 
467 # define NEED_SAFE_REALLOC 1
468 	int r=-1;
469 	int buflen=BUFSTART;
470 	*buf = NULL;
471 	for(;buflen<BUFMAX;) {
472 		if (safe_realloc( buf, buflen )==NULL)
473 			return r;
474 
475 #if (GETHOSTBYNAME_R_NARGS < 6)
476 		*result=gethostbyname_r( name, resbuf, *buf, buflen, herrno_ptr );
477 		r = (*result == NULL) ?  -1 : 0;
478 #else
479 		while((r = gethostbyname_r( name, resbuf, *buf, buflen, result, herrno_ptr )) == ERANGE) {
480 			/* Increase the buffer */
481 			buflen*=2;
482 			if (safe_realloc(buf, buflen) == NULL)
483 				return -1;
484 		}
485 #endif
486 
487 		Debug2( LDAP_DEBUG_TRACE, "ldap_pvt_gethostbyname_a: host=%s, r=%d\n",
488 		       name, r );
489 
490 #ifdef NETDB_INTERNAL
491 		if ((r<0) &&
492 			(*herrno_ptr==NETDB_INTERNAL) &&
493 			(errno==ERANGE))
494 		{
495 			buflen*=2;
496 			continue;
497 	 	}
498 #endif
499 		return r;
500 	}
501 	return -1;
502 #elif defined( LDAP_R_COMPILE )
503 # define NEED_COPY_HOSTENT
504 	struct hostent *he;
505 	int	retval;
506 	*buf = NULL;
507 
508 	LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
509 
510 	he = gethostbyname( name );
511 
512 	if (he==NULL) {
513 		*herrno_ptr = h_errno;
514 		retval = -1;
515 	} else if (copy_hostent( resbuf, buf, he )<0) {
516 		*herrno_ptr = -1;
517 		retval = -1;
518 	} else {
519 		*result = resbuf;
520 		retval = 0;
521 	}
522 
523 	LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
524 
525 	return retval;
526 #else
527 	*buf = NULL;
528 	*result = gethostbyname( name );
529 
530 	if (*result!=NULL) {
531 		return 0;
532 	}
533 
534 	*herrno_ptr = h_errno;
535 
536 	return -1;
537 #endif
538 }
539 
540 #if !defined( HAVE_GETNAMEINFO ) && !defined( HAVE_HSTRERROR )
541 static const char *
hp_strerror(int err)542 hp_strerror( int err )
543 {
544 	switch (err) {
545 	case HOST_NOT_FOUND:	return _("Host not found (authoritative)");
546 	case TRY_AGAIN:			return _("Host not found (server fail?)");
547 	case NO_RECOVERY:		return _("Non-recoverable failure");
548 	case NO_DATA:			return _("No data of requested type");
549 #ifdef NETDB_INTERNAL
550 	case NETDB_INTERNAL:	return STRERROR( errno );
551 #endif
552 	}
553 	return _("Unknown resolver error");
554 }
555 #endif
556 
ldap_pvt_get_hname(const struct sockaddr * sa,int len,char * name,int namelen,char ** err)557 int ldap_pvt_get_hname(
558 	const struct sockaddr *sa,
559 	int len,
560 	char *name,
561 	int namelen,
562 	char **err )
563 {
564 	int rc;
565 #if defined( HAVE_GETNAMEINFO )
566 
567 	LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
568 	rc = getnameinfo( sa, len, name, namelen, NULL, 0, 0 );
569 	LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
570 	if ( rc ) *err = (char *)AC_GAI_STRERROR( rc );
571 	return rc;
572 
573 #else /* !HAVE_GETNAMEINFO */
574 	char *addr;
575 	int alen;
576 	struct hostent *hp = NULL;
577 #ifdef HAVE_GETHOSTBYADDR_R
578 	struct hostent hb;
579 	int buflen=BUFSTART, h_errno;
580 	char *buf=NULL;
581 #endif
582 
583 #ifdef LDAP_PF_INET6
584 	if (sa->sa_family == AF_INET6) {
585 		struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa;
586 		addr = (char *)&sin->sin6_addr;
587 		alen = sizeof(sin->sin6_addr);
588 	} else
589 #endif
590 	if (sa->sa_family == AF_INET) {
591 		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
592 		addr = (char *)&sin->sin_addr;
593 		alen = sizeof(sin->sin_addr);
594 	} else {
595 		rc = NO_RECOVERY;
596 		*err = (char *)HSTRERROR( rc );
597 		return rc;
598 	}
599 #if defined( HAVE_GETHOSTBYADDR_R )
600 	for(;buflen<BUFMAX;) {
601 		if (safe_realloc( &buf, buflen )==NULL) {
602 			*err = (char *)STRERROR( ENOMEM );
603 			return ENOMEM;
604 		}
605 #if (GETHOSTBYADDR_R_NARGS < 8)
606 		hp=gethostbyaddr_r( addr, alen, sa->sa_family,
607 			&hb, buf, buflen, &h_errno );
608 		rc = (hp == NULL) ? -1 : 0;
609 #else
610 		rc = gethostbyaddr_r( addr, alen, sa->sa_family,
611 			&hb, buf, buflen,
612 			&hp, &h_errno );
613 #endif
614 #ifdef NETDB_INTERNAL
615 		if ((rc<0) &&
616 			(h_errno==NETDB_INTERNAL) &&
617 			(errno==ERANGE))
618 		{
619 			buflen*=2;
620 			continue;
621 		}
622 #endif
623 		break;
624 	}
625 	if (hp) {
626 		strncpy( name, hp->h_name, namelen );
627 	} else {
628 		*err = (char *)HSTRERROR( h_errno );
629 	}
630 	LDAP_FREE(buf);
631 #else /* HAVE_GETHOSTBYADDR_R */
632 
633 	LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
634 	hp = gethostbyaddr( addr, alen, sa->sa_family );
635 	if (hp) {
636 		strncpy( name, hp->h_name, namelen );
637 		rc = 0;
638 	} else {
639 		rc = h_errno;
640 		*err = (char *)HSTRERROR( h_errno );
641 	}
642 	LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
643 
644 #endif	/* !HAVE_GETHOSTBYADDR_R */
645 	return rc;
646 #endif	/* !HAVE_GETNAMEINFO */
647 }
648 
ldap_pvt_gethostbyaddr_a(const char * addr,int len,int type,struct hostent * resbuf,char ** buf,struct hostent ** result,int * herrno_ptr)649 int ldap_pvt_gethostbyaddr_a(
650 	const char *addr,
651 	int len,
652 	int type,
653 	struct hostent *resbuf,
654 	char **buf,
655 	struct hostent **result,
656 	int *herrno_ptr )
657 {
658 #if defined( HAVE_GETHOSTBYADDR_R )
659 
660 # undef NEED_SAFE_REALLOC
661 # define NEED_SAFE_REALLOC
662 	int r=-1;
663 	int buflen=BUFSTART;
664 	*buf = NULL;
665 	for(;buflen<BUFMAX;) {
666 		if (safe_realloc( buf, buflen )==NULL)
667 			return r;
668 #if (GETHOSTBYADDR_R_NARGS < 8)
669 		*result=gethostbyaddr_r( addr, len, type,
670 			resbuf, *buf, buflen, herrno_ptr );
671 		r = (*result == NULL) ? -1 : 0;
672 #else
673 		r = gethostbyaddr_r( addr, len, type,
674 			resbuf, *buf, buflen,
675 			result, herrno_ptr );
676 #endif
677 
678 #ifdef NETDB_INTERNAL
679 		if ((r<0) &&
680 			(*herrno_ptr==NETDB_INTERNAL) &&
681 			(errno==ERANGE))
682 		{
683 			buflen*=2;
684 			continue;
685 		}
686 #endif
687 		return r;
688 	}
689 	return -1;
690 #elif defined( LDAP_R_COMPILE )
691 # undef NEED_COPY_HOSTENT
692 # define NEED_COPY_HOSTENT
693 	struct hostent *he;
694 	int	retval;
695 	*buf = NULL;
696 
697 	LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
698 	he = gethostbyaddr( addr, len, type );
699 
700 	if (he==NULL) {
701 		*herrno_ptr = h_errno;
702 		retval = -1;
703 	} else if (copy_hostent( resbuf, buf, he )<0) {
704 		*herrno_ptr = -1;
705 		retval = -1;
706 	} else {
707 		*result = resbuf;
708 		retval = 0;
709 	}
710 	LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
711 
712 	return retval;
713 
714 #else /* gethostbyaddr() */
715 	*buf = NULL;
716 	*result = gethostbyaddr( addr, len, type );
717 
718 	if (*result!=NULL) {
719 		return 0;
720 	}
721 	return -1;
722 #endif
723 }
724 /*
725  * ldap_int_utils_init() should be called before any other function.
726  */
727 
ldap_int_utils_init(void)728 void ldap_int_utils_init( void )
729 {
730 	static int done=0;
731 	if (done)
732 	  return;
733 	done=1;
734 
735 #ifdef LDAP_R_COMPILE
736 #if !defined( USE_CTIME_R ) && !defined( HAVE_REENTRANT_FUNCTIONS )
737 	ldap_pvt_thread_mutex_init( &ldap_int_ctime_mutex );
738 #endif
739 #if !defined( USE_GMTIME_R ) && !defined( USE_LOCALTIME_R )
740 	ldap_pvt_thread_mutex_init( &ldap_int_gmtime_mutex );
741 #endif
742 	ldap_pvt_thread_mutex_init( &ldap_int_resolv_mutex );
743 
744 	ldap_pvt_thread_mutex_init( &ldap_int_hostname_mutex );
745 
746 	ldap_pvt_thread_mutex_init( &ldap_int_gettime_mutex );
747 
748 #ifdef HAVE_GSSAPI
749 	ldap_pvt_thread_mutex_init( &ldap_int_gssapi_mutex );
750 #endif
751 #endif
752 
753 	/* call other module init functions here... */
754 }
755 
756 #if defined( NEED_COPY_HOSTENT )
757 # undef NEED_SAFE_REALLOC
758 #define NEED_SAFE_REALLOC
759 
cpy_aliases(char *** tgtio,char * buf,char ** src)760 static char *cpy_aliases(
761 	char ***tgtio,
762 	char *buf,
763 	char **src )
764 {
765 	int len;
766 	char **tgt=*tgtio;
767 	for( ; (*src) ; src++ ) {
768 		len = strlen( *src ) + 1;
769 		AC_MEMCPY( buf, *src, len );
770 		*tgt++=buf;
771 		buf+=len;
772 	}
773 	*tgtio=tgt;
774 	return buf;
775 }
776 
cpy_addresses(char *** tgtio,char * buf,char ** src,int len)777 static char *cpy_addresses(
778 	char ***tgtio,
779 	char *buf,
780 	char **src,
781 	int len )
782 {
783    	char **tgt=*tgtio;
784 	for( ; (*src) ; src++ ) {
785 		AC_MEMCPY( buf, *src, len );
786 		*tgt++=buf;
787 		buf+=len;
788 	}
789 	*tgtio=tgt;
790 	return buf;
791 }
792 
copy_hostent(struct hostent * res,char ** buf,struct hostent * src)793 static int copy_hostent(
794 	struct hostent *res,
795 	char **buf,
796 	struct hostent * src )
797 {
798 	char	**p;
799 	char	**tp;
800 	char	*tbuf;
801 	int	name_len;
802 	int	n_alias=0;
803 	int	total_alias_len=0;
804 	int	n_addr=0;
805 	int	total_addr_len=0;
806 	int	total_len;
807 
808 	/* calculate the size needed for the buffer */
809 	name_len = strlen( src->h_name ) + 1;
810 
811 	if( src->h_aliases != NULL ) {
812 		for( p = src->h_aliases; (*p) != NULL; p++ ) {
813 			total_alias_len += strlen( *p ) + 1;
814 			n_alias++;
815 		}
816 	}
817 
818 	if( src->h_addr_list != NULL ) {
819 		for( p = src->h_addr_list; (*p) != NULL; p++ ) {
820 			n_addr++;
821 		}
822 		total_addr_len = n_addr * src->h_length;
823 	}
824 
825 	total_len = (n_alias + n_addr + 2) * sizeof( char * ) +
826 		total_addr_len + total_alias_len + name_len;
827 
828 	if (safe_realloc( buf, total_len )) {
829 		tp = (char **) *buf;
830 		tbuf = *buf + (n_alias + n_addr + 2) * sizeof( char * );
831 		AC_MEMCPY( res, src, sizeof( struct hostent ) );
832 		/* first the name... */
833 		AC_MEMCPY( tbuf, src->h_name, name_len );
834 		res->h_name = tbuf; tbuf+=name_len;
835 		/* now the aliases */
836 		res->h_aliases = tp;
837 		if ( src->h_aliases != NULL ) {
838 			tbuf = cpy_aliases( &tp, tbuf, src->h_aliases );
839 		}
840 		*tp++=NULL;
841 		/* finally the addresses */
842 		res->h_addr_list = tp;
843 		if ( src->h_addr_list != NULL ) {
844 			tbuf = cpy_addresses( &tp, tbuf, src->h_addr_list, src->h_length );
845 		}
846 		*tp++=NULL;
847 		return 0;
848 	}
849 	return -1;
850 }
851 #endif
852 
853 #if defined( NEED_SAFE_REALLOC )
safe_realloc(char ** buf,int len)854 static char *safe_realloc( char **buf, int len )
855 {
856 	char *tmpbuf;
857 	tmpbuf = LDAP_REALLOC( *buf, len );
858 	if (tmpbuf) {
859 		*buf=tmpbuf;
860 	}
861 	return tmpbuf;
862 }
863 #endif
864 
ldap_pvt_get_fqdn(char * name)865 char * ldap_pvt_get_fqdn( char *name )
866 {
867 #ifdef HAVE_GETADDRINFO
868 	struct addrinfo hints, *res;
869 #else
870 	char *ha_buf;
871 	struct hostent *hp, he_buf;
872 	int local_h_errno;
873 #endif
874 	int rc;
875 	char *fqdn, hostbuf[MAXHOSTNAMELEN+1];
876 
877 	if( name == NULL ) {
878 		if( gethostname( hostbuf, MAXHOSTNAMELEN ) == 0 ) {
879 			hostbuf[MAXHOSTNAMELEN] = '\0';
880 			name = hostbuf;
881 		} else {
882 			name = "localhost";
883 		}
884 	}
885 
886 #ifdef HAVE_GETADDRINFO
887 	memset( &hints, 0, sizeof( hints ));
888 	hints.ai_family = AF_UNSPEC;
889 	hints.ai_flags = AI_CANONNAME;
890 
891 	LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex );
892 	rc = getaddrinfo( name, NULL, &hints, &res );
893 	LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex );
894 	if ( rc == 0 && res->ai_canonname ) {
895 		fqdn = LDAP_STRDUP( res->ai_canonname );
896 	} else {
897 		fqdn = LDAP_STRDUP( name );
898 	}
899 	if ( rc == 0 )
900 		freeaddrinfo( res );
901 #else
902 	rc = ldap_pvt_gethostbyname_a( name,
903 		&he_buf, &ha_buf, &hp, &local_h_errno );
904 
905 	if( rc < 0 || hp == NULL || hp->h_name == NULL ) {
906 		fqdn = LDAP_STRDUP( name );
907 	} else {
908 		fqdn = LDAP_STRDUP( hp->h_name );
909 	}
910 
911 	LDAP_FREE( ha_buf );
912 #endif
913 	return fqdn;
914 }
915 
916 #if ( defined( HAVE_GETADDRINFO ) || defined( HAVE_GETNAMEINFO ) ) \
917 	&& !defined( HAVE_GAI_STRERROR )
ldap_pvt_gai_strerror(int code)918 char *ldap_pvt_gai_strerror (int code) {
919 	static struct {
920 		int code;
921 		const char *msg;
922 	} values[] = {
923 #ifdef EAI_ADDRFAMILY
924 		{ EAI_ADDRFAMILY, N_("Address family for hostname not supported") },
925 #endif
926 		{ EAI_AGAIN, N_("Temporary failure in name resolution") },
927 		{ EAI_BADFLAGS, N_("Bad value for ai_flags") },
928 		{ EAI_FAIL, N_("Non-recoverable failure in name resolution") },
929 		{ EAI_FAMILY, N_("ai_family not supported") },
930 		{ EAI_MEMORY, N_("Memory allocation failure") },
931 #ifdef EAI_NODATA
932 		{ EAI_NODATA, N_("No address associated with hostname") },
933 #endif
934 		{ EAI_NONAME, N_("Name or service not known") },
935 		{ EAI_SERVICE, N_("Servname not supported for ai_socktype") },
936 		{ EAI_SOCKTYPE, N_("ai_socktype not supported") },
937 #ifdef EAI_SYSTEM
938 		{ EAI_SYSTEM, N_("System error") },
939 #endif
940 		{ 0, NULL }
941 	};
942 
943 	int i;
944 
945 	for ( i = 0; values[i].msg != NULL; i++ ) {
946 		if ( values[i].code == code ) {
947 			return (char *) _(values[i].msg);
948 		}
949 	}
950 
951 	return _("Unknown error");
952 }
953 #endif
954 
955 /* format a socket address as a string */
956 
957 #ifdef HAVE_TCPD
958 # include <tcpd.h>
959 # define SOCKADDR_STRING_UNKNOWN	STRING_UNKNOWN
960 #else /* ! TCP Wrappers */
961 # define SOCKADDR_STRING_UNKNOWN	"unknown"
962 #endif /* ! TCP Wrappers */
963 
964 void
ldap_pvt_sockaddrstr(Sockaddr * sa,struct berval * addrbuf)965 ldap_pvt_sockaddrstr( Sockaddr *sa, struct berval *addrbuf )
966 {
967 	char *addr;
968 	switch( sa->sa_addr.sa_family ) {
969 #ifdef LDAP_PF_LOCAL
970 	case AF_LOCAL:
971 		addrbuf->bv_len = snprintf( addrbuf->bv_val, addrbuf->bv_len,
972 			"PATH=%s", sa->sa_un_addr.sun_path );
973 		break;
974 #endif
975 #ifdef LDAP_PF_INET6
976 	case AF_INET6:
977 		strcpy(addrbuf->bv_val, "IP=");
978 		if ( IN6_IS_ADDR_V4MAPPED(&sa->sa_in6_addr.sin6_addr) ) {
979 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
980 			addr = (char *)inet_ntop( AF_INET,
981 			   ((struct in_addr *)&sa->sa_in6_addr.sin6_addr.s6_addr[12]),
982 			   addrbuf->bv_val+3, addrbuf->bv_len-3 );
983 #else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
984 			addr = inet_ntoa( *((struct in_addr *)
985 					&sa->sa_in6_addr.sin6_addr.s6_addr[12]) );
986 #endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
987 			if ( !addr ) addr = SOCKADDR_STRING_UNKNOWN;
988 			if ( addr != addrbuf->bv_val+3 ) {
989 				addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "%s:%d", addr,
990 				 (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + 3;
991 			} else {
992 				int len = strlen( addr );
993 				addrbuf->bv_len = sprintf( addr+len, ":%d",
994 				 (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + len + 3;
995 			}
996 		} else {
997 			addr = (char *)inet_ntop( AF_INET6,
998 				      &sa->sa_in6_addr.sin6_addr,
999 				      addrbuf->bv_val+4, addrbuf->bv_len-4 );
1000 			if ( !addr ) addr = SOCKADDR_STRING_UNKNOWN;
1001 			if ( addr != addrbuf->bv_val+4 ) {
1002 				addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "[%s]:%d", addr,
1003 				 (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + 3;
1004 			} else {
1005 				int len = strlen( addr );
1006 				addrbuf->bv_val[3] = '[';
1007 				addrbuf->bv_len = sprintf( addr+len, "]:%d",
1008 				 (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + len + 4;
1009 			}
1010 		}
1011 		break;
1012 #endif /* LDAP_PF_INET6 */
1013 	case AF_INET:
1014 		strcpy(addrbuf->bv_val, "IP=");
1015 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
1016 		addr = (char *)inet_ntop( AF_INET, &sa->sa_in_addr.sin_addr,
1017 			   addrbuf->bv_val+3, addrbuf->bv_len-3 );
1018 #else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
1019 		addr = inet_ntoa( sa->sa_in_addr.sin_addr );
1020 #endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
1021 		if ( !addr ) addr = SOCKADDR_STRING_UNKNOWN;
1022 		if ( addr != addrbuf->bv_val+3 ) {
1023 			addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "%s:%d", addr,
1024 			 (unsigned) ntohs( sa->sa_in_addr.sin_port ) ) + 3;
1025 		} else {
1026 			int len = strlen( addr );
1027 			addrbuf->bv_len = sprintf( addr+len, ":%d",
1028 			 (unsigned) ntohs( sa->sa_in_addr.sin_port ) ) + len + 3;
1029 		}
1030 		break;
1031 	default:
1032 		addrbuf->bv_val[0] = '\0';
1033 	}
1034 }
1035