Commit 7426ab07 authored by Howard Chu's avatar Howard Chu
Browse files

ITS#4893 define LDAP_PF_LOCAL_SENDMSG in <ac/socket.h> if a message must

be sent to transmit client credentials. Buffer the message data.
parent 724784e6
......@@ -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 */
......
......@@ -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
......
......@@ -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 )
......
......@@ -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 );
}
......
......@@ -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 );
......
......@@ -21,6 +21,14 @@
#include <sys/types.h>
#include <ac/unistd.h>
#ifdef LDAP_PF_LOCAL_SENDMSG
#include <lber.h>
#ifdef HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
#include <sys/stat.h>
#endif
#include <ac/socket.h>
#include <ac/errno.h>
......@@ -35,21 +43,13 @@
#include <sys/ucred.h>
#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 <sys/uio.h>
#endif
#include <sys/stat.h>
#endif
#include <stdlib.h>
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;
......
......@@ -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;
}
......
......@@ -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 );
......
......@@ -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,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment