From 7426ab07fc8cc231598e439663e73230a21190df Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Sun, 25 Mar 2007 04:40:22 +0000 Subject: [PATCH] ITS#4893 define LDAP_PF_LOCAL_SENDMSG in if a message must be sent to transmit client credentials. Buffer the message data. --- include/ac/socket.h | 20 +++++++++-- include/lber.h | 6 +++- libraries/liblber/lber-int.h | 6 +++- libraries/liblber/sockbuf.c | 32 ++++++++++++++++++ libraries/libldap/os-local.c | 13 +++----- libraries/liblutil/getpeereid.c | 59 ++++++++++++++++++--------------- servers/slapd/connection.c | 17 +++++----- servers/slapd/daemon.c | 30 ++++++++++++----- servers/slapd/proto-slap.h | 2 +- 9 files changed, 127 insertions(+), 58 deletions(-) diff --git a/include/ac/socket.h b/include/ac/socket.h index 0496c4d62c..3ee751e3a6 100644 --- a/include/ac/socket.h +++ b/include/ac/socket.h @@ -213,8 +213,24 @@ LDAP_F (int) ldap_pvt_inet_aton LDAP_P(( const char *, struct in_addr * )); # endif #endif -#ifndef HAVE_GETPEEREID -LDAP_LUTIL_F( int ) getpeereid( int s, uid_t *, gid_t * ); +#if defined(LDAP_PF_LOCAL) && \ + !defined(HAVE_GETPEEREID) && \ + !defined(HAVE_GETPEERUCRED) && \ + !defined(SO_PEERCRED) && !defined(LOCAL_PEERCRED) && \ + defined(HAVE_SENDMSG) && (defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTSLEN) || \ + defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)) +# define LDAP_PF_LOCAL_SENDMSG 1 +#endif + +#ifdef HAVE_GETPEEREID +#define LUTIL_GETPEEREID( s, uid, gid, bv ) getpeereid( s, uid, gid ) +#elif defined(LDAP_PF_LOCAL_SENDMSG) +struct berval; +LDAP_LUTIL_F( int ) lutil_getpeereid( int s, uid_t *, gid_t *, struct berval *bv ); +#define LUTIL_GETPEEREID( s, uid, gid, bv ) lutil_getpeereid( s, uid, gid, bv ) +#else +LDAP_LUTIL_F( int ) lutil_getpeereid( int s, uid_t *, gid_t * ); +#define LUTIL_GETPEEREID( s, uid, gid, bv ) lutil_getpeereid( s, uid, gid ) #endif /* DNS RFC defines max host name as 255. New systems seem to use 1024 */ diff --git a/include/lber.h b/include/lber.h index 9d05c4f546..4b3a8d5ecd 100644 --- a/include/lber.h +++ b/include/lber.h @@ -138,8 +138,12 @@ typedef struct lber_memory_fns { #define LBER_SB_OPT_NEEDS_WRITE 12 #define LBER_SB_OPT_GET_MAX_INCOMING 13 #define LBER_SB_OPT_SET_MAX_INCOMING 14 + +/* Only meaningful ifdef LDAP_PF_LOCAL_SENDMSG */ +#define LBER_SB_OPT_UNGET_BUF 15 + /* Largest option used by the library */ -#define LBER_SB_OPT_OPT_MAX 14 +#define LBER_SB_OPT_OPT_MAX 15 /* LBER IO operations stacking levels */ #define LBER_SBIOD_LEVEL_PROVIDER 10 diff --git a/libraries/liblber/lber-int.h b/libraries/liblber/lber-int.h index 4e73a58ebb..9870f3bdda 100644 --- a/libraries/liblber/lber-int.h +++ b/libraries/liblber/lber-int.h @@ -99,9 +99,13 @@ struct sockbuf { #define sb_options sb_opts.lbo_options #define sb_debug sb_opts.lbo_debug ber_socket_t sb_fd; + ber_len_t sb_max_incoming; unsigned int sb_trans_needs_read:1; unsigned int sb_trans_needs_write:1; - ber_len_t sb_max_incoming; +#ifdef LDAP_PF_LOCAL_SENDMSG + char sb_ungetlen; + char sb_ungetbuf[8]; +#endif }; #define SOCKBUF_VALID( sb ) ( (sb)->sb_valid == LBER_VALID_SOCKBUF ) diff --git a/libraries/liblber/sockbuf.c b/libraries/liblber/sockbuf.c index 353d526320..2739b185e1 100644 --- a/libraries/liblber/sockbuf.c +++ b/libraries/liblber/sockbuf.c @@ -150,6 +150,20 @@ ber_sockbuf_ctrl( Sockbuf *sb, int opt, void *arg ) ret = 1; break; + case LBER_SB_OPT_UNGET_BUF: +#ifdef LDAP_PF_LOCAL_SENDMSG + sb->sb_ungetlen = ((struct berval *)arg)->bv_len; + if ( sb->sb_ungetlen <= sizeof( sb->sb_ungetbuf )) { + AC_MEMCPY( sb->sb_ungetbuf, ((struct berval *)arg)->bv_val, + sb->sb_ungetlen ); + ret = 1; + } else { + sb->sb_ungetlen = 0; + ret = -1; + } +#endif + break; + default: ret = sb->sb_iod->sbiod_io->sbi_ctrl( sb->sb_iod, opt, arg ); break; @@ -704,6 +718,24 @@ sb_fd_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len ) assert( sbiod != NULL); assert( SOCKBUF_VALID( sbiod->sbiod_sb ) ); +#ifdef LDAP_PF_LOCAL_SENDMSG + if ( sbiod->sbiod_sb->sb_ungetlen ) { + ber_len_t blen = sbiod->sbiod_sb->sb_ungetlen; + if ( blen > len ) + blen = len; + AC_MEMCPY( buf, sbiod->sbiod_sb->sb_ungetbuf, blen ); + buf += blen; + len -= blen; + if ( blen < sbiod->sbiod_sb->sb_ungetlen ) { + sbiod->sbiod_sb->sb_ungetlen -= blen; + AC_MEMCPY( sbiod->sbiod_sb->sb_ungetbuf, + sbiod->sbiod_sb->sb_ungetbuf+blen, + sbiod->sbiod_sb->sb_ungetlen ); + } + if ( len == 0 ) + return blen; + } +#endif return read( sbiod->sbiod_sb->sb_fd, buf, len ); } diff --git a/libraries/libldap/os-local.c b/libraries/libldap/os-local.c index 4e3a19e5a2..fa8562369a 100644 --- a/libraries/libldap/os-local.c +++ b/libraries/libldap/os-local.c @@ -154,12 +154,7 @@ ldap_pvt_is_socket_ready(LDAP *ld, int s) } #undef TRACE -#if !defined(HAVE_GETPEEREID) && \ - !defined(HAVE_GETPEERUCRED) && \ - !defined(SO_PEERCRED) && !defined(LOCAL_PEERCRED) && \ - defined(HAVE_SENDMSG) && (defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTSLEN) || \ - defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)) -#define DO_SENDMSG +#ifdef LDAP_PF_LOCAL_SENDMSG static const char abandonPDU[] = {LDAP_TAG_MESSAGE, 6, LDAP_TAG_MSGID, 1, 0, LDAP_REQ_ABANDON, 1, 0}; #endif @@ -185,7 +180,7 @@ ldap_pvt_connect(LDAP *ld, ber_socket_t s, struct sockaddr_un *sa, int async) { if ( ldap_pvt_ndelay_off(ld, s) == -1 ) return -1; -#ifdef DO_SENDMSG +#ifdef LDAP_PF_LOCAL_SENDMSG /* Send a dummy message with access rights. Remote side will * obtain our uid/gid by fstat'ing this descriptor. */ @@ -266,7 +261,7 @@ sendcred: if( fd.revents & POLL_WRITE ) { if ( ldap_pvt_is_socket_ready(ld, s) == -1 ) return -1; if ( ldap_pvt_ndelay_off(ld, s) == -1 ) return -1; -#ifdef DO_SENDMSG +#ifdef LDAP_PF_LOCAL_SENDMSG goto sendcred; #else return ( 0 ); @@ -297,7 +292,7 @@ sendcred: if ( FD_ISSET(s, &wfds) ) { if ( ldap_pvt_is_socket_ready(ld, s) == -1 ) return -1; if ( ldap_pvt_ndelay_off(ld, s) == -1 ) return -1; -#ifdef DO_SENDMSG +#ifdef LDAP_PF_LOCAL_SENDMSG goto sendcred; #else return ( 0 ); diff --git a/libraries/liblutil/getpeereid.c b/libraries/liblutil/getpeereid.c index 97d87982ab..08e482e16a 100644 --- a/libraries/liblutil/getpeereid.c +++ b/libraries/liblutil/getpeereid.c @@ -21,6 +21,14 @@ #include #include +#ifdef LDAP_PF_LOCAL_SENDMSG +#include +#ifdef HAVE_SYS_UIO_H +#include +#endif +#include +#endif + #include #include @@ -35,21 +43,13 @@ #include #endif -#if !defined(HAVE_GETPEERUCRED) && \ - !defined(SO_PEERCRED) && !defined(LOCAL_PEERCRED) && \ - defined(HAVE_SENDMSG) && (defined(HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTSLEN) || \ - defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)) -#define DO_SENDMSG -#ifdef HAVE_SYS_UIO_H -#include -#endif -#include -#endif - #include - -int getpeereid( int s, uid_t *euid, gid_t *egid ) +int lutil_getpeereid( int s, uid_t *euid, gid_t *egid +#ifdef LDAP_PF_LOCAL_SENDMSG + , struct berval *peerbv +#endif + ) { #ifdef LDAP_PF_LOCAL #if defined( HAVE_GETPEERUCRED ) @@ -85,9 +85,8 @@ int getpeereid( int s, uid_t *euid, gid_t *egid ) *egid = peercred.cr_gid; return 0; } -#elif defined( DO_SENDMSG ) - char dummy[8]; - int err, fd[2]; +#elif defined( LDAP_PF_LOCAL_SENDMSG ) + int err, fd; struct iovec iov; struct msghdr msg = {0}; # ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL @@ -108,8 +107,8 @@ int getpeereid( int s, uid_t *euid, gid_t *egid ) msg.msg_name = NULL; msg.msg_namelen = 0; - iov.iov_base = dummy; - iov.iov_len = sizeof dummy; + iov.iov_base = peerbv->bv_val; + iov.iov_len = peerbv->bv_len; msg.msg_iov = &iov; msg.msg_iovlen = 1; # ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL @@ -117,30 +116,34 @@ int getpeereid( int s, uid_t *euid, gid_t *egid ) msg.msg_controllen = sizeof( control_un.control ); cmsg = CMSG_FIRSTHDR( &msg ); +# else + msg.msg_accrights = (char *)&fd; + msg.msg_accrightslen = sizeof(fd); +# endif /* * AIX returns a bogus file descriptor if recvmsg() is * called with MSG_PEEK (is this a bug?). Hence we need * to receive the Abandon PDU. */ - if( recvmsg( s, &msg, MSG_WAITALL ) >= 0 && + peerbv->bv_len = recvmsg( s, &msg, MSG_WAITALL ); + if( peerbv->bv_len >= 0 && +# ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL cmsg->cmsg_len == CMSG_LEN( sizeof(int) ) && cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_RIGHTS ) + cmsg->cmsg_type == SCM_RIGHTS # else - msg.msg_accrights = (char *)fd; - msg.msg_accrightslen = sizeof(fd); - if( recvmsg( s, &msg, MSG_PEEK) >= 0 && msg.msg_accrightslen == sizeof(int) ) + msg.msg_accrightslen == sizeof(int) # endif /* HAVE_STRUCT_MSGHDR_MSG_CONTROL*/ - { + ) { /* We must receive a valid descriptor, it must be a pipe, * and it must only be accessible by its owner. */ # ifdef HAVE_STRUCT_MSGHDR_MSG_CONTROL - fd[0] = (*(int *)CMSG_DATA( cmsg )); + fd = (*(int *)CMSG_DATA( cmsg )); # endif - err = fstat( fd[0], &st ); - close(fd[0]); + err = fstat( fd, &st ); + close(fd); if( err == 0 && S_ISFIFO(st.st_mode) && ((st.st_mode & (S_IRWXG|S_IRWXO)) == 0)) { @@ -148,6 +151,8 @@ int getpeereid( int s, uid_t *euid, gid_t *egid ) *egid = st.st_gid; return 0; } + } else if ( peer->bv_len < 0 ) { + peer->bv_len = 0; } #elif defined(SOCKCREDSIZE) struct msghdr msg; diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c index 42f86865c6..9c0c05e778 100644 --- a/servers/slapd/connection.c +++ b/servers/slapd/connection.c @@ -359,7 +359,7 @@ static void connection_return( Connection *c ) ldap_pvt_thread_mutex_unlock( &c->c_mutex ); } -long connection_init( +Connection * connection_init( ber_socket_t s, Listener *listener, const char* dnsname, @@ -385,7 +385,7 @@ long connection_init( if( s == AC_SOCKET_INVALID ) { Debug( LDAP_DEBUG_ANY, "connection_init: init of socket %ld invalid.\n", (long)s, 0, 0 ); - return -1; + return NULL; } assert( s >= 0 ); @@ -442,7 +442,7 @@ long connection_init( Debug( LDAP_DEBUG_ANY, "connection_init(%d): connection table full " "(%d/%d)\n", s, i, dtblsize); - return -1; + return NULL; } } #endif @@ -526,13 +526,14 @@ long connection_init( c->c_listener = listener; if ( flags == CONN_IS_CLIENT ) { + c->c_connid = 0; c->c_conn_state = SLAP_C_CLIENT; c->c_struct_state = SLAP_C_USED; c->c_close_reason = "?"; /* should never be needed */ ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_SET_FD, &s ); ldap_pvt_thread_mutex_unlock( &c->c_mutex ); - return 0; + return c; } ber_str2bv( dnsname, 0, 1, &c->c_peer_domain ); @@ -622,7 +623,7 @@ long connection_init( backend_connection_init(c); - return id; + return c; } void connection2anonymous( Connection *c ) @@ -1187,17 +1188,15 @@ int connection_client_setup( int rc; Connection *c; - rc = connection_init( s, (Listener *)&dummy_list, "", "", + c = connection_init( s, (Listener *)&dummy_list, "", "", CONN_IS_CLIENT, 0, NULL ); - if ( rc < 0 ) return -1; + if ( !c ) return -1; - c = connection_get( s ); c->c_clientfunc = func; c->c_clientarg = arg; slapd_add_internal( s, 0 ); slapd_set_read( s, 1 ); - connection_return( c ); return 0; } diff --git a/servers/slapd/daemon.c b/servers/slapd/daemon.c index 9a3eb6b567..2675eb84b8 100644 --- a/servers/slapd/daemon.c +++ b/servers/slapd/daemon.c @@ -1572,7 +1572,7 @@ slap_listener( ber_socket_t s; socklen_t len = sizeof(from); - long id; + Connection *c; slap_ssf_t ssf = 0; struct berval authid = BER_BVNULL; #ifdef SLAPD_RLOOKUPS @@ -1583,6 +1583,10 @@ slap_listener( char *peeraddr = NULL; #ifdef LDAP_PF_LOCAL char peername[MAXPATHLEN + sizeof("PATH=")]; +#ifdef LDAP_PF_LOCAL_SENDMSG + char peerbuf[8]; + struct berval peerbv = BER_BVNULL; +#endif #elif defined(LDAP_PF_INET6) char peername[sizeof("IP=[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535")]; #else /* ! LDAP_PF_LOCAL && ! LDAP_PF_INET6 */ @@ -1716,8 +1720,13 @@ slap_listener( { uid_t uid; gid_t gid; + int rc; - if( getpeereid( s, &uid, &gid ) == 0 ) { +#ifdef LDAP_PF_LOCAL_SENDMSG + peerbv.bv_val = peerbuf; + peerbv.bv_len = sizeof( peerbuf ); +#endif + if( LUTIL_GETPEEREID( s, &uid, &gid, &peerbv ) == 0 ) { authid.bv_val = ch_malloc( STRLENOF( "gidNumber=4294967295+uidNumber=4294967295," "cn=peercred,cn=external,cn=auth" ) + 1 ); @@ -1809,7 +1818,7 @@ slap_listener( #endif /* HAVE_TCPD */ } - id = connection_init(s, sl, + c = connection_init(s, sl, dnsname != NULL ? dnsname : SLAP_STRING_UNKNOWN, peername, #ifdef HAVE_TLS @@ -1822,7 +1831,7 @@ slap_listener( if( authid.bv_val ) ch_free(authid.bv_val); - if( id < 0 ) { + if( !c ) { Debug( LDAP_DEBUG_ANY, "daemon: connection_init(%ld, %s, %s) failed.\n", (long) s, peername, sl->sl_name.bv_val ); @@ -1830,9 +1839,14 @@ slap_listener( return 0; } +#ifdef LDAP_PF_LOCAL_SENDMSG + if ( !BER_BVISEMPTY( &peerbv )) + ber_sockbuf_ctrl( c->c_sb, LBER_SB_OPT_UNGET_BUF, &peerbv ); +#endif + Statslog( LDAP_DEBUG_STATS, "conn=%ld fd=%ld ACCEPT from %s (%s)\n", - id, (long) s, peername, sl->sl_name.bv_val, + c->c_connid, (long) s, peername, sl->sl_name.bv_val, 0 ); return 0; @@ -2516,16 +2530,16 @@ connectionless_init( void ) for ( l = 0; slap_listeners[l] != NULL; l++ ) { Listener *lr = slap_listeners[l]; - long id; + Connection *c; if ( !lr->sl_is_udp ) { continue; } - id = connection_init( lr->sl_sd, lr, "", "", + c = connection_init( lr->sl_sd, lr, "", "", CONN_IS_UDP, (slap_ssf_t) 0, NULL ); - if ( id < 0 ) { + if ( !c ) { Debug( LDAP_DEBUG_TRACE, "connectionless_init: failed on %s (%d)\n", lr->sl_url, lr->sl_sd, 0 ); diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 6064c3b185..666ca13679 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -686,7 +686,7 @@ LDAP_SLAPD_F (void) connection_client_enable LDAP_P(( ber_socket_t s )); LDAP_SLAPD_F (void) connection_client_stop LDAP_P(( ber_socket_t s )); -LDAP_SLAPD_F (long) connection_init LDAP_P(( +LDAP_SLAPD_F (Connection *) connection_init LDAP_P(( ber_socket_t s, Listener* url, const char* dnsname, -- 2.39.5