ITS#4987 extensions from Emmanuel Dreyfus manu @ netbsd.org with major

cleanups
This commit is contained in:
Howard Chu 2007-12-15 11:12:56 +00:00
parent da53cd0c40
commit 8a622361d1
2 changed files with 502 additions and 295 deletions

View File

@ -1,13 +1,15 @@
.TH SLAPO-CONSTRAINT 5 "RELEASEDATE" "OpenLDAP LDVERSION"
.\" Copyright 2005-2006 Hewlett-Packard Company
.\" Copyright 2006-2007 The OpenLDAP Foundation All Rights Reserved.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.\" $OpenLDAP$
.SH NAME
slapo-constraint \- Attribute Constraint Overlay to slapd
.SH SYNOPSIS
ETCDIR/slapd.conf
.SH DESCRIPTION
The constraint overlay is used to enforce a regular expression
constraint on all values of specified attributes. Attributes can
The constraint overlay is used to ensure that attribute values match
some constraints beyond basic LDAP syntax. Attributes can
have multiple constraints placed upon them, and all must be satisfied
when modifying an attribute value under constraint.
.LP
@ -25,33 +27,55 @@ directive.
.B constraint_attribute <attribute_name> <type> <value>
Specifies the constraint which should apply to the attribute named as
the first parameter.
At the moment only one type of constraint is supported -
.B
regex.
Two types of constraint are currently supported -
.B regex
and
.BR uri .
The parameter following the
.B
regex
.B regex
type is a Unix style regular expression (See
.B
regex(7))
.BR regex (7)
). The parameter following the
.B uri
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.
Any attempt to add or modify an attribute named as part of the
constraint overlay specification which does not fit the regular
expression constraint listed will fail with a
constraint overlay specification which does not fit the
constraint listed will fail with a
LDAP_CONSTRAINT_VIOLATION error.
.SH EXAMPLES
.B
.LP
.RS
.nf
overlay constraint
constraint_attribute mail regex ^[:alnum:]+@mydomain.com$
constraint_attribute title uri
ldap:///dc=catalog,dc=example,dc=com?title?sub?(objectClass=titleCatalog)
.fi
A specification like the above would reject any
.B
mail
.B mail
attribute which did not look like
.B
<alpha-numeric string>@mydomain.com
It would also reject any
.B title
attribute whose values were not listed in the
.B title
attribute of any
.B titleCatalog
entries in the given scope.
.RE
.SH FILES
.TP
ETCDIR/slapd.conf
default slapd configuration file
.SH SEE ALSO
.BR slapd.conf (5).
.SH ACKNOWLEDGEMENTS
This module was written in 2005 by Neil Dunbar of Hewlett-Packard and subsequently
extended by Howard Chu and Emmanuel Dreyfus.
.so ../Project

View File

@ -1,7 +1,8 @@
/* $OpenLDAP$ */
/* constraint.c - Overlay to constrain attributes to certain values */
/*
*
* Copyright 2003-2004 Hewlett-Packard Company
* Copyright 2007 Emmanuel Dreyfus
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -13,7 +14,8 @@
* <http://www.OpenLDAP.org/license.html>.
*/
/*
* Author: Neil Dunbar <neil.dunbar@hp.com>
* Authors: Neil Dunbar <neil.dunbar@hp.com>
* Emmannuel Dreyfus <manu@netbsd.org>
*/
#include "portable.h"
@ -25,6 +27,7 @@
#include <ac/socket.h>
#include <ac/regex.h>
#include "lutil.h"
#include "slap.h"
#include "config.h"
@ -37,6 +40,7 @@
*/
#define REGEX_STR "regex"
#define URI_STR "uri"
/*
* Linked list of attribute constraints which we should enforce.
@ -47,298 +51,488 @@
*/
typedef struct constraint {
struct constraint *ap_next;
AttributeDescription *ap;
regex_t *re;
char *re_str; /* string representation of regex */
struct constraint *ap_next;
AttributeDescription *ap;
regex_t *re;
LDAPURLDesc *lud;
AttributeDescription **attrs;
struct berval val; /* constraint value */
struct berval dn;
struct berval filter;
} constraint;
enum {
CONSTRAINT_ATTRIBUTE = 1
CONSTRAINT_ATTRIBUTE = 1
};
static ConfigDriver constraint_cf_gen;
static ConfigTable constraintcfg[] = {
{ "constraint_attribute", "attribute regex <regular expression>",
4, 4, 0, ARG_MAGIC | CONSTRAINT_ATTRIBUTE, constraint_cf_gen,
"( OLcfgOvAt:13.1 NAME 'olcConstraintAttribute' "
"DESC 'regular expression constraint for attribute' "
{ "constraint_attribute", "attribute> (regex|uri) <value",
4, 4, 0, ARG_MAGIC | CONSTRAINT_ATTRIBUTE, constraint_cf_gen,
"( OLcfgOvAt:13.1 NAME 'olcConstraintAttribute' "
"DESC 'regular expression constraint for attribute' "
"EQUALITY caseIgnoreMatch "
"SYNTAX OMsDirectoryString )", NULL, NULL },
{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
"SYNTAX OMsDirectoryString )", NULL, NULL },
{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
};
static ConfigOCs constraintocs[] = {
{ "( OLcfgOvOc:13.1 "
"NAME 'olcConstraintConfig' "
"DESC 'Constraint overlay configuration' "
"SUP olcOverlayConfig "
"MAY ( olcConstraintAttribute ) )",
Cft_Overlay, constraintcfg },
{ NULL, 0, NULL }
{ "( OLcfgOvOc:13.1 "
"NAME 'olcConstraintConfig' "
"DESC 'Constraint overlay configuration' "
"SUP olcOverlayConfig "
"MAY ( olcConstraintAttribute ) )",
Cft_Overlay, constraintcfg },
{ NULL, 0, NULL }
};
static void
constraint_free( constraint *cp )
{
if (cp->re) {
regfree(cp->re);
ch_free(cp->re);
}
if (!BER_BVISNULL(&cp->val))
ch_free(cp->val.bv_val);
if (cp->lud)
ldap_free_urldesc(cp->lud);
if (cp->attrs)
ch_free(cp->attrs);
ch_free(cp);
}
static int
constraint_cf_gen( ConfigArgs *c )
{
slap_overinst *on = (slap_overinst *)(c->bi);
constraint *cn = on->on_bi.bi_private, *cp;
struct berval bv;
int i, rc = 0;
constraint ap = { NULL, NULL, NULL }, *a2 = NULL;
const char *text = NULL;
switch ( c->op ) {
case SLAP_CONFIG_EMIT:
switch (c->type) {
case CONSTRAINT_ATTRIBUTE:
for (cp=cn; cp; cp=cp->ap_next) {
int len;
char *s;
len = cp->ap->ad_cname.bv_len +
strlen( REGEX_STR ) + strlen( cp->re_str) + 3;
s = ch_malloc(len);
if (!s) continue;
snprintf(s, len, "%s %s %s", cp->ap->ad_cname.bv_val,
REGEX_STR, cp->re_str);
bv.bv_val = s;
bv.bv_len = strlen(s);
rc = value_add_one( &c->rvalue_vals, &bv );
if (rc) return rc;
rc = value_add_one( &c->rvalue_nvals, &bv );
if (rc) return rc;
ch_free(s);
}
break;
default:
abort();
break;
}
break;
case LDAP_MOD_DELETE:
switch (c->type) {
case CONSTRAINT_ATTRIBUTE:
if (!cn) break; /* nothing to do */
if (c->valx < 0) {
/* zap all constraints */
while (cn) {
cp = cn->ap_next;
if (cn->re) {
regfree(cn->re);
ch_free(cn->re);
}
if (cn->re_str) ch_free(cn->re_str);
ch_free(cn);
cn = cp;
}
on->on_bi.bi_private = NULL;
} else {
constraint **cpp;
/* zap constraint numbered 'valx' */
for(i=0, cp = cn, cpp = &cn;
(cp) && (i<c->valx);
i++, cpp = &cp->ap_next, cp = *cpp);
slap_overinst *on = (slap_overinst *)(c->bi);
constraint *cn = on->on_bi.bi_private, *cp;
struct berval bv;
int i, rc = 0;
constraint ap = { NULL, NULL, NULL }, *a2 = NULL;
const char *text = NULL;
switch ( c->op ) {
case SLAP_CONFIG_EMIT:
switch (c->type) {
case CONSTRAINT_ATTRIBUTE:
for (cp=cn; cp; cp=cp->ap_next) {
int len;
char *s;
char *tstr = NULL;
if (cp) {
/* zap cp, and join cpp to cp->ap_next */
*cpp = cp->ap_next;
if (cp->re) {
regfree(cp->re);
ch_free(cp->re);
}
if (cp->re_str) ch_free(cp->re_str);
ch_free(cp);
}
on->on_bi.bi_private = cn;
}
break;
default:
abort();
break;
}
break;
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 );
}
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;
}
len += cp->val.bv_len;
if ( strcasecmp( c->argv[2], "regex" ) == 0) {
int err;
ap.re = ch_malloc( sizeof(regex_t) );
if ((err = regcomp( ap.re,
c->argv[3], REG_EXTENDED )) != 0) {
char errmsg[1024];
regerror( err, ap.re, errmsg, sizeof(errmsg) );
ch_free(ap.re);
s = ch_malloc(len);
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) return rc;
rc = value_add_one( &c->rvalue_nvals, &bv );
if (rc) return rc;
ch_free(s);
}
break;
default:
abort();
break;
}
break;
case LDAP_MOD_DELETE:
switch (c->type) {
case CONSTRAINT_ATTRIBUTE:
if (!cn) break; /* nothing to do */
if (c->valx < 0) {
/* zap all constraints */
while (cn) {
cp = cn->ap_next;
constraint_free( cn );
cn = cp;
}
on->on_bi.bi_private = NULL;
} else {
constraint **cpp;
/* zap constraint numbered 'valx' */
for(i=0, cp = cn, cpp = &cn;
(cp) && (i<c->valx);
i++, cpp = &cp->ap_next, cp = *cpp);
if (cp) {
/* zap cp, and join cpp to cp->ap_next */
*cpp = cp->ap_next;
constraint_free( cp );
}
on->on_bi.bi_private = cn;
}
break;
default:
abort();
break;
}
break;
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 );
}
if ( strcasecmp( c->argv[2], REGEX_STR ) == 0) {
int err;
ap.re = ch_malloc( sizeof(regex_t) );
if ((err = regcomp( ap.re,
c->argv[3], REG_EXTENDED )) != 0) {
char errmsg[1024];
regerror( err, ap.re, errmsg, sizeof(errmsg) );
ch_free(ap.re);
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"%s %s: Illegal regular expression \"%s\": Error %s",
c->argv[0], c->argv[1], c->argv[3], errmsg);
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
"%s: %s\n", c->log, c->cr_msg, 0 );
ap.re = NULL;
return( ARG_BAD_CONF );
}
ber_str2bv( c->argv[3], 0, 1, &ap.val );
} else if ( strcasecmp( c->argv[2], URI_STR ) == 0) {
int err;
err = ldap_url_parse(c->argv[3], &ap.lud);
if ( err != LDAP_URL_SUCCESS ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"%s %s: Invalid URI \"%s\"",
c->argv[0], c->argv[1], c->argv[3]);
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
"%s: %s\n", c->log, c->cr_msg, 0 );
return( ARG_BAD_CONF );
}
if (ap.lud->lud_host != NULL) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"%s %s: unsupported hostname in URI \"%s\"",
c->argv[0], c->argv[1], c->argv[3]);
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
"%s: %s\n", c->log, c->cr_msg, 0 );
ldap_free_urldesc(ap.lud);
return( ARG_BAD_CONF );
}
for ( i=0; ap.lud->lud_attrs[i]; i++);
/* FIXME: This is worthless without at least one attr */
if ( i ) {
ap.attrs = ch_malloc( (i+1)*sizeof(AttributeDescription *));
for ( i=0; ap.lud->lud_attrs[i]; i++) {
ap.attrs[i] = NULL;
if ( slap_str2ad( ap.lud->lud_attrs[i], &ap.attrs[i], &text ) ) {
ch_free( ap.attrs );
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"%s %s: Illegal regular expression \"%s\": Error %s",
c->argv[0], c->argv[1], c->argv[3], errmsg);
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
"%s: %s\n", c->log, c->cr_msg, 0 );
ap.re = NULL;
return( ARG_BAD_CONF );
}
ap.re_str = ch_strdup( c->argv[3] );
} else {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"%s %s: Unknown constraint type: %s",
c->argv[0], c->argv[1], c->argv[2] );
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
"%s: %s\n", c->log, c->cr_msg, 0 );
return ( ARG_BAD_CONF );
}
"%s <%s>: %s\n", c->argv[0], ap.lud->lud_attrs[i], text );
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
"%s: %s\n", c->log, c->cr_msg, 0 );
return( ARG_BAD_CONF );
}
}
ap.attrs[i] = NULL;
}
a2 = ch_malloc( sizeof(constraint) );
a2->ap_next = on->on_bi.bi_private;
a2->ap = ap.ap;
a2->re = ap.re;
a2->re_str = ap.re_str;
on->on_bi.bi_private = a2;
break;
default:
abort();
break;
}
break;
default:
abort();
}
if (ap.lud->lud_dn == NULL)
ap.lud->lud_dn = ch_strdup("");
return rc;
if (ap.lud->lud_filter == NULL)
ap.lud->lud_filter = ch_strdup("objectClass=*");
ber_str2bv( c->argv[3], 0, 1, &ap.val );
} else {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"%s %s: Unknown constraint type: %s",
c->argv[0], c->argv[1], c->argv[2] );
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
"%s: %s\n", c->log, c->cr_msg, 0 );
return ( ARG_BAD_CONF );
}
a2 = ch_malloc( sizeof(constraint) );
a2->ap_next = on->on_bi.bi_private;
a2->ap = ap.ap;
a2->re = ap.re;
a2->val = ap.val;
a2->lud = ap.lud;
ber_str2bv(a2->lud->lud_dn, 0, 0, &a2->dn);
ber_str2bv(a2->lud->lud_filter, 0, 0, &a2->filter);
a2->attrs = ap.attrs;
on->on_bi.bi_private = a2;
break;
default:
abort();
break;
}
break;
default:
abort();
}
return rc;
}
static int
constraint_violation( constraint *c, struct berval *bv )
constraint_uri_cb( Operation *op, SlapReply *rs )
{
if ((!c) || (!bv)) return 0;
if ((c->re) &&
(regexec(c->re, bv->bv_val, 0, NULL, 0) == REG_NOMATCH))
return 1; /* regular expression violation */
return 0;
if(rs->sr_type == REP_SEARCH) {
int *foundp = op->o_callback->sc_private;
*foundp = 1;
Debug(LDAP_DEBUG_TRACE, "==> constraint_uri_cb <%s>\n",
rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 0);
}
return 0;
}
static int
constraint_violation( constraint *c, struct berval *bv, Operation *op, SlapReply *rs)
{
if ((!c) || (!bv)) return 0;
if ((c->re) &&
(regexec(c->re, bv->bv_val, 0, NULL, 0) == REG_NOMATCH))
return 1; /* regular expression violation */
if (c->lud) {
Operation nop = *op;
slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
slap_callback cb;
SlapReply nrs = { REP_RESULT };
int i;
int found;
int rc;
size_t len;
struct berval filterstr;
char *ptr;
found = 0;
nrs.sr_entry = NULL;
nrs.sr_nentries = 0;
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 || !nop.o_bd->be_search) {
return 1; /* 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;
}
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++) {
const char *text = NULL;
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 );
*ptr++ = ')';
}
*ptr++ = ')';
*ptr++ = ')';
Debug(LDAP_DEBUG_TRACE,
"==> constraint_violation uri filter = %s\n",
filterstr.bv_val, 0, 0);
nop.ors_filterstr = filterstr;
nop.ors_filter = str2filter_x(&nop, filterstr.bv_val);
rc = nop.o_bd->be_search( &nop, &nrs );
op->o_tmpfree(filterstr.bv_val, op->o_tmpmemctx);
Debug(LDAP_DEBUG_TRACE,
"==> constraint_violation uri rc = %d, found = %d\n",
rc, found, 0);
if((rc != LDAP_SUCCESS) && (rc != LDAP_NO_SUCH_OBJECT)) {
send_ldap_error(op, rs, rc,
"constraint_violation uri search failed");
return 1; /* unexpected error */
}
if (!found)
return 1; /* constraint violation */
}
return 0;
}
static char *
print_message( const char *errtext, AttributeDescription *a )
print_message( struct berval *errtext, AttributeDescription *a )
{
char *ret;
int sz;
sz = strlen(errtext) + sizeof(" on ") + a->ad_cname.bv_len;
ret = ch_malloc(sz);
snprintf( ret, sz, "%s on %s", errtext, a->ad_cname.bv_val );
return ret;
char *ret;
int sz;
sz = errtext->bv_len + sizeof(" on ") + a->ad_cname.bv_len;
ret = ch_malloc(sz);
snprintf( ret, sz, "%s on %s", errtext->bv_val, a->ad_cname.bv_val );
return ret;
}
static int
constraint_add( Operation *op, SlapReply *rs )
{
slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
Attribute *a;
constraint *c = on->on_bi.bi_private, *cp;
BerVarray b = NULL;
int i;
const char *rsv = "add breaks regular expression constraint";
char *msg;
if ((a = op->ora_e->e_attrs) == NULL) {
op->o_bd->bd_info = (BackendInfo *)(on->on_info);
send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
"constraint_add() got null op.ora_e.e_attrs");
return(rs->sr_err);
}
slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
Attribute *a;
constraint *c = on->on_bi.bi_private, *cp;
BerVarray b = NULL;
int i;
struct berval rsv = BER_BVC("add breaks constraint");
char *msg;
for(; a; a = a->a_next ) {
/* we don't constrain operational attributes */
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;
if ((b = a->a_vals) == NULL) continue;
for(i=0; b[i].bv_val; i++) {
int cv = constraint_violation( cp, &b[i]);
if (cv) {
/* regex 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);
}
}
}
}
if ((a = op->ora_e->e_attrs) == NULL) {
op->o_bd->bd_info = (BackendInfo *)(on->on_info);
send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
"constraint_add() got null op.ora_e.e_attrs");
return(rs->sr_err);
}
for(; a; a = a->a_next ) {
/* we don't constrain operational attributes */
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;
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);
}
}
}
}
/* Default is to just fall through to the normal processing */
return SLAP_CB_CONTINUE;
return SLAP_CB_CONTINUE;
}
static int
constraint_modify( Operation *op, SlapReply *rs )
{
slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
constraint *c = on->on_bi.bi_private, *cp;
Modifications *m;
BerVarray b = NULL;
int i;
const char *rsv = "modify breaks regular expression constraint";
char *msg;
if ((m = op->orm_modlist) == NULL) {
op->o_bd->bd_info = (BackendInfo *)(on->on_info);
send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
"constraint_modify() got null orm_modlist");
return(rs->sr_err);
}
slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
constraint *c = on->on_bi.bi_private, *cp;
Modifications *m;
BerVarray b = NULL;
int i;
struct berval rsv = BER_BVC("modify breaks constraint");
char *msg;
if ((m = op->orm_modlist) == NULL) {
op->o_bd->bd_info = (BackendInfo *)(on->on_info);
send_ldap_error(op, rs, LDAP_INVALID_SYNTAX,
"constraint_modify() got null orm_modlist");
return(rs->sr_err);
}
for(;m; m = m->sml_next) {
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))
continue;
/* we only care about ADD and REPLACE modifications */
if ((( b = m->sml_values ) == NULL ) || (b[0].bv_val == NULL))
continue;
for(;m; m = m->sml_next) {
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))
continue;
/* we only care about ADD and REPLACE modifications */
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]);
if (cv) {
/* regex 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);
}
}
}
}
return SLAP_CB_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);
}
}
}
}
return SLAP_CB_CONTINUE;
}
static int
@ -346,54 +540,43 @@ constraint_close(
BackendDB *be,
ConfigReply *cr )
{
slap_overinst *on = (slap_overinst *) be->bd_info;
constraint *ap, *a2;
slap_overinst *on = (slap_overinst *) be->bd_info;
constraint *ap, *a2;
for ( ap = on->on_bi.bi_private; ap; ap = a2 ) {
a2 = ap->ap_next;
if (ap->re_str) ch_free(ap->re_str);
if (ap->re) {
regfree( ap->re );
ch_free( ap->re );
}
ch_free( ap );
}
for ( ap = on->on_bi.bi_private; ap; ap = a2 ) {
a2 = ap->ap_next;
constraint_free( ap );
}
return 0;
return 0;
}
static slap_overinst constraint_ovl;
/* This overlay is set up for dynamic loading via moduleload. For static
* configuration, you'll need to arrange for the slap_overinst to be
* initialized and registered by some other function inside slapd.
*/
#if SLAPD_OVER_CONSTRAINT == SLAPD_MOD_DYNAMIC
static
#endif
int
constraint_initialize( void ) {
int rc;
int rc;
constraint_ovl.on_bi.bi_type = "constraint";
constraint_ovl.on_bi.bi_db_close = constraint_close;
constraint_ovl.on_bi.bi_op_add = constraint_add;
constraint_ovl.on_bi.bi_op_modify = constraint_modify;
constraint_ovl.on_bi.bi_type = "constraint";
constraint_ovl.on_bi.bi_db_close = constraint_close;
constraint_ovl.on_bi.bi_op_add = constraint_add;
constraint_ovl.on_bi.bi_op_modify = constraint_modify;
constraint_ovl.on_bi.bi_private = NULL;
constraint_ovl.on_bi.bi_cf_ocs = constraintocs;
rc = config_register_schema( constraintcfg, constraintocs );
if (rc) return rc;
return overlay_register( &constraint_ovl );
constraint_ovl.on_bi.bi_private = NULL;
constraint_ovl.on_bi.bi_cf_ocs = constraintocs;
rc = config_register_schema( constraintcfg, constraintocs );
if (rc) return rc;
return overlay_register( &constraint_ovl );
}
#if SLAPD_OVER_CONSTRAINT == SLAPD_MOD_DYNAMIC
int init_module(int argc, char *argv[]) {
return constraint_initialize();
return constraint_initialize();
}
#endif