int is_object_subclass( ObjectClass *sup, ObjectClass *sub ) { int i; if( sub == NULL || sup == NULL ) return 0; #if 0 Debug( LDAP_DEBUG_TRACE, "is_object_subclass(%s,%s) %d\n", sup->soc_oid, sub->soc_oid, sup == sub ); #endif if ( sup == sub ) { return 1; } if ( sub->soc_sups == NULL ) { return 0; } for ( i = 0; sub->soc_sups[i] != NULL; i++ ) { if ( is_object_subclass( sup, sub->soc_sups[i] ) ) { return 1; } } return 0; }
static int objectSubClassMatch( int *matchp, slap_mask_t flags, Syntax *syntax, MatchingRule *mr, struct berval *value, void *assertedValue ) { struct berval *a = (struct berval *) assertedValue; ObjectClass *oc = oc_bvfind( value ); ObjectClass *asserted = oc_bvfind( a ); if( asserted == NULL ) { if( OID_LEADCHAR( *a->bv_val ) ) { /* OID form, return FALSE */ *matchp = 1; return LDAP_SUCCESS; } /* desc form, return undefined */ return LDAP_INVALID_SYNTAX; } if ( oc == NULL ) { /* unrecognized stored value */ return LDAP_INVALID_SYNTAX; } if( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX( flags ) ) { *matchp = ( asserted != oc ); } else { *matchp = !is_object_subclass( asserted, oc ); } return LDAP_SUCCESS; }
int is_entry_objectclass( Entry* e, ObjectClass *oc, unsigned flags ) { /* * set_flags should only be true if oc is one of operational * object classes which we support objectClass flags for * (e.g., referral, alias, ...). See <slap.h>. */ Attribute *attr; struct berval *bv; assert( !( e == NULL || oc == NULL ) ); assert( ( flags & SLAP_OCF_MASK ) != SLAP_OCF_MASK ); if ( e == NULL || oc == NULL ) { return 0; } if ( flags == SLAP_OCF_SET_FLAGS && ( e->e_ocflags & SLAP_OC__END ) ) { /* flags are set, use them */ return (e->e_ocflags & oc->soc_flags & SLAP_OC__MASK) != 0; } /* * find objectClass attribute */ attr = attr_find( e->e_attrs, slap_schema.si_ad_objectClass ); if ( attr == NULL ) { /* no objectClass attribute */ Debug( LDAP_DEBUG_ANY, "is_entry_objectclass(\"%s\", \"%s\") " "no objectClass attribute\n", e->e_dn == NULL ? "" : e->e_dn, oc->soc_oclass.oc_oid ); /* mark flags as set */ e->e_ocflags |= SLAP_OC__END; return 0; } for ( bv = attr->a_vals; bv->bv_val; bv++ ) { ObjectClass *objectClass = oc_bvfind( bv ); if ( objectClass == NULL ) { /* FIXME: is this acceptable? */ continue; } if ( !( flags & SLAP_OCF_SET_FLAGS ) ) { if ( objectClass == oc ) { return 1; } if ( ( flags & SLAP_OCF_CHECK_SUP ) && is_object_subclass( oc, objectClass ) ) { return 1; } } e->e_ocflags |= objectClass->soc_flags; } /* mark flags as set */ e->e_ocflags |= SLAP_OC__END; return ( e->e_ocflags & oc->soc_flags & SLAP_OC__MASK ) != 0; }
int backsql_id2entry( backsql_srch_info *bsi, backsql_entryID *eid ) { Operation *op = bsi->bsi_op; backsql_info *bi = (backsql_info *)op->o_bd->be_private; int i; int rc; Debug( LDAP_DEBUG_TRACE, "==>backsql_id2entry()\n", 0, 0, 0 ); assert( bsi->bsi_e != NULL ); memset( bsi->bsi_e, 0, sizeof( Entry ) ); if ( bi->sql_baseObject && BACKSQL_IS_BASEOBJECT_ID( &eid->eid_id ) ) { Entry *e; e = entry_dup( bi->sql_baseObject ); if ( e == NULL ) { return LDAP_NO_MEMORY; } *bsi->bsi_e = *e; free( e ); goto done; } ber_dupbv_x( &bsi->bsi_e->e_name, &eid->eid_dn, op->o_tmpmemctx ); ber_dupbv_x( &bsi->bsi_e->e_nname, &eid->eid_ndn, op->o_tmpmemctx ); bsi->bsi_e->e_attrs = NULL; bsi->bsi_e->e_private = NULL; if ( eid->eid_oc == NULL ) { eid->eid_oc = backsql_id2oc( bsi->bsi_op->o_bd->be_private, eid->eid_oc_id ); } bsi->bsi_oc = eid->eid_oc; bsi->bsi_c_eid = eid; #ifndef BACKSQL_ARBITRARY_KEY /* FIXME: unused */ bsi->bsi_e->e_id = eid->eid_id; #endif /* ! BACKSQL_ARBITRARY_KEY */ rc = attr_merge_normalize_one( bsi->bsi_e, slap_schema.si_ad_objectClass, &bsi->bsi_oc->bom_oc->soc_cname, bsi->bsi_op->o_tmpmemctx ); if ( rc != LDAP_SUCCESS ) { backsql_entry_clean( op, bsi->bsi_e ); return rc; } if ( bsi->bsi_attrs == NULL || ( bsi->bsi_flags & BSQL_SF_ALL_USER ) ) { Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): " "retrieving all attributes\n", 0, 0, 0 ); avl_apply( bsi->bsi_oc->bom_attrs, backsql_get_attr_vals, bsi, 0, AVL_INORDER ); } else { Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): " "custom attribute list\n", 0, 0, 0 ); for ( i = 0; !BER_BVISNULL( &bsi->bsi_attrs[ i ].an_name ); i++ ) { backsql_at_map_rec **vat; AttributeName *an = &bsi->bsi_attrs[ i ]; int j; /* if one of the attributes listed here is * a subtype of another, it must be ignored, * because subtypes are already dealt with * by backsql_supad2at() */ for ( j = 0; !BER_BVISNULL( &bsi->bsi_attrs[ j ].an_name ); j++ ) { /* skip self */ if ( j == i ) { continue; } /* skip subtypes */ if ( is_at_subtype( an->an_desc->ad_type, bsi->bsi_attrs[ j ].an_desc->ad_type ) ) { goto next; } } rc = backsql_supad2at( bsi->bsi_oc, an->an_desc, &vat ); if ( rc != 0 || vat == NULL ) { Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(): " "attribute \"%s\" is not defined " "for objectlass \"%s\"\n", an->an_name.bv_val, BACKSQL_OC_NAME( bsi->bsi_oc ), 0 ); continue; } for ( j = 0; vat[j]; j++ ) { backsql_get_attr_vals( vat[j], bsi ); } ch_free( vat ); next:; } } if ( bsi->bsi_flags & BSQL_SF_RETURN_ENTRYUUID ) { Attribute *a_entryUUID, **ap; a_entryUUID = backsql_operational_entryUUID( bi, eid ); if ( a_entryUUID != NULL ) { for ( ap = &bsi->bsi_e->e_attrs; *ap; ap = &(*ap)->a_next ); *ap = a_entryUUID; } } if ( ( bsi->bsi_flags & BSQL_SF_ALL_OPER ) || an_find( bsi->bsi_attrs, slap_bv_all_operational_attrs ) || an_find( bsi->bsi_attrs, &slap_schema.si_ad_structuralObjectClass->ad_cname ) ) { ObjectClass *soc = NULL; if ( BACKSQL_CHECK_SCHEMA( bi ) ) { Attribute *a; const char *text = NULL; char textbuf[ 1024 ]; size_t textlen = sizeof( textbuf ); struct berval bv[ 2 ], *nvals; int rc = LDAP_SUCCESS; a = attr_find( bsi->bsi_e->e_attrs, slap_schema.si_ad_objectClass ); if ( a != NULL ) { nvals = a->a_nvals; } else { bv[ 0 ] = bsi->bsi_oc->bom_oc->soc_cname; BER_BVZERO( &bv[ 1 ] ); nvals = bv; } rc = structural_class( nvals, &soc, NULL, &text, textbuf, textlen, op->o_tmpmemctx ); if ( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): " "structural_class() failed %d (%s)\n", bsi->bsi_e->e_name.bv_val, rc, text ? text : "" ); backsql_entry_clean( op, bsi->bsi_e ); return rc; } if ( !bvmatch( &soc->soc_cname, &bsi->bsi_oc->bom_oc->soc_cname ) ) { if ( !is_object_subclass( bsi->bsi_oc->bom_oc, soc ) ) { Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): " "computed structuralObjectClass %s " "does not match objectClass %s associated " "to entry\n", bsi->bsi_e->e_name.bv_val, soc->soc_cname.bv_val, bsi->bsi_oc->bom_oc->soc_cname.bv_val ); backsql_entry_clean( op, bsi->bsi_e ); return rc; } Debug( LDAP_DEBUG_TRACE, "backsql_id2entry(%s): " "computed structuralObjectClass %s " "is subclass of objectClass %s associated " "to entry\n", bsi->bsi_e->e_name.bv_val, soc->soc_cname.bv_val, bsi->bsi_oc->bom_oc->soc_cname.bv_val ); } } else { soc = bsi->bsi_oc->bom_oc; } rc = attr_merge_normalize_one( bsi->bsi_e, slap_schema.si_ad_structuralObjectClass, &soc->soc_cname, bsi->bsi_op->o_tmpmemctx ); if ( rc != LDAP_SUCCESS ) { backsql_entry_clean( op, bsi->bsi_e ); return rc; } } done:; Debug( LDAP_DEBUG_TRACE, "<==backsql_id2entry()\n", 0, 0, 0 ); return LDAP_SUCCESS; }
/* * Determine the structural object class from a set of OIDs */ int structural_class( BerVarray ocs, ObjectClass **scp, ObjectClass ***socsp, const char **text, char *textbuf, size_t textlen, void *ctx ) { int i, nocs; ObjectClass *oc, **socs; ObjectClass *sc = NULL; int scn = -1; *text = "structural_class: internal error"; /* count them */ for( i=0; ocs[i].bv_val; i++ ) ; nocs = i; socs = slap_sl_malloc( (nocs+1) * sizeof(ObjectClass *), ctx ); for( i=0; ocs[i].bv_val; i++ ) { socs[i] = oc_bvfind( &ocs[i] ); if( socs[i] == NULL ) { snprintf( textbuf, textlen, "unrecognized objectClass '%s'", ocs[i].bv_val ); *text = textbuf; goto fail; } } socs[i] = NULL; for( i=0; ocs[i].bv_val; i++ ) { oc = socs[i]; 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 = socs[j]; if( xc == NULL ) { snprintf( textbuf, textlen, "unrecognized objectClass '%s'", ocs[j].bv_val ); *text = textbuf; goto fail; } 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; goto fail; } } } } if( scp ) { *scp = sc; } if( sc == NULL ) { *text = "no structural object class provided"; goto fail; } if( scn < 0 ) { *text = "invalid structural object class"; goto fail; } if ( socsp ) { *socsp = socs; } else { slap_sl_free( socs, ctx ); } *text = NULL; return LDAP_SUCCESS; fail: slap_sl_free( socs, ctx ); return LDAP_OBJECT_CLASS_VIOLATION; }
int entry_schema_check( Operation *op, Entry *e, Attribute *oldattrs, int manage, int add, Attribute **socp, const char** text, char *textbuf, size_t textlen ) { Attribute *a, *asc = NULL, *aoc = NULL; ObjectClass *sc, *oc, **socs = NULL; AttributeType *at; ContentRule *cr; int rc, i; AttributeDescription *ad_structuralObjectClass = slap_schema.si_ad_structuralObjectClass; AttributeDescription *ad_objectClass = slap_schema.si_ad_objectClass; int extensible = 0; int subentry = is_entry_subentry( e ); int collectiveSubentry = 0; if ( SLAP_NO_SCHEMA_CHECK( op->o_bd )) { return LDAP_SUCCESS; } if ( get_no_schema_check( op ) ) { return LDAP_SUCCESS; } if( subentry ) { collectiveSubentry = is_entry_collectiveAttributeSubentry( e ); } *text = textbuf; /* misc attribute checks */ for ( a = e->e_attrs; a != NULL; a = a->a_next ) { const char *type = a->a_desc->ad_cname.bv_val; /* there should be at least one value */ assert( a->a_vals != NULL ); assert( a->a_vals[0].bv_val != NULL ); if( a->a_desc->ad_type->sat_check ) { rc = (a->a_desc->ad_type->sat_check)( op->o_bd, e, a, text, textbuf, textlen ); if( rc != LDAP_SUCCESS ) { return rc; } } if( a->a_desc == ad_structuralObjectClass ) asc = a; else if ( a->a_desc == ad_objectClass ) aoc = a; if( !collectiveSubentry && is_at_collective( a->a_desc->ad_type ) ) { snprintf( textbuf, textlen, "'%s' can only appear in collectiveAttributeSubentry", type ); return LDAP_OBJECT_CLASS_VIOLATION; } /* if single value type, check for multiple values */ if( is_at_single_value( a->a_desc->ad_type ) && a->a_vals[1].bv_val != NULL ) { Debug(LDAP_DEBUG_ANY, "Entry (%s), attribute '%s' cannot have multiple values\n", e->e_dn, type ); return LDAP_CONSTRAINT_VIOLATION; } } /* check the object class attribute */ if ( aoc == NULL ) { Debug( LDAP_DEBUG_ANY, "No objectClass for entry (%s)\n", e->e_dn ); *text = "no objectClass attribute"; return LDAP_OBJECT_CLASS_VIOLATION; } assert( aoc->a_vals != NULL ); assert( aoc->a_vals[0].bv_val != NULL ); /* check the structural object class attribute */ if ( asc == NULL && !add ) { Debug( LDAP_DEBUG_ANY, "No structuralObjectClass for entry (%s)\n", e->e_dn ); *text = "no structuralObjectClass operational attribute"; return LDAP_OTHER; } rc = structural_class( aoc->a_vals, &oc, &socs, text, textbuf, textlen, op->o_tmpmemctx ); if( rc != LDAP_SUCCESS ) { return rc; } if ( asc == NULL && add ) { attr_merge_one( e, ad_structuralObjectClass, &oc->soc_cname, NULL ); asc = attr_find( e->e_attrs, ad_structuralObjectClass ); sc = oc; goto got_soc; } assert( asc->a_vals != NULL ); assert( asc->a_vals[0].bv_val != NULL ); assert( asc->a_vals[1].bv_val == NULL ); sc = oc_bvfind( &asc->a_vals[0] ); if( sc == NULL ) { Debug(LDAP_DEBUG_ANY, "entry_check_schema(%s): unrecognized structuralObjectClass '%s'\n", e->e_dn, asc->a_vals[0].bv_val ); rc = LDAP_OBJECT_CLASS_VIOLATION; goto done; } if( sc->soc_kind != LDAP_SCHEMA_STRUCTURAL ) { Debug(LDAP_DEBUG_ANY, "entry_check_schema(%s): structuralObjectClass '%s' is not STRUCTURAL\n", e->e_dn, asc->a_vals[0].bv_val ); rc = LDAP_OTHER; goto done; } got_soc: if( !manage && sc->soc_obsolete ) { Debug(LDAP_DEBUG_ANY, "entry_check_schema(%s): structuralObjectClass '%s' is OBSOLETE\n", e->e_dn, asc->a_vals[0].bv_val ); rc = LDAP_OBJECT_CLASS_VIOLATION; goto done; } *text = textbuf; if ( oc == NULL ) { snprintf( textbuf, textlen, "unrecognized objectClass '%s'", aoc->a_vals[0].bv_val ); rc = LDAP_OBJECT_CLASS_VIOLATION; goto done; } else if ( sc != oc ) { if ( !manage && sc != slap_schema.si_oc_glue ) { snprintf( textbuf, textlen, "structural object class modification " "from '%s' to '%s' not allowed", asc->a_vals[0].bv_val, oc->soc_cname.bv_val ); rc = LDAP_NO_OBJECT_CLASS_MODS; goto done; } assert( asc->a_vals != NULL ); assert( !BER_BVISNULL( &asc->a_vals[0] ) ); assert( BER_BVISNULL( &asc->a_vals[1] ) ); assert( asc->a_nvals == asc->a_vals ); /* draft-zeilenga-ldap-relax: automatically modify * structuralObjectClass if changed with relax */ sc = oc; ber_bvreplace( &asc->a_vals[ 0 ], &sc->soc_cname ); if ( socp ) { *socp = asc; } } /* naming check */ if ( !is_entry_glue ( e ) ) { rc = entry_naming_check( e, manage, add, text, textbuf, textlen ); if( rc != LDAP_SUCCESS ) { goto done; } } else { /* Glue Entry */ } /* find the content rule for the structural class */ cr = cr_find( sc->soc_oid ); /* the cr must be same as the structural class */ assert( !cr || !strcmp( cr->scr_oid, sc->soc_oid ) ); /* check that the entry has required attrs of the content rule */ if( cr ) { if( !manage && cr->scr_obsolete ) { Debug(LDAP_DEBUG_ANY, "Entry (%s): content rule '%s' is obsolete\n", e->e_dn, ldap_contentrule2name(&cr->scr_crule) ); rc = LDAP_OBJECT_CLASS_VIOLATION; goto done; } if( cr->scr_required ) for( i=0; cr->scr_required[i]; i++ ) { at = cr->scr_required[i]; for ( a = e->e_attrs; a != NULL; a = a->a_next ) { if( a->a_desc->ad_type == at ) { break; } } /* not there => schema violation */ if ( a == NULL ) { Debug(LDAP_DEBUG_ANY, "Entry (%s): content rule '%s' requires attribute '%s'\n", e->e_dn, ldap_contentrule2name(&cr->scr_crule), at->sat_cname.bv_val ); rc = LDAP_OBJECT_CLASS_VIOLATION; goto done; } } if( cr->scr_precluded ) for( i=0; cr->scr_precluded[i]; i++ ) { at = cr->scr_precluded[i]; for ( a = e->e_attrs; a != NULL; a = a->a_next ) { if( a->a_desc->ad_type == at ) { break; } } /* there => schema violation */ if ( a != NULL ) { Debug(LDAP_DEBUG_ANY, "Entry (%s): content rule '%s' precluded attribute '%s'\n", e->e_dn, ldap_contentrule2name(&cr->scr_crule), at->sat_cname.bv_val ); rc = LDAP_OBJECT_CLASS_VIOLATION; goto done; } } } /* check that the entry has required attrs for each oc */ for ( i = 0; socs[i]; i++ ) { oc = socs[i]; if ( !manage && oc->soc_obsolete ) { /* disallow obsolete classes */ Debug(LDAP_DEBUG_ANY, "entry_check_schema(%s): objectClass '%s' is OBSOLETE\n", e->e_dn, aoc->a_vals[i].bv_val ); rc = LDAP_OBJECT_CLASS_VIOLATION; goto done; } if ( oc->soc_check ) { rc = (oc->soc_check)( op->o_bd, e, oc, text, textbuf, textlen ); if( rc != LDAP_SUCCESS ) { goto done; } } if ( oc->soc_kind == LDAP_SCHEMA_ABSTRACT ) { /* object class is abstract */ if ( oc != slap_schema.si_oc_top && !is_object_subclass( oc, sc )) { int j; ObjectClass *xc = NULL; for( j=0; socs[j]; j++ ) { if( i != j ) { xc = socs[j]; /* since we previous check against the * structural object of this entry, the * abstract class must be a (direct or indirect) * superclass of one of the auxiliary classes of * the entry. */ if ( xc->soc_kind == LDAP_SCHEMA_AUXILIARY && is_object_subclass( oc, xc ) ) { xc = NULL; break; } } } if( xc != NULL ) { Debug(LDAP_DEBUG_ANY, "entry_check_schema(%s): instantiation of " "abstract objectClass '%s' not allowed\n", e->e_dn, aoc->a_vals[i].bv_val ); rc = LDAP_OBJECT_CLASS_VIOLATION; goto done; } } } else if ( oc->soc_kind != LDAP_SCHEMA_STRUCTURAL || oc == sc ) { char *s; if( oc->soc_kind == LDAP_SCHEMA_AUXILIARY ) { int k; if( cr ) { int j; k = -1; if( cr->scr_auxiliaries ) { for( j = 0; cr->scr_auxiliaries[j]; j++ ) { if( cr->scr_auxiliaries[j] == oc ) { k = 0; break; } } } if ( k ) { snprintf( textbuf, textlen, "class '%s' not allowed by content rule '%s'", oc->soc_cname.bv_val, ldap_contentrule2name( &cr->scr_crule ) ); } } else if ( global_disallows & SLAP_DISALLOW_AUX_WO_CR ) { k = -1; snprintf( textbuf, textlen, "class '%s' not allowed by any content rule", oc->soc_cname.bv_val ); } else { k = 0; } if( k == -1 ) { Debug( LDAP_DEBUG_ANY, "Entry (%s): %s\n", e->e_dn, textbuf ); rc = LDAP_OBJECT_CLASS_VIOLATION; goto done; } } s = oc_check_required( e, oc, &aoc->a_vals[i] ); if (s != NULL) { Debug(LDAP_DEBUG_ANY, "Entry (%s): object class '%s' requires attribute '%s'\n", e->e_dn, aoc->a_vals[i].bv_val, s ); rc = LDAP_OBJECT_CLASS_VIOLATION; goto done; } if( oc == slap_schema.si_oc_extensibleObject ) { extensible=1; } } } if( extensible ) { *text = NULL; rc = LDAP_SUCCESS; goto done; } /* check that each attr in the entry is allowed by some oc */ for ( a = e->e_attrs; a != NULL; a = a->a_next ) { rc = LDAP_OBJECT_CLASS_VIOLATION; if( cr && cr->scr_required ) { for( i=0; cr->scr_required[i]; i++ ) { if( cr->scr_required[i] == a->a_desc->ad_type ) { rc = LDAP_SUCCESS; break; } } } if( rc != LDAP_SUCCESS && cr && cr->scr_allowed ) { for( i=0; cr->scr_allowed[i]; i++ ) { if( cr->scr_allowed[i] == a->a_desc->ad_type ) { rc = LDAP_SUCCESS; break; } } } if( rc != LDAP_SUCCESS ) { rc = oc_check_allowed( a->a_desc->ad_type, socs, sc ); } if ( rc != LDAP_SUCCESS ) { char *type = a->a_desc->ad_cname.bv_val; Debug(LDAP_DEBUG_ANY, "Entry (%s), attribute '%s' not allowed\n", e->e_dn, type ); goto done; } } *text = NULL; done: slap_sl_free( socs, op->o_tmpmemctx ); return rc; }