/* 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 <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.
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",
/* 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) {
+ if ( (oc = oc_find( aoc->a_vals[i]->bv_val )) == 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;
+ "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;
+ }
}
}
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.
- * this function should be externalized...
*/
-static int
-oc_check_operational( char *type )
+int
+oc_check_operational_attr( const 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_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 )
{
AttributeType *at;
int i, j;
char **pp;
+ char *p, *t;
Debug( LDAP_DEBUG_TRACE,
"oc_check_allowed type \"%s\"\n", type, 0, 0 );
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 );
}
+ /*
+ * 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 */
oc->soc_required[j] != NULL; j++ ) {
at = oc->soc_required[j];
if ( at->sat_oid &&
- strcmp(at->sat_oid, type ) == 0 ) {
+ 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, type ) == 0 ) {
+ if ( strcasecmp( *pp, t ) == 0 ) {
+ if ( t != type )
+ ldap_memfree( t );
return( 0 );
}
pp++;
oc->soc_allowed[j] != NULL; j++ ) {
at = oc->soc_allowed[j];
if ( at->sat_oid &&
- strcmp(at->sat_oid, type ) == 0 ) {
+ 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, type ) == 0 ||
+ 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 );
}
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) )
+
+ code = oc_create_required(soc,soc1->soc_at_oids_must,err);
+ if ( code )
return code;
- if ( code = oc_create_allowed(soc,
- soc1->soc_at_oids_may,err) )
+ code = oc_create_allowed(soc,soc1->soc_at_oids_may,err);
+ if ( code )
return code;
+
nsups++;
sups1++;
}
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) )
+ 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) )
+ 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) )
+ if ( (code = oc_create_allowed(soc,soc->soc_at_oids_may,err)) != 0 )
return code;
code = oc_insert(soc,err);
return code;
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,
};
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.3 DESC 'AttributeTypeDescription' )", 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.6 DESC 'BitString' )", 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.9 DESC 'CertificateList' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'CertificatePair' )", 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.14 DESC 'DeliveryMethod' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'DirectoryString' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DITContentRuleDescription' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DITStructureRuleDescription' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'EnhancedGuide' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'FacsimileTelephoneNumber' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'GeneralizedTime' )", 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.26 DESC 'IA5String' )", 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.28 DESC 'JPEG' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'MatchingRuleDescription' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'MatchingRuleUseDescription' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'MailPreference' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'NameAndOptionalUID' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'NameFormDescription' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'NumericString' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'ObjectClassDescription' )", 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},
+ {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'OtherMailbox' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'OctetString' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'PostalAddress' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'ProtocolInformation' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'PresentationAddress' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'PrintableString' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'SupportedAlgorithm' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'TelephoneNumber' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'TeletexTerminalIdentifier' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'TelexNumber' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTCTime' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAPSyntaxDescription' )", NULL},
+ {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'SubstringAssertion' )", NULL},
+ {"( 1.3.6.1.1.1.0.0 DESC 'NISnetgrouptriple' )", NULL},
+ {"( 1.3.6.1.1.1.0.1 DESC 'Bootparameter' )", NULL},
{NULL, NULL}
};
schema_init( void )
{
int res;
- int code;
- const char *err;
int i;
static int schema_init_done = 0;
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++ ) {
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;
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 );
+ 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 {
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 );
+ 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 {
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 );
+ 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 {
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( 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 */
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 );
}
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,
+ 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;
+}