+
+/*
+ * Determine the structural object class from a set of OIDs
+ */
+int structural_class(
+ BVarray ocs,
+ struct berval *scbv,
+ const char **text,
+ char *textbuf, size_t textlen )
+{
+ int i;
+ ObjectClass *oc;
+ ObjectClass *sc = NULL;
+ int scn = -1;
+
+ *text = "structural_class: internal error";
+ scbv->bv_len = 0;
+
+ for( i=0; ocs[i].bv_val; i++ ) {
+ oc = oc_bvfind( &ocs[i] );
+
+ if( oc == NULL ) {
+ snprintf( textbuf, textlen,
+ "unrecongized objectClass '%s'",
+ ocs[i].bv_val );
+ *text = textbuf;
+ return LDAP_OBJECT_CLASS_VIOLATION;
+ }
+
+ if( oc->soc_kind == LDAP_SCHEMA_STRUCTURAL ) {
+ if( sc == NULL || is_object_subclass( sc, oc ) ) {
+ sc = oc;
+ scn = i;
+
+ } else if ( !is_object_subclass( oc, sc ) ) {
+ int j;
+ ObjectClass *xc = NULL;
+
+ /* find common superior */
+ for( j=i+1; ocs[j].bv_val; j++ ) {
+ xc = oc_bvfind( &ocs[j] );
+
+ if( xc == NULL ) {
+ snprintf( textbuf, textlen,
+ "unrecongized objectClass '%s'",
+ ocs[i].bv_val );
+ *text = textbuf;
+ return LDAP_OBJECT_CLASS_VIOLATION;
+ }
+
+ if( xc->soc_kind != LDAP_SCHEMA_STRUCTURAL ) {
+ xc = NULL;
+ continue;
+ }
+
+ if( is_object_subclass( sc, xc ) &&
+ is_object_subclass( oc, xc ) )
+ {
+ /* found common subclass */
+ break;
+ }
+
+ xc = NULL;
+ }
+
+ if( xc == NULL ) {
+ /* no common subclass */
+ snprintf( textbuf, textlen,
+ "invalid structural object class chain (%s/%s)",
+ ocs[scn].bv_val, ocs[i].bv_val );
+ *text = textbuf;
+ return LDAP_OBJECT_CLASS_VIOLATION;
+ }
+ }
+ }
+ }
+
+ if( sc == NULL ) {
+ *text = "no structural object classes provided";
+ return LDAP_OBJECT_CLASS_VIOLATION;
+ }
+
+ *scbv = ocs[scn];
+ return LDAP_SUCCESS;
+}
+
+/*
+ * Return structural object class from list of modifications
+ */
+int mods_structural_class(
+ Modifications *mods,
+ struct berval *sc,
+ const char **text,
+ char *textbuf, size_t textlen )
+{
+ Modifications *ocmod = NULL;
+
+ for( ; mods != NULL; mods = mods->sml_next ) {
+ if( mods->sml_desc == slap_schema.si_ad_objectClass ) {
+ if( ocmod != NULL ) {
+ *text = "entry has multiple objectClass attributes";
+ return LDAP_OBJECT_CLASS_VIOLATION;
+ }
+ ocmod = mods;
+ }
+ }
+
+ if( ocmod == NULL ) {
+ *text = "entry has no objectClass attribute";
+ return LDAP_OBJECT_CLASS_VIOLATION;
+ }
+
+ if( ocmod->sml_bvalues == NULL || ocmod->sml_bvalues[0].bv_val == NULL ) {
+ *text = "objectClass attribute has no values";
+ return LDAP_OBJECT_CLASS_VIOLATION;
+ }
+
+ return structural_class( ocmod->sml_bvalues, sc,
+ text, textbuf, textlen );
+}