mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-15 03:01:09 +08:00
117a37272d
routine. Could be combined into one routine. Modify slapd matching rule struct to only have match function. Modify old attribute such that 'bin' implies octetString, not 'binary'. Add compatibility for IA5 strings. Only directoryStrings were handled before. Treat attribute types without syntax as incomplete, not default. Add OctetStringValidate (always returns okay). Add {UTF8,IA5}StringValidate/Normalize (IA5 based loosely on case_exact_normalize). Need case{Exact,Ignore}UTFMatch, using IA5 versions for now. Removed default of syntax/mr handlders, should just skip registration of syntax/mr's without handlers. Added comments to slap.h about types versus descriptions.
1555 lines
33 KiB
C
1555 lines
33 KiB
C
/* schema.c - routines to enforce schema definitions */
|
|
/* $OpenLDAP$ */
|
|
/*
|
|
* Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
|
|
* COPYING RESTRICTIONS APPLY, see COPYRIGHT file
|
|
*/
|
|
|
|
#include "portable.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ac/ctype.h>
|
|
#include <ac/string.h>
|
|
#include <ac/socket.h>
|
|
|
|
#include "slap.h"
|
|
#include "ldap_pvt.h"
|
|
|
|
static char * oc_check_required(Entry *e, char *ocname);
|
|
static int oc_check_allowed(char *type, struct berval **ocl);
|
|
|
|
/*
|
|
* oc_check - check that entry e conforms to the schema required by
|
|
* its object class(es). returns 0 if so, non-zero otherwise.
|
|
*/
|
|
|
|
int
|
|
oc_schema_check( Entry *e )
|
|
{
|
|
Attribute *a, *aoc;
|
|
ObjectClass *oc;
|
|
int i;
|
|
int ret = 0;
|
|
|
|
|
|
/* find the object class attribute - could error out here */
|
|
if ( (aoc = attr_find( e->e_attrs, "objectclass" )) == NULL ) {
|
|
Debug( LDAP_DEBUG_ANY, "No object class for entry (%s)\n",
|
|
e->e_dn, 0, 0 );
|
|
return( 1 );
|
|
}
|
|
|
|
/* check that the entry has required attrs for each oc */
|
|
for ( i = 0; aoc->a_vals[i] != NULL; i++ ) {
|
|
if ( (oc = oc_find( aoc->a_vals[i]->bv_val )) == NULL ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"Objectclass \"%s\" not defined\n",
|
|
aoc->a_vals[i]->bv_val, 0, 0 );
|
|
}
|
|
else
|
|
{
|
|
char *s = oc_check_required( e, aoc->a_vals[i]->bv_val );
|
|
|
|
if (s != NULL) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"Entry (%s), oc \"%s\" requires attr \"%s\"\n",
|
|
e->e_dn, aoc->a_vals[i]->bv_val, s );
|
|
ret = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( ret != 0 ) {
|
|
return( ret );
|
|
}
|
|
|
|
/* check that each attr in the entry is allowed by some oc */
|
|
for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
|
|
if ( oc_check_allowed( a->a_type, aoc->a_vals ) != 0 ) {
|
|
Debug( LDAP_DEBUG_ANY,
|
|
"Entry (%s), attr \"%s\" not allowed\n",
|
|
e->e_dn, a->a_type, 0 );
|
|
ret = 1;
|
|
}
|
|
}
|
|
|
|
return( ret );
|
|
}
|
|
|
|
static char *
|
|
oc_check_required( Entry *e, char *ocname )
|
|
{
|
|
ObjectClass *oc;
|
|
AttributeType *at;
|
|
int i;
|
|
Attribute *a;
|
|
char **pp;
|
|
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
"oc_check_required entry (%s), objectclass \"%s\"\n",
|
|
e->e_dn, ocname, 0 );
|
|
|
|
/* find global oc defn. it we don't know about it assume it's ok */
|
|
if ( (oc = oc_find( ocname )) == NULL ) {
|
|
return( 0 );
|
|
}
|
|
|
|
/* check for empty oc_required */
|
|
if(oc->soc_required == NULL) {
|
|
return( 0 );
|
|
}
|
|
|
|
/* for each required attribute */
|
|
for ( i = 0; oc->soc_required[i] != NULL; i++ ) {
|
|
at = oc->soc_required[i];
|
|
/* see if it's in the entry */
|
|
for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
|
|
if ( at->sat_oid &&
|
|
strcmp( a->a_type, at->sat_oid ) == 0 ) {
|
|
break;
|
|
}
|
|
pp = at->sat_names;
|
|
if ( pp == NULL ) {
|
|
/* Empty name list => not found */
|
|
a = NULL;
|
|
break;
|
|
}
|
|
while ( *pp ) {
|
|
if ( strcasecmp( a->a_type, *pp ) == 0 ) {
|
|
break;
|
|
}
|
|
pp++;
|
|
}
|
|
if ( *pp ) {
|
|
break;
|
|
}
|
|
}
|
|
/* not there => schema violation */
|
|
if ( a == NULL ) {
|
|
if ( at->sat_names && at->sat_names[0] ) {
|
|
return at->sat_names[0];
|
|
} else {
|
|
return at->sat_oid;
|
|
}
|
|
}
|
|
}
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
static char *oc_usermod_attrs[] = {
|
|
/*
|
|
* OpenLDAP doesn't support any user modification of
|
|
* operational attributes.
|
|
*/
|
|
NULL
|
|
};
|
|
|
|
static char *oc_operational_attrs[] = {
|
|
/*
|
|
* these are operational attributes
|
|
* most could be user modifiable
|
|
*/
|
|
"objectClasses",
|
|
"attributeTypes",
|
|
"matchingRules",
|
|
"matchingRuleUse",
|
|
"dITStructureRules",
|
|
"dITContentRules",
|
|
"nameForms",
|
|
"ldapSyntaxes",
|
|
"namingContexts",
|
|
"supportedExtension",
|
|
"supportedControl",
|
|
"supportedSASLMechanisms",
|
|
"supportedLDAPversion",
|
|
"supportedACIMechanisms",
|
|
"subschemaSubentry", /* NO USER MOD */
|
|
NULL
|
|
|
|
};
|
|
|
|
/* this list should be extensible */
|
|
static char *oc_no_usermod_attrs[] = {
|
|
/*
|
|
* Operational and 'no user modification' attributes
|
|
* which are STORED in the directory server.
|
|
*/
|
|
|
|
/* RFC2252, 3.2.1 */
|
|
"creatorsName",
|
|
"createTimestamp",
|
|
"modifiersName",
|
|
"modifyTimestamp",
|
|
|
|
NULL
|
|
};
|
|
|
|
|
|
/*
|
|
* check to see if attribute is 'operational' or not.
|
|
*/
|
|
int
|
|
oc_check_operational_attr( const char *type )
|
|
{
|
|
return charray_inlist( oc_operational_attrs, type )
|
|
|| charray_inlist( oc_usermod_attrs, type )
|
|
|| charray_inlist( oc_no_usermod_attrs, type );
|
|
}
|
|
|
|
/*
|
|
* check to see if attribute can be user modified or not.
|
|
*/
|
|
int
|
|
oc_check_usermod_attr( const char *type )
|
|
{
|
|
return charray_inlist( oc_usermod_attrs, type );
|
|
}
|
|
|
|
/*
|
|
* check to see if attribute is 'no user modification' or not.
|
|
*/
|
|
int
|
|
oc_check_no_usermod_attr( const char *type )
|
|
{
|
|
return charray_inlist( oc_no_usermod_attrs, type );
|
|
}
|
|
|
|
|
|
static int
|
|
oc_check_allowed( char *type, struct berval **ocl )
|
|
{
|
|
ObjectClass *oc;
|
|
AttributeType *at;
|
|
int i, j;
|
|
char **pp;
|
|
char *p, *t;
|
|
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
"oc_check_allowed type \"%s\"\n", type, 0, 0 );
|
|
|
|
/* always allow objectclass attribute */
|
|
if ( strcasecmp( type, "objectclass" ) == 0 ) {
|
|
return( 0 );
|
|
}
|
|
|
|
/*
|
|
* All operational attributions are allowed by schema rules.
|
|
* However, we only check attributions which are stored in the
|
|
* the directory regardless if they are user or non-user modified.
|
|
*/
|
|
if ( oc_check_usermod_attr( type ) || oc_check_no_usermod_attr( type ) ) {
|
|
return( 0 );
|
|
}
|
|
|
|
/*
|
|
* The "type" we have received is actually an AttributeDescription.
|
|
* Let's find out the corresponding type.
|
|
*/
|
|
p = strchr( type, ';' );
|
|
if ( p ) {
|
|
t = ch_malloc( p-type+1 );
|
|
strncpy( t, type, p-type );
|
|
t[p-type] = '\0';
|
|
Debug( LDAP_DEBUG_TRACE,
|
|
"oc_check_allowed type \"%s\" from \"%s\"\n",
|
|
t, type, 0 );
|
|
|
|
} else {
|
|
t = type;
|
|
}
|
|
|
|
/* check that the type appears as req or opt in at least one oc */
|
|
for ( i = 0; ocl[i] != NULL; i++ ) {
|
|
/* if we know about the oc */
|
|
if ( (oc = oc_find( ocl[i]->bv_val )) != NULL ) {
|
|
/* does it require the type? */
|
|
for ( j = 0; oc->soc_required != NULL &&
|
|
oc->soc_required[j] != NULL; j++ ) {
|
|
at = oc->soc_required[j];
|
|
if ( at->sat_oid &&
|
|
strcmp(at->sat_oid, t ) == 0 ) {
|
|
if ( t != type )
|
|
ldap_memfree( t );
|
|
return( 0 );
|
|
}
|
|
pp = at->sat_names;
|
|
if ( pp == NULL )
|
|
continue;
|
|
while ( *pp ) {
|
|
if ( strcasecmp( *pp, t ) == 0 ) {
|
|
if ( t != type )
|
|
ldap_memfree( t );
|
|
return( 0 );
|
|
}
|
|
pp++;
|
|
}
|
|
}
|
|
/* does it allow the type? */
|
|
for ( j = 0; oc->soc_allowed != NULL &&
|
|
oc->soc_allowed[j] != NULL; j++ ) {
|
|
at = oc->soc_allowed[j];
|
|
if ( at->sat_oid &&
|
|
strcmp( at->sat_oid, t ) == 0 ) {
|
|
if ( t != type )
|
|
ldap_memfree( t );
|
|
return( 0 );
|
|
}
|
|
pp = at->sat_names;
|
|
if ( pp == NULL )
|
|
continue;
|
|
while ( *pp ) {
|
|
if ( strcasecmp( *pp, t ) == 0 ||
|
|
strcmp( *pp, "*" ) == 0 ) {
|
|
if ( t != type )
|
|
ldap_memfree( t );
|
|
return( 0 );
|
|
}
|
|
pp++;
|
|
}
|
|
}
|
|
/* maybe the next oc allows it */
|
|
|
|
#ifdef OC_UNDEFINED_IMPLES_EXTENSIBLE
|
|
/* we don't know about the oc. assume it allows it */
|
|
} else {
|
|
if ( t != type )
|
|
ldap_memfree( t );
|
|
return( 0 );
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if ( t != type )
|
|
ldap_memfree( t );
|
|
/* not allowed by any oc */
|
|
return( 1 );
|
|
}
|
|
|
|
struct oindexrec {
|
|
char *oir_name;
|
|
ObjectClass *oir_oc;
|
|
};
|
|
|
|
static Avlnode *oc_index = NULL;
|
|
static ObjectClass *oc_list = NULL;
|
|
|
|
static int
|
|
oc_index_cmp(
|
|
struct oindexrec *oir1,
|
|
struct oindexrec *oir2
|
|
)
|
|
{
|
|
return (strcasecmp( oir1->oir_name, oir2->oir_name ));
|
|
}
|
|
|
|
static int
|
|
oc_index_name_cmp(
|
|
char *name,
|
|
struct oindexrec *oir
|
|
)
|
|
{
|
|
return (strcasecmp( name, oir->oir_name ));
|
|
}
|
|
|
|
ObjectClass *
|
|
oc_find( const char *ocname )
|
|
{
|
|
struct oindexrec *oir = NULL;
|
|
|
|
if ( (oir = (struct oindexrec *) avl_find( oc_index, ocname,
|
|
(AVL_CMP) oc_index_name_cmp )) != NULL ) {
|
|
return( oir->oir_oc );
|
|
}
|
|
return( NULL );
|
|
}
|
|
|
|
static int
|
|
oc_create_required(
|
|
ObjectClass *soc,
|
|
char **attrs,
|
|
const char **err
|
|
)
|
|
{
|
|
char **attrs1;
|
|
AttributeType *sat;
|
|
AttributeType **satp;
|
|
int i;
|
|
|
|
if ( attrs ) {
|
|
attrs1 = attrs;
|
|
while ( *attrs1 ) {
|
|
sat = at_find(*attrs1);
|
|
if ( !sat ) {
|
|
*err = *attrs1;
|
|
return SLAP_SCHERR_ATTR_NOT_FOUND;
|
|
}
|
|
if ( at_find_in_list(sat, soc->soc_required) < 0) {
|
|
if ( at_append_to_list(sat, &soc->soc_required) ) {
|
|
*err = *attrs1;
|
|
return SLAP_SCHERR_OUTOFMEM;
|
|
}
|
|
}
|
|
attrs1++;
|
|
}
|
|
/* Now delete duplicates from the allowed list */
|
|
for ( satp = soc->soc_required; *satp; satp++ ) {
|
|
i = at_find_in_list(*satp,soc->soc_allowed);
|
|
if ( i >= 0 ) {
|
|
at_delete_from_list(i, &soc->soc_allowed);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
oc_create_allowed(
|
|
ObjectClass *soc,
|
|
char **attrs,
|
|
const char **err
|
|
)
|
|
{
|
|
char **attrs1;
|
|
AttributeType *sat;
|
|
|
|
if ( attrs ) {
|
|
attrs1 = attrs;
|
|
while ( *attrs1 ) {
|
|
sat = at_find(*attrs1);
|
|
if ( !sat ) {
|
|
*err = *attrs1;
|
|
return SLAP_SCHERR_ATTR_NOT_FOUND;
|
|
}
|
|
if ( at_find_in_list(sat, soc->soc_required) < 0 &&
|
|
at_find_in_list(sat, soc->soc_allowed) < 0 ) {
|
|
if ( at_append_to_list(sat, &soc->soc_allowed) ) {
|
|
*err = *attrs1;
|
|
return SLAP_SCHERR_OUTOFMEM;
|
|
}
|
|
}
|
|
attrs1++;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
oc_add_sups(
|
|
ObjectClass *soc,
|
|
char **sups,
|
|
const char **err
|
|
)
|
|
{
|
|
int code;
|
|
ObjectClass *soc1;
|
|
int nsups;
|
|
char **sups1;
|
|
int add_sups = 0;
|
|
|
|
if ( sups ) {
|
|
if ( !soc->soc_sups ) {
|
|
/* We are at the first recursive level */
|
|
add_sups = 1;
|
|
nsups = 0;
|
|
sups1 = sups;
|
|
while ( *sups1 ) {
|
|
nsups++;
|
|
sups1++;
|
|
}
|
|
nsups++;
|
|
soc->soc_sups = (ObjectClass **)ch_calloc(1,
|
|
nsups*sizeof(ObjectClass *));
|
|
}
|
|
nsups = 0;
|
|
sups1 = sups;
|
|
while ( *sups1 ) {
|
|
soc1 = oc_find(*sups1);
|
|
if ( !soc1 ) {
|
|
*err = *sups1;
|
|
return SLAP_SCHERR_CLASS_NOT_FOUND;
|
|
}
|
|
|
|
if ( add_sups )
|
|
soc->soc_sups[nsups] = soc1;
|
|
|
|
code = oc_add_sups(soc,soc1->soc_sup_oids, err);
|
|
if ( code )
|
|
return code;
|
|
|
|
code = oc_create_required(soc,soc1->soc_at_oids_must,err);
|
|
if ( code )
|
|
return code;
|
|
code = oc_create_allowed(soc,soc1->soc_at_oids_may,err);
|
|
if ( code )
|
|
return code;
|
|
|
|
nsups++;
|
|
sups1++;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
oc_insert(
|
|
ObjectClass *soc,
|
|
const char **err
|
|
)
|
|
{
|
|
ObjectClass **ocp;
|
|
struct oindexrec *oir;
|
|
char **names;
|
|
|
|
ocp = &oc_list;
|
|
while ( *ocp != NULL ) {
|
|
ocp = &(*ocp)->soc_next;
|
|
}
|
|
*ocp = soc;
|
|
|
|
if ( soc->soc_oid ) {
|
|
oir = (struct oindexrec *)
|
|
ch_calloc( 1, sizeof(struct oindexrec) );
|
|
oir->oir_name = soc->soc_oid;
|
|
oir->oir_oc = soc;
|
|
if ( avl_insert( &oc_index, (caddr_t) oir,
|
|
(AVL_CMP) oc_index_cmp,
|
|
(AVL_DUP) avl_dup_error ) ) {
|
|
*err = soc->soc_oid;
|
|
ldap_memfree(oir);
|
|
return SLAP_SCHERR_DUP_CLASS;
|
|
}
|
|
/* FIX: temporal consistency check */
|
|
oc_find(oir->oir_name);
|
|
}
|
|
if ( (names = soc->soc_names) ) {
|
|
while ( *names ) {
|
|
oir = (struct oindexrec *)
|
|
ch_calloc( 1, sizeof(struct oindexrec) );
|
|
oir->oir_name = ch_strdup(*names);
|
|
oir->oir_oc = soc;
|
|
if ( avl_insert( &oc_index, (caddr_t) oir,
|
|
(AVL_CMP) oc_index_cmp,
|
|
(AVL_DUP) avl_dup_error ) ) {
|
|
*err = *names;
|
|
ldap_memfree(oir);
|
|
return SLAP_SCHERR_DUP_CLASS;
|
|
}
|
|
/* FIX: temporal consistency check */
|
|
oc_find(oir->oir_name);
|
|
names++;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
oc_add(
|
|
LDAP_OBJECT_CLASS *oc,
|
|
const char **err
|
|
)
|
|
{
|
|
ObjectClass *soc;
|
|
int code;
|
|
|
|
soc = (ObjectClass *) ch_calloc( 1, sizeof(ObjectClass) );
|
|
memcpy( &soc->soc_oclass, oc, sizeof(LDAP_OBJECT_CLASS));
|
|
if ( (code = oc_add_sups(soc,soc->soc_sup_oids,err)) != 0 )
|
|
return code;
|
|
if ( (code = oc_create_required(soc,soc->soc_at_oids_must,err)) != 0 )
|
|
return code;
|
|
if ( (code = oc_create_allowed(soc,soc->soc_at_oids_may,err)) != 0 )
|
|
return code;
|
|
code = oc_insert(soc,err);
|
|
return code;
|
|
}
|
|
|
|
struct sindexrec {
|
|
char *sir_name;
|
|
Syntax *sir_syn;
|
|
};
|
|
|
|
static Avlnode *syn_index = NULL;
|
|
static Syntax *syn_list = NULL;
|
|
|
|
static int
|
|
syn_index_cmp(
|
|
struct sindexrec *sir1,
|
|
struct sindexrec *sir2
|
|
)
|
|
{
|
|
return (strcmp( sir1->sir_name, sir2->sir_name ));
|
|
}
|
|
|
|
static int
|
|
syn_index_name_cmp(
|
|
char *name,
|
|
struct sindexrec *sir
|
|
)
|
|
{
|
|
return (strcmp( name, sir->sir_name ));
|
|
}
|
|
|
|
Syntax *
|
|
syn_find( const char *synname )
|
|
{
|
|
struct sindexrec *sir = NULL;
|
|
|
|
if ( (sir = (struct sindexrec *) avl_find( syn_index, synname,
|
|
(AVL_CMP) syn_index_name_cmp )) != NULL ) {
|
|
return( sir->sir_syn );
|
|
}
|
|
return( NULL );
|
|
}
|
|
|
|
Syntax *
|
|
syn_find_desc( const char *syndesc, int *len )
|
|
{
|
|
Syntax *synp;
|
|
|
|
for (synp = syn_list; synp; synp = synp->ssyn_next)
|
|
if ((*len = dscompare( synp->ssyn_syn.syn_desc, syndesc, '{')))
|
|
return synp;
|
|
return( NULL );
|
|
}
|
|
|
|
static int
|
|
syn_insert(
|
|
Syntax *ssyn,
|
|
const char **err
|
|
)
|
|
{
|
|
Syntax **synp;
|
|
struct sindexrec *sir;
|
|
|
|
synp = &syn_list;
|
|
while ( *synp != NULL ) {
|
|
synp = &(*synp)->ssyn_next;
|
|
}
|
|
*synp = ssyn;
|
|
|
|
if ( ssyn->ssyn_oid ) {
|
|
sir = (struct sindexrec *)
|
|
ch_calloc( 1, sizeof(struct sindexrec) );
|
|
sir->sir_name = ssyn->ssyn_oid;
|
|
sir->sir_syn = ssyn;
|
|
if ( avl_insert( &syn_index, (caddr_t) sir,
|
|
(AVL_CMP) syn_index_cmp,
|
|
(AVL_DUP) avl_dup_error ) ) {
|
|
*err = ssyn->ssyn_oid;
|
|
ldap_memfree(sir);
|
|
return SLAP_SCHERR_DUP_SYNTAX;
|
|
}
|
|
/* FIX: temporal consistency check */
|
|
syn_find(sir->sir_name);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
syn_add(
|
|
LDAP_SYNTAX *syn,
|
|
slap_syntax_validate_func *validate,
|
|
slap_syntax_normalize_func *normalize,
|
|
const char **err
|
|
)
|
|
{
|
|
Syntax *ssyn;
|
|
int code;
|
|
|
|
ssyn = (Syntax *) ch_calloc( 1, sizeof(Syntax) );
|
|
memcpy( &ssyn->ssyn_syn, syn, sizeof(LDAP_SYNTAX));
|
|
ssyn->ssyn_validate = validate;
|
|
ssyn->ssyn_normalize = normalize;
|
|
code = syn_insert(ssyn,err);
|
|
return code;
|
|
}
|
|
|
|
struct mindexrec {
|
|
char *mir_name;
|
|
MatchingRule *mir_mr;
|
|
};
|
|
|
|
static Avlnode *mr_index = NULL;
|
|
static MatchingRule *mr_list = NULL;
|
|
|
|
static int
|
|
mr_index_cmp(
|
|
struct mindexrec *mir1,
|
|
struct mindexrec *mir2
|
|
)
|
|
{
|
|
return (strcmp( mir1->mir_name, mir2->mir_name ));
|
|
}
|
|
|
|
static int
|
|
mr_index_name_cmp(
|
|
char *name,
|
|
struct mindexrec *mir
|
|
)
|
|
{
|
|
return (strcmp( name, mir->mir_name ));
|
|
}
|
|
|
|
MatchingRule *
|
|
mr_find( const char *mrname )
|
|
{
|
|
struct mindexrec *mir = NULL;
|
|
|
|
if ( (mir = (struct mindexrec *) avl_find( mr_index, mrname,
|
|
(AVL_CMP) mr_index_name_cmp )) != NULL ) {
|
|
return( mir->mir_mr );
|
|
}
|
|
return( NULL );
|
|
}
|
|
|
|
static int
|
|
mr_insert(
|
|
MatchingRule *smr,
|
|
const char **err
|
|
)
|
|
{
|
|
MatchingRule **mrp;
|
|
struct mindexrec *mir;
|
|
char **names;
|
|
|
|
mrp = &mr_list;
|
|
while ( *mrp != NULL ) {
|
|
mrp = &(*mrp)->smr_next;
|
|
}
|
|
*mrp = smr;
|
|
|
|
if ( smr->smr_oid ) {
|
|
mir = (struct mindexrec *)
|
|
ch_calloc( 1, sizeof(struct mindexrec) );
|
|
mir->mir_name = smr->smr_oid;
|
|
mir->mir_mr = smr;
|
|
if ( avl_insert( &mr_index, (caddr_t) mir,
|
|
(AVL_CMP) mr_index_cmp,
|
|
(AVL_DUP) avl_dup_error ) ) {
|
|
*err = smr->smr_oid;
|
|
ldap_memfree(mir);
|
|
return SLAP_SCHERR_DUP_RULE;
|
|
}
|
|
/* FIX: temporal consistency check */
|
|
mr_find(mir->mir_name);
|
|
}
|
|
if ( (names = smr->smr_names) ) {
|
|
while ( *names ) {
|
|
mir = (struct mindexrec *)
|
|
ch_calloc( 1, sizeof(struct mindexrec) );
|
|
mir->mir_name = ch_strdup(*names);
|
|
mir->mir_mr = smr;
|
|
if ( avl_insert( &mr_index, (caddr_t) mir,
|
|
(AVL_CMP) mr_index_cmp,
|
|
(AVL_DUP) avl_dup_error ) ) {
|
|
*err = *names;
|
|
ldap_memfree(mir);
|
|
return SLAP_SCHERR_DUP_RULE;
|
|
}
|
|
/* FIX: temporal consistency check */
|
|
mr_find(mir->mir_name);
|
|
names++;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
mr_add(
|
|
LDAP_MATCHING_RULE *mr,
|
|
slap_mr_match_func *match,
|
|
const char **err
|
|
)
|
|
{
|
|
MatchingRule *smr;
|
|
Syntax *syn;
|
|
int code;
|
|
|
|
smr = (MatchingRule *) ch_calloc( 1, sizeof(MatchingRule) );
|
|
memcpy( &smr->smr_mrule, mr, sizeof(LDAP_MATCHING_RULE));
|
|
smr->smr_match = match;
|
|
if ( smr->smr_syntax_oid ) {
|
|
if ( (syn = syn_find(smr->smr_syntax_oid)) ) {
|
|
smr->smr_syntax = syn;
|
|
} else {
|
|
*err = smr->smr_syntax_oid;
|
|
return SLAP_SCHERR_SYN_NOT_FOUND;
|
|
}
|
|
} else {
|
|
*err = "";
|
|
return SLAP_SCHERR_MR_INCOMPLETE;
|
|
}
|
|
code = mr_insert(smr,err);
|
|
return code;
|
|
}
|
|
|
|
static int
|
|
octetStringValidate( struct berval *val )
|
|
{
|
|
/* any value allowed */
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
UTF8StringValidate( struct berval *val )
|
|
{
|
|
ber_len_t count;
|
|
int len;
|
|
unsigned char *u = val->bv_val;
|
|
|
|
for( count = val->bv_len; count > 0; count+=len, u+=len ) {
|
|
/* get the length indicated by the first byte */
|
|
len = LDAP_UTF8_CHARLEN( u );
|
|
|
|
/* should not be zero */
|
|
if( len == 0 ) return -1;
|
|
|
|
/* make sure len corresponds with the offset
|
|
to the next character */
|
|
if( LDAP_UTF8_OFFSET( u ) != len ) return -1;
|
|
}
|
|
|
|
if( count != 0 ) return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
UTF8StringNormalize(
|
|
struct berval *val,
|
|
struct berval **normalized
|
|
)
|
|
{
|
|
struct berval *newval;
|
|
char *p, *q, *s;
|
|
|
|
newval = ch_malloc( sizeof( struct berval ) );
|
|
|
|
p = val->bv_val;
|
|
|
|
/* Ignore initial whitespace */
|
|
while ( ldap_utf8_isspace( p ) ) {
|
|
LDAP_UTF8_INCR( p );
|
|
}
|
|
|
|
if( *p ) {
|
|
ch_free( newval );
|
|
return 1;
|
|
}
|
|
|
|
newval->bv_val = ch_strdup( p );
|
|
p = q = newval->bv_val;
|
|
s = NULL;
|
|
|
|
while ( *p ) {
|
|
int len;
|
|
|
|
if ( ldap_utf8_isspace( p ) ) {
|
|
len = LDAP_UTF8_COPY(q,p);
|
|
s=q;
|
|
p+=len;
|
|
q+=len;
|
|
|
|
/* Ignore the extra whitespace */
|
|
while ( ldap_utf8_isspace( p ) ) {
|
|
LDAP_UTF8_INCR( p );
|
|
}
|
|
} else {
|
|
len = LDAP_UTF8_COPY(q,p);
|
|
s=NULL;
|
|
p+=len;
|
|
q+=len;
|
|
}
|
|
}
|
|
|
|
assert( *newval->bv_val );
|
|
assert( newval->bv_val < p );
|
|
assert( p <= q );
|
|
|
|
/* cannot start with a space */
|
|
assert( !ldap_utf8_isspace(newval->bv_val) );
|
|
|
|
/*
|
|
* If the string ended in space, backup the pointer one
|
|
* position. One is enough because the above loop collapsed
|
|
* all whitespace to a single space.
|
|
*/
|
|
|
|
if ( s != NULL ) {
|
|
q = s;
|
|
}
|
|
|
|
/* cannot end with a space */
|
|
assert( !ldap_utf8_isspace( LDAP_UTF8_PREV(q) ) );
|
|
|
|
/* null terminate */
|
|
*q = '\0';
|
|
|
|
newval->bv_len = q - newval->bv_val;
|
|
normalized = &newval;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
IA5StringValidate( struct berval *val )
|
|
{
|
|
int i;
|
|
|
|
for(i=0; i < val->bv_len; i++) {
|
|
if( !isascii(val->bv_val[i]) ) return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
IA5StringNormalize(
|
|
struct berval *val,
|
|
struct berval **normalized
|
|
)
|
|
{
|
|
struct berval *newval;
|
|
char *p, *q;
|
|
|
|
newval = ch_malloc( sizeof( struct berval ) );
|
|
|
|
p = val->bv_val;
|
|
|
|
/* Ignore initial whitespace */
|
|
while ( isspace( *p++ ) ) {
|
|
/* EMPTY */ ;
|
|
}
|
|
|
|
if( *p ) {
|
|
ch_free( newval );
|
|
return 1;
|
|
}
|
|
|
|
newval->bv_val = ch_strdup( p );
|
|
p = q = newval->bv_val;
|
|
|
|
while ( *p ) {
|
|
if ( isspace( *p ) ) {
|
|
*q++ = *p++;
|
|
|
|
/* Ignore the extra whitespace */
|
|
while ( isspace( *p++ ) ) {
|
|
/* EMPTY */ ;
|
|
}
|
|
} else {
|
|
*q++ = *p++;
|
|
}
|
|
}
|
|
|
|
assert( *newval->bv_val );
|
|
assert( newval->bv_val < p );
|
|
assert( p <= q );
|
|
|
|
/* cannot start with a space */
|
|
assert( !isspace(*newval->bv_val) );
|
|
|
|
/*
|
|
* If the string ended in space, backup the pointer one
|
|
* position. One is enough because the above loop collapsed
|
|
* all whitespace to a single space.
|
|
*/
|
|
|
|
if ( isspace( q[-1] ) ) {
|
|
--q;
|
|
}
|
|
|
|
/* cannot end with a space */
|
|
assert( !isspace( q[-1] ) );
|
|
|
|
/* null terminate */
|
|
*q = '\0';
|
|
|
|
newval->bv_len = q - newval->bv_val;
|
|
normalized = &newval;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
caseExactIA5Match(
|
|
struct berval *val1,
|
|
struct berval *val2
|
|
)
|
|
{
|
|
return strcmp( val1->bv_val, val2->bv_val );
|
|
}
|
|
|
|
static int
|
|
caseIgnoreIA5Match(
|
|
struct berval *val1,
|
|
struct berval *val2
|
|
)
|
|
{
|
|
return strcasecmp( val1->bv_val, val2->bv_val );
|
|
}
|
|
|
|
int
|
|
register_syntax(
|
|
char * desc,
|
|
slap_syntax_validate_func *validate,
|
|
slap_syntax_normalize_func *normalize )
|
|
{
|
|
LDAP_SYNTAX *syn;
|
|
int code;
|
|
const char *err;
|
|
|
|
syn = ldap_str2syntax( desc, &code, &err);
|
|
if ( !syn ) {
|
|
Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s before %s in %s\n",
|
|
ldap_scherr2str(code), err, desc );
|
|
return( -1 );
|
|
}
|
|
code = syn_add( syn, validate, normalize, &err );
|
|
if ( code ) {
|
|
Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s %s in %s\n",
|
|
scherr2str(code), err, desc );
|
|
return( -1 );
|
|
}
|
|
return( 0 );
|
|
}
|
|
|
|
int
|
|
register_matching_rule(
|
|
char * desc,
|
|
slap_mr_match_func *match )
|
|
{
|
|
LDAP_MATCHING_RULE *mr;
|
|
int code;
|
|
const char *err;
|
|
|
|
mr = ldap_str2matchingrule( desc, &code, &err);
|
|
if ( !mr ) {
|
|
Debug( LDAP_DEBUG_ANY, "Error in register_matching_rule: %s before %s in %s\n",
|
|
ldap_scherr2str(code), err, desc );
|
|
return( -1 );
|
|
}
|
|
code = mr_add( mr, match, &err );
|
|
if ( code ) {
|
|
Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s for %s in %s\n",
|
|
scherr2str(code), err, desc );
|
|
return( -1 );
|
|
}
|
|
return( 0 );
|
|
}
|
|
|
|
struct syntax_defs_rec {
|
|
char *sd_desc;
|
|
slap_syntax_validate_func *sd_validate;
|
|
slap_syntax_normalize_func *sd_normalize;
|
|
};
|
|
|
|
struct syntax_defs_rec syntax_defs[] = {
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'AttributeTypeDescription' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'BitString' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'CertificateList' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'CertificatePair' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'DN' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'DeliveryMethod' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'DirectoryString' )",
|
|
UTF8StringValidate, UTF8StringNormalize},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DITContentRuleDescription' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DITStructureRuleDescription' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'EnhancedGuide' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'FacsimileTelephoneNumber' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'GeneralizedTime' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5String' )",
|
|
IA5StringValidate, IA5StringNormalize},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'MatchingRuleDescription' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'MatchingRuleUseDescription' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'MailPreference' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'NameAndOptionalUID' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'NameFormDescription' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'NumericString' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'ObjectClassDescription' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'OtherMailbox' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'OctetString' )",
|
|
octetStringValidate, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'PostalAddress' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'ProtocolInformation' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'PresentationAddress' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'PrintableString' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'SupportedAlgorithm' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'TelephoneNumber' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'TeletexTerminalIdentifier' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'TelexNumber' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTCTime' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAPSyntaxDescription' )",
|
|
NULL, NULL},
|
|
{"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'SubstringAssertion' )",
|
|
NULL, NULL},
|
|
|
|
{NULL, NULL, NULL}
|
|
};
|
|
|
|
struct mrule_defs_rec {
|
|
char *mrd_desc;
|
|
slap_mr_match_func *mrd_match;
|
|
};
|
|
|
|
/*
|
|
* Other matching rules in X.520 that we do not use:
|
|
*
|
|
* 2.5.13.9 numericStringOrderingMatch
|
|
* 2.5.13.12 caseIgnoreListSubstringsMatch
|
|
* 2.5.13.13 booleanMatch
|
|
* 2.5.13.15 integerOrderingMatch
|
|
* 2.5.13.18 octetStringOrderingMatch
|
|
* 2.5.13.19 octetStringSubstringsMatch
|
|
* 2.5.13.25 uTCTimeMatch
|
|
* 2.5.13.26 uTCTimeOrderingMatch
|
|
* 2.5.13.31 directoryStringFirstComponentMatch
|
|
* 2.5.13.32 wordMatch
|
|
* 2.5.13.33 keywordMatch
|
|
* 2.5.13.34 certificateExactMatch
|
|
* 2.5.13.35 certificateMatch
|
|
* 2.5.13.36 certificatePairExactMatch
|
|
* 2.5.13.37 certificatePairMatch
|
|
* 2.5.13.38 certificateListExactMatch
|
|
* 2.5.13.39 certificateListMatch
|
|
* 2.5.13.40 algorithmIdentifierMatch
|
|
* 2.5.13.41 storedPrefixMatch
|
|
* 2.5.13.42 attributeCertificateMatch
|
|
* 2.5.13.43 readerAndKeyIDMatch
|
|
* 2.5.13.44 attributeIntegrityMatch
|
|
*/
|
|
|
|
/* recycled matching functions */
|
|
#define caseIgnoreMatch caseIgnoreIA5Match
|
|
#define caseExactMatch caseExactIA5Match
|
|
|
|
/* unimplemented matching functions */
|
|
#define objectIdentifierMatch NULL
|
|
#define distinguishedNameMatch NULL
|
|
#define caseIgnoreOrderingMatch NULL
|
|
#define caseIgnoreSubstringsMatch NULL
|
|
#define caseExactOrderingMatch NULL
|
|
#define caseExactSubstringsMatch NULL
|
|
#define numericStringMatch NULL
|
|
#define numericStringSubstringsMatch NULL
|
|
#define caseIgnoreListMatch NULL
|
|
#define integerMatch NULL
|
|
#define bitStringMatch NULL
|
|
#define octetStringMatch NULL
|
|
#define telephoneNumberMatch NULL
|
|
#define telephoneNumberSubstringsMatch NULL
|
|
#define presentationAddressMatch NULL
|
|
#define uniqueMemberMatch NULL
|
|
#define protocolInformationMatch NULL
|
|
#define generalizedTimeMatch NULL
|
|
#define generalizedTimeOrderingMatch NULL
|
|
#define integerFirstComponentMatch NULL
|
|
#define objectIdentifierFirstComponentMatch NULL
|
|
#define caseIgnoreIA5SubstringsMatch NULL
|
|
|
|
struct mrule_defs_rec mrule_defs[] = {
|
|
{"( 2.5.13.0 NAME 'objectIdentifierMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
|
|
objectIdentifierMatch},
|
|
|
|
{"( 2.5.13.1 NAME 'distinguishedNameMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
|
|
distinguishedNameMatch},
|
|
|
|
{"( 2.5.13.2 NAME 'caseIgnoreMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
|
|
caseIgnoreMatch},
|
|
|
|
{"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
|
|
caseIgnoreOrderingMatch},
|
|
|
|
{"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
|
|
caseIgnoreSubstringsMatch},
|
|
|
|
/* Next three are not in the RFC's, but are needed for compatibility */
|
|
{"( 2.5.13.5 NAME 'caseExactMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
|
|
caseExactMatch},
|
|
|
|
{"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
|
|
caseExactOrderingMatch},
|
|
|
|
{"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
|
|
caseExactSubstringsMatch},
|
|
|
|
{"( 2.5.13.8 NAME 'numericStringMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
|
|
numericStringMatch},
|
|
|
|
{"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
|
|
numericStringSubstringsMatch},
|
|
|
|
{"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
|
|
caseIgnoreListMatch},
|
|
|
|
{"( 2.5.13.14 NAME 'integerMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
|
|
integerMatch},
|
|
|
|
{"( 2.5.13.16 NAME 'bitStringMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
|
|
bitStringMatch},
|
|
|
|
{"( 2.5.13.17 NAME 'octetStringMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
|
|
octetStringMatch},
|
|
|
|
{"( 2.5.13.20 NAME 'telephoneNumberMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
|
|
telephoneNumberMatch},
|
|
|
|
{"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
|
|
telephoneNumberSubstringsMatch},
|
|
|
|
{"( 2.5.13.22 NAME 'presentationAddressMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
|
|
presentationAddressMatch},
|
|
|
|
{"( 2.5.13.23 NAME 'uniqueMemberMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
|
|
uniqueMemberMatch},
|
|
|
|
{"( 2.5.13.24 NAME 'protocolInformationMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
|
|
protocolInformationMatch},
|
|
|
|
{"( 2.5.13.27 NAME 'generalizedTimeMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
|
|
generalizedTimeMatch},
|
|
|
|
{"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
|
|
generalizedTimeOrderingMatch},
|
|
|
|
{"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
|
|
integerFirstComponentMatch},
|
|
|
|
{"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
|
|
objectIdentifierFirstComponentMatch},
|
|
|
|
{"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
|
|
caseExactIA5Match},
|
|
|
|
{"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
|
|
caseIgnoreIA5Match},
|
|
|
|
{"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
|
|
"SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
|
|
caseIgnoreIA5SubstringsMatch},
|
|
|
|
{NULL, NULL}
|
|
};
|
|
|
|
int
|
|
schema_init( void )
|
|
{
|
|
int res;
|
|
int i;
|
|
static int schema_init_done = 0;
|
|
|
|
/* We are called from read_config that is recursive */
|
|
if ( schema_init_done )
|
|
return( 0 );
|
|
|
|
for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
|
|
res = register_syntax( syntax_defs[i].sd_desc,
|
|
syntax_defs[i].sd_validate,
|
|
syntax_defs[i].sd_normalize );
|
|
|
|
if ( res ) {
|
|
fprintf( stderr, "schema_init: Error registering syntax %s\n",
|
|
syntax_defs[i].sd_desc );
|
|
exit( EXIT_FAILURE );
|
|
}
|
|
}
|
|
|
|
for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
|
|
res = register_matching_rule( mrule_defs[i].mrd_desc,
|
|
mrule_defs[i].mrd_match );
|
|
|
|
if ( res ) {
|
|
fprintf( stderr, "schema_init: Error registering matching rule %s\n",
|
|
mrule_defs[i].mrd_desc );
|
|
exit( EXIT_FAILURE );
|
|
}
|
|
}
|
|
schema_init_done = 1;
|
|
return( 0 );
|
|
}
|
|
|
|
#if defined( SLAPD_SCHEMA_DN )
|
|
|
|
static int
|
|
syn_schema_info( Entry *e )
|
|
{
|
|
struct berval val;
|
|
struct berval *vals[2];
|
|
Syntax *syn;
|
|
|
|
vals[0] = &val;
|
|
vals[1] = NULL;
|
|
|
|
for ( syn = syn_list; syn; syn = syn->ssyn_next ) {
|
|
val.bv_val = ldap_syntax2str( &syn->ssyn_syn );
|
|
if ( val.bv_val ) {
|
|
val.bv_len = strlen( val.bv_val );
|
|
Debug( LDAP_DEBUG_TRACE, "Merging syn [%ld] %s\n",
|
|
(long) val.bv_len, val.bv_val, 0 );
|
|
attr_merge( e, "ldapSyntaxes", vals );
|
|
ldap_memfree( val.bv_val );
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
mr_schema_info( Entry *e )
|
|
{
|
|
struct berval val;
|
|
struct berval *vals[2];
|
|
MatchingRule *mr;
|
|
|
|
vals[0] = &val;
|
|
vals[1] = NULL;
|
|
|
|
for ( mr = mr_list; mr; mr = mr->smr_next ) {
|
|
val.bv_val = ldap_matchingrule2str( &mr->smr_mrule );
|
|
if ( val.bv_val ) {
|
|
val.bv_len = strlen( val.bv_val );
|
|
Debug( LDAP_DEBUG_TRACE, "Merging mr [%ld] %s\n",
|
|
(long) val.bv_len, val.bv_val, 0 );
|
|
attr_merge( e, "matchingRules", vals );
|
|
ldap_memfree( val.bv_val );
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
oc_schema_info( Entry *e )
|
|
{
|
|
struct berval val;
|
|
struct berval *vals[2];
|
|
ObjectClass *oc;
|
|
|
|
vals[0] = &val;
|
|
vals[1] = NULL;
|
|
|
|
for ( oc = oc_list; oc; oc = oc->soc_next ) {
|
|
val.bv_val = ldap_objectclass2str( &oc->soc_oclass );
|
|
if ( val.bv_val ) {
|
|
val.bv_len = strlen( val.bv_val );
|
|
Debug( LDAP_DEBUG_TRACE, "Merging oc [%ld] %s\n",
|
|
(long) val.bv_len, val.bv_val, 0 );
|
|
attr_merge( e, "objectClasses", vals );
|
|
ldap_memfree( val.bv_val );
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
schema_info( Connection *conn, Operation *op, char **attrs, int attrsonly )
|
|
{
|
|
Entry *e;
|
|
struct berval val;
|
|
struct berval *vals[2];
|
|
|
|
vals[0] = &val;
|
|
vals[1] = NULL;
|
|
|
|
e = (Entry *) ch_calloc( 1, sizeof(Entry) );
|
|
|
|
e->e_attrs = NULL;
|
|
e->e_dn = ch_strdup( SLAPD_SCHEMA_DN );
|
|
e->e_ndn = ch_strdup( SLAPD_SCHEMA_DN );
|
|
(void) dn_normalize( e->e_ndn );
|
|
e->e_private = NULL;
|
|
|
|
{
|
|
char *rdn = ch_strdup( SLAPD_SCHEMA_DN );
|
|
val.bv_val = strchr( rdn, '=' );
|
|
|
|
if( val.bv_val != NULL ) {
|
|
*val.bv_val = '\0';
|
|
val.bv_len = strlen( ++val.bv_val );
|
|
|
|
attr_merge( e, rdn, vals );
|
|
}
|
|
|
|
free( rdn );
|
|
}
|
|
|
|
if ( syn_schema_info( e ) ) {
|
|
/* Out of memory, do something about it */
|
|
entry_free( e );
|
|
return;
|
|
}
|
|
if ( mr_schema_info( e ) ) {
|
|
/* Out of memory, do something about it */
|
|
entry_free( e );
|
|
return;
|
|
}
|
|
if ( at_schema_info( e ) ) {
|
|
/* Out of memory, do something about it */
|
|
entry_free( e );
|
|
return;
|
|
}
|
|
if ( oc_schema_info( e ) ) {
|
|
/* Out of memory, do something about it */
|
|
entry_free( e );
|
|
return;
|
|
}
|
|
|
|
val.bv_val = "top";
|
|
val.bv_len = sizeof("top")-1;
|
|
attr_merge( e, "objectClass", vals );
|
|
|
|
val.bv_val = "LDAPsubentry";
|
|
val.bv_len = sizeof("LDAPsubentry")-1;
|
|
attr_merge( e, "objectClass", vals );
|
|
|
|
val.bv_val = "subschema";
|
|
val.bv_len = sizeof("subschema")-1;
|
|
attr_merge( e, "objectClass", vals );
|
|
|
|
val.bv_val = "extensibleObject";
|
|
val.bv_len = sizeof("extensibleObject")-1;
|
|
attr_merge( e, "objectClass", vals );
|
|
|
|
send_search_entry( &backends[0], conn, op,
|
|
e, attrs, attrsonly, NULL );
|
|
send_search_result( conn, op, LDAP_SUCCESS,
|
|
NULL, NULL, NULL, NULL, 1 );
|
|
|
|
entry_free( e );
|
|
}
|
|
#endif
|
|
|
|
#ifdef LDAP_DEBUG
|
|
|
|
static void
|
|
oc_print( ObjectClass *oc )
|
|
{
|
|
int i;
|
|
const char *mid;
|
|
|
|
printf( "objectclass %s\n", ldap_objectclass2name( &oc->soc_oclass ) );
|
|
if ( oc->soc_required != NULL ) {
|
|
mid = "\trequires ";
|
|
for ( i = 0; oc->soc_required[i] != NULL; i++, mid = "," )
|
|
printf( "%s%s", mid,
|
|
ldap_attributetype2name( &oc->soc_required[i]->sat_atype ) );
|
|
printf( "\n" );
|
|
}
|
|
if ( oc->soc_allowed != NULL ) {
|
|
mid = "\tallows ";
|
|
for ( i = 0; oc->soc_allowed[i] != NULL; i++, mid = "," )
|
|
printf( "%s%s", mid,
|
|
ldap_attributetype2name( &oc->soc_allowed[i]->sat_atype ) );
|
|
printf( "\n" );
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
int is_entry_objectclass(
|
|
Entry* e,
|
|
const char* oc)
|
|
{
|
|
Attribute *attr;
|
|
struct berval bv;
|
|
|
|
if( e == NULL || oc == NULL || *oc == '\0' )
|
|
return 0;
|
|
|
|
/*
|
|
* find objectClass attribute
|
|
*/
|
|
attr = attr_find(e->e_attrs, "objectclass");
|
|
|
|
if( attr == NULL ) {
|
|
/* no objectClass attribute */
|
|
return 0;
|
|
}
|
|
|
|
bv.bv_val = (char *) oc;
|
|
bv.bv_len = strlen( bv.bv_val );
|
|
|
|
if( value_find(attr->a_vals, &bv, attr->a_syntax, 1) != 0) {
|
|
/* entry is not of this objectclass */
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|