#define REGEX_STR "regex"
#define URI_STR "uri"
+#define SET_STR "set"
#define SIZE_STR "size"
#define COUNT_STR "count"
typedef struct constraint {
struct constraint *ap_next;
- AttributeDescription *ap;
+ AttributeDescription **ap;
regex_t *re;
LDAPURLDesc *lud;
+ int set;
size_t size;
size_t count;
AttributeDescription **attrs;
ldap_free_urldesc(cp->lud);
if (cp->attrs)
ch_free(cp->attrs);
+ if (cp->ap)
+ ch_free(cp->ap);
ch_free(cp);
}
switch (c->type) {
case CONSTRAINT_ATTRIBUTE:
for (cp=cn; cp; cp=cp->ap_next) {
- int len;
char *s;
char *tstr = NULL;
+ int quotes = 0;
+ int j;
+
+ bv.bv_len = STRLENOF(" ");
+ for (j = 0; cp->ap[j]; j++) {
+ bv.bv_len += cp->ap[j]->ad_cname.bv_len;
+ }
+
+ /* room for commas */
+ bv.bv_len += j - 1;
- len = cp->ap->ad_cname.bv_len + 3;
if (cp->re) {
- len += STRLENOF(REGEX_STR);
tstr = REGEX_STR;
} else if (cp->lud) {
- len += STRLENOF(URI_STR);
tstr = URI_STR;
+ } else if (cp->set) {
+ tstr = SET_STR;
+ quotes = 1;
} else if (cp->size) {
- len += STRLENOF(SIZE_STR);
tstr = SIZE_STR;
} else if (cp->count) {
- len += STRLENOF(COUNT_STR);
tstr = COUNT_STR;
}
- len += cp->val.bv_len;
- s = ch_malloc(len);
+ bv.bv_len += strlen(tstr);
+ bv.bv_len += cp->val.bv_len + 2*quotes;
+
+ s = bv.bv_val = ch_malloc(bv.bv_len + 1);
+
+ s = lutil_strncopy( s, cp->ap[0]->ad_cname.bv_val, cp->ap[0]->ad_cname.bv_len );
+ for (j = 1; cp->ap[j]; j++) {
+ *s++ = ',';
+ s = lutil_strncopy( s, cp->ap[j]->ad_cname.bv_val, cp->ap[j]->ad_cname.bv_len );
+ }
+ *s++ = ' ';
+ s = lutil_strcopy( s, tstr );
+ *s++ = ' ';
+ if ( quotes ) *s++ = '"';
+ s = lutil_strncopy( s, cp->val.bv_val, cp->val.bv_len );
+ if ( quotes ) *s++ = '"';
+ *s = '\0';
- bv.bv_len = snprintf(s, len, "%s %s %s", cp->ap->ad_cname.bv_val,
- tstr, cp->val.bv_val);
- bv.bv_val = s;
rc = value_add_one( &c->rvalue_vals, &bv );
+ if (rc == LDAP_SUCCESS)
+ rc = value_add_one( &c->rvalue_nvals, &bv );
+ ch_free(bv.bv_val);
if (rc) return rc;
- rc = value_add_one( &c->rvalue_nvals, &bv );
- if (rc) return rc;
- ch_free(s);
}
break;
default:
case SLAP_CONFIG_ADD:
case LDAP_MOD_ADD:
switch (c->type) {
- case CONSTRAINT_ATTRIBUTE:
- if ( slap_str2ad( c->argv[1], &ap.ap, &text ) ) {
- snprintf( c->cr_msg, sizeof( c->cr_msg ),
- "%s <%s>: %s\n", c->argv[0], c->argv[1], text );
- Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
- "%s: %s\n", c->log, c->cr_msg, 0 );
- return( ARG_BAD_CONF );
+ case CONSTRAINT_ATTRIBUTE: {
+ int j;
+ char **attrs = ldap_str2charray( c->argv[1], "," );
+
+ for ( j = 0; attrs[j]; j++)
+ /* just count */ ;
+ ap.ap = ch_calloc( sizeof(AttributeDescription*), j + 1 );
+ for ( j = 0; attrs[j]; j++) {
+ if ( slap_str2ad( attrs[j], &ap.ap[j], &text ) ) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "%s <%s>: %s\n", c->argv[0], attrs[j], text );
+ Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
+ "%s: %s\n", c->log, c->cr_msg, 0 );
+ ldap_memvfree((void**)attrs);
+ return( ARG_BAD_CONF );
+ }
}
+ ldap_memvfree((void**)attrs);
if ( strcasecmp( c->argv[2], REGEX_STR ) == 0) {
int err;
}
ber_str2bv( c->argv[3], 0, 1, &ap.val );
+
+ } else if ( strcasecmp( c->argv[2], SET_STR ) == 0 ) {
+ ap.set = 1;
+ ber_str2bv( c->argv[3], 0, 1, &ap.val );
+
} else {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"%s %s: Unknown constraint type: %s",
a2->re = ap.re;
a2->val = ap.val;
a2->lud = ap.lud;
+ a2->set = ap.set;
a2->size = ap.size;
a2->count = ap.count;
if ( a2->lud ) {
}
a2->attrs = ap.attrs;
on->on_bi.bi_private = a2;
- break;
+ } break;
default:
abort();
break;
return LDAP_CONSTRAINT_VIOLATION; /* constraint violation */
}
-
+
return LDAP_SUCCESS;
}
if (is_at_operational(a->a_desc->ad_type)) continue;
for(cp = c; cp; cp = cp->ap_next) {
- if (cp->ap != a->a_desc) continue;
+ int j;
+ for (j = 0; cp->ap[j]; j++) {
+ if (cp->ap[j] == a->a_desc) break;
+ }
+ if (cp->ap[j] == NULL) continue;
if ((b = a->a_vals) == NULL) continue;
Debug(LDAP_DEBUG_TRACE,
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 */
+ }
+
}
}
+
/* Default is to just fall through to the normal processing */
return SLAP_CB_CONTINUE;
slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
Backend *be = op->o_bd;
constraint *c = on->on_bi.bi_private, *cp;
- Entry *target_entry = NULL;
+ Entry *target_entry = NULL, *target_entry_copy = NULL;
Modifications *m;
BerVarray b = NULL;
int i;
int rc;
char *msg = NULL;
- Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "constraint_modify()", 0,0,0);
+ Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "constraint_modify()\n", 0,0,0);
if ((m = op->orm_modlist) == NULL) {
op->o_bd->bd_info = (BackendInfo *)(on->on_info);
send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
/* Do we need to count attributes? */
for(cp = c; cp; cp = cp->ap_next) {
- if (cp->count != 0) {
-
+ if (cp->count != 0 || cp->set) {
op->o_bd = on->on_info->oi_origdb;
rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &target_entry );
op->o_bd = be;
for(;m; m = m->sml_next) {
int ce = 0;
- /* Get this attribute count, if needed */
- if (target_entry)
- ce = constraint_count_attr(target_entry, m->sml_desc);
-
if (is_at_operational( m->sml_desc->ad_type )) continue;
+
if ((( m->sml_op & LDAP_MOD_OP ) != LDAP_MOD_ADD) &&
(( m->sml_op & LDAP_MOD_OP ) != LDAP_MOD_REPLACE) &&
(( m->sml_op & LDAP_MOD_OP ) != LDAP_MOD_DELETE))
if ((( b = m->sml_values ) == NULL ) || (b[0].bv_val == NULL))
continue;
+ /* Get this attribute count, if needed */
+ if (target_entry)
+ ce = constraint_count_attr(target_entry, m->sml_desc);
+
for(cp = c; cp; cp = cp->ap_next) {
- if (cp->ap != m->sml_desc) continue;
+ int j;
+ for (j = 0; cp->ap[j]; j++) {
+ if (cp->ap[j] == m->sml_desc) {
+ break;
+ }
+ }
+ if (cp->ap[j] == NULL) continue;
if (cp->count != 0) {
int ca;
goto mod_violation;
}
}
+
+ if (cp->set && target_entry) {
+ if (target_entry_copy == NULL) {
+ Modifications *ml;
+
+ target_entry_copy = entry_dup(target_entry);
+
+ /* apply modifications, in an attempt
+ * to estimate what the entry would
+ * look like in case all modifications
+ * pass */
+ for ( ml = op->orm_modlist; ml; ml = ml->sml_next ) {
+ Modification *mod = &ml->sml_mod;
+ const char *text;
+ char textbuf[SLAP_TEXT_BUFLEN];
+ size_t textlen = sizeof(textbuf);
+ int err;
+
+ switch ( mod->sm_op ) {
+ case LDAP_MOD_ADD:
+ err = modify_add_values( target_entry_copy,
+ mod, get_permissiveModify(op),
+ &text, textbuf, textlen );
+ break;
+
+ case LDAP_MOD_DELETE:
+ err = modify_delete_values( target_entry_copy,
+ mod, get_permissiveModify(op),
+ &text, textbuf, textlen );
+ break;
+
+ case LDAP_MOD_REPLACE:
+ err = modify_replace_values( target_entry_copy,
+ mod, get_permissiveModify(op),
+ &text, textbuf, textlen );
+ break;
+
+ case LDAP_MOD_INCREMENT:
+ err = modify_increment_values( target_entry_copy,
+ mod, get_permissiveModify(op),
+ &text, textbuf, textlen );
+ break;
+
+ case SLAP_MOD_SOFTADD:
+ mod->sm_op = LDAP_MOD_ADD;
+ err = modify_add_values( target_entry_copy,
+ mod, get_permissiveModify(op),
+ &text, textbuf, textlen );
+ mod->sm_op = SLAP_MOD_SOFTADD;
+ if ( err == LDAP_TYPE_OR_VALUE_EXISTS ) {
+ err = LDAP_SUCCESS;
+ }
+ break;
+
+ default:
+ err = LDAP_OTHER;
+ break;
+ }
+
+ if ( err != LDAP_SUCCESS ) {
+ rc = err;
+ goto mod_violation;
+ }
+ }
+ }
+
+
+ if ( acl_match_set(&cp->val, op, target_entry_copy, NULL) == 0) {
+ rc = LDAP_CONSTRAINT_VIOLATION;
+ goto mod_violation;
+ }
+ }
}
}
-
+
if (target_entry) {
op->o_bd = on->on_info->oi_origdb;
be_entry_release_r(op, target_entry);
op->o_bd = be;
}
+
+ if (target_entry_copy) {
+ entry_free(target_entry_copy);
+ }
+
return SLAP_CB_CONTINUE;
mod_violation:
be_entry_release_r(op, target_entry);
op->o_bd = be;
}
+
+ if (target_entry_copy) {
+ entry_free(target_entry_copy);
+ }
+
op->o_bd->bd_info = (BackendInfo *)(on->on_info);
if ( rc == LDAP_CONSTRAINT_VIOLATION ) {
msg = print_message( &rsv, m->sml_desc );