]> git.sur5r.net Git - openldap/commitdiff
Resurrection/rewrite of CLDAP (RFC1798 Connectionless LDAP).
authorHoward Chu <hyc@openldap.org>
Fri, 28 Sep 2001 00:18:40 +0000 (00:18 +0000)
committerHoward Chu <hyc@openldap.org>
Fri, 28 Sep 2001 00:18:40 +0000 (00:18 +0000)
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.

17 files changed:
include/lber.h
libraries/liblber/sockbuf.c
libraries/libldap/abandon.c
libraries/libldap/init.c
libraries/libldap/ldap-int.h
libraries/libldap/open.c
libraries/libldap/os-ip.c
libraries/libldap/request.c
libraries/libldap/result.c
libraries/libldap/sasl.c
libraries/libldap/search.c
libraries/libldap/unbind.c
libraries/libldap/url.c
servers/slapd/connection.c
servers/slapd/daemon.c
servers/slapd/result.c
servers/slapd/slap.h

index 8ff10d51c98b935c0b127979379c3d2b57ea2835..129dfc0dd3c30ebd4f49d044b22e3610303413f4 100644 (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
index e201157433b6808ec62f4833b4b2606ad85403f7..5ce23ac656d310ccd7c246544d4adf27f903fe9b 100644 (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 */
index 8220e47a99672fe6accb95c81a7cfc3e57717545..0bcae1ff955965c0d54168fbf67522ed2308f35c 100644 (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 */
index e9c290c4d90dfa1bac9c51ed24ba0288211986e7..54c6ba5a4d1f4aa9f96dd1c9464819a97951631f 100644 (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;
index b90b6ab3225b0a2716b6b7d4da3a6793858b212a..fffaa610eca65f046da4d50c168ddbe3ad9d38cd 100644 (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>
index fcfd80ddaa421326b70a69fb8ffd8db37eb3ba5b..fe69cdf24671369e0c769bce3f8253da308e2106 100644 (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 */
index 79bd49af9fb7d9048a3091cd3e346dfdd80c4cc1..b2c44c2f07492f2ce1b38b52d8477ac4b07bf97c 100644 (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;
index 576383fb10605959df9de1765a50a084a288293a..a909f4c4f7828b45904da9d15469eff35ca62b41 100644 (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)
index d8c0a6c47ab5cff74ab8de261d4eb99e7f340f8a..eb52071ae0c309c637a3ced97883ac4ec0a8a168 100644 (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;
index 2d47636b7c175e6dca2c4ad209451228ae2d26e9..a435b2b2d19182ca8bff4598bb9eba77150cf4a2 100644 (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;
 
index 5adb5b8ed2d7aa976264eb91664b6c5df1d1f745..cfcfd8cf307bd421690c1bc4a0fcdcc3bafecbef 100644 (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;
index 7009a052eb270b8b564612bf558b7e83263a7eb7..b138161a41fd1a5b5ae3b551357e1af0606501d3 100644 (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 );
index 6fe98adafba9840d629090c8e6e2a94557db9ad1..c58ba59f7fdaaa78507d28403ec3dd99d7fe1118 100644 (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 );
 }
 
index 439c6fdd1c0210776692d9e015e5479f0d27ef48..dc417a4b48da7f61c891cea16a2f8fb525544ea2 100644 (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;
index 57c3a89d502b087fef5d56c095179a14830172db..461e949c1857e43deb04c42ea0d33d645d2c1065 100644 (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;
                                }
index 0736484e858143de420b19cf91d3f431905006f1..a4890e8fc68d876114f4e16a646db22473ac1baa 100644 (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,
index 36071a11d8ba3e15b58e570ecbfdc2ab32d5692d..2e7d74a8d9773ccc3ab501d4ae8e4898e44dee6c 100644 (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 */