diff --git a/servers/slapd/overlays/dynlist.c b/servers/slapd/overlays/dynlist.c index 96c0b0cf20d30dddf57efdf74d4f2b886a9c8f32..8a080ceadcabbe3ebdd74530f89b7bfed5aca173 100644 --- a/servers/slapd/overlays/dynlist.c +++ b/servers/slapd/overlays/dynlist.c @@ -58,7 +58,7 @@ static AttributeName anlist_no_attrs[] = { static AttributeName *slap_anlist_no_attrs = anlist_no_attrs; #endif -static AttributeDescription *ad_dgIdentity; +static AttributeDescription *ad_dgIdentity, *ad_dgAuthz; typedef struct dynlist_info_t { ObjectClass *dli_oc; @@ -348,6 +348,26 @@ dynlist_prepare_entry( Operation *op, SlapReply *rs, dynlist_info_t *dli ) return SLAP_CB_CONTINUE; } + if ( ad_dgIdentity && ( id = attrs_find( rs->sr_entry->e_attrs, ad_dgIdentity ))) { + Attribute *authz = NULL; + + /* if not rootdn and dgAuthz is present, + * check if user can be authorized as dgIdentity */ + if ( ad_dgAuthz && !BER_BVISEMPTY( &id->a_nvals[0] ) && !be_isroot( op ) + && ( authz = attrs_find( rs->sr_entry->e_attrs, ad_dgAuthz ) ) ) + { + if ( slap_sasl_matches( op, authz->a_nvals, + &o.o_ndn, &o.o_ndn ) != LDAP_SUCCESS ) + { + return SLAP_CB_CONTINUE; + } + } + + o.o_dn = id->a_vals[0]; + o.o_ndn = id->a_nvals[0]; + o.o_groups = NULL; + } + if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) { e = entry_dup( rs->sr_entry ); } else { @@ -355,12 +375,6 @@ dynlist_prepare_entry( Operation *op, SlapReply *rs, dynlist_info_t *dli ) } e_flags = rs->sr_flags | ( REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED ); - if ( ad_dgIdentity && ( id = attrs_find( e->e_attrs, ad_dgIdentity ))) { - o.o_dn = id->a_vals[0]; - o.o_ndn = id->a_nvals[0]; - o.o_groups = NULL; - } - dlc.dlc_e = e; dlc.dlc_dli = dli; cb.sc_private = &dlc; @@ -557,16 +571,33 @@ dynlist_compare( Operation *op, SlapReply *rs ) * interested in. We'll use slapd's existing dyngroup * evaluator to get the answer we want. */ - struct berval *id = NULL; + BerVarray id = NULL, authz = NULL; o.o_do_not_cache = 1; if ( ad_dgIdentity && backend_attribute( &o, NULL, &o.o_req_ndn, - ad_dgIdentity, &id, ACL_READ ) == LDAP_SUCCESS ) { + ad_dgIdentity, &id, ACL_READ ) == LDAP_SUCCESS ) + { + /* if not rootdn and dgAuthz is present, + * check if user can be authorized as dgIdentity */ + if ( ad_dgAuthz && !BER_BVISEMPTY( id ) && !be_isroot( op ) + && backend_attribute( &o, NULL, &o.o_req_ndn, + ad_dgAuthz, &authz, ACL_READ ) == LDAP_SUCCESS ) + { + + rs->sr_err = slap_sasl_matches( op, authz, + &o.o_ndn, &o.o_ndn ); + ber_bvarray_free_x( authz, op->o_tmpmemctx ); + if ( rs->sr_err != LDAP_SUCCESS ) { + goto done; + } + } + o.o_dn = *id; o.o_ndn = *id; o.o_groups = NULL; /* authz changed, invalidate cached groups */ } + rs->sr_err = backend_group( &o, NULL, &o.o_req_ndn, &o.oq_compare.rs_ava->aa_value, dli->dli_oc, dli->dli_ad ); switch ( rs->sr_err ) { @@ -586,6 +617,7 @@ dynlist_compare( Operation *op, SlapReply *rs ) break; } +done:; if ( id ) ber_bvarray_free_x( id, o.o_tmpmemctx ); return SLAP_CB_CONTINUE; @@ -593,17 +625,34 @@ dynlist_compare( Operation *op, SlapReply *rs ) } if ( overlay_entry_get_ov( &o, &o.o_req_ndn, NULL, NULL, 0, &e, on ) != - LDAP_SUCCESS || e == NULL ) { + LDAP_SUCCESS || e == NULL ) + { return SLAP_CB_CONTINUE; } + if ( ad_dgIdentity ) { Attribute *id = attrs_find( e->e_attrs, ad_dgIdentity ); if ( id ) { + Attribute *authz; + + /* if not rootdn and dgAuthz is present, + * check if user can be authorized as dgIdentity */ + if ( ad_dgAuthz && !BER_BVISEMPTY( &id->a_nvals[0] ) && !be_isroot( op ) + && ( authz = attrs_find( e->e_attrs, ad_dgAuthz ) ) ) + { + if ( slap_sasl_matches( op, authz->a_nvals, + &o.o_ndn, &o.o_ndn ) != LDAP_SUCCESS ) + { + goto release; + } + } + o.o_dn = id->a_vals[0]; o.o_ndn = id->a_nvals[0]; o.o_groups = NULL; } } + dli = (dynlist_info_t *)on->on_bi.bi_private; for ( ; dli != NULL && rs->sr_err != LDAP_COMPARE_TRUE; dli = dli->dli_next ) { Attribute *a; @@ -1353,6 +1402,15 @@ dynlist_db_open( /* Just a warning */ } + rc = slap_str2ad( "dgAuthz", &ad_dgAuthz, &text ); + if ( rc != LDAP_SUCCESS ) { + snprintf( cr->msg, sizeof( cr->msg), + "unable to fetch attributeDescription \"dgAuthz\": %d (%s)", + rc, text ); + Debug( LDAP_DEBUG_ANY, "dynlist_db_open: %s\n", cr->msg, 0, 0 ); + /* Just a warning */ + } + return 0; } diff --git a/servers/slapd/schema/dyngroup.schema b/servers/slapd/schema/dyngroup.schema index 2e3366f14d74aaddab9ffd7e5ae8faff7e6c3287..b8244b3f493d4a207894f23df6b975943abf78f5 100644 --- a/servers/slapd/schema/dyngroup.schema +++ b/servers/slapd/schema/dyngroup.schema @@ -67,6 +67,13 @@ attributetype ( DynGroupAttr:1 DESC 'Identity to use when processing the memberURL' SUP distinguishedName SINGLE-VALUE ) +attributeType ( DynGroupAttr:2 + NAME 'dgAuthz' + DESC 'Optional authorization rules that determine who is allowed to assume the dgIdentity' + EQUALITY authzMatch + SYNTAX 1.3.6.1.4.1.4203.666.2.7 + X-ORDERED 'VALUES' ) + objectClass ( NetscapeLDAPobjectClass:33 NAME 'groupOfURLs' SUP top STRUCTURAL @@ -79,4 +86,6 @@ objectClass ( NetscapeLDAPobjectClass:33 objectClass ( DynGroupOC:1 NAME 'dgIdentityAux' SUP top AUXILIARY - MAY dgIdentity ) + MAY ( dgIdentity $ dgAuthz ) ) + + diff --git a/tests/data/dynlist.out b/tests/data/dynlist.out index c6b5be3079cc8922acafda9c546b6cf9f028b5e7..370a5dafebaaca28850a677a3c4e9f00db1cb065 100644 --- a/tests/data/dynlist.out +++ b/tests/data/dynlist.out @@ -139,7 +139,7 @@ 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 +dgIdentity: cn=Bjorn Jensen,ou=Information Technology DivisioN,ou=People,dc=ex ample,dc=com member: cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=exam ple,dc=com @@ -156,3 +156,39 @@ member: cn=John Doe,ou=Information Technology Division,ou=People,dc=example,dc 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 +# Testing list search with dgIdentity and dgAuthz anonymously... +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 + +# Testing list search with dgIdentity and dgAuthz as the authorized identity... +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 + diff --git a/tests/scripts/test044-dynlist b/tests/scripts/test044-dynlist index 5ec785021b20e57fb6a324b88e495a53729a5606..e0bb527409e2f8923625cae15621a32725f9fd3b 100755 --- a/tests/scripts/test044-dynlist +++ b/tests/scripts/test044-dynlist @@ -316,7 +316,7 @@ if test $RC != 0 ; then exit $RC fi -CMPDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,$BASEDN" +CMPDN="$BJORNSDN" echo "Testing list compare..." echo "# Testing list compare..." >> $SEARCHOUT $LDAPCOMPARE -h $LOCALHOST -p $PORT1 \ @@ -451,6 +451,42 @@ if test $RC != 0 ; then exit $RC fi +echo "Testing dgAuthz..." + +CMPDN="cn=Bjorn Jensen,ou=Information Technology Division,ou=People,$BASEDN" +$LDAPMODIFY -v -D "$MANAGERDN" -h $LOCALHOST -p $PORT1 -w $PASSWD \ + > $TESTOUT 2>&1 << EOMODS +dn: cn=Dynamic List of Members,$LISTDN +changetype: modify +add: dgAuthz +dgAuthz: dn:$BABSDN +EOMODS + +echo "Testing list search with dgIdentity and dgAuthz anonymously..." +echo "# Testing list search with dgIdentity and dgAuthz anonymously..." >> $SEARCHOUT +$LDAPSEARCH -S "" -b "$LISTDN" -h $LOCALHOST -p $PORT1 \ + '(cn=Dynamic List of Members)' '*' \ + >> $SEARCHOUT 2>&1 +RC=$? +if test $RC != 0 ; then + echo "ldapsearch failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +echo "Testing list search with dgIdentity and dgAuthz as the authorized identity..." +echo "# Testing list search with dgIdentity and dgAuthz as the authorized identity..." >> $SEARCHOUT +$LDAPSEARCH -S "" -b "$LISTDN" -h $LOCALHOST -p $PORT1 \ + -D "$BABSDN" -w bjensen \ + '(cn=Dynamic List of Members)' '*' \ + >> $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