From 47f4343694c8335b590acc28d1e98e07c2dd1293 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Kuzn=C3=ADk?= <ondra@mistotebe.net>
Date: Mon, 15 Sep 2014 22:34:17 +0100
Subject: [PATCH] ITS#7780,ITS#7781 Fix slapo-constraint with 0 count

---
 servers/slapd/overlays/constraint.c | 323 +++++++++++++++-------------
 1 file changed, 178 insertions(+), 145 deletions(-)

diff --git a/servers/slapd/overlays/constraint.c b/servers/slapd/overlays/constraint.c
index e101cd8656..9e68d3b43a 100644
--- a/servers/slapd/overlays/constraint.c
+++ b/servers/slapd/overlays/constraint.c
@@ -62,6 +62,7 @@ typedef struct constraint {
 	Filter *restrict_filter;
 	struct berval restrict_val;
 
+	int type;
 	regex_t *re;
 	LDAPURLDesc *lud;
 	int set;
@@ -74,7 +75,12 @@ typedef struct constraint {
 } constraint;
 
 enum {
-	CONSTRAINT_ATTRIBUTE = 1
+	CONSTRAINT_ATTRIBUTE = 1,
+	CONSTRAINT_COUNT,
+	CONSTRAINT_SIZE,
+	CONSTRAINT_REGEX,
+	CONSTRAINT_SET,
+	CONSTRAINT_URI,
 };
 
 static ConfigDriver constraint_cf_gen;
@@ -143,7 +149,7 @@ constraint_cf_gen( ConfigArgs *c )
 			for (cp=cn; cp; cp=cp->ap_next) {
 				char *s;
 				char *tstr = NULL;
-				int quotes = 0;
+				int quotes = 0, numeric = 0;
 				int j;
 				size_t val;
 				char val_buf[SLAP_TEXT_BUFLEN] = { '\0' };
@@ -156,21 +162,31 @@ constraint_cf_gen( ConfigArgs *c )
 				/* room for commas */
 				bv.bv_len += j - 1;
 
-				if (cp->re) {
-					tstr = REGEX_STR;
-					quotes = 1;
-				} else if (cp->lud) {
-					tstr = URI_STR;
-					quotes = 1;
-				} else if (cp->set) {
-					tstr = SET_STR;
-					quotes = 1;
-				} else if (cp->size) {
-					tstr = SIZE_STR;
-					val = cp->size;
-				} else if (cp->count) {
-					tstr = COUNT_STR;
-					val = cp->count;
+				switch (cp->type) {
+					case CONSTRAINT_COUNT:
+						tstr = COUNT_STR;
+						val = cp->count;
+						numeric = 1;
+						break;
+					case CONSTRAINT_SIZE:
+						tstr = SIZE_STR;
+						val = cp->size;
+						numeric = 1;
+						break;
+					case CONSTRAINT_REGEX:
+						tstr = REGEX_STR;
+						quotes = 1;
+						break;
+					case CONSTRAINT_SET:
+						tstr = SET_STR;
+						quotes = 1;
+						break;
+					case CONSTRAINT_URI:
+						tstr = URI_STR;
+						quotes = 1;
+						break;
+					default:
+						abort();
 				}
 
 				bv.bv_len += strlen(tstr);
@@ -180,8 +196,8 @@ constraint_cf_gen( ConfigArgs *c )
 					bv.bv_len += cp->restrict_val.bv_len + STRLENOF(" restrict=\"\"");
 				}
 
-				if (cp->count || cp->size) {
-					int len = snprintf(val_buf, sizeof(val_buf), "%zd", val);
+				if (numeric) {
+					int len = snprintf(val_buf, sizeof(val_buf), "%zu", val);
 					if (len <= 0) {
 						/* error */
 						return -1;
@@ -199,7 +215,7 @@ constraint_cf_gen( ConfigArgs *c )
 				*s++ = ' ';
 				s = lutil_strcopy( s, tstr );
 				*s++ = ' ';
-				if (cp->count || cp->size) {
+				if (numeric) {
 					s = lutil_strcopy( s, val_buf );
 				} else {
 					if ( quotes ) *s++ = '"';
@@ -283,6 +299,7 @@ constraint_cf_gen( ConfigArgs *c )
 			if ( strcasecmp( c->argv[2], REGEX_STR ) == 0) {
 				int err;
 			
+				ap.type = CONSTRAINT_REGEX;
 				ap.re = ch_malloc( sizeof(regex_t) );
 				if ((err = regcomp( ap.re,
 					c->argv[3], REG_EXTENDED )) != 0) {
@@ -300,17 +317,24 @@ constraint_cf_gen( ConfigArgs *c )
 				ber_str2bv( c->argv[3], 0, 1, &ap.val );
 			} else if ( strcasecmp( c->argv[2], SIZE_STR ) == 0 ) {
 				size_t size;
+				char *endptr;
 
-				if ( ( size = atoi(c->argv[3]) ) != 0 )
-					ap.size = size;	
+				ap.type = CONSTRAINT_SIZE;
+				ap.size = strtoull(c->argv[3], &endptr, 10);
+				if ( *endptr )
+					rc = ARG_BAD_CONF;
 			} else if ( strcasecmp( c->argv[2], COUNT_STR ) == 0 ) {
 				size_t count;
+				char *endptr;
 
-				if ( ( count = atoi(c->argv[3]) ) != 0 )
-					ap.count = count;	
+				ap.type = CONSTRAINT_COUNT;
+				ap.count = strtoull(c->argv[3], &endptr, 10);
+				if ( *endptr )
+					rc = ARG_BAD_CONF;
 			} else if ( strcasecmp( c->argv[2], URI_STR ) == 0 ) {
 				int err;
 			
+				ap.type = CONSTRAINT_URI;
 				err = ldap_url_parse(c->argv[3], &ap.lud);
 				if ( err != LDAP_URL_SUCCESS ) {
 					snprintf( c->cr_msg, sizeof( c->cr_msg ),
@@ -386,6 +410,7 @@ constraint_cf_gen( ConfigArgs *c )
 			} else if ( strcasecmp( c->argv[2], SET_STR ) == 0 ) {
 				ap.set = 1;
 				ber_str2bv( c->argv[3], 0, 1, &ap.val );
+				ap.type = CONSTRAINT_SET;
 
 			} else {
 				snprintf( c->cr_msg, sizeof( c->cr_msg ),
@@ -507,6 +532,7 @@ done:;
 				constraint *a2 = ch_calloc( sizeof(constraint), 1 );
 				a2->ap_next = on->on_bi.bi_private;
 				a2->ap = ap.ap;
+				a2->type = ap.type;
 				a2->re = ap.re;
 				a2->val = ap.val;
 				a2->lud = ap.lud;
@@ -563,120 +589,124 @@ constraint_violation( constraint *c, struct berval *bv, Operation *op )
 {
 	if ((!c) || (!bv)) return LDAP_SUCCESS;
 	
-	if ((c->re) &&
-		(regexec(c->re, bv->bv_val, 0, NULL, 0) == REG_NOMATCH))
-		return LDAP_CONSTRAINT_VIOLATION; /* regular expression violation */
-
-	if ((c->size) && (bv->bv_len > c->size))
-		return LDAP_CONSTRAINT_VIOLATION; /* size violation */
-
-	if (c->lud) {
-		Operation nop = *op;
-		slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
-		slap_callback cb;
-		int i;
-		int found = 0;
-		int rc;
-		size_t len;
-		struct berval filterstr;
-		char *ptr;
-
-		cb.sc_next = NULL;
-		cb.sc_response = constraint_uri_cb;
-		cb.sc_cleanup = NULL;
-		cb.sc_private = &found;
-
-		nop.o_protocol = LDAP_VERSION3;
-		nop.o_tag = LDAP_REQ_SEARCH;
-		nop.o_time = slap_get_time();
-		if (c->lud->lud_dn) {
-			struct berval dn;
-
-			ber_str2bv(c->lud->lud_dn, 0, 0, &dn);
-			nop.o_req_dn = dn;
-			nop.o_req_ndn = dn;
-			nop.o_bd = select_backend(&nop.o_req_ndn, 1 );
-			if (!nop.o_bd) {
-				return LDAP_NO_SUCH_OBJECT; /* unexpected error */
+	switch (c->type) {
+		case CONSTRAINT_SIZE:
+			if (bv->bv_len > c->size)
+				return LDAP_CONSTRAINT_VIOLATION; /* size violation */
+			break;
+		case CONSTRAINT_REGEX:
+			if (regexec(c->re, bv->bv_val, 0, NULL, 0) == REG_NOMATCH)
+				return LDAP_CONSTRAINT_VIOLATION; /* regular expression violation */
+			break;
+		case CONSTRAINT_URI: {
+			Operation nop = *op;
+			slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
+			slap_callback cb;
+			int i;
+			int found = 0;
+			int rc;
+			size_t len;
+			struct berval filterstr;
+			char *ptr;
+
+			cb.sc_next = NULL;
+			cb.sc_response = constraint_uri_cb;
+			cb.sc_cleanup = NULL;
+			cb.sc_private = &found;
+
+			nop.o_protocol = LDAP_VERSION3;
+			nop.o_tag = LDAP_REQ_SEARCH;
+			nop.o_time = slap_get_time();
+			if (c->lud->lud_dn) {
+				struct berval dn;
+
+				ber_str2bv(c->lud->lud_dn, 0, 0, &dn);
+				nop.o_req_dn = dn;
+				nop.o_req_ndn = dn;
+				nop.o_bd = select_backend(&nop.o_req_ndn, 1 );
+				if (!nop.o_bd) {
+					return LDAP_NO_SUCH_OBJECT; /* unexpected error */
+				}
+				if (!nop.o_bd->be_search) {
+					return LDAP_OTHER; /* unexpected error */
+				}
+			} else {
+				nop.o_req_dn = nop.o_bd->be_nsuffix[0];
+				nop.o_req_ndn = nop.o_bd->be_nsuffix[0];
+				nop.o_bd = on->on_info->oi_origdb;
 			}
-			if (!nop.o_bd->be_search) {
-				return LDAP_OTHER; /* unexpected error */
+			nop.o_do_not_cache = 1;
+			nop.o_callback = &cb;
+
+			nop.ors_scope = c->lud->lud_scope;
+			nop.ors_deref = LDAP_DEREF_NEVER;
+			nop.ors_slimit = SLAP_NO_LIMIT;
+			nop.ors_tlimit = SLAP_NO_LIMIT;
+			nop.ors_limit = NULL;
+
+			nop.ors_attrsonly = 0;
+			nop.ors_attrs = slap_anlist_no_attrs;
+
+			len = STRLENOF("(&(") +
+				  c->filter.bv_len +
+				  STRLENOF(")(|");
+
+			for (i = 0; c->attrs[i]; i++) {
+				len += STRLENOF("(") +
+					   c->attrs[i]->ad_cname.bv_len +
+					   STRLENOF("=") +
+					   bv->bv_len +
+					   STRLENOF(")");
 			}
-		} else {
-			nop.o_req_dn = nop.o_bd->be_nsuffix[0];
-			nop.o_req_ndn = nop.o_bd->be_nsuffix[0];
-			nop.o_bd = on->on_info->oi_origdb;
-		}
-		nop.o_do_not_cache = 1;
-		nop.o_callback = &cb;
-
-		nop.ors_scope = c->lud->lud_scope;
-		nop.ors_deref = LDAP_DEREF_NEVER;
-		nop.ors_slimit = SLAP_NO_LIMIT;
-		nop.ors_tlimit = SLAP_NO_LIMIT;
-		nop.ors_limit = NULL;
-
-		nop.ors_attrsonly = 0;
-		nop.ors_attrs = slap_anlist_no_attrs;
-
-		len = STRLENOF("(&(") + 
-			  c->filter.bv_len +
-			  STRLENOF(")(|");
-
-		for (i = 0; c->attrs[i]; i++) {
-			len += STRLENOF("(") +
-				   c->attrs[i]->ad_cname.bv_len +
-				   STRLENOF("=") + 
-				   bv->bv_len +
-				   STRLENOF(")");
-		}
 
-		len += STRLENOF("))");
-		filterstr.bv_len = len;
-		filterstr.bv_val = op->o_tmpalloc(len + 1, op->o_tmpmemctx);
-
-		ptr = filterstr.bv_val +
-			snprintf(filterstr.bv_val, len, "(&(%s)(|", c->lud->lud_filter);
-		for (i = 0; c->attrs[i]; i++) {
-			*ptr++ = '(';
-			ptr = lutil_strcopy( ptr, c->attrs[i]->ad_cname.bv_val );
-			*ptr++ = '=';
-			ptr = lutil_strcopy( ptr, bv->bv_val );
+			len += STRLENOF("))");
+			filterstr.bv_len = len;
+			filterstr.bv_val = op->o_tmpalloc(len + 1, op->o_tmpmemctx);
+
+			ptr = filterstr.bv_val +
+				snprintf(filterstr.bv_val, len, "(&(%s)(|", c->lud->lud_filter);
+			for (i = 0; c->attrs[i]; i++) {
+				*ptr++ = '(';
+				ptr = lutil_strcopy( ptr, c->attrs[i]->ad_cname.bv_val );
+				*ptr++ = '=';
+				ptr = lutil_strcopy( ptr, bv->bv_val );
+				*ptr++ = ')';
+			}
 			*ptr++ = ')';
-		}
-		*ptr++ = ')';
-		*ptr++ = ')';
-		*ptr++ = '\0';
+			*ptr++ = ')';
+			*ptr++ = '\0';
 
-		nop.ors_filterstr = filterstr;
-		nop.ors_filter = str2filter_x(&nop, filterstr.bv_val);
-		if ( nop.ors_filter == NULL ) {
-			Debug( LDAP_DEBUG_ANY,
-				"%s constraint_violation uri filter=\"%s\" invalid\n",
-				op->o_log_prefix, filterstr.bv_val, 0 );
-			rc = LDAP_OTHER;
+			nop.ors_filterstr = filterstr;
+			nop.ors_filter = str2filter_x(&nop, filterstr.bv_val);
+			if ( nop.ors_filter == NULL ) {
+				Debug( LDAP_DEBUG_ANY,
+					"%s constraint_violation uri filter=\"%s\" invalid\n",
+					op->o_log_prefix, filterstr.bv_val, 0 );
+				rc = LDAP_OTHER;
 
-		} else {
-			SlapReply nrs = { REP_RESULT };
+			} else {
+				SlapReply nrs = { REP_RESULT };
 
-			Debug(LDAP_DEBUG_TRACE, 
-				"==> constraint_violation uri filter = %s\n",
-				filterstr.bv_val, 0, 0);
+				Debug(LDAP_DEBUG_TRACE,
+					"==> constraint_violation uri filter = %s\n",
+					filterstr.bv_val, 0, 0);
 
-			rc = nop.o_bd->be_search( &nop, &nrs );
-		
-			Debug(LDAP_DEBUG_TRACE, 
-				"==> constraint_violation uri rc = %d, found = %d\n",
-				rc, found, 0);
-		}
-		op->o_tmpfree(filterstr.bv_val, op->o_tmpmemctx);
+				rc = nop.o_bd->be_search( &nop, &nrs );
 
-		if ((rc != LDAP_SUCCESS) && (rc != LDAP_NO_SUCH_OBJECT)) {
-			return rc; /* unexpected error */
-		}
+				Debug(LDAP_DEBUG_TRACE,
+					"==> constraint_violation uri rc = %d, found = %d\n",
+					rc, found, 0);
+			}
+			op->o_tmpfree(filterstr.bv_val, op->o_tmpmemctx);
 
-		if (!found)
-			return LDAP_CONSTRAINT_VIOLATION; /* constraint violation */
+			if ((rc != LDAP_SUCCESS) && (rc != LDAP_NO_SUCH_OBJECT)) {
+				return rc; /* unexpected error */
+			}
+
+			if (!found)
+				return LDAP_CONSTRAINT_VIOLATION; /* constraint violation */
+			break;
+		}
 	}
 
 	return LDAP_SUCCESS;
@@ -803,22 +833,25 @@ constraint_add( Operation *op, SlapReply *rs )
 				"a->a_numvals = %u, cp->count = %lu\n",
 				a->a_numvals, (unsigned long) cp->count, 0);
 
-			if ((cp->count != 0) && (a->a_numvals > cp->count)) {
-				rc = LDAP_CONSTRAINT_VIOLATION;
-				goto add_violation;
-			}
-
-			for ( i = 0; b[i].bv_val; i++ ) {
-				rc = constraint_violation( cp, &b[i], op );
-				if ( rc ) {
-					goto add_violation;
+			switch (cp->type) {
+				case CONSTRAINT_COUNT:
+					if (a->a_numvals > cp->count)
+						rc = LDAP_CONSTRAINT_VIOLATION;
+					break;
+				case CONSTRAINT_SET:
+					if (acl_match_set(&cp->val, op, op->ora_e, NULL) == 0)
+						rc = LDAP_CONSTRAINT_VIOLATION;
+					break;
+				default:
+					for ( i = 0; b[i].bv_val; i++ ) {
+						rc = constraint_violation( cp, &b[i], op );
+						if ( rc ) {
+							goto add_violation;
+						}
+					}
 				}
-			}
-
-			if (cp->set && acl_match_set(&cp->val, op, op->ora_e, NULL) == 0) {
-				rc = LDAP_CONSTRAINT_VIOLATION;
-				goto add_violation; /* constraint violation */
-			}
+			if ( rc )
+				goto add_violation;
 
 		}
 	}
@@ -946,7 +979,7 @@ constraint_update( Operation *op, SlapReply *rs )
 
 	/* Do we need to count attributes? */
 	for(cp = c; cp; cp = cp->ap_next) {
-		if (cp->count != 0) {
+		if (cp->type == CONSTRAINT_COUNT) {
 			if (rc != 0 || target_entry == NULL) {
 				Debug(LDAP_DEBUG_TRACE, 
 					"==> constraint_update rc = %d DN=\"%s\"%s\n",
@@ -1012,7 +1045,7 @@ constraint_update( Operation *op, SlapReply *rs )
 				}
 			}
 
-			if (cp->set && target_entry) {
+			if (cp->type == CONSTRAINT_SET && target_entry) {
 				if (target_entry_copy == NULL) {
 					Modifications *ml;
 
-- 
GitLab