From: Howard Chu Date: Fri, 26 Jan 2024 17:22:16 +0000 (+0000) Subject: ITS#10161 Add nestgroup overlay X-Git-Tag: OPENLDAP_REL_ENG_2_6_8~32 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=fbef77d42d390e228464c2ba147bcd28fe99c670;p=thirdparty%2Fopenldap.git ITS#10161 Add nestgroup overlay --- diff --git a/configure.ac b/configure.ac index 5fe4e0c41c..20de381444 100644 --- a/configure.ac +++ b/configure.ac @@ -349,6 +349,7 @@ Overlays="accesslog \ dynlist \ homedir \ memberof \ + nestgroup \ otp \ ppolicy \ proxycache \ @@ -392,6 +393,8 @@ OL_ARG_ENABLE(homedir, [AS_HELP_STRING([--enable-homedir], [Home Directory Manag no, [no yes mod], ol_enable_overlays) OL_ARG_ENABLE(memberof, [AS_HELP_STRING([--enable-memberof], [Reverse Group Membership overlay])], no, [no yes mod], ol_enable_overlays) +OL_ARG_ENABLE(nestgroup, [AS_HELP_STRING([--enable-nestgroup], [Nested Group overlay])], + no, [no yes mod], ol_enable_overlays) OL_ARG_ENABLE(otp, [AS_HELP_STRING([--enable-otp], [OTP 2-factor authentication overlay])], no, [no yes mod], ol_enable_overlays) OL_ARG_ENABLE(ppolicy, [AS_HELP_STRING([--enable-ppolicy], [Password Policy overlay])], @@ -2866,6 +2869,17 @@ if test "$ol_enable_memberof" != no ; then AC_DEFINE_UNQUOTED(SLAPD_OVER_MEMBEROF,$MFLAG,[define for Reverse Group Membership overlay]) fi +if test "$ol_enable_nestgroup" != no ; then + if test "$ol_enable_nestgroup" = mod ; then + MFLAG=SLAPD_MOD_DYNAMIC + SLAPD_DYNAMIC_OVERLAYS="$SLAPD_DYNAMIC_OVERLAYS nestgroup.la" + else + MFLAG=SLAPD_MOD_STATIC + SLAPD_STATIC_OVERLAYS="$SLAPD_STATIC_OVERLAYS nestgroup.o" + fi + AC_DEFINE_UNQUOTED(SLAPD_OVER_NESTGROUP,$MFLAG,[define for Nested Group overlay]) +fi + if test "$ol_enable_otp" != no ; then if test $ol_with_tls = no ; then AC_MSG_ERROR([--enable-otp=$ol_enable_otp requires --with-tls]) diff --git a/doc/man/man5/slapo-nestgroup.5 b/doc/man/man5/slapo-nestgroup.5 new file mode 100644 index 0000000000..9f0ddbbac5 --- /dev/null +++ b/doc/man/man5/slapo-nestgroup.5 @@ -0,0 +1,92 @@ +.TH SLAPO-NESTGROUP 5 "RELEASEDATE" "OpenLDAP LDVERSION" +.\" Copyright 2024 The OpenLDAP Foundation, All Rights Reserved. +.\" Copying restrictions apply. See the COPYRIGHT file. +.\" $OpenLDAP$ +.SH NAME +slapo\-nestgroup \- Nested Group overlay to slapd +.SH SYNOPSIS +ETCDIR/slapd.conf +.SH DESCRIPTION +The +.B nestgroup +overlay to +.BR slapd (8) +supports evaluation of nested groups in Search operations. Support consists +of four possible features: inclusion of parent groups when searching with +(member=) filters, inclusion of child groups when searching with (memberOf=) +filters, expansion of child groups when returning member attributes, and +expansion of parent groups when returning memberOf attributes. Each of +these features may be enabled independently. By default, no features are +enabled, so this overlay does nothing unless explicitly enabled. + +.SH CONFIGURATION +The config directives that are specific to the +.B nestgroup +overlay must be prefixed by +.BR nestgroup\- , +to avoid potential conflicts with directives specific to the underlying +database or to other stacked overlays. + +.TP +.B overlay nestgroup +This directive adds the nestgroup overlay to the current database; see +.BR slapd.conf (5) +for details. + +.LP +The following +.B slapd.conf +configuration options are defined for the nestgroup overlay. + +.TP +.BI nestgroup\-member \ +The value +.I +is the name of the attribute that contains the names of the members +in the group objects; it must be DN-valued. +It defaults to \fImember\fP. + +.TP +.BI nestgroup\-memberof \ +The value +.I +is the name of the attribute that contains the names of the groups +an entry is member of; it must be DN-valued. +It defaults to \fImemberOf\fP. + +.TP +.BI nestgroup\-base \ +The value +.I +specifies a subtree that contains group entries in the DIT. This +may be specified multiple times for multiple distinct subtrees. +It has no default and the overlay does no processing unless it is +explicitly configured. + +.TP +.BI "nestgroup\-flags {" member-filter ", " memberof-filter ", " member-values ", " memberof-values "}" +This option specifies which features to enable in the overlay. +By default, nothing is enabled and the overlay is a no-op. + +.LP +The nestgroup overlay may be used with any backend that provides standard +search functionality. + +.SH FILES +.TP +ETCDIR/slapd.conf +default slapd configuration file +.SH SEE ALSO +.BR slapo\-dynlist (5), +.BR slapo\-memberof (5), +.BR slapd.conf (5), +.BR slapd\-config (5), +.BR slapd (8). +The +.BR slapo\-nestgroup (5) +overlay supports dynamic configuration via +.BR back-config . +.SH ACKNOWLEDGEMENTS +.P +This module was written in 2024 by Howard Chu of Symas Corporation. + diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c index 00b0191c3f..572bcc4b2d 100644 --- a/servers/slapd/bconfig.c +++ b/servers/slapd/bconfig.c @@ -285,6 +285,7 @@ static OidRec OidMacros[] = { * OLcfgOv{Oc|At}:21 -> sssvlv * OLcfgOv{Oc|At}:22 -> autoca * OLcfgOv{Oc|At}:24 -> remoteauth + * OLcfgOv{Oc|At}:25 -> nestgroup */ /* alphabetical ordering */ diff --git a/servers/slapd/overlays/Makefile.in b/servers/slapd/overlays/Makefile.in index 1fb18b749d..6d886f8503 100644 --- a/servers/slapd/overlays/Makefile.in +++ b/servers/slapd/overlays/Makefile.in @@ -24,6 +24,7 @@ SRCS = overlays.c \ dynlist.c \ homedir.c \ memberof.c \ + nestgroup.c \ otp.c \ pcache.c \ collect.c \ @@ -96,6 +97,9 @@ homedir.la : homedir.lo memberof.la : memberof.lo $(LTLINK_MOD) -module -o $@ memberof.lo version.lo $(LINK_LIBS) +nestgroup.la : nestgroup.lo + $(LTLINK_MOD) -module -o $@ nestgroup.lo version.lo $(LINK_LIBS) + otp.la : otp.lo $(LTLINK_MOD) -module -o $@ otp.lo version.lo $(LINK_LIBS) diff --git a/servers/slapd/overlays/nestgroup.c b/servers/slapd/overlays/nestgroup.c new file mode 100644 index 0000000000..ca5c928d22 --- /dev/null +++ b/servers/slapd/overlays/nestgroup.c @@ -0,0 +1,909 @@ +/* nestgroup.c - nested group overlay */ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 2024 The OpenLDAP Foundation. + * Copyright 2024 by Howard Chu. + * 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 + * . + */ +/* ACKNOWLEDGEMENTS: + * This work was initially developed by Howard Chu for inclusion in + * OpenLDAP Software. + */ + +#include "portable.h" + +#ifdef SLAPD_OVER_NESTGROUP + +#include + +#include +#include + +#include "lutil.h" +#include "slap.h" +#include "slap-config.h" + +/* This overlay dynamically constructs member and memberOf attributes + * for nested groups. + */ + +#define SLAPD_MEMBEROF_ATTR "memberOf" + +#define NG_MBR_VALUES 0x01 +#define NG_MBR_FILTER 0x02 +#define NG_MOF_VALUES 0x04 +#define NG_MOF_FILTER 0x08 +#define NG_NEGATED 0x10 + +static AttributeDescription *ad_member; +static AttributeDescription *ad_memberOf; + +static slap_verbmasks nestgroup_flags[] = { + { BER_BVC("member-values"), NG_MBR_VALUES }, + { BER_BVC("member-filter"), NG_MBR_FILTER }, + { BER_BVC("memberof-values"), NG_MOF_VALUES }, + { BER_BVC("memberof-filter"), NG_MOF_FILTER }, + { BER_BVNULL, 0 } +}; + +enum { + NG_MEMBER = 1, + NG_MEMBEROF, + NG_GROUPBASE, + NG_FLAGS +}; + +typedef struct nestgroup_info_t { + AttributeDescription *ngi_member; + AttributeDescription *ngi_memberOf; + BerVarray ngi_groupBase; + BerVarray ngi_ngroupBase; + int ngi_flags; +} nestgroup_info_t; + +static int ngroup_cf( ConfigArgs *c ) +{ + slap_overinst *on = (slap_overinst *)c->bi; + nestgroup_info_t *ngi = (nestgroup_info_t *)on->on_bi.bi_private; + int rc = 1; + + if ( c->op == SLAP_CONFIG_EMIT ) { + switch( c->type ) { + case NG_MEMBER: + if ( ngi->ngi_member ) { + value_add_one( &c->rvalue_vals, &ngi->ngi_member->ad_cname ); + rc = 0; + } + break; + case NG_MEMBEROF: + if ( ngi->ngi_memberOf ) { + value_add_one( &c->rvalue_vals, &ngi->ngi_memberOf->ad_cname ); + rc = 0; + } + break; + case NG_GROUPBASE: + if ( ngi->ngi_groupBase ) { + value_add( &c->rvalue_vals, ngi->ngi_groupBase ); + value_add( &c->rvalue_nvals, ngi->ngi_ngroupBase ); + rc = 0; + } + break; + case NG_FLAGS: + return mask_to_verbs( nestgroup_flags, ngi->ngi_flags, &c->rvalue_vals ); + default: + break; + } + return rc; + } else if ( c->op == LDAP_MOD_DELETE ) { + switch( c->type ) { + case NG_MEMBER: + ngi->ngi_member = ad_member; + rc = 0; + break; + case NG_MEMBEROF: + ngi->ngi_memberOf = ad_memberOf; + rc = 0; + break; + case NG_GROUPBASE: + if ( c->valx < 0 ) { + ber_bvarray_free( ngi->ngi_groupBase ); + ber_bvarray_free( ngi->ngi_ngroupBase ); + ngi->ngi_groupBase = NULL; + ngi->ngi_ngroupBase = NULL; + } else { + int i = c->valx; + ch_free( ngi->ngi_groupBase[i].bv_val ); + ch_free( ngi->ngi_ngroupBase[i].bv_val ); + do { + ngi->ngi_groupBase[i] = ngi->ngi_groupBase[i+1]; + ngi->ngi_ngroupBase[i] = ngi->ngi_ngroupBase[i+1]; + i++; + } while ( !BER_BVISNULL( &ngi->ngi_groupBase[i] )); + } + rc = 0; + break; + case NG_FLAGS: + if ( !c->line ) { + ngi->ngi_flags = 0; + } else { + int i = verb_to_mask( c->line, nestgroup_flags ); + ngi->ngi_flags &= ~nestgroup_flags[i].mask; + } + rc = 0; + break; + default: + break; + } + return rc; + } + + switch( c->type ) { + case NG_MEMBER: + if ( !is_at_syntax( c->value_ad->ad_type, SLAPD_DN_SYNTAX ) && + !is_at_syntax( c->value_ad->ad_type, SLAPD_NAMEUID_SYNTAX )) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "member attribute=\"%s\" must use DN (%s) or NAMEUID (%s) syntax", + c->argv[1], SLAPD_DN_SYNTAX, SLAPD_NAMEUID_SYNTAX ); + Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, + "%s: %s\n", c->log, c->cr_msg ); + return ARG_BAD_CONF; + } + ngi->ngi_member = c->value_ad; + rc = 0; + break; + case NG_MEMBEROF: + if ( !is_at_syntax( c->value_ad->ad_type, SLAPD_DN_SYNTAX ) && + !is_at_syntax( c->value_ad->ad_type, SLAPD_NAMEUID_SYNTAX )) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "memberOf attribute=\"%s\" must use DN (%s) or NAMEUID (%s) syntax", + c->argv[1], SLAPD_DN_SYNTAX, SLAPD_NAMEUID_SYNTAX ); + Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, + "%s: %s\n", c->log, c->cr_msg ); + return ARG_BAD_CONF; + } + ngi->ngi_memberOf = c->value_ad; + rc = 0; + break; + case NG_GROUPBASE: + ber_bvarray_add( &ngi->ngi_groupBase, &c->value_dn ); + ber_bvarray_add( &ngi->ngi_ngroupBase, &c->value_ndn ); + rc = 0; + break; + case NG_FLAGS: { + slap_mask_t flags = 0; + int i; + if ( c->op != SLAP_CONFIG_ADD && c->argc > 2 ) { + /* We wouldn't know how to delete these values later */ + snprintf( c->cr_msg, sizeof( c->cr_msg ), + "Please insert multiple names as separate %s values", + c->argv[0] ); + Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, + "%s: %s\n", c->log, c->cr_msg ); + rc = LDAP_INVALID_SYNTAX; + break; + } + i = verbs_to_mask( c->argc, c->argv, nestgroup_flags, &flags ); + if ( i ) { + snprintf( c->cr_msg, sizeof( c->cr_msg ), "<%s> unknown option", c->argv[0] ); + Debug(LDAP_DEBUG_ANY, "%s: %s %s\n", + c->log, c->cr_msg, c->argv[i]); + return(1); + } + ngi->ngi_flags |= flags; + rc = 0; + break; } + default: + break; + } + + return rc; +} + +static ConfigTable ngroupcfg[] = { + { "nestgroup-member", "member-ad", 2, 2, 0, + ARG_MAGIC|ARG_ATDESC|NG_MEMBER, ngroup_cf, + "( OLcfgOvAt:25.1 NAME 'olcNestGroupMember' " + "EQUALITY caseIgnoreMatch " + "DESC 'Member attribute' " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, + { "nestgroup-memberof", "memberOf-ad", 2, 2, 0, + ARG_MAGIC|ARG_ATDESC|NG_MEMBEROF, ngroup_cf, + "( OLcfgOvAt:25.2 NAME 'olcNestGroupMemberOf' " + "EQUALITY caseIgnoreMatch " + "DESC 'MemberOf attribute' " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, + { "nestgroup-base", "dn", 2, 2, 0, + ARG_DN|ARG_QUOTE|ARG_MAGIC|NG_GROUPBASE, ngroup_cf, + "( OLcfgOvAt:25.3 NAME 'olcNestGroupBase' " + "EQUALITY distinguishedNameMatch " + "DESC 'Base[s] of group subtree[s]' " + "SYNTAX OMsDN )", NULL, NULL }, + { "nestgroup-flags", "options", 2, 0, 0, + ARG_MAGIC|NG_FLAGS, ngroup_cf, + "( OLcfgOvAt:25.4 NAME 'olcNestGroupFlags' " + "EQUALITY caseIgnoreMatch " + "DESC 'Features to use' " + "SYNTAX OMsDirectoryString )", NULL, NULL }, + { NULL, NULL, 0, 0, 0, ARG_IGNORED } +}; + +static ConfigOCs ngroupocs[] = { + { "( OLcfgOvOc:25.1 " + "NAME 'olcNestGroupConfig' " + "DESC 'Nested Group configuration' " + "SUP olcOverlayConfig " + "MAY ( olcNestGroupMember $ olcNestGroupMemberOf $ " + " olcNestGroupBase $ olcNestGroupFlags ) ) ", + Cft_Overlay, ngroupcfg }, + { NULL, 0, NULL } +}; + +typedef struct nestgroup_filterinst_t { + Filter *nf_f; + Filter *nf_new; + Entry *nf_e; +} nestgroup_filterinst_t; + +/* Record occurrences of ad in filter. Ignore in negated filters. */ +static void +nestgroup_filter_instances( Operation *op, AttributeDescription *ad, Filter *f, int not, + int *nfn, nestgroup_filterinst_t **nfp, int *negated ) +{ + if ( !f ) + return; + + switch( f->f_choice & SLAPD_FILTER_MASK ) { + case LDAP_FILTER_EQUALITY: + if ( f->f_av_desc == ad ) { + if ( not ) { + *negated = 1; + } else { + nestgroup_filterinst_t *nf = *nfp; + int n = *nfn; + nf = op->o_tmprealloc( nf, (n + 1) * sizeof(nestgroup_filterinst_t), op->o_tmpmemctx ); + nf[n].nf_f = f; + nf[n].nf_new = NULL; + nf[n++].nf_e = NULL; + *nfp = nf; + *nfn = n; + } + } + break; + case SLAPD_FILTER_COMPUTED: + case LDAP_FILTER_PRESENT: + case LDAP_FILTER_GE: + case LDAP_FILTER_LE: + case LDAP_FILTER_APPROX: + case LDAP_FILTER_SUBSTRINGS: + case LDAP_FILTER_EXT: + break; + case LDAP_FILTER_NOT: not ^= 1; + /* FALLTHRU */ + case LDAP_FILTER_AND: + case LDAP_FILTER_OR: + for ( f = f->f_list; f; f = f->f_next ) + nestgroup_filter_instances( op, ad, f, not, nfn, nfp, negated ); + } +} + +static int +nestgroup_check_needed( Operation *op, int attrflags, AttributeDescription *ad ) +{ + if ( is_at_operational( ad->ad_type )) { + if ( SLAP_OPATTRS( attrflags )) + return 1; + } else { + if ( SLAP_USERATTRS( attrflags )) + return 1; + } + return ( ad_inlist( ad, op->ors_attrs )); +} + +typedef struct DNpair { + struct berval dp_ndn; + struct berval dp_dn; + struct DNpair *dp_next; + int dp_flag; +} DNpair; + +typedef struct gdn_info { + TAvlnode *gi_DNs; + DNpair *gi_DNlist; + nestgroup_info_t *gi_ngi; + int gi_numDNs; + int gi_saveDN; + Attribute *gi_merge; +} gdn_info; + +static int +nestgroup_dncmp( const void *v1, const void *v2 ) +{ + return ber_bvcmp((const struct berval *)v1, (const struct berval *)v2); +} + +static int +nestgroup_gotDNresp( Operation *op, SlapReply *rs ) +{ + if ( rs->sr_type == REP_SEARCH ) { + gdn_info *gi = (gdn_info *)(op->o_callback+1); + DNpair *dp = op->o_tmpalloc( sizeof(DNpair), op->o_tmpmemctx ); + dp->dp_ndn = rs->sr_entry->e_nname; + if ( ldap_tavl_insert( &gi->gi_DNs, dp, nestgroup_dncmp, ldap_avl_dup_error )) { + op->o_tmpfree( dp, op->o_tmpmemctx ); + } else { + ber_dupbv_x( &dp->dp_ndn, &rs->sr_entry->e_nname, op->o_tmpmemctx ); + if ( gi->gi_saveDN ) + ber_dupbv_x( &dp->dp_dn, &rs->sr_entry->e_name, op->o_tmpmemctx ); + gi->gi_numDNs++; + dp->dp_next = gi->gi_DNlist; + dp->dp_flag = 0; + gi->gi_DNlist = dp; + } + } + return 0; +} + +static void +nestgroup_get_parentDNs( Operation *op, struct berval *ndn ) +{ + SlapReply r = { REP_SEARCH }; + gdn_info *gi = (gdn_info *)(op->o_callback+1); + nestgroup_info_t *ngi = gi->gi_ngi; + int i; + + op->ors_filter->f_av_value = *ndn; + for ( i=0; !BER_BVISEMPTY( &ngi->ngi_ngroupBase[i] ); i++ ) { + op->o_req_dn = ngi->ngi_groupBase[i]; + op->o_req_ndn = ngi->ngi_ngroupBase[i]; + op->o_bd->be_search( op, &r ); + } + gi->gi_numDNs = 0; /* ignore first count, that's just the original member= result set */ + + while ( gi->gi_DNlist ) { + int prevnum; + DNpair *dp = gi->gi_DNlist; + gi->gi_DNlist = NULL; + for ( ; dp; dp=dp->dp_next ) { + op->ors_filter->f_av_value = dp->dp_ndn; + prevnum = gi->gi_numDNs; + for ( i=0; !BER_BVISEMPTY( &ngi->ngi_ngroupBase[i] ); i++ ) { + op->o_req_dn = ngi->ngi_groupBase[i]; + op->o_req_ndn = ngi->ngi_ngroupBase[i]; + op->o_bd->be_search( op, &r ); + } + if ( gi->gi_numDNs > prevnum ) + dp->dp_flag = 1; /* this group had a parent */ + } + } +} + +static void +nestgroup_memberFilter( Operation *op, int mbr_nf, nestgroup_filterinst_t *mbr_f ) +{ + slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + nestgroup_info_t *ngi = on->on_bi.bi_private; + AttributeDescription *ad = mbr_f[0].nf_f->f_av_desc; + slap_callback *sc; + gdn_info *gi; + Filter mf; + AttributeAssertion mava; + Operation o = *op; + int i; + + o.o_managedsait = SLAP_CONTROL_CRITICAL; + sc = op->o_tmpcalloc( 1, sizeof(slap_callback) + sizeof(gdn_info), op->o_tmpmemctx); + gi = (gdn_info *)(sc+1); + gi->gi_ngi = ngi; + o.o_callback = sc; + sc->sc_response = nestgroup_gotDNresp; + o.ors_attrs = slap_anlist_no_attrs; + + mf.f_choice = LDAP_FILTER_EQUALITY; + mf.f_ava = &mava; + mf.f_av_desc = ad; + mf.f_next = NULL; + + o.ors_scope = LDAP_SCOPE_SUBTREE; + o.ors_deref = LDAP_DEREF_NEVER; + o.ors_limit = NULL; + o.ors_tlimit = SLAP_NO_LIMIT; + o.ors_slimit = SLAP_NO_LIMIT; + o.ors_filter = &mf; + o.o_bd->bd_info = (BackendInfo *)on->on_info; + + for ( i=0; igi_DNs = NULL; + gi->gi_numDNs = 0; + nestgroup_get_parentDNs( &o, &mbr_f[i].nf_f->f_av_value ); + if ( gi->gi_numDNs ) { + int j; + Filter *f, *nf; + TAvlnode *t; + DNpair *dp; + + f = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx ); + f->f_next = NULL; + t = ldap_tavl_end( gi->gi_DNs, TAVL_DIR_RIGHT ); + do { + dp = t->avl_data; + if ( dp->dp_flag ) { + nf = f; + nf->f_ava = op->o_tmpcalloc( 1, sizeof( AttributeAssertion ), op->o_tmpmemctx ); + nf->f_choice = LDAP_FILTER_EQUALITY; + nf->f_av_desc = ad; + nf->f_av_value = dp->dp_ndn; + f = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx ); + f->f_next = nf; + } + t = ldap_tavl_next( t, TAVL_DIR_LEFT ); + op->o_tmpfree( dp, op->o_tmpmemctx ); + } while ( t ); + ldap_tavl_free( gi->gi_DNs, NULL ); + f->f_choice = LDAP_FILTER_EQUALITY; + f->f_ava = mbr_f[i].nf_f->f_ava; + mbr_f[i].nf_new = f; + } + } + o.o_bd->bd_info = (BackendInfo *)on->on_info; + op->o_tmpfree( sc, op->o_tmpmemctx ); +} + +static void +nestgroup_addUnique( Operation *op, Attribute *old, Attribute *new ) +{ + /* strip out any duplicates from new before adding */ + struct berval *bv, *nbv; + int i, j, flags; + + bv = op->o_tmpalloc( (new->a_numvals + 1) * 2 * sizeof(struct berval), op->o_tmpmemctx ); + nbv = bv + new->a_numvals+1; + + flags = SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH|SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH; + for (i=0,j=0; ia_numvals; i++) { + int rc = attr_valfind( old, flags, &new->a_nvals[i], NULL, NULL ); + if ( rc ) { + bv[j] = new->a_vals[i]; + nbv[j++] = new->a_nvals[i]; + } + } + BER_BVZERO( &bv[j] ); + BER_BVZERO( &nbv[j] ); + attr_valadd( old, bv, nbv, j ); + op->o_tmpfree( bv, op->o_tmpmemctx ); +} + +static void +nestgroup_get_childDNs( Operation *op, slap_overinst *on, gdn_info *gi, struct berval *ndn ) +{ + nestgroup_info_t *ngi = on->on_bi.bi_private; + Entry *e; + Attribute *a; + + if ( overlay_entry_get_ov( op, ndn, NULL, NULL, 0, &e, on ) != LDAP_SUCCESS || e == NULL ) + return; + + a = attr_find( e->e_attrs, ngi->ngi_member ); + if ( a ) { + int i, j; + for (i = 0; ia_numvals; i++ ) { + /* record all group entries */ + for (j = 0; !BER_BVISEMPTY( &ngi->ngi_groupBase[j] ); j++) { + if ( dnIsSuffix( &a->a_nvals[i], &ngi->ngi_ngroupBase[j] )) { + DNpair *dp = op->o_tmpalloc( sizeof(DNpair), op->o_tmpmemctx ); + dp->dp_ndn = a->a_nvals[i]; + if ( ldap_tavl_insert( &gi->gi_DNs, dp, nestgroup_dncmp, ldap_avl_dup_error )) { + op->o_tmpfree( dp, op->o_tmpmemctx ); + } else { + ber_dupbv_x( &dp->dp_ndn, &a->a_nvals[i], op->o_tmpmemctx ); + gi->gi_numDNs++; + dp->dp_next = gi->gi_DNlist; + gi->gi_DNlist = dp; + } + break; + } + } + } + if ( gi->gi_merge ) { + nestgroup_addUnique( op, gi->gi_merge, a ); + } + } + overlay_entry_release_ov( op, e, 0, on ); +} + +static void +nestgroup_memberOfFilter( Operation *op, int mof_nf, nestgroup_filterinst_t *mof_f ) +{ + slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + AttributeDescription *ad = mof_f[0].nf_f->f_av_desc; + gdn_info gi = {0}; + int i; + + for ( i=0; if_av_value ); + + while ( gi.gi_DNlist ) { + DNpair *dp = gi.gi_DNlist; + gi.gi_DNlist = NULL; + for ( ; dp; dp=dp->dp_next ) { + nestgroup_get_childDNs( op, on, &gi, &dp->dp_ndn ); + } + } + + if ( gi.gi_numDNs ) { + int j; + Filter *f, *nf; + TAvlnode *t; + DNpair *dp; + + f = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx ); + f->f_next = NULL; + t = ldap_tavl_end( gi.gi_DNs, TAVL_DIR_RIGHT ); + do { + dp = t->avl_data; + nf = f; + nf->f_ava = op->o_tmpcalloc( 1, sizeof( AttributeAssertion ), op->o_tmpmemctx ); + nf->f_choice = LDAP_FILTER_EQUALITY; + nf->f_av_desc = ad; + nf->f_av_value = dp->dp_ndn; + f = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx ); + f->f_next = nf; + t = ldap_tavl_next( t, TAVL_DIR_LEFT ); + op->o_tmpfree( dp, op->o_tmpmemctx ); + } while ( t ); + ldap_tavl_free( gi.gi_DNs, NULL ); + f->f_choice = LDAP_FILTER_EQUALITY; + f->f_ava = mof_f[i].nf_f->f_ava; + mof_f[i].nf_new = f; + } + } +} + +static void +nestgroup_memberOfVals( Operation *op, slap_overinst *on, Attribute *a ) +{ + nestgroup_info_t *ngi = on->on_bi.bi_private; + Operation o = *op; + slap_callback *sc; + gdn_info *gi; + Filter mf; + AttributeAssertion mava; + int i; + + o.o_managedsait = SLAP_CONTROL_CRITICAL; + sc = op->o_tmpcalloc( 1, sizeof(slap_callback) + sizeof(gdn_info), op->o_tmpmemctx); + gi = (gdn_info *)(sc+1); + gi->gi_ngi = ngi; + o.o_callback = sc; + sc->sc_response = nestgroup_gotDNresp; + o.ors_attrs = slap_anlist_no_attrs; + + mf.f_choice = LDAP_FILTER_EQUALITY; + mf.f_ava = &mava; + mf.f_av_desc = ngi->ngi_member; + mf.f_next = NULL; + + o.ors_filter = &mf; + o.ors_scope = LDAP_SCOPE_SUBTREE; + o.ors_deref = LDAP_DEREF_NEVER; + o.ors_limit = NULL; + o.ors_tlimit = SLAP_NO_LIMIT; + o.ors_slimit = SLAP_NO_LIMIT; + o.o_bd->bd_info = (BackendInfo *)on->on_info; + gi->gi_saveDN = 1; + + for ( i=0; ia_numvals; i++ ) { + nestgroup_get_parentDNs( &o, &a->a_nvals[i] ); + + while ( gi->gi_DNlist ) { + DNpair *dp = gi->gi_DNlist; + gi->gi_DNlist = NULL; + for ( ; dp; dp=dp->dp_next ) { + nestgroup_get_parentDNs( &o, &dp->dp_ndn ); + } + } + } + if ( gi->gi_DNs ) { + TAvlnode *p = ldap_tavl_end( gi->gi_DNs, TAVL_DIR_LEFT ); + int flags = SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH|SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH; + do { + DNpair *dp = p->avl_data; + int rc = attr_valfind( a, flags, &dp->dp_ndn, NULL, NULL ); + if ( rc ) + attr_valadd( a, &dp->dp_dn, &dp->dp_ndn, 1 ); + op->o_tmpfree( dp->dp_dn.bv_val, op->o_tmpmemctx ); + op->o_tmpfree( dp->dp_ndn.bv_val, op->o_tmpmemctx ); + op->o_tmpfree( dp, op->o_tmpmemctx ); + p = ldap_tavl_next( p, TAVL_DIR_RIGHT ); + } while ( p ); + ldap_tavl_free( gi->gi_DNs, NULL ); + } + o.o_bd->bd_info = (BackendInfo *)on->on_info; + op->o_tmpfree( sc, op->o_tmpmemctx ); +} + +typedef struct nestgroup_cbinfo { + slap_overinst *nc_on; + int nc_needed; +} nestgroup_cbinfo; + +static int +nestgroup_searchresp( Operation *op, SlapReply *rs ) +{ + if (rs->sr_type == REP_SEARCH ) { + nestgroup_cbinfo *nc = op->o_callback->sc_private; + slap_overinst *on = nc->nc_on; + nestgroup_info_t *ngi = on->on_bi.bi_private; + Attribute *a; + + if ( nc->nc_needed & NG_MBR_VALUES ) { + a = attr_find( rs->sr_entry->e_attrs, ngi->ngi_member ); + if ( a ) { + gdn_info gi = {0}; + int i, j; + if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE )) { + Entry *e = entry_dup( rs->sr_entry ); + rs_replace_entry( op, rs, on, e ); + rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED; + a = attr_find( e->e_attrs, ngi->ngi_member ); + } + gi.gi_merge = a; + + for ( i=0; ia_numvals; i++ ) { + for ( j=0; !BER_BVISEMPTY( &ngi->ngi_ngroupBase[j] ); j++ ) { + if ( dnIsSuffix( &a->a_nvals[i], &ngi->ngi_ngroupBase[j] )) { + nestgroup_get_childDNs( op, on, &gi, &a->a_nvals[i] ); + + while ( gi.gi_DNlist ) { + DNpair *dp = gi.gi_DNlist; + gi.gi_DNlist = NULL; + for ( ; dp; dp=dp->dp_next ) { + nestgroup_get_childDNs( op, on, &gi, &dp->dp_ndn ); + } + } + break; + } + } + } + if ( gi.gi_numDNs ) { + TAvlnode *p = ldap_tavl_end( gi.gi_DNs, TAVL_DIR_LEFT ); + do { + DNpair *dp = p->avl_data; + op->o_tmpfree( dp->dp_ndn.bv_val, op->o_tmpmemctx ); + op->o_tmpfree( dp, op->o_tmpmemctx ); + p = ldap_tavl_next( p, TAVL_DIR_RIGHT ); + } while ( p ); + ldap_tavl_free( gi.gi_DNs, NULL ); + } + } + } + + if ( nc->nc_needed & NG_MOF_VALUES ) { + a = attr_find( rs->sr_entry->e_attrs, ngi->ngi_memberOf ); + if ( a ) { + if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE )) { + Entry *e = entry_dup( rs->sr_entry ); + rs_replace_entry( op, rs, on, e ); + rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED; + a = attr_find( e->e_attrs, ngi->ngi_memberOf ); + } + nestgroup_memberOfVals( op, on, a ); + } + } + if (( nc->nc_needed & NG_NEGATED ) && + test_filter( op, rs->sr_entry, op->ors_filter ) != LDAP_COMPARE_TRUE ) + return 0; + } + return SLAP_CB_CONTINUE; +} + +static int +nestgroup_op_search( Operation *op, SlapReply *rs ) +{ + slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + nestgroup_info_t *ngi = on->on_bi.bi_private; + int mbr_nf = 0, mof_nf = 0, negated = 0; + nestgroup_filterinst_t *mbr_f = NULL, *mof_f = NULL; + + if ( get_manageDSAit( op )) + return SLAP_CB_CONTINUE; + + /* groupBase must be explicitly configured */ + if ( !ngi->ngi_ngroupBase ) + return SLAP_CB_CONTINUE; + + /* handle attrs in filter */ + if ( ngi->ngi_flags & NG_MBR_FILTER ) { + nestgroup_filter_instances( op, ngi->ngi_member, op->ors_filter, 0, &mbr_nf, &mbr_f, &negated ); + if ( mbr_nf ) { + /* find member=(parent groups) */ + nestgroup_memberFilter( op, mbr_nf, mbr_f ); + } + } + if ( ngi->ngi_flags & NG_MOF_FILTER ) { + nestgroup_filter_instances( op, ngi->ngi_memberOf, op->ors_filter, 0, &mof_nf, &mof_f, &negated ); + if ( mof_nf ) { + /* find memberOf=(child groups) */ + nestgroup_memberOfFilter( op, mof_nf, mof_f ); + } + } + if ( mbr_nf ) { + int i; + for ( i=0; if_choice = LDAP_FILTER_OR; + mbr_f[i].nf_f->f_list = mbr_f[i].nf_new; + } + } + op->o_tmpfree( mbr_f, op->o_tmpmemctx ); + } + if ( mof_nf ) { + int i; + for ( i=0; if_choice = LDAP_FILTER_OR; + mof_f[i].nf_f->f_list = mof_f[i].nf_new; + } + } + op->o_tmpfree( mof_f, op->o_tmpmemctx ); + } + + if ( ngi->ngi_flags & ( NG_MBR_VALUES|NG_MOF_VALUES )) { + /* check for attrs in attrlist */ + int attrflags = slap_attr_flags( op->ors_attrs ); + int needed = 0; + if (( ngi->ngi_flags & NG_MBR_VALUES ) && + nestgroup_check_needed( op, attrflags, ngi->ngi_member )) { + /* collect all members from child groups */ + needed |= NG_MBR_VALUES; + } + if (( ngi->ngi_flags & NG_MOF_VALUES ) && + nestgroup_check_needed( op, attrflags, ngi->ngi_memberOf )) { + /* collect DNs of all parent groups */ + needed |= NG_MOF_VALUES; + } + if ( needed ) { + nestgroup_cbinfo *nc; + slap_callback *sc = op->o_tmpcalloc( 1, sizeof(slap_callback)+sizeof(nestgroup_cbinfo), op->o_tmpmemctx ); + nc = (nestgroup_cbinfo *)(sc+1); + sc->sc_private = nc; + nc->nc_needed = needed; + nc->nc_on = on; + sc->sc_response = nestgroup_searchresp; + sc->sc_next = op->o_callback; + op->o_callback = sc; + if ( negated ) nc->nc_needed |= NG_NEGATED; + } + } + return SLAP_CB_CONTINUE; +} + +static int +nestgroup_db_init( + BackendDB *be, + ConfigReply *cr) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + nestgroup_info_t *ngi; + int rc; + const char *text = NULL; + + ngi = (nestgroup_info_t *)ch_calloc( 1, sizeof( *ngi )); + on->on_bi.bi_private = ngi; + + if ( !ad_memberOf ) { + rc = slap_str2ad( SLAPD_MEMBEROF_ATTR, &ad_memberOf, &text ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, "nestgroup_db_init: " + "unable to find attribute=\"%s\": %s (%d)\n", + SLAPD_MEMBEROF_ATTR, text, rc ); + return rc; + } + } + + if ( !ad_member ) { + rc = slap_str2ad( SLAPD_GROUP_ATTR, &ad_member, &text ); + if ( rc != LDAP_SUCCESS ) { + Debug( LDAP_DEBUG_ANY, "nestgroup_db_init: " + "unable to find attribute=\"%s\": %s (%d)\n", + SLAPD_GROUP_ATTR, text, rc ); + return rc; + } + } + + return 0; +} + +static int +nestgroup_db_open( + BackendDB *be, + ConfigReply *cr) +{ + slap_overinst *on = (slap_overinst *)be->bd_info; + nestgroup_info_t *ngi = on->on_bi.bi_private; + + if ( !ngi->ngi_member ) + ngi->ngi_member = ad_member; + + if ( !ngi->ngi_memberOf ) + ngi->ngi_memberOf = ad_memberOf; + + return 0; +} + +static int +nestgroup_db_destroy( + BackendDB *be, + ConfigReply *cr +) +{ + slap_overinst *on = (slap_overinst *) be->bd_info; + nestgroup_info_t *ngi = on->on_bi.bi_private; + + ber_bvarray_free( ngi->ngi_groupBase ); + ber_bvarray_free( ngi->ngi_ngroupBase ); + ch_free( ngi ); + + return 0; +} + +static slap_overinst nestgroup; + +/* This overlay is set up for dynamic loading via moduleload. For static + * configuration, you'll need to arrange for the slap_overinst to be + * initialized and registered by some other function inside slapd. + */ + +int nestgroup_initialize() { + int code; + + code = register_at( + "( 1.2.840.113556.1.2.102 " + "NAME 'memberOf' " + "DESC 'Group that the entry belongs to' " + "SYNTAX '1.3.6.1.4.1.1466.115.121.1.12' " + "EQUALITY distinguishedNameMatch " /* added */ + "USAGE dSAOperation " /* added; questioned */ + "NO-USER-MODIFICATION " /* added */ + "X-ORIGIN 'iPlanet Delegated Administrator' )", + &ad_memberOf, 0 ); + if ( code && code != SLAP_SCHERR_ATTR_DUP ) { + Debug( LDAP_DEBUG_ANY, + "nestgroup_initialize: register_at (memberOf) failed\n" ); + return code; + } + + nestgroup.on_bi.bi_type = "nestgroup"; + nestgroup.on_bi.bi_db_init = nestgroup_db_init; + nestgroup.on_bi.bi_db_open = nestgroup_db_open; + nestgroup.on_bi.bi_db_destroy = nestgroup_db_destroy; + + nestgroup.on_bi.bi_op_search = nestgroup_op_search; +/* nestgroup.on_bi.bi_op_compare = nestgroup_op_compare; */ + + nestgroup.on_bi.bi_cf_ocs = ngroupocs; + code = config_register_schema( ngroupcfg, ngroupocs ); + if ( code ) return code; + + return overlay_register( &nestgroup ); +} + +#if SLAPD_OVER_NESTGROUP == SLAPD_MOD_DYNAMIC +int +init_module( int argc, char *argv[] ) +{ + return nestgroup_initialize(); +} +#endif + +#endif /* defined(SLAPD_OVER_NESTGROUP) */ diff --git a/tests/data/nestgroup.out.1 b/tests/data/nestgroup.out.1 new file mode 100644 index 0000000000..93716ac071 --- /dev/null +++ b/tests/data/nestgroup.out.1 @@ -0,0 +1,389 @@ +# Search the entire database... +dn: cn=A-M,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: A-M +member: cn=Baby Herman,ou=People,dc=example,dc=com +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Daffy Duck,ou=People,dc=example,dc=com +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Foghorn Leghorn,ou=People,dc=example,dc=com +member: cn=Jessica Rabbit,ou=People,dc=example,dc=com + +dn: cn=Baby Herman,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Baby Herman +sn: Herman + +dn: cn=Bugs Bunny,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Bugs Bunny +sn: Bunny + +dn: cn=Daffy Duck,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Daffy Duck +sn: Duck + +dn: cn=Desert Foes,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Desert Foes +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com + +dn: cn=Elmer Fudd,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Elmer Fudd +sn: Fudd + +dn: cn=Endless Loop,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Endless Loop +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Loop\2C Endless,ou=Groups,dc=example,dc=com + +dn: dc=example,dc=com +objectClass: organization +objectClass: dcObject +o: Example, Inc. +dc: example + +dn: cn=Foghorn Leghorn,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Foghorn Leghorn +sn: Leghorn + +dn: ou=Groups,dc=example,dc=com +objectClass: organizationalUnit +ou: Groups + +dn: cn=Humans,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Humans +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Yosemite Sam,ou=People,dc=example,dc=com + +dn: cn=Jessica Rabbit,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Jessica Rabbit +sn: Rabbit + +dn: cn=Leporidae,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Leporidae +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Rabbits,ou=Groups,dc=example,dc=com + +dn: cn=Looney Tunes,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Looney Tunes +member: cn=Porky Pig,ou=People,dc=example,dc=com +member: cn=Daffy Duck,ou=People,dc=example,dc=com +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Tweety Bird,ou=People,dc=example,dc=com + +dn: cn=Loop\2C Endless,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Loop, Endless +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +member: cn=Endless Loop,ou=Groups,dc=example,dc=com + +dn: cn=Mixer1,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer1 +member: cn=Leporidae,ou=Groups,dc=example,dc=com +member: cn=Desert Foes,ou=Groups,dc=example,dc=com +member: cn=Foghorn Leghorn,ou=People,dc=example,dc=com + +dn: cn=Mixer2,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer2 +member: cn=Humans,ou=Groups,dc=example,dc=com +member: cn=Baby Herman,ou=People,dc=example,dc=com + +dn: cn=Mixer3,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer3 +member: cn=Desert Foes,ou=Groups,dc=example,dc=com +member: cn=Porky Pig,ou=People,dc=example,dc=com + +dn: cn=Mixer4,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer4 +member: cn=Mixer1,ou=Groups,dc=example,dc=com +member: cn=Mixer2,ou=Groups,dc=example,dc=com +member: cn=Foghorn Leghorn,ou=People,dc=example,dc=com + +dn: cn=Mixer5,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer5 +member: cn=Mixer2,ou=Groups,dc=example,dc=com +member: cn=Mixer3,ou=Groups,dc=example,dc=com +member: cn=A-M,ou=Groups,dc=example,dc=com + +dn: cn=N-Z,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: N-Z +member: cn=Porky Pig,ou=People,dc=example,dc=com +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Roger Rabbit,ou=People,dc=example,dc=com +member: cn=Tweety Bird,ou=People,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +member: cn=Yosemite Sam,ou=People,dc=example,dc=com + +dn: ou=People,dc=example,dc=com +objectClass: organizationalUnit +ou: People + +dn: cn=Porky Pig,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Porky Pig +sn: Pig + +dn: cn=Rabbits,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Rabbits +member: cn=Roger Rabbit,ou=People,dc=example,dc=com +member: cn=Jessica Rabbit,ou=People,dc=example,dc=com + +dn: cn=Road Runner,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Road Runner +sn: Runner + +dn: cn=Roger Rabbit,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Roger Rabbit +sn: Rabbit + +dn: cn=Tweety Bird,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Tweety Bird +sn: Bird + +dn: cn=Wile E. Coyote,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Wile E. Coyote +sn: Coyote + +dn: cn=Yosemite Sam,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Yosemite Sam +sn: Sam + +# Search for member=cn=Bugs Bunny... +dn: cn=A-M,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: A-M +member: cn=Baby Herman,ou=People,dc=example,dc=com +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Daffy Duck,ou=People,dc=example,dc=com +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Foghorn Leghorn,ou=People,dc=example,dc=com +member: cn=Jessica Rabbit,ou=People,dc=example,dc=com + +dn: cn=Leporidae,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Leporidae +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Rabbits,ou=Groups,dc=example,dc=com + +dn: cn=Looney Tunes,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Looney Tunes +member: cn=Porky Pig,ou=People,dc=example,dc=com +member: cn=Daffy Duck,ou=People,dc=example,dc=com +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Tweety Bird,ou=People,dc=example,dc=com + +# Re-search for nested member=cn=Bugs Bunny... +dn: cn=A-M,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: A-M +member: cn=Baby Herman,ou=People,dc=example,dc=com +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Daffy Duck,ou=People,dc=example,dc=com +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Foghorn Leghorn,ou=People,dc=example,dc=com +member: cn=Jessica Rabbit,ou=People,dc=example,dc=com + +dn: cn=Leporidae,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Leporidae +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Rabbits,ou=Groups,dc=example,dc=com + +dn: cn=Looney Tunes,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Looney Tunes +member: cn=Porky Pig,ou=People,dc=example,dc=com +member: cn=Daffy Duck,ou=People,dc=example,dc=com +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Tweety Bird,ou=People,dc=example,dc=com + +dn: cn=Mixer1,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer1 +member: cn=Leporidae,ou=Groups,dc=example,dc=com +member: cn=Desert Foes,ou=Groups,dc=example,dc=com +member: cn=Foghorn Leghorn,ou=People,dc=example,dc=com + +dn: cn=Mixer4,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer4 +member: cn=Mixer1,ou=Groups,dc=example,dc=com +member: cn=Mixer2,ou=Groups,dc=example,dc=com +member: cn=Foghorn Leghorn,ou=People,dc=example,dc=com + +dn: cn=Mixer5,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer5 +member: cn=Mixer2,ou=Groups,dc=example,dc=com +member: cn=Mixer3,ou=Groups,dc=example,dc=com +member: cn=A-M,ou=Groups,dc=example,dc=com + +# Search the expanded groups... +dn: cn=A-M,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: A-M +member: cn=Baby Herman,ou=People,dc=example,dc=com +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Daffy Duck,ou=People,dc=example,dc=com +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Foghorn Leghorn,ou=People,dc=example,dc=com +member: cn=Jessica Rabbit,ou=People,dc=example,dc=com + +dn: cn=Desert Foes,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Desert Foes +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com + +dn: cn=Endless Loop,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Endless Loop +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Loop\2C Endless,ou=Groups,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +member: cn=Endless Loop,ou=Groups,dc=example,dc=com + +dn: ou=Groups,dc=example,dc=com +objectClass: organizationalUnit +ou: Groups + +dn: cn=Humans,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Humans +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Yosemite Sam,ou=People,dc=example,dc=com + +dn: cn=Leporidae,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Leporidae +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Rabbits,ou=Groups,dc=example,dc=com +member: cn=Roger Rabbit,ou=People,dc=example,dc=com +member: cn=Jessica Rabbit,ou=People,dc=example,dc=com + +dn: cn=Looney Tunes,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Looney Tunes +member: cn=Porky Pig,ou=People,dc=example,dc=com +member: cn=Daffy Duck,ou=People,dc=example,dc=com +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Tweety Bird,ou=People,dc=example,dc=com + +dn: cn=Loop\2C Endless,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Loop, Endless +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +member: cn=Endless Loop,ou=Groups,dc=example,dc=com +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Loop\2C Endless,ou=Groups,dc=example,dc=com + +dn: cn=Mixer1,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer1 +member: cn=Leporidae,ou=Groups,dc=example,dc=com +member: cn=Desert Foes,ou=Groups,dc=example,dc=com +member: cn=Foghorn Leghorn,ou=People,dc=example,dc=com +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Rabbits,ou=Groups,dc=example,dc=com +member: cn=Roger Rabbit,ou=People,dc=example,dc=com +member: cn=Jessica Rabbit,ou=People,dc=example,dc=com +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com + +dn: cn=Mixer2,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer2 +member: cn=Humans,ou=Groups,dc=example,dc=com +member: cn=Baby Herman,ou=People,dc=example,dc=com +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Yosemite Sam,ou=People,dc=example,dc=com + +dn: cn=Mixer3,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer3 +member: cn=Desert Foes,ou=Groups,dc=example,dc=com +member: cn=Porky Pig,ou=People,dc=example,dc=com +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com + +dn: cn=Mixer4,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer4 +member: cn=Mixer1,ou=Groups,dc=example,dc=com +member: cn=Mixer2,ou=Groups,dc=example,dc=com +member: cn=Foghorn Leghorn,ou=People,dc=example,dc=com +member: cn=Leporidae,ou=Groups,dc=example,dc=com +member: cn=Desert Foes,ou=Groups,dc=example,dc=com +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Rabbits,ou=Groups,dc=example,dc=com +member: cn=Roger Rabbit,ou=People,dc=example,dc=com +member: cn=Jessica Rabbit,ou=People,dc=example,dc=com +member: cn=Humans,ou=Groups,dc=example,dc=com +member: cn=Baby Herman,ou=People,dc=example,dc=com +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Yosemite Sam,ou=People,dc=example,dc=com + +dn: cn=Mixer5,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer5 +member: cn=Mixer2,ou=Groups,dc=example,dc=com +member: cn=Mixer3,ou=Groups,dc=example,dc=com +member: cn=A-M,ou=Groups,dc=example,dc=com +member: cn=Humans,ou=Groups,dc=example,dc=com +member: cn=Baby Herman,ou=People,dc=example,dc=com +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Yosemite Sam,ou=People,dc=example,dc=com +member: cn=Desert Foes,ou=Groups,dc=example,dc=com +member: cn=Porky Pig,ou=People,dc=example,dc=com +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Daffy Duck,ou=People,dc=example,dc=com +member: cn=Foghorn Leghorn,ou=People,dc=example,dc=com +member: cn=Jessica Rabbit,ou=People,dc=example,dc=com + +dn: cn=N-Z,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: N-Z +member: cn=Porky Pig,ou=People,dc=example,dc=com +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Roger Rabbit,ou=People,dc=example,dc=com +member: cn=Tweety Bird,ou=People,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +member: cn=Yosemite Sam,ou=People,dc=example,dc=com + +dn: cn=Rabbits,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Rabbits +member: cn=Roger Rabbit,ou=People,dc=example,dc=com +member: cn=Jessica Rabbit,ou=People,dc=example,dc=com + diff --git a/tests/data/nestgroup.out.2 b/tests/data/nestgroup.out.2 new file mode 100644 index 0000000000..3269c8130d --- /dev/null +++ b/tests/data/nestgroup.out.2 @@ -0,0 +1,606 @@ +# Re-search the entire database after adding memberof configuration... +dn: cn=A-M,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: A-M +member: cn=Baby Herman,ou=People,dc=example,dc=com +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Daffy Duck,ou=People,dc=example,dc=com +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Foghorn Leghorn,ou=People,dc=example,dc=com +member: cn=Jessica Rabbit,ou=People,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com + +dn: cn=Baby Herman,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Baby Herman +sn: Herman +memberOf: cn=A-M,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer2,ou=Groups,dc=example,dc=com + +dn: cn=Bugs Bunny,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Bugs Bunny +sn: Bunny +memberOf: cn=Leporidae,ou=Groups,dc=example,dc=com +memberOf: cn=A-M,ou=Groups,dc=example,dc=com +memberOf: cn=Looney Tunes,ou=Groups,dc=example,dc=com + +dn: cn=Daffy Duck,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Daffy Duck +sn: Duck +memberOf: cn=A-M,ou=Groups,dc=example,dc=com +memberOf: cn=Looney Tunes,ou=Groups,dc=example,dc=com + +dn: cn=Desert Foes,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Desert Foes +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +memberOf: cn=Mixer1,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer3,ou=Groups,dc=example,dc=com + +dn: cn=Elmer Fudd,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Elmer Fudd +sn: Fudd +memberOf: cn=A-M,ou=Groups,dc=example,dc=com +memberOf: cn=Humans,ou=Groups,dc=example,dc=com +memberOf: cn=Looney Tunes,ou=Groups,dc=example,dc=com + +dn: cn=Endless Loop,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Endless Loop +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Loop\2C Endless,ou=Groups,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +member: cn=Endless Loop,ou=Groups,dc=example,dc=com +memberOf: cn=Loop\2C Endless,ou=Groups,dc=example,dc=com + +dn: dc=example,dc=com +objectClass: organization +objectClass: dcObject +o: Example, Inc. +dc: example + +dn: cn=Foghorn Leghorn,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Foghorn Leghorn +sn: Leghorn +memberOf: cn=A-M,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer1,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com + +dn: ou=Groups,dc=example,dc=com +objectClass: organizationalUnit +ou: Groups + +dn: cn=Humans,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Humans +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Yosemite Sam,ou=People,dc=example,dc=com +memberOf: cn=Mixer2,ou=Groups,dc=example,dc=com + +dn: cn=Jessica Rabbit,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Jessica Rabbit +sn: Rabbit +memberOf: cn=Rabbits,ou=Groups,dc=example,dc=com +memberOf: cn=A-M,ou=Groups,dc=example,dc=com + +dn: cn=Leporidae,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Leporidae +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Rabbits,ou=Groups,dc=example,dc=com +member: cn=Roger Rabbit,ou=People,dc=example,dc=com +member: cn=Jessica Rabbit,ou=People,dc=example,dc=com +memberOf: cn=Mixer1,ou=Groups,dc=example,dc=com + +dn: cn=Looney Tunes,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Looney Tunes +member: cn=Porky Pig,ou=People,dc=example,dc=com +member: cn=Daffy Duck,ou=People,dc=example,dc=com +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Tweety Bird,ou=People,dc=example,dc=com + +dn: cn=Loop\2C Endless,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Loop, Endless +memberOf: cn=Endless Loop,ou=Groups,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +member: cn=Endless Loop,ou=Groups,dc=example,dc=com +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Loop\2C Endless,ou=Groups,dc=example,dc=com + +dn: cn=Mixer1,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer1 +member: cn=Leporidae,ou=Groups,dc=example,dc=com +member: cn=Desert Foes,ou=Groups,dc=example,dc=com +member: cn=Foghorn Leghorn,ou=People,dc=example,dc=com +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Rabbits,ou=Groups,dc=example,dc=com +member: cn=Roger Rabbit,ou=People,dc=example,dc=com +member: cn=Jessica Rabbit,ou=People,dc=example,dc=com +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com + +dn: cn=Mixer2,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer2 +member: cn=Humans,ou=Groups,dc=example,dc=com +member: cn=Baby Herman,ou=People,dc=example,dc=com +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Yosemite Sam,ou=People,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com + +dn: cn=Mixer3,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer3 +member: cn=Desert Foes,ou=Groups,dc=example,dc=com +member: cn=Porky Pig,ou=People,dc=example,dc=com +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com + +dn: cn=Mixer4,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer4 +member: cn=Mixer1,ou=Groups,dc=example,dc=com +member: cn=Mixer2,ou=Groups,dc=example,dc=com +member: cn=Foghorn Leghorn,ou=People,dc=example,dc=com +member: cn=Leporidae,ou=Groups,dc=example,dc=com +member: cn=Desert Foes,ou=Groups,dc=example,dc=com +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Rabbits,ou=Groups,dc=example,dc=com +member: cn=Roger Rabbit,ou=People,dc=example,dc=com +member: cn=Jessica Rabbit,ou=People,dc=example,dc=com +member: cn=Humans,ou=Groups,dc=example,dc=com +member: cn=Baby Herman,ou=People,dc=example,dc=com +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Yosemite Sam,ou=People,dc=example,dc=com + +dn: cn=Mixer5,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer5 +member: cn=Mixer2,ou=Groups,dc=example,dc=com +member: cn=Mixer3,ou=Groups,dc=example,dc=com +member: cn=A-M,ou=Groups,dc=example,dc=com +member: cn=Humans,ou=Groups,dc=example,dc=com +member: cn=Baby Herman,ou=People,dc=example,dc=com +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Yosemite Sam,ou=People,dc=example,dc=com +member: cn=Desert Foes,ou=Groups,dc=example,dc=com +member: cn=Porky Pig,ou=People,dc=example,dc=com +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Daffy Duck,ou=People,dc=example,dc=com +member: cn=Foghorn Leghorn,ou=People,dc=example,dc=com +member: cn=Jessica Rabbit,ou=People,dc=example,dc=com + +dn: cn=N-Z,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: N-Z +member: cn=Porky Pig,ou=People,dc=example,dc=com +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Roger Rabbit,ou=People,dc=example,dc=com +member: cn=Tweety Bird,ou=People,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +member: cn=Yosemite Sam,ou=People,dc=example,dc=com + +dn: ou=People,dc=example,dc=com +objectClass: organizationalUnit +ou: People + +dn: cn=Porky Pig,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Porky Pig +sn: Pig +memberOf: cn=N-Z,ou=Groups,dc=example,dc=com +memberOf: cn=Looney Tunes,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer3,ou=Groups,dc=example,dc=com + +dn: cn=Rabbits,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Rabbits +member: cn=Roger Rabbit,ou=People,dc=example,dc=com +member: cn=Jessica Rabbit,ou=People,dc=example,dc=com +memberOf: cn=Leporidae,ou=Groups,dc=example,dc=com + +dn: cn=Road Runner,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Road Runner +sn: Runner +memberOf: cn=N-Z,ou=Groups,dc=example,dc=com +memberOf: cn=Desert Foes,ou=Groups,dc=example,dc=com +memberOf: cn=Endless Loop,ou=Groups,dc=example,dc=com + +dn: cn=Roger Rabbit,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Roger Rabbit +sn: Rabbit +memberOf: cn=Rabbits,ou=Groups,dc=example,dc=com +memberOf: cn=N-Z,ou=Groups,dc=example,dc=com + +dn: cn=Tweety Bird,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Tweety Bird +sn: Bird +memberOf: cn=N-Z,ou=Groups,dc=example,dc=com +memberOf: cn=Looney Tunes,ou=Groups,dc=example,dc=com + +dn: cn=Wile E. Coyote,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Wile E. Coyote +sn: Coyote +memberOf: cn=N-Z,ou=Groups,dc=example,dc=com +memberOf: cn=Desert Foes,ou=Groups,dc=example,dc=com +memberOf: cn=Loop\2C Endless,ou=Groups,dc=example,dc=com + +dn: cn=Yosemite Sam,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Yosemite Sam +sn: Sam +memberOf: cn=N-Z,ou=Groups,dc=example,dc=com +memberOf: cn=Humans,ou=Groups,dc=example,dc=com + +# Search for memberOf=cn=Mixer3... +dn: cn=Desert Foes,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Desert Foes +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +memberOf: cn=Mixer1,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer3,ou=Groups,dc=example,dc=com + +dn: cn=Porky Pig,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Porky Pig +sn: Pig +memberOf: cn=N-Z,ou=Groups,dc=example,dc=com +memberOf: cn=Looney Tunes,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer3,ou=Groups,dc=example,dc=com + +# Re-search for memberOf=cn=Mixer3 with filter nesting... +dn: cn=Desert Foes,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Desert Foes +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +memberOf: cn=Mixer1,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer3,ou=Groups,dc=example,dc=com + +dn: cn=Porky Pig,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Porky Pig +sn: Pig +memberOf: cn=N-Z,ou=Groups,dc=example,dc=com +memberOf: cn=Looney Tunes,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer3,ou=Groups,dc=example,dc=com + +dn: cn=Road Runner,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Road Runner +sn: Runner +memberOf: cn=N-Z,ou=Groups,dc=example,dc=com +memberOf: cn=Desert Foes,ou=Groups,dc=example,dc=com +memberOf: cn=Endless Loop,ou=Groups,dc=example,dc=com + +dn: cn=Wile E. Coyote,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Wile E. Coyote +sn: Coyote +memberOf: cn=N-Z,ou=Groups,dc=example,dc=com +memberOf: cn=Desert Foes,ou=Groups,dc=example,dc=com +memberOf: cn=Loop\2C Endless,ou=Groups,dc=example,dc=com + +# Re-search for memberOf=cn=Mixer3 with filter and value nesting... +dn: cn=Desert Foes,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Desert Foes +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +memberOf: cn=Mixer1,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer3,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com + +dn: cn=Porky Pig,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Porky Pig +sn: Pig +memberOf: cn=N-Z,ou=Groups,dc=example,dc=com +memberOf: cn=Looney Tunes,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer3,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com + +dn: cn=Road Runner,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Road Runner +sn: Runner +memberOf: cn=N-Z,ou=Groups,dc=example,dc=com +memberOf: cn=Desert Foes,ou=Groups,dc=example,dc=com +memberOf: cn=Endless Loop,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer1,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer3,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com +memberOf: cn=Loop\2C Endless,ou=Groups,dc=example,dc=com + +dn: cn=Wile E. Coyote,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Wile E. Coyote +sn: Coyote +memberOf: cn=N-Z,ou=Groups,dc=example,dc=com +memberOf: cn=Desert Foes,ou=Groups,dc=example,dc=com +memberOf: cn=Loop\2C Endless,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer1,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer3,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com +memberOf: cn=Endless Loop,ou=Groups,dc=example,dc=com + +# Re-search the entire database with memberof value nesting... +dn: cn=A-M,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: A-M +member: cn=Baby Herman,ou=People,dc=example,dc=com +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Daffy Duck,ou=People,dc=example,dc=com +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Foghorn Leghorn,ou=People,dc=example,dc=com +member: cn=Jessica Rabbit,ou=People,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com + +dn: cn=Baby Herman,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Baby Herman +sn: Herman +memberOf: cn=A-M,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer2,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com + +dn: cn=Bugs Bunny,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Bugs Bunny +sn: Bunny +memberOf: cn=Leporidae,ou=Groups,dc=example,dc=com +memberOf: cn=A-M,ou=Groups,dc=example,dc=com +memberOf: cn=Looney Tunes,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer1,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com + +dn: cn=Daffy Duck,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Daffy Duck +sn: Duck +memberOf: cn=A-M,ou=Groups,dc=example,dc=com +memberOf: cn=Looney Tunes,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com + +dn: cn=Desert Foes,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Desert Foes +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +memberOf: cn=Mixer1,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer3,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com + +dn: cn=Elmer Fudd,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Elmer Fudd +sn: Fudd +memberOf: cn=A-M,ou=Groups,dc=example,dc=com +memberOf: cn=Humans,ou=Groups,dc=example,dc=com +memberOf: cn=Looney Tunes,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer2,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com + +dn: cn=Endless Loop,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Endless Loop +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Loop\2C Endless,ou=Groups,dc=example,dc=com +memberOf: cn=Loop\2C Endless,ou=Groups,dc=example,dc=com +memberOf: cn=Endless Loop,ou=Groups,dc=example,dc=com + +dn: dc=example,dc=com +objectClass: organization +objectClass: dcObject +o: Example, Inc. +dc: example + +dn: cn=Foghorn Leghorn,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Foghorn Leghorn +sn: Leghorn +memberOf: cn=A-M,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer1,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com + +dn: ou=Groups,dc=example,dc=com +objectClass: organizationalUnit +ou: Groups + +dn: cn=Humans,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Humans +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Yosemite Sam,ou=People,dc=example,dc=com +memberOf: cn=Mixer2,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com + +dn: cn=Jessica Rabbit,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Jessica Rabbit +sn: Rabbit +memberOf: cn=Rabbits,ou=Groups,dc=example,dc=com +memberOf: cn=A-M,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer1,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com +memberOf: cn=Leporidae,ou=Groups,dc=example,dc=com + +dn: cn=Leporidae,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Leporidae +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Rabbits,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer1,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com + +dn: cn=Looney Tunes,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Looney Tunes +member: cn=Porky Pig,ou=People,dc=example,dc=com +member: cn=Daffy Duck,ou=People,dc=example,dc=com +member: cn=Elmer Fudd,ou=People,dc=example,dc=com +member: cn=Bugs Bunny,ou=People,dc=example,dc=com +member: cn=Tweety Bird,ou=People,dc=example,dc=com + +dn: cn=Loop\2C Endless,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Loop, Endless +memberOf: cn=Endless Loop,ou=Groups,dc=example,dc=com +memberOf: cn=Loop\2C Endless,ou=Groups,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +member: cn=Endless Loop,ou=Groups,dc=example,dc=com + +dn: cn=Mixer1,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer1 +member: cn=Leporidae,ou=Groups,dc=example,dc=com +member: cn=Desert Foes,ou=Groups,dc=example,dc=com +member: cn=Foghorn Leghorn,ou=People,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com + +dn: cn=Mixer2,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer2 +member: cn=Humans,ou=Groups,dc=example,dc=com +member: cn=Baby Herman,ou=People,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com + +dn: cn=Mixer3,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer3 +member: cn=Desert Foes,ou=Groups,dc=example,dc=com +member: cn=Porky Pig,ou=People,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com + +dn: cn=Mixer4,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer4 +member: cn=Mixer1,ou=Groups,dc=example,dc=com +member: cn=Mixer2,ou=Groups,dc=example,dc=com +member: cn=Foghorn Leghorn,ou=People,dc=example,dc=com + +dn: cn=Mixer5,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Mixer5 +member: cn=Mixer2,ou=Groups,dc=example,dc=com +member: cn=Mixer3,ou=Groups,dc=example,dc=com +member: cn=A-M,ou=Groups,dc=example,dc=com + +dn: cn=N-Z,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: N-Z +member: cn=Porky Pig,ou=People,dc=example,dc=com +member: cn=Road Runner,ou=People,dc=example,dc=com +member: cn=Roger Rabbit,ou=People,dc=example,dc=com +member: cn=Tweety Bird,ou=People,dc=example,dc=com +member: cn=Wile E. Coyote,ou=People,dc=example,dc=com +member: cn=Yosemite Sam,ou=People,dc=example,dc=com + +dn: ou=People,dc=example,dc=com +objectClass: organizationalUnit +ou: People + +dn: cn=Porky Pig,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Porky Pig +sn: Pig +memberOf: cn=N-Z,ou=Groups,dc=example,dc=com +memberOf: cn=Looney Tunes,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer3,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com + +dn: cn=Rabbits,ou=Groups,dc=example,dc=com +objectClass: groupOfNames +cn: Rabbits +member: cn=Roger Rabbit,ou=People,dc=example,dc=com +member: cn=Jessica Rabbit,ou=People,dc=example,dc=com +memberOf: cn=Leporidae,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer1,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com + +dn: cn=Road Runner,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Road Runner +sn: Runner +memberOf: cn=N-Z,ou=Groups,dc=example,dc=com +memberOf: cn=Desert Foes,ou=Groups,dc=example,dc=com +memberOf: cn=Endless Loop,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer1,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer3,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com +memberOf: cn=Loop\2C Endless,ou=Groups,dc=example,dc=com + +dn: cn=Roger Rabbit,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Roger Rabbit +sn: Rabbit +memberOf: cn=Rabbits,ou=Groups,dc=example,dc=com +memberOf: cn=N-Z,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer1,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com +memberOf: cn=Leporidae,ou=Groups,dc=example,dc=com + +dn: cn=Tweety Bird,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Tweety Bird +sn: Bird +memberOf: cn=N-Z,ou=Groups,dc=example,dc=com +memberOf: cn=Looney Tunes,ou=Groups,dc=example,dc=com + +dn: cn=Wile E. Coyote,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Wile E. Coyote +sn: Coyote +memberOf: cn=N-Z,ou=Groups,dc=example,dc=com +memberOf: cn=Desert Foes,ou=Groups,dc=example,dc=com +memberOf: cn=Loop\2C Endless,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer1,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer3,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com +memberOf: cn=Endless Loop,ou=Groups,dc=example,dc=com + +dn: cn=Yosemite Sam,ou=People,dc=example,dc=com +objectClass: inetOrgPerson +cn: Yosemite Sam +sn: Sam +memberOf: cn=N-Z,ou=Groups,dc=example,dc=com +memberOf: cn=Humans,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer2,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer4,ou=Groups,dc=example,dc=com +memberOf: cn=Mixer5,ou=Groups,dc=example,dc=com + diff --git a/tests/scripts/conf.sh b/tests/scripts/conf.sh index 837abfd082..47420c8440 100755 --- a/tests/scripts/conf.sh +++ b/tests/scripts/conf.sh @@ -42,6 +42,7 @@ sed -e "s/@BACKEND@/${BACKEND}/" \ -e "s/^#${AC_dynlist}#//" \ -e "s/^#${AC_homedir}#//" \ -e "s/^#${AC_memberof}#//" \ + -e "s/^#${AC_nestgroup}#//" \ -e "s/^#${AC_pcache}#//" \ -e "s/^#${AC_ppolicy}#//" \ -e "s/^#${AC_refint}#//" \ diff --git a/tests/scripts/defines.sh b/tests/scripts/defines.sh index 7caab6d2f5..df9e1edb41 100755 --- a/tests/scripts/defines.sh +++ b/tests/scripts/defines.sh @@ -51,6 +51,7 @@ DEREF=${AC_deref-derefno} DYNLIST=${AC_dynlist-dynlistno} HOMEDIR=${AC_homedir-homedirno} MEMBEROF=${AC_memberof-memberofno} +NESTGROUP=${AC_nestgroup-nestgroupno} OTP=${AC_otp-otpno} PROXYCACHE=${AC_pcache-pcacheno} PPOLICY=${AC_ppolicy-ppolicyno} @@ -460,6 +461,8 @@ DDSOUT=$DATADIR/dds.out DEREFOUT=$DATADIR/deref.out MEMBEROFOUT=$DATADIR/memberof.out MEMBEROFREFINTOUT=$DATADIR/memberof-refint.out +NESTGROUPOUT1=$DATADIR/nestgroup.out.1 +NESTGROUPOUT2=$DATADIR/nestgroup.out.2 SHTOOL="$TOPSRCDIR/build/shtool" . $ABS_SRCDIR/scripts/functions.sh diff --git a/tests/scripts/test089-nestgroup b/tests/scripts/test089-nestgroup new file mode 100755 index 0000000000..0c8d7dd92d --- /dev/null +++ b/tests/scripts/test089-nestgroup @@ -0,0 +1,662 @@ +#! /bin/sh +# $OpenLDAP$ +## This work is part of OpenLDAP Software . +## +## Copyright 1998-2024 The OpenLDAP Foundation. +## 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 +## . + +echo "running defines.sh" +. $SRCDIR/scripts/defines.sh + +if test $NESTGROUP = nestgroupno; then + echo "Nestgroup overlay not available, test skipped" + exit 0 +fi +if test $MEMBEROF = memberofno; then + echo "Memberof overlay not available, memberof testing disabled" +fi + +mkdir -p $TESTDIR $DBDIR1 $TESTDIR/confdir + +$SLAPPASSWD -g -n >$CONFIGPWF +echo "rootpw `$SLAPPASSWD -T $CONFIGPWF`" >$TESTDIR/configpw.conf + +echo "Starting slapd on TCP/IP port $PORT1..." +. $CONFFILTER $BACKEND < $NAKEDCONF > $CONF1 +$SLAPD -f $CONF1 -F $TESTDIR/confdir -h $URI1 -d $LVL > $LOG1 2>&1 & +PID=$! +if test $WAIT != 0 ; then + echo PID $PID + read foo +fi +KILLPIDS="$PID" + +sleep 1 +for i in 0 1 2 3 4 5; do + $LDAPSEARCH -s base -b "$MONITOR" -H $URI1 \ + 'objectclass=*' > /dev/null 2>&1 + RC=$? + if test $RC = 0 ; then + break + fi + echo "Waiting 5 seconds for slapd to start..." + sleep 5 +done +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +cat /dev/null > $TESTOUT + +if [ "$NESTGROUP" = nestgroupmod ]; then + echo "Inserting nestgroup overlay on provider..." + $LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF < $TESTOUT 2>&1 +dn: cn=module,cn=config +objectClass: olcModuleList +cn: module +olcModulePath: ../servers/slapd/overlays +olcModuleLoad: nestgroup.la +EOF + RC=$? + if test $RC != 0 ; then + echo "ldapadd failed for moduleLoad ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + fi +fi + +indexInclude="" mainInclude="" nullExclude="" +test $INDEXDB = indexdb || indexInclude="# " +test $MAINDB = maindb || mainInclude="# " +case $BACKEND in +null) nullExclude="# " ;; +esac + +echo "Running ldapadd to build slapd config database..." +$LDAPADD -H $URI1 -D 'cn=config' -w `cat $CONFIGPWF` \ + >> $TESTOUT 2>&1 <> $TESTOUT 2>&1 << EOF +dn: $BASEDN +objectClass: organization +objectClass: dcObject +o: Example, Inc. +dc: example + +dn: ou=People,$BASEDN +objectClass: organizationalUnit +ou: People + +dn: ou=Groups,$BASEDN +objectClass: organizationalUnit +ou: Groups + +dn: cn=Roger Rabbit,ou=People,$BASEDN +objectClass: inetOrgPerson +cn: Roger Rabbit +sn: Rabbit + +dn: cn=Baby Herman,ou=People,$BASEDN +objectClass: inetOrgPerson +cn: Baby Herman +sn: Herman + +dn: cn=Jessica Rabbit,ou=People,$BASEDN +objectClass: inetOrgPerson +cn: Jessica Rabbit +sn: Rabbit + +dn: cn=Bugs Bunny,ou=People,$BASEDN +objectClass: inetOrgPerson +cn: Bugs Bunny +sn: Bunny + +dn: cn=Daffy Duck,ou=People,$BASEDN +objectClass: inetOrgPerson +cn: Daffy Duck +sn: Duck + +dn: cn=Elmer Fudd,ou=People,$BASEDN +objectClass: inetOrgPerson +cn: Elmer Fudd +sn: Fudd + +dn: cn=Yosemite Sam,ou=People,$BASEDN +objectClass: inetOrgPerson +cn: Yosemite Sam +sn: Sam + +dn: cn=Foghorn Leghorn,ou=People,$BASEDN +objectClass: inetOrgPerson +cn: Foghorn Leghorn +sn: Leghorn + +dn: cn=Wile E. Coyote,ou=People,$BASEDN +objectClass: inetOrgPerson +cn: Wile E. Coyote +sn: Coyote + +dn: cn=Road Runner,ou=People,$BASEDN +objectClass: inetOrgPerson +cn: Road Runner +sn: Runner + +dn: cn=Tweety Bird,ou=People,$BASEDN +objectClass: inetOrgPerson +cn: Tweety Bird +sn: Bird + +dn: cn=Porky Pig,ou=People,$BASEDN +objectClass: inetOrgPerson +cn: Porky Pig +sn: Pig + +dn: cn=Rabbits,ou=Groups,$BASEDN +objectClass: groupOfNames +cn: Rabbits +member: cn=Roger Rabbit,ou=People,$BASEDN +member: cn=Jessica Rabbit,ou=People,$BASEDN + +dn: cn=Leporidae,ou=Groups,$BASEDN +objectClass: groupOfNames +cn: Leporidae +member: cn=Bugs Bunny,ou=People,$BASEDN +member: cn=Rabbits,ou=Groups,$BASEDN + +dn: cn=A-M,ou=Groups,$BASEDN +objectClass: groupOfNames +cn: A-M +member: cn=Baby Herman,ou=People,$BASEDN +member: cn=Bugs Bunny,ou=People,$BASEDN +member: cn=Daffy Duck,ou=People,$BASEDN +member: cn=Elmer Fudd,ou=People,$BASEDN +member: cn=Foghorn Leghorn,ou=People,$BASEDN +member: cn=Jessica Rabbit,ou=People,$BASEDN + +dn: cn=N-Z,ou=Groups,$BASEDN +objectClass: groupOfNames +cn: N-Z +member: cn=Porky Pig,ou=People,$BASEDN +member: cn=Road Runner,ou=People,$BASEDN +member: cn=Roger Rabbit,ou=People,$BASEDN +member: cn=Tweety Bird,ou=People,$BASEDN +member: cn=Wile E. Coyote,ou=People,$BASEDN +member: cn=Yosemite Sam,ou=People,$BASEDN + +dn: cn=Humans,ou=Groups,$BASEDN +objectClass: groupOfNames +cn: Humans +member: cn=Elmer Fudd,ou=People,$BASEDN +member: cn=Yosemite Sam,ou=People,$BASEDN + +dn: cn=Looney Tunes,ou=Groups,$BASEDN +objectClass: groupOfNames +cn: Looney Tunes +member: cn=Porky Pig,ou=People,$BASEDN +member: cn=Daffy Duck,ou=People,$BASEDN +member: cn=Elmer Fudd,ou=People,$BASEDN +member: cn=Bugs Bunny,ou=People,$BASEDN +member: cn=Tweety Bird,ou=People,$BASEDN + +dn: cn=Desert Foes,ou=Groups,$BASEDN +objectClass: groupOfNames +cn: Desert Foes +member: cn=Road Runner,ou=People,$BASEDN +member: cn=Wile E. Coyote,ou=People,$BASEDN + +dn: cn=Mixer1,ou=Groups,$BASEDN +objectClass: groupOfNames +cn: Mixer1 +member: cn=Leporidae,ou=Groups,$BASEDN +member: cn=Desert Foes,ou=Groups,$BASEDN +member: cn=Foghorn Leghorn,ou=People,$BASEDN + +dn: cn=Mixer2,ou=Groups,$BASEDN +objectClass: groupOfNames +cn: Mixer2 +member: cn=Humans,ou=Groups,$BASEDN +member: cn=Baby Herman,ou=People,$BASEDN + +dn: cn=Mixer3,ou=Groups,$BASEDN +objectClass: groupOfNames +cn: Mixer3 +member: cn=Desert Foes,ou=Groups,$BASEDN +member: cn=Porky Pig,ou=People,$BASEDN + +dn: cn=Mixer4,ou=Groups,$BASEDN +objectClass: groupOfNames +cn: Mixer4 +member: cn=Mixer1,ou=Groups,$BASEDN +member: cn=Mixer2,ou=Groups,$BASEDN +member: cn=Foghorn Leghorn,ou=People,$BASEDN + +dn: cn=Mixer5,ou=Groups,$BASEDN +objectClass: groupOfNames +cn: Mixer5 +member: cn=Mixer2,ou=Groups,$BASEDN +member: cn=Mixer3,ou=Groups,$BASEDN +member: cn=A-M,ou=Groups,$BASEDN + +dn: cn=Endless Loop,ou=Groups,$BASEDN +objectClass: groupOfNames +cn: Endless Loop +member: cn=Road Runner,ou=People,$BASEDN +member: cn=Loop\, Endless,ou=Groups,$BASEDN + +dn: cn=Loop\, Endless,ou=Groups,$BASEDN +objectClass: groupOfNames +cn: Loop, Endless +member: cn=Wile E. Coyote,ou=People,$BASEDN +member: cn=Endless Loop,ou=Groups,$BASEDN + +EOF +RC=$? +if test $RC != 0 ; then + echo "ldapadd failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Search the entire database..." +echo "# Search the entire database..." > $SEARCHOUT +$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \ + '(objectClass=*)' '*' >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Search for member=cn=Bugs Bunny..." +echo "# Search for member=cn=Bugs Bunny..." >> $SEARCHOUT +$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \ + "(member=cn=Bugs Bunny,ou=People,$BASEDN)" '*' memberof >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Running ldapmodify to enable nested member filter..." +$LDAPMODIFY -H $URI1 -D 'cn=config' -w `cat $CONFIGPWF` \ + >> $TESTOUT 2>&1 <> $SEARCHOUT +$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \ + "(member=cn=Bugs Bunny,ou=People,$BASEDN)" '*' memberof >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Running ldapmodify to enable nested member values..." +$LDAPMODIFY -H $URI1 -D 'cn=config' -w `cat $CONFIGPWF` \ + >> $TESTOUT 2>&1 <> $SEARCHOUT +$LDAPSEARCH -S "" -b "ou=Groups,$BASEDN" -H $URI1 \ + '(objectClass=*)' '*' memberof >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +LDIF=$NESTGROUPOUT1 + +echo "Filtering ldapsearch results..." +$LDIFFILTER < $SEARCHOUT > $SEARCHFLT +echo "Filtering original ldif used to create database..." +$LDIFFILTER < $LDIF > $LDIFFLT +echo "Comparing filter output..." +$CMP $SEARCHFLT $LDIFFLT > $CMPOUT + +if test $? != 0 ; then + echo "Comparison failed" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 +fi + +echo ">>>>> Test succeeded (first half)" + +if [ "$MEMBEROF" = memberofno ]; then + test $KILLSERVERS != no && kill -HUP $KILLPIDS + + test $KILLSERVERS != no && wait + + exit 0 +fi + +echo "Adding memberof overlay to database configuration..." + +if [ "$MEMBEROF" = memberofmod ]; then + echo "Inserting memberof module on provider..." + $LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF < $TESTOUT 2>&1 +dn: cn=module,cn=config +objectClass: olcModuleList +cn: module +olcModulePath: ../servers/slapd/overlays +olcModuleLoad: memberof.la +EOF + RC=$? + if test $RC != 0 ; then + echo "ldapadd failed for moduleLoad ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC + fi +fi + +$LDAPADD -H $URI1 -D 'cn=config' -w `cat $CONFIGPWF` \ + >> $TESTOUT 2>&1 <> $TESTOUT 2>&1 <> $SEARCHOUT +$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \ + '(objectClass=*)' '*' memberOf >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Search for memberOf=cn=Mixer3..." +echo "# Search for memberOf=cn=Mixer3..." >> $SEARCHOUT +$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \ + "(memberOf=cn=Mixer3,ou=Groups,$BASEDN)" '*' memberof >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Running ldapmodify to enable nested memberOf filter..." +$LDAPMODIFY -H $URI1 -D 'cn=config' -w `cat $CONFIGPWF` \ + >> $TESTOUT 2>&1 <> $SEARCHOUT +$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \ + "(memberOf=cn=Mixer3,ou=Groups,$BASEDN)" '*' memberof >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Running ldapmodify to also enable nested memberOf values..." +$LDAPMODIFY -H $URI1 -D 'cn=config' -w `cat $CONFIGPWF` \ + >> $TESTOUT 2>&1 <> $SEARCHOUT +$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \ + "(memberOf=cn=Mixer3,ou=Groups,$BASEDN)" '*' memberof >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Re-search the entire database with memberof value nesting..." +echo "# Re-search the entire database with memberof value nesting..." >> $SEARCHOUT +$LDAPSEARCH -S "" -b "$BASEDN" -H $URI1 \ + '(objectClass=*)' '*' memberOf >> $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=$NESTGROUPOUT2 + +echo "Filtering ldapsearch results..." +$LDIFFILTER < $SEARCHOUT > $SEARCHFLT +echo "Filtering original ldif used to create database..." +$LDIFFILTER < $LDIF > $LDIFFLT +echo "Comparing filter output..." +$CMP $SEARCHFLT $LDIFFLT > $CMPOUT + +if test $? != 0 ; then + echo "Comparison failed" + exit 1 +fi + +echo ">>>>> Test succeeded" + +test $KILLSERVERS != no && wait + +exit 0