From 8768d99013e1fdc12cc0ea1717709e8f91ac58d1 Mon Sep 17 00:00:00 2001 From: Emmanuel Dreyfus Date: Fri, 9 May 2008 12:59:16 +0000 Subject: [PATCH] Add attribute size and count constraints to slapo-constaint Approved by Ando Usage example: overlay constraint constraint_attribute jpegPhoto size 131072 constraint_attribute userPassword count 3 --- doc/man/man5/slapo-constraint.5 | 12 ++- servers/slapd/overlays/constraint.c | 158 +++++++++++++++++++++++----- 2 files changed, 143 insertions(+), 27 deletions(-) diff --git a/doc/man/man5/slapo-constraint.5 b/doc/man/man5/slapo-constraint.5 index ad80d05df5..1a60c0e244 100644 --- a/doc/man/man5/slapo-constraint.5 +++ b/doc/man/man5/slapo-constraint.5 @@ -31,7 +31,9 @@ directive. Specifies the constraint which should apply to the attribute named as the first parameter. Two types of constraint are currently supported - -.B regex +.B regex , +.B size , +.B count , and .BR uri . @@ -45,6 +47,12 @@ type is an LDAP URI. The URI will be evaluated using an internal search. It must not include a hostname, and it must include a list of attributes to evaluate. +The +.B size +type can be used to enfore a limit on an attribute length, and the +.B count +type limits the count of an attribute. + Any attempt to add or modify an attribute named as part of the constraint overlay specification which does not fit the constraint listed will fail with a @@ -54,6 +62,8 @@ LDAP_CONSTRAINT_VIOLATION error. .RS .nf overlay constraint +constraint_attribute jpegPhoto size 131072 +constraint_attribute userPassword count 3 constraint_attribute mail regex ^[:alnum:]+@mydomain.com$ constraint_attribute title uri ldap:///dc=catalog,dc=example,dc=com?title?sub?(objectClass=titleCatalog) diff --git a/servers/slapd/overlays/constraint.c b/servers/slapd/overlays/constraint.c index 8ce8a0fc6a..7d2bf73aaa 100644 --- a/servers/slapd/overlays/constraint.c +++ b/servers/slapd/overlays/constraint.c @@ -41,6 +41,8 @@ #define REGEX_STR "regex" #define URI_STR "uri" +#define SIZE_STR "size" +#define COUNT_STR "count" /* * Linked list of attribute constraints which we should enforce. @@ -55,6 +57,8 @@ typedef struct constraint { AttributeDescription *ap; regex_t *re; LDAPURLDesc *lud; + size_t size; + size_t count; AttributeDescription **attrs; struct berval val; /* constraint value */ struct berval dn; @@ -129,6 +133,12 @@ constraint_cf_gen( ConfigArgs *c ) } else if (cp->lud) { len += STRLENOF(URI_STR); tstr = URI_STR; + } 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; @@ -216,7 +226,17 @@ constraint_cf_gen( ConfigArgs *c ) return( ARG_BAD_CONF ); } ber_str2bv( c->argv[3], 0, 1, &ap.val ); - } else if ( strcasecmp( c->argv[2], URI_STR ) == 0) { + } else if ( strcasecmp( c->argv[2], SIZE_STR ) == 0 ) { + size_t size; + + if ( ( size = atoi(c->argv[3]) ) != 0 ) + ap.size = size; + } else if ( strcasecmp( c->argv[2], COUNT_STR ) == 0 ) { + size_t count; + + if ( ( count = atoi(c->argv[3]) ) != 0 ) + ap.count = count; + } else if ( strcasecmp( c->argv[2], URI_STR ) == 0 ) { int err; err = ldap_url_parse(c->argv[3], &ap.lud); @@ -281,6 +301,8 @@ constraint_cf_gen( ConfigArgs *c ) a2->re = ap.re; a2->val = ap.val; a2->lud = ap.lud; + a2->size = ap.size; + a2->count = ap.count; if ( a2->lud ) { ber_str2bv(a2->lud->lud_dn, 0, 0, &a2->dn); ber_str2bv(a2->lud->lud_filter, 0, 0, &a2->filter); @@ -323,6 +345,9 @@ constraint_violation( constraint *c, struct berval *bv, Operation *op, SlapReply (regexec(c->re, bv->bv_val, 0, NULL, 0) == REG_NOMATCH)) return 1; /* regular expression violation */ + if ((c->size) && (bv->bv_len > c->size)) + return 1; /* size violation */ + if (c->lud) { Operation nop = *op; slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; @@ -443,10 +468,21 @@ print_message( struct berval *errtext, AttributeDescription *a ) return ret; } +static unsigned +constraint_count_attr(Entry *e, AttributeDescription *ad) +{ + struct Attribute *a; + + if ((a = attr_find(e->e_attrs, ad)) != NULL) + return a->a_numvals; + return 0; +} + static int constraint_add( Operation *op, SlapReply *rs ) { slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + Backend *be = op->o_bd; Attribute *a; constraint *c = on->on_bi.bi_private, *cp; BerVarray b = NULL; @@ -469,35 +505,45 @@ constraint_add( Operation *op, SlapReply *rs ) if (cp->ap != a->a_desc) continue; if ((b = a->a_vals) == NULL) continue; - for(i=0; b[i].bv_val; i++) { - int cv = constraint_violation( cp, &b[i], op, rs); - - if (cv) { - /* violation */ - op->o_bd->bd_info = (BackendInfo *)(on->on_info); - msg = print_message( &rsv, a->a_desc ); - send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, msg ); - ch_free(msg); - return (rs->sr_err); - } - } + Debug(LDAP_DEBUG_TRACE, + "==> constraint_add, " + "a->a_numvals = %d, cp->count = %d\n", + a->a_numvals, cp->count, 0); + + if ((cp->count != 0) && (a->a_numvals > cp->count)) + goto add_violation; + + for(i=0; b[i].bv_val; i++) + if (constraint_violation( cp, &b[i], op, rs)) + goto add_violation; } } /* Default is to just fall through to the normal processing */ return SLAP_CB_CONTINUE; + +add_violation: + op->o_bd->bd_info = (BackendInfo *)(on->on_info); + msg = print_message( &rsv, a->a_desc ); + send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, msg ); + ch_free(msg); + return (rs->sr_err); } + static int constraint_modify( Operation *op, SlapReply *rs ) { 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; Modifications *m; BerVarray b = NULL; int i; struct berval rsv = BER_BVC("modify breaks constraint"); char *msg; + Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, "constraint_modify()", 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, @@ -505,34 +551,94 @@ constraint_modify( Operation *op, SlapReply *rs ) return(rs->sr_err); } + /* Do we need to count attributes? */ + for(cp = c; cp; cp = cp->ap_next) { + if (cp->count != 0) { + int rc; + + 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; + + if (rc != 0 || target_entry == NULL) { + Debug(LDAP_DEBUG_TRACE, + "==> constraint_modify rc = %d\n", + rc, 0, 0); + goto mod_violation; + } + break; + } + } + 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_REPLACE) && + (( m->sml_op & LDAP_MOD_OP ) != LDAP_MOD_DELETE)) continue; /* we only care about ADD and REPLACE modifications */ + /* and DELETE are used to track attribute count */ if ((( b = m->sml_values ) == NULL ) || (b[0].bv_val == NULL)) continue; for(cp = c; cp; cp = cp->ap_next) { if (cp->ap != m->sml_desc) continue; - for(i=0; b[i].bv_val; i++) { - int cv = constraint_violation( cp, &b[i], op, rs); - - if (cv) { - /* violation */ - op->o_bd->bd_info = (BackendInfo *)(on->on_info); - msg = print_message( &rsv, m->sml_desc ); - send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, msg ); - ch_free(msg); - return (rs->sr_err); - } - } + if (cp->count != 0) { + int ca; + + if (m->sml_op == LDAP_MOD_DELETE) + ce = 0; + + for (ca = 0; b[ca].bv_val; ++ca); + + Debug(LDAP_DEBUG_TRACE, + "==> constraint_modify ce = %d, " + "ca = %d, cp->count = %d\n", + ca, ce, cp->count); + + if (m->sml_op == LDAP_MOD_ADD) + if (ca + ce > cp->count) + goto mod_violation; + if (m->sml_op == LDAP_MOD_REPLACE) + if (ca > cp->count) + goto mod_violation; + } + + /* DELETE are to be ignored beyond this point */ + if (( m->sml_op & LDAP_MOD_OP ) == LDAP_MOD_DELETE) + continue; + + for(i=0; b[i].bv_val; i++) + if (constraint_violation( cp, &b[i], op, rs)) + 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; + } return SLAP_CB_CONTINUE; +mod_violation: + /* violation */ + if (target_entry) { + op->o_bd = on->on_info->oi_origdb; + be_entry_release_r(op, target_entry); + op->o_bd = be; + } + op->o_bd->bd_info = (BackendInfo *)(on->on_info); + msg = print_message( &rsv, m->sml_desc ); + send_ldap_error(op, rs, LDAP_CONSTRAINT_VIOLATION, msg ); + ch_free(msg); + return (rs->sr_err); } static int -- 2.39.5