ITS#4463 add constraint overlay

This commit is contained in:
Howard Chu 2006-04-29 10:03:36 +00:00
parent 442a3f1fde
commit d8595b7c6e
3 changed files with 344 additions and 0 deletions

View file

@ -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 <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.
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
<alpha-numeric string>@mydomain.com
.SH FILES
.TP
ETCDIR/slapd.conf
default slapd configuration file
.SH SEE ALSO
.BR slapd.conf (5).

View file

@ -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)

View file

@ -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
* <http://www.OpenLDAP.org/license.html>.
*/
/*
* Author: Neil Dunbar <neil.dunbar@hp.com>
*/
#include "portable.h"
#ifdef SLAPD_OVER_CONSTRAINT
#include <stdio.h>
#include <ac/string.h>
#include <ac/socket.h>
#include <ac/regex.h>
#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 <attribute> <constraint> <constraint_value>\" 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) */