be sent to transmit client credentials. Buffer the message data.
# 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 */
#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
#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 )
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;
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 );
}
}
#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
{
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.
*/
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 );
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 );
#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>
#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 )
*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
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
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))
{
*egid = st.st_gid;
return 0;
}
+ } else if ( peer->bv_len < 0 ) {
+ peer->bv_len = 0;
}
#elif defined(SOCKCREDSIZE)
struct msghdr msg;
ldap_pvt_thread_mutex_unlock( &c->c_mutex );
}
-long connection_init(
+Connection * connection_init(
ber_socket_t s,
Listener *listener,
const char* dnsname,
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 );
Debug( LDAP_DEBUG_ANY,
"connection_init(%d): connection table full "
"(%d/%d)\n", s, i, dtblsize);
- return -1;
+ return NULL;
}
}
#endif
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 );
backend_connection_init(c);
- return id;
+ return c;
}
void connection2anonymous( Connection *c )
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;
}
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
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 */
{
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 );
#endif /* HAVE_TCPD */
}
- id = connection_init(s, sl,
+ c = connection_init(s, sl,
dnsname != NULL ? dnsname : SLAP_STRING_UNKNOWN,
peername,
#ifdef HAVE_TLS
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 );
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;
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 );
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,