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.
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
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 */
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 */
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;
#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)
#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 */
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>
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;
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 );
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;
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_" );
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 */
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;
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];
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) ) {
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;
}
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;
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)
/* 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) {
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;
#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;
}
}
- 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;
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 );
if( strcmp("ldaps", scheme) == 0 ) {
return LDAP_PROTO_TCP;
}
+#ifdef LDAP_CONNECTIONLESS
+ if( strcmp("cldap", scheme) == 0 ) {
+ return LDAP_PROTO_UDP;
+ }
+#endif
return -1;
}
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,
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 );
}
const char* dnsname,
const char* peername,
const char* sockname,
- int use_tls,
+ int tls_udp_option,
slap_ssf_t ssf,
const char *authid )
{
assert( sockname != NULL );
#ifndef HAVE_TLS
- assert( !use_tls );
+ assert( tls_udp_option != 1 );
#endif
if( s == AC_SOCKET_INVALID ) {
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 );
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 {
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 ) {
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;
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 */
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 );
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 )
{
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;
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;
unsigned short port;
int err, addrlen;
struct sockaddr **sal, **psal;
+ int socktype = SOCK_STREAM; /* default to COTS */
rc = ldap_url_parse( url, &lud );
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);
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 )
{
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
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();
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 ) {
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;
}
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;
}
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;
}
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 ) {
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
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
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,
#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;
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 */
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 */