X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fschema.c;h=44c86656d8bc2ddbf87eae3596e314a35f6a0590;hb=740f1b422edc48c9eeed8346c45872a63b683370;hp=a5c297fbe3995976e2307fcb6101273322c86c93;hpb=fcbca73f90d6f4dd09e7ff34533b6ac1baff2135;p=openldap diff --git a/servers/slapd/schema.c b/servers/slapd/schema.c index a5c297fbe3..44c86656d8 100644 --- a/servers/slapd/schema.c +++ b/servers/slapd/schema.c @@ -1,21 +1,23 @@ /* schema.c - routines to enforce schema definitions */ +/* + * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" #include -#include -#include -#include -#include "slap.h" -extern Attribute *attr_find(); -extern char **str2charray(); -extern void charray_merge(); +#include +#include +#include + +#include "ldap_defaults.h" +#include "slap.h" -extern struct objclass *global_oc; -extern int global_schemacheck; +static char * oc_check_required(Entry *e, char *ocname); +static int oc_check_allowed(char *type, struct berval **ocl); -static struct objclass *oc_find(); -static int oc_check_required(); -static int oc_check_allowed(); /* * oc_check - check that entry e conforms to the schema required by @@ -26,7 +28,6 @@ int oc_schema_check( Entry *e ) { Attribute *a, *aoc; - struct objclass *oc; int i; int ret = 0; @@ -34,15 +35,17 @@ oc_schema_check( Entry *e ) 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( 0 ); + return( 1 ); } /* check that the entry has required attrs for each oc */ for ( i = 0; aoc->a_vals[i] != NULL; i++ ) { - if ( oc_check_required( e, aoc->a_vals[i]->bv_val ) != 0 ) { + char *s = oc_check_required( e, aoc->a_vals[i]->bv_val ); + + if (s != NULL) { Debug( LDAP_DEBUG_ANY, - "Entry (%s), required attr (%s) missing\n", - e->e_dn, aoc->a_vals[i]->bv_val, 0 ); + "Entry (%s), oc \"%s\" requires attr \"%s\"\n", + e->e_dn, aoc->a_vals[i]->bv_val, s ); ret = 1; } } @@ -55,7 +58,7 @@ oc_schema_check( Entry *e ) 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", + "Entry (%s), attr \"%s\" not allowed\n", e->e_dn, a->a_type, 0 ); ret = 1; } @@ -64,69 +67,210 @@ oc_schema_check( Entry *e ) return( ret ); } -static int +static char * oc_check_required( Entry *e, char *ocname ) { - struct objclass *oc; + 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->oc_required[i] != NULL; i++ ) { + 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 ( strcasecmp( a->a_type, oc->oc_required[i] ) - == 0 ) { + 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 ) { - return( 1 ); + if ( at->sat_names && at->sat_names[0] ) { + return at->sat_names[0]; + } else { + return at->sat_oid; + } } } - return( 0 ); + 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", + "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( 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 ) { - struct objclass *oc; + 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->oc_required != NULL && - oc->oc_required[j] != NULL; j++ ) { - if ( strcasecmp( oc->oc_required[j], type ) - == 0 ) { + 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->oc_allowed != NULL && - oc->oc_allowed[j] != NULL; j++ ) { - if ( strcasecmp( oc->oc_allowed[j], type ) - == 0 || strcmp( oc->oc_allowed[j], "*" ) - == 0 ) - { + 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 */ @@ -140,42 +284,960 @@ oc_check_allowed( char *type, struct berval **ocl ) return( 1 ); } -static struct objclass * -oc_find( char *ocname ) +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 +) { - struct objclass *oc; + char **attrs1; + AttributeType *sat; - for ( oc = global_oc; oc != NULL; oc = oc->oc_next ) { - if ( strcasecmp( oc->oc_name, ocname ) == 0 ) { - return( oc ); + 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( 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_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( 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 [%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 = ch_strdup( SLAPD_SCHEMA_DN ); + (void) dn_normalize_case( 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 = "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 -oc_print( struct objclass *oc ) +static void +oc_print( ObjectClass *oc ) { int i; - printf( "objectclass %s\n", oc->oc_name ); - if ( oc->oc_required != NULL ) { - printf( "\trequires %s", oc->oc_required[0] ); - for ( i = 1; oc->oc_required[i] != NULL; i++ ) { - printf( ",%s", oc->oc_required[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->oc_allowed != NULL ) { - printf( "\tallows %s", oc->oc_allowed[0] ); - for ( i = 1; oc->oc_allowed[i] != NULL; i++ ) { - printf( ",%s", oc->oc_allowed[i] ); + 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; +}