mirror of
https://git.openldap.org/openldap/openldap.git
synced 2026-01-06 15:10:22 -05:00
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
This commit is contained in:
parent
9ce205818e
commit
8768d99013
2 changed files with 143 additions and 27 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue