1 /* $NetBSD: os-ip.c,v 1.12 2025/09/05 21:16:21 christos Exp $ */ 2 3 /* os-ip.c -- platform-specific TCP & UDP related code */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 1998-2024 The OpenLDAP Foundation. 8 * Portions Copyright 1999 Lars Uffmann. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted only as authorized by the OpenLDAP 13 * Public License. 14 * 15 * A copy of this license is available in the file LICENSE in the 16 * top-level directory of the distribution or, alternatively, at 17 * <http://www.OpenLDAP.org/license.html>. 18 */ 19 /* Portions Copyright (c) 1995 Regents of the University of Michigan. 20 * All rights reserved. 21 */ 22 /* Significant additional contributors include: 23 * Lars Uffman 24 */ 25 26 #include <sys/cdefs.h> 27 __RCSID("$NetBSD: os-ip.c,v 1.12 2025/09/05 21:16:21 christos Exp $"); 28 29 #include "portable.h" 30 31 #include <stdio.h> 32 33 #include <ac/stdlib.h> 34 35 #include <ac/errno.h> 36 #include <ac/socket.h> 37 #include <ac/string.h> 38 #include <ac/time.h> 39 #include <ac/unistd.h> 40 41 #ifdef HAVE_IO_H 42 #include <io.h> 43 #endif /* HAVE_IO_H */ 44 #ifdef HAVE_FCNTL_H 45 #include <fcntl.h> 46 #endif 47 48 #include "ldap-int.h" 49 50 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) 51 # ifdef LDAP_PF_INET6 52 int ldap_int_inet4or6 = AF_UNSPEC; 53 # else 54 int ldap_int_inet4or6 = AF_INET; 55 # endif 56 #endif 57 58 static void 59 ldap_pvt_set_errno(int err) 60 { 61 sock_errset(err); 62 } 63 64 int 65 ldap_int_timeval_dup( struct timeval **dest, const struct timeval *src ) 66 { 67 struct timeval *new; 68 69 assert( dest != NULL ); 70 71 if (src == NULL) { 72 *dest = NULL; 73 return 0; 74 } 75 76 new = (struct timeval *) LDAP_MALLOC(sizeof(struct timeval)); 77 78 if( new == NULL ) { 79 *dest = NULL; 80 return 1; 81 } 82 83 AC_MEMCPY( (char *) new, (const char *) src, sizeof(struct timeval)); 84 85 *dest = new; 86 return 0; 87 } 88 89 static int 90 ldap_pvt_ndelay_on(LDAP *ld, int fd) 91 { 92 Debug1(LDAP_DEBUG_TRACE, "ldap_ndelay_on: %d\n",fd ); 93 return ber_pvt_socket_set_nonblock( fd, 1 ); 94 } 95 96 static int 97 ldap_pvt_ndelay_off(LDAP *ld, int fd) 98 { 99 Debug1(LDAP_DEBUG_TRACE, "ldap_ndelay_off: %d\n",fd ); 100 return ber_pvt_socket_set_nonblock( fd, 0 ); 101 } 102 103 static ber_socket_t 104 ldap_int_socket(LDAP *ld, int family, int type ) 105 { 106 ber_socket_t s = socket(family, type, 0); 107 Debug1(LDAP_DEBUG_TRACE, "ldap_new_socket: %d\n",s ); 108 #ifdef FD_CLOEXEC 109 fcntl(s, F_SETFD, FD_CLOEXEC); 110 #endif 111 return ( s ); 112 } 113 114 static int 115 ldap_pvt_close_socket(LDAP *ld, int s) 116 { 117 Debug1(LDAP_DEBUG_TRACE, "ldap_close_socket: %d\n",s ); 118 return tcp_close(s); 119 } 120 121 static int 122 ldap_int_prepare_socket(LDAP *ld, int s, int proto ) 123 { 124 Debug1(LDAP_DEBUG_TRACE, "ldap_prepare_socket: %d\n", s ); 125 126 #if defined( SO_KEEPALIVE ) || defined( TCP_NODELAY ) || defined( TCP_USER_TIMEOUT ) 127 if ( proto == LDAP_PROTO_TCP ) { 128 int dummy = 1; 129 #ifdef SO_KEEPALIVE 130 if ( setsockopt( s, SOL_SOCKET, SO_KEEPALIVE, 131 (char*) &dummy, sizeof(dummy) ) == AC_SOCKET_ERROR ) 132 { 133 Debug1(LDAP_DEBUG_TRACE, "ldap_prepare_socket: " 134 "setsockopt(%d, SO_KEEPALIVE) failed (ignored).\n", 135 s ); 136 } 137 if ( ld->ld_options.ldo_keepalive_idle > 0 ) 138 { 139 #ifdef TCP_KEEPIDLE 140 if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPIDLE, 141 (void*) &ld->ld_options.ldo_keepalive_idle, 142 sizeof(ld->ld_options.ldo_keepalive_idle) ) == AC_SOCKET_ERROR ) 143 { 144 Debug1(LDAP_DEBUG_TRACE, 145 "ldap_prepare_socket: " 146 "setsockopt(%d, TCP_KEEPIDLE) failed (ignored).\n", 147 s ); 148 } 149 #else 150 Debug0(LDAP_DEBUG_TRACE, "ldap_prepare_socket: " 151 "sockopt TCP_KEEPIDLE not supported on this system.\n" ); 152 #endif /* TCP_KEEPIDLE */ 153 } 154 if ( ld->ld_options.ldo_keepalive_probes > 0 ) 155 { 156 #ifdef TCP_KEEPCNT 157 if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPCNT, 158 (void*) &ld->ld_options.ldo_keepalive_probes, 159 sizeof(ld->ld_options.ldo_keepalive_probes) ) == AC_SOCKET_ERROR ) 160 { 161 Debug1(LDAP_DEBUG_TRACE, 162 "ldap_prepare_socket: " 163 "setsockopt(%d, TCP_KEEPCNT) failed (ignored).\n", 164 s ); 165 } 166 #else 167 Debug0(LDAP_DEBUG_TRACE, "ldap_prepare_socket: " 168 "sockopt TCP_KEEPCNT not supported on this system.\n" ); 169 #endif /* TCP_KEEPCNT */ 170 } 171 if ( ld->ld_options.ldo_keepalive_interval > 0 ) 172 { 173 #ifdef TCP_KEEPINTVL 174 if ( setsockopt( s, IPPROTO_TCP, TCP_KEEPINTVL, 175 (void*) &ld->ld_options.ldo_keepalive_interval, 176 sizeof(ld->ld_options.ldo_keepalive_interval) ) == AC_SOCKET_ERROR ) 177 { 178 Debug1(LDAP_DEBUG_TRACE, 179 "ldap_prepare_socket: " 180 "setsockopt(%d, TCP_KEEPINTVL) failed (ignored).\n", 181 s ); 182 } 183 #else 184 Debug0(LDAP_DEBUG_TRACE, "ldap_prepare_socket: " 185 "sockopt TCP_KEEPINTVL not supported on this system.\n" ); 186 #endif /* TCP_KEEPINTVL */ 187 } 188 #endif /* SO_KEEPALIVE */ 189 #ifdef TCP_NODELAY 190 if ( setsockopt( s, IPPROTO_TCP, TCP_NODELAY, 191 (char*) &dummy, sizeof(dummy) ) == AC_SOCKET_ERROR ) 192 { 193 Debug1(LDAP_DEBUG_TRACE, "ldap_prepare_socket: " 194 "setsockopt(%d, TCP_NODELAY) failed (ignored).\n", 195 s ); 196 } 197 #endif /* TCP_NODELAY */ 198 if ( ld->ld_options.ldo_tcp_user_timeout > 0 ) 199 { 200 #ifdef TCP_USER_TIMEOUT 201 if ( setsockopt( s, IPPROTO_TCP, TCP_USER_TIMEOUT, 202 (void*) &ld->ld_options.ldo_tcp_user_timeout, 203 sizeof(ld->ld_options.ldo_tcp_user_timeout) ) == AC_SOCKET_ERROR ) 204 { 205 Debug1(LDAP_DEBUG_TRACE, 206 "ldap_prepare_socket: " 207 "setsockopt(%d, TCP_USER_TIMEOUT) failed (ignored).\n", 208 s ); 209 } 210 #else 211 Debug0(LDAP_DEBUG_TRACE, "ldap_prepare_socket: " 212 "sockopt TCP_USER_TIMEOUT not supported on this system.\n" ); 213 #endif /* TCP_USER_TIMEOUT */ 214 } 215 } 216 #endif /* SO_KEEPALIVE || TCP_NODELAY || TCP_USER_TIMEOUT */ 217 218 return 0; 219 } 220 221 #ifndef HAVE_WINSOCK 222 223 #undef TRACE 224 #define TRACE do { \ 225 char ebuf[128]; \ 226 int saved_errno = errno; \ 227 Debug3(LDAP_DEBUG_TRACE, "ldap_is_socket_ready: error on socket %d: errno: %d (%s)\n", \ 228 s, \ 229 saved_errno, \ 230 sock_errstr(saved_errno, ebuf, sizeof(ebuf)) ); \ 231 } while( 0 ) 232 233 /* 234 * check the socket for errors after select returned. 235 */ 236 static int 237 ldap_pvt_is_socket_ready(LDAP *ld, int s) 238 { 239 Debug1(LDAP_DEBUG_TRACE, "ldap_is_sock_ready: %d\n",s ); 240 241 #if defined( notyet ) /* && defined( SO_ERROR ) */ 242 { 243 int so_errno; 244 ber_socklen_t dummy = sizeof(so_errno); 245 if ( getsockopt( s, SOL_SOCKET, SO_ERROR, &so_errno, &dummy ) 246 == AC_SOCKET_ERROR ) 247 { 248 return -1; 249 } 250 if ( so_errno ) { 251 ldap_pvt_set_errno(so_errno); 252 TRACE; 253 return -1; 254 } 255 return 0; 256 } 257 #else 258 { 259 /* error slippery */ 260 #ifdef LDAP_PF_INET6 261 struct sockaddr_storage sin; 262 #else 263 struct sockaddr_in sin; 264 #endif 265 char ch; 266 ber_socklen_t dummy = sizeof(sin); 267 if ( getpeername( s, (struct sockaddr *) &sin, &dummy ) 268 == AC_SOCKET_ERROR ) 269 { 270 /* XXX: needs to be replace with ber_stream_read() */ 271 (void)!read(s, &ch, 1); 272 TRACE; 273 return -1; 274 } 275 return 0; 276 } 277 #endif 278 return -1; 279 } 280 #undef TRACE 281 282 #endif /* HAVE_WINSOCK */ 283 284 /* NOTE: this is identical to analogous code in os-local.c */ 285 int 286 ldap_int_poll( 287 LDAP *ld, 288 ber_socket_t s, 289 struct timeval *tvp, 290 int wr ) 291 { 292 int rc; 293 294 295 Debug2(LDAP_DEBUG_TRACE, "ldap_int_poll: fd: %d tm: %jd\n", 296 s, (intmax_t)(tvp ? tvp->tv_sec : -1)); 297 298 #ifdef HAVE_POLL 299 { 300 struct pollfd fd; 301 int timeout = INFTIM; 302 short event = wr ? POLL_WRITE : POLL_READ; 303 304 fd.fd = s; 305 fd.events = event; 306 307 if ( tvp != NULL ) { 308 timeout = TV2MILLISEC( tvp ); 309 } 310 do { 311 fd.revents = 0; 312 rc = poll( &fd, 1, timeout ); 313 314 } while ( rc == AC_SOCKET_ERROR && errno == EINTR && 315 LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_RESTART ) ); 316 317 if ( rc == AC_SOCKET_ERROR ) { 318 return rc; 319 } 320 321 if ( timeout == 0 && rc == 0 ) { 322 return -2; 323 } 324 325 if ( fd.revents & event ) { 326 if ( ldap_pvt_is_socket_ready( ld, s ) == -1 ) { 327 return -1; 328 } 329 330 if ( ldap_pvt_ndelay_off( ld, s ) == -1 ) { 331 return -1; 332 } 333 return 0; 334 } 335 } 336 #else 337 { 338 fd_set wfds, *z = NULL; 339 #ifdef HAVE_WINSOCK 340 fd_set efds; 341 #endif 342 struct timeval tv = { 0 }; 343 344 #if defined( FD_SETSIZE ) && !defined( HAVE_WINSOCK ) 345 if ( s >= FD_SETSIZE ) { 346 rc = AC_SOCKET_ERROR; 347 tcp_close( s ); 348 ldap_pvt_set_errno( EMFILE ); 349 return rc; 350 } 351 #endif 352 353 if ( tvp != NULL ) { 354 tv = *tvp; 355 } 356 357 do { 358 FD_ZERO(&wfds); 359 FD_SET(s, &wfds ); 360 361 #ifdef HAVE_WINSOCK 362 FD_ZERO(&efds); 363 FD_SET(s, &efds ); 364 #endif 365 366 rc = select( ldap_int_tblsize, z, &wfds, 367 #ifdef HAVE_WINSOCK 368 &efds, 369 #else 370 z, 371 #endif 372 tvp ? &tv : NULL ); 373 } while ( rc == AC_SOCKET_ERROR && errno == EINTR && 374 LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_RESTART ) ); 375 376 if ( rc == AC_SOCKET_ERROR ) { 377 return rc; 378 } 379 380 if ( rc == 0 && tvp && tvp->tv_sec == 0 && tvp->tv_usec == 0 ) { 381 return -2; 382 } 383 384 #ifdef HAVE_WINSOCK 385 /* This means the connection failed */ 386 if ( FD_ISSET(s, &efds) ) { 387 int so_errno; 388 ber_socklen_t dummy = sizeof(so_errno); 389 if ( getsockopt( s, SOL_SOCKET, SO_ERROR, 390 (char *) &so_errno, &dummy ) == AC_SOCKET_ERROR || !so_errno ) 391 { 392 /* impossible */ 393 so_errno = WSAGetLastError(); 394 } 395 ldap_pvt_set_errno( so_errno ); 396 Debug3(LDAP_DEBUG_TRACE, 397 "ldap_int_poll: error on socket %d: " 398 "errno: %d (%s)\n", s, so_errno, sock_errstr( so_errno, dummy, dummy )); 399 return -1; 400 } 401 #endif 402 if ( FD_ISSET(s, &wfds) ) { 403 #ifndef HAVE_WINSOCK 404 if ( ldap_pvt_is_socket_ready( ld, s ) == -1 ) { 405 return -1; 406 } 407 #endif 408 if ( ldap_pvt_ndelay_off(ld, s) == -1 ) { 409 return -1; 410 } 411 return 0; 412 } 413 } 414 #endif 415 416 Debug0(LDAP_DEBUG_TRACE, "ldap_int_poll: timed out\n" ); 417 ldap_pvt_set_errno( ETIMEDOUT ); 418 return -1; 419 } 420 421 static int 422 ldap_pvt_connect(LDAP *ld, ber_socket_t s, 423 struct sockaddr *sin, ber_socklen_t addrlen, 424 int async) 425 { 426 int rc, err; 427 struct timeval tv, *opt_tv = NULL; 428 429 #ifdef LDAP_CONNECTIONLESS 430 /* We could do a connect() but that would interfere with 431 * attempts to poll a broadcast address 432 */ 433 if (LDAP_IS_UDP(ld)) { 434 if (ld->ld_options.ldo_peer) 435 ldap_memfree(ld->ld_options.ldo_peer); 436 ld->ld_options.ldo_peer=ldap_memcalloc(1, sizeof(struct sockaddr_storage)); 437 AC_MEMCPY(ld->ld_options.ldo_peer,sin,addrlen); 438 return ( 0 ); 439 } 440 #endif 441 if ( ld->ld_options.ldo_tm_net.tv_sec >= 0 ) { 442 tv = ld->ld_options.ldo_tm_net; 443 opt_tv = &tv; 444 } 445 446 Debug3(LDAP_DEBUG_TRACE, 447 "ldap_pvt_connect: fd: %d tm: %jd async: %d\n", 448 s, (intmax_t)(opt_tv ? tv.tv_sec : -1), async); 449 450 if ( opt_tv && ldap_pvt_ndelay_on(ld, s) == -1 ) 451 return ( -1 ); 452 453 do{ 454 Debug0(LDAP_DEBUG_TRACE, "attempting to connect: \n" ); 455 if ( connect(s, sin, addrlen) != AC_SOCKET_ERROR ) { 456 Debug0(LDAP_DEBUG_TRACE, "connect success\n" ); 457 458 if ( !async && opt_tv && ldap_pvt_ndelay_off(ld, s) == -1 ) 459 return ( -1 ); 460 return ( 0 ); 461 } 462 err = sock_errno(); 463 Debug1(LDAP_DEBUG_TRACE, "connect errno: %d\n", err ); 464 465 } while(err == EINTR && 466 LDAP_BOOL_GET( &ld->ld_options, LDAP_BOOL_RESTART )); 467 468 if ( err != EINPROGRESS && err != EWOULDBLOCK ) { 469 return ( -1 ); 470 } 471 472 if ( async ) { 473 /* caller will call ldap_int_poll() as appropriate? */ 474 return ( -2 ); 475 } 476 477 rc = ldap_int_poll( ld, s, opt_tv, 1 ); 478 479 Debug1(LDAP_DEBUG_TRACE, "ldap_pvt_connect: %d\n", rc ); 480 481 return rc; 482 } 483 484 #ifndef HAVE_INET_ATON 485 int 486 ldap_pvt_inet_aton( const char *host, struct in_addr *in) 487 { 488 unsigned long u = inet_addr( host ); 489 490 #ifdef INADDR_NONE 491 if ( u == INADDR_NONE ) return 0; 492 #endif 493 if ( u == 0xffffffffUL || u == (unsigned long) -1L ) return 0; 494 495 in->s_addr = u; 496 return 1; 497 } 498 #endif 499 500 int 501 ldap_validate_and_fill_sourceip (char** source_ip_lst, ldapsourceip* temp_source_ip ) 502 { 503 int i = 0; 504 int rc = LDAP_PARAM_ERROR; 505 506 for ( i = 0; source_ip_lst[i] != NULL; i++ ) { 507 Debug1( LDAP_DEBUG_TRACE, 508 "ldap_validate_and_fill_sourceip(%s)\n", 509 source_ip_lst[i] ); 510 511 if ( !temp_source_ip->has_ipv4 ) { 512 if ( inet_aton( source_ip_lst[i], &temp_source_ip->ip4_addr ) ) { 513 temp_source_ip->has_ipv4 = 1; 514 rc = LDAP_OPT_SUCCESS; 515 continue; 516 } 517 } 518 #ifdef LDAP_PF_INET6 519 if ( !temp_source_ip->has_ipv6 ) { 520 if ( inet_pton( AF_INET6, source_ip_lst[i], 521 & temp_source_ip->ip6_addr ) ) { 522 temp_source_ip->has_ipv6 = 1; 523 rc = LDAP_OPT_SUCCESS; 524 continue; 525 } 526 } 527 #endif 528 memset( temp_source_ip, 0, sizeof( * (temp_source_ip ) ) ); 529 Debug1( LDAP_DEBUG_TRACE, 530 "ldap_validate_and_fill_sourceip: validation failed for (%s)\n", 531 source_ip_lst[i] ); 532 break; 533 } 534 return rc; 535 } 536 537 int 538 ldap_int_connect_cbs(LDAP *ld, Sockbuf *sb, ber_socket_t *s, LDAPURLDesc *srv, struct sockaddr *addr) 539 { 540 struct ldapoptions *lo; 541 ldaplist *ll; 542 ldap_conncb *cb; 543 int rc; 544 545 ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, s ); 546 547 /* Invoke all handle-specific callbacks first */ 548 lo = &ld->ld_options; 549 for (ll = lo->ldo_conn_cbs; ll; ll = ll->ll_next) { 550 cb = ll->ll_data; 551 rc = cb->lc_add( ld, sb, srv, addr, cb ); 552 /* on any failure, call the teardown functions for anything 553 * that previously succeeded 554 */ 555 if ( rc ) { 556 ldaplist *l2; 557 for (l2 = lo->ldo_conn_cbs; l2 != ll; l2 = l2->ll_next) { 558 cb = l2->ll_data; 559 cb->lc_del( ld, sb, cb ); 560 } 561 /* a failure might have implicitly closed the fd */ 562 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, s ); 563 return rc; 564 } 565 } 566 lo = LDAP_INT_GLOBAL_OPT(); 567 for (ll = lo->ldo_conn_cbs; ll; ll = ll->ll_next) { 568 cb = ll->ll_data; 569 rc = cb->lc_add( ld, sb, srv, addr, cb ); 570 if ( rc ) { 571 ldaplist *l2; 572 for (l2 = lo->ldo_conn_cbs; l2 != ll; l2 = l2->ll_next) { 573 cb = l2->ll_data; 574 cb->lc_del( ld, sb, cb ); 575 } 576 lo = &ld->ld_options; 577 for (l2 = lo->ldo_conn_cbs; l2; l2 = l2->ll_next) { 578 cb = l2->ll_data; 579 cb->lc_del( ld, sb, cb ); 580 } 581 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, s ); 582 return rc; 583 } 584 } 585 return 0; 586 } 587 588 int 589 ldap_connect_to_host(LDAP *ld, Sockbuf *sb, 590 int proto, LDAPURLDesc *srv, 591 int async ) 592 { 593 int rc; 594 int socktype, port; 595 ber_socket_t s = AC_SOCKET_INVALID; 596 char *host; 597 598 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) 599 char serv[7]; 600 int err; 601 struct addrinfo hints, *res, *sai; 602 #else 603 int i; 604 int use_hp = 0; 605 struct hostent *hp = NULL; 606 struct hostent he_buf; 607 struct in_addr in; 608 char *ha_buf=NULL; 609 #endif 610 611 if ( srv->lud_host == NULL || *srv->lud_host == 0 ) { 612 host = "localhost"; 613 } else { 614 host = srv->lud_host; 615 } 616 617 port = srv->lud_port; 618 619 if( !port ) { 620 if( strcmp(srv->lud_scheme, "ldaps") == 0 ) { 621 port = LDAPS_PORT; 622 } else { 623 port = LDAP_PORT; 624 } 625 } 626 627 switch(proto) { 628 case LDAP_PROTO_TCP: socktype = SOCK_STREAM; 629 Debug2(LDAP_DEBUG_TRACE, "ldap_connect_to_host: TCP %s:%d\n", 630 host, port ); 631 break; 632 case LDAP_PROTO_UDP: socktype = SOCK_DGRAM; 633 Debug2(LDAP_DEBUG_TRACE, "ldap_connect_to_host: UDP %s:%d\n", 634 host, port ); 635 break; 636 default: 637 Debug1(LDAP_DEBUG_TRACE, 638 "ldap_connect_to_host: unknown proto: %d\n", 639 proto ); 640 return -1; 641 } 642 643 #if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP ) 644 memset( &hints, '\0', sizeof(hints) ); 645 #ifdef USE_AI_ADDRCONFIG /* FIXME: configure test needed */ 646 /* Use AI_ADDRCONFIG only on systems where its known to be needed. */ 647 hints.ai_flags = AI_ADDRCONFIG; 648 #endif 649 hints.ai_family = ldap_int_inet4or6; 650 hints.ai_socktype = socktype; 651 snprintf(serv, sizeof serv, "%d", port ); 652 653 /* most getaddrinfo(3) use non-threadsafe resolver libraries */ 654 LDAP_MUTEX_LOCK(&ldap_int_resolv_mutex); 655 656 err = getaddrinfo( host, serv, &hints, &res ); 657 658 LDAP_MUTEX_UNLOCK(&ldap_int_resolv_mutex); 659 660 if ( err != 0 ) { 661 Debug1(LDAP_DEBUG_TRACE, 662 "ldap_connect_to_host: getaddrinfo failed: %s\n", 663 AC_GAI_STRERROR(err) ); 664 return -1; 665 } 666 rc = -1; 667 668 for( sai=res; sai != NULL; sai=sai->ai_next) { 669 unsigned short bind_success = 1; 670 if( sai->ai_addr == NULL ) { 671 Debug0(LDAP_DEBUG_TRACE, 672 "ldap_connect_to_host: getaddrinfo " 673 "ai_addr is NULL?\n" ); 674 continue; 675 } 676 677 #ifndef LDAP_PF_INET6 678 if ( sai->ai_family == AF_INET6 ) continue; 679 #endif 680 /* we assume AF_x and PF_x are equal for all x */ 681 s = ldap_int_socket( ld, sai->ai_family, socktype ); 682 if ( s == AC_SOCKET_INVALID ) { 683 continue; 684 } 685 686 if ( ldap_int_prepare_socket(ld, s, proto ) == -1 ) { 687 ldap_pvt_close_socket(ld, s); 688 break; 689 } 690 691 switch (sai->ai_family) { 692 #ifdef LDAP_PF_INET6 693 case AF_INET6: { 694 char addr[INET6_ADDRSTRLEN]; 695 inet_ntop( AF_INET6, 696 &((struct sockaddr_in6 *)sai->ai_addr)->sin6_addr, 697 addr, sizeof addr); 698 Debug2(LDAP_DEBUG_TRACE, 699 "ldap_connect_to_host: Trying %s %s\n", 700 addr, serv ); 701 if( ld->ld_options.ldo_local_ip_addrs.has_ipv6 ) { 702 struct sockaddr_in6 ip6addr; 703 char bind_addr[INET6_ADDRSTRLEN]; 704 ip6addr.sin6_family = AF_INET6; 705 ip6addr.sin6_port = 0; 706 ip6addr.sin6_addr = ld->ld_options.ldo_local_ip_addrs.ip6_addr; 707 inet_ntop( AF_INET6, 708 &(ip6addr.sin6_addr), 709 bind_addr, sizeof bind_addr ); 710 Debug1( LDAP_DEBUG_TRACE, 711 "ldap_connect_to_host: From source address %s\n", 712 bind_addr ); 713 if ( bind( s, ( struct sockaddr* ) &ip6addr, sizeof ip6addr ) != 0 ) { 714 Debug1( LDAP_DEBUG_TRACE, 715 "ldap_connect_to_host: Failed to bind source address %s\n", 716 bind_addr ); 717 bind_success = 0; 718 } 719 } 720 } break; 721 #endif 722 case AF_INET: { 723 char addr[INET_ADDRSTRLEN]; 724 inet_ntop( AF_INET, 725 &((struct sockaddr_in *)sai->ai_addr)->sin_addr, 726 addr, sizeof addr); 727 Debug2(LDAP_DEBUG_TRACE, 728 "ldap_connect_to_host: Trying %s:%s\n", 729 addr, serv ); 730 if( ld->ld_options.ldo_local_ip_addrs.has_ipv4 ) { 731 struct sockaddr_in ip4addr; 732 char bind_addr[INET_ADDRSTRLEN]; 733 ip4addr.sin_family = AF_INET; 734 ip4addr.sin_port = 0; 735 ip4addr.sin_addr = ld->ld_options.ldo_local_ip_addrs.ip4_addr; 736 inet_ntop( AF_INET, 737 &(ip4addr.sin_addr), 738 bind_addr, sizeof bind_addr ); 739 Debug1( LDAP_DEBUG_TRACE, 740 "ldap_connect_to_host: From source address %s\n", 741 bind_addr ); 742 if ( bind(s, ( struct sockaddr* )&ip4addr, sizeof ip4addr ) != 0 ) { 743 Debug1( LDAP_DEBUG_TRACE, 744 "ldap_connect_to_host: Failed to bind source address %s\n", 745 bind_addr ); 746 bind_success = 0; 747 } 748 } 749 } break; 750 } 751 if ( bind_success ) { 752 rc = ldap_pvt_connect( ld, s, 753 sai->ai_addr, sai->ai_addrlen, async ); 754 if ( rc == 0 || rc == -2 ) { 755 err = ldap_int_connect_cbs( ld, sb, &s, srv, sai->ai_addr ); 756 if ( err ) 757 rc = err; 758 else 759 break; 760 } 761 } 762 ldap_pvt_close_socket(ld, s); 763 } 764 freeaddrinfo(res); 765 766 #else 767 if (! inet_aton( host, &in ) ) { 768 int local_h_errno; 769 rc = ldap_pvt_gethostbyname_a( host, &he_buf, &ha_buf, 770 &hp, &local_h_errno ); 771 772 if ( (rc < 0) || (hp == NULL) ) { 773 #ifdef HAVE_WINSOCK 774 ldap_pvt_set_errno( WSAGetLastError() ); 775 #else 776 /* not exactly right, but... */ 777 ldap_pvt_set_errno( EHOSTUNREACH ); 778 #endif 779 if (ha_buf) LDAP_FREE(ha_buf); 780 return -1; 781 } 782 783 use_hp = 1; 784 } 785 786 rc = s = -1; 787 for ( i = 0; !use_hp || (hp->h_addr_list[i] != 0); ++i, rc = -1 ) { 788 struct sockaddr_in sin; 789 unsigned short bind_success = 1; 790 #ifdef HAVE_INET_NTOA_B 791 char address[INET_ADDR_LEN]; 792 char bind_addr[INET_ADDR_LEN]; 793 #else 794 char *address; 795 char *bind_addr; 796 #endif 797 s = ldap_int_socket( ld, PF_INET, socktype ); 798 if ( s == AC_SOCKET_INVALID ) { 799 /* use_hp ? continue : break; */ 800 break; 801 } 802 803 if ( ldap_int_prepare_socket( ld, s, proto ) == -1 ) { 804 ldap_pvt_close_socket(ld, s); 805 break; 806 } 807 808 (void)memset((char *)&sin, '\0', sizeof sin); 809 sin.sin_family = AF_INET; 810 sin.sin_port = htons((unsigned short) port); 811 812 if( use_hp ) { 813 AC_MEMCPY( &sin.sin_addr, hp->h_addr_list[i], 814 sizeof(sin.sin_addr) ); 815 } else { 816 AC_MEMCPY( &sin.sin_addr, &in.s_addr, 817 sizeof(sin.sin_addr) ); 818 } 819 820 #ifdef HAVE_INET_NTOA_B 821 /* for VxWorks */ 822 inet_ntoa_b( sin.sin_address, address ); 823 #else 824 address = inet_ntoa( sin.sin_addr ); 825 #endif 826 Debug2( LDAP_DEBUG_TRACE, 827 "ldap_connect_to_host: Trying %s:%d\n", 828 address, port ); 829 if( ld->ld_options.ldo_local_ip_addrs.has_ipv4 ) { 830 struct sockaddr_in ip4addr; 831 ip4addr.sin_family = AF_INET; 832 ip4addr.sin_addr = ld->ld_options.ldo_local_ip_addrs.ip4_addr; 833 #ifdef HAVE_INET_NTOA_B 834 inet_ntoa_b( ip4addr.sin_address, bind_addr ); 835 #else 836 bind_addr = inet_ntoa( ip4addr.sin_addr ); 837 #endif 838 Debug1( LDAP_DEBUG_TRACE, 839 "ldap_connect_to_host: From source address %s\n", 840 bind_addr ); 841 if ( bind( s, (struct sockaddr*)&ip4addr, sizeof ip4addr ) != 0 ) { 842 Debug1( LDAP_DEBUG_TRACE, 843 "ldap_connect_to_host: Failed to bind source address %s\n", 844 bind_addr ); 845 bind_success = 0; 846 } 847 } 848 if ( bind_success ) { 849 rc = ldap_pvt_connect(ld, s, 850 (struct sockaddr *)&sin, sizeof(sin), 851 async); 852 853 if ( (rc == 0) || (rc == -2) ) { 854 int err = ldap_int_connect_cbs( ld, sb, &s, srv, (struct sockaddr *)&sin ); 855 if ( err ) 856 rc = err; 857 else 858 break; 859 } 860 } 861 862 ldap_pvt_close_socket(ld, s); 863 864 if (!use_hp) break; 865 } 866 if (ha_buf) LDAP_FREE(ha_buf); 867 #endif 868 869 return rc; 870 } 871 872 #if defined( HAVE_CYRUS_SASL ) 873 char * 874 ldap_host_connected_to( Sockbuf *sb, const char *host ) 875 { 876 ber_socklen_t len; 877 #ifdef LDAP_PF_INET6 878 struct sockaddr_storage sabuf; 879 #else 880 struct sockaddr sabuf; 881 #endif 882 struct sockaddr *sa = (struct sockaddr *) &sabuf; 883 ber_socket_t sd; 884 885 (void)memset( (char *)sa, '\0', sizeof sabuf ); 886 len = sizeof sabuf; 887 888 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); 889 if ( getpeername( sd, sa, &len ) == -1 ) { 890 return( NULL ); 891 } 892 893 /* 894 * do a reverse lookup on the addr to get the official hostname. 895 * this is necessary for kerberos to work right, since the official 896 * hostname is used as the kerberos instance. 897 */ 898 899 switch (sa->sa_family) { 900 #ifdef LDAP_PF_LOCAL 901 case AF_LOCAL: 902 return LDAP_STRDUP( ldap_int_hostname ); 903 #endif 904 #ifdef LDAP_PF_INET6 905 case AF_INET6: 906 { 907 struct in6_addr localhost = IN6ADDR_LOOPBACK_INIT; 908 if( memcmp ( &((struct sockaddr_in6 *)sa)->sin6_addr, 909 &localhost, sizeof(localhost)) == 0 ) 910 { 911 return LDAP_STRDUP( ldap_int_hostname ); 912 } 913 } 914 break; 915 #endif 916 case AF_INET: 917 { 918 struct in_addr localhost; 919 localhost.s_addr = htonl( INADDR_ANY ); 920 921 if( memcmp ( &((struct sockaddr_in *)sa)->sin_addr, 922 &localhost, sizeof(localhost) ) == 0 ) 923 { 924 return LDAP_STRDUP( ldap_int_hostname ); 925 } 926 927 #ifdef INADDR_LOOPBACK 928 localhost.s_addr = htonl( INADDR_LOOPBACK ); 929 930 if( memcmp ( &((struct sockaddr_in *)sa)->sin_addr, 931 &localhost, sizeof(localhost) ) == 0 ) 932 { 933 return LDAP_STRDUP( ldap_int_hostname ); 934 } 935 #endif 936 } 937 break; 938 939 default: 940 return( NULL ); 941 break; 942 } 943 944 { 945 char *herr; 946 #ifdef NI_MAXHOST 947 char hbuf[NI_MAXHOST]; 948 #elif defined( MAXHOSTNAMELEN ) 949 char hbuf[MAXHOSTNAMELEN]; 950 #else 951 char hbuf[256]; 952 #endif 953 hbuf[0] = 0; 954 955 if (ldap_pvt_get_hname( sa, len, hbuf, sizeof(hbuf), &herr ) == 0 956 && hbuf[0] ) 957 { 958 return LDAP_STRDUP( hbuf ); 959 } 960 } 961 962 return host ? LDAP_STRDUP( host ) : NULL; 963 } 964 #endif 965 966 967 struct selectinfo { 968 #ifdef HAVE_POLL 969 /* for UNIX poll(2) */ 970 int si_maxfd; 971 struct pollfd si_fds[FD_SETSIZE]; 972 #else 973 /* for UNIX select(2) */ 974 fd_set si_readfds; 975 fd_set si_writefds; 976 fd_set si_use_readfds; 977 fd_set si_use_writefds; 978 #endif 979 }; 980 981 void 982 ldap_mark_select_write( LDAP *ld, Sockbuf *sb ) 983 { 984 struct selectinfo *sip; 985 ber_socket_t sd; 986 987 sip = (struct selectinfo *)ld->ld_selectinfo; 988 989 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); 990 991 #ifdef HAVE_POLL 992 /* for UNIX poll(2) */ 993 { 994 int empty=-1; 995 int i; 996 for(i=0; i < sip->si_maxfd; i++) { 997 if( sip->si_fds[i].fd == sd ) { 998 sip->si_fds[i].events |= POLL_WRITE; 999 return; 1000 } 1001 if( empty==-1 && sip->si_fds[i].fd == -1 ) { 1002 empty=i; 1003 } 1004 } 1005 1006 if( empty == -1 ) { 1007 if( sip->si_maxfd >= FD_SETSIZE ) { 1008 /* FIXME */ 1009 return; 1010 } 1011 empty = sip->si_maxfd++; 1012 } 1013 1014 sip->si_fds[empty].fd = sd; 1015 sip->si_fds[empty].events = POLL_WRITE; 1016 } 1017 #else 1018 /* for UNIX select(2) */ 1019 if ( !FD_ISSET( sd, &sip->si_writefds )) { 1020 FD_SET( sd, &sip->si_writefds ); 1021 } 1022 #endif 1023 } 1024 1025 1026 void 1027 ldap_mark_select_read( LDAP *ld, Sockbuf *sb ) 1028 { 1029 struct selectinfo *sip; 1030 ber_socket_t sd; 1031 1032 sip = (struct selectinfo *)ld->ld_selectinfo; 1033 1034 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); 1035 1036 #ifdef HAVE_POLL 1037 /* for UNIX poll(2) */ 1038 { 1039 int empty=-1; 1040 int i; 1041 for(i=0; i < sip->si_maxfd; i++) { 1042 if( sip->si_fds[i].fd == sd ) { 1043 sip->si_fds[i].events |= POLL_READ; 1044 return; 1045 } 1046 if( empty==-1 && sip->si_fds[i].fd == -1 ) { 1047 empty=i; 1048 } 1049 } 1050 1051 if( empty == -1 ) { 1052 if( sip->si_maxfd >= FD_SETSIZE ) { 1053 /* FIXME */ 1054 return; 1055 } 1056 empty = sip->si_maxfd++; 1057 } 1058 1059 sip->si_fds[empty].fd = sd; 1060 sip->si_fds[empty].events = POLL_READ; 1061 } 1062 #else 1063 /* for UNIX select(2) */ 1064 if ( !FD_ISSET( sd, &sip->si_readfds )) { 1065 FD_SET( sd, &sip->si_readfds ); 1066 } 1067 #endif 1068 } 1069 1070 1071 void 1072 ldap_mark_select_clear( LDAP *ld, Sockbuf *sb ) 1073 { 1074 struct selectinfo *sip; 1075 ber_socket_t sd; 1076 1077 sip = (struct selectinfo *)ld->ld_selectinfo; 1078 1079 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); 1080 1081 #ifdef HAVE_POLL 1082 /* for UNIX poll(2) */ 1083 { 1084 int i; 1085 for(i=0; i < sip->si_maxfd; i++) { 1086 if( sip->si_fds[i].fd == sd ) { 1087 sip->si_fds[i].fd = -1; 1088 } 1089 } 1090 } 1091 #else 1092 /* for UNIX select(2) */ 1093 FD_CLR( sd, &sip->si_writefds ); 1094 FD_CLR( sd, &sip->si_readfds ); 1095 #endif 1096 } 1097 1098 void 1099 ldap_clear_select_write( LDAP *ld, Sockbuf *sb ) 1100 { 1101 struct selectinfo *sip; 1102 ber_socket_t sd; 1103 1104 sip = (struct selectinfo *)ld->ld_selectinfo; 1105 1106 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); 1107 1108 #ifdef HAVE_POLL 1109 /* for UNIX poll(2) */ 1110 { 1111 int i; 1112 for(i=0; i < sip->si_maxfd; i++) { 1113 if( sip->si_fds[i].fd == sd ) { 1114 sip->si_fds[i].events &= ~POLL_WRITE; 1115 } 1116 } 1117 } 1118 #else 1119 /* for UNIX select(2) */ 1120 FD_CLR( sd, &sip->si_writefds ); 1121 #endif 1122 } 1123 1124 1125 int 1126 ldap_is_write_ready( LDAP *ld, Sockbuf *sb ) 1127 { 1128 struct selectinfo *sip; 1129 ber_socket_t sd; 1130 1131 sip = (struct selectinfo *)ld->ld_selectinfo; 1132 1133 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); 1134 1135 #ifdef HAVE_POLL 1136 /* for UNIX poll(2) */ 1137 { 1138 int i; 1139 for(i=0; i < sip->si_maxfd; i++) { 1140 if( sip->si_fds[i].fd == sd ) { 1141 return sip->si_fds[i].revents & POLL_WRITE; 1142 } 1143 } 1144 1145 return 0; 1146 } 1147 #else 1148 /* for UNIX select(2) */ 1149 return( FD_ISSET( sd, &sip->si_use_writefds )); 1150 #endif 1151 } 1152 1153 1154 int 1155 ldap_is_read_ready( LDAP *ld, Sockbuf *sb ) 1156 { 1157 struct selectinfo *sip; 1158 ber_socket_t sd; 1159 1160 sip = (struct selectinfo *)ld->ld_selectinfo; 1161 1162 if (ber_sockbuf_ctrl( sb, LBER_SB_OPT_DATA_READY, NULL )) 1163 return 1; 1164 1165 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd ); 1166 1167 #ifdef HAVE_POLL 1168 /* for UNIX poll(2) */ 1169 { 1170 int i; 1171 for(i=0; i < sip->si_maxfd; i++) { 1172 if( sip->si_fds[i].fd == sd ) { 1173 return sip->si_fds[i].revents & POLL_READ; 1174 } 1175 } 1176 1177 return 0; 1178 } 1179 #else 1180 /* for UNIX select(2) */ 1181 return( FD_ISSET( sd, &sip->si_use_readfds )); 1182 #endif 1183 } 1184 1185 1186 void * 1187 ldap_new_select_info( void ) 1188 { 1189 struct selectinfo *sip; 1190 1191 sip = (struct selectinfo *)LDAP_CALLOC( 1, sizeof( struct selectinfo )); 1192 1193 if ( sip == NULL ) return NULL; 1194 1195 #ifdef HAVE_POLL 1196 /* for UNIX poll(2) */ 1197 /* sip->si_maxfd=0 */ 1198 #else 1199 /* for UNIX select(2) */ 1200 FD_ZERO( &sip->si_readfds ); 1201 FD_ZERO( &sip->si_writefds ); 1202 #endif 1203 1204 return( (void *)sip ); 1205 } 1206 1207 1208 void 1209 ldap_free_select_info( void *sip ) 1210 { 1211 LDAP_FREE( sip ); 1212 } 1213 1214 1215 #ifndef HAVE_POLL 1216 int ldap_int_tblsize = 0; 1217 1218 void 1219 ldap_int_ip_init( void ) 1220 { 1221 #if defined( HAVE_SYSCONF ) 1222 long tblsize = sysconf( _SC_OPEN_MAX ); 1223 if( tblsize > INT_MAX ) tblsize = INT_MAX; 1224 1225 #elif defined( HAVE_GETDTABLESIZE ) 1226 int tblsize = getdtablesize(); 1227 #else 1228 int tblsize = FD_SETSIZE; 1229 #endif /* !USE_SYSCONF */ 1230 1231 #ifdef FD_SETSIZE 1232 if( tblsize > FD_SETSIZE ) tblsize = FD_SETSIZE; 1233 #endif /* FD_SETSIZE */ 1234 1235 ldap_int_tblsize = tblsize; 1236 } 1237 #endif 1238 1239 1240 int 1241 ldap_int_select( LDAP *ld, struct timeval *timeout ) 1242 { 1243 int rc; 1244 struct selectinfo *sip; 1245 1246 Debug0( LDAP_DEBUG_TRACE, "ldap_int_select\n" ); 1247 1248 #ifndef HAVE_POLL 1249 if ( ldap_int_tblsize == 0 ) ldap_int_ip_init(); 1250 #endif 1251 1252 sip = (struct selectinfo *)ld->ld_selectinfo; 1253 assert( sip != NULL ); 1254 1255 #ifdef HAVE_POLL 1256 { 1257 int to = timeout ? TV2MILLISEC( timeout ) : INFTIM; 1258 rc = poll( sip->si_fds, sip->si_maxfd, to ); 1259 } 1260 #else 1261 sip->si_use_readfds = sip->si_readfds; 1262 sip->si_use_writefds = sip->si_writefds; 1263 1264 rc = select( ldap_int_tblsize, 1265 &sip->si_use_readfds, &sip->si_use_writefds, 1266 NULL, timeout ); 1267 #endif 1268 1269 return rc; 1270 } 1271