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:
Howard Chu 2001-09-28 00:18:40 +00:00
parent a466dc75b1
commit 647b5f84ee
17 changed files with 488 additions and 35 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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;

View File

@ -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>

View File

@ -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 */

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 );

View File

@ -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 );
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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,

View File

@ -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 */