Back to index

openldap  2.4.31
os-local.c
Go to the documentation of this file.
00001 /* os-local.c -- platform-specific domain socket code */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 1998-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 /* Portions Copyright (c) 1995 Regents of the University of Michigan.
00017  * All rights reserved. 
00018  */
00019 /* Portions (C) Copyright PADL Software Pty Ltd. 1999
00020  * Redistribution and use in source and binary forms, with or without 
00021  * modification, are permitted provided that this notice is preserved
00022  * and that due credit is given to PADL Software Pty Ltd. This software
00023  * is provided ``as is'' without express or implied warranty.  
00024  */
00025 
00026 #include "portable.h"
00027 
00028 #ifdef LDAP_PF_LOCAL
00029 
00030 #include <stdio.h>
00031 
00032 #include <ac/stdlib.h>
00033 
00034 #include <ac/errno.h>
00035 #include <ac/socket.h>
00036 #include <ac/string.h>
00037 #include <ac/time.h>
00038 #include <ac/unistd.h>
00039 
00040 #ifdef HAVE_SYS_STAT_H
00041 #include <sys/stat.h>
00042 #endif
00043 #ifdef HAVE_SYS_UIO_H
00044 #include <sys/uio.h>
00045 #endif
00046 
00047 #ifdef HAVE_IO_H
00048 #include <io.h>
00049 #endif /* HAVE_IO_H */
00050 #ifdef HAVE_FCNTL_H
00051 #include <fcntl.h>
00052 #endif
00053 
00054 #include "ldap-int.h"
00055 #include "ldap_defaults.h"
00056 
00057 #ifdef LDAP_DEBUG
00058 
00059 #define oslocal_debug(ld,fmt,arg1,arg2,arg3) \
00060 do { \
00061        ldap_log_printf(ld, LDAP_DEBUG_TRACE, fmt, arg1, arg2, arg3); \
00062 } while(0)
00063 
00064 #else
00065 
00066 #define oslocal_debug(ld,fmt,arg1,arg2,arg3) ((void)0)
00067 
00068 #endif /* LDAP_DEBUG */
00069 
00070 static void
00071 ldap_pvt_set_errno(int err)
00072 {
00073        errno = err;
00074 }
00075 
00076 static int
00077 ldap_pvt_ndelay_on(LDAP *ld, int fd)
00078 {
00079        oslocal_debug(ld, "ldap_ndelay_on: %d\n",fd,0,0);
00080        return ber_pvt_socket_set_nonblock( fd, 1 );
00081 }
00082    
00083 static int
00084 ldap_pvt_ndelay_off(LDAP *ld, int fd)
00085 {
00086        oslocal_debug(ld, "ldap_ndelay_off: %d\n",fd,0,0);
00087        return ber_pvt_socket_set_nonblock( fd, 0 );
00088 }
00089 
00090 static ber_socket_t
00091 ldap_pvt_socket(LDAP *ld)
00092 {
00093        ber_socket_t s = socket(PF_LOCAL, SOCK_STREAM, 0);
00094        oslocal_debug(ld, "ldap_new_socket: %d\n",s,0,0);
00095 #ifdef FD_CLOEXEC
00096        fcntl(s, F_SETFD, FD_CLOEXEC);
00097 #endif
00098        return ( s );
00099 }
00100 
00101 static int
00102 ldap_pvt_close_socket(LDAP *ld, int s)
00103 {
00104        oslocal_debug(ld, "ldap_close_socket: %d\n",s,0,0);
00105        return tcp_close(s);
00106 }
00107 
00108 #undef TRACE
00109 #define TRACE do { \
00110        char ebuf[128]; \
00111        oslocal_debug(ld, \
00112               "ldap_is_socket_ready: errror on socket %d: errno: %d (%s)\n", \
00113               s, \
00114               errno, \
00115               AC_STRERROR_R(errno, ebuf, sizeof ebuf)); \
00116 } while( 0 )
00117 
00118 /*
00119  * check the socket for errors after select returned.
00120  */
00121 static int
00122 ldap_pvt_is_socket_ready(LDAP *ld, int s)
00123 {
00124        oslocal_debug(ld, "ldap_is_sock_ready: %d\n",s,0,0);
00125 
00126 #if defined( notyet ) /* && defined( SO_ERROR ) */
00127 {
00128        int so_errno;
00129        ber_socklen_t dummy = sizeof(so_errno);
00130        if ( getsockopt( s, SOL_SOCKET, SO_ERROR, &so_errno, &dummy )
00131               == AC_SOCKET_ERROR )
00132        {
00133               return -1;
00134        }
00135        if ( so_errno ) {
00136               ldap_pvt_set_errno(so_errno);
00137               TRACE;
00138               return -1;
00139        }
00140        return 0;
00141 }
00142 #else
00143 {
00144        /* error slippery */
00145        struct sockaddr_un sa;
00146        char ch;
00147        ber_socklen_t dummy = sizeof(sa);
00148        if ( getpeername( s, (struct sockaddr *) &sa, &dummy )
00149               == AC_SOCKET_ERROR )
00150        {
00151               /* XXX: needs to be replace with ber_stream_read() */
00152               (void)read(s, &ch, 1);
00153               TRACE;
00154               return -1;
00155        }
00156        return 0;
00157 }
00158 #endif
00159        return -1;
00160 }
00161 #undef TRACE
00162 
00163 #ifdef LDAP_PF_LOCAL_SENDMSG
00164 static const char abandonPDU[] = {LDAP_TAG_MESSAGE, 6,
00165        LDAP_TAG_MSGID, 1, 0, LDAP_REQ_ABANDON, 1, 0};
00166 #endif
00167 
00168 static int
00169 ldap_pvt_connect(LDAP *ld, ber_socket_t s, struct sockaddr_un *sa, int async)
00170 {
00171        int rc;
00172        struct timeval       tv, *opt_tv = NULL;
00173 
00174        if ( ld->ld_options.ldo_tm_net.tv_sec >= 0 ) {
00175               tv = ld->ld_options.ldo_tm_net;
00176               opt_tv = &tv;
00177        }
00178 
00179        oslocal_debug(ld, "ldap_connect_timeout: fd: %d tm: %ld async: %d\n",
00180               s, opt_tv ? tv.tv_sec : -1L, async);
00181 
00182        if ( ldap_pvt_ndelay_on(ld, s) == -1 ) return -1;
00183 
00184        if ( connect(s, (struct sockaddr *) sa, sizeof(struct sockaddr_un))
00185               != AC_SOCKET_ERROR )
00186        {
00187               if ( ldap_pvt_ndelay_off(ld, s) == -1 ) return -1;
00188 
00189 #ifdef LDAP_PF_LOCAL_SENDMSG
00190        /* Send a dummy message with access rights. Remote side will
00191         * obtain our uid/gid by fstat'ing this descriptor. The
00192         * descriptor permissions must match exactly, and we also
00193         * send the socket name, which must also match.
00194         */
00195 sendcred:
00196               {
00197                      int fds[2];
00198                      ber_socklen_t salen = sizeof(*sa);
00199                      if (pipe(fds) == 0) {
00200                             /* Abandon, noop, has no reply */
00201                             struct iovec iov;
00202                             struct msghdr msg = {0};
00203 # ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
00204 # ifndef CMSG_SPACE
00205 # define CMSG_SPACE(len)    (_CMSG_ALIGN( sizeof(struct cmsghdr)) + _CMSG_ALIGN(len) )
00206 # endif
00207 # ifndef CMSG_LEN
00208 # define CMSG_LEN(len)             (_CMSG_ALIGN( sizeof(struct cmsghdr)) + (len) )
00209 # endif
00210                             union {
00211                                    struct cmsghdr cm;
00212                                    unsigned char control[CMSG_SPACE(sizeof(int))];
00213                             } control_un;
00214                             struct cmsghdr *cmsg;
00215 # endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
00216                             msg.msg_name = NULL;
00217                             msg.msg_namelen = 0;
00218                             iov.iov_base = (char *) abandonPDU;
00219                             iov.iov_len = sizeof abandonPDU;
00220                             msg.msg_iov = &iov;
00221                             msg.msg_iovlen = 1;
00222 # ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL
00223                             msg.msg_control = control_un.control;
00224                             msg.msg_controllen = sizeof( control_un.control );
00225                             msg.msg_flags = 0;
00226 
00227                             cmsg = CMSG_FIRSTHDR( &msg );
00228                             cmsg->cmsg_len = CMSG_LEN( sizeof(int) );
00229                             cmsg->cmsg_level = SOL_SOCKET;
00230                             cmsg->cmsg_type = SCM_RIGHTS;
00231 
00232                             *((int *)CMSG_DATA(cmsg)) = fds[0];
00233 # else
00234                             msg.msg_accrights = (char *)fds;
00235                             msg.msg_accrightslen = sizeof(int);
00236 # endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL */
00237                             getpeername( s, (struct sockaddr *) sa, &salen );
00238                             fchmod( fds[0], S_ISUID|S_IRWXU );
00239                             write( fds[1], sa, salen );
00240                             sendmsg( s, &msg, 0 );
00241                             close(fds[0]);
00242                             close(fds[1]);
00243                      }
00244               }
00245 #endif
00246               return 0;
00247        }
00248 
00249        if ( errno != EINPROGRESS && errno != EWOULDBLOCK ) return -1;
00250        
00251 #ifdef notyet
00252        if ( async ) return -2;
00253 #endif
00254 
00255 #ifdef HAVE_POLL
00256        {
00257               struct pollfd fd;
00258               int timeout = INFTIM;
00259 
00260               if( opt_tv != NULL ) timeout = TV2MILLISEC( &tv );
00261 
00262               fd.fd = s;
00263               fd.events = POLL_WRITE;
00264 
00265               do {
00266                      fd.revents = 0;
00267                      rc = poll( &fd, 1, timeout );
00268               } while( rc == AC_SOCKET_ERROR && errno == EINTR &&
00269                      LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART ));
00270 
00271               if( rc == AC_SOCKET_ERROR ) return rc;
00272 
00273               if( fd.revents & POLL_WRITE ) {
00274                      if ( ldap_pvt_is_socket_ready(ld, s) == -1 ) return -1;
00275                      if ( ldap_pvt_ndelay_off(ld, s) == -1 ) return -1;
00276 #ifdef LDAP_PF_LOCAL_SENDMSG
00277                      goto sendcred;
00278 #else
00279                      return ( 0 );
00280 #endif
00281               }
00282        }
00283 #else
00284        {
00285               fd_set wfds, *z=NULL;
00286 
00287 #ifdef FD_SETSIZE
00288               if ( s >= FD_SETSIZE ) {
00289                      rc = AC_SOCKET_ERROR;
00290                      tcp_close( s );
00291                      ldap_pvt_set_errno( EMFILE );
00292                      return rc;
00293               }
00294 #endif
00295               do { 
00296                      FD_ZERO(&wfds);
00297                      FD_SET(s, &wfds );
00298                      rc = select( ldap_int_tblsize, z, &wfds, z, opt_tv ? &tv : NULL );
00299               } while( rc == AC_SOCKET_ERROR && errno == EINTR &&
00300                      LDAP_BOOL_GET(&ld->ld_options, LDAP_BOOL_RESTART ));
00301 
00302               if( rc == AC_SOCKET_ERROR ) return rc;
00303 
00304               if ( FD_ISSET(s, &wfds) ) {
00305                      if ( ldap_pvt_is_socket_ready(ld, s) == -1 ) return -1;
00306                      if ( ldap_pvt_ndelay_off(ld, s) == -1 ) return -1;
00307 #ifdef LDAP_PF_LOCAL_SENDMSG
00308                      goto sendcred;
00309 #else
00310                      return ( 0 );
00311 #endif
00312               }
00313        }
00314 #endif
00315 
00316        oslocal_debug(ld, "ldap_connect_timeout: timed out\n",0,0,0);
00317        ldap_pvt_set_errno( ETIMEDOUT );
00318        return ( -1 );
00319 }
00320 
00321 int
00322 ldap_connect_to_path(LDAP *ld, Sockbuf *sb, LDAPURLDesc *srv, int async)
00323 {
00324        struct sockaddr_un   server;
00325        ber_socket_t         s;
00326        int                  rc;
00327        const char *path = srv->lud_host;
00328 
00329        oslocal_debug(ld, "ldap_connect_to_path\n",0,0,0);
00330 
00331        if ( path == NULL || path[0] == '\0' ) {
00332               path = LDAPI_SOCK;
00333        } else {
00334               if ( strlen(path) > (sizeof( server.sun_path ) - 1) ) {
00335                      ldap_pvt_set_errno( ENAMETOOLONG );
00336                      return -1;
00337               }
00338        }
00339 
00340        s = ldap_pvt_socket( ld );
00341        if ( s == AC_SOCKET_INVALID ) {
00342               return -1;
00343        }
00344 
00345        oslocal_debug(ld, "ldap_connect_to_path: Trying %s\n", path, 0, 0);
00346 
00347        memset( &server, '\0', sizeof(server) );
00348        server.sun_family = AF_LOCAL;
00349        strcpy( server.sun_path, path );
00350 
00351        rc = ldap_pvt_connect(ld, s, &server, async);
00352 
00353        if (rc == 0) {
00354               rc = ldap_int_connect_cbs( ld, sb, &s, srv, (struct sockaddr *)&server );
00355        }
00356        if ( rc ) {
00357               ldap_pvt_close_socket(ld, s);
00358        }
00359        return rc;
00360 }
00361 #else
00362 static int dummy;
00363 #endif /* LDAP_PF_LOCAL */