openldap/servers/slapd/schema.c
Kurt Zeilenga 73276e84ae Import experimental referral implementation from OPENLDAP_DEVEL_REFERRALS.
Includes support for update referral for each replicated backend.
	Reworked replication test to use update referral.
Includes major rewrite of response encoding codes (result.c).
Includes reworked alias support and eliminates old suffix alias codes
(can be emulated using named alias).
Includes (untested) support for the Manage DSA IT control.
Works in LDAPv2 world.  Still testing in LDAPv3 world.
Added default referral (test009) test.
1999-07-16 02:45:46 +00:00

1215 lines
28 KiB
C

/* schema.c - routines to enforce schema definitions */
#include "portable.h"
#include <stdio.h>
#include <ac/ctype.h>
#include <ac/string.h>
#include <ac/socket.h>
#include "ldap_defaults.h"
#include "slap.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;
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++ ) {
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 that *could* be
* modified by users if we supported such.
*/
"objectClasses",
"attributeTypes",
"matchingRules",
"matchingRuleUse",
"dITStructureRules",
"dITContentRules",
"nameForms",
"ldapSyntaxes",
NULL
};
/* this list should be extensible */
static char *oc_no_usermod_attrs[] = {
/*
* Operational and 'no user modification' attributes
*/
/* RFC2252, 3.2.1 */
"creatorsName",
"createTimestamp",
"modifiersName",
"modifyTimestamp",
"subschemaSubentry",
NULL
};
/*
* check to see if attribute is 'operational' or not.
*/
int
oc_check_operational_attr( 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( 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( 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;
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 );
}
/* 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, type ) == 0 ) {
return( 0 );
}
pp = at->sat_names;
if ( pp == NULL )
continue;
while ( *pp ) {
if ( strcasecmp( *pp, type ) == 0 ) {
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, type ) == 0 ) {
return( 0 );
}
pp = at->sat_names;
if ( pp == NULL )
continue;
while ( *pp ) {
if ( strcasecmp( *pp, type ) == 0 ||
strcmp( *pp, "*" ) == 0 ) {
return( 0 );
}
pp++;
}
}
/* maybe the next oc allows it */
/* we don't know about the oc. assume it allows it */
} else {
return( 0 );
}
}
/* 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;
if ( code = oc_create_required(soc,
soc1->soc_at_oids_must,err) )
return code;
if ( code = oc_create_allowed(soc,
soc1->soc_at_oids_may,err) )
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) )
return code;
if ( code = oc_create_required(soc,soc->soc_at_oids_must,err) )
return code;
if ( code = oc_create_allowed(soc,soc->soc_at_oids_may,err) )
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 );
}
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_check_func *check,
const char **err
)
{
Syntax *ssyn;
int code;
ssyn = (Syntax *) ch_calloc( 1, sizeof(Syntax) );
memcpy( &ssyn->ssyn_syn, syn, sizeof(LDAP_SYNTAX));
ssyn->ssyn_check = check;
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_normalize_func *normalize,
slap_mr_compare_func *compare,
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_normalize = normalize;
smr->smr_compare = compare;
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
case_exact_normalize(
struct berval *val,
struct berval **normalized
)
{
struct berval *newval;
char *p, *q;
newval = ber_bvdup( val );
p = q = newval->bv_val;
/* Ignore initial whitespace */
while ( isspace( *p++ ) )
;
while ( *p ) {
if ( isspace( *p ) ) {
*q++ = *p++;
/* Ignore the extra whitespace */
while ( isspace(*p++) )
;
} else {
*q++ = *p++;
}
}
/*
* 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 ( p != newval->bv_val && isspace( *(p-1) ) ) {
*(q-1) = '\0';
}
newval->bv_len = strlen( newval->bv_val );
normalized = &newval;
return 0;
}
static int
case_exact_compare(
struct berval *val1,
struct berval *val2
)
{
return strcmp( val1->bv_val, val2->bv_val );
}
int
case_ignore_normalize(
struct berval *val,
struct berval **normalized
)
{
struct berval *newval;
char *p, *q;
newval = ber_bvdup( val );
p = q = newval->bv_val;
/* Ignore initial whitespace */
while ( isspace( *p++ ) )
;
while ( *p ) {
if ( isspace( *p ) ) {
*q++ = *p++;
/* Ignore the extra whitespace */
while ( isspace(*p++) )
;
} else {
*q++ = TOUPPER( *p++ );
}
}
/*
* 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 ( p != newval->bv_val && isspace( *(p-1) ) ) {
*(q-1) = '\0';
}
newval->bv_len = strlen( newval->bv_val );
normalized = &newval;
return 0;
}
static int
case_ignore_compare(
struct berval *val1,
struct berval *val2
)
{
return strcasecmp( val1->bv_val, val2->bv_val );
}
int
register_syntax(
char * desc,
slap_syntax_check_func *check )
{
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, check, &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_normalize_func *normalize,
slap_mr_compare_func *compare )
{
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, normalize, compare, &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_check_func *sd_check;
};
struct syntax_defs_rec syntax_defs[] = {
{"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'DN' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'INTEGER' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )", NULL},
{"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )", NULL},
{"( 1.3.6.1.1.1.0.0 DESC 'NIS netgroup triple' )", NULL},
{"( 1.3.6.1.1.1.0.1 DESC 'Boot parameter' )", NULL},
{NULL, NULL}
};
struct mrule_defs_rec {
char *mrd_desc;
slap_mr_normalize_func *mrd_normalize;
slap_mr_compare_func *mrd_compare;
};
/*
* 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
*/
struct mrule_defs_rec mrule_defs[] = {
{"( 2.5.13.0 NAME 'objectIdentifierMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", NULL, NULL},
{"( 2.5.13.1 NAME 'distinguishedNameMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )", NULL, NULL},
{"( 2.5.13.2 NAME 'caseIgnoreMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
case_ignore_normalize, case_ignore_compare},
{"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
case_ignore_normalize, case_ignore_compare},
{"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
case_ignore_normalize, case_ignore_compare},
/* 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 )",
case_exact_normalize, case_exact_compare},
{"( 2.5.13.6 NAME 'caseExactOrderingMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
case_exact_normalize, case_exact_compare},
{"( 2.5.13.7 NAME 'caseExactSubstringsMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
case_exact_normalize, case_exact_compare},
{"( 2.5.13.8 NAME 'numericStringMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )", NULL, NULL},
{"( 2.5.13.10 NAME 'numericStringSubstringsMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", NULL, NULL},
{"( 2.5.13.11 NAME 'caseIgnoreListMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )", NULL, NULL},
{"( 2.5.13.14 NAME 'integerMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", NULL, NULL},
{"( 2.5.13.16 NAME 'bitStringMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )", NULL, NULL},
{"( 2.5.13.17 NAME 'octetStringMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", NULL, NULL},
{"( 2.5.13.20 NAME 'telephoneNumberMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )", NULL, NULL},
{"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", NULL, NULL},
{"( 2.5.13.22 NAME 'presentationAddressMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )", NULL, NULL},
{"( 2.5.13.23 NAME 'uniqueMemberMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )", NULL, NULL},
{"( 2.5.13.24 NAME 'protocolInformationMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )", NULL, NULL},
{"( 2.5.13.27 NAME 'generalizedTimeMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )", NULL, NULL},
{"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )", NULL, NULL},
{"( 2.5.13.29 NAME 'integerFirstComponentMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", NULL, NULL},
{"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", NULL, NULL},
{"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
case_exact_normalize, case_exact_compare},
{"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
case_ignore_normalize, case_ignore_compare},
{NULL, 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_check );
if ( res ) {
fprintf( stderr, "schema_init: Error registering syntax %s\n",
syntax_defs[i].sd_desc );
exit( 1 );
}
}
for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
res = register_matching_rule( mrule_defs[i].mrd_desc,
( mrule_defs[i].mrd_normalize ?
mrule_defs[i].mrd_normalize : case_ignore_normalize ),
( mrule_defs[i].mrd_compare ?
mrule_defs[i].mrd_compare : case_ignore_compare ) );
if ( res ) {
fprintf( stderr, "schema_init: Error registering matching rule %s\n",
mrule_defs[i].mrd_desc );
exit( 1 );
}
}
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 [%d] %s\n",
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 [%d] %s\n",
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 [%d] %s\n",
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 = dn_normalize_case( ch_strdup( SLAPD_SCHEMA_DN ));
e->e_private = NULL;
val.bv_val = ch_strdup( "top" );
val.bv_len = strlen( val.bv_val );
attr_merge( e, "objectClass", vals );
ldap_memfree( val.bv_val );
val.bv_val = ch_strdup( "subschema" );
val.bv_len = strlen( val.bv_val );
attr_merge( e, "objectClass", vals );
ldap_memfree( val.bv_val );
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;
}
send_search_entry( &backends[0], conn, op,
e, attrs, attrsonly, 0, 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;
if ( oc->soc_names && oc->soc_names[0] ) {
printf( "objectclass %s\n", oc->soc_names[0] );
} else {
printf( "objectclass %s\n", oc->soc_oid );
}
if ( oc->soc_required != NULL ) {
printf( "\trequires %s", oc->soc_required[0] );
for ( i = 1; oc->soc_required[i] != NULL; i++ ) {
printf( ",%s", oc->soc_required[i] );
}
printf( "\n" );
}
if ( oc->soc_allowed != NULL ) {
printf( "\tallows %s", oc->soc_allowed[0] );
for ( i = 1; oc->soc_allowed[i] != NULL; i++ ) {
printf( ",%s", oc->soc_allowed[i] );
}
printf( "\n" );
}
}
#endif
int is_entry_objectclass(
Entry* e,
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 = 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;
}