.B overlay
directive.
.TP
-.B dynlist\-attrset <group-oc> [<URI>] <URL-ad> [[<mapped-ad>:]<member-ad>[+<memberOf-ad] ...]
+.B dynlist\-attrset <group-oc> [<URI>] <URL-ad> [[<mapped-ad>:]<member-ad>[+<memberOf-ad[@<static-oc>[*]] ...]
The value
.B group\-oc
is the name of the objectClass that triggers the dynamic expansion of the
.B memberOf-ad
attribute is also specified, then it will be populated with the DNs of the
dynamic groups that an entry is a member of.
+If the optional
+.B static-oc
+objectClass is also specified, then the memberOf attribute will also be
+populated with the DNs of the static groups that an entry is a member of.
+If the optional
+.B *
+character is also specified, then the member and memberOf values will be
+populated recursively, for nested groups. Note that currently nesting is
+only supported for Search operations, not Compares.
Alternatively,
.B mapped-ad
AttributeDescription *dlm_memberOf_ad;
ObjectClass *dlm_static_oc;
int dlm_memberOf_nested;
+ int dlm_member_oper;
+ int dlm_memberOf_oper;
struct dynlist_map_t *dlm_next;
} dynlist_map_t;
dynlist_info_t *dlg_dli;
int dlg_memberOf;
} dynlist_gen_t;
-#define DYNLIST_HAS_MEMBEROF 1
#define DYNLIST_USAGE \
"\"dynlist-attrset <oc> [uri] <URL-ad> [[<mapped-ad>:]<member-ad>[+<memberOf-ad>[@<static-oc>[*]] ...]\": "
static int
dynlist_make_filter( Operation *op, Entry *e, dynlist_info_t *dli, const char *url, struct berval *oldf, struct berval *newf )
{
- slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
-
char *ptr;
int needBrackets = 0;
return 0;
}
-
+
+typedef struct dynlist_name_t {
+ struct berval dy_name;
+ dynlist_info_t *dy_dli;
+ AttributeDescription *dy_staticmember;
+ int dy_seen;
+ int dy_numuris;
+ TAvlnode *dy_subs;
+ TAvlnode *dy_sups;
+ LDAPURLDesc *dy_uris[];
+} dynlist_name_t;
+
+static void
+dynlist_urlmembers( Operation *op, dynlist_name_t *dyn, slap_callback *sc )
+{
+ Operation o = *op;
+ LDAPURLDesc *ludp;
+ int i;
+
+ o.ors_deref = LDAP_DEREF_NEVER;
+ o.ors_limit = NULL;
+ o.ors_tlimit = SLAP_NO_LIMIT;
+ o.ors_slimit = SLAP_NO_LIMIT;
+ o.ors_attrs = NULL;
+ o.o_callback = sc;
+
+ for (i=0; i<dyn->dy_numuris; i++) {
+ ludp = dyn->dy_uris[i];
+ if ( ludp->lud_attrs )
+ continue;
+ o.o_req_dn.bv_val = ludp->lud_dn;
+ o.o_req_dn.bv_len = ludp->lud_port;
+ o.o_req_ndn = o.o_req_dn;
+ o.ors_scope = ludp->lud_scope;
+ o.ors_filter = (Filter *)ludp->lud_filter;
+ filter2bv_x( op, o.ors_filter, &o.ors_filterstr );
+ o.o_bd = select_backend( &o.o_req_ndn, 1 );
+ if ( o.o_bd && o.o_bd->be_search ) {
+ SlapReply r = { REP_SEARCH };
+ r.sr_attr_flags = slap_attr_flags( o.ors_attrs );
+ o.o_managedsait = SLAP_CONTROL_CRITICAL;
+ (void)o.o_bd->be_search( &o, &r );
+ }
+ op->o_tmpfree( o.ors_filterstr.bv_val, op->o_tmpmemctx );
+ }
+}
+
+static void
+dynlist_nested_memberOf( Entry *e, AttributeDescription *ad, TAvlnode *sups )
+{
+ TAvlnode *ptr;
+ dynlist_name_t *dyn;
+ Attribute *a;
+
+ a = attr_find( e->e_attrs, ad );
+ for ( ptr = tavl_end( sups, TAVL_DIR_LEFT ); ptr;
+ ptr = tavl_next( ptr, TAVL_DIR_RIGHT )) {
+ dyn = ptr->avl_data;
+ if ( a ) {
+ unsigned slot;
+ if ( attr_valfind( a, SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX |
+ SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH |
+ SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
+ &dyn->dy_name, &slot, NULL ) == LDAP_SUCCESS )
+ continue;
+ }
+ attr_merge_one( e, ad, &dyn->dy_name, &dyn->dy_name );
+ if ( !a )
+ a = attr_find( e->e_attrs, ad );
+ if ( dyn->dy_sups )
+ dynlist_nested_memberOf( e, ad, dyn->dy_sups );
+ }
+}
+
+typedef struct dynlist_member_t {
+ Entry *dm_e;
+ AttributeDescription *dm_ad;
+ Modification dm_mod;
+ TAvlnode *dm_groups;
+ struct berval dm_bv[2];
+ struct berval dm_nbv[2];
+ const char *dm_text;
+ char dm_textbuf[1024];
+} dynlist_member_t;
+
+static int
+dynlist_ptr_cmp( const void *c1, const void *c2 )
+{
+ return ( c1 < c2 ) ? -1 : c1 > c2;
+}
+
+static int
+dynlist_nested_member_dg( Operation *op, SlapReply *rs )
+{
+ dynlist_member_t *dm = op->o_callback->sc_private;
+
+ if ( rs->sr_type != REP_SEARCH )
+ return LDAP_SUCCESS;
+
+ dm->dm_bv[0] = rs->sr_entry->e_name;
+ dm->dm_nbv[0] = rs->sr_entry->e_nname;
+ modify_add_values( dm->dm_e, &dm->dm_mod, /* permissive */ 1,
+ &dm->dm_text, dm->dm_textbuf, sizeof( dm->dm_textbuf ));
+
+ return LDAP_SUCCESS;
+}
+
+static void
+dynlist_nested_member( Operation *op, dynlist_member_t *dm, TAvlnode *subs )
+{
+ slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
+ TAvlnode *ptr;
+ dynlist_name_t *dyn;
+ Entry *ne;
+ Attribute *a, *b;
+
+ a = attr_find( dm->dm_e->e_attrs, dm->dm_ad );
+ if ( !a )
+ return;
+
+ for ( ptr = tavl_end( subs, TAVL_DIR_LEFT ); ptr;
+ ptr = tavl_next( ptr, TAVL_DIR_RIGHT )) {
+ dyn = ptr->avl_data;
+ if ( tavl_insert( &dm->dm_groups, dyn, dynlist_ptr_cmp, avl_dup_error ))
+ continue;
+ if ( overlay_entry_get_ov( op, &dyn->dy_name, NULL, NULL, 0, &ne, on ) != LDAP_SUCCESS || ne == NULL )
+ continue;
+ b = attr_find( ne->e_attrs, dm->dm_ad );
+ if ( b ) {
+ dm->dm_mod.sm_values = b->a_vals;
+ dm->dm_mod.sm_nvalues = b->a_nvals;
+ dm->dm_mod.sm_numvals = b->a_numvals;
+ modify_add_values( dm->dm_e, &dm->dm_mod, /* permissive */ 1,
+ &dm->dm_text, dm->dm_textbuf, sizeof( dm->dm_textbuf ));
+ }
+ overlay_entry_release_ov( op, ne, 0, on );
+ if ( dyn->dy_numuris ) {
+ slap_callback cb = { 0 };
+ cb.sc_private = dm;
+ BER_BVZERO( &dm->dm_bv[1] );
+ BER_BVZERO( &dm->dm_nbv[1] );
+ dm->dm_mod.sm_values = dm->dm_bv;
+ dm->dm_mod.sm_nvalues = dm->dm_nbv;
+ dm->dm_mod.sm_numvals = 1;
+ cb.sc_response = dynlist_nested_member_dg;
+ dynlist_urlmembers( op, dyn, &cb );
+ }
+ if ( dyn->dy_subs )
+ dynlist_nested_member( op, dm, dyn->dy_subs );
+ }
+}
+
static int
-dynlist_prepare_entry( Operation *op, SlapReply *rs, dynlist_info_t *dli )
+dynlist_prepare_entry( Operation *op, SlapReply *rs, dynlist_info_t *dli, dynlist_name_t *dyn )
{
Attribute *a, *id = NULL;
slap_callback cb = { 0 };
dynlist_sc_t dlc = { 0 };
dynlist_map_t *dlm;
+ e = rs->sr_entry;
a = attrs_find( rs->sr_entry->e_attrs, dli->dli_ad );
if ( a == NULL ) {
/* FIXME: error? */
- return SLAP_CB_CONTINUE;
+ goto checkdyn;
}
opattrs = SLAP_OPATTRS( rs->sr_attr_flags );
break;
}
if ( dli->dli_dlm && !dlm )
- return SLAP_CB_CONTINUE;
+ goto checkdyn;
if ( ad_dgIdentity && ( id = attrs_find( rs->sr_entry->e_attrs, ad_dgIdentity ))) {
Attribute *authz = NULL;
if ( slap_sasl_matches( op, authz->a_nvals,
&o.o_ndn, &o.o_ndn ) != LDAP_SUCCESS )
{
- return SLAP_CB_CONTINUE;
+ goto checkdyn;
}
}
o.o_groups = NULL;
}
- e = rs->sr_entry;
/* ensure e is modifiable, but do not replace
* sr_entry yet since we have pointers into it */
if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
&dli->dli_default_filter, op->o_tmpmemctx );
} else {
- struct berval flt;
- ber_str2bv( lud->lud_filter, 0, 0, &flt );
- if ( dynlist_make_filter( op, rs->sr_entry, dli, url->bv_val, &flt, &o.ors_filterstr ) ) {
- /* error */
- goto cleanup;
+ /* don't allow recursion in lists */
+ if ( lud->lud_attrs ) {
+ struct berval flt;
+ ber_str2bv( lud->lud_filter, 0, 0, &flt );
+ if ( dynlist_make_filter( op, rs->sr_entry, dli, url->bv_val, &flt, &o.ors_filterstr ) ) {
+ /* error */
+ goto cleanup;
+ }
+ } else {
+ ber_str2bv( lud->lud_filter, 0, 0, &o.ors_filterstr );
}
}
o.ors_filter = str2filter_x( op, o.ors_filterstr.bv_val );
if ( !BER_BVISNULL( &o.o_req_ndn ) ) {
op->o_tmpfree( o.o_req_ndn.bv_val, op->o_tmpmemctx );
}
- assert( BER_BVISNULL( &o.ors_filterstr )
- || o.ors_filterstr.bv_val != lud->lud_filter );
- op->o_tmpfree( o.ors_filterstr.bv_val, op->o_tmpmemctx );
+ if ( lud->lud_attrs ) {
+ assert( BER_BVISNULL( &o.ors_filterstr )
+ || o.ors_filterstr.bv_val != lud->lud_filter );
+ op->o_tmpfree( o.ors_filterstr.bv_val, op->o_tmpmemctx );
+ } else {
+ if ( o.ors_filterstr.bv_val != lud->lud_filter )
+ op->o_tmpfree( o.ors_filterstr.bv_val, op->o_tmpmemctx );
+ }
ldap_free_urldesc( lud );
}
+checkdyn:
+ /* handle nested groups */
+ if ( dyn && ( dyn->dy_sups || dyn->dy_subs )) {
+ /* ensure e is modifiable */
+ if ( e == rs->sr_entry && !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
+ e = entry_dup( rs->sr_entry );
+ rs_replace_entry( op, rs, (slap_overinst *)op->o_bd->bd_info, e );
+ rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
+ }
+ if ( dyn->dy_subs ) {
+ for ( dlm = dyn->dy_dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
+ if ( dlm->dlm_member_ad ) {
+ dynlist_member_t dm;
+ dm.dm_groups = NULL;
+ dm.dm_mod.sm_op = LDAP_MOD_ADD;
+ dm.dm_mod.sm_desc = dlm->dlm_member_ad;
+ dm.dm_mod.sm_type = dlm->dlm_member_ad->ad_cname;
+ dm.dm_e = e;
+ dm.dm_ad = dlm->dlm_member_ad;
+ dynlist_nested_member( op, &dm, dyn->dy_subs );
+ if ( dm.dm_groups )
+ tavl_free( dm.dm_groups, NULL );
+ }
+ }
+ }
+ if ( dyn->dy_sups ) {
+ for ( dlm = dyn->dy_dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
+ if ( dlm->dlm_memberOf_ad ) {
+ dynlist_nested_memberOf( e, dlm->dlm_memberOf_ad, dyn->dy_sups );
+ }
+ }
+ }
+ }
+
if ( e != rs->sr_entry ) {
rs_replace_entry( op, rs, (slap_overinst *)op->o_bd->bd_info, e );
rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
r.sr_attrs = an;
o.o_acl_priv = ACL_COMPARE;
- dynlist_prepare_entry( &o, &r, dli );
+ dynlist_prepare_entry( &o, &r, dli, NULL );
a = attrs_find( r.sr_entry->e_attrs, op->orc_ava->aa_desc );
ret = LDAP_NO_SUCH_ATTRIBUTE;
return ret;
}
-typedef struct dynlist_name_t {
- struct berval dy_name;
- dynlist_info_t *dy_dli;
- AttributeDescription *dy_staticmember;
- int dy_seen;
- int dy_numuris;
- LDAPURLDesc *dy_uris[];
-} dynlist_name_t;
+#define WANT_MEMBEROF 1
+#define WANT_MEMBER 2
typedef struct dynlist_search_t {
TAvlnode *ds_names;
+ TAvlnode *ds_fnodes;
dynlist_info_t *ds_dli;
dynlist_map_t *ds_dlm;
Filter *ds_origfilter;
struct berval ds_origfilterbv;
- int ds_memberOf;
+ int ds_want;
+ int ds_found;
} dynlist_search_t;
static int
ldap_free_urldesc( ludp );
}
ch_free( dyn );
+ } else {
+ ds->ds_found++;
}
}
}
* using (&(entryDN=<groupURIbase>)<groupURIfilter>)
*/
static int
-dynlist_filter_dyngroup( Operation *op, Filter *f, Filter *n, Attribute *a )
+dynlist_filter_dyngroup( Operation *op, Filter *n, Attribute *a )
{
Filter *andf = NULL, *dnf, *urif, *orf = NULL;
LDAPURLDesc *ludp;
} else {
urif = NULL;
}
- if ( !andf ) {
+ if ( !andf && n->f_choice == SLAPD_FILTER_COMPUTED ) {
andf = n;
+ andf->f_next = NULL;
} else {
- if ( !orf ) {
+ orf = n;
+ if ( n->f_choice != LDAP_FILTER_OR ) {
andf = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
- andf->f_choice = n->f_choice;
- andf->f_list = n->f_list;
- orf = n;
+ *andf = *n;
orf->f_choice = LDAP_FILTER_OR;
+ orf->f_next = NULL;
orf->f_list = andf;
}
- andf->f_next = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
- andf = andf->f_next;
+ andf = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
+ andf->f_next = orf->f_list;
+ orf->f_list = andf;
}
dnf = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
andf->f_choice = LDAP_FILTER_AND;
- andf->f_next = NULL;
andf->f_list = dnf;
dnf->f_next = urif;
if ( ludp->lud_scope == LDAP_SCOPE_BASE ) {
* using (|(entryDN=<memberN>)[...])
*/
static int
-dynlist_filter_stgroup( Operation *op, Filter *f, Filter *n, Attribute *a )
+dynlist_filter_stgroup( Operation *op, Filter *n, Attribute *a )
{
- Filter *dnf, *orf;
+ Filter *dnf, *orf = NULL;
int i;
- if ( a->a_numvals == 1 ) {
+ if ( a->a_numvals == 1 && n->f_choice == SLAPD_FILTER_COMPUTED ) {
dnf = n;
+ dnf->f_next = NULL;
} else {
orf = n;
- orf->f_choice = LDAP_FILTER_OR;
- orf->f_next = NULL;
+ if ( n->f_choice != LDAP_FILTER_OR ) {
+ dnf = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
+ *dnf = *n;
+ orf->f_choice = LDAP_FILTER_OR;
+ orf->f_next = NULL;
+ orf->f_list = dnf;
+ }
dnf = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
+ dnf->f_next = orf->f_list;
orf->f_list = dnf;
}
for (i=0; i<a->a_numvals; i++) {
- if ( i > 1 ) {
- dnf->f_next = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
- dnf = dnf->f_next;
+ if ( i ) {
+ dnf = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx );
+ dnf->f_next = orf->f_list;
+ orf->f_list = dnf;
}
dnf->f_choice = LDAP_FILTER_EQUALITY;
dnf->f_ava = op->o_tmpcalloc( 1, sizeof(AttributeAssertion), op->o_tmpmemctx );
dnf->f_av_desc = slap_schema.si_ad_entryDN;
ber_dupbv_x( &dnf->f_av_value, &a->a_nvals[i], op->o_tmpmemctx );
}
- dnf->f_next = NULL;
return 0;
}
* its members.
*/
static int
-dynlist_filter_group( Operation *op, Filter *f, Filter *n, dynlist_search_t *ds )
+dynlist_filter_group( Operation *op, dynlist_name_t *dyn, Filter *n, dynlist_search_t *ds )
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
Entry *e;
Attribute *a;
int rc = -1;
- if ( overlay_entry_get_ov( op, &f->f_av_value, NULL, NULL, 0, &e, on ) !=
+ if ( tavl_insert( &ds->ds_fnodes, dyn, dynlist_ptr_cmp, avl_dup_error ))
+ return 0;
+
+ if ( overlay_entry_get_ov( op, &dyn->dy_name, NULL, NULL, 0, &e, on ) !=
LDAP_SUCCESS || e == NULL ) {
return -1;
}
if ( ds->ds_dlm->dlm_static_oc && is_entry_objectclass( e, ds->ds_dlm->dlm_static_oc, 0 )) {
a = attr_find( e->e_attrs, ds->ds_dlm->dlm_member_ad );
if ( a ) {
- rc = dynlist_filter_stgroup( op, f, n, a );
+ rc = dynlist_filter_stgroup( op, n, a );
}
} else {
a = attr_find( e->e_attrs, ds->ds_dli->dli_ad );
if ( a ) {
- rc = dynlist_filter_dyngroup( op, f, n, a );
+ rc = dynlist_filter_dyngroup( op, n, a );
}
}
overlay_entry_release_ov( op, e, 0, on );
+ if ( dyn->dy_subs && !rc ) {
+ TAvlnode *ptr;
+ for ( ptr = tavl_end( dyn->dy_subs, TAVL_DIR_LEFT ); ptr;
+ ptr = tavl_next( ptr, TAVL_DIR_RIGHT )) {
+ dyn = ptr->avl_data;
+ rc = dynlist_filter_group( op, dyn, n, ds );
+ if ( rc )
+ break;
+ }
+ }
return rc;
}
break;
case LDAP_FILTER_EQUALITY:
- if ( f->f_av_desc == ad && !dynlist_filter_group( op, f, n, ds ))
- break;
+ n->f_choice = SLAPD_FILTER_COMPUTED;
+ if ( f->f_av_desc == ad ) {
+ dynlist_name_t *dyn = tavl_find( ds->ds_names, &f->f_av_value, dynlist_avl_cmp );
+ if ( dyn && !dynlist_filter_group( op, dyn, n, ds ))
+ break;
+ }
/* FALLTHRU */
case LDAP_FILTER_GE:
case LDAP_FILTER_LE:
}
ldap_free_urldesc( ludp );
}
+ if ( dyn->dy_subs )
+ tavl_free( dyn->dy_subs, NULL );
+ if ( dyn->dy_sups )
+ tavl_free( dyn->dy_sups, NULL );
ch_free( ptr );
}
slap_callback *sc = op->o_callback;
dynlist_search_t *ds = op->o_callback->sc_private;
tavl_free( ds->ds_names, dynlist_search_free );
+ if ( ds->ds_fnodes )
+ tavl_free( ds->ds_fnodes, NULL );
if ( ds->ds_origfilter ) {
op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
dynlist_filter_free( op, op->ors_filter );
}
static int
-dynlist_testurl(Operation *op, dynlist_name_t *dyn, Entry *e)
+dynlist_test_membership(Operation *op, dynlist_name_t *dyn, Entry *e)
{
LDAPURLDesc *ludp;
struct berval nbase, bv;
return rc;
}
+static void
+dynlist_add_memberOf(Operation *op, SlapReply *rs, dynlist_search_t *ds)
+{
+ TAvlnode *ptr;
+ Entry *e = rs->sr_entry;
+ dynlist_name_t *dyn;
+ Attribute *a;
+
+ /* See if there are any memberOf values to attach to this entry */
+ for ( ptr = tavl_end( ds->ds_names, TAVL_DIR_LEFT ); ptr;
+ ptr = tavl_next( ptr, TAVL_DIR_RIGHT )) {
+ dynlist_map_t *dlm;
+ dyn = ptr->avl_data;
+ for ( dlm = dyn->dy_dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
+ if ( dlm->dlm_memberOf_ad ) {
+ if ( dynlist_test_membership( op, dyn, e ) == LDAP_COMPARE_TRUE ) {
+ /* ensure e is modifiable, but do not replace
+ * sr_entry yet since we have pointers into it */
+ if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) && e == rs->sr_entry ) {
+ e = entry_dup( rs->sr_entry );
+ }
+ a = attr_find( e->e_attrs, dlm->dlm_memberOf_ad );
+ if ( a ) {
+ unsigned slot;
+ if ( attr_valfind( a, SLAP_MR_EQUALITY | SLAP_MR_VALUE_OF_ASSERTION_SYNTAX |
+ SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH |
+ SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
+ &dyn->dy_name, &slot, NULL ) != LDAP_SUCCESS )
+ a = NULL;
+ }
+ if ( !a )
+ attr_merge_one( e, dlm->dlm_memberOf_ad, &dyn->dy_name, &dyn->dy_name );
+ if ( dyn->dy_sups ) {
+ dynlist_nested_memberOf( e, dlm->dlm_memberOf_ad, dyn->dy_sups );
+ }
+ break;
+ }
+ }
+ }
+ }
+ if ( e != rs->sr_entry ) {
+ rs_replace_entry( op, rs, (slap_overinst *)op->o_bd->bd_info, e );
+ rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
+ }
+}
+
/* process the search responses */
static int
dynlist_search2resp( Operation *op, SlapReply *rs )
int rc;
if ( rs->sr_type == REP_SEARCH && rs->sr_entry != NULL ) {
+ rc = SLAP_CB_CONTINUE;
/* See if this is one of our dynamic entries */
dyn = tavl_find( ds->ds_names, &rs->sr_entry->e_nname, dynlist_avl_cmp );
if ( dyn ) {
- Entry *e = rs->sr_entry;
dyn->dy_seen = 1;
- rc = dynlist_prepare_entry( op, rs, dyn->dy_dli );
- if ( ds->ds_origfilter && test_filter( op, rs->sr_entry, ds->ds_origfilter ) != LDAP_COMPARE_TRUE ) {
- if ( e != rs->sr_entry )
- rs_flush_entry( op, rs, NULL );
- rc = LDAP_SUCCESS;
- }
- return rc;
- } else if ( ds->ds_memberOf ) {
- TAvlnode *ptr;
- Entry *e = rs->sr_entry;
- /* See if there are any memberOf values to attach to this entry */
- for ( ptr = tavl_end( ds->ds_names, TAVL_DIR_LEFT ); ptr;
- ptr = tavl_next( ptr, TAVL_DIR_RIGHT )) {
- dynlist_map_t *dlm;
- dyn = ptr->avl_data;
- for ( dlm = dyn->dy_dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
- if ( dlm->dlm_memberOf_ad ) {
- if ( dynlist_testurl( op, dyn, e ) == LDAP_COMPARE_TRUE ) {
- /* ensure e is modifiable, but do not replace
- * sr_entry yet since we have pointers into it */
- if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) && e == rs->sr_entry ) {
- e = entry_dup( rs->sr_entry );
- }
- attr_merge_one( e, dlm->dlm_memberOf_ad, &dyn->dy_name, &dyn->dy_name );
- break;
- }
- }
- }
- }
- if ( e != rs->sr_entry ) {
- rs_replace_entry( op, rs, (slap_overinst *)op->o_bd->bd_info, e );
- rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
- }
- if ( ds->ds_origfilter && test_filter( op, rs->sr_entry, ds->ds_origfilter ) != LDAP_COMPARE_TRUE ) {
- rs_flush_entry( op, rs, NULL );
- return LDAP_SUCCESS;
- }
+ rc = dynlist_prepare_entry( op, rs, dyn->dy_dli, dyn );
+ } else if ( ds->ds_want )
+ dynlist_add_memberOf( op, rs, ds );
+ if ( ds->ds_origfilter && test_filter( op, rs->sr_entry, ds->ds_origfilter ) != LDAP_COMPARE_TRUE ) {
+ rs_flush_entry( op, rs, NULL );
+ return LDAP_SUCCESS;
}
+ return rc;
} else if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS ) {
TAvlnode *ptr;
SlapReply r = *rs;
+ Filter *f = ds->ds_origfilter ? ds->ds_origfilter : op->ors_filter;
+
/* Check for any unexpanded dynamic group entries that weren't picked up
* by the original search filter.
*/
r.sr_entry == NULL )
continue;
r.sr_flags = REP_ENTRY_MUSTRELEASE;
- dynlist_prepare_entry( op, &r, dyn->dy_dli );
- if ( test_filter( op, r.sr_entry, op->ors_filter ) == LDAP_COMPARE_TRUE ) {
+ dynlist_prepare_entry( op, &r, dyn->dy_dli, dyn );
+ if ( test_filter( op, r.sr_entry, f ) == LDAP_COMPARE_TRUE ) {
r.sr_attrs = op->ors_attrs;
rs->sr_err = send_search_entry( op, &r );
if ( rs->sr_err != LDAP_SUCCESS )
filter2bv_x( op, f, &op->ors_filterstr );
}
+typedef struct dynlist_link_t {
+ dynlist_search_t *dl_ds;
+ dynlist_name_t *dl_sup;
+} dynlist_link_t;
+
+static int
+dynlist_nestlink_dg( Operation *op, SlapReply *rs )
+{
+ dynlist_link_t *dll = op->o_callback->sc_private;
+ dynlist_search_t *ds = dll->dl_ds;
+ dynlist_name_t *di = dll->dl_sup, *dj;
+
+ if ( rs->sr_type != REP_SEARCH )
+ return LDAP_SUCCESS;
+
+ dj = tavl_find( dll->dl_ds->ds_names, &rs->sr_entry->e_nname, dynlist_avl_cmp );
+ if ( dj ) {
+ if ( ds->ds_want & WANT_MEMBEROF ) {
+ tavl_insert( &dj->dy_sups, di, dynlist_ptr_cmp, avl_dup_error );
+ }
+ if ( ds->ds_want & WANT_MEMBER ) {
+ tavl_insert( &di->dy_subs, dj, dynlist_ptr_cmp, avl_dup_error );
+ }
+ }
+ return LDAP_SUCCESS;
+}
+
+/* Connect all nested groups to their parents/children */
+static void
+dynlist_nestlink( Operation *op, dynlist_search_t *ds )
+{
+ slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
+ dynlist_name_t *di, *dj;
+ TAvlnode *ptr;
+ Entry *e;
+ Attribute *a;
+ int i;
+
+ for ( ptr = tavl_end( ds->ds_names, TAVL_DIR_LEFT ); ptr;
+ ptr = tavl_next( ptr, TAVL_DIR_RIGHT )) {
+ di = ptr->avl_data;
+ if ( ds->ds_dlm ) {
+ if ( overlay_entry_get_ov( op, &di->dy_name, NULL, NULL, 0, &e, on ) != LDAP_SUCCESS || e == NULL )
+ continue;
+ a = attr_find( e->e_attrs, ds->ds_dlm->dlm_member_ad );
+ if ( a ) {
+ for ( i=0; i < a->a_numvals; i++ ) {
+ dj = tavl_find( ds->ds_names, &a->a_nvals[i], dynlist_avl_cmp );
+ if ( dj ) {
+ if ( ds->ds_want & WANT_MEMBEROF ) {
+ tavl_insert( &dj->dy_sups, di, dynlist_ptr_cmp, avl_dup_error );
+ }
+ if ( ds->ds_want & WANT_MEMBER ) {
+ tavl_insert( &di->dy_subs, dj, dynlist_ptr_cmp, avl_dup_error );
+ }
+ }
+ }
+ }
+ overlay_entry_release_ov( op, e, 0, on );
+ }
+
+ if ( di->dy_numuris ) {
+ slap_callback cb = { 0 };
+ dynlist_link_t dll;
+ dll.dl_ds = ds;
+ dll.dl_sup = di;
+ cb.sc_private = &dll;
+ cb.sc_response = dynlist_nestlink_dg;
+ dynlist_urlmembers( op, di, &cb );
+ }
+ }
+}
+
static int
dynlist_search( Operation *op, SlapReply *rs )
{
slap_callback *sc;
dynlist_search_t *ds;
- ObjectClass *static_oc = NULL;
+ ObjectClass *static_oc;
+ int nested, found, tmpwant;
+ int opattrs, userattrs;
if ( get_manageDSAit( op ) )
return SLAP_CB_CONTINUE;
sc = op->o_tmpcalloc( 1, sizeof(slap_callback)+sizeof(dynlist_search_t), op->o_tmpmemctx );
sc->sc_private = (void *)(sc+1);
ds = sc->sc_private;
- ds->ds_memberOf = 0;
o.o_managedsait = SLAP_CONTROL_CRITICAL;
/* Are we using memberOf, and does it affect this request? */
if ( dlg->dlg_memberOf ) {
int attrflags = slap_attr_flags( op->ors_attrs );
- int opattrs = SLAP_OPATTRS( attrflags );
- int userattrs = SLAP_USERATTRS( attrflags );
+ opattrs = SLAP_OPATTRS( attrflags );
+ userattrs = SLAP_USERATTRS( attrflags );
+ }
- for ( dli = dlg->dlg_dli; dli; dli = dli->dli_next ) {
+ /* Find all groups in scope. For group expansion
+ * we only need the groups within the search scope, but
+ * for memberOf populating, we need all dyngroups.
+ */
+ for ( dli = dlg->dlg_dli; dli; dli = dli->dli_next ) {
+ static_oc = NULL;
+ nested = 0;
+ tmpwant = 0;
+ if ( dlg->dlg_memberOf ) {
for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
if ( dlm->dlm_memberOf_ad ) {
- /* if attribute is in filter, fix it */
- if ( ad_infilter( dlm->dlm_memberOf_ad, op->ors_filter )) {
- ds->ds_dli = dli;
- ds->ds_dlm = dlm;
- dynlist_fix_filter( op, dlm->dlm_memberOf_ad, ds );
+ int want = 0;
+
+ /* with nesting, filter attributes also require nestlink */
+ if ( dlm->dlm_memberOf_nested ) {
+ /* WANT_ flags have inverted meaning here:
+ * to satisfy (memberOf=) filter, we need to also
+ * find all subordinate groups. No special
+ * treatment is needed for (member=) since we
+ * already search all group entries.
+ */
+ if ( ad_infilter( dlm->dlm_memberOf_ad, op->ors_filter ))
+ want |= WANT_MEMBER;
}
/* if attribute is not requested, skip it */
if ( op->ors_attrs == NULL ) {
- if ( is_at_operational( dlm->dlm_memberOf_ad->ad_type ) ) {
- continue;
- }
+ if ( !dlm->dlm_memberOf_oper )
+ want |= WANT_MEMBEROF;
+ if ( dlm->dlm_memberOf_nested && !dlm->dlm_member_oper )
+ want |= WANT_MEMBER;
} else {
- if ( is_at_operational( dlm->dlm_memberOf_ad->ad_type ) ) {
- if ( !opattrs && !ad_inlist( dlm->dlm_memberOf_ad, op->ors_attrs ) )
- {
- continue;
- }
+ if ( ad_inlist( dlm->dlm_memberOf_ad, op->ors_attrs ))
+ want |= WANT_MEMBEROF;
+ if ( dlm->dlm_memberOf_nested && ad_inlist( dlm->dlm_member_ad, op->ors_attrs )) {
+ want |= WANT_MEMBER;
} else {
- if ( !userattrs && !ad_inlist( dlm->dlm_memberOf_ad, op->ors_attrs ) )
- {
- continue;
+ if ( opattrs ) {
+ if ( dlm->dlm_memberOf_oper )
+ want |= WANT_MEMBEROF;
+ if ( dlm->dlm_memberOf_nested && dlm->dlm_member_oper )
+ want |= WANT_MEMBER;
+ }
+ if ( userattrs ) {
+ if ( !dlm->dlm_memberOf_oper )
+ want |= WANT_MEMBEROF;
+ if ( dlm->dlm_memberOf_nested && !dlm->dlm_member_oper )
+ want |= WANT_MEMBER;
}
}
}
- ds->ds_memberOf = 1;
- if ( dlm->dlm_static_oc ) {
- static_oc = dlm->dlm_static_oc;
- ds->ds_dlm = dlm;
+ if ( want ) {
+ nested = dlm->dlm_memberOf_nested;
+ ds->ds_want = tmpwant = want;
+ if ( dlm->dlm_static_oc ) {
+ static_oc = dlm->dlm_static_oc;
+ ds->ds_dlm = dlm;
+ }
}
}
}
}
- }
- if ( static_oc ) {
- f[0].f_choice = LDAP_FILTER_OR;
- f[0].f_list = &f[1];
- f[0].f_next = NULL;
- f[1].f_choice = LDAP_FILTER_EQUALITY;
- f[1].f_ava = &ava[0];
- f[1].f_av_desc = slap_schema.si_ad_objectClass;
- f[1].f_next = &f[2];
- f[2].f_choice = LDAP_FILTER_EQUALITY;
- f[2].f_ava = &ava[1];
- f[2].f_av_desc = slap_schema.si_ad_objectClass;
- f[2].f_next = NULL;
- } else {
- f[0].f_choice = LDAP_FILTER_EQUALITY;
- f[0].f_ava = ava;
- f[0].f_av_desc = slap_schema.si_ad_objectClass;
- f[0].f_next = NULL;
- }
+ if ( static_oc ) {
+ f[0].f_choice = LDAP_FILTER_OR;
+ f[0].f_list = &f[1];
+ f[0].f_next = NULL;
+ f[1].f_choice = LDAP_FILTER_EQUALITY;
+ f[1].f_next = &f[2];
+ f[1].f_ava = &ava[0];
+ f[1].f_av_desc = slap_schema.si_ad_objectClass;
+ f[1].f_av_value = dli->dli_oc->soc_cname;
+ f[2].f_choice = LDAP_FILTER_EQUALITY;
+ f[2].f_ava = &ava[1];
+ f[2].f_av_desc = slap_schema.si_ad_objectClass;
+ f[2].f_av_value = static_oc->soc_cname;
+ f[2].f_next = NULL;
+ } else {
+ f[0].f_choice = LDAP_FILTER_EQUALITY;
+ f[0].f_ava = ava;
+ f[0].f_av_desc = slap_schema.si_ad_objectClass;
+ f[0].f_av_value = dli->dli_oc->soc_cname;
+ f[0].f_next = NULL;
+ }
- /* Find all groups in scope. For group expansion
- * we only need the groups within the search scope, but
- * for memberOf populating, we need all dyngroups.
- */
- for ( dli = dlg->dlg_dli; dli != NULL; dli = dli->dli_next ) {
if ( o.o_callback != sc ) {
o.o_callback = sc;
o.ors_filter = f;
- if ( ds->ds_memberOf ) {
+ if ( tmpwant ) {
o.o_req_dn = op->o_bd->be_suffix[0];
o.o_req_ndn = op->o_bd->be_nsuffix[0];
o.ors_scope = LDAP_SCOPE_SUBTREE;
BER_BVZERO( &o.ors_filterstr );
sc->sc_response = dynlist_search1resp;
}
+
ds->ds_dli = dli;
- if ( static_oc ) {
- f[1].f_av_value = dli->dli_oc->soc_cname;
- f[2].f_av_value = static_oc->soc_cname;
- } else {
- f[0].f_av_value = dli->dli_oc->soc_cname;
- }
if ( o.ors_filterstr.bv_val )
o.o_tmpfree( o.ors_filterstr.bv_val, o.o_tmpmemctx );
filter2bv_x( &o, f, &o.ors_filterstr );
an[0].an_desc = dli->dli_ad;
an[0].an_name = dli->dli_ad->ad_cname;
+ found = ds->ds_found;
{
SlapReply r = { REP_SEARCH };
(void)o.o_bd->be_search( &o, &r );
}
+ if ( found != ds->ds_found && nested )
+ dynlist_nestlink( op, ds );
}
if ( ds->ds_names != NULL ) {
sc->sc_cleanup = dynlist_search_cleanup;
sc->sc_next = op->o_callback;
op->o_callback = sc;
+
+ /* see if filter needs fixing */
+ if ( dlg->dlg_memberOf ) {
+ for ( dli = dlg->dlg_dli; dli; dli = dli->dli_next ) {
+ for ( dlm = dli->dli_dlm; dlm; dlm = dlm->dlm_next ) {
+ if ( dlm->dlm_memberOf_ad ) {
+
+ /* if attribute is in filter, fix it */
+ if ( ad_infilter( dlm->dlm_memberOf_ad, op->ors_filter )) {
+ ds->ds_dli = dli;
+ ds->ds_dlm = dlm;
+ dynlist_fix_filter( op, dlm->dlm_memberOf_ad, ds );
+ }
+ }
+ }
+ }
+ }
+
} else {
op->o_tmpfree( sc, op->o_tmpmemctx );
}
dlmp->dlm_memberOf_ad = memberOf_ad;
dlmp->dlm_static_oc = static_oc;
dlmp->dlm_memberOf_nested = nested;
+ dlmp->dlm_member_oper = is_at_operational( member_ad->ad_type );
+ if ( memberOf_ad ) {
+ dlmp->dlm_memberOf_oper = is_at_operational( memberOf_ad->ad_type );
+ } else {
+ dlmp->dlm_memberOf_oper = 0;
+ }
dlmp->dlm_next = NULL;
if ( dlml != NULL )
dgMemberOf: cn=alumni assoc staff,ou=groups,dc=example,dc=com
dgMemberOf: cn=dynamic list of members,ou=dynamic lists,dc=example,dc=com
+# Testing nested dynamic group functionality...
+dn: cn=Dynamic List,ou=Dynamic Lists,dc=example,dc=com
+objectClass: groupOfURLs
+cn: Dynamic List
+memberURL: ldap:///ou=People,dc=example,dc=com?cn,mail?sub?(objectClass=person
+ )
+
+dn: cn=Dynamic List of Members,ou=Dynamic Lists,dc=example,dc=com
+objectClass: groupOfURLs
+objectClass: dgIdentityAux
+cn: Dynamic List of Members
+memberURL: ldap:///ou=People,dc=example,dc=com??sub?(objectClass=person)
+dgIdentity: cn=Bjorn Jensen,ou=Information Technology DivisioN,ou=People,dc=ex
+ ample,dc=com
+dgAuthz: {0}dn:cn=Barbara Jensen,ou=Information Technology DivisioN,ou=People,
+ dc=example,dc=com
+member: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=exam
+ ple,dc=com
+member: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=exampl
+ e,dc=com
+member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=James A Jones 2,ou=Information Technology Division,ou=People,dc=exa
+ mple,dc=com
+member: cn=Jane Doe,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=John Doe,ou=Information Technology Division,ou=People,dc=example,dc
+ =com
+member: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com
+
+dn: ou=Dynamic Lists,dc=example,dc=com
+objectClass: organizationalUnit
+ou: Dynamic Lists
+
+dn: cn=Meta Group,ou=Dynamic Lists,dc=example,dc=com
+objectClass: groupOfURLs
+cn: Meta Group
+memberURL: ldap:///ou=Dynamic Lists,dc=example,dc=com??sub?(description=Smith%
+ 20family)
+member: cn=The Smiths,ou=Dynamic Lists,dc=example,dc=com
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com
+
+dn: cn=The Smiths,ou=Dynamic Lists,dc=example,dc=com
+objectClass: groupOfURLs
+cn: The Smiths
+memberURL: ldap:///ou=People,dc=example,dc=com??sub?(sn=Smith)
+description: Smith family
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com
+dgMemberOf: cn=meta group,ou=dynamic lists,dc=example,dc=com
+
+dn: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com
+objectClass: OpenLDAPperson
+cn: Mark Elliot
+cn: Mark A Elliot
+sn: Elliot
+uid: melliot
+postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109
+seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com
+homePostalAddress: 199 Outer Drive $ Ypsilanti, MI 48198
+homePhone: +1 313 555 0388
+drink: Gasoline
+title: Director, UM Alumni Association
+mail: melliot@mail.alumni.example.com
+pager: +1 313 555 7671
+facsimileTelephoneNumber: +1 313 555 7762
+telephoneNumber: +1 313 555 4177
+dgMemberOf: cn=dynamic list of members,ou=dynamic lists,dc=example,dc=com
+
+# Testing nested static group functionality...
+dn: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,
+ dc=com
+objectClass: OpenLDAPperson
+cn: Barbara Jensen
+cn: Babs Jensen
+sn:: IEplbnNlbiA=
+uid: bjensen
+title: Mythical Manager, Research Systems
+postalAddress: ITD Prod Dev & Deployment $ 535 W. William St. Room 4212 $ Anyt
+ own, MI 48103-4943
+seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com
+userPassword:: YmplbnNlbg==
+mail: bjensen@mailgw.example.com
+homePostalAddress: 123 Wesley $ Anytown, MI 48103
+description: Mythical manager of the rsdd unix project
+drink: water
+homePhone: +1 313 555 2333
+pager: +1 313 555 3233
+facsimileTelephoneNumber: +1 313 555 2274
+telephoneNumber: +1 313 555 9022
+dgMemberOf: cn=all staff,ou=groups,dc=example,dc=com
+dgMemberOf: cn=the jensens,ou=groups,dc=example,dc=com
+dgMemberOf: cn=jjs,ou=groups,dc=example,dc=com
+dgMemberOf: cn=dynamic list of members,ou=dynamic lists,dc=example,dc=com
+
+dn: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=example,dc
+ =com
+objectClass: OpenLDAPperson
+cn: Bjorn Jensen
+cn: Biiff Jensen
+sn: Jensen
+uid: bjorn
+seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com
+seeAlso: cn=itd staff,ou=groups,dc=example,dc=com
+userPassword:: Ympvcm4=
+homePostalAddress: 19923 Seven Mile Rd. $ South Lyon, MI 49999
+drink: Iced Tea
+description: Hiker, biker
+title: Director, Embedded Systems
+postalAddress: Info Tech Division $ 535 W. William St. $ Anytown, MI 48103
+mail: bjorn@mailgw.example.com
+homePhone: +1 313 555 5444
+pager: +1 313 555 4474
+facsimileTelephoneNumber: +1 313 555 2177
+telephoneNumber: +1 313 555 0355
+dgMemberOf: cn=all staff,ou=groups,dc=example,dc=com
+dgMemberOf: cn=the jensens,ou=groups,dc=example,dc=com
+dgMemberOf: cn=jjs,ou=groups,dc=example,dc=com
+dgMemberOf: cn=dynamic list of members,ou=dynamic lists,dc=example,dc=com
+
+dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com
+objectClass: OpenLDAPperson
+cn: Ursula Hampster
+sn: Hampster
+uid: uham
+title: Secretary, UM Alumni Association
+postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109
+seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com
+homePostalAddress: 123 Anystreet $ Anytown, MI 48104
+mail: uham@mail.alumni.example.com
+homePhone: +1 313 555 8421
+pager: +1 313 555 2844
+facsimileTelephoneNumber: +1 313 555 9700
+telephoneNumber: +1 313 555 5331
+dgMemberOf: cn=all staff,ou=groups,dc=example,dc=com
+dgMemberOf: cn=bonus group,ou=groups,dc=example,dc=com
+dgMemberOf: cn=alumni assoc staff,ou=groups,dc=example,dc=com
+dgMemberOf: cn=dynamic list of members,ou=dynamic lists,dc=example,dc=com
+
+dn: cn=James A Jones 2,ou=Information Technology Division,ou=People,dc=example
+ ,dc=com
+objectClass: OpenLDAPperson
+cn: James A Jones 2
+cn: James Jones
+cn: Jim Jones
+sn: Doe
+uid: jjones
+seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com
+seeAlso: cn=itd staff,ou=groups,dc=example,dc=com
+homePostalAddress: 933 Brooks $ Anytown, MI 48104
+homePhone: +1 313 555 8838
+title: Senior Manager, Information Technology Division
+description: Not around very much
+mail: jjones@mailgw.example.com
+postalAddress: Info Tech Division $ 535 W William $ Anytown, MI 48103
+pager: +1 313 555 2833
+facsimileTelephoneNumber: +1 313 555 8688
+telephoneNumber: +1 313 555 7334
+dgMemberOf: cn=jjs,ou=groups,dc=example,dc=com
+dgMemberOf: cn=all staff,ou=groups,dc=example,dc=com
+dgMemberOf: cn=dynamic list of members,ou=dynamic lists,dc=example,dc=com
+
+dn: cn=Jane Doe,ou=Alumni Association,ou=People,dc=example,dc=com
+objectClass: OpenLDAPperson
+cn: Jane Doe
+cn: Jane Alverson
+sn: Doe
+uid: jdoe
+title: Programmer Analyst, UM Alumni Association
+postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109
+seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com
+homePostalAddress: 123 Anystreet $ Anytown, MI 48104
+drink: diet coke
+description: Enthusiastic
+mail: jdoe@woof.net
+homePhone: +1 313 555 5445
+pager: +1 313 555 1220
+facsimileTelephoneNumber: +1 313 555 2311
+telephoneNumber: +1 313 555 4774
+dgMemberOf: cn=all staff,ou=groups,dc=example,dc=com
+dgMemberOf: cn=alumni assoc staff,ou=groups,dc=example,dc=com
+dgMemberOf: cn=dynamic list of members,ou=dynamic lists,dc=example,dc=com
+
+dn: cn=John Doe,ou=Information Technology Division,ou=People,dc=example,dc=com
+objectClass: OpenLDAPperson
+cn: John Doe
+cn: Jonathon Doe
+sn: Doe
+uid: johnd
+postalAddress: ITD $ 535 W. William $ Anytown, MI 48109
+seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com
+seeAlso: cn=itd staff,ou=groups,dc=example,dc=com
+homePostalAddress: 912 East Bllvd $ Anytown, MI 48104
+title: System Administrator, Information Technology Division
+description: overworked!
+mail: johnd@mailgw.example.com
+homePhone: +1 313 555 3774
+pager: +1 313 555 6573
+facsimileTelephoneNumber: +1 313 555 4544
+telephoneNumber: +1 313 555 9394
+dgMemberOf: cn=all staff,ou=groups,dc=example,dc=com
+dgMemberOf: cn=dynamic list of members,ou=dynamic lists,dc=example,dc=com
+
+dn: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com
+objectClass: OpenLDAPperson
+cn: Jennifer Smith
+cn: Jen Smith
+sn: Smith
+uid: jen
+postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109
+seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com
+drink: Sam Adams
+homePostalAddress: 1000 Maple #44 $ Anytown, MI 48103
+title: Telemarketer, UM Alumni Association
+mail: jen@mail.alumni.example.com
+homePhone: +1 313 555 2333
+pager: +1 313 555 6442
+facsimileTelephoneNumber: +1 313 555 2756
+telephoneNumber: +1 313 555 8232
+dgMemberOf: cn=all staff,ou=groups,dc=example,dc=com
+dgMemberOf: cn=the smiths,ou=dynamic lists,dc=example,dc=com
+dgMemberOf: cn=meta group,ou=dynamic lists,dc=example,dc=com
+dgMemberOf: cn=bonus group,ou=groups,dc=example,dc=com
+dgMemberOf: cn=alumni assoc staff,ou=groups,dc=example,dc=com
+dgMemberOf: cn=dynamic list of members,ou=dynamic lists,dc=example,dc=com
+
+# Testing filtered nested memberOf functionality...
+dn: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com
+objectClass: OpenLDAPperson
+cn: Jennifer Smith
+cn: Jen Smith
+sn: Smith
+uid: jen
+postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109
+seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com
+drink: Sam Adams
+homePostalAddress: 1000 Maple #44 $ Anytown, MI 48103
+title: Telemarketer, UM Alumni Association
+mail: jen@mail.alumni.example.com
+homePhone: +1 313 555 2333
+pager: +1 313 555 6442
+facsimileTelephoneNumber: +1 313 555 2756
+telephoneNumber: +1 313 555 8232
+dgMemberOf: cn=all staff,ou=groups,dc=example,dc=com
+dgMemberOf: cn=the smiths,ou=dynamic lists,dc=example,dc=com
+dgMemberOf: cn=meta group,ou=dynamic lists,dc=example,dc=com
+dgMemberOf: cn=bonus group,ou=groups,dc=example,dc=com
+dgMemberOf: cn=alumni assoc staff,ou=groups,dc=example,dc=com
+dgMemberOf: cn=dynamic list of members,ou=dynamic lists,dc=example,dc=com
+
+dn: cn=Meta Group,ou=Dynamic Lists,dc=example,dc=com
+objectClass: groupOfURLs
+cn: Meta Group
+memberURL: ldap:///ou=Dynamic Lists,dc=example,dc=com??sub?(description=Smith%
+ 20family)
+member: cn=The Smiths,ou=Dynamic Lists,dc=example,dc=com
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com
+dgMemberOf: cn=bonus group,ou=groups,dc=example,dc=com
+
+dn: cn=The Smiths,ou=Dynamic Lists,dc=example,dc=com
+objectClass: groupOfURLs
+cn: The Smiths
+memberURL: ldap:///ou=People,dc=example,dc=com??sub?(sn=Smith)
+description: Smith family
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com
+dgMemberOf: cn=meta group,ou=dynamic lists,dc=example,dc=com
+dgMemberOf: cn=bonus group,ou=groups,dc=example,dc=com
+
+dn: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com
+objectClass: OpenLDAPperson
+cn: Ursula Hampster
+sn: Hampster
+uid: uham
+title: Secretary, UM Alumni Association
+postalAddress: Alumni Association $ 111 Maple St $ Anytown, MI 48109
+seeAlso: cn=All Staff,ou=Groups,dc=example,dc=com
+homePostalAddress: 123 Anystreet $ Anytown, MI 48104
+mail: uham@mail.alumni.example.com
+homePhone: +1 313 555 8421
+pager: +1 313 555 2844
+facsimileTelephoneNumber: +1 313 555 9700
+telephoneNumber: +1 313 555 5331
+dgMemberOf: cn=all staff,ou=groups,dc=example,dc=com
+dgMemberOf: cn=bonus group,ou=groups,dc=example,dc=com
+dgMemberOf: cn=alumni assoc staff,ou=groups,dc=example,dc=com
+dgMemberOf: cn=dynamic list of members,ou=dynamic lists,dc=example,dc=com
+
+# Testing filtered nested member functionality...
+dn: cn=All Staff,ou=Groups,dc=example,dc=com
+member: cn=Manager,dc=example,dc=com
+member: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=exam
+ ple,dc=com
+member: cn=Jane Doe,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=John Doe,ou=Information Technology Division,ou=People,dc=example,dc
+ =com
+member: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=James A Jones 2,ou=Information Technology Division,ou=People,dc=exa
+ mple,dc=com
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=exampl
+ e,dc=com
+owner: cn=Manager,dc=example,dc=com
+cn: All Staff
+description: Everyone in the sample data
+objectClass: groupofnames
+
+dn: cn=Alumni Assoc Staff,ou=Groups,dc=example,dc=com
+member: cn=Manager,dc=example,dc=com
+member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Jane Doe,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com
+owner: cn=Manager,dc=example,dc=com
+description: All Alumni Assoc Staff
+cn: Alumni Assoc Staff
+objectClass: groupofnames
+
+dn: cn=Bonus Group,ou=Groups,dc=example,dc=com
+objectClass: groupOfNames
+cn: Bonus Group
+member: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Meta Group,ou=Dynamic Lists,dc=example,dc=com
+member: cn=The Smiths,ou=Dynamic Lists,dc=example,dc=com
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com
+
+dn: cn=Dynamic List of Members,ou=Dynamic Lists,dc=example,dc=com
+objectClass: groupOfURLs
+objectClass: dgIdentityAux
+cn: Dynamic List of Members
+memberURL: ldap:///ou=People,dc=example,dc=com??sub?(objectClass=person)
+dgIdentity: cn=Bjorn Jensen,ou=Information Technology DivisioN,ou=People,dc=ex
+ ample,dc=com
+dgAuthz: {0}dn:cn=Barbara Jensen,ou=Information Technology DivisioN,ou=People,
+ dc=example,dc=com
+member: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=exam
+ ple,dc=com
+member: cn=Bjorn Jensen,ou=Information Technology Division,ou=People,dc=exampl
+ e,dc=com
+member: cn=Dorothy Stevens,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=James A Jones 1,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=James A Jones 2,ou=Information Technology Division,ou=People,dc=exa
+ mple,dc=com
+member: cn=Jane Doe,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=John Doe,ou=Information Technology Division,ou=People,dc=example,dc
+ =com
+member: cn=Mark Elliot,ou=Alumni Association,ou=People,dc=example,dc=com
+member: cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com
+
+dn: cn=Meta Group,ou=Dynamic Lists,dc=example,dc=com
+objectClass: groupOfURLs
+cn: Meta Group
+memberURL: ldap:///ou=Dynamic Lists,dc=example,dc=com??sub?(description=Smith%
+ 20family)
+member: cn=The Smiths,ou=Dynamic Lists,dc=example,dc=com
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com
+dgMemberOf: cn=bonus group,ou=groups,dc=example,dc=com
+
+dn: cn=The Smiths,ou=Dynamic Lists,dc=example,dc=com
+objectClass: groupOfURLs
+cn: The Smiths
+memberURL: ldap:///ou=People,dc=example,dc=com??sub?(sn=Smith)
+description: Smith family
+member: cn=Jennifer Smith,ou=Alumni Association,ou=People,dc=example,dc=com
+dgMemberOf: cn=meta group,ou=dynamic lists,dc=example,dc=com
+dgMemberOf: cn=bonus group,ou=groups,dc=example,dc=com
+
exit $RC
fi
+echo "Reconfiguring slapd..."
+$LDAPMODIFY -x -D cn=config -h $LOCALHOST -p $PORT1 -y $CONFIGPWF > \
+ $TESTOUT 2>&1 << EOMODS
+version: 1
+dn: olcOverlay={0}dynlist,olcDatabase={$DBIX}$BACKEND,cn=config
+changetype: modify
+delete: olcDynListAttrSet
+olcDynListAttrSet: {0}
+-
+add: olcDynListAttrSet
+olcDynListAttrSet: groupOfURLs memberURL member+dgMemberOf*
+-
+EOMODS
+
+echo "==========================================================" >> $LOG1
+
+echo "Adding a couple dynamic groups..."
+$LDAPADD -v -D "$MANAGERDN" -h $LOCALHOST -p $PORT1 -w $PASSWD \
+ > $TESTOUT 2>&1 << EOMODS
+dn: cn=The Smiths,$LISTDN
+objectClass: groupOfURLs
+cn: The Smiths
+memberURL: ldap:///ou=People,${BASEDN}??sub?(sn=Smith)
+description: Smith family
+
+dn: cn=Meta Group,$LISTDN
+objectClass: groupOfURLs
+cn: Meta Group
+memberURL: ldap:///${LISTDN}??sub?(description=Smith%20family)
+EOMODS
+
+echo "Testing nested dynamic group functionality..."
+echo "# Testing nested dynamic group functionality..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "$LISTDN" -h $LOCALHOST -p $PORT1 \
+ -D "$BABSDN" -w bjensen \
+ '(objectclass=*)' '*' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -S "" -b "ou=People,$BASEDN" -h $LOCALHOST -p $PORT1 \
+ -D "$BABSDN" -w bjensen \
+ '(cn=Mark Elliot)' '*' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Reconfiguring slapd..."
+$LDAPMODIFY -x -D cn=config -h $LOCALHOST -p $PORT1 -y $CONFIGPWF > \
+ $TESTOUT 2>&1 << EOMODS
+version: 1
+dn: olcOverlay={0}dynlist,olcDatabase={$DBIX}$BACKEND,cn=config
+changetype: modify
+delete: olcDynListAttrSet
+olcDynListAttrSet: {0}
+-
+add: olcDynListAttrSet
+olcDynListAttrSet: groupOfURLs memberURL member+dgMemberOf@groupOfNames*
+olcDynListAttrSet: labeledURIObject labeledURI uniqueMember+seeAlso@groupOfUniqueNames
+-
+EOMODS
+
+echo "==========================================================" >> $LOG1
+
+echo "Adding a couple static groups..."
+$LDAPADD -v -D "$MANAGERDN" -h $LOCALHOST -p $PORT1 -w $PASSWD \
+ > $TESTOUT 2>&1 << EOMODS
+dn: cn=The Jensens,ou=Groups,$BASEDN
+objectClass: groupOfnames
+cn: The Jensens
+member: cn=Bjorn Jensen,ou=Information Technology DivisioN,ou=People,$BASEDN
+member: cn=Barbara Jensen,ou=Information Technology DivisioN,ou=People,$BASEDN
+
+dn: cn=JJs,ou=Groups,$BASEDN
+objectClass: groupOfnames
+cn: JJs
+member: cn=James A Jones 1,ou=Alumni Association,ou=People,$BASEDN
+member: cn=James A Jones 2,ou=Information Technology Division,ou=People,$BASEDN
+member: cn=The Jensens,ou=Groups,$BASEDN
+EOMODS
+
+echo "Testing nested static group functionality..."
+echo "# Testing nested static group functionality..." >> $SEARCHOUT
+$LDAPSEARCH -S "" -b "ou=People,$BASEDN" -h $LOCALHOST -p $PORT1 \
+ -D "$BABSDN" -w bjensen \
+ '(sn=Jensen)' '*' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Adding another nested group..."
+$LDAPADD -v -D "$MANAGERDN" -h $LOCALHOST -p $PORT1 -w $PASSWD \
+ > $TESTOUT 2>&1 << EOMODS
+dn: cn=Bonus Group,ou=Groups,$BASEDN
+objectClass: groupOfnames
+cn: Bonus Group
+member: cn=Ursula Hampster,ou=Alumni Association,ou=People,$BASEDN
+member: cn=Meta Group,$LISTDN
+EOMODS
+
+$LDAPSEARCH -S "" -b "ou=People,$BASEDN" -h $LOCALHOST -p $PORT1 \
+ -D "$BABSDN" -w bjensen \
+ '(sn=Hampster)' '*' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -S "" -b "ou=People,$BASEDN" -h $LOCALHOST -p $PORT1 \
+ -D "$BABSDN" -w bjensen \
+ '(sn=Doe)' '*' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+$LDAPSEARCH -S "" -b "ou=People,$BASEDN" -h $LOCALHOST -p $PORT1 \
+ -D "$BABSDN" -w bjensen \
+ '(sn=Smith)' '*' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing filtered nested memberOf functionality..."
+echo "# Testing filtered nested memberOf functionality..." >> $SEARCHOUT
+
+$LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT1 \
+ -D "$BABSDN" -w bjensen \
+ "(dgMemberOf=cn=bonus group,ou=groups,$BASEDN)" '*' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
+echo "Testing filtered nested member functionality..."
+echo "# Testing filtered nested member functionality..." >> $SEARCHOUT
+
+$LDAPSEARCH -S "" -b "$BASEDN" -h $LOCALHOST -p $PORT1 \
+ -D "$BABSDN" -w bjensen \
+ "(member=cn=Jennifer Smith,ou=Alumni Association,ou=People,$BASEDN)" '*' \
+ >> $SEARCHOUT 2>&1
+RC=$?
+if test $RC != 0 ; then
+ echo "ldapsearch failed ($RC)!"
+ test $KILLSERVERS != no && kill -HUP $KILLPIDS
+ exit $RC
+fi
+
test $KILLSERVERS != no && kill -HUP $KILLPIDS
LDIF=$DYNLISTOUT