1 /* $NetBSD: os-ip.c,v 1.11 2021/08/14 16:14:56 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-2021 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.11 2021/08/14 16:14:56 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
ldap_pvt_set_errno(int err)59 ldap_pvt_set_errno(int err)
60 {
61 sock_errset(err);
62 }
63
64 int
ldap_int_timeval_dup(struct timeval ** dest,const struct timeval * src)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
ldap_pvt_ndelay_on(LDAP * ld,int fd)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
ldap_pvt_ndelay_off(LDAP * ld,int fd)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
ldap_int_socket(LDAP * ld,int family,int type)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
ldap_pvt_close_socket(LDAP * ld,int s)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
ldap_int_prepare_socket(LDAP * ld,int s,int proto)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
ldap_pvt_is_socket_ready(LDAP * ld,int s)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
ldap_int_poll(LDAP * ld,ber_socket_t s,struct timeval * tvp,int wr)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
ldap_pvt_connect(LDAP * ld,ber_socket_t s,struct sockaddr * sin,ber_socklen_t addrlen,int async)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
ldap_pvt_inet_aton(const char * host,struct in_addr * in)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
ldap_validate_and_fill_sourceip(char ** source_ip_lst,ldapsourceip * temp_source_ip)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
ldap_int_connect_cbs(LDAP * ld,Sockbuf * sb,ber_socket_t * s,LDAPURLDesc * srv,struct sockaddr * addr)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
ldap_connect_to_host(LDAP * ld,Sockbuf * sb,int proto,LDAPURLDesc * srv,int async)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_addr = ld->ld_options.ldo_local_ip_addrs.ip6_addr;
706 inet_ntop( AF_INET6,
707 &(ip6addr.sin6_addr),
708 bind_addr, sizeof bind_addr );
709 Debug1( LDAP_DEBUG_TRACE,
710 "ldap_connect_to_host: From source address %s\n",
711 bind_addr );
712 if ( bind( s, ( struct sockaddr* ) &ip6addr, sizeof ip6addr ) != 0 ) {
713 Debug1( LDAP_DEBUG_TRACE,
714 "ldap_connect_to_host: Failed to bind source address %s\n",
715 bind_addr );
716 bind_success = 0;
717 }
718 }
719 } break;
720 #endif
721 case AF_INET: {
722 char addr[INET_ADDRSTRLEN];
723 inet_ntop( AF_INET,
724 &((struct sockaddr_in *)sai->ai_addr)->sin_addr,
725 addr, sizeof addr);
726 Debug2(LDAP_DEBUG_TRACE,
727 "ldap_connect_to_host: Trying %s:%s\n",
728 addr, serv );
729 if( ld->ld_options.ldo_local_ip_addrs.has_ipv4 ) {
730 struct sockaddr_in ip4addr;
731 char bind_addr[INET_ADDRSTRLEN];
732 ip4addr.sin_family = AF_INET;
733 ip4addr.sin_addr = ld->ld_options.ldo_local_ip_addrs.ip4_addr;
734 inet_ntop( AF_INET,
735 &(ip4addr.sin_addr),
736 bind_addr, sizeof bind_addr );
737 Debug1( LDAP_DEBUG_TRACE,
738 "ldap_connect_to_host: From source address %s\n",
739 bind_addr );
740 if ( bind(s, ( struct sockaddr* )&ip4addr, sizeof ip4addr ) != 0 ) {
741 Debug1( LDAP_DEBUG_TRACE,
742 "ldap_connect_to_host: Failed to bind source address %s\n",
743 bind_addr );
744 bind_success = 0;
745 }
746 }
747 } break;
748 }
749 if ( bind_success ) {
750 rc = ldap_pvt_connect( ld, s,
751 sai->ai_addr, sai->ai_addrlen, async );
752 if ( rc == 0 || rc == -2 ) {
753 err = ldap_int_connect_cbs( ld, sb, &s, srv, sai->ai_addr );
754 if ( err )
755 rc = err;
756 else
757 break;
758 }
759 }
760 ldap_pvt_close_socket(ld, s);
761 }
762 freeaddrinfo(res);
763
764 #else
765 if (! inet_aton( host, &in ) ) {
766 int local_h_errno;
767 rc = ldap_pvt_gethostbyname_a( host, &he_buf, &ha_buf,
768 &hp, &local_h_errno );
769
770 if ( (rc < 0) || (hp == NULL) ) {
771 #ifdef HAVE_WINSOCK
772 ldap_pvt_set_errno( WSAGetLastError() );
773 #else
774 /* not exactly right, but... */
775 ldap_pvt_set_errno( EHOSTUNREACH );
776 #endif
777 if (ha_buf) LDAP_FREE(ha_buf);
778 return -1;
779 }
780
781 use_hp = 1;
782 }
783
784 rc = s = -1;
785 for ( i = 0; !use_hp || (hp->h_addr_list[i] != 0); ++i, rc = -1 ) {
786 struct sockaddr_in sin;
787 unsigned short bind_success = 1;
788 #ifdef HAVE_INET_NTOA_B
789 char address[INET_ADDR_LEN];
790 char bind_addr[INET_ADDR_LEN];
791 #else
792 char *address;
793 char *bind_addr;
794 #endif
795 s = ldap_int_socket( ld, PF_INET, socktype );
796 if ( s == AC_SOCKET_INVALID ) {
797 /* use_hp ? continue : break; */
798 break;
799 }
800
801 if ( ldap_int_prepare_socket( ld, s, proto ) == -1 ) {
802 ldap_pvt_close_socket(ld, s);
803 break;
804 }
805
806 (void)memset((char *)&sin, '\0', sizeof sin);
807 sin.sin_family = AF_INET;
808 sin.sin_port = htons((unsigned short) port);
809
810 if( use_hp ) {
811 AC_MEMCPY( &sin.sin_addr, hp->h_addr_list[i],
812 sizeof(sin.sin_addr) );
813 } else {
814 AC_MEMCPY( &sin.sin_addr, &in.s_addr,
815 sizeof(sin.sin_addr) );
816 }
817
818 #ifdef HAVE_INET_NTOA_B
819 /* for VxWorks */
820 inet_ntoa_b( sin.sin_address, address );
821 #else
822 address = inet_ntoa( sin.sin_addr );
823 #endif
824 Debug2( LDAP_DEBUG_TRACE,
825 "ldap_connect_to_host: Trying %s:%d\n",
826 address, port );
827 if( ld->ld_options.ldo_local_ip_addrs.has_ipv4 ) {
828 struct sockaddr_in ip4addr;
829 ip4addr.sin_family = AF_INET;
830 ip4addr.sin_addr = ld->ld_options.ldo_local_ip_addrs.ip4_addr;
831 #ifdef HAVE_INET_NTOA_B
832 inet_ntoa_b( ip4addr.sin_address, bind_addr );
833 #else
834 bind_addr = inet_ntoa( ip4addr.sin_addr );
835 #endif
836 Debug1( LDAP_DEBUG_TRACE,
837 "ldap_connect_to_host: From source address %s\n",
838 bind_addr );
839 if ( bind( s, (struct sockaddr*)&ip4addr, sizeof ip4addr ) != 0 ) {
840 Debug1( LDAP_DEBUG_TRACE,
841 "ldap_connect_to_host: Failed to bind source address %s\n",
842 bind_addr );
843 bind_success = 0;
844 }
845 }
846 if ( bind_success ) {
847 rc = ldap_pvt_connect(ld, s,
848 (struct sockaddr *)&sin, sizeof(sin),
849 async);
850
851 if ( (rc == 0) || (rc == -2) ) {
852 int err = ldap_int_connect_cbs( ld, sb, &s, srv, (struct sockaddr *)&sin );
853 if ( err )
854 rc = err;
855 else
856 break;
857 }
858 }
859
860 ldap_pvt_close_socket(ld, s);
861
862 if (!use_hp) break;
863 }
864 if (ha_buf) LDAP_FREE(ha_buf);
865 #endif
866
867 return rc;
868 }
869
870 #if defined( HAVE_CYRUS_SASL )
871 char *
ldap_host_connected_to(Sockbuf * sb,const char * host)872 ldap_host_connected_to( Sockbuf *sb, const char *host )
873 {
874 ber_socklen_t len;
875 #ifdef LDAP_PF_INET6
876 struct sockaddr_storage sabuf;
877 #else
878 struct sockaddr sabuf;
879 #endif
880 struct sockaddr *sa = (struct sockaddr *) &sabuf;
881 ber_socket_t sd;
882
883 (void)memset( (char *)sa, '\0', sizeof sabuf );
884 len = sizeof sabuf;
885
886 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
887 if ( getpeername( sd, sa, &len ) == -1 ) {
888 return( NULL );
889 }
890
891 /*
892 * do a reverse lookup on the addr to get the official hostname.
893 * this is necessary for kerberos to work right, since the official
894 * hostname is used as the kerberos instance.
895 */
896
897 switch (sa->sa_family) {
898 #ifdef LDAP_PF_LOCAL
899 case AF_LOCAL:
900 return LDAP_STRDUP( ldap_int_hostname );
901 #endif
902 #ifdef LDAP_PF_INET6
903 case AF_INET6:
904 {
905 struct in6_addr localhost = IN6ADDR_LOOPBACK_INIT;
906 if( memcmp ( &((struct sockaddr_in6 *)sa)->sin6_addr,
907 &localhost, sizeof(localhost)) == 0 )
908 {
909 return LDAP_STRDUP( ldap_int_hostname );
910 }
911 }
912 break;
913 #endif
914 case AF_INET:
915 {
916 struct in_addr localhost;
917 localhost.s_addr = htonl( INADDR_ANY );
918
919 if( memcmp ( &((struct sockaddr_in *)sa)->sin_addr,
920 &localhost, sizeof(localhost) ) == 0 )
921 {
922 return LDAP_STRDUP( ldap_int_hostname );
923 }
924
925 #ifdef INADDR_LOOPBACK
926 localhost.s_addr = htonl( INADDR_LOOPBACK );
927
928 if( memcmp ( &((struct sockaddr_in *)sa)->sin_addr,
929 &localhost, sizeof(localhost) ) == 0 )
930 {
931 return LDAP_STRDUP( ldap_int_hostname );
932 }
933 #endif
934 }
935 break;
936
937 default:
938 return( NULL );
939 break;
940 }
941
942 {
943 char *herr;
944 #ifdef NI_MAXHOST
945 char hbuf[NI_MAXHOST];
946 #elif defined( MAXHOSTNAMELEN )
947 char hbuf[MAXHOSTNAMELEN];
948 #else
949 char hbuf[256];
950 #endif
951 hbuf[0] = 0;
952
953 if (ldap_pvt_get_hname( sa, len, hbuf, sizeof(hbuf), &herr ) == 0
954 && hbuf[0] )
955 {
956 return LDAP_STRDUP( hbuf );
957 }
958 }
959
960 return host ? LDAP_STRDUP( host ) : NULL;
961 }
962 #endif
963
964
965 struct selectinfo {
966 #ifdef HAVE_POLL
967 /* for UNIX poll(2) */
968 int si_maxfd;
969 struct pollfd si_fds[FD_SETSIZE];
970 #else
971 /* for UNIX select(2) */
972 fd_set si_readfds;
973 fd_set si_writefds;
974 fd_set si_use_readfds;
975 fd_set si_use_writefds;
976 #endif
977 };
978
979 void
ldap_mark_select_write(LDAP * ld,Sockbuf * sb)980 ldap_mark_select_write( LDAP *ld, Sockbuf *sb )
981 {
982 struct selectinfo *sip;
983 ber_socket_t sd;
984
985 sip = (struct selectinfo *)ld->ld_selectinfo;
986
987 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
988
989 #ifdef HAVE_POLL
990 /* for UNIX poll(2) */
991 {
992 int empty=-1;
993 int i;
994 for(i=0; i < sip->si_maxfd; i++) {
995 if( sip->si_fds[i].fd == sd ) {
996 sip->si_fds[i].events |= POLL_WRITE;
997 return;
998 }
999 if( empty==-1 && sip->si_fds[i].fd == -1 ) {
1000 empty=i;
1001 }
1002 }
1003
1004 if( empty == -1 ) {
1005 if( sip->si_maxfd >= FD_SETSIZE ) {
1006 /* FIXME */
1007 return;
1008 }
1009 empty = sip->si_maxfd++;
1010 }
1011
1012 sip->si_fds[empty].fd = sd;
1013 sip->si_fds[empty].events = POLL_WRITE;
1014 }
1015 #else
1016 /* for UNIX select(2) */
1017 if ( !FD_ISSET( sd, &sip->si_writefds )) {
1018 FD_SET( sd, &sip->si_writefds );
1019 }
1020 #endif
1021 }
1022
1023
1024 void
ldap_mark_select_read(LDAP * ld,Sockbuf * sb)1025 ldap_mark_select_read( LDAP *ld, Sockbuf *sb )
1026 {
1027 struct selectinfo *sip;
1028 ber_socket_t sd;
1029
1030 sip = (struct selectinfo *)ld->ld_selectinfo;
1031
1032 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
1033
1034 #ifdef HAVE_POLL
1035 /* for UNIX poll(2) */
1036 {
1037 int empty=-1;
1038 int i;
1039 for(i=0; i < sip->si_maxfd; i++) {
1040 if( sip->si_fds[i].fd == sd ) {
1041 sip->si_fds[i].events |= POLL_READ;
1042 return;
1043 }
1044 if( empty==-1 && sip->si_fds[i].fd == -1 ) {
1045 empty=i;
1046 }
1047 }
1048
1049 if( empty == -1 ) {
1050 if( sip->si_maxfd >= FD_SETSIZE ) {
1051 /* FIXME */
1052 return;
1053 }
1054 empty = sip->si_maxfd++;
1055 }
1056
1057 sip->si_fds[empty].fd = sd;
1058 sip->si_fds[empty].events = POLL_READ;
1059 }
1060 #else
1061 /* for UNIX select(2) */
1062 if ( !FD_ISSET( sd, &sip->si_readfds )) {
1063 FD_SET( sd, &sip->si_readfds );
1064 }
1065 #endif
1066 }
1067
1068
1069 void
ldap_mark_select_clear(LDAP * ld,Sockbuf * sb)1070 ldap_mark_select_clear( LDAP *ld, Sockbuf *sb )
1071 {
1072 struct selectinfo *sip;
1073 ber_socket_t sd;
1074
1075 sip = (struct selectinfo *)ld->ld_selectinfo;
1076
1077 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
1078
1079 #ifdef HAVE_POLL
1080 /* for UNIX poll(2) */
1081 {
1082 int i;
1083 for(i=0; i < sip->si_maxfd; i++) {
1084 if( sip->si_fds[i].fd == sd ) {
1085 sip->si_fds[i].fd = -1;
1086 }
1087 }
1088 }
1089 #else
1090 /* for UNIX select(2) */
1091 FD_CLR( sd, &sip->si_writefds );
1092 FD_CLR( sd, &sip->si_readfds );
1093 #endif
1094 }
1095
1096 void
ldap_clear_select_write(LDAP * ld,Sockbuf * sb)1097 ldap_clear_select_write( LDAP *ld, Sockbuf *sb )
1098 {
1099 struct selectinfo *sip;
1100 ber_socket_t sd;
1101
1102 sip = (struct selectinfo *)ld->ld_selectinfo;
1103
1104 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
1105
1106 #ifdef HAVE_POLL
1107 /* for UNIX poll(2) */
1108 {
1109 int i;
1110 for(i=0; i < sip->si_maxfd; i++) {
1111 if( sip->si_fds[i].fd == sd ) {
1112 sip->si_fds[i].events &= ~POLL_WRITE;
1113 }
1114 }
1115 }
1116 #else
1117 /* for UNIX select(2) */
1118 FD_CLR( sd, &sip->si_writefds );
1119 #endif
1120 }
1121
1122
1123 int
ldap_is_write_ready(LDAP * ld,Sockbuf * sb)1124 ldap_is_write_ready( LDAP *ld, Sockbuf *sb )
1125 {
1126 struct selectinfo *sip;
1127 ber_socket_t sd;
1128
1129 sip = (struct selectinfo *)ld->ld_selectinfo;
1130
1131 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
1132
1133 #ifdef HAVE_POLL
1134 /* for UNIX poll(2) */
1135 {
1136 int i;
1137 for(i=0; i < sip->si_maxfd; i++) {
1138 if( sip->si_fds[i].fd == sd ) {
1139 return sip->si_fds[i].revents & POLL_WRITE;
1140 }
1141 }
1142
1143 return 0;
1144 }
1145 #else
1146 /* for UNIX select(2) */
1147 return( FD_ISSET( sd, &sip->si_use_writefds ));
1148 #endif
1149 }
1150
1151
1152 int
ldap_is_read_ready(LDAP * ld,Sockbuf * sb)1153 ldap_is_read_ready( LDAP *ld, Sockbuf *sb )
1154 {
1155 struct selectinfo *sip;
1156 ber_socket_t sd;
1157
1158 sip = (struct selectinfo *)ld->ld_selectinfo;
1159
1160 if (ber_sockbuf_ctrl( sb, LBER_SB_OPT_DATA_READY, NULL ))
1161 return 1;
1162
1163 ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
1164
1165 #ifdef HAVE_POLL
1166 /* for UNIX poll(2) */
1167 {
1168 int i;
1169 for(i=0; i < sip->si_maxfd; i++) {
1170 if( sip->si_fds[i].fd == sd ) {
1171 return sip->si_fds[i].revents & POLL_READ;
1172 }
1173 }
1174
1175 return 0;
1176 }
1177 #else
1178 /* for UNIX select(2) */
1179 return( FD_ISSET( sd, &sip->si_use_readfds ));
1180 #endif
1181 }
1182
1183
1184 void *
ldap_new_select_info(void)1185 ldap_new_select_info( void )
1186 {
1187 struct selectinfo *sip;
1188
1189 sip = (struct selectinfo *)LDAP_CALLOC( 1, sizeof( struct selectinfo ));
1190
1191 if ( sip == NULL ) return NULL;
1192
1193 #ifdef HAVE_POLL
1194 /* for UNIX poll(2) */
1195 /* sip->si_maxfd=0 */
1196 #else
1197 /* for UNIX select(2) */
1198 FD_ZERO( &sip->si_readfds );
1199 FD_ZERO( &sip->si_writefds );
1200 #endif
1201
1202 return( (void *)sip );
1203 }
1204
1205
1206 void
ldap_free_select_info(void * sip)1207 ldap_free_select_info( void *sip )
1208 {
1209 LDAP_FREE( sip );
1210 }
1211
1212
1213 #ifndef HAVE_POLL
1214 int ldap_int_tblsize = 0;
1215
1216 void
ldap_int_ip_init(void)1217 ldap_int_ip_init( void )
1218 {
1219 #if defined( HAVE_SYSCONF )
1220 long tblsize = sysconf( _SC_OPEN_MAX );
1221 if( tblsize > INT_MAX ) tblsize = INT_MAX;
1222
1223 #elif defined( HAVE_GETDTABLESIZE )
1224 int tblsize = getdtablesize();
1225 #else
1226 int tblsize = FD_SETSIZE;
1227 #endif /* !USE_SYSCONF */
1228
1229 #ifdef FD_SETSIZE
1230 if( tblsize > FD_SETSIZE ) tblsize = FD_SETSIZE;
1231 #endif /* FD_SETSIZE */
1232
1233 ldap_int_tblsize = tblsize;
1234 }
1235 #endif
1236
1237
1238 int
ldap_int_select(LDAP * ld,struct timeval * timeout)1239 ldap_int_select( LDAP *ld, struct timeval *timeout )
1240 {
1241 int rc;
1242 struct selectinfo *sip;
1243
1244 Debug0( LDAP_DEBUG_TRACE, "ldap_int_select\n" );
1245
1246 #ifndef HAVE_POLL
1247 if ( ldap_int_tblsize == 0 ) ldap_int_ip_init();
1248 #endif
1249
1250 sip = (struct selectinfo *)ld->ld_selectinfo;
1251 assert( sip != NULL );
1252
1253 #ifdef HAVE_POLL
1254 {
1255 int to = timeout ? TV2MILLISEC( timeout ) : INFTIM;
1256 rc = poll( sip->si_fds, sip->si_maxfd, to );
1257 }
1258 #else
1259 sip->si_use_readfds = sip->si_readfds;
1260 sip->si_use_writefds = sip->si_writefds;
1261
1262 rc = select( ldap_int_tblsize,
1263 &sip->si_use_readfds, &sip->si_use_writefds,
1264 NULL, timeout );
1265 #endif
1266
1267 return rc;
1268 }
1269