1 /* $NetBSD: util-int.c,v 1.1.1.2 2010/03/08 02:14:20 lukem Exp $ */ 2 3 /* OpenLDAP: pkg/ldap/libraries/libldap/util-int.c,v 1.57.2.5 2009/01/22 00:00:56 kurt Exp */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2009 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 "portable.h" 30 31 #include <ac/stdlib.h> 32 33 #include <ac/errno.h> 34 #include <ac/socket.h> 35 #include <ac/string.h> 36 #include <ac/time.h> 37 #include <ac/unistd.h> 38 39 #include "ldap-int.h" 40 41 #ifndef h_errno 42 /* newer systems declare this in <netdb.h> for you, older ones don't. 43 * harmless to declare it again (unless defined by a macro). 44 */ 45 extern int h_errno; 46 #endif 47 48 #ifdef HAVE_HSTRERROR 49 # define HSTRERROR(e) hstrerror(e) 50 #else 51 # define HSTRERROR(e) hp_strerror(e) 52 #endif 53 54 #ifndef LDAP_R_COMPILE 55 # undef HAVE_REENTRANT_FUNCTIONS 56 # undef HAVE_CTIME_R 57 # undef HAVE_GETHOSTBYNAME_R 58 # undef HAVE_GETHOSTBYADDR_R 59 60 #else 61 # include <ldap_pvt_thread.h> 62 ldap_pvt_thread_mutex_t ldap_int_resolv_mutex; 63 64 # if (defined( HAVE_CTIME_R ) || defined( HAVE_REENTRANT_FUNCTIONS)) \ 65 && defined( CTIME_R_NARGS ) 66 # define USE_CTIME_R 67 # else 68 static ldap_pvt_thread_mutex_t ldap_int_ctime_mutex; 69 # endif 70 71 # if defined(HAVE_GETHOSTBYNAME_R) && \ 72 (GETHOSTBYNAME_R_NARGS < 5) || (6 < GETHOSTBYNAME_R_NARGS) 73 /* Don't know how to handle this version, pretend it's not there */ 74 # undef HAVE_GETHOSTBYNAME_R 75 # endif 76 # if defined(HAVE_GETHOSTBYADDR_R) && \ 77 (GETHOSTBYADDR_R_NARGS < 7) || (8 < GETHOSTBYADDR_R_NARGS) 78 /* Don't know how to handle this version, pretend it's not there */ 79 # undef HAVE_GETHOSTBYADDR_R 80 # endif 81 #endif /* LDAP_R_COMPILE */ 82 83 char *ldap_pvt_ctime( const time_t *tp, char *buf ) 84 { 85 #ifdef USE_CTIME_R 86 # if (CTIME_R_NARGS > 3) || (CTIME_R_NARGS < 2) 87 # error "CTIME_R_NARGS should be 2 or 3" 88 # elif CTIME_R_NARGS > 2 && defined(CTIME_R_RETURNS_INT) 89 return( ctime_r(tp,buf,26) < 0 ? 0 : buf ); 90 # elif CTIME_R_NARGS > 2 91 return ctime_r(tp,buf,26); 92 # else 93 return ctime_r(tp,buf); 94 # endif 95 96 #else 97 98 # ifdef LDAP_R_COMPILE 99 ldap_pvt_thread_mutex_lock( &ldap_int_ctime_mutex ); 100 # endif 101 102 AC_MEMCPY( buf, ctime(tp), 26 ); 103 104 # ifdef LDAP_R_COMPILE 105 ldap_pvt_thread_mutex_unlock( &ldap_int_ctime_mutex ); 106 # endif 107 108 return buf; 109 #endif 110 } 111 112 #define BUFSTART (1024-32) 113 #define BUFMAX (32*1024-32) 114 115 #if defined(LDAP_R_COMPILE) 116 static char *safe_realloc( char **buf, int len ); 117 118 #if !(defined(HAVE_GETHOSTBYNAME_R) && defined(HAVE_GETHOSTBYADDR_R)) 119 static int copy_hostent( struct hostent *res, 120 char **buf, struct hostent * src ); 121 #endif 122 #endif 123 124 int ldap_pvt_gethostbyname_a( 125 const char *name, 126 struct hostent *resbuf, 127 char **buf, 128 struct hostent **result, 129 int *herrno_ptr ) 130 { 131 #if defined( HAVE_GETHOSTBYNAME_R ) 132 133 # define NEED_SAFE_REALLOC 1 134 int r=-1; 135 int buflen=BUFSTART; 136 *buf = NULL; 137 for(;buflen<BUFMAX;) { 138 if (safe_realloc( buf, buflen )==NULL) 139 return r; 140 141 #if (GETHOSTBYNAME_R_NARGS < 6) 142 *result=gethostbyname_r( name, resbuf, *buf, buflen, herrno_ptr ); 143 r = (*result == NULL) ? -1 : 0; 144 #else 145 r = gethostbyname_r( name, resbuf, *buf, 146 buflen, result, herrno_ptr ); 147 #endif 148 149 Debug( LDAP_DEBUG_TRACE, "ldap_pvt_gethostbyname_a: host=%s, r=%d\n", 150 name, r, 0 ); 151 152 #ifdef NETDB_INTERNAL 153 if ((r<0) && 154 (*herrno_ptr==NETDB_INTERNAL) && 155 (errno==ERANGE)) 156 { 157 buflen*=2; 158 continue; 159 } 160 #endif 161 return r; 162 } 163 return -1; 164 #elif defined( LDAP_R_COMPILE ) 165 # define NEED_COPY_HOSTENT 166 struct hostent *he; 167 int retval; 168 *buf = NULL; 169 170 ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex ); 171 172 he = gethostbyname( name ); 173 174 if (he==NULL) { 175 *herrno_ptr = h_errno; 176 retval = -1; 177 } else if (copy_hostent( resbuf, buf, he )<0) { 178 *herrno_ptr = -1; 179 retval = -1; 180 } else { 181 *result = resbuf; 182 retval = 0; 183 } 184 185 ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex ); 186 187 return retval; 188 #else 189 *buf = NULL; 190 *result = gethostbyname( name ); 191 192 if (*result!=NULL) { 193 return 0; 194 } 195 196 *herrno_ptr = h_errno; 197 198 return -1; 199 #endif 200 } 201 202 #if !defined( HAVE_GETNAMEINFO ) && !defined( HAVE_HSTRERROR ) 203 static const char * 204 hp_strerror( int err ) 205 { 206 switch (err) { 207 case HOST_NOT_FOUND: return _("Host not found (authoritative)"); 208 case TRY_AGAIN: return _("Host not found (server fail?)"); 209 case NO_RECOVERY: return _("Non-recoverable failure"); 210 case NO_DATA: return _("No data of requested type"); 211 #ifdef NETDB_INTERNAL 212 case NETDB_INTERNAL: return STRERROR( errno ); 213 #endif 214 } 215 return _("Unknown resolver error"); 216 } 217 #endif 218 219 int ldap_pvt_get_hname( 220 const struct sockaddr *sa, 221 int len, 222 char *name, 223 int namelen, 224 char **err ) 225 { 226 int rc; 227 #if defined( HAVE_GETNAMEINFO ) 228 229 #if defined( LDAP_R_COMPILE ) 230 ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex ); 231 #endif 232 rc = getnameinfo( sa, len, name, namelen, NULL, 0, 0 ); 233 #if defined( LDAP_R_COMPILE ) 234 ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex ); 235 #endif 236 if ( rc ) *err = (char *)AC_GAI_STRERROR( rc ); 237 return rc; 238 239 #else /* !HAVE_GETNAMEINFO */ 240 char *addr; 241 int alen; 242 struct hostent *hp = NULL; 243 #ifdef HAVE_GETHOSTBYADDR_R 244 struct hostent hb; 245 int buflen=BUFSTART, h_errno; 246 char *buf=NULL; 247 #endif 248 249 #ifdef LDAP_PF_INET6 250 if (sa->sa_family == AF_INET6) { 251 struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa; 252 addr = (char *)&sin->sin6_addr; 253 alen = sizeof(sin->sin6_addr); 254 } else 255 #endif 256 if (sa->sa_family == AF_INET) { 257 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 258 addr = (char *)&sin->sin_addr; 259 alen = sizeof(sin->sin_addr); 260 } else { 261 rc = NO_RECOVERY; 262 *err = (char *)HSTRERROR( rc ); 263 return rc; 264 } 265 #if defined( HAVE_GETHOSTBYADDR_R ) 266 for(;buflen<BUFMAX;) { 267 if (safe_realloc( &buf, buflen )==NULL) { 268 *err = (char *)STRERROR( ENOMEM ); 269 return ENOMEM; 270 } 271 #if (GETHOSTBYADDR_R_NARGS < 8) 272 hp=gethostbyaddr_r( addr, alen, sa->sa_family, 273 &hb, buf, buflen, &h_errno ); 274 rc = (hp == NULL) ? -1 : 0; 275 #else 276 rc = gethostbyaddr_r( addr, alen, sa->sa_family, 277 &hb, buf, buflen, 278 &hp, &h_errno ); 279 #endif 280 #ifdef NETDB_INTERNAL 281 if ((rc<0) && 282 (h_errno==NETDB_INTERNAL) && 283 (errno==ERANGE)) 284 { 285 buflen*=2; 286 continue; 287 } 288 #endif 289 break; 290 } 291 if (hp) { 292 strncpy( name, hp->h_name, namelen ); 293 } else { 294 *err = (char *)HSTRERROR( h_errno ); 295 } 296 LDAP_FREE(buf); 297 #else /* HAVE_GETHOSTBYADDR_R */ 298 299 #if defined( LDAP_R_COMPILE ) 300 ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex ); 301 #endif 302 hp = gethostbyaddr( addr, alen, sa->sa_family ); 303 if (hp) { 304 strncpy( name, hp->h_name, namelen ); 305 rc = 0; 306 } else { 307 rc = h_errno; 308 *err = (char *)HSTRERROR( h_errno ); 309 } 310 #if defined( LDAP_R_COMPILE ) 311 ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex ); 312 #endif 313 314 #endif /* !HAVE_GETHOSTBYADDR_R */ 315 return rc; 316 #endif /* !HAVE_GETNAMEINFO */ 317 } 318 319 int ldap_pvt_gethostbyaddr_a( 320 const char *addr, 321 int len, 322 int type, 323 struct hostent *resbuf, 324 char **buf, 325 struct hostent **result, 326 int *herrno_ptr ) 327 { 328 #if defined( HAVE_GETHOSTBYADDR_R ) 329 330 # undef NEED_SAFE_REALLOC 331 # define NEED_SAFE_REALLOC 332 int r=-1; 333 int buflen=BUFSTART; 334 *buf = NULL; 335 for(;buflen<BUFMAX;) { 336 if (safe_realloc( buf, buflen )==NULL) 337 return r; 338 #if (GETHOSTBYADDR_R_NARGS < 8) 339 *result=gethostbyaddr_r( addr, len, type, 340 resbuf, *buf, buflen, herrno_ptr ); 341 r = (*result == NULL) ? -1 : 0; 342 #else 343 r = gethostbyaddr_r( addr, len, type, 344 resbuf, *buf, buflen, 345 result, herrno_ptr ); 346 #endif 347 348 #ifdef NETDB_INTERNAL 349 if ((r<0) && 350 (*herrno_ptr==NETDB_INTERNAL) && 351 (errno==ERANGE)) 352 { 353 buflen*=2; 354 continue; 355 } 356 #endif 357 return r; 358 } 359 return -1; 360 #elif defined( LDAP_R_COMPILE ) 361 # undef NEED_COPY_HOSTENT 362 # define NEED_COPY_HOSTENT 363 struct hostent *he; 364 int retval; 365 *buf = NULL; 366 367 ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex ); 368 369 he = gethostbyaddr( addr, len, type ); 370 371 if (he==NULL) { 372 *herrno_ptr = h_errno; 373 retval = -1; 374 } else if (copy_hostent( resbuf, buf, he )<0) { 375 *herrno_ptr = -1; 376 retval = -1; 377 } else { 378 *result = resbuf; 379 retval = 0; 380 } 381 382 ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex ); 383 384 return retval; 385 386 #else /* gethostbyaddr() */ 387 *buf = NULL; 388 *result = gethostbyaddr( addr, len, type ); 389 390 if (*result!=NULL) { 391 return 0; 392 } 393 return -1; 394 #endif 395 } 396 /* 397 * ldap_int_utils_init() should be called before any other function. 398 */ 399 400 void ldap_int_utils_init( void ) 401 { 402 static int done=0; 403 if (done) 404 return; 405 done=1; 406 407 #ifdef LDAP_R_COMPILE 408 #if !defined( USE_CTIME_R ) && !defined( HAVE_REENTRANT_FUNCTIONS ) 409 ldap_pvt_thread_mutex_init( &ldap_int_ctime_mutex ); 410 #endif 411 ldap_pvt_thread_mutex_init( &ldap_int_resolv_mutex ); 412 413 #ifdef HAVE_CYRUS_SASL 414 ldap_pvt_thread_mutex_init( &ldap_int_sasl_mutex ); 415 #endif 416 #ifdef HAVE_GSSAPI 417 ldap_pvt_thread_mutex_init( &ldap_int_gssapi_mutex ); 418 #endif 419 #endif 420 421 /* call other module init functions here... */ 422 } 423 424 #if defined( NEED_COPY_HOSTENT ) 425 # undef NEED_SAFE_REALLOC 426 #define NEED_SAFE_REALLOC 427 428 static char *cpy_aliases( 429 char ***tgtio, 430 char *buf, 431 char **src ) 432 { 433 int len; 434 char **tgt=*tgtio; 435 for( ; (*src) ; src++ ) { 436 len = strlen( *src ) + 1; 437 AC_MEMCPY( buf, *src, len ); 438 *tgt++=buf; 439 buf+=len; 440 } 441 *tgtio=tgt; 442 return buf; 443 } 444 445 static char *cpy_addresses( 446 char ***tgtio, 447 char *buf, 448 char **src, 449 int len ) 450 { 451 char **tgt=*tgtio; 452 for( ; (*src) ; src++ ) { 453 AC_MEMCPY( buf, *src, len ); 454 *tgt++=buf; 455 buf+=len; 456 } 457 *tgtio=tgt; 458 return buf; 459 } 460 461 static int copy_hostent( 462 struct hostent *res, 463 char **buf, 464 struct hostent * src ) 465 { 466 char **p; 467 char **tp; 468 char *tbuf; 469 int name_len; 470 int n_alias=0; 471 int total_alias_len=0; 472 int n_addr=0; 473 int total_addr_len=0; 474 int total_len; 475 476 /* calculate the size needed for the buffer */ 477 name_len = strlen( src->h_name ) + 1; 478 479 if( src->h_aliases != NULL ) { 480 for( p = src->h_aliases; (*p) != NULL; p++ ) { 481 total_alias_len += strlen( *p ) + 1; 482 n_alias++; 483 } 484 } 485 486 if( src->h_addr_list != NULL ) { 487 for( p = src->h_addr_list; (*p) != NULL; p++ ) { 488 n_addr++; 489 } 490 total_addr_len = n_addr * src->h_length; 491 } 492 493 total_len = (n_alias + n_addr + 2) * sizeof( char * ) + 494 total_addr_len + total_alias_len + name_len; 495 496 if (safe_realloc( buf, total_len )) { 497 tp = (char **) *buf; 498 tbuf = *buf + (n_alias + n_addr + 2) * sizeof( char * ); 499 AC_MEMCPY( res, src, sizeof( struct hostent ) ); 500 /* first the name... */ 501 AC_MEMCPY( tbuf, src->h_name, name_len ); 502 res->h_name = tbuf; tbuf+=name_len; 503 /* now the aliases */ 504 res->h_aliases = tp; 505 if ( src->h_aliases != NULL ) { 506 tbuf = cpy_aliases( &tp, tbuf, src->h_aliases ); 507 } 508 *tp++=NULL; 509 /* finally the addresses */ 510 res->h_addr_list = tp; 511 if ( src->h_addr_list != NULL ) { 512 tbuf = cpy_addresses( &tp, tbuf, src->h_addr_list, src->h_length ); 513 } 514 *tp++=NULL; 515 return 0; 516 } 517 return -1; 518 } 519 #endif 520 521 #if defined( NEED_SAFE_REALLOC ) 522 static char *safe_realloc( char **buf, int len ) 523 { 524 char *tmpbuf; 525 tmpbuf = LDAP_REALLOC( *buf, len ); 526 if (tmpbuf) { 527 *buf=tmpbuf; 528 } 529 return tmpbuf; 530 } 531 #endif 532 533 char * ldap_pvt_get_fqdn( char *name ) 534 { 535 char *fqdn, *ha_buf; 536 char hostbuf[MAXHOSTNAMELEN+1]; 537 struct hostent *hp, he_buf; 538 int rc, local_h_errno; 539 540 if( name == NULL ) { 541 if( gethostname( hostbuf, MAXHOSTNAMELEN ) == 0 ) { 542 hostbuf[MAXHOSTNAMELEN] = '\0'; 543 name = hostbuf; 544 } else { 545 name = "localhost"; 546 } 547 } 548 549 rc = ldap_pvt_gethostbyname_a( name, 550 &he_buf, &ha_buf, &hp, &local_h_errno ); 551 552 if( rc < 0 || hp == NULL || hp->h_name == NULL ) { 553 fqdn = LDAP_STRDUP( name ); 554 } else { 555 fqdn = LDAP_STRDUP( hp->h_name ); 556 } 557 558 LDAP_FREE( ha_buf ); 559 return fqdn; 560 } 561 562 #if ( defined( HAVE_GETADDRINFO ) || defined( HAVE_GETNAMEINFO ) ) \ 563 && !defined( HAVE_GAI_STRERROR ) 564 char *ldap_pvt_gai_strerror (int code) { 565 static struct { 566 int code; 567 const char *msg; 568 } values[] = { 569 #ifdef EAI_ADDRFAMILY 570 { EAI_ADDRFAMILY, N_("Address family for hostname not supported") }, 571 #endif 572 { EAI_AGAIN, N_("Temporary failure in name resolution") }, 573 { EAI_BADFLAGS, N_("Bad value for ai_flags") }, 574 { EAI_FAIL, N_("Non-recoverable failure in name resolution") }, 575 { EAI_FAMILY, N_("ai_family not supported") }, 576 { EAI_MEMORY, N_("Memory allocation failure") }, 577 #ifdef EAI_NODATA 578 { EAI_NODATA, N_("No address associated with hostname") }, 579 #endif 580 { EAI_NONAME, N_("Name or service not known") }, 581 { EAI_SERVICE, N_("Servname not supported for ai_socktype") }, 582 { EAI_SOCKTYPE, N_("ai_socktype not supported") }, 583 { EAI_SYSTEM, N_("System error") }, 584 { 0, NULL } 585 }; 586 587 int i; 588 589 for ( i = 0; values[i].msg != NULL; i++ ) { 590 if ( values[i].code == code ) { 591 return (char *) _(values[i].msg); 592 } 593 } 594 595 return _("Unknown error"); 596 } 597 #endif 598