diff -r -U4 openldap-2.4.4alpha.orig/servers/slapd/overlays/constraint.c openldap-2.4.4alpha/servers/slapd/overlays/constraint.c --- openldap-2.4.4alpha.orig/servers/slapd/overlays/constraint.c 2007-02-13 20:22:29.000000000 +0000 +++ openldap-2.4.4alpha/servers/slapd/overlays/constraint.c 2007-05-28 20:10:48.000000000 +0000 @@ -1,8 +1,9 @@ /* 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 * modification, are permitted only as authorized by the OpenLDAP @@ -12,9 +13,10 @@ * top-level directory of the distribution or, alternatively, at * . */ /* - * Author: Neil Dunbar + * Authors: Neil Dunbar + * Emmannuel Dreyfus */ #include "portable.h" #ifdef SLAPD_OVER_CONSTRAINT @@ -36,8 +38,9 @@ * control the add and modify value mods of a modify) */ #define REGEX_STR "regex" +#define KEY_STR "key" /* * Linked list of attribute constraints which we should enforce. * This is probably a sub optimal structure - some form of sorted @@ -50,8 +53,9 @@ struct constraint *ap_next; AttributeDescription *ap; regex_t *re; char *re_str; /* string representation of regex */ + AttributeDescription *ap_key; } constraint; enum { CONSTRAINT_ATTRIBUTE = 1 @@ -65,8 +69,14 @@ "( OLcfgOvAt:13.1 NAME 'olcConstraintAttribute' " "DESC 'regular expression constraint for attribute' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString )", NULL, NULL }, + { "constraint_attribute", "attribute key ", + 4, 4, 0, ARG_MAGIC | CONSTRAINT_ATTRIBUTE, constraint_cf_gen, + "( OLcfgOvAt:13.1 NAME 'olcConstraintAttribute' " + "DESC 'attribute value constraint for attribute' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString )", NULL, NULL }, { NULL, NULL, 0, 0, 0, ARG_IGNORED } }; static ConfigOCs constraintocs[] = { @@ -95,15 +105,25 @@ case CONSTRAINT_ATTRIBUTE: for (cp=cn; cp; cp=cp->ap_next) { int len; char *s; + char *tstr = NULL; + char *vstr = NULL; - len = cp->ap->ad_cname.bv_len + - strlen( REGEX_STR ) + strlen( cp->re_str) + 3; + if (cp->re) { + tstr = REGEX_STR; + vstr = cp->re_str; + } else if (cp->ap_key) { + tstr = KEY_STR; + vstr = cp->ap_key->ad_cname.bv_val; + } + + len = cp->ap->ad_cname.bv_len + + strlen(tstr) + strlen(vstr); + 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); + tstr, vstr); bv.bv_val = s; bv.bv_len = strlen(s); rc = value_add_one( &c->rvalue_vals, &bv ); if (rc) return rc; @@ -174,9 +194,17 @@ "%s: %s\n", c->log, c->msg, 0 ); return( ARG_BAD_CONF ); } - if ( strcasecmp( c->argv[2], "regex" ) == 0) { + if ( strcasecmp( c->argv[2], KEY_STR ) == 0) { + if ( slap_str2ad( c->argv[3], &ap.ap_key, &text ) ) { + snprintf( c->msg, sizeof( c->msg ), + "%s <%s>: %s\n", c->argv[0], c->argv[3], text ); + Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, + "%s: %s\n", c->log, c->msg, 0 ); + return( ARG_BAD_CONF ); + } + } else if ( strcasecmp( c->argv[2], REGEX_STR ) == 0) { int err; ap.re = ch_malloc( sizeof(regex_t) ); if ((err = regcomp( ap.re, @@ -208,8 +236,9 @@ a2->ap_next = on->on_bi.bi_private; a2->ap = ap.ap; a2->re = ap.re; a2->re_str = ap.re_str; + a2->ap_key = ap.ap_key; on->on_bi.bi_private = a2; break; default: abort(); @@ -223,16 +252,112 @@ return rc; } static int -constraint_violation( constraint *c, struct berval *bv ) +constraint_key_cb( Operation *op, SlapReply *rs ) +{ + int *foundp; + + if(!op || !rs) + return(0); + + if(rs->sr_type != REP_SEARCH) + return 0; + + foundp = (int *)op->o_callback->sc_private; + *foundp = 1; + + Debug(LDAP_DEBUG_TRACE, "==> constraint_key_cb <%s>\n", + rs->sr_entry ? rs->sr_entry->e_name.bv_val : "UNKNOWN_DN", 0, 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->ap_key) { + Connection conn = {0}; + OperationBuffer opbuf; + Operation *nop = (Operation *) &opbuf; + slap_overinst *on = (slap_overinst *) op->o_bd->bd_info; + slap_callback cb; + SlapReply nrs = { REP_RESULT }; + AttributeAssertion ava; + Filter filter; + int rc; + int found = 0; + + connection_fake_init(&conn, nop, + ldap_pvt_thread_pool_context()); + + nrs.sr_entry = NULL; + nrs.sr_nentries = 0; + + ava.aa_desc = c->ap_key; + rc = asserted_value_validate_normalize(c->ap_key, + ad_mr(c->ap_key, SLAP_MR_EQUALITY), + SLAP_MR_EQUALITY, + bv, &ava.aa_value, + &nrs.sr_text, nop->o_tmpmemctx); + if (rc != LDAP_SUCCESS) { + send_ldap_error(op, rs, rc, + "constraint_violation key search failed"); + return 1; /* unexpected error */ + } +#ifdef LDAP_COMP_MATCH + ava.aa_cf = NULL; +#endif + + filter.f_choice = LDAP_FILTER_EQUALITY; + filter.f_ava = &ava; + filter.f_next = NULL; + + cb.sc_next = NULL; + cb.sc_response = constraint_key_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(); + nop->o_bd = on->on_info->oi_origdb; + nop->o_req_dn = nop->o_bd->be_suffix[0]; + nop->o_req_ndn = nop->o_bd->be_nsuffix[0]; + nop->o_do_not_cache = 1; + nop->o_callback = &cb; + + nop->ors_scope = LDAP_SCOPE_SUBTREE; + nop->ors_deref = LDAP_DEREF_NEVER; + nop->ors_slimit = SLAP_NO_LIMIT; + nop->ors_tlimit = SLAP_NO_LIMIT; + nop->ors_limit = NULL; + nop->ors_attrs = slap_anlist_no_attrs; + nop->ors_attrsonly = 0; + nop->ors_filter = &filter; + filter2bv_x( nop, nop->ors_filter, &nop->ors_filterstr ); + + rc = nop->o_bd->be_search( nop, &nrs ); + nop->o_tmpfree( nop->ors_filterstr.bv_val, nop->o_tmpmemctx ); + + Debug(LDAP_DEBUG_TRACE, + "==> constraint_violation key 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 key search failed"); + return 1; /* unexpected error */ + } + + if (!found) + return 1; /* constraint violation */ + + } return 0; } @@ -255,9 +380,9 @@ Attribute *a; constraint *c = on->on_bi.bi_private, *cp; BerVarray b = NULL; int i; - const char *rsv = "add breaks regular expression constraint on %s"; + const char *rsv = "add breaks constraint on %s"; char *msg; if ((a = op->ora_e->e_attrs) == NULL) { op->o_bd->bd_info = (BackendInfo *)(on->on_info); @@ -275,9 +400,9 @@ 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]); + int cv = constraint_violation( cp, &b[i], op, rs); if (cv) { /* regex violation */ op->o_bd->bd_info = (BackendInfo *)(on->on_info); @@ -300,9 +425,9 @@ constraint *c = on->on_bi.bi_private, *cp; Modifications *m; BerVarray b = NULL; int i; - const char *rsv = "modify breaks regular expression constraint on %s"; + const char *rsv = "modify breaks constraint on %s"; char *msg; if ((m = op->orm_modlist) == NULL) { op->o_bd->bd_info = (BackendInfo *)(on->on_info); @@ -323,9 +448,9 @@ 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]); + int cv = constraint_violation( cp, &b[i], op, rs); if (cv) { /* regex violation */ op->o_bd->bd_info = (BackendInfo *)(on->on_info);