Commit 2ad1caaa authored by Quanah Gibson-Mount's avatar Quanah Gibson-Mount
Browse files

ITS#5702

parent 568be260
......@@ -4,6 +4,7 @@ OpenLDAP 2.4.13 Engineering
Fixed liblutil hex conversion (ITS#5699)
Added slapd support for certificateListExactMatch from RFC4523 (ITS#5700)
Fixed slapd-bdb/hdb invalid db crash (ITS#5698)
Added slapo-constraint "set" type (ITS#5702)
Added slapo-translucent try local bind when remote fails (ITS#5656)
OpenLDAP 2.4.12 Release (2008/10/12)
......
......@@ -27,15 +27,16 @@ It should appear after the
.B overlay
directive.
.TP
.B constraint_attribute <attribute_name> <type> <value>
.B constraint_attribute <attribute_name>[,...] <type> <value>
Specifies the constraint which should apply to the attribute named as
the first parameter.
Two types of constraint are currently supported -
.B regex ,
.B size ,
.B count ,
.BR regex ,
.BR size ,
.BR count ,
.BR uri ,
and
.BR uri .
.BR set .
The parameter following the
.B regex
......@@ -47,6 +48,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 parameter following the
.B set
type is a string that is interpreted according to the syntax in use
for ACL sets. This allows to construct constraints based on the contents
of the entry.
The
.B size
type can be used to enforce a limit on an attribute length, and the
......@@ -67,8 +74,11 @@ 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)
constraint_attribute cn,sn,givenName set
"(this/givenName + [ ] + this/sn) & this/cn"
.fi
.RE
A specification like the above would reject any
.B mail
attribute which did not look like
......@@ -80,6 +90,13 @@ attribute whose values were not listed in the
attribute of any
.B titleCatalog
entries in the given scope.
Finally, it requires the values of the attribute
.B cn
to be constructed by pairing values of the attributes
.B sn
and
.BR givenName ,
separated by a space.
.RE
.SH FILES
.TP
......
......@@ -41,6 +41,7 @@
#define REGEX_STR "regex"
#define URI_STR "uri"
#define SET_STR "set"
#define SIZE_STR "size"
#define COUNT_STR "count"
......@@ -54,9 +55,10 @@
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;
......@@ -104,6 +106,8 @@ constraint_free( constraint *cp )
ldap_free_urldesc(cp->lud);
if (cp->attrs)
ch_free(cp->attrs);
if (cp->ap)
ch_free(cp->ap);
ch_free(cp);
}
......@@ -122,36 +126,55 @@ constraint_cf_gen( ConfigArgs *c )
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:
......@@ -198,14 +221,24 @@ constraint_cf_gen( ConfigArgs *c )
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;
......@@ -294,6 +327,11 @@ constraint_cf_gen( ConfigArgs *c )
}
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",
......@@ -309,6 +347,7 @@ constraint_cf_gen( ConfigArgs *c )
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 ) {
......@@ -317,7 +356,7 @@ constraint_cf_gen( ConfigArgs *c )
}
a2->attrs = ap.attrs;
on->on_bi.bi_private = a2;
break;
} break;
default:
abort();
break;
......@@ -468,7 +507,7 @@ constraint_violation( constraint *c, struct berval *bv, Operation *op, SlapReply
return LDAP_CONSTRAINT_VIOLATION; /* constraint violation */
}
return LDAP_SUCCESS;
}
......@@ -518,7 +557,11 @@ constraint_add( Operation *op, SlapReply *rs )
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,
......@@ -537,8 +580,15 @@ constraint_add( Operation *op, SlapReply *rs )
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;
......@@ -559,7 +609,7 @@ 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;
Entry *target_entry = NULL, *target_entry_copy = NULL;
Modifications *m;
BerVarray b = NULL;
int i;
......@@ -567,7 +617,7 @@ constraint_modify( Operation *op, SlapReply *rs )
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,
......@@ -577,8 +627,7 @@ constraint_modify( Operation *op, SlapReply *rs )
/* 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;
......@@ -600,11 +649,8 @@ constraint_modify( Operation *op, SlapReply *rs )
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))
......@@ -614,8 +660,18 @@ constraint_modify( Operation *op, SlapReply *rs )
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;
......@@ -655,14 +711,91 @@ constraint_modify( Operation *op, SlapReply *rs )
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:
......@@ -672,6 +805,11 @@ 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 );
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment