From b816c6d8df45960f60d52d05c99b26a7f05cc6f1 Mon Sep 17 00:00:00 2001
From: Quanah Gibson-Mount <quanah@openldap.org>
Date: Tue, 11 Nov 2008 21:51:53 +0000
Subject: [PATCH] ITS#5572

---
 CHANGES                    |  1 +
 servers/slapd/acl.c        | 36 ++++++++++++++++++++++++++++--------
 servers/slapd/aclparse.c   | 11 ++---------
 servers/slapd/backend.c    |  9 +++------
 servers/slapd/bconfig.c    | 23 ++++++-----------------
 servers/slapd/config.c     |  2 +-
 servers/slapd/proto-slap.h |  2 +-
 servers/slapd/slap.h       |  3 ++-
 8 files changed, 44 insertions(+), 43 deletions(-)

diff --git a/CHANGES b/CHANGES
index 0b266a2df5..4bb5f22edb 100644
--- a/CHANGES
+++ b/CHANGES
@@ -8,6 +8,7 @@ OpenLDAP 2.4.13 Engineering
 	Fixed libldap interaction with GnuTLS CN IP-based matches (ITS#5789)
 	Fixed libldap Ipv6 detection (ITS#5739)
 	Fixed slapd acl checks on ADD (ITS#4556,ITS#5723)
+	Fixed slapd acl application to newly created backends (ITS#5572)
 	Added slapd keyword add_content_acl for add checks (ITS#4556,ITS#5723)
 	Fixed slapd config backend olcLogFile support (ITS#5765)
 	Fixed slapd contextCSN pending list (ITS#5709)
diff --git a/servers/slapd/acl.c b/servers/slapd/acl.c
index a9c2a79155..c04f3044b0 100644
--- a/servers/slapd/acl.c
+++ b/servers/slapd/acl.c
@@ -138,6 +138,7 @@ slap_access_allowed(
 	slap_access_t			access_level;
 	const char			*attr;
 	regmatch_t			matches[MAXREMATCHES];
+	AccessControlState	acl_state = ACL_STATE_INIT;
 
 	assert( op != NULL );
 	assert( e != NULL );
@@ -179,7 +180,7 @@ slap_access_allowed(
 	}
 
 	/* use backend default access if no backend acls */
-	if ( op->o_bd->be_acl == NULL ) {
+	if ( op->o_bd->be_acl == NULL && frontendDB->be_acl == NULL ) {
 		int	i;
 
 		Debug( LDAP_DEBUG_ACL,
@@ -201,15 +202,22 @@ slap_access_allowed(
 	ret = 0;
 	control = ACL_BREAK;
 
-	if ( state && state->as_vd_ad == desc ) {
+	if ( state == NULL )
+		state = &acl_state;
+	if ( state->as_vd_ad == desc ) {
 		a = state->as_vd_acl;
 		count = state->as_vd_acl_count;
-
+		if ( state->as_fe_done )
+			state->as_fe_done--;
 	} else {
-		if ( state ) state->as_vi_acl = NULL;
+		state->as_vi_acl = NULL;
+
 		a = NULL;
 		count = 0;
 	}
+	if ( a == NULL )
+		state->as_fe_done = 0;
+
 	ACL_PRIV_ASSIGN( mask, *maskp );
 	memset( matches, '\0', sizeof( matches ) );
 
@@ -476,13 +484,14 @@ slap_acl_get(
 	assert( e != NULL );
 	assert( count != NULL );
 	assert( desc != NULL );
+	assert( state != NULL );
 
 	attr = desc->ad_cname.bv_val;
 
 	assert( attr != NULL );
 
 	if( a == NULL ) {
-		if( op->o_bd == NULL ) {
+		if( op->o_bd == NULL || op->o_bd->be_acl == NULL ) {
 			a = frontendDB->be_acl;
 		} else {
 			a = op->o_bd->be_acl;
@@ -490,7 +499,8 @@ slap_acl_get(
 		prev = NULL;
 
 		assert( a != NULL );
-
+		if ( a == frontendDB->be_acl )
+			state->as_fe_done = 1;
 	} else {
 		prev = a;
 		a = a->acl_next;
@@ -498,9 +508,13 @@ slap_acl_get(
 
 	dnlen = e->e_nname.bv_len;
 
+ retry:
 	for ( ; a != NULL; prev = a, a = a->acl_next ) {
 		(*count) ++;
 
+		if ( a != frontendDB->be_acl && state->as_fe_done )
+			state->as_fe_done++;
+
 		if ( a->acl_dn_pat.bv_len || ( a->acl_dn_style != ACL_STYLE_REGEX )) {
 			if ( a->acl_dn_style == ACL_STYLE_REGEX ) {
 				Debug( LDAP_DEBUG_ACL, "=> dnpat: [%d] %s nsub: %d\n", 
@@ -567,7 +581,7 @@ slap_acl_get(
 				continue;
 			}
 
-			if( state && !( state->as_recorded & ACL_STATE_RECORDED_VD )) {
+			if( !( state->as_recorded & ACL_STATE_RECORDED_VD )) {
 				state->as_recorded |= ACL_STATE_RECORDED_VD;
 				state->as_vd_acl = prev;
 				state->as_vd_acl_count = *count - 1;
@@ -649,6 +663,12 @@ slap_acl_get(
 		return a;
 	}
 
+	if ( !state->as_fe_done ) {
+		state->as_fe_done = 1;
+		a = frontendDB->be_acl;
+		goto retry;
+	}
+
 	Debug( LDAP_DEBUG_ACL, "<= acl_get: done.\n", 0, 0, 0 );
 	return( NULL );
 }
@@ -1856,7 +1876,7 @@ acl_check_modlist(
 	}
 
 	/* use backend default access if no backend acls */
-	if( op->o_bd != NULL && op->o_bd->be_acl == NULL ) {
+	if( op->o_bd != NULL && op->o_bd->be_acl == NULL && frontendDB->be_acl == NULL ) {
 		Debug( LDAP_DEBUG_ACL,
 			"=> access_allowed: backend default %s access %s to \"%s\"\n",
 			access2str( ACL_WRITE ),
diff --git a/servers/slapd/aclparse.c b/servers/slapd/aclparse.c
index 29910379d3..1679f2b0e8 100644
--- a/servers/slapd/aclparse.c
+++ b/servers/slapd/aclparse.c
@@ -2449,19 +2449,12 @@ acl_free( AccessControl *a )
 	free( a );
 }
 
-/* Because backend_startup uses acl_append to tack on the global_acl to
- * the end of each backend's acl, we cannot just take one argument and
- * merrily free our way to the end of the list. backend_destroy calls us
- * with the be_acl in arg1, and global_acl in arg2 to give us a stopping
- * point. config_destroy calls us with global_acl in arg1 and NULL in
- * arg2, so we then proceed to polish off the global_acl.
- */
 void
-acl_destroy( AccessControl *a, AccessControl *end )
+acl_destroy( AccessControl *a )
 {
 	AccessControl *n;
 
-	for ( ; a && a != end; a = n ) {
+	for ( ; a; a = n ) {
 		n = a->acl_next;
 		acl_free( a );
 	}
diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c
index 3754a258f2..0a573ca1a1 100644
--- a/servers/slapd/backend.c
+++ b/servers/slapd/backend.c
@@ -261,8 +261,6 @@ int backend_startup(Backend *be)
 				return rc;
 			}
 		}
-		/* append global access controls */
-		acl_append( &be->be_acl, frontendDB->be_acl, -1 );
 
 		return backend_startup_one( be, &cr );
 	}
@@ -310,8 +308,6 @@ int backend_startup(Backend *be)
 				"has no suffix\n",
 				i, be->bd_info->bi_type, 0 );
 		}
-		/* append global access controls */
-		acl_append( &be->be_acl, frontendDB->be_acl, -1 );
 
 		rc = backend_startup_one( be, &cr );
 
@@ -453,7 +449,7 @@ void backend_destroy_one( BackendDB *bd, int dynamic )
 	if ( !BER_BVISNULL( &bd->be_rootpw ) ) {
 		free( bd->be_rootpw.bv_val );
 	}
-	acl_destroy( bd->be_acl, frontendDB->be_acl );
+	acl_destroy( bd->be_acl );
 	limits_destroy( bd->be_limits );
 	if ( !BER_BVISNULL( &bd->be_update_ndn ) ) {
 		ch_free( bd->be_update_ndn.bv_val );
@@ -504,7 +500,8 @@ int backend_destroy(void)
 		if ( !BER_BVISNULL( &bd->be_rootpw ) ) {
 			free( bd->be_rootpw.bv_val );
 		}
-		acl_destroy( bd->be_acl, frontendDB->be_acl );
+		acl_destroy( bd->be_acl );
+		frontendDB = NULL;
 	}
 
 	return 0;
diff --git a/servers/slapd/bconfig.c b/servers/slapd/bconfig.c
index 0d1431923b..8c1a9b91db 100644
--- a/servers/slapd/bconfig.c
+++ b/servers/slapd/bconfig.c
@@ -979,12 +979,7 @@ config_generic(ConfigArgs *c) {
 			AccessControl *a;
 			char *src, *dst, ibuf[11];
 			struct berval bv, abv;
-			AccessControl *end;
-			if ( c->be == frontendDB )
-				end = NULL;
-			else
-				end = frontendDB->be_acl;
-			for (i=0, a=c->be->be_acl; a && a != end; i++,a=a->acl_next) {
+			for (i=0, a=c->be->be_acl; a; i++,a=a->acl_next) {
 				abv.bv_len = snprintf( ibuf, sizeof( ibuf ), SLAP_X_ORDERED_FMT, i );
 				if ( abv.bv_len >= sizeof( ibuf ) ) {
 					ber_bvarray_free_x( c->rvalue_vals, NULL );
@@ -1220,13 +1215,8 @@ config_generic(ConfigArgs *c) {
 
 		case CFG_ACL:
 			if ( c->valx < 0 ) {
-				AccessControl *end;
-				if ( c->be == frontendDB )
-					end = NULL;
-				else
-					end = frontendDB->be_acl;
-				acl_destroy( c->be->be_acl, end );
-				c->be->be_acl = end;
+				acl_destroy( c->be->be_acl );
+				c->be->be_acl = NULL;
 
 			} else {
 				AccessControl **prev, *a;
@@ -1691,11 +1681,10 @@ sortval_reject:
 		case CFG_ACL:
 			/* Don't append to the global ACL if we're on a specific DB */
 			i = c->valx;
-			if ( c->be != frontendDB && frontendDB->be_acl && c->valx == -1 ) {
+			if ( c->valx == -1 ) {
 				AccessControl *a;
 				i = 0;
-				for ( a=c->be->be_acl; a && a != frontendDB->be_acl;
-					a = a->acl_next )
+				for ( a=c->be->be_acl; a; a = a->acl_next )
 					i++;
 			}
 			if ( parse_acl(c->be, c->fname, c->lineno, c->argc, c->argv, i ) ) {
@@ -5920,7 +5909,7 @@ config_back_db_open( BackendDB *be, ConfigReply *cr )
 	/* If we have no explicitly configured ACLs, don't just use
 	 * the global ACLs. Explicitly deny access to everything.
 	 */
-	if ( frontendDB->be_acl && be->be_acl == frontendDB->be_acl ) {
+	if ( !be->be_acl ) {
 		parse_acl(be, "config_back_db_open", 0, 6, (char **)defacl, 0 );
 	}
 
diff --git a/servers/slapd/config.c b/servers/slapd/config.c
index 368fb9cef6..a81ab852c9 100644
--- a/servers/slapd/config.c
+++ b/servers/slapd/config.c
@@ -1984,7 +1984,7 @@ config_destroy( )
 		if ( frontendDB->be_schemadn.bv_val )
 			free( frontendDB->be_schemadn.bv_val );
 		if ( frontendDB->be_acl )
-			acl_destroy( frontendDB->be_acl, NULL );
+			acl_destroy( frontendDB->be_acl );
 	}
 	free( line );
 	if ( slapd_args_file )
diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h
index 1d08b5488a..560ffc3f2d 100644
--- a/servers/slapd/proto-slap.h
+++ b/servers/slapd/proto-slap.h
@@ -111,7 +111,7 @@ LDAP_SLAPD_F (slap_access_t) str2access LDAP_P(( const char *str ));
 LDAP_SLAPD_F (char *) accessmask2str LDAP_P(( slap_mask_t mask, char*, int debug ));
 LDAP_SLAPD_F (slap_mask_t) str2accessmask LDAP_P(( const char *str ));
 LDAP_SLAPD_F (void) acl_unparse LDAP_P(( AccessControl*, struct berval* ));
-LDAP_SLAPD_F (void) acl_destroy LDAP_P(( AccessControl*, AccessControl* ));
+LDAP_SLAPD_F (void) acl_destroy LDAP_P(( AccessControl* ));
 LDAP_SLAPD_F (void) acl_free LDAP_P(( AccessControl *a ));
 
 
diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h
index ae7d51b8d6..9a699456d3 100644
--- a/servers/slapd/slap.h
+++ b/servers/slapd/slap.h
@@ -1542,9 +1542,10 @@ typedef struct AccessControlState {
 	slap_acl_state_t as_recorded;
 	int as_vd_acl_count;
 	int as_result;
+	int as_fe_done;
 } AccessControlState;
 #define ACL_STATE_INIT { NULL, NULL, NULL, \
-	ACL_STATE_NOT_RECORDED, 0, 0 }
+	ACL_STATE_NOT_RECORDED, 0, 0, 0 }
 
 /*
  * Backend-info
-- 
GitLab