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