X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fschema.c;h=ad022a60bbfa062a185d49523edc49e0a59850a2;hb=6147119dc8526a758a7c576940fe8483e2b93915;hp=e9eee40396c07ac753bd4dec5a4affc2ab8526e0;hpb=87b86a52e4bc136e0c4cd279ca867de599a25b0b;p=openldap diff --git a/servers/slapd/schema.c b/servers/slapd/schema.c index e9eee40396..ad022a60bb 100644 --- a/servers/slapd/schema.c +++ b/servers/slapd/schema.c @@ -1,18 +1,24 @@ /* 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 "ldapconfig.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. @@ -29,7 +35,7 @@ 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 */ @@ -122,20 +128,84 @@ oc_check_required( Entry *e, char *ocname ) 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. - * this function should be externalized... */ -static int -oc_check_operational( char *type ) +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 ( strcasecmp( type, "modifiersname" ) == 0 || - strcasecmp( type, "modifytimestamp" ) == 0 || - strcasecmp( type, "creatorsname" ) == 0 || - strcasecmp( type, "createtimestamp" ) == 0 ) - ? 1 : 0; + return charray_inlist( oc_no_usermod_attrs, type ); } + static int oc_check_allowed( char *type, struct berval **ocl ) { @@ -152,7 +222,12 @@ oc_check_allowed( char *type, struct berval **ocl ) return( 0 ); } - if ( oc_check_operational( type ) ) { + /* + * 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 ); } @@ -633,16 +708,122 @@ mr_add( ) { 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, @@ -660,7 +841,7 @@ register_syntax( } code = syn_add( syn, check, &err ); if ( code ) { - Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s for %s in %s\n", + Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s %s in %s\n", scherr2str(code), err, desc ); return( -1 ); } @@ -699,21 +880,46 @@ struct syntax_defs_rec { 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} }; @@ -723,16 +929,68 @@ struct mrule_defs_rec { 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 )", NULL, NULL}, - {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", 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} }; @@ -740,31 +998,35 @@ int schema_init( void ) { int res; - int code; - const char *err; int i; + static int schema_init_done = 0; - /* For now */ - return( 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 ); + 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_compare ); + ( 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 ); + exit( EXIT_FAILURE ); } } + schema_init_done = 1; + return( 0 ); } #if defined( SLAPD_SCHEMA_DN ) @@ -858,18 +1120,23 @@ schema_info( Connection *conn, Operation *op, char **attrs, int attrsonly ) 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_ndn = ch_strdup( SLAPD_SCHEMA_DN ); + (void) dn_normalize_case( e->e_ndn ); 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 ); + { + char *rdn = ch_strdup( SLAPD_SCHEMA_DN ); + val.bv_val = strchr( rdn, '=' ); - val.bv_val = ch_strdup( "subschema" ); - val.bv_len = strlen( val.bv_val ); - attr_merge( e, "objectclass", vals ); - ldap_memfree( val.bv_val ); + 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 */ @@ -892,8 +1159,26 @@ schema_info( Connection *conn, Operation *op, char **attrs, int attrsonly ) return; } - send_search_entry( &backends[0], conn, op, e, attrs, attrsonly ); - send_ldap_search_result( conn, op, LDAP_SUCCESS, NULL, NULL, 1 ); + 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 ); } @@ -905,26 +1190,55 @@ static void oc_print( ObjectClass *oc ) { int i; + const char *mid; - if ( oc->soc_names && oc->soc_names[0] ) { - printf( "objectclass %s\n", oc->soc_names[0] ); - } else { - printf( "objectclass %s\n", oc->soc_oid ); - } + printf( "objectclass %s\n", ldap_objectclass2name( &oc->soc_oclass ) ); 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] ); - } + 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 ) { - printf( "\tallows %s", oc->soc_allowed[0] ); - for ( i = 1; oc->soc_allowed[i] != NULL; i++ ) { - printf( ",%s", oc->soc_allowed[i] ); - } + 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, + 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; +}