1 /* $NetBSD: util-int.c,v 1.4 2025/09/05 21:16:22 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2024 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.4 2025/09/05 21:16:22 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 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 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 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 * 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 * 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_start_count; 191 static long _ldap_pvt_gt_start_sec; 192 static long _ldap_pvt_gt_start_nsec; 193 static double _ldap_pvt_gt_nanoticks; 194 195 #define SEC_TO_UNIX_EPOCH 11644473600LL 196 #define TICKS_PER_SECOND 10000000 197 #define BILLION 1000000000L 198 199 static int 200 ldap_pvt_gettimensec(long *sec) 201 { 202 LARGE_INTEGER count; 203 LARGE_INTEGER freq; 204 int nsec; 205 206 QueryPerformanceFrequency( &freq ); 207 /* We assume Windows has at least a vague idea of 208 * when a second begins. So we align our nanosecond count 209 * with the Windows millisecond count. 210 */ 211 if ( freq.QuadPart != _ldap_pvt_gt_freq.QuadPart ) { 212 ULARGE_INTEGER ut; 213 FILETIME ft0, ft1; 214 /* initialize */ 215 LDAP_MUTEX_LOCK( &ldap_int_gettime_mutex ); 216 /* Wait for a tick of the system time: 10-15ms */ 217 GetSystemTimeAsFileTime( &ft0 ); 218 do { 219 GetSystemTimeAsFileTime( &ft1 ); 220 } while ( ft1.dwLowDateTime == ft0.dwLowDateTime ); 221 QueryPerformanceCounter( &_ldap_pvt_gt_start_count ); 222 223 ut.LowPart = ft1.dwLowDateTime; 224 ut.HighPart = ft1.dwHighDateTime; 225 _ldap_pvt_gt_start_nsec = ut.QuadPart % TICKS_PER_SECOND * 100; 226 _ldap_pvt_gt_start_sec = ut.QuadPart / TICKS_PER_SECOND - SEC_TO_UNIX_EPOCH; 227 _ldap_pvt_gt_freq = freq; 228 _ldap_pvt_gt_nanoticks = (double)BILLION / freq.QuadPart; 229 LDAP_MUTEX_UNLOCK( &ldap_int_gettime_mutex ); 230 } 231 QueryPerformanceCounter( &count ); 232 count.QuadPart -= _ldap_pvt_gt_start_count.QuadPart; 233 *sec = _ldap_pvt_gt_start_sec + count.QuadPart / freq.QuadPart; 234 nsec = _ldap_pvt_gt_start_nsec + (double)(count.QuadPart % freq.QuadPart) * _ldap_pvt_gt_nanoticks; 235 if ( nsec > BILLION) { 236 nsec -= BILLION; 237 (*sec)++; 238 } 239 return nsec; 240 } 241 242 /* emulate POSIX clock_gettime */ 243 int 244 ldap_pvt_clock_gettime( int clk_id, struct timespec *tv ) 245 { 246 long sec; 247 tv->tv_nsec = ldap_pvt_gettimensec( &sec ); 248 tv->tv_sec = sec; 249 return 0; 250 } 251 252 /* emulate POSIX gettimeofday */ 253 int 254 ldap_pvt_gettimeofday( struct timeval *tv, void *unused ) 255 { 256 struct timespec ts; 257 ldap_pvt_clock_gettime( 0, &ts ); 258 tv->tv_sec = ts.tv_sec; 259 tv->tv_usec = ts.tv_nsec / 1000; 260 return 0; 261 } 262 263 static long _ldap_pvt_gt_prevsec; 264 static int _ldap_pvt_gt_prevnsec; 265 266 /* return a broken out time, with nanoseconds 267 */ 268 void 269 ldap_pvt_gettime( struct lutil_tm *tm ) 270 { 271 SYSTEMTIME st; 272 LARGE_INTEGER ft; 273 long sec; 274 275 /* Convert sec/nsec to Windows FILETIME, 276 * then turn that into broken out SYSTEMTIME */ 277 tm->tm_nsec = ldap_pvt_gettimensec(&sec); 278 ft.QuadPart = sec; 279 ft.QuadPart += SEC_TO_UNIX_EPOCH; 280 ft.QuadPart *= TICKS_PER_SECOND; 281 ft.QuadPart += tm->tm_nsec / 100; 282 FileTimeToSystemTime( (FILETIME *)&ft, &st ); 283 284 tm->tm_sec = st.wSecond; 285 tm->tm_min = st.wMinute; 286 tm->tm_hour = st.wHour; 287 tm->tm_mday = st.wDay; 288 tm->tm_mon = st.wMonth - 1; 289 tm->tm_year = st.wYear - 1900; 290 291 LDAP_MUTEX_LOCK( &ldap_int_gettime_mutex ); 292 if ( tm->tm_sec < _ldap_pvt_gt_prevsec 293 || ( tm->tm_sec == _ldap_pvt_gt_prevsec 294 && tm->tm_nsec <= _ldap_pvt_gt_prevnsec )) { 295 _ldap_pvt_gt_subs++; 296 } else { 297 _ldap_pvt_gt_subs = 0; 298 _ldap_pvt_gt_prevsec = sec; 299 _ldap_pvt_gt_prevnsec = tm->tm_nsec; 300 } 301 LDAP_MUTEX_UNLOCK( &ldap_int_gettime_mutex ); 302 tm->tm_usub = _ldap_pvt_gt_subs; 303 } 304 #else 305 306 #ifdef HAVE_CLOCK_GETTIME 307 static struct timespec _ldap_pvt_gt_prevTv; 308 #else 309 static struct timeval _ldap_pvt_gt_prevTv; 310 #endif 311 312 void 313 ldap_pvt_gettime( struct lutil_tm *ltm ) 314 { 315 struct tm tm; 316 time_t t; 317 #ifdef HAVE_CLOCK_GETTIME 318 #define FRAC tv_nsec 319 #define NSECS(x) x 320 struct timespec tv; 321 322 clock_gettime( CLOCK_REALTIME, &tv ); 323 #else 324 #define FRAC tv_usec 325 #define NSECS(x) x * 1000 326 struct timeval tv; 327 328 gettimeofday( &tv, NULL ); 329 #endif 330 t = tv.tv_sec; 331 332 LDAP_MUTEX_LOCK( &ldap_int_gettime_mutex ); 333 if ( tv.tv_sec < _ldap_pvt_gt_prevTv.tv_sec 334 || ( tv.tv_sec == _ldap_pvt_gt_prevTv.tv_sec 335 && tv.FRAC <= _ldap_pvt_gt_prevTv.FRAC )) { 336 _ldap_pvt_gt_subs++; 337 } else { 338 _ldap_pvt_gt_subs = 0; 339 _ldap_pvt_gt_prevTv = tv; 340 } 341 LDAP_MUTEX_UNLOCK( &ldap_int_gettime_mutex ); 342 343 ltm->tm_usub = _ldap_pvt_gt_subs; 344 345 ldap_pvt_gmtime( &t, &tm ); 346 347 ltm->tm_sec = tm.tm_sec; 348 ltm->tm_min = tm.tm_min; 349 ltm->tm_hour = tm.tm_hour; 350 ltm->tm_mday = tm.tm_mday; 351 ltm->tm_mon = tm.tm_mon; 352 ltm->tm_year = tm.tm_year; 353 ltm->tm_nsec = NSECS(tv.FRAC); 354 } 355 #endif 356 357 size_t 358 ldap_pvt_csnstr(char *buf, size_t len, unsigned int replica, unsigned int mod) 359 { 360 struct lutil_tm tm; 361 int n; 362 363 ldap_pvt_gettime( &tm ); 364 365 n = snprintf( buf, len, 366 "%4d%02d%02d%02d%02d%02d.%06dZ#%06x#%03x#%06x", 367 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, 368 tm.tm_min, tm.tm_sec, tm.tm_nsec / 1000, tm.tm_usub, replica, mod ); 369 370 if( n < 0 ) return 0; 371 return ( (size_t) n < len ) ? n : 0; 372 } 373 374 #define BUFSTART (1024-32) 375 #define BUFMAX (32*1024-32) 376 377 #if defined(LDAP_R_COMPILE) 378 static char *safe_realloc( char **buf, int len ); 379 380 #if !(defined(HAVE_GETHOSTBYNAME_R) && defined(HAVE_GETHOSTBYADDR_R)) 381 static int copy_hostent( struct hostent *res, 382 char **buf, struct hostent * src ); 383 #endif 384 #endif 385 386 int ldap_pvt_gethostbyname_a( 387 const char *name, 388 struct hostent *resbuf, 389 char **buf, 390 struct hostent **result, 391 int *herrno_ptr ) 392 { 393 #if defined( HAVE_GETHOSTBYNAME_R ) 394 395 # define NEED_SAFE_REALLOC 1 396 int r=-1; 397 int buflen=BUFSTART; 398 *buf = NULL; 399 for(;buflen<BUFMAX;) { 400 if (safe_realloc( buf, buflen )==NULL) 401 return r; 402 403 #if (GETHOSTBYNAME_R_NARGS < 6) 404 *result=gethostbyname_r( name, resbuf, *buf, buflen, herrno_ptr ); 405 r = (*result == NULL) ? -1 : 0; 406 #else 407 while((r = gethostbyname_r( name, resbuf, *buf, buflen, result, herrno_ptr )) == ERANGE) { 408 /* Increase the buffer */ 409 buflen*=2; 410 if (safe_realloc(buf, buflen) == NULL) 411 return -1; 412 } 413 #endif 414 415 Debug2( LDAP_DEBUG_TRACE, "ldap_pvt_gethostbyname_a: host=%s, r=%d\n", 416 name, r ); 417 418 #ifdef NETDB_INTERNAL 419 if ((r<0) && 420 (*herrno_ptr==NETDB_INTERNAL) && 421 (errno==ERANGE)) 422 { 423 buflen*=2; 424 continue; 425 } 426 #endif 427 return r; 428 } 429 return -1; 430 #elif defined( LDAP_R_COMPILE ) 431 # define NEED_COPY_HOSTENT 432 struct hostent *he; 433 int retval; 434 *buf = NULL; 435 436 LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex ); 437 438 he = gethostbyname( name ); 439 440 if (he==NULL) { 441 *herrno_ptr = h_errno; 442 retval = -1; 443 } else if (copy_hostent( resbuf, buf, he )<0) { 444 *herrno_ptr = -1; 445 retval = -1; 446 } else { 447 *result = resbuf; 448 retval = 0; 449 } 450 451 LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex ); 452 453 return retval; 454 #else 455 *buf = NULL; 456 *result = gethostbyname( name ); 457 458 if (*result!=NULL) { 459 return 0; 460 } 461 462 *herrno_ptr = h_errno; 463 464 return -1; 465 #endif 466 } 467 468 #if !defined( HAVE_GETNAMEINFO ) && !defined( HAVE_HSTRERROR ) 469 static const char * 470 hp_strerror( int err ) 471 { 472 switch (err) { 473 case HOST_NOT_FOUND: return _("Host not found (authoritative)"); 474 case TRY_AGAIN: return _("Host not found (server fail?)"); 475 case NO_RECOVERY: return _("Non-recoverable failure"); 476 case NO_DATA: return _("No data of requested type"); 477 #ifdef NETDB_INTERNAL 478 case NETDB_INTERNAL: return STRERROR( errno ); 479 #endif 480 } 481 return _("Unknown resolver error"); 482 } 483 #endif 484 485 int ldap_pvt_get_hname( 486 const struct sockaddr *sa, 487 int len, 488 char *name, 489 int namelen, 490 char **err ) 491 { 492 int rc; 493 #if defined( HAVE_GETNAMEINFO ) 494 495 LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex ); 496 rc = getnameinfo( sa, len, name, namelen, NULL, 0, 0 ); 497 LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex ); 498 if ( rc ) *err = (char *)AC_GAI_STRERROR( rc ); 499 return rc; 500 501 #else /* !HAVE_GETNAMEINFO */ 502 char *addr; 503 int alen; 504 struct hostent *hp = NULL; 505 #ifdef HAVE_GETHOSTBYADDR_R 506 struct hostent hb; 507 int buflen=BUFSTART, h_errno; 508 char *buf=NULL; 509 #endif 510 511 #ifdef LDAP_PF_INET6 512 if (sa->sa_family == AF_INET6) { 513 struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa; 514 addr = (char *)&sin->sin6_addr; 515 alen = sizeof(sin->sin6_addr); 516 } else 517 #endif 518 if (sa->sa_family == AF_INET) { 519 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 520 addr = (char *)&sin->sin_addr; 521 alen = sizeof(sin->sin_addr); 522 } else { 523 rc = NO_RECOVERY; 524 *err = (char *)HSTRERROR( rc ); 525 return rc; 526 } 527 #if defined( HAVE_GETHOSTBYADDR_R ) 528 for(;buflen<BUFMAX;) { 529 if (safe_realloc( &buf, buflen )==NULL) { 530 *err = (char *)STRERROR( ENOMEM ); 531 return ENOMEM; 532 } 533 #if (GETHOSTBYADDR_R_NARGS < 8) 534 hp=gethostbyaddr_r( addr, alen, sa->sa_family, 535 &hb, buf, buflen, &h_errno ); 536 rc = (hp == NULL) ? -1 : 0; 537 #else 538 rc = gethostbyaddr_r( addr, alen, sa->sa_family, 539 &hb, buf, buflen, 540 &hp, &h_errno ); 541 #endif 542 #ifdef NETDB_INTERNAL 543 if ((rc<0) && 544 (h_errno==NETDB_INTERNAL) && 545 (errno==ERANGE)) 546 { 547 buflen*=2; 548 continue; 549 } 550 #endif 551 break; 552 } 553 if (hp) { 554 strncpy( name, hp->h_name, namelen ); 555 } else { 556 *err = (char *)HSTRERROR( h_errno ); 557 } 558 LDAP_FREE(buf); 559 #else /* HAVE_GETHOSTBYADDR_R */ 560 561 LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex ); 562 hp = gethostbyaddr( addr, alen, sa->sa_family ); 563 if (hp) { 564 strncpy( name, hp->h_name, namelen ); 565 rc = 0; 566 } else { 567 rc = h_errno; 568 *err = (char *)HSTRERROR( h_errno ); 569 } 570 LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex ); 571 572 #endif /* !HAVE_GETHOSTBYADDR_R */ 573 return rc; 574 #endif /* !HAVE_GETNAMEINFO */ 575 } 576 577 int ldap_pvt_gethostbyaddr_a( 578 const char *addr, 579 int len, 580 int type, 581 struct hostent *resbuf, 582 char **buf, 583 struct hostent **result, 584 int *herrno_ptr ) 585 { 586 #if defined( HAVE_GETHOSTBYADDR_R ) 587 588 # undef NEED_SAFE_REALLOC 589 # define NEED_SAFE_REALLOC 590 int r=-1; 591 int buflen=BUFSTART; 592 *buf = NULL; 593 for(;buflen<BUFMAX;) { 594 if (safe_realloc( buf, buflen )==NULL) 595 return r; 596 #if (GETHOSTBYADDR_R_NARGS < 8) 597 *result=gethostbyaddr_r( addr, len, type, 598 resbuf, *buf, buflen, herrno_ptr ); 599 r = (*result == NULL) ? -1 : 0; 600 #else 601 r = gethostbyaddr_r( addr, len, type, 602 resbuf, *buf, buflen, 603 result, herrno_ptr ); 604 #endif 605 606 #ifdef NETDB_INTERNAL 607 if ((r<0) && 608 (*herrno_ptr==NETDB_INTERNAL) && 609 (errno==ERANGE)) 610 { 611 buflen*=2; 612 continue; 613 } 614 #endif 615 return r; 616 } 617 return -1; 618 #elif defined( LDAP_R_COMPILE ) 619 # undef NEED_COPY_HOSTENT 620 # define NEED_COPY_HOSTENT 621 struct hostent *he; 622 int retval; 623 *buf = NULL; 624 625 LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex ); 626 he = gethostbyaddr( addr, len, type ); 627 628 if (he==NULL) { 629 *herrno_ptr = h_errno; 630 retval = -1; 631 } else if (copy_hostent( resbuf, buf, he )<0) { 632 *herrno_ptr = -1; 633 retval = -1; 634 } else { 635 *result = resbuf; 636 retval = 0; 637 } 638 LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex ); 639 640 return retval; 641 642 #else /* gethostbyaddr() */ 643 *buf = NULL; 644 *result = gethostbyaddr( addr, len, type ); 645 646 if (*result!=NULL) { 647 return 0; 648 } 649 return -1; 650 #endif 651 } 652 /* 653 * ldap_int_utils_init() should be called before any other function. 654 */ 655 656 void ldap_int_utils_init( void ) 657 { 658 static int done=0; 659 if (done) 660 return; 661 done=1; 662 663 #ifdef LDAP_R_COMPILE 664 #if !defined( USE_CTIME_R ) && !defined( HAVE_REENTRANT_FUNCTIONS ) 665 ldap_pvt_thread_mutex_init( &ldap_int_ctime_mutex ); 666 #endif 667 #if !defined( USE_GMTIME_R ) && !defined( USE_LOCALTIME_R ) 668 ldap_pvt_thread_mutex_init( &ldap_int_gmtime_mutex ); 669 #endif 670 ldap_pvt_thread_mutex_init( &ldap_int_resolv_mutex ); 671 672 ldap_pvt_thread_mutex_init( &ldap_int_hostname_mutex ); 673 674 ldap_pvt_thread_mutex_init( &ldap_int_gettime_mutex ); 675 676 #ifdef HAVE_GSSAPI 677 ldap_pvt_thread_mutex_init( &ldap_int_gssapi_mutex ); 678 #endif 679 #endif 680 681 /* call other module init functions here... */ 682 } 683 684 #if defined( NEED_COPY_HOSTENT ) 685 # undef NEED_SAFE_REALLOC 686 #define NEED_SAFE_REALLOC 687 688 static char *cpy_aliases( 689 char ***tgtio, 690 char *buf, 691 char **src ) 692 { 693 int len; 694 char **tgt=*tgtio; 695 for( ; (*src) ; src++ ) { 696 len = strlen( *src ) + 1; 697 AC_MEMCPY( buf, *src, len ); 698 *tgt++=buf; 699 buf+=len; 700 } 701 *tgtio=tgt; 702 return buf; 703 } 704 705 static char *cpy_addresses( 706 char ***tgtio, 707 char *buf, 708 char **src, 709 int len ) 710 { 711 char **tgt=*tgtio; 712 for( ; (*src) ; src++ ) { 713 AC_MEMCPY( buf, *src, len ); 714 *tgt++=buf; 715 buf+=len; 716 } 717 *tgtio=tgt; 718 return buf; 719 } 720 721 static int copy_hostent( 722 struct hostent *res, 723 char **buf, 724 struct hostent * src ) 725 { 726 char **p; 727 char **tp; 728 char *tbuf; 729 int name_len; 730 int n_alias=0; 731 int total_alias_len=0; 732 int n_addr=0; 733 int total_addr_len=0; 734 int total_len; 735 736 /* calculate the size needed for the buffer */ 737 name_len = strlen( src->h_name ) + 1; 738 739 if( src->h_aliases != NULL ) { 740 for( p = src->h_aliases; (*p) != NULL; p++ ) { 741 total_alias_len += strlen( *p ) + 1; 742 n_alias++; 743 } 744 } 745 746 if( src->h_addr_list != NULL ) { 747 for( p = src->h_addr_list; (*p) != NULL; p++ ) { 748 n_addr++; 749 } 750 total_addr_len = n_addr * src->h_length; 751 } 752 753 total_len = (n_alias + n_addr + 2) * sizeof( char * ) + 754 total_addr_len + total_alias_len + name_len; 755 756 if (safe_realloc( buf, total_len )) { 757 tp = (char **) *buf; 758 tbuf = *buf + (n_alias + n_addr + 2) * sizeof( char * ); 759 AC_MEMCPY( res, src, sizeof( struct hostent ) ); 760 /* first the name... */ 761 AC_MEMCPY( tbuf, src->h_name, name_len ); 762 res->h_name = tbuf; tbuf+=name_len; 763 /* now the aliases */ 764 res->h_aliases = tp; 765 if ( src->h_aliases != NULL ) { 766 tbuf = cpy_aliases( &tp, tbuf, src->h_aliases ); 767 } 768 *tp++=NULL; 769 /* finally the addresses */ 770 res->h_addr_list = tp; 771 if ( src->h_addr_list != NULL ) { 772 tbuf = cpy_addresses( &tp, tbuf, src->h_addr_list, src->h_length ); 773 } 774 *tp++=NULL; 775 return 0; 776 } 777 return -1; 778 } 779 #endif 780 781 #if defined( NEED_SAFE_REALLOC ) 782 static char *safe_realloc( char **buf, int len ) 783 { 784 char *tmpbuf; 785 tmpbuf = LDAP_REALLOC( *buf, len ); 786 if (tmpbuf) { 787 *buf=tmpbuf; 788 } 789 return tmpbuf; 790 } 791 #endif 792 793 char * ldap_pvt_get_fqdn( char *name ) 794 { 795 #ifdef HAVE_GETADDRINFO 796 struct addrinfo hints, *res; 797 #else 798 char *ha_buf; 799 struct hostent *hp, he_buf; 800 int local_h_errno; 801 #endif 802 int rc; 803 char *fqdn, hostbuf[MAXHOSTNAMELEN+1]; 804 805 if( name == NULL ) { 806 if( gethostname( hostbuf, MAXHOSTNAMELEN ) == 0 ) { 807 hostbuf[MAXHOSTNAMELEN] = '\0'; 808 name = hostbuf; 809 } else { 810 name = "localhost"; 811 } 812 } 813 814 #ifdef HAVE_GETADDRINFO 815 memset( &hints, 0, sizeof( hints )); 816 hints.ai_family = AF_UNSPEC; 817 hints.ai_flags = AI_CANONNAME; 818 819 LDAP_MUTEX_LOCK( &ldap_int_resolv_mutex ); 820 rc = getaddrinfo( name, NULL, &hints, &res ); 821 LDAP_MUTEX_UNLOCK( &ldap_int_resolv_mutex ); 822 if ( rc == 0 && res->ai_canonname ) { 823 fqdn = LDAP_STRDUP( res->ai_canonname ); 824 } else { 825 fqdn = LDAP_STRDUP( name ); 826 } 827 if ( rc == 0 ) 828 freeaddrinfo( res ); 829 #else 830 rc = ldap_pvt_gethostbyname_a( name, 831 &he_buf, &ha_buf, &hp, &local_h_errno ); 832 833 if( rc < 0 || hp == NULL || hp->h_name == NULL ) { 834 fqdn = LDAP_STRDUP( name ); 835 } else { 836 fqdn = LDAP_STRDUP( hp->h_name ); 837 } 838 839 LDAP_FREE( ha_buf ); 840 #endif 841 return fqdn; 842 } 843 844 #if ( defined( HAVE_GETADDRINFO ) || defined( HAVE_GETNAMEINFO ) ) \ 845 && !defined( HAVE_GAI_STRERROR ) 846 char *ldap_pvt_gai_strerror (int code) { 847 static struct { 848 int code; 849 const char *msg; 850 } values[] = { 851 #ifdef EAI_ADDRFAMILY 852 { EAI_ADDRFAMILY, N_("Address family for hostname not supported") }, 853 #endif 854 { EAI_AGAIN, N_("Temporary failure in name resolution") }, 855 { EAI_BADFLAGS, N_("Bad value for ai_flags") }, 856 { EAI_FAIL, N_("Non-recoverable failure in name resolution") }, 857 { EAI_FAMILY, N_("ai_family not supported") }, 858 { EAI_MEMORY, N_("Memory allocation failure") }, 859 #ifdef EAI_NODATA 860 { EAI_NODATA, N_("No address associated with hostname") }, 861 #endif 862 { EAI_NONAME, N_("Name or service not known") }, 863 { EAI_SERVICE, N_("Servname not supported for ai_socktype") }, 864 { EAI_SOCKTYPE, N_("ai_socktype not supported") }, 865 #ifdef EAI_SYSTEM 866 { EAI_SYSTEM, N_("System error") }, 867 #endif 868 { 0, NULL } 869 }; 870 871 int i; 872 873 for ( i = 0; values[i].msg != NULL; i++ ) { 874 if ( values[i].code == code ) { 875 return (char *) _(values[i].msg); 876 } 877 } 878 879 return _("Unknown error"); 880 } 881 #endif 882 883 /* format a socket address as a string */ 884 885 #ifdef HAVE_TCPD 886 # include <tcpd.h> 887 # define SOCKADDR_STRING_UNKNOWN STRING_UNKNOWN 888 #else /* ! TCP Wrappers */ 889 # define SOCKADDR_STRING_UNKNOWN "unknown" 890 #endif /* ! TCP Wrappers */ 891 892 void 893 ldap_pvt_sockaddrstr( Sockaddr *sa, struct berval *addrbuf ) 894 { 895 char *addr; 896 switch( sa->sa_addr.sa_family ) { 897 #ifdef LDAP_PF_LOCAL 898 case AF_LOCAL: 899 addrbuf->bv_len = snprintf( addrbuf->bv_val, addrbuf->bv_len, 900 "PATH=%s", sa->sa_un_addr.sun_path ); 901 break; 902 #endif 903 #ifdef LDAP_PF_INET6 904 case AF_INET6: 905 strcpy(addrbuf->bv_val, "IP="); 906 if ( IN6_IS_ADDR_V4MAPPED(&sa->sa_in6_addr.sin6_addr) ) { 907 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) 908 addr = (char *)inet_ntop( AF_INET, 909 ((struct in_addr *)&sa->sa_in6_addr.sin6_addr.s6_addr[12]), 910 addrbuf->bv_val+3, addrbuf->bv_len-3 ); 911 #else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ 912 addr = inet_ntoa( *((struct in_addr *) 913 &sa->sa_in6_addr.sin6_addr.s6_addr[12]) ); 914 #endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ 915 if ( !addr ) addr = SOCKADDR_STRING_UNKNOWN; 916 if ( addr != addrbuf->bv_val+3 ) { 917 addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "%s:%d", addr, 918 (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + 3; 919 } else { 920 int len = strlen( addr ); 921 addrbuf->bv_len = sprintf( addr+len, ":%d", 922 (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + len + 3; 923 } 924 } else { 925 addr = (char *)inet_ntop( AF_INET6, 926 &sa->sa_in6_addr.sin6_addr, 927 addrbuf->bv_val+4, addrbuf->bv_len-4 ); 928 if ( !addr ) addr = SOCKADDR_STRING_UNKNOWN; 929 if ( addr != addrbuf->bv_val+4 ) { 930 addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "[%s]:%d", addr, 931 (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + 3; 932 } else { 933 int len = strlen( addr ); 934 addrbuf->bv_val[3] = '['; 935 addrbuf->bv_len = sprintf( addr+len, "]:%d", 936 (unsigned) ntohs( sa->sa_in6_addr.sin6_port ) ) + len + 4; 937 } 938 } 939 break; 940 #endif /* LDAP_PF_INET6 */ 941 case AF_INET: 942 strcpy(addrbuf->bv_val, "IP="); 943 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) 944 addr = (char *)inet_ntop( AF_INET, &sa->sa_in_addr.sin_addr, 945 addrbuf->bv_val+3, addrbuf->bv_len-3 ); 946 #else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ 947 addr = inet_ntoa( sa->sa_in_addr.sin_addr ); 948 #endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */ 949 if ( !addr ) addr = SOCKADDR_STRING_UNKNOWN; 950 if ( addr != addrbuf->bv_val+3 ) { 951 addrbuf->bv_len = sprintf( addrbuf->bv_val+3, "%s:%d", addr, 952 (unsigned) ntohs( sa->sa_in_addr.sin_port ) ) + 3; 953 } else { 954 int len = strlen( addr ); 955 addrbuf->bv_len = sprintf( addr+len, ":%d", 956 (unsigned) ntohs( sa->sa_in_addr.sin_port ) ) + len + 3; 957 } 958 break; 959 default: 960 addrbuf->bv_val[0] = '\0'; 961 } 962 } 963