From: Howard Chu Date: Sat, 29 Apr 2006 10:03:36 +0000 (+0000) Subject: ITS#4463 add constraint overlay X-Git-Tag: OPENLDAP_REL_ENG_2_4_1ALPHA~2^2~106 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=d8595b7c6e4b5d21ef0a68a672eb1eca3bc03781;p=openldap ITS#4463 add constraint overlay --- diff --git a/doc/man/man5/slapo-constraint.5 b/doc/man/man5/slapo-constraint.5 new file mode 100644 index 0000000000..b8ad73566f --- /dev/null +++ b/doc/man/man5/slapo-constraint.5 @@ -0,0 +1,57 @@ +.TH SLAPO-CONSTRAINT 5 "RELEASEDATE" "OpenLDAP LDVERSION" +.\" Copyright 2005-2006 Hewlett-Packard Company +.\" Copying restrictions apply. See COPYRIGHT/LICENSE. +.SH NAME +slapo-constraint \- Attribute Constraint Overlay +.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 +have multiple constraints placed upon them, and all must be satisfied +when modifying an attribute value under constraint. +.LP +This overlay is intended to be used to force syntactic regularity upon +certain string represented data which have well known canonical forms, +like telephone numbers, post codes, FQDNs, etc. +.SH CONFIGURATION +This +.B slapd.conf +option applies to the constraint overlay. +It should appear after the +.B overlay +directive. +.TP +.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. +The parameter following the +.B +regex +type is a Unix style regular expression (See +.B +regex(7)) + +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 +LDAP_CONSTRAINT_VIOLATION error. +.SH EXAMPLES +.B +constraint_attribute mail regex ^[:alnum:]+@mydomain.com$ + +A specification like the above would reject any +.B +mail +attribute which did not look like +.B +@mydomain.com +.SH FILES +.TP +ETCDIR/slapd.conf +default slapd configuration file +.SH SEE ALSO +.BR slapd.conf (5). diff --git a/servers/slapd/overlays/Makefile.in b/servers/slapd/overlays/Makefile.in index 67af446af4..7d0cca84b5 100644 --- a/servers/slapd/overlays/Makefile.in +++ b/servers/slapd/overlays/Makefile.in @@ -16,6 +16,7 @@ SRCS = overlays.c \ accesslog.c \ auditlog.c \ + constraint.c \ dds.c \ denyop.c \ dyngroup.c \ @@ -65,6 +66,9 @@ accesslog.la : accesslog.lo auditlog.la : auditlog.lo $(LTLINK_MOD) -module -o $@ auditlog.lo version.lo $(LINK_LIBS) +constraint.la : constraint.lo + $(LTLINK_MOD) -module -o $@ constraint.lo version.lo $(LINK_LIBS) + dds.la : dds.lo $(LTLINK_MOD) -module -o $@ dds.lo version.lo $(LINK_LIBS) diff --git a/servers/slapd/overlays/constraint.c b/servers/slapd/overlays/constraint.c new file mode 100644 index 0000000000..4173b746d9 --- /dev/null +++ b/servers/slapd/overlays/constraint.c @@ -0,0 +1,283 @@ +/* constraint.c - Overlay to constrain attributes to certain values */ +/* + * + * Copyright 2003-2004 Hewlett-Packard Company + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ +/* + * Author: Neil Dunbar + */ +#include "portable.h" + +#ifdef SLAPD_OVER_CONSTRAINT + +#include + +#include +#include +#include + +#include "slap.h" + +/* + * This overlay limits the values which can be placed into an + * attribute, over and above the limits placed by the schema. + * + * It traps only LDAP adds and modify commands (and only seeks to + * control the add and modify value mods of a modify) + */ + +/* + * Linked list of attribute constraints which we should enforce. + * This is probably a sub optimal structure - some form of sorted + * array would be better if the number of attributes contrained is + * likely to be much bigger than 4 or 5. We stick with a list for + * the moment. + */ +typedef struct constraint { + struct constraint *ap_next; + AttributeDescription *ap; + regex_t *re; +} constraint; + +static int +constraint_violation( constraint *c, struct berval *bv ) +{ + 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; +} + +static char * +print_message( const char *fmt, AttributeDescription *a ) +{ + char *ret; + int sz; + + sz = strlen(fmt) + a->ad_cname.bv_len + 1; + ret = ch_malloc(sz); + snprintf( ret, sz, fmt, 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 on %s"; + 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); + } + + 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); + } + } + } + } + /* Default is to just fall through to the normal processing */ + 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 on %s"; + 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(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; +} + +static int constraint_config( + BackendDB *be, + const char *fname, + int lineno, + int argc, + char **argv + ) +{ + slap_overinst *on = (slap_overinst *) be->bd_info; + constraint ap = { NULL, NULL, NULL }, *a2 = NULL; + regmatch_t rm[2]; + + if ( strcasecmp( argv[0], "constraint_attribute" ) == 0 ) { + const char *text; + + if ( argc != 4 ) { + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "wrong number of parameters in" + "\"constraint_attribute \" line.\n", + fname, lineno, 0 ); + return( 1 ); + } + if ( slap_str2ad( argv[1], &ap.ap, &text ) ) { + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "attribute description unknown \"constraint_attribute\" line: %s.\n", + fname, lineno, text ); + return( 1 ); + } + + if ( strcasecmp( argv[2], "regex" ) == 0) { + int err; + + ap.re = ch_malloc( sizeof(regex_t) ); + if ((err = regcomp( ap.re, argv[3], REG_EXTENDED )) != 0) { + const char *fmt = "%s: line %d: Illegal regular expression \"%s\": Error %s\n"; + char errmsg[1024], *msg; + int i, l, msgsize; + + msgsize = regerror( err, ap.re, errmsg, sizeof(errmsg) ); + msgsize += strlen(fmt) + strlen(argv[3]) + strlen(fname); + for(l=lineno; l>0; l/=10, msgsize++); + msgsize++; + + msg = ch_malloc( msgsize + 1 ); + snprintf( msg, msgsize, fmt, fname, lineno, argv[3], errmsg ); + ch_free(ap.re); + Debug( LDAP_DEBUG_ANY, msg, 0, 0, 0); + ch_free(msg); + ap.re = NULL; + return(1); + } + } else + Debug( LDAP_DEBUG_ANY, "%s: line %d: " + "Unknown constraint type: %s", + fname, lineno, argv[2] ); + + + a2 = ch_malloc( sizeof(constraint) ); + a2->ap_next = on->on_bi.bi_private; + a2->ap = ap.ap; + a2->re = ap.re; + on->on_bi.bi_private = a2; + } else { + return SLAP_CONF_UNKNOWN; + } + + return 0; +} + +static int +constraint_close( + BackendDB *be + ) +{ + 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) { + regfree( ap->re ); + ch_free( ap->re ); + } + + ch_free( ap ); + } + + 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. + */ + +int constraint_init() { + constraint_ovl.on_bi.bi_type = "constraint"; + constraint_ovl.on_bi.bi_db_config = constraint_config; + 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; + + return overlay_register( &constraint_ovl ); +} + +#if SLAPD_OVER_CONSTRAINT == SLAPD_MOD_DYNAMIC +int init_module(int argc, char *argv[]) { + return constraint_init(); +} +#endif + +#endif /* defined(SLAPD_OVER_CONSTRAINT) */ +