]> git.sur5r.net Git - openldap/commitdiff
add support for (experimental) dereference control (ITS#5768); need to re-run autocon...
authorPierangelo Masarati <ando@openldap.org>
Wed, 22 Oct 2008 22:19:49 +0000 (22:19 +0000)
committerPierangelo Masarati <ando@openldap.org>
Wed, 22 Oct 2008 22:19:49 +0000 (22:19 +0000)
clients/tools/common.c
clients/tools/ldapsearch.c
configure.in
include/ldap.h
include/portable.hin
libraries/libldap/Makefile.in
libraries/libldap/deref.c [new file with mode: 0644]
servers/slapd/overlays/Makefile.in
servers/slapd/overlays/deref.c [new file with mode: 0644]

index 5222d6321dc20af868509fa2e96ca1e78166231f..4f38ede9fdb189b5f6d65408bedfe604caaf6aab 100644 (file)
@@ -135,6 +135,9 @@ static int print_paged_results( LDAP *ld, LDAPControl *ctrl );
 static int print_ppolicy( LDAP *ld, LDAPControl *ctrl );
 #endif
 static int print_sss( LDAP *ld, LDAPControl *ctrl );
+#ifdef LDAP_CONTROL_X_DEREF
+static int print_deref( LDAP *ld, LDAPControl *ctrl );
+#endif
 
 static struct tool_ctrls_t {
        const char      *oid;
@@ -148,6 +151,9 @@ static struct tool_ctrls_t {
        { LDAP_CONTROL_PASSWORDPOLICYRESPONSE,          TOOL_ALL,       print_ppolicy },
 #endif
        { LDAP_CONTROL_SORTRESPONSE,    TOOL_SEARCH,    print_sss },
+#ifdef LDAP_CONTROL_X_DEREF
+       { LDAP_CONTROL_X_DEREF,                         TOOL_SEARCH,    print_deref },
+#endif
        { NULL,                                         0,              NULL }
 };
 
@@ -1890,6 +1896,76 @@ print_sss( LDAP *ld, LDAPControl *ctrl )
        return rc;
 }
 
+#ifdef LDAP_CONTROL_X_DEREF
+static int
+print_deref( LDAP *ld, LDAPControl *ctrl )
+{
+       LDAPDerefRes    *drhead = NULL, *dr;
+       int             rc;
+
+       rc = ldap_parse_derefresponse_control( ld, ctrl, &drhead );
+       if ( rc != LDAP_SUCCESS ) {
+               return rc;
+       }
+
+       for ( dr = drhead; dr != NULL; dr = dr->next ) {
+               LDAPDerefVal    *dv;
+               ber_len_t       len;
+               char            *buf, *ptr;
+
+               len = strlen( dr->derefAttr ) + STRLENOF(": ");
+
+               for ( dv = dr->attrVals; dv != NULL; dv = dv->next ) {
+                       if ( dv->vals != NULL ) {
+                               int j;
+                               ber_len_t tlen = strlen(dv->type);
+
+                               for ( j = 0; dv->vals[ j ].bv_val != NULL; j++ ) {
+                                       len += STRLENOF("<=>;") + tlen + dv->vals[ j ].bv_len;
+                               }
+                       }
+               }
+               len += dr->derefVal.bv_len;
+               buf = ldap_memalloc( len + 1 );
+               if ( buf == NULL ) {
+                       rc = LDAP_NO_MEMORY;
+                       goto done;
+               }
+
+               ptr = buf;
+               ptr = lutil_strcopy( ptr, dr->derefAttr );
+               *ptr++ = ':';
+               *ptr++ = ' ';
+               for ( dv = dr->attrVals; dv != NULL; dv = dv->next ) {
+                       if ( dv->vals != NULL ) {
+                               int j;
+                               for ( j = 0; dv->vals[ j ].bv_val != NULL; j++ ) {
+                                       *ptr++ = '<';
+                                       ptr = lutil_strcopy( ptr, dv->type );
+                                       *ptr++ = '=';
+                                       ptr = lutil_strncopy( ptr, dv->vals[ j ].bv_val, dv->vals[ j ].bv_len );
+                                       *ptr++ = '>';
+                                       *ptr++ = ';';
+                               }
+                       }
+               }
+               ptr = lutil_strncopy( ptr, dr->derefVal.bv_val, dr->derefVal.bv_len );
+               *ptr++ = '\0';
+
+               tool_write_ldif( LDIF_PUT_COMMENT, NULL, buf, len );
+
+               ldap_memfree( buf );
+       }
+
+       rc = LDAP_SUCCESS;
+
+done:;
+       ldap_derefresponse_free( drhead );
+
+       return rc;
+}
+#endif
+
 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
 static int
 print_ppolicy( LDAP *ld, LDAPControl *ctrl )
index 7e69fa5992b174a4aa56ff8274137afd4df8e71c..213f8c1f0f164d559db3118ea86eb08f1d1cf64c 100644 (file)
@@ -223,6 +223,12 @@ static LDAPControl *c = NULL;
 static int nctrls = 0;
 static int save_nctrls = 0;
 
+#ifdef LDAP_CONTROL_X_DEREF
+static int derefcrit;
+static LDAPDerefSpec *ds;
+static struct berval derefval;
+#endif
+
 static int
 ctrl_add( void )
 {
@@ -491,6 +497,43 @@ handle_private_option( int i )
                        }
                        if ( crit ) ldapsync *= -1;
 
+#ifdef LDAP_CONTROL_X_DEREF
+               } else if ( strcasecmp( control, "deref" ) == 0 ) {
+                       int ispecs;
+                       char **specs;
+
+                       /* cvalue is something like
+                        *
+                        * derefAttr:attr[,attr[...]][;derefAttr:attr[,attr[...]]]"
+                        */
+
+                       specs = ldap_str2charray( cvalue, ";" );
+                       for ( ispecs = 0; specs[ ispecs ] != NULL; ispecs++ )
+                               /* count'em */
+
+                       ds = ldap_memcalloc( ispecs + 1, sizeof( LDAPDerefSpec ) );
+                       if ( ds == NULL ) {
+                               /* error */
+                       }
+
+                       for ( ispecs = 0; specs[ ispecs ] != NULL; ispecs++ ) {
+                               char *ptr;
+
+                               ptr = strchr( specs[ ispecs ], ':' );
+                               if ( ptr == NULL ) {
+                                       /* error */
+                               }
+
+                               ds[ ispecs ].derefAttr = specs[ ispecs ];
+                               *ptr++ = '\0';
+                               ds[ ispecs ].attributes = ldap_str2charray( ptr, "," );
+                       }
+
+                       derefcrit = 1 + crit;
+
+                       ldap_memfree( specs );
+#endif /* LDAP_CONTROL_X_DEREF */
+
                } else if ( tool_is_oid( control ) ) {
                        if ( ctrl_add() ) {
                                exit( EXIT_FAILURE );
@@ -780,6 +823,9 @@ getNextPage:
        if ( nctrls > 0
 #ifdef LDAP_CONTROL_DONTUSECOPY
                || dontUseCopy
+#endif
+#ifdef LDAP_CONTROL_X_DEREF
+               || derefcrit
 #endif
                || domainScope
                || pagedResults
@@ -933,6 +979,32 @@ getNextPage:
                        c[i].ldctl_iscritical = sss > 1;
                        i++;
                }
+
+#ifdef LDAP_CONTROL_X_DEREF
+               if ( ds ) {
+                       if ( derefval.bv_val == NULL ) {
+                               int i;
+                               if ( ldap_create_deref_control_value( ld, ds, &derefval ) != LDAP_SUCCESS ) {
+                                       return EXIT_FAILURE;
+                               }
+
+                               for ( i = 0; ds[ i ].derefAttr != NULL; i++ ) {
+                                       ldap_memfree( ds[ i ].derefAttr );
+                                       ldap_charray_free( ds[ i ].attributes );
+                               }
+                               ldap_memfree( ds );
+                       }
+
+                       if ( ctrl_add() ) {
+                               exit( EXIT_FAILURE );
+                       }
+
+                       c[ i ].ldctl_iscritical = derefcrit > 1;
+                       c[ i ].ldctl_oid = LDAP_CONTROL_X_DEREF;
+                       c[ i ].ldctl_value = derefval;
+                       i++;
+               }
+#endif /* LDAP_CONTROL_X_DEREF */
        }
 
        tool_server_controls( ld, c, i );
@@ -1019,6 +1091,12 @@ getNextPage:
                        printf(_("\n# with server side sorting %scontrol"),
                                sss > 1 ? _("critical ") : "" );
                }
+#ifdef LDAP_CONTROL_X_DEREF
+               if ( sss ) {
+                       printf(_("\n# with dereference %scontrol"),
+                               sss > 1 ? _("critical ") : "" );
+               }
+#endif
 
                printf( _("\n#\n\n") );
 
index b4618fdcae24a9e7593cb3f3aff6a77ab6508c77..7e758534fc8a61daf9ac9351193181bc3c618d3b 100644 (file)
@@ -338,6 +338,7 @@ Overlays="accesslog \
        collect \
        constraint \
        dds \
+       deref \
        dyngroup \
        dynlist \
        memberof \
@@ -367,6 +368,8 @@ OL_ARG_ENABLE(constraint,[    --enable-constraint     Attribute Constraint overlay
        no, [no yes mod], ol_enable_overlays)
 OL_ARG_ENABLE(dds,[    --enable-dds      Dynamic Directory Services overlay],
        no, [no yes mod], ol_enable_overlays)
+OL_ARG_ENABLE(deref,[    --enable-deref          Dereference overlay],
+       no, [no yes mod], ol_enable_overlays)
 OL_ARG_ENABLE(dyngroup,[    --enable-dyngroup    Dynamic Group overlay],
        no, [no yes mod], ol_enable_overlays)
 OL_ARG_ENABLE(dynlist,[    --enable-dynlist      Dynamic List overlay],
@@ -2846,6 +2849,18 @@ if test "$ol_enable_dds" != no ; then
        AC_DEFINE_UNQUOTED(SLAPD_OVER_DDS,$MFLAG,[define for Dynamic Directory Services overlay])
 fi
 
+if test "$ol_enable_deref" != no ; then
+       BUILD_DDS=$ol_enable_deref
+       if test "$ol_enable_deref" = mod ; then
+               MFLAG=SLAPD_MOD_DYNAMIC
+               SLAPD_DYNAMIC_OVERLAYS="$SLAPD_DYNAMIC_OVERLAYS deref.la"
+       else
+               MFLAG=SLAPD_MOD_STATIC
+               SLAPD_STATIC_OVERLAYS="$SLAPD_STATIC_OVERLAYS deref.o"
+       fi
+       AC_DEFINE_UNQUOTED(SLAPD_OVER_DEREF,$MFLAG,[define for Dynamic Directory Services overlay])
+fi
+
 if test "$ol_enable_dyngroup" != no ; then
        BUILD_DYNGROUP=$ol_enable_dyngroup
        if test "$ol_enable_dyngroup" = mod ; then
index b86071aadbcf8f546b09a6a271272a4f236ddbf7..99c2474723ff9a4a9540331eac62e5447d2c9ebd 100644 (file)
@@ -321,6 +321,8 @@ typedef struct ldapcontrol {
                                                LDAP_CONTROL_X_SESSION_TRACKING ".2"
 #define LDAP_CONTROL_X_SESSION_TRACKING_USERNAME \
                                                LDAP_CONTROL_X_SESSION_TRACKING ".3"
+/* Dereference Control (work in progress) */
+#define        LDAP_CONTROL_X_DEREF                    "1.3.6.1.4.1.4203.666.5.16"
 #endif /* LDAP_DEVEL */
 
 /* various expired works */
@@ -2400,5 +2402,56 @@ ldap_create_assertion_control LDAP_P((
        int             iscritical,
        LDAPControl     **ctrlp ));
 
+/*
+ * in deref.c
+ */
+
+typedef struct LDAPDerefSpec {
+       char *derefAttr;
+       char **attributes;
+} LDAPDerefSpec;
+
+typedef struct LDAPDerefVal {
+       char *type;
+       BerVarray vals;
+       struct LDAPDerefVal *next;
+} LDAPDerefVal;
+
+typedef struct LDAPDerefRes {
+       char *derefAttr;
+       struct berval derefVal;
+       LDAPDerefVal *attrVals;
+       struct LDAPDerefRes *next;
+} LDAPDerefRes;
+
+LDAP_F( int )
+ldap_create_deref_control_value LDAP_P((
+       LDAP *ld,
+       LDAPDerefSpec *ds,
+       struct berval *value ));
+
+LDAP_F( int )
+ldap_create_deref_control LDAP_P((
+       LDAP            *ld,
+       LDAPDerefSpec   *ds,
+       int             iscritical,
+       LDAPControl     **ctrlp ));
+
+LDAP_F( void )
+ldap_derefresponse_free LDAP_P((
+       LDAPDerefRes *dr ));
+
+LDAP_F( int )
+ldap_parse_derefresponse_control LDAP_P((
+       LDAP *ld,
+       LDAPControl *ctrl,
+       LDAPDerefRes **drp ));
+
+LDAP_F( int )
+ldap_parse_deref_control LDAP_P((
+       LDAP            *ld,
+       LDAPControl     **ctrls,
+       LDAPDerefRes    **drp ));
+
 LDAP_END_DECL
 #endif /* _LDAP_H */
index eaaaa3aeb52992002640fc14479f127d8f630bfc..e5ff22e8ff2424ba01bcacdee6c7b7b456f6e50f 100644 (file)
 /* define for Dynamic Directory Services overlay */
 #undef SLAPD_OVER_DDS
 
+/* define for Dynamic Directory Services overlay */
+#undef SLAPD_OVER_DEREF
+
 /* define for Dynamic Group overlay */
 #undef SLAPD_OVER_DYNGROUP
 
index c62e56ffc0627fc48e8cfff41a7b9738a11f75dd..ed8c2b17e62cf248a0d8f18d2229a0adf7265040 100644 (file)
@@ -27,7 +27,7 @@ SRCS  = bind.c open.c result.c error.c compare.c search.c \
        init.c options.c print.c string.c util-int.c schema.c \
        charray.c tls.c os-local.c dnssrv.c utf-8.c utf-8-conv.c \
        turn.c ppolicy.c dds.c txn.c ldap_sync.c stctrl.c \
-       assertion.c
+       assertion.c deref.c
 
 OBJS   = bind.lo open.lo result.lo error.lo compare.lo search.lo \
        controls.lo messages.lo references.lo extended.lo cyrus.lo \
@@ -39,7 +39,7 @@ OBJS  = bind.lo open.lo result.lo error.lo compare.lo search.lo \
        init.lo options.lo print.lo string.lo util-int.lo schema.lo \
        charray.lo tls.lo os-local.lo dnssrv.lo utf-8.lo utf-8-conv.lo \
        turn.lo ppolicy.lo dds.lo txn.lo ldap_sync.lo stctrl.lo \
-       assertion.lo
+       assertion.lo deref.lo
 
 LDAP_INCDIR= ../../include       
 LDAP_LIBDIR= ../../libraries
diff --git a/libraries/libldap/deref.c b/libraries/libldap/deref.c
new file mode 100644 (file)
index 0000000..d5a52ae
--- /dev/null
@@ -0,0 +1,279 @@
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2008 The OpenLDAP Foundation.
+ * Portions Copyright 2008 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati
+ * for inclusion in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/stdlib.h>
+#include <ac/string.h>
+#include <ac/time.h>
+
+#include "ldap-int.h"
+
+int
+ldap_create_deref_control_value(
+       LDAP            *ld,
+       LDAPDerefSpec   *ds,
+       struct berval   *value )
+{
+       BerElement      *ber = NULL;
+       ber_tag_t       tag;
+       int             i;
+
+       if ( ld == NULL || value == NULL || ds == NULL )
+       {
+               if ( ld )
+                       ld->ld_errno = LDAP_PARAM_ERROR;
+               return LDAP_PARAM_ERROR;
+       }
+
+       assert( LDAP_VALID( ld ) );
+
+       value->bv_val = NULL;
+       value->bv_len = 0;
+       ld->ld_errno = LDAP_SUCCESS;
+
+       ber = ldap_alloc_ber_with_options( ld );
+       if ( ber == NULL ) {
+               ld->ld_errno = LDAP_NO_MEMORY;
+               return ld->ld_errno;
+       }
+
+       tag = ber_printf( ber, "{" /*}*/ );
+       if ( tag == LBER_ERROR ) {
+               ld->ld_errno = LDAP_ENCODING_ERROR;
+               goto done;
+       }
+
+       for ( i = 0; ds[i].derefAttr != NULL; i++ ) {
+               int j;
+
+               tag = ber_printf( ber, "{s{" /*}}*/ , ds[i].derefAttr );
+               if ( tag == LBER_ERROR ) {
+                       ld->ld_errno = LDAP_ENCODING_ERROR;
+                       goto done;
+               }
+
+               for ( j = 0; ds[i].attributes[j] != NULL; j++ ) {
+                       tag = ber_printf( ber, "s", ds[i].attributes[ j ] );
+                       if ( tag == LBER_ERROR ) {
+                               ld->ld_errno = LDAP_ENCODING_ERROR;
+                               goto done;
+                       }
+               }
+
+               tag = ber_printf( ber, /*{{*/ "}N}" );
+               if ( tag == LBER_ERROR ) {
+                       ld->ld_errno = LDAP_ENCODING_ERROR;
+                       goto done;
+               }
+       }
+
+       tag = ber_printf( ber, /*{*/ "}" );
+       if ( tag == LBER_ERROR ) {
+               ld->ld_errno = LDAP_ENCODING_ERROR;
+               goto done;
+       }
+
+       if ( ber_flatten2( ber, value, 1 ) == -1 ) {
+               ld->ld_errno = LDAP_NO_MEMORY;
+       }
+
+done:;
+       if ( ber != NULL ) {
+               ber_free( ber, 1 );
+       }
+
+       return ld->ld_errno;
+}
+
+int
+ldap_create_deref_control(
+       LDAP            *ld,
+       LDAPDerefSpec   *ds,
+       int             iscritical,
+       LDAPControl     **ctrlp )
+{
+       struct berval   value;
+
+       if ( ctrlp == NULL ) {
+               ld->ld_errno = LDAP_PARAM_ERROR;
+               return ld->ld_errno;
+       }
+
+       ld->ld_errno = ldap_create_deref_control_value( ld, ds, &value );
+       if ( ld->ld_errno == LDAP_SUCCESS ) {
+               ld->ld_errno = ldap_control_create( LDAP_CONTROL_PAGEDRESULTS,
+                       iscritical, &value, 0, ctrlp );
+               if ( ld->ld_errno != LDAP_SUCCESS ) {
+                       LDAP_FREE( value.bv_val );
+               }
+       }
+
+       return ld->ld_errno;
+}
+
+void
+ldap_derefresponse_free( LDAPDerefRes *dr )
+{
+       for ( ; dr; ) {
+               LDAPDerefRes *drnext = dr->next;
+               LDAPDerefVal *dv;
+
+               LDAP_FREE( dr->derefAttr );
+               LDAP_FREE( dr->derefVal.bv_val );
+
+               for ( dv = dr->attrVals; dv; ) {
+                       LDAPDerefVal *dvnext = dv->next;
+                       LDAP_FREE( dv->type );
+                       ber_bvarray_free( dv->vals );
+                       LDAP_FREE( dv );
+                       dv = dvnext;
+               }
+
+               LDAP_FREE( dr );
+
+               dr = drnext;
+       }
+}
+
+int
+ldap_parse_derefresponse_control(
+       LDAP            *ld,
+       LDAPControl     *ctrl,
+       LDAPDerefRes    **drp2 )
+{
+       BerElement *ber;
+       ber_tag_t tag;
+       ber_len_t len;
+       char *last;
+       LDAPDerefRes *drhead = NULL, **drp;
+
+       if ( ld == NULL || ctrl == NULL || drp2 == NULL ) {
+               if ( ld )
+                       ld->ld_errno = LDAP_PARAM_ERROR;
+               return LDAP_PARAM_ERROR;
+       }
+
+       /* Create a BerElement from the berval returned in the control. */
+       ber = ber_init( &ctrl->ldctl_value );
+
+       if ( ber == NULL ) {
+               ld->ld_errno = LDAP_NO_MEMORY;
+               return ld->ld_errno;
+       }
+
+       /* Extract the count and cookie from the control. */
+       drp = &drhead;
+       for ( tag = ber_first_element( ber, &len, &last );
+               tag != LBER_DEFAULT;
+               tag = ber_next_element( ber, &len, last ) )
+       {
+               LDAPDerefRes *dr;
+               LDAPDerefVal **dvp;
+               char *last2;
+
+               dr = LDAP_CALLOC( 1, sizeof(LDAPDerefRes) );
+               dvp = &dr->attrVals;
+
+               tag = ber_scanf( ber, "{ao", &dr->derefAttr, &dr->derefVal );
+               if ( tag == LBER_ERROR ) {
+                       goto done;
+               }
+
+               for ( tag = ber_first_element( ber, &len, &last2 );
+                       tag != LBER_DEFAULT;
+                       tag = ber_next_element( ber, &len, last2 ) )
+               {
+                       LDAPDerefVal *dv;
+
+                       dv = LDAP_CALLOC( 1, sizeof(LDAPDerefVal) );
+
+                       tag = ber_scanf( ber, "{a[W]}", &dv->type, &dv->vals );
+                       if ( tag == LBER_ERROR ) {
+                               goto done;
+                       }
+
+                       *dvp = dv;
+                       dvp = &dv->next;
+               }
+
+               tag = ber_scanf( ber, "}" );
+               if ( tag == LBER_ERROR ) {
+                       goto done;
+               }
+
+               *drp = dr;
+               drp = &dr->next;
+       }
+
+       tag = 0;
+
+done:;
+        ber_free( ber, 1 );
+
+       if ( tag == LBER_ERROR ) {
+               if ( drhead != NULL ) {
+                       ldap_derefresponse_free( drhead );
+               }
+
+               *drp2 = NULL;
+               ld->ld_errno = LDAP_DECODING_ERROR;
+
+       } else {
+               *drp2 = drhead;
+               ld->ld_errno = LDAP_SUCCESS;
+       }
+
+       return ld->ld_errno;
+}
+
+int
+ldap_parse_deref_control(
+       LDAP            *ld,
+       LDAPControl     **ctrls,
+       LDAPDerefRes    **drp )
+{
+       LDAPControl *c;
+
+       if ( drp == NULL ) {
+               ld->ld_errno = LDAP_PARAM_ERROR;
+               return ld->ld_errno;
+       }
+
+       *drp = NULL;
+
+       if ( ctrls == NULL ) {
+               ld->ld_errno =  LDAP_CONTROL_NOT_FOUND;
+               return ld->ld_errno;
+       }
+
+       c = ldap_control_find( LDAP_CONTROL_X_DEREF, ctrls, NULL );
+       if ( c == NULL ) {
+               /* No deref control was found. */
+               ld->ld_errno = LDAP_CONTROL_NOT_FOUND;
+               return ld->ld_errno;
+       }
+
+       ld->ld_errno = ldap_parse_derefresponse_control( ld, c, drp );
+
+       return ld->ld_errno;
+}
+
index 07b4b1ebb46befbacde63728b6b28178be0faa2d..ce60327a4e2c39e407a48d0a64a0b9917b9a956d 100644 (file)
@@ -18,6 +18,7 @@ SRCS = overlays.c \
        auditlog.c \
        constraint.c \
        dds.c \
+       deref.c \
        dyngroup.c \
        dynlist.c \
        memberof.c \
@@ -72,6 +73,9 @@ constraint.la : constraint.lo
 dds.la : dds.lo
        $(LTLINK_MOD) -module -o $@ dds.lo version.lo $(LINK_LIBS)
 
+deref.la : deref.lo
+       $(LTLINK_MOD) -module -o $@ deref.lo version.lo $(LINK_LIBS)
+
 dyngroup.la : dyngroup.lo
        $(LTLINK_MOD) -module -o $@ dyngroup.lo version.lo $(LINK_LIBS)
 
diff --git a/servers/slapd/overlays/deref.c b/servers/slapd/overlays/deref.c
new file mode 100644 (file)
index 0000000..96b210a
--- /dev/null
@@ -0,0 +1,517 @@
+/* deref.c - dereference overlay */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2008 The OpenLDAP Foundation.
+ * Portions Copyright 2008 Pierangelo Masarati.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati
+ * for inclusion in OpenLDAP Software.
+ */
+
+#include "portable.h"
+
+#ifdef SLAPD_OVER_DEREF
+
+#include <stdio.h>
+
+#include "ac/string.h"
+#include "ac/socket.h"
+
+#include "slap.h"
+#include "config.h"
+
+#include "lutil.h"
+
+/*
+ * 1. Specification
+ *
+ * 1.1. Request
+ *
+ *  controlValue ::= SEQUENCE OF derefSpec DerefSpec
+ *
+ *  DerefSpec ::= SEQUENCE {
+ *      derefAttr       attributeDescription,    ; DN-valued
+ *      attributes      AttributeList }
+ *
+ *  AttributeList ::= SEQUENCE OF attr AttributeDescription
+ *
+ *  derefAttr MUST be unique within controlValue
+ *
+ *
+ * 1.2. Response
+ *
+ *  controlValue ::= SEQUENCE OF DerefRes
+ *
+ * From RFC 4511:
+ *      PartialAttribute ::= SEQUENCE {
+ *           type       AttributeDescription,
+ *           vals       SET OF value AttributeValue }
+ *
+ *      PartialAttributeList ::= SEQUENCE OF
+ *                           partialAttribute PartialAttribute
+ *
+ *  DerefRes ::= SEQUENCE {
+ *      derefAttr       AttributeDescription,
+ *      derefVal        LDAPDN,
+ *      attrVals        PartialAttributeList OPTIONAL }
+ *
+ *  If vals is empty, partialAttribute is omitted.
+ *  If all vals in attrVals are empty, attrVals is omitted.
+ *      
+ * 2. Examples
+ *
+ * 2.1. Example
+ *
+ * 2.1.1. Request
+ *
+ * { { member, { GUID, SID } }, { memberOf, { GUID, SID } } }
+ *
+ * 2.1.2. Response
+ *
+ * { { memberOf, "cn=abartlet,cn=users,dc=abartlet,dc=net",
+ *     { GUID, [ "0bc11d00-e431-40a0-8767-344a320142fa" ],
+ *       SID, [ "S-1-2-3-2345" ] } },
+ *   { memberOf, "cn=ando,cn=users,dc=sys-net,dc=it",
+ *     { GUID, [ "0bc11d00-e431-40a0-8767-344a320142fb" ],
+ *       SID, [ "S-1-2-3-2346" ] } } }
+ *
+ * 2.2. Example
+ *
+ * 2.2.1. Request
+ *
+ * { { member, { cn, uid, drink } } }
+ *
+ * 2.2.2. Response
+ *
+ * { { member, "cn=ando,cn=users,dc=sys-net,dc=it",
+ *     { cn, [ "ando", "Pierangelo Masarati" ],
+ *       uid, [ "ando" ] } } }
+ */
+
+#define o_deref                        o_ctrlflag[deref_cid]
+#define o_ctrlderef            o_controls[deref_cid]
+
+typedef struct DerefSpec {
+       AttributeDescription    *ds_derefAttr;
+       AttributeDescription    **ds_attributes;
+       int                     ds_nattrs;
+       struct DerefSpec        *ds_next;
+} DerefSpec;
+
+typedef struct DerefVal {
+       struct berval   dv_derefSpecVal;
+       BerVarray       *dv_attrVals;
+} DerefVal;
+
+typedef struct DerefRes {
+       DerefSpec               dr_spec;
+       DerefVal                *dr_vals;
+       struct DerefRes         *dr_next;
+} DerefRes;
+
+typedef struct deref_cb_t {
+       slap_overinst *dc_on;
+       DerefSpec *dc_ds;
+} deref_cb_t;
+
+static int                     deref_cid;
+static slap_overinst           deref;
+
+static int
+deref_parseCtrl (
+       Operation *op,
+       SlapReply *rs,
+       LDAPControl *ctrl )
+{
+       ber_tag_t tag;
+       BerElementBuffer berbuf;
+       BerElement *ber = (BerElement *)&berbuf;
+       ber_len_t len;
+       char *last;
+       DerefSpec *dshead = NULL, **dsp = &dshead;
+       BerVarray attributes = NULL;
+
+       if ( op->o_deref != SLAP_CONTROL_NONE ) {
+               rs->sr_text = "Dereference control specified multiple times";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+       if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
+               rs->sr_text = "Dereference control value is absent";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+       if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
+               rs->sr_text = "Dereference control value is empty";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+       ber_init2( ber, &ctrl->ldctl_value, 0 );
+
+       for ( tag = ber_first_element( ber, &len, &last );
+               tag != LBER_DEFAULT;
+               tag = ber_next_element( ber, &len, last ) )
+       {
+               struct berval derefAttr;
+               DerefSpec *ds, *dstmp;
+               const char *text;
+               int rc;
+               ber_len_t cnt = sizeof(struct berval);
+               ber_len_t off = 0;
+
+               if ( ber_scanf( ber, "{m{M}}", &derefAttr, &attributes, &cnt, off ) == LBER_ERROR )
+               {
+                       rs->sr_text = "Dereference control: derefSpec decoding error";
+                       rs->sr_err = LDAP_PROTOCOL_ERROR;
+                       goto done;
+               }
+
+               ds = (DerefSpec *)op->o_tmpcalloc( 1,
+                       sizeof(DerefSpec) + sizeof(AttributeDescription *)*(cnt + 1),
+                       op->o_tmpmemctx );
+               ds->ds_attributes = (AttributeDescription **)&ds[1];
+               ds->ds_nattrs = cnt;
+
+               rc = slap_bv2ad( &derefAttr, &ds->ds_derefAttr, &text );
+               if ( rc != LDAP_SUCCESS ) {
+                       rs->sr_text = "Dereference control: derefAttr decoding error";
+                       rs->sr_err = LDAP_PROTOCOL_ERROR;
+                       goto done;
+               }
+
+               for ( dstmp = dshead; dstmp && dstmp != ds; dstmp = dstmp->ds_next ) {
+                       if ( dstmp->ds_derefAttr == ds->ds_derefAttr ) {
+                               rs->sr_text = "Dereference control: derefAttr must be unique within control";
+                               rs->sr_err = LDAP_PROTOCOL_ERROR;
+                               goto done;
+                       }
+               }
+
+               if ( ds->ds_derefAttr->ad_type->sat_syntax != slap_schema.si_syn_distinguishedName ) {
+                       if ( ctrl->ldctl_iscritical ) {
+                               rs->sr_text = "Dereference control: derefAttr syntax not distinguishedName";
+                               rs->sr_err = LDAP_PROTOCOL_ERROR;
+                               goto done;
+                       }
+
+                       rs->sr_err = LDAP_SUCCESS;
+                       goto justcleanup;
+               }
+
+               for ( cnt = 0; !BER_BVISNULL( &attributes[ cnt ] ); cnt++ ) {
+                       rc = slap_bv2ad( &attributes[ cnt ], &ds->ds_attributes[ cnt ], &text );
+                       if ( rc != LDAP_SUCCESS ) {
+                               rs->sr_text = "Dereference control: attribute decoding error";
+                               rs->sr_err = LDAP_PROTOCOL_ERROR;
+                               goto done;
+                       }
+               }
+
+               ber_memfree_x( attributes, op->o_tmpmemctx );
+               attributes = NULL;
+
+               *dsp = ds;
+               dsp = &ds->ds_next;
+       }
+
+       op->o_ctrlderef = (void *)dshead;
+
+       op->o_deref = ctrl->ldctl_iscritical
+               ? SLAP_CONTROL_CRITICAL
+               : SLAP_CONTROL_NONCRITICAL;
+
+       rs->sr_err = LDAP_SUCCESS;
+
+done:;
+       if ( rs->sr_err != LDAP_SUCCESS ) {
+justcleanup:;
+               for ( ; dshead; ) {
+                       DerefSpec *dsnext = dshead->ds_next;
+                       op->o_tmpfree( dshead, op->o_tmpmemctx );
+                       dshead = dsnext;
+               }
+       }
+
+       if ( attributes != NULL ) {
+               ber_memfree_x( attributes, op->o_tmpmemctx );
+       }
+
+       return rs->sr_err;
+}
+
+static int
+deref_response( Operation *op, SlapReply *rs )
+{
+       int rc = SLAP_CB_CONTINUE;
+
+       if ( rs->sr_type == REP_SEARCH ) {
+               BerElementBuffer berbuf;
+               BerElement *ber = (BerElement *) &berbuf;
+               deref_cb_t *dc = (deref_cb_t *)op->o_callback->sc_private;
+               DerefSpec *ds;
+               DerefRes *dr, *drhead = NULL, **drp = &drhead;
+               BackendInfo *bi = op->o_bd->bd_info;
+               struct berval bv = BER_BVNULL;
+               int nDerefRes = 0, nDerefVals = 0, nAttrs = 0, nVals = 0;
+               struct berval ctrlval;
+               LDAPControl *ctrl, **ctrlsp;
+               int i;
+
+               op->o_bd->bd_info = (BackendInfo *)dc->dc_on->on_info;
+               for ( ds = dc->dc_ds; ds; ds = ds->ds_next ) {
+                       Attribute *a = attr_find( rs->sr_entry->e_attrs, ds->ds_derefAttr );
+
+                       if ( a != NULL ) {
+                               DerefVal *dv;
+                               BerVarray *bva;
+
+                               dr = op->o_tmpcalloc( 1,
+                                       sizeof( DerefRes ) + ( sizeof( DerefVal ) + sizeof( BerVarray * ) * ds->ds_nattrs ) * ( a->a_numvals + 1 ),
+                                       op->o_tmpmemctx );
+                               dr->dr_spec = *ds;
+                               dv = dr->dr_vals = (DerefVal *)&dr[ 1 ];
+                               bva = (BerVarray *)&dv[ a->a_numvals + 1 ];
+
+                               bv.bv_len += ds->ds_derefAttr->ad_cname.bv_len;
+                               nAttrs++;
+                               nDerefRes++;
+
+                               for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) {
+                                       Entry *e = NULL;
+
+                                       dv[ i ].dv_attrVals = bva;
+                                       bva += ds->ds_nattrs;
+
+                                       dv[i].dv_derefSpecVal = a->a_vals[ i ];
+                                       bv.bv_len += dv[i].dv_derefSpecVal.bv_len;
+                                       nVals++;
+                                       nDerefVals++;
+
+                                       rc = overlay_entry_get_ov( op, &a->a_nvals[ i ], NULL, NULL, 0, &e, dc->dc_on );
+                                       if ( rc == LDAP_SUCCESS && e != NULL ) {
+                                               int j;
+
+                                               for ( j = 0; j < ds->ds_nattrs; j++ ) {
+                                                       Attribute *aa = attr_find( e->e_attrs, ds->ds_attributes[ j ] );
+                                                       if ( aa != NULL ) {
+                                                               int k;
+
+                                                               dv[i].dv_attrVals[ j ] = aa->a_vals;
+
+                                                               bv.bv_len += ds->ds_attributes[ j ]->ad_cname.bv_len;
+                                                               for ( k = 0; !BER_BVISNULL( &aa->a_vals[ k ] ); k++ ) {
+                                                                       bv.bv_len += aa->a_vals[ k ].bv_len;
+                                                                       nVals++;
+                                                               }
+                                                               nAttrs++;
+                                                       }
+                                               }
+
+                                               overlay_entry_release_ov( op, e, 0, dc->dc_on );
+                                       }
+                               }
+
+                               *drp = dr;
+                               drp = &dr->dr_next;
+                       }
+               }
+               op->o_bd->bd_info = bi;
+
+               if ( drhead == NULL ) {
+                       return SLAP_CB_CONTINUE;
+               }
+
+               /* cook the control value */
+               bv.bv_len += nVals * sizeof(struct berval)
+                       + nAttrs * sizeof(struct berval)
+                       + nDerefVals * sizeof(DerefVal)
+                       + nDerefRes * sizeof(DerefRes);
+               bv.bv_val = op->o_tmpalloc( bv.bv_len, op->o_tmpmemctx );
+
+               ber_init2( ber, &bv, LBER_USE_DER );
+               ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
+
+#if 0
+               rc = ber_printf( ber, "{" /*}*/ );
+               for ( dr = drhead; dr != NULL; dr = dr->dr_next ) {
+                       rc = ber_printf( ber, "{{O{" /*}}}*/,
+                               &dr->dr_spec.ds_derefAttr->ad_cname );
+                       for ( i = 0; i < dr->dr_spec.ds_nattrs; i++ ) {
+                               rc = ber_printf( ber, "O",
+                                       &dr->dr_spec.ds_attributes[ i ]->ad_cname );
+                       }
+                       rc = ber_printf( ber, /*{{*/ "}}{" /*}*/ );
+                       for ( i = 0; !BER_BVISNULL( &dr->dr_vals[ i ].dv_derefSpecVal ); i++ ) {
+                               int j;
+
+                               rc = ber_printf( ber, "{O{" /*}}*/ ,
+                                       &dr->dr_vals[ i ].dv_derefSpecVal );
+                               for ( j = 0; j < dr->dr_spec.ds_nattrs; j++ ) {
+                                       if ( dr->dr_vals[ i ].dv_attrVals[ j ] != NULL ) {
+                                               rc = ber_printf( ber, "[W]", dr->dr_vals[ i ].dv_attrVals[ j ] );
+                                       } else {
+                                               rc = ber_printf( ber, "b", 0 );
+                                       }
+                               }
+                               rc = ber_printf( ber, /*{{*/ "}}" );
+                       }
+                       rc = ber_printf( ber, /*{{*/ "}}" );
+               }
+               rc = ber_printf( ber, /*{*/ "}" );
+#endif
+
+               rc = ber_printf( ber, "{" /*}*/ );
+               for ( dr = drhead; dr != NULL; dr = dr->dr_next ) {
+                       for ( i = 0; !BER_BVISNULL( &dr->dr_vals[ i ].dv_derefSpecVal ); i++ ) {
+                               int j;
+
+                               rc = ber_printf( ber, "{OO{" /*}*/,
+                                       &dr->dr_spec.ds_derefAttr->ad_cname,
+                                       &dr->dr_vals[ i ].dv_derefSpecVal );
+                               for ( j = 0; j < dr->dr_spec.ds_nattrs; j++ ) {
+                                       if ( dr->dr_vals[ i ].dv_attrVals[ j ] != NULL ) {
+                                               rc = ber_printf( ber, "{O[W]}",
+                                                       &dr->dr_spec.ds_attributes[ j ]->ad_cname,
+                                                       dr->dr_vals[ i ].dv_attrVals[ j ] );
+                                       }
+                               }
+                               rc = ber_printf( ber, /*{*/ "}N}" );
+                       }
+               }
+               rc = ber_printf( ber, /*{*/ "}" );
+               if ( ber_flatten2( ber, &ctrlval, 0 ) == -1 ) {
+                       if ( op->o_deref == SLAP_CONTROL_CRITICAL ) {
+                               rc = LDAP_CONSTRAINT_VIOLATION;
+
+                       } else {
+                               rc = SLAP_CB_CONTINUE;
+                       }
+                       goto cleanup;
+               }
+
+               ctrl = op->o_tmpcalloc( 1,
+                       sizeof( LDAPControl ) + ctrlval.bv_len + 1,
+                       op->o_tmpmemctx );
+               ctrl->ldctl_value.bv_val = (char *)&ctrl[ 1 ];
+               ctrl->ldctl_oid = LDAP_CONTROL_X_DEREF;
+               ctrl->ldctl_iscritical = 0;
+               ctrl->ldctl_value.bv_len = ctrlval.bv_len;
+               lutil_strncopy( ctrl->ldctl_value.bv_val, ctrlval.bv_val, ctrlval.bv_len );
+               ctrl->ldctl_value.bv_val[ ctrl->ldctl_value.bv_len ] = '\0';
+
+               ber_free_buf( ber );
+
+               i = 0;
+               if ( rs->sr_ctrls ) {
+                       for ( ; rs->sr_ctrls[ i ] != NULL; i++ )
+                               /* count'em */ ;
+               }
+               i += 2;
+               ctrlsp = op->o_tmpcalloc( i, sizeof(LDAPControl *), op->o_tmpmemctx );
+               i = 0;
+               if ( rs->sr_ctrls != NULL ) {
+                       for ( ; rs->sr_ctrls[ i ] != NULL; i++ ) {
+                               ctrlsp[ i ] = rs->sr_ctrls[ i ];
+                       }
+               }
+               ctrlsp[ i++ ] = ctrl;
+               ctrlsp[ i++ ] = NULL;
+               if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) {
+                       op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx );
+               }
+               rs->sr_ctrls = ctrlsp;
+               rs->sr_flags |= REP_CTRLS_MUSTBEFREED;
+
+               rc = SLAP_CB_CONTINUE;
+
+cleanup:;
+               /* release all */
+               for ( ; drhead != NULL; ) {
+                       DerefRes *drnext = drhead->dr_next;
+                       op->o_tmpfree( drhead, op->o_tmpmemctx );
+                       drhead = drnext;
+               }
+       }
+
+       return rc;
+}
+
+static int
+deref_cleanup( Operation *op, SlapReply *rs )
+{
+       if ( rs->sr_type == REP_RESULT || rs->sr_err == SLAPD_ABANDON ) {
+               op->o_tmpfree( op->o_callback, op->o_tmpmemctx );
+               op->o_callback = NULL;
+
+               op->o_tmpfree( op->o_ctrlderef, op->o_tmpmemctx );
+               op->o_ctrlderef = NULL;
+       }
+
+       return SLAP_CB_CONTINUE;
+}
+
+static int
+deref_op_search( Operation *op, SlapReply *rs )
+{
+       if ( op->o_deref ) {
+               slap_callback *sc;
+               deref_cb_t *dc;
+
+               sc = op->o_tmpcalloc( 1, sizeof( slap_callback ) + sizeof( deref_cb_t ), op->o_tmpmemctx );
+
+               dc = (deref_cb_t *)&sc[ 1 ];
+               dc->dc_on = (slap_overinst *)op->o_bd->bd_info;
+               dc->dc_ds = (DerefSpec *)op->o_ctrlderef;
+
+               sc->sc_response = deref_response;
+               sc->sc_cleanup = deref_cleanup;
+               sc->sc_private = (void *)dc;
+
+               sc->sc_next = op->o_callback->sc_next;
+                op->o_callback->sc_next = sc;
+       }
+
+       return SLAP_CB_CONTINUE;
+}
+
+int
+deref_initialize()
+{
+       int rc;
+
+       rc = register_supported_control( LDAP_CONTROL_X_DEREF,
+               SLAP_CTRL_SEARCH, NULL,
+               deref_parseCtrl, &deref_cid );
+       if ( rc != LDAP_SUCCESS ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "deref_init: Failed to register control (%d)\n",
+               rc, 0, 0 );
+               return rc;
+       }
+
+       deref.on_bi.bi_type = "deref";
+       deref.on_bi.bi_op_search = deref_op_search;
+
+       return overlay_register( &deref );
+}
+
+#if SLAPD_OVER_DEREF == SLAPD_MOD_DYNAMIC
+int
+init_module( int argc, char *argv[] )
+{
+       return deref_initialize();
+}
+#endif /* SLAPD_OVER_DEREF == SLAPD_MOD_DYNAMIC */
+
+#endif /* SLAPD_OVER_DEREF */