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