[Date Prev][Date Next] [Chronological] [Thread] [Top]

Re: "dynamic" acls



Hi,


On Thursday 22 January 2004 11:42, Turbo Fredriksson wrote:
> >>>>> "Quanah" == Quanah Gibson-Mount <quanah@stanford.edu> writes:
>     Quanah> ACI's work for some environments, but they definitely
>     Quanah> won't work for mine, where ACL's are all entirely tree
>     Quanah> based, not entry based.  Maybe they will work for the
>     Quanah> person who wants that functionality though.
>
> Tree based ACL can be 'simulated' with ACI's. It's just a matter
> of making sure your administration program can recursivly modify
> ACI's. It's not easy, but it CAN be done.

Not to forget: there is the subtree ACI patch by Ralf Haferkamp 
which should be in 2.2.

I've tried to backport it to 2.1.26 and I'd be grateful for feedback.

Peter
-- 
Peter Marschall
eMail: peter@adpm.de
# patch from OpenLDAP mailing list submitted by Ralf Haferkamp in July 2003
# backported from 2.2 HEAD to 2.1.x and tweaked a bit by Peter Marschall
--- servers/slapd/acl.c	22 May 2003 07:22:41 -0000	1.189
+++ servers/slapd/acl.c	Wed Sep 10 19:45:52 2003
@@ -24,6 +24,7 @@
  */
 static struct berval 
 	aci_bv_entry 		= BER_BVC("entry"),
+	aci_bv_children 	= BER_BVC("children"),
 	aci_bv_br_entry		= BER_BVC("[entry]"),
 	aci_bv_br_all		= BER_BVC("[all]"),
 	aci_bv_access_id 	= BER_BVC("access-id"),
@@ -73,7 +74,8 @@
 	struct berval *aci,
 	regmatch_t *matches,
 	slap_access_t *grant,
-	slap_access_t *deny );
+	slap_access_t *deny,
+	struct berval *scope);
 #endif
 
 static int	regex_matches(
@@ -568,6 +570,7 @@
 	Access	*b;
 #ifdef LDAP_DEBUG
 	char accessmaskbuf[ACCESSMASK_MAXLEN];
+	char accessmaskbuf1[ACCESSMASK_MAXLEN];
 #endif
 	const char *attr;
 
@@ -1068,6 +1071,9 @@
 		if ( b->a_aci_at != NULL ) {
 			Attribute	*at;
 			slap_access_t grant, deny, tgrant, tdeny;
+			struct berval parent_ndn, old_parent_ndn;
+			BerVarray bvals = NULL;
+			int ret,stop;
 
 			/* this case works different from the others above.
 			 * since aci's themselves give permissions, we need
@@ -1086,31 +1092,91 @@
 				continue;
 			}
 
-			/* get the aci attribute */
-			at = attr_find( e->e_attrs, b->a_aci_at );
-			if ( at == NULL ) {
-				continue;
-			}
-
-			ACL_RECORD_VALUE_STATE;
-
 			/* start out with nothing granted, nothing denied */
 			ACL_INIT(tgrant);
 			ACL_INIT(tdeny);
 
+			/* get the aci attribute */
+			at = attr_find( e->e_attrs, b->a_aci_at );
+			if ( at != NULL ) {
+				ACL_RECORD_VALUE_STATE;
 			/* the aci is an multi-valued attribute.  The
 			 * rights are determined by OR'ing the individual
 			 * rights given by the acis.
 			 */
 			for ( i = 0; at->a_vals[i].bv_val != NULL; i++ ) {
-				if (aci_mask( be, conn, op,
-					e, desc, val, &at->a_vals[i],
-					matches, &grant, &deny ) != 0)
+					if (aci_mask( be, conn, op,
+						e, desc, val,
+						&at->a_vals[i],
+						matches, &grant, &deny, &aci_bv_entry ) != 0)
 				{
 					tgrant |= grant;
 					tdeny |= deny;
 				}
 			}
+				Debug(LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
+					accessmask2str(tgrant,accessmaskbuf),
+					accessmask2str(tdeny, accessmaskbuf1), 0);
+
+			}
+			/* If the entry level aci didn't contain anything valid for the
+			 * current operation, climb up the tree and evaluate the
+			 * acis with scope set to subtree
+			 */
+			if ( (tgrant == ACL_PRIV_NONE) && (tdeny == ACL_PRIV_NONE) ){
+				dnParent(&(e->e_nname), &parent_ndn);
+				while ( parent_ndn.bv_val != old_parent_ndn.bv_val ){
+					old_parent_ndn = parent_ndn;
+					Debug(LDAP_DEBUG_ACL, "checking ACI of %s\n", parent_ndn.bv_val, 0, 0);
+					ret=backend_attribute(be, NULL, op, e, &parent_ndn, b->a_aci_at, &bvals);
+					switch(ret){
+						case LDAP_SUCCESS :
+							if(bvals){
+								for( i = 0; bvals[i].bv_val != NULL; i++){
+									ACL_RECORD_VALUE_STATE;
+									if (aci_mask(be, conn, op, e, desc, val, &bvals[i], matches,
+											&grant, &deny, &aci_bv_children) != 0) {
+										tgrant |= grant;
+										tdeny |= deny;
+										/* evaluation stops as soon as either a "deny" or a
+										 * "grant" directive matches.
+										 */
+										if( (tgrant != ACL_PRIV_NONE) || (tdeny != ACL_PRIV_NONE) ){
+											stop=1;
+										}
+									}
+									Debug(LDAP_DEBUG_ACL, "<= aci_mask grant %s deny %s\n",
+										accessmask2str(tgrant,accessmaskbuf),
+										accessmask2str(tdeny, accessmaskbuf1), 0);
+								}
+							}
+							stop=0;
+							break;
+						case LDAP_NO_SUCH_ATTRIBUTE:
+							/* just go on if the aci-Attribute is not present in
+							 * the current entry
+							 */
+							Debug(LDAP_DEBUG_ACL, "no such attribute\n", 0, 0, 0);
+							stop=0;
+							break;
+						case LDAP_NO_SUCH_OBJECT:
+							/* We have reached the base object */
+							Debug(LDAP_DEBUG_ACL, "no such object\n", 0, 0, 0);
+							stop=1;
+							break;
+						default:
+							stop=1;
+							break;
+					}
+					if(stop){
+						break;
+					}
+					dnParent(&old_parent_ndn, &parent_ndn);
+				}
+			}
+
+
+
 
 			/* remove anything that the ACL clause does not allow */
 			tgrant &= b->a_access_mask & ACL_PRIV_MASK;
@@ -1730,7 +1796,8 @@
     struct berval	*aci,
 	regmatch_t		*matches,
 	slap_access_t	*grant,
-	slap_access_t	*deny
+	slap_access_t	*deny,
+	struct berval	*scope
 )
 {
     struct berval bv, perms, sdn;
@@ -1749,7 +1816,6 @@
 
 	   For now, this routine only supports scope=entry.
 	 */
-
 	/* check that the aci has all 5 components */
 	if (aci_get_part(aci, 4, '#', NULL) < 0)
 		return(0);
@@ -1758,9 +1824,9 @@
 	if (aci_get_part(aci, 0, '#', &bv) < 0)
 		return(0);
 
-	/* check that the scope is "entry" */
+	/* check that the scope matches */
 	if (aci_get_part(aci, 1, '#', &bv) < 0
-		|| ber_bvstrcasecmp( &aci_bv_entry, &bv ) != 0)
+		|| ber_bvstrcasecmp( scope, &bv ) != 0)
 	{
 		return(0);
 	}