diff --git a/doc/man/man5/slapo-constraint.5 b/doc/man/man5/slapo-constraint.5 index e5752fdb0a..1343bf12e8 100644 --- a/doc/man/man5/slapo-constraint.5 +++ b/doc/man/man5/slapo-constraint.5 @@ -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 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 @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 diff --git a/servers/slapd/overlays/constraint.c b/servers/slapd/overlays/constraint.c index aed82a6620..d56d21cc7d 100644 --- a/servers/slapd/overlays/constraint.c +++ b/servers/slapd/overlays/constraint.c @@ -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 @@ * . */ /* - * Author: Neil Dunbar + * Authors: Neil Dunbar + * Emmannuel Dreyfus */ #include "portable.h" @@ -25,6 +27,7 @@ #include #include +#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 ", - 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) 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) && (ivalx); - 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) && (ivalx); + 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