mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-03-01 14:15:49 +08:00
Resurrection/rewrite of CLDAP (RFC1798 Connectionless LDAP).
Compile with -DLDAP_CONNECTIONLESS to use this code. For slapd, use "-h cldap://" to listen on UDP. For ldapsearch, use "-H cldap://" to query on UDP. Client-side support is very minimal: no automatic timeout/retries no basedn wildcard expansion on results no support for specifying multiple servers at once.
This commit is contained in:
parent
a466dc75b1
commit
647b5f84ee
@ -502,6 +502,9 @@ LBER_F( Sockbuf_IO ) ber_sockbuf_io_tcp;
|
||||
LBER_F( Sockbuf_IO ) ber_sockbuf_io_readahead;
|
||||
LBER_F( Sockbuf_IO ) ber_sockbuf_io_fd;
|
||||
LBER_F( Sockbuf_IO ) ber_sockbuf_io_debug;
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
LBER_F( Sockbuf_IO ) ber_sockbuf_io_udp;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* LBER memory.c
|
||||
|
@ -871,3 +871,106 @@ Sockbuf_IO ber_sockbuf_io_debug = {
|
||||
sb_debug_write, /* sbi_write */
|
||||
NULL /* sbi_close */
|
||||
};
|
||||
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
|
||||
/*
|
||||
* Support for UDP (CLDAP)
|
||||
*
|
||||
* All I/O at this level must be atomic. For ease of use, the sb_readahead
|
||||
* must be used above this module. All data reads and writes are prefixed
|
||||
* with a sockaddr containing the address of the remote entity. Upper levels
|
||||
* must read and write this sockaddr before doing the usual ber_printf/scanf
|
||||
* operations on LDAP messages.
|
||||
*/
|
||||
|
||||
static int
|
||||
sb_dgram_setup( Sockbuf_IO_Desc *sbiod, void *arg )
|
||||
{
|
||||
assert( sbiod != NULL);
|
||||
assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
|
||||
|
||||
if ( arg != NULL )
|
||||
sbiod->sbiod_sb->sb_fd = *((int *)arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ber_slen_t
|
||||
sb_dgram_read( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
|
||||
{
|
||||
ber_slen_t rc;
|
||||
socklen_t addrlen;
|
||||
struct sockaddr *src;
|
||||
|
||||
assert( sbiod != NULL );
|
||||
assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
|
||||
assert( buf != NULL );
|
||||
|
||||
addrlen = sizeof( struct sockaddr );
|
||||
src = buf;
|
||||
buf += addrlen;
|
||||
rc = recvfrom( sbiod->sbiod_sb->sb_fd, buf, len, 0, src,
|
||||
&addrlen );
|
||||
|
||||
return rc > 0 ? rc+sizeof(struct sockaddr) : rc;
|
||||
}
|
||||
|
||||
static ber_slen_t
|
||||
sb_dgram_write( Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len )
|
||||
{
|
||||
ber_slen_t rc;
|
||||
struct sockaddr *dst;
|
||||
|
||||
assert( sbiod != NULL );
|
||||
assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
|
||||
assert( buf != NULL );
|
||||
|
||||
dst = buf;
|
||||
buf += sizeof( struct sockaddr );
|
||||
len -= sizeof( struct sockaddr );
|
||||
|
||||
rc = sendto( sbiod->sbiod_sb->sb_fd, buf, len, 0, dst,
|
||||
sizeof( struct sockaddr ) );
|
||||
|
||||
if ( rc < 0 )
|
||||
return -1;
|
||||
|
||||
/* fake error if write was not atomic */
|
||||
if (rc < len) {
|
||||
# ifdef EMSGSIZE
|
||||
errno = EMSGSIZE;
|
||||
# endif
|
||||
return -1;
|
||||
}
|
||||
rc = len + sizeof(struct sockaddr);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_dgram_close( Sockbuf_IO_Desc *sbiod )
|
||||
{
|
||||
assert( sbiod != NULL );
|
||||
assert( SOCKBUF_VALID( sbiod->sbiod_sb ) );
|
||||
|
||||
tcp_close( sbiod->sbiod_sb->sb_fd );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_dgram_ctrl( Sockbuf_IO_Desc *sbiod, int opt, void *arg )
|
||||
{
|
||||
/* This is an end IO descriptor */
|
||||
return 0;
|
||||
}
|
||||
|
||||
Sockbuf_IO ber_sockbuf_io_udp =
|
||||
{
|
||||
sb_dgram_setup, /* sbi_setup */
|
||||
NULL, /* sbi_remove */
|
||||
sb_dgram_ctrl, /* sbi_ctrl */
|
||||
sb_dgram_read, /* sbi_read */
|
||||
sb_dgram_write, /* sbi_write */
|
||||
sb_dgram_close /* sbi_close */
|
||||
};
|
||||
|
||||
#endif /* LDAP_CONNECTIONLESS */
|
||||
|
@ -147,10 +147,25 @@ do_abandon(
|
||||
ld->ld_errno = LDAP_NO_MEMORY;
|
||||
|
||||
} else {
|
||||
/* create a message to send */
|
||||
err = ber_printf( ber, "{iti", /* '}' */
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if ( LDAP_IS_UDP(ld) ) {
|
||||
err = ber_write( ber, ld->ld_options.ldo_peer,
|
||||
sizeof(struct sockaddr), 0);
|
||||
if (err == sizeof(struct sockaddr)) {
|
||||
char *dn = ld->ld_options.ldo_cldapdn;
|
||||
if (!dn) dn = "";
|
||||
err = ber_printf( ber, "{isti", /* '}' */
|
||||
++ld->ld_msgid, dn,
|
||||
LDAP_REQ_ABANDON, msgid );
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/* create a message to send */
|
||||
err = ber_printf( ber, "{iti", /* '}' */
|
||||
++ld->ld_msgid,
|
||||
LDAP_REQ_ABANDON, msgid );
|
||||
LDAP_REQ_ABANDON, msgid );
|
||||
}
|
||||
|
||||
if( err == -1 ) {
|
||||
/* encoding error */
|
||||
|
@ -396,6 +396,11 @@ void ldap_int_initialize_global_options( struct ldapoptions *gopts, int *dbglvl
|
||||
|
||||
LDAP_BOOL_SET(gopts, LDAP_BOOL_REFERRALS);
|
||||
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
gopts->ldo_peer = NULL;
|
||||
gopts->ldo_cldapdn = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CYRUS_SASL
|
||||
gopts->ldo_def_sasl_mech = NULL;
|
||||
gopts->ldo_def_sasl_realm = NULL;
|
||||
|
@ -68,6 +68,10 @@ LDAP_BEGIN_DECL
|
||||
#define LDAPS_URL_PREFIX_LEN (sizeof(LDAPS_URL_PREFIX)-1)
|
||||
#define LDAPI_URL_PREFIX "ldapi://"
|
||||
#define LDAPI_URL_PREFIX_LEN (sizeof(LDAPI_URL_PREFIX)-1)
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
#define LDAPC_URL_PREFIX "cldap://"
|
||||
#define LDAPC_URL_PREFIX_LEN (sizeof(LDAPC_URL_PREFIX)-1)
|
||||
#endif
|
||||
#define LDAP_URL_URLCOLON "URL:"
|
||||
#define LDAP_URL_URLCOLON_LEN (sizeof(LDAP_URL_URLCOLON)-1)
|
||||
|
||||
@ -114,6 +118,12 @@ struct ldapoptions {
|
||||
#define LDAP_UNINITIALIZED 0x0
|
||||
#define LDAP_INITIALIZED 0x1
|
||||
#define LDAP_VALID_SESSION 0x2
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
#define LDAP_UDP_SESSION 0x4
|
||||
#define LDAP_IS_UDP(ld) (ld->ld_options.ldo_valid & LDAP_UDP_SESSION)
|
||||
void* ldo_peer; /* struct sockaddr* */
|
||||
char* ldo_cldapdn;
|
||||
#endif
|
||||
|
||||
int ldo_debug;
|
||||
/* per API call timeout */
|
||||
@ -291,7 +301,7 @@ struct ldap {
|
||||
LDAPConn *ld_conns; /* list of server connections */
|
||||
void *ld_selectinfo; /* platform specifics for select */
|
||||
};
|
||||
#define LDAP_VALID(ld) ( (ld)->ld_valid == LDAP_VALID_SESSION )
|
||||
#define LDAP_VALID(ld) ( (ld)->ld_valid & LDAP_VALID_SESSION )
|
||||
|
||||
#ifdef LDAP_R_COMPILE
|
||||
#include <ldap_pvt_thread.h>
|
||||
|
@ -236,6 +236,8 @@ ldap_initialize( LDAP **ldp, LDAP_CONST char *url )
|
||||
ldap_ld_free(ld, 1, NULL, NULL);
|
||||
return rc;
|
||||
}
|
||||
if (ldap_is_ldapc_url(url))
|
||||
ld->ld_options.ldo_valid |= LDAP_UDP_SESSION;
|
||||
}
|
||||
|
||||
*ldp = ld;
|
||||
@ -255,12 +257,12 @@ ldap_int_open_connection(
|
||||
int sasl_ssf = 0;
|
||||
#endif
|
||||
char *host;
|
||||
int port;
|
||||
int port, proto;
|
||||
long addr;
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, "ldap_int_open_connection\n", 0, 0, 0 );
|
||||
|
||||
switch ( ldap_pvt_url_scheme2proto( srv->lud_scheme ) ) {
|
||||
switch ( proto = ldap_pvt_url_scheme2proto( srv->lud_scheme ) ) {
|
||||
case LDAP_PROTO_TCP:
|
||||
port = htons( (short) srv->lud_port );
|
||||
|
||||
@ -272,8 +274,8 @@ ldap_int_open_connection(
|
||||
host = srv->lud_host;
|
||||
}
|
||||
|
||||
rc = ldap_connect_to_host( ld, conn->lconn_sb, 0,
|
||||
host, addr, port, async );
|
||||
rc = ldap_connect_to_host( ld, conn->lconn_sb,
|
||||
proto, host, addr, port, async );
|
||||
|
||||
if ( rc == -1 ) return rc;
|
||||
|
||||
@ -288,13 +290,36 @@ ldap_int_open_connection(
|
||||
sasl_host = ldap_host_connected_to( conn->lconn_sb );
|
||||
#endif
|
||||
break;
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
case LDAP_PROTO_UDP:
|
||||
port = htons( (short) srv->lud_port );
|
||||
|
||||
addr = 0;
|
||||
if ( srv->lud_host == NULL || *srv->lud_host == 0 ) {
|
||||
host = NULL;
|
||||
addr = htonl( INADDR_LOOPBACK );
|
||||
} else {
|
||||
host = srv->lud_host;
|
||||
}
|
||||
ld->ld_options.ldo_valid |= LDAP_UDP_SESSION;
|
||||
rc = ldap_connect_to_host( ld, conn->lconn_sb,
|
||||
proto, host, addr, port, async );
|
||||
|
||||
if ( rc == -1 ) return rc;
|
||||
#ifdef LDAP_DEBUG
|
||||
ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
|
||||
LBER_SBIOD_LEVEL_PROVIDER, (void *)"udp_" );
|
||||
#endif
|
||||
ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_udp,
|
||||
LBER_SBIOD_LEVEL_PROVIDER, NULL );
|
||||
break;
|
||||
#endif
|
||||
case LDAP_PROTO_IPC:
|
||||
#ifdef LDAP_PF_LOCAL
|
||||
/* only IPC mechanism supported is PF_LOCAL (PF_UNIX) */
|
||||
rc = ldap_connect_to_path( ld, conn->lconn_sb,
|
||||
srv->lud_host, async );
|
||||
if ( rc == -1 ) return rc;
|
||||
|
||||
#ifdef LDAP_DEBUG
|
||||
ber_sockbuf_add_io( conn->lconn_sb, &ber_sockbuf_io_debug,
|
||||
LBER_SBIOD_LEVEL_PROVIDER, (void *)"ipc_" );
|
||||
@ -321,6 +346,11 @@ ldap_int_open_connection(
|
||||
INT_MAX, (void *)"ldap_" );
|
||||
#endif
|
||||
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if( proto == LDAP_PROTO_UDP )
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CYRUS_SASL
|
||||
/* establish Cyrus SASL context prior to starting TLS so
|
||||
that SASL EXTERNAL might be used */
|
||||
|
@ -198,6 +198,18 @@ ldap_pvt_connect(LDAP *ld, ber_socket_t s,
|
||||
fd_set efds;
|
||||
#endif
|
||||
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
/* We could do a connect() but that would interfere with
|
||||
* attempts to poll a broadcast address
|
||||
*/
|
||||
if (LDAP_IS_UDP(ld)) {
|
||||
if (ld->ld_options.ldo_peer)
|
||||
ldap_memfree(ld->ld_options.ldo_peer);
|
||||
ld->ld_options.ldo_peer=ldap_memalloc(sizeof(struct sockaddr));
|
||||
AC_MEMCPY(ld->ld_options.ldo_peer,sin,sizeof(struct sockaddr));
|
||||
return ( 0 );
|
||||
}
|
||||
#endif
|
||||
if ( (opt_tv = ld->ld_options.ldo_tm_net) != NULL ) {
|
||||
tv.tv_usec = opt_tv->tv_usec;
|
||||
tv.tv_sec = opt_tv->tv_sec;
|
||||
@ -293,9 +305,18 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *sb,
|
||||
int rc, i, use_hp = 0;
|
||||
struct hostent *hp = NULL;
|
||||
char *ha_buf=NULL, *p, *q;
|
||||
int socktype;
|
||||
|
||||
osip_debug(ld, "ldap_connect_to_host: %s\n",host,0,0);
|
||||
|
||||
switch(proto) {
|
||||
case LDAP_PROTO_TCP: socktype = SOCK_STREAM; break;
|
||||
case LDAP_PROTO_UDP: socktype = SOCK_DGRAM; break;
|
||||
default: osip_debug(ld, "ldap_connect_to_host: unknown proto: %d\n",
|
||||
proto, 0, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (host != NULL) {
|
||||
#if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
|
||||
char serv[7];
|
||||
@ -304,7 +325,7 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *sb,
|
||||
|
||||
memset( &hints, '\0', sizeof(hints) );
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_socktype = socktype;
|
||||
|
||||
snprintf(serv, sizeof serv, "%d", ntohs(port));
|
||||
if ( err = getaddrinfo(host, serv, &hints, &res) ) {
|
||||
@ -316,7 +337,7 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *sb,
|
||||
rc = -1;
|
||||
do {
|
||||
/* we assume AF_x and PF_x are equal for all x */
|
||||
s = ldap_int_socket( ld, sai->ai_family, SOCK_STREAM );
|
||||
s = ldap_int_socket( ld, sai->ai_family, socktype );
|
||||
if ( s == AC_SOCKET_INVALID ) {
|
||||
continue;
|
||||
}
|
||||
@ -384,7 +405,7 @@ ldap_connect_to_host(LDAP *ld, Sockbuf *sb,
|
||||
rc = s = -1;
|
||||
for ( i = 0; !use_hp || (hp->h_addr_list[i] != 0); ++i, rc = -1 ) {
|
||||
|
||||
s = ldap_int_socket( ld, PF_INET, SOCK_STREAM );
|
||||
s = ldap_int_socket( ld, PF_INET, socktype );
|
||||
if ( s == AC_SOCKET_INVALID ) {
|
||||
/* use_hp ? continue : break; */
|
||||
break;
|
||||
|
@ -107,6 +107,18 @@ ldap_send_initial_request(
|
||||
servers = NULL;
|
||||
}
|
||||
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if (LDAP_IS_UDP(ld)) {
|
||||
if (msgtype == LDAP_REQ_BIND) {
|
||||
if (ld->ld_options.ldo_cldapdn)
|
||||
ldap_memfree(ld->ld_options.ldo_cldapdn);
|
||||
ld->ld_options.ldo_cldapdn = ldap_strdup(dn);
|
||||
return 0;
|
||||
}
|
||||
if (msgtype != LDAP_REQ_ABANDON && msgtype != LDAP_REQ_SEARCH)
|
||||
return LDAP_PARAM_ERROR;
|
||||
}
|
||||
#endif
|
||||
rc = ldap_send_server_request( ld, ber, ld->ld_msgid, NULL,
|
||||
servers, NULL, NULL );
|
||||
if (servers)
|
||||
|
@ -372,6 +372,12 @@ try_read1msg(
|
||||
|
||||
/* get the next message */
|
||||
errno = 0;
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if ( LDAP_IS_UDP(ld) ) {
|
||||
struct sockaddr from;
|
||||
ber_int_sb_read(sb, &from, sizeof(struct sockaddr));
|
||||
}
|
||||
#endif
|
||||
if ( (tag = ber_get_next( sb, &len, ber ))
|
||||
!= LDAP_TAG_MESSAGE ) {
|
||||
if ( tag == LBER_DEFAULT) {
|
||||
@ -419,7 +425,14 @@ try_read1msg(
|
||||
ber_free( ber, 1 );
|
||||
return( -2 ); /* continue looking */
|
||||
}
|
||||
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if (LDAP_IS_UDP(ld)) {
|
||||
char *blank;
|
||||
ber_scanf(ber, "a{", &blank);
|
||||
if (blank)
|
||||
ber_memfree(blank);
|
||||
}
|
||||
#endif
|
||||
/* the message type */
|
||||
if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
|
||||
ld->ld_errno = LDAP_DECODING_ERROR;
|
||||
|
@ -423,7 +423,16 @@ ldap_sasl_interactive_bind_s(
|
||||
#if defined( LDAP_R_COMPILE ) && defined( HAVE_CYRUS_SASL )
|
||||
ldap_pvt_thread_mutex_lock( &ldap_int_sasl_mutex );
|
||||
#endif
|
||||
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if( LDAP_IS_UDP(ld) ) {
|
||||
/* Just force it to simple bind, silly to make the user
|
||||
* ask all the time. No, we don't ever actually bind, but I'll
|
||||
* let the final bind handler take care of saving the cdn.
|
||||
*/
|
||||
rc = ldap_simple_bind(ld, dn, NULL);
|
||||
return rc < 0 ? rc : 0;
|
||||
} else
|
||||
#endif
|
||||
if( mechs == NULL || *mechs == '\0' ) {
|
||||
char *smechs;
|
||||
|
||||
|
@ -297,11 +297,28 @@ ldap_build_search_req(
|
||||
}
|
||||
}
|
||||
|
||||
err = ber_printf( ber, "{it{seeiib", ++ld->ld_msgid,
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if ( LDAP_IS_UDP(ld) ) {
|
||||
err = ber_write( ber, ld->ld_options.ldo_peer,
|
||||
sizeof(struct sockaddr), 0);
|
||||
if (err == sizeof(struct sockaddr)) {
|
||||
char *dn = ld->ld_options.ldo_cldapdn;
|
||||
if (!dn) dn = "";
|
||||
err = ber_printf( ber, "{ist{seeiib", ++ld->ld_msgid, dn,
|
||||
LDAP_REQ_SEARCH, base, (ber_int_t) scope, ld->ld_deref,
|
||||
(sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
|
||||
(timelimit < 0) ? ld->ld_timelimit : timelimit,
|
||||
attrsonly );
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
err = ber_printf( ber, "{it{seeiib", ++ld->ld_msgid,
|
||||
LDAP_REQ_SEARCH, base, (ber_int_t) scope, ld->ld_deref,
|
||||
(sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
|
||||
(timelimit < 0) ? ld->ld_timelimit : timelimit,
|
||||
attrsonly );
|
||||
}
|
||||
|
||||
if ( err == -1 ) {
|
||||
ld->ld_errno = LDAP_ENCODING_ERROR;
|
||||
|
@ -158,6 +158,10 @@ ldap_send_unbind(
|
||||
|
||||
Debug( LDAP_DEBUG_TRACE, "ldap_send_unbind\n", 0, 0, 0 );
|
||||
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if (LDAP_IS_UDP(ld))
|
||||
return LDAP_SUCCESS;
|
||||
#endif
|
||||
/* create a message to send */
|
||||
if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
|
||||
return( ld->ld_errno );
|
||||
|
@ -60,6 +60,11 @@ int ldap_pvt_url_scheme2proto( const char *scheme )
|
||||
if( strcmp("ldaps", scheme) == 0 ) {
|
||||
return LDAP_PROTO_TCP;
|
||||
}
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if( strcmp("cldap", scheme) == 0 ) {
|
||||
return LDAP_PROTO_UDP;
|
||||
}
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
}
|
||||
@ -126,6 +131,25 @@ ldap_is_ldapi_url( LDAP_CONST char *url )
|
||||
return strcmp(scheme, "ldapi") == 0;
|
||||
}
|
||||
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
int
|
||||
ldap_is_ldapc_url( LDAP_CONST char *url )
|
||||
{
|
||||
int enclosed;
|
||||
const char * scheme;
|
||||
|
||||
if( url == NULL ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( skip_url_prefix( url, &enclosed, &scheme ) == NULL ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return strcmp(scheme, "cldap") == 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char*
|
||||
skip_url_prefix(
|
||||
const char *url,
|
||||
@ -181,6 +205,16 @@ skip_url_prefix(
|
||||
return( p );
|
||||
}
|
||||
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
/* check for "cldap://" prefix */
|
||||
if ( strncasecmp( p, LDAPC_URL_PREFIX, LDAPC_URL_PREFIX_LEN ) == 0 ) {
|
||||
/* skip over "cldap://" prefix and return success */
|
||||
p += LDAPC_URL_PREFIX_LEN;
|
||||
*scheme = "cldap";
|
||||
return( p );
|
||||
}
|
||||
#endif
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
|
@ -317,7 +317,7 @@ long connection_init(
|
||||
const char* dnsname,
|
||||
const char* peername,
|
||||
const char* sockname,
|
||||
int use_tls,
|
||||
int tls_udp_option,
|
||||
slap_ssf_t ssf,
|
||||
const char *authid )
|
||||
{
|
||||
@ -331,7 +331,7 @@ long connection_init(
|
||||
assert( sockname != NULL );
|
||||
|
||||
#ifndef HAVE_TLS
|
||||
assert( !use_tls );
|
||||
assert( tls_udp_option != 1 );
|
||||
#endif
|
||||
|
||||
if( s == AC_SOCKET_INVALID ) {
|
||||
@ -474,12 +474,27 @@ long connection_init(
|
||||
|
||||
c->c_activitytime = c->c_starttime = slap_get_time();
|
||||
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
c->c_is_udp = 0;
|
||||
if (tls_udp_option == 2)
|
||||
{
|
||||
c->c_is_udp = 1;
|
||||
#ifdef LDAP_DEBUG
|
||||
ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug,
|
||||
LBER_SBIOD_LEVEL_PROVIDER, (void*)"udp_" );
|
||||
#endif
|
||||
ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_udp,
|
||||
LBER_SBIOD_LEVEL_PROVIDER, (void *)&s );
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
#ifdef LDAP_DEBUG
|
||||
ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_debug,
|
||||
LBER_SBIOD_LEVEL_PROVIDER, (void*)"tcp_" );
|
||||
#endif
|
||||
ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_tcp,
|
||||
LBER_SBIOD_LEVEL_PROVIDER, (void *)&s );
|
||||
}
|
||||
ber_sockbuf_add_io( c->c_sb, &ber_sockbuf_io_readahead,
|
||||
LBER_SBIOD_LEVEL_PROVIDER, NULL );
|
||||
|
||||
@ -511,7 +526,7 @@ long connection_init(
|
||||
c->c_tls_ssf = 0;
|
||||
|
||||
#ifdef HAVE_TLS
|
||||
if ( use_tls ) {
|
||||
if ( tls_udp_option == 1 ) {
|
||||
c->c_is_tls = 1;
|
||||
c->c_needs_tls_accept = 1;
|
||||
} else {
|
||||
@ -1160,6 +1175,10 @@ connection_input(
|
||||
ber_len_t len;
|
||||
ber_int_t msgid;
|
||||
BerElement *ber;
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
Sockaddr peeraddr;
|
||||
char *cdn = NULL;
|
||||
#endif
|
||||
|
||||
if ( conn->c_currentber == NULL && (conn->c_currentber = ber_alloc())
|
||||
== NULL ) {
|
||||
@ -1174,6 +1193,21 @@ connection_input(
|
||||
|
||||
errno = 0;
|
||||
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if (conn->c_is_udp)
|
||||
{
|
||||
char peername[sizeof("IP=255.255.255.255:65336")];
|
||||
len = ber_int_sb_read(conn->c_sb, &peeraddr,
|
||||
sizeof(struct sockaddr));
|
||||
sprintf( peername, "IP=%s:%d",
|
||||
inet_ntoa( peeraddr.sa_in_addr.sin_addr ),
|
||||
(unsigned) ntohs( peeraddr.sa_in_addr.sin_port ) );
|
||||
Statslog( LDAP_DEBUG_STATS,
|
||||
"conn=%ld UDP request from %s (%s) accepted.\n",
|
||||
conn->c_connid, peername,
|
||||
conn->c_sock_name, 0, 0 );
|
||||
}
|
||||
#endif
|
||||
tag = ber_get_next( conn->c_sb, &len, conn->c_currentber );
|
||||
if ( tag != LDAP_TAG_MESSAGE ) {
|
||||
int err = errno;
|
||||
@ -1216,6 +1250,11 @@ connection_input(
|
||||
ber_free( ber, 1 );
|
||||
return -1;
|
||||
}
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if (conn->c_is_udp) {
|
||||
tag = ber_get_stringa( ber, &cdn );
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( (tag = ber_peek_tag( ber, &len )) == LBER_ERROR ) {
|
||||
/* log, close and send error */
|
||||
@ -1232,6 +1271,22 @@ connection_input(
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if (conn->c_is_udp && (tag != LDAP_REQ_ABANDON &&
|
||||
tag != LDAP_REQ_SEARCH))
|
||||
{
|
||||
#ifdef NEW_LOGGING
|
||||
LDAP_LOG(( "connection", LDAP_LEVEL_ERR,
|
||||
"connection_input: conn %d invalid req for UDP 0x%lx.\n",
|
||||
conn->c_connid, tag ));
|
||||
#else
|
||||
Debug( LDAP_DEBUG_ANY, "invalid req for UDP 0x%lx\n", tag, 0,
|
||||
0 );
|
||||
#endif
|
||||
ber_free( ber, 1 );
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if(tag == LDAP_REQ_BIND) {
|
||||
/* immediately abandon all exiting operations upon BIND */
|
||||
connection_abandon( conn );
|
||||
@ -1239,6 +1294,10 @@ connection_input(
|
||||
|
||||
op = slap_op_alloc( ber, msgid, tag, conn->c_n_ops_received++ );
|
||||
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
op->o_peeraddr = peeraddr;
|
||||
op->o_dn = cdn;
|
||||
#endif
|
||||
if ( conn->c_conn_state == SLAP_C_BINDING
|
||||
|| conn->c_conn_state == SLAP_C_CLOSING )
|
||||
{
|
||||
@ -1366,8 +1425,10 @@ static int connection_op_activate( Connection *conn, Operation *op )
|
||||
arg->co_conn = conn;
|
||||
arg->co_op = op;
|
||||
|
||||
arg->co_op->o_authz = conn->c_authz;
|
||||
arg->co_op->o_dn = ch_strdup( conn->c_dn != NULL ? conn->c_dn : "" );
|
||||
if (!arg->co_op->o_dn) {
|
||||
arg->co_op->o_authz = conn->c_authz;
|
||||
arg->co_op->o_dn = ch_strdup( conn->c_dn != NULL ? conn->c_dn : "" );
|
||||
}
|
||||
arg->co_op->o_ndn = ch_strdup( arg->co_op->o_dn );
|
||||
(void) dn_normalize( arg->co_op->o_ndn );
|
||||
arg->co_op->o_authtype = conn->c_authtype;
|
||||
|
@ -35,22 +35,14 @@ int deny_severity = LOG_NOTICE;
|
||||
time_t starttime;
|
||||
ber_socket_t dtblsize;
|
||||
|
||||
typedef union slap_sockaddr {
|
||||
struct sockaddr sa_addr;
|
||||
struct sockaddr_in sa_in_addr;
|
||||
#ifdef LDAP_PF_INET6
|
||||
struct sockaddr_in6 sa_in6_addr;
|
||||
#endif
|
||||
#ifdef LDAP_PF_LOCAL
|
||||
struct sockaddr_un sa_un_addr;
|
||||
#endif
|
||||
} Sockaddr;
|
||||
|
||||
typedef struct slap_listener {
|
||||
char* sl_url;
|
||||
char* sl_name;
|
||||
#ifdef HAVE_TLS
|
||||
int sl_is_tls;
|
||||
#endif
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
int sl_is_udp; /* UDP listener is also data port */
|
||||
#endif
|
||||
ber_socket_t sl_sd;
|
||||
Sockaddr sl_sa;
|
||||
@ -498,6 +490,7 @@ static Listener * slap_open_listener(
|
||||
unsigned short port;
|
||||
int err, addrlen;
|
||||
struct sockaddr **sal, **psal;
|
||||
int socktype = SOCK_STREAM; /* default to COTS */
|
||||
|
||||
rc = ldap_url_parse( url, &lud );
|
||||
|
||||
@ -543,7 +536,8 @@ static Listener * slap_open_listener(
|
||||
|
||||
port = (unsigned short) lud->lud_port;
|
||||
|
||||
if ( ldap_pvt_url_scheme2proto(lud->lud_scheme) == LDAP_PROTO_IPC ) {
|
||||
tmp = ldap_pvt_url_scheme2proto(lud->lud_scheme);
|
||||
if ( tmp == LDAP_PROTO_IPC ) {
|
||||
#ifdef LDAP_PF_LOCAL
|
||||
if ( lud->lud_host == NULL || lud->lud_host[0] == '\0' ) {
|
||||
err = slap_get_listener_addresses(LDAPI_SOCK, 0, &sal);
|
||||
@ -564,6 +558,10 @@ static Listener * slap_open_listener(
|
||||
return NULL;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if ( tmp == LDAP_PROTO_UDP )
|
||||
l.sl_is_udp = 1;
|
||||
#endif
|
||||
if( lud->lud_host == NULL || lud->lud_host[0] == '\0'
|
||||
|| strcmp(lud->lud_host, "*") == 0 )
|
||||
{
|
||||
@ -593,7 +591,11 @@ static Listener * slap_open_listener(
|
||||
sal++;
|
||||
continue;
|
||||
}
|
||||
l.sl_sd = socket( (*sal)->sa_family, SOCK_STREAM, 0);
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if (l.sl_is_udp)
|
||||
socktype = SOCK_DGRAM;
|
||||
#endif
|
||||
l.sl_sd = socket( (*sal)->sa_family, socktype, 0);
|
||||
if ( l.sl_sd == AC_SOCKET_INVALID ) {
|
||||
int err = sock_errno();
|
||||
#ifdef NEW_LOGGING
|
||||
@ -931,6 +933,17 @@ slapd_daemon_task(
|
||||
for ( l = 0; slap_listeners[l] != NULL; l++ ) {
|
||||
if ( slap_listeners[l]->sl_sd == AC_SOCKET_INVALID )
|
||||
continue;
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
/* Since this is connectionless, the data port is the
|
||||
* listening port. The listen() and accept() calls
|
||||
* are unnecessary.
|
||||
*/
|
||||
if ( slap_listeners[l]->sl_is_udp )
|
||||
{
|
||||
slapd_add( slap_listeners[l]->sl_sd );
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( listen( slap_listeners[l]->sl_sd, SLAPD_LISTEN ) == -1 ) {
|
||||
int err = sock_errno();
|
||||
@ -1146,6 +1159,26 @@ slapd_daemon_task(
|
||||
if ( !FD_ISSET( slap_listeners[l]->sl_sd, &readfds ) )
|
||||
continue;
|
||||
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if ( slap_listeners[l]->sl_is_udp )
|
||||
{
|
||||
/* The first time we receive a query, we set this
|
||||
* up as a "connection". It remains open for the life
|
||||
* of the slapd.
|
||||
*/
|
||||
if ( slap_listeners[l]->sl_is_udp < 2 )
|
||||
{
|
||||
id = connection_init(
|
||||
slap_listeners[l]->sl_sd,
|
||||
slap_listeners[l]->sl_url, "", "",
|
||||
slap_listeners[l]->sl_name,
|
||||
2, ssf, authid );
|
||||
slap_listeners[l]->sl_is_udp++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
s = accept( slap_listeners[l]->sl_sd,
|
||||
(struct sockaddr *) &from, &len );
|
||||
if ( s == AC_SOCKET_INVALID ) {
|
||||
@ -1404,6 +1437,13 @@ slapd_daemon_task(
|
||||
|
||||
for ( l = 0; slap_listeners[l] != NULL; l++ ) {
|
||||
if ( i == slap_listeners[l]->sl_sd ) {
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
/* The listener is the data port. Don't
|
||||
* skip it.
|
||||
*/
|
||||
if (slap_listeners[l]->sl_is_udp)
|
||||
continue;
|
||||
#endif
|
||||
is_listener = 1;
|
||||
break;
|
||||
}
|
||||
@ -1453,6 +1493,10 @@ slapd_daemon_task(
|
||||
|
||||
for ( l = 0; slap_listeners[l] != NULL; l++ ) {
|
||||
if ( i == slap_listeners[l]->sl_sd ) {
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if (slap_listeners[l]->sl_is_udp)
|
||||
continue;
|
||||
#endif
|
||||
is_listener = 1;
|
||||
break;
|
||||
}
|
||||
@ -1501,6 +1545,10 @@ slapd_daemon_task(
|
||||
|
||||
for ( l = 0; slap_listeners[l] != NULL; l++ ) {
|
||||
if ( rd == slap_listeners[l]->sl_sd ) {
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if (slap_listeners[l]->sl_is_udp)
|
||||
continue;
|
||||
#endif
|
||||
is_listener = 1;
|
||||
break;
|
||||
}
|
||||
|
@ -309,10 +309,32 @@ send_ldap_response(
|
||||
return;
|
||||
}
|
||||
|
||||
rc = ber_printf( ber, "{it{ess",
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if (conn->c_is_udp) {
|
||||
rc = ber_write(ber, (char *)&op->o_peeraddr, sizeof(struct sockaddr), 0);
|
||||
if (rc != sizeof(struct sockaddr)) {
|
||||
#ifdef NEW_LOGGING
|
||||
LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
|
||||
"send_ldap_response: conn %d ber_write failed\n",
|
||||
conn ? conn->c_connid : 0 ));
|
||||
#else
|
||||
Debug( LDAP_DEBUG_ANY, "ber_write failed\n", 0, 0, 0 );
|
||||
#endif
|
||||
ber_free(ber, 1);
|
||||
return;
|
||||
}
|
||||
rc = ber_printf( ber, "{is{t{ess",
|
||||
msgid, "", tag, err,
|
||||
matched == NULL ? "" : matched,
|
||||
text == NULL ? "" : text );
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
rc = ber_printf( ber, "{it{ess",
|
||||
msgid, tag, err,
|
||||
matched == NULL ? "" : matched,
|
||||
text == NULL ? "" : text );
|
||||
}
|
||||
|
||||
if( rc != -1 ) {
|
||||
if ( ref != NULL ) {
|
||||
@ -342,6 +364,11 @@ send_ldap_response(
|
||||
if( rc != -1 ) {
|
||||
rc = ber_printf( ber, "N}N}" );
|
||||
}
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if( conn->c_is_udp && rc != -1 ) {
|
||||
rc = ber_printf( ber, "N}" );
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( rc == -1 ) {
|
||||
#ifdef NEW_LOGGING
|
||||
@ -731,8 +758,28 @@ send_search_entry(
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
rc = ber_printf( ber, "{it{s{" /*}}}*/, op->o_msgid,
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if (conn->c_is_udp) {
|
||||
rc = ber_write(ber, (char *)&op->o_peeraddr, sizeof(struct sockaddr), 0);
|
||||
if (rc != sizeof(struct sockaddr)) {
|
||||
#ifdef NEW_LOGGING
|
||||
LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
|
||||
"send_search_entry: conn %d ber_printf failed\n",
|
||||
conn ? conn->c_connid : 0 ));
|
||||
#else
|
||||
Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
|
||||
#endif
|
||||
ber_free(ber, 1);
|
||||
return;
|
||||
}
|
||||
rc = ber_printf( ber, "{is{t{s{",
|
||||
op->o_msgid, "", LDAP_RES_SEARCH_ENTRY, e->e_dn );
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
rc = ber_printf( ber, "{it{s{" /*}}}*/, op->o_msgid,
|
||||
LDAP_RES_SEARCH_ENTRY, e->e_dn );
|
||||
}
|
||||
|
||||
if ( rc == -1 ) {
|
||||
#ifdef NEW_LOGGING
|
||||
@ -974,6 +1021,10 @@ send_search_entry(
|
||||
|
||||
rc = ber_printf( ber, /*{{{*/ "}N}N}" );
|
||||
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
if (conn->c_is_udp && rc != -1)
|
||||
rc = ber_printf( ber, "}" );
|
||||
#endif
|
||||
if ( rc == -1 ) {
|
||||
#ifdef NEW_LOGGING
|
||||
LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
|
||||
|
@ -218,6 +218,17 @@ typedef struct slap_ssf_set {
|
||||
#define SLAP_SCHERR_NOT_SUPPORTED 15
|
||||
#define SLAP_SCHERR_BAD_DESCR 16
|
||||
|
||||
typedef union slap_sockaddr {
|
||||
struct sockaddr sa_addr;
|
||||
struct sockaddr_in sa_in_addr;
|
||||
#ifdef LDAP_PF_INET6
|
||||
struct sockaddr_in6 sa_in6_addr;
|
||||
#endif
|
||||
#ifdef LDAP_PF_LOCAL
|
||||
struct sockaddr_un sa_un_addr;
|
||||
#endif
|
||||
} Sockaddr;
|
||||
|
||||
typedef struct slap_oid_macro {
|
||||
struct berval som_oid;
|
||||
char **som_names;
|
||||
@ -1127,6 +1138,9 @@ struct slap_backend_info {
|
||||
typedef struct slap_op {
|
||||
ber_int_t o_opid; /* id of this operation */
|
||||
ber_int_t o_msgid; /* msgid of the request */
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
Sockaddr o_peeraddr; /* UDP peer address */
|
||||
#endif
|
||||
|
||||
ldap_pvt_thread_t o_tid; /* thread handling this op */
|
||||
|
||||
@ -1194,6 +1208,9 @@ typedef struct slap_conn {
|
||||
BerElement *c_currentber; /* ber we're attempting to read */
|
||||
int c_writewaiter; /* true if writer is waiting */
|
||||
|
||||
#ifdef LDAP_CONNECTIONLESS
|
||||
int c_is_udp; /* true if this is (C)LDAP over UDP */
|
||||
#endif
|
||||
#ifdef HAVE_TLS
|
||||
int c_is_tls; /* true if this LDAP over raw TLS */
|
||||
int c_needs_tls_accept; /* true if SSL_accept should be called */
|
||||
|
Loading…
Reference in New Issue
Block a user