OpenLDAP 2.4 Change Log
OpenLDAP 2.4.13 Engineering
+ Added libldap dereference control support (ITS#5768)
Fixed liblutil hex conversion (ITS#5699)
Fixed liblutil returning undefined data (ITS#5748)
Fixed libldap error code return (ITS#5762)
Build Environment
Added ldapurl command
Added slapd GSSAPI refactoring (ITS#5369)
+ Added slapo-deref overlay (ITS#5768)
Documentation
admin24 added olcLimits to example (ITS#5746)
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;
{ 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 }
};
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 )
fprintf( stderr, _(" [!]subentries[=true|false] (RFC 3672 subentries)\n"));
fprintf( stderr, _(" [!]sync=ro[/<cookie>] (RFC 4533 LDAP Sync refreshOnly)\n"));
fprintf( stderr, _(" rp[/<cookie>][/<slimit>] (refreshAndPersist)\n"));
+#ifdef LDAP_CONTROL_X_DEREF
+ fprintf( stderr, _(" [!]deref=derefAttr:attr[,...][;derefAttr:attr[,...][;...]]\n"));
+#endif
fprintf( stderr, _(" [!]<oid>=:<value> (generic control; no response handling)\n"));
fprintf( stderr, _(" -F prefix URL prefix for files (default: %s)\n"), def_urlpre);
fprintf( stderr, _(" -l limit time limit (in seconds, or \"none\" or \"max\") for search\n"));
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 )
{
}
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 );
if ( nctrls > 0
#ifdef LDAP_CONTROL_DONTUSECOPY
|| dontUseCopy
+#endif
+#ifdef LDAP_CONTROL_X_DEREF
+ || derefcrit
#endif
|| domainScope
|| pagedResults
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 );
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") );
#! /bin/sh
-# From configure.in OpenLDAP: pkg/ldap/configure.in,v 1.631.2.14 2008/09/17 22:54:33 quanah Exp .
+# From configure.in OpenLDAP: pkg/ldap/configure.in,v 1.631.2.15 2008/11/08 00:14:44 quanah Exp .
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.59.
#
--enable-collect Collect overlay no|yes|mod [no]
--enable-constraint Attribute Constraint overlay no|yes|mod [no]
--enable-dds Dynamic Directory Services overlay no|yes|mod [no]
+ --enable-deref Dereference overlay no|yes|mod [no]
--enable-dyngroup Dynamic Group overlay no|yes|mod [no]
--enable-dynlist Dynamic List overlay no|yes|mod [no]
--enable-memberof Reverse Group Membership overlay no|yes|mod [no]
collect \
constraint \
dds \
+ deref \
dyngroup \
dynlist \
memberof \
fi;
# end --enable-dds
+# OpenLDAP --enable-deref
+
+ # Check whether --enable-deref or --disable-deref was given.
+if test "${enable_deref+set}" = set; then
+ enableval="$enable_deref"
+
+ ol_arg=invalid
+ for ol_val in no yes mod ; do
+ if test "$enableval" = "$ol_val" ; then
+ ol_arg="$ol_val"
+ fi
+ done
+ if test "$ol_arg" = "invalid" ; then
+ { { echo "$as_me:$LINENO: error: bad value $enableval for --enable-deref" >&5
+echo "$as_me: error: bad value $enableval for --enable-deref" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ ol_enable_deref="$ol_arg"
+
+else
+ ol_enable_deref=${ol_enable_overlays:-no}
+fi;
+# end --enable-deref
+
# OpenLDAP --enable-dyngroup
# Check whether --enable-dyngroup or --disable-dyngroup was given.
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 5704 "configure"' > conftest.$ac_ext
+ echo '#line 5730 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:7684: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:7710: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:7688: \$? = $ac_status" >&5
+ echo "$as_me:7714: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:7946: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:7972: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:7950: \$? = $ac_status" >&5
+ echo "$as_me:7976: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:8008: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:8034: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:8012: \$? = $ac_status" >&5
+ echo "$as_me:8038: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 10256 "configure"
+#line 10282 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 10354 "configure"
+#line 10380 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
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
+
+cat >>confdefs.h <<_ACEOF
+#define SLAPD_OVER_DEREF $MFLAG
+_ACEOF
+
+fi
+
if test "$ol_enable_dyngroup" != no ; then
BUILD_DYNGROUP=$ol_enable_dyngroup
if test "$ol_enable_dyngroup" = mod ; then
collect \
constraint \
dds \
+ deref \
dyngroup \
dynlist \
memberof \
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],
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
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 */
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 */
/* 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
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 \
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
--- /dev/null
+/* $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;
+ }
+
+ tag = ber_peek_tag( ber, &len );
+ if ( tag == (LBER_CONSTRUCTED|LBER_CLASS_CONTEXT) ) {
+ 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;
+}
+
auditlog.c \
constraint.c \
dds.c \
+ deref.c \
dyngroup.c \
dynlist.c \
memberof.c \
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)
--- /dev/null
+/* 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 [0] 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" ] } } },
+ * { member, "dc=sys-net,dc=it" } }
+ *
+ *
+ * 3. Security considerations
+ *
+ * The control result must not disclose information the client's
+ * identity could not have accessed directly by performing the related
+ * search operations. The presence of a derefVal in the control
+ * response does not imply neither the existence of nor any access
+ * privilege to the corresponding entry. It is merely a consequence
+ * of the read access the client's identity has on the corresponding
+ * attribute's value.
+ */
+
+#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_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_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;
+ struct berval bv = BER_BVNULL;
+ int nDerefRes = 0, nDerefVals = 0, nAttrs = 0, nVals = 0;
+ struct berval ctrlval;
+ LDAPControl *ctrl, **ctrlsp;
+ AccessControlState acl_state = ACL_STATE_INIT;
+ static char dummy = '\0';
+ Entry *ebase;
+ int i;
+
+ rc = overlay_entry_get_ov( op, &rs->sr_entry->e_nname, NULL, NULL, 0, &ebase, dc->dc_on );
+ if ( rc != LDAP_SUCCESS || ebase == NULL ) {
+ return SLAP_CB_CONTINUE;
+ }
+
+ for ( ds = dc->dc_ds; ds; ds = ds->ds_next ) {
+ Attribute *a = attr_find( ebase->e_attrs, ds->ds_derefAttr );
+
+ if ( a != NULL ) {
+ DerefVal *dv;
+ BerVarray *bva;
+
+ if ( !access_allowed( op, rs->sr_entry, a->a_desc,
+ NULL, ACL_READ, &acl_state ) )
+ {
+ continue;
+ }
+
+ 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;
+
+
+ if ( !access_allowed( op, rs->sr_entry, a->a_desc,
+ &a->a_nvals[ i ], ACL_READ, &acl_state ) )
+ {
+ dv[ i ].dv_derefSpecVal.bv_val = &dummy;
+ continue;
+ }
+
+ ber_dupbv_x( &dv[ i ].dv_derefSpecVal, &a->a_vals[ i ], op->o_tmpmemctx );
+ 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;
+
+ if ( access_allowed( op, e, slap_schema.si_ad_entry,
+ NULL, ACL_READ, NULL ) )
+ {
+ for ( j = 0; j < ds->ds_nattrs; j++ ) {
+ Attribute *aa;
+
+ if ( !access_allowed( op, e, ds->ds_attributes[ j ], NULL,
+ ACL_READ, &acl_state ) )
+ {
+ continue;
+ }
+
+ aa = attr_find( e->e_attrs, ds->ds_attributes[ j ] );
+ if ( aa != NULL ) {
+ unsigned k, h, last = aa->a_numvals;
+
+ ber_bvarray_dup_x( &dv[ i ].dv_attrVals[ j ],
+ aa->a_vals, op->o_tmpmemctx );
+
+ bv.bv_len += ds->ds_attributes[ j ]->ad_cname.bv_len;
+
+ for ( k = 0, h = 0; k < aa->a_numvals; k++ ) {
+ if ( !access_allowed( op, e,
+ aa->a_desc,
+ &aa->a_nvals[ k ],
+ ACL_READ, &acl_state ) )
+ {
+ op->o_tmpfree( dv[ i ].dv_attrVals[ j ][ h ].bv_val,
+ op->o_tmpmemctx );
+ dv[ i ].dv_attrVals[ j ][ h ] = dv[ i ].dv_attrVals[ j ][ --last ];
+ BER_BVZERO( &dv[ i ].dv_attrVals[ j ][ last ] );
+ continue;
+ }
+ bv.bv_len += dv[ i ].dv_attrVals[ j ][ h ].bv_len;
+ nVals++;
+ h++;
+ }
+ nAttrs++;
+ }
+ }
+ }
+
+ overlay_entry_release_ov( op, e, 0, dc->dc_on );
+ }
+ }
+
+ *drp = dr;
+ drp = &dr->dr_next;
+ }
+ }
+ overlay_entry_release_ov( op, ebase, 0, dc->dc_on );
+
+ 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 );
+
+ 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, first = 1;
+
+ if ( dr->dr_vals[ i ].dv_derefSpecVal.bv_val == &dummy ) {
+ continue;
+ }
+
+ rc = ber_printf( ber, "{OO" /*}*/,
+ &dr->dr_spec.ds_derefAttr->ad_cname,
+ &dr->dr_vals[ i ].dv_derefSpecVal );
+ op->o_tmpfree( dr->dr_vals[ i ].dv_derefSpecVal.bv_val, op->o_tmpmemctx );
+ for ( j = 0; j < dr->dr_spec.ds_nattrs; j++ ) {
+ if ( dr->dr_vals[ i ].dv_attrVals[ j ] != NULL ) {
+ if ( first ) {
+ rc = ber_printf( ber, "t{" /*}*/,
+ (LBER_CONSTRUCTED|LBER_CLASS_CONTEXT) );
+ first = 0;
+ }
+ rc = ber_printf( ber, "{O[W]}",
+ &dr->dr_spec.ds_attributes[ j ]->ad_cname,
+ dr->dr_vals[ i ].dv_attrVals[ j ] );
+ op->o_tmpfree( dr->dr_vals[ i ].dv_attrVals[ j ],
+ op->o_tmpmemctx );
+ }
+ }
+ if ( !first ) {
+ rc = ber_printf( ber, /*{{*/ "}N}" );
+ } else {
+ rc = ber_printf( ber, /*{*/ "}" );
+ }
+ }
+ }
+ 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;
+ }
+
+ } else if ( rs->sr_type == REP_RESULT ) {
+ rc = deref_cleanup( op, rs );
+ }
+
+ return rc;
+}
+
+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(void)
+{
+ 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 -1;
+ }
+
+ 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 */