+enum {
+ 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' "
+ "EQUALITY caseIgnoreMatch "
+ "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 }
+};
+
+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);
+
+ 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->msg, sizeof( c->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->msg, 0 );
+ return( ARG_BAD_CONF );
+ }
+
+ 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);
+ snprintf( c->msg, sizeof( c->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->msg, 0 );
+ ap.re = NULL;
+ return( ARG_BAD_CONF );
+ }
+ ap.re_str = ch_strdup( c->argv[3] );
+ } else {
+ snprintf( c->msg, sizeof( c->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->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->re_str = ap.re_str;
+ on->on_bi.bi_private = a2;
+ break;
+ default:
+ abort();
+ break;
+ }
+ break;
+ default:
+ abort();
+ }
+
+ return rc;
+}
+