From 24b0a5611baa19f936a96fd00de03cc4988bce7e Mon Sep 17 00:00:00 2001 From: Kurt Zeilenga Date: Thu, 10 Oct 2002 03:45:55 +0000 Subject: [PATCH] DIT content rule code (behind #ifdef) security simple_bind support obsolete checks --- servers/slapd/Makefile.in | 4 +- servers/slapd/backend.c | 9 + servers/slapd/compare.c | 6 +- servers/slapd/config.c | 25 ++- servers/slapd/cr.c | 417 +++++++++++++++++++++++++++++++++++ servers/slapd/libslapd.dsp | 4 + servers/slapd/proto-slap.h | 20 +- servers/slapd/schema.c | 3 +- servers/slapd/schema_check.c | 199 ++++++++++++++++- servers/slapd/schema_prep.c | 2 +- servers/slapd/schemaparse.c | 65 +++++- servers/slapd/slap.h | 39 ++-- 12 files changed, 760 insertions(+), 33 deletions(-) create mode 100644 servers/slapd/cr.c diff --git a/servers/slapd/Makefile.in b/servers/slapd/Makefile.in index 2176cdcc35..717b91dc70 100644 --- a/servers/slapd/Makefile.in +++ b/servers/slapd/Makefile.in @@ -9,7 +9,7 @@ XSRCS=version.c NT_SRCS = nt_svc.c NT_OBJS = nt_svc.o ../../libraries/liblutil/slapdmsg.res -SRCS = main.c daemon.c connection.c search.c filter.c add.c \ +SRCS = main.c daemon.c connection.c search.c filter.c add.c cr.c \ attr.c entry.c config.c backend.c result.c operation.c \ dn.c compare.c modify.c delete.c modrdn.c ch_malloc.c \ value.c ava.c bind.c unbind.c abandon.c filterentry.c \ @@ -22,7 +22,7 @@ SRCS = main.c daemon.c connection.c search.c filter.c add.c \ limits.c backglue.c operational.c matchedValues.c \ $(@PLAT@_SRCS) -OBJS = main.o daemon.o connection.o search.o filter.o add.o \ +OBJS = main.o daemon.o connection.o search.o filter.o add.o cr.o \ attr.o entry.o config.o backend.o result.o operation.o \ dn.o compare.o modify.o delete.o modrdn.o ch_malloc.o \ value.o ava.o bind.o unbind.o abandon.o filterentry.o \ diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c index 23ee665e88..04fac3ccec 100644 --- a/servers/slapd/backend.c +++ b/servers/slapd/backend.c @@ -866,6 +866,15 @@ backend_check_restrictions( return LDAP_CONFIDENTIALITY_REQUIRED; } + + if( op->o_tag == LDAP_REQ_BIND && opdata == NULL ) { + /* simple bind specific check */ + if( op->o_ssf < ssf->sss_simple_bind ) { + *text = "confidentiality required"; + return LDAP_CONFIDENTIALITY_REQUIRED; + } + } + if( op->o_tag != LDAP_REQ_BIND || opdata == NULL ) { /* these checks don't apply to SASL bind */ diff --git a/servers/slapd/compare.c b/servers/slapd/compare.c index 7934821fd4..81e3e9f54e 100644 --- a/servers/slapd/compare.c +++ b/servers/slapd/compare.c @@ -36,6 +36,7 @@ do_compare( ) { Entry *entry = NULL; + Entry *fentry = NULL; struct berval dn = { 0, NULL }; struct berval pdn = { 0, NULL }; struct berval ndn = { 0, NULL }; @@ -169,6 +170,8 @@ do_compare( goto cleanup; } + fentry = entry; + } else if ( bvmatch( &ndn, &global_schemandn ) ) { #ifdef NEW_LOGGING LDAP_LOG( OPERATION, ARGS, @@ -198,11 +201,12 @@ do_compare( rc = 0; goto cleanup; } + fentry = entry; } if( entry ) { rc = compare_entry( conn, op, entry, &ava ); - entry_free( entry ); + if( fentry) entry_free( fentry ); send_ldap_result( conn, op, rc, NULL, text, NULL, NULL ); diff --git a/servers/slapd/config.c b/servers/slapd/config.c index 1f890888ea..72a9964021 100644 --- a/servers/slapd/config.c +++ b/servers/slapd/config.c @@ -1331,9 +1331,6 @@ read_config( const char *fname, int depth ) } else if( strcasecmp( cargv[i], "bind_simple" ) == 0 ) { disallows |= SLAP_DISALLOW_BIND_SIMPLE; - } else if( strcasecmp( cargv[i], "bind_simple_unprotected" ) == 0 ) { - disallows |= SLAP_DISALLOW_BIND_SIMPLE_UNPROTECTED; - } else if( strcasecmp( cargv[i], "bind_krbv4" ) == 0 ) { disallows |= SLAP_DISALLOW_BIND_KRBV4; @@ -1494,6 +1491,12 @@ read_config( const char *fname, int depth ) set->sss_update_sasl = atoi( &cargv[i][sizeof("update_sasl")] ); + } else if( strncasecmp( cargv[i], "simple_bind=", + sizeof("simple_bind") ) == 0 ) + { + set->sss_simple_bind = + atoi( &cargv[i][sizeof("simple_bind")] ); + } else { #ifdef NEW_LOGGING LDAP_LOG( CONFIG, CRIT, @@ -1588,9 +1591,9 @@ read_config( const char *fname, int depth ) /* specify an objectclass */ } else if ( strcasecmp( cargv[0], "objectclass" ) == 0 ) { - if ( *cargv[1] == '(' ) { + if ( *cargv[1] == '(' /*')'*/) { char * p; - p = strchr(saveline,'('); + p = strchr(saveline,'(' /*')'*/); rc = parse_oc( fname, lineno, p, cargv ); if( rc ) return rc; @@ -1606,13 +1609,21 @@ read_config( const char *fname, int depth ) #endif } +#ifdef SLAP_EXTENDED_SCHEMA + } else if ( strcasecmp( cargv[0], "ditcontentrule" ) == 0 ) { + char * p; + p = strchr(saveline,'(' /*')'*/); + rc = parse_cr( fname, lineno, p, cargv ); + if( rc ) return rc; +#endif + /* specify an attribute type */ } else if (( strcasecmp( cargv[0], "attributetype" ) == 0 ) || ( strcasecmp( cargv[0], "attribute" ) == 0 )) { - if ( *cargv[1] == '(' ) { + if ( *cargv[1] == '(' /*')'*/) { char * p; - p = strchr(saveline,'('); + p = strchr(saveline,'(' /*')'*/); rc = parse_at( fname, lineno, p, cargv ); if( rc ) return rc; diff --git a/servers/slapd/cr.c b/servers/slapd/cr.c new file mode 100644 index 0000000000..f8f5216cb4 --- /dev/null +++ b/servers/slapd/cr.c @@ -0,0 +1,417 @@ +/* cr.c - content rule routines */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ + +#include "portable.h" + +#include + +#include +#include +#include + +#include "slap.h" +#include "ldap_pvt.h" + +#ifdef SLAP_EXTENDED_SCHEMA + +struct cindexrec { + struct berval cir_name; + ContentRule *cir_cr; +}; + +static Avlnode *cr_index = NULL; +static ContentRule *cr_list = NULL; + +static int +cr_index_cmp( + struct cindexrec *cir1, + struct cindexrec *cir2 ) +{ + int i = cir1->cir_name.bv_len - cir2->cir_name.bv_len; + if (i) + return i; + return strcasecmp( cir1->cir_name.bv_val, cir2->cir_name.bv_val ); +} + +static int +cr_index_name_cmp( + struct berval *name, + struct cindexrec *cir ) +{ + int i = name->bv_len - cir->cir_name.bv_len; + if (i) + return i; + return strncasecmp( name->bv_val, cir->cir_name.bv_val, name->bv_len ); +} + +ContentRule * +cr_find( const char *crname ) +{ + struct berval bv; + + bv.bv_val = (char *)crname; + bv.bv_len = strlen( crname ); + + return( cr_bvfind( &bv ) ); +} + +ContentRule * +cr_bvfind( struct berval *crname ) +{ + struct cindexrec *cir; + + cir = (struct cindexrec *) avl_find( cr_index, crname, + (AVL_CMP) cr_index_name_cmp ); + + if ( cir != NULL ) { + return( cir->cir_cr ); + } + + return( NULL ); +} + +void +cr_destroy( void ) +{ + ContentRule *c, *n; + + avl_free(cr_index, ldap_memfree); + for (c=cr_list; c; c=n) + { + n = c->scr_next; + if (c->scr_auxiliaries) ldap_memfree(c->scr_auxiliaries); + if (c->scr_required) ldap_memfree(c->scr_required); + if (c->scr_allowed) ldap_memfree(c->scr_allowed); + if (c->scr_precluded) ldap_memfree(c->scr_precluded); + ldap_contentrule_free((LDAPContentRule *)c); + } +} + +static int +cr_insert( + ContentRule *scr, + const char **err +) +{ + ContentRule **crp; + struct cindexrec *cir; + char **names; + + crp = &cr_list; + while ( *crp != NULL ) { + crp = &(*crp)->scr_next; + } + *crp = scr; + + if ( scr->scr_oid ) { + cir = (struct cindexrec *) + ch_calloc( 1, sizeof(struct cindexrec) ); + cir->cir_name.bv_val = scr->scr_oid; + cir->cir_name.bv_len = strlen( scr->scr_oid ); + cir->cir_cr = scr; + + assert( cir->cir_name.bv_val ); + assert( cir->cir_cr ); + + if ( avl_insert( &cr_index, (caddr_t) cir, + (AVL_CMP) cr_index_cmp, + (AVL_DUP) avl_dup_error ) ) + { + *err = scr->scr_oid; + ldap_memfree(cir); + return SLAP_SCHERR_CR_DUP; + } + + /* FIX: temporal consistency check */ + assert( cr_bvfind(&cir->cir_name) != NULL ); + } + + if ( (names = scr->scr_names) ) { + while ( *names ) { + cir = (struct cindexrec *) + ch_calloc( 1, sizeof(struct cindexrec) ); + cir->cir_name.bv_val = *names; + cir->cir_name.bv_len = strlen( *names ); + cir->cir_cr = scr; + + assert( cir->cir_name.bv_val ); + assert( cir->cir_cr ); + + if ( avl_insert( &cr_index, (caddr_t) cir, + (AVL_CMP) cr_index_cmp, + (AVL_DUP) avl_dup_error ) ) + { + *err = *names; + ldap_memfree(cir); + return SLAP_SCHERR_CR_DUP; + } + + /* FIX: temporal consistency check */ + assert( cr_bvfind(&cir->cir_name) != NULL ); + + names++; + } + } + + return 0; +} + +static int +cr_add_auxiliaries( + ContentRule *scr, + int *op, + const char **err ) +{ + int naux; + + if( scr->scr_oc_oids_aux == NULL ) return 0; + + for( naux=0; scr->scr_oc_oids_aux[naux]; naux++ ) { + /* count them */ ; + } + + scr->scr_auxiliaries = ch_calloc( naux+1, sizeof(ObjectClass *)); + + for( naux=0; scr->scr_oc_oids_aux[naux]; naux++ ) { + ObjectClass *soc = scr->scr_auxiliaries[naux] + = oc_find(scr->scr_oc_oids_aux[naux]); + if ( !soc ) { + *err = scr->scr_oc_oids_aux[naux]; + return SLAP_SCHERR_CLASS_NOT_FOUND; + } + + if( soc->soc_flags & SLAP_OC_OPERATIONAL ) (*op)++; + + if( soc->soc_kind != LDAP_SCHEMA_AUXILIARY ) { + *err = scr->scr_oc_oids_aux[naux]; + return SLAP_SCHERR_CR_BAD_AUX; + } + } + + scr->scr_auxiliaries[naux] = NULL; + + return 0; +} + +static int +cr_create_required( + ContentRule *scr, + int *op, + const char **err ) +{ + char **attrs = scr->scr_at_oids_must; + char **attrs1; + AttributeType *sat; + + if ( attrs ) { + attrs1 = attrs; + while ( *attrs1 ) { + sat = at_find(*attrs1); + if ( !sat ) { + *err = *attrs1; + return SLAP_SCHERR_ATTR_NOT_FOUND; + } + + if( is_at_operational( sat )) (*op)++; + + if ( at_find_in_list(sat, scr->scr_required) < 0) { + if ( at_append_to_list(sat, &scr->scr_required) ) { + *err = *attrs1; + return SLAP_SCHERR_OUTOFMEM; + } + } else { + *err = *attrs1; + return SLAP_SCHERR_CR_BAD_AT; + } + attrs1++; + } + } + return 0; +} + +static int +cr_create_allowed( + ContentRule *scr, + int *op, + const char **err ) +{ + char **attrs = scr->scr_at_oids_may; + char **attrs1; + AttributeType *sat; + + if ( attrs ) { + attrs1 = attrs; + while ( *attrs1 ) { + sat = at_find(*attrs1); + if ( !sat ) { + *err = *attrs1; + return SLAP_SCHERR_ATTR_NOT_FOUND; + } + + if( is_at_operational( sat )) (*op)++; + + if ( at_find_in_list(sat, scr->scr_required) < 0 && + at_find_in_list(sat, scr->scr_allowed) < 0 ) + { + if ( at_append_to_list(sat, &scr->scr_allowed) ) { + *err = *attrs1; + return SLAP_SCHERR_OUTOFMEM; + } + } else { + *err = *attrs1; + return SLAP_SCHERR_CR_BAD_AT; + } + attrs1++; + } + } + return 0; +} + +static int +cr_create_precluded( + ContentRule *scr, + int *op, + const char **err ) +{ + char **attrs = scr->scr_at_oids_not; + char **attrs1; + AttributeType *sat; + + if ( attrs ) { + attrs1 = attrs; + while ( *attrs1 ) { + sat = at_find(*attrs1); + if ( !sat ) { + *err = *attrs1; + return SLAP_SCHERR_ATTR_NOT_FOUND; + } + + if( is_at_operational( sat )) (*op)++; + + /* FIXME: should also make sure attribute type is not + a required attribute of the structural class or + any auxiliary class */ + if ( at_find_in_list(sat, scr->scr_required) < 0 && + at_find_in_list(sat, scr->scr_allowed) < 0 && + at_find_in_list(sat, scr->scr_precluded) < 0 ) + { + if ( at_append_to_list(sat, &scr->scr_precluded) ) { + *err = *attrs1; + return SLAP_SCHERR_OUTOFMEM; + } + } else { + *err = *attrs1; + return SLAP_SCHERR_CR_BAD_AT; + } + attrs1++; + } + } + return 0; +} + +int +cr_add( + LDAPContentRule *cr, + int user, + const char **err +) +{ + ContentRule *scr; + int code; + int op = 0; + + if ( cr->cr_names != NULL ) { + int i; + + for( i=0; cr->cr_names[i]; i++ ) { + if( !slap_valid_descr( cr->cr_names[i] ) ) { + return SLAP_SCHERR_BAD_DESCR; + } + } + } + + if ( !OID_LEADCHAR( cr->cr_oid[0] )) { + /* Expand OID macros */ + char *oid = oidm_find( cr->cr_oid ); + if ( !oid ) { + *err = cr->cr_oid; + return SLAP_SCHERR_OIDM; + } + if ( oid != cr->cr_oid ) { + ldap_memfree( cr->cr_oid ); + cr->cr_oid = oid; + } + } + + scr = (ContentRule *) ch_calloc( 1, sizeof(ContentRule) ); + AC_MEMCPY( &scr->scr_crule, cr, sizeof(LDAPContentRule) ); + + scr->scr_sclass = oc_find(cr->cr_oid); + if ( !scr->scr_sclass ) { + *err = cr->cr_oid; + return SLAP_SCHERR_CLASS_NOT_FOUND; + } + + /* check object class usage */ + if( scr->scr_sclass->soc_kind != LDAP_SCHEMA_STRUCTURAL ) + { + *err = cr->cr_oid; + return SLAP_SCHERR_CR_BAD_STRUCT; + } + + if( scr->scr_sclass->soc_flags & SLAP_OC_OPERATIONAL ) op++; + + code = cr_add_auxiliaries( scr, &op, err ); + if ( code != 0 ) return code; + + code = cr_create_required( scr, &op, err ); + if ( code != 0 ) return code; + + code = cr_create_allowed( scr, &op, err ); + if ( code != 0 ) return code; + + code = cr_create_precluded( scr, &op, err ); + if ( code != 0 ) return code; + + if( user && op ) return SLAP_SCHERR_CR_BAD_AUX; + + code = cr_insert(scr,err); + return code; +} + +#endif + +int +cr_schema_info( Entry *e ) +{ +#ifdef SLAP_EXTENDED_SCHEMA + struct berval vals[2]; + ContentRule *cr; + + AttributeDescription *ad_ditContentRules = slap_schema.si_ad_ditContentRules; + + vals[1].bv_val = NULL; + + for ( cr = cr_list; cr; cr = cr->scr_next ) { + if ( ldap_contentrule2bv( &cr->scr_crule, vals ) == NULL ) { + return -1; + } + +#if 0 + if( cr->scr_flags & SLAP_CR_HIDE ) continue; +#endif + +#if 0 + Debug( LDAP_DEBUG_TRACE, "Merging cr [%ld] %s\n", + (long) vals[0].bv_len, vals[0].bv_val, 0 ); +#endif + attr_merge( e, ad_ditContentRules, vals ); + ldap_memfree( vals[0].bv_val ); + } +#endif + return 0; +} diff --git a/servers/slapd/libslapd.dsp b/servers/slapd/libslapd.dsp index 41614b6491..9920e800df 100644 --- a/servers/slapd/libslapd.dsp +++ b/servers/slapd/libslapd.dsp @@ -192,6 +192,10 @@ SOURCE=.\controls.c # End Source File # Begin Source File +SOURCE=.\cr.c +# End Source File +# Begin Source File + SOURCE=.\daemon.c # End Source File # Begin Source File diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 74f2b2655b..d7a963ed1b 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -312,6 +312,22 @@ LDAP_SLAPD_F (void) connection_done LDAP_P((Connection *)); LDAP_SLAPD_F (void) connection2anonymous LDAP_P((Connection *)); +/* + * cr.c + */ +LDAP_SLAPD_F (int) cr_schema_info( Entry *e ); + +LDAP_SLAPD_F (int) cr_add LDAP_P(( + LDAPContentRule *oc, + int user, + const char **err)); +LDAP_SLAPD_F (void) cr_destroy LDAP_P(( void )); + +LDAP_SLAPD_F (ContentRule *) cr_find LDAP_P(( + const char *crname)); +LDAP_SLAPD_F (ContentRule *) cr_bvfind LDAP_P(( + struct berval *crname)); + /* * daemon.c */ @@ -954,8 +970,8 @@ LDAP_SLAPD_F (int) slap_schema_check LDAP_P((void)); */ LDAP_SLAPD_F( int ) slap_valid_descr( const char * ); -LDAP_SLAPD_F (int) parse_oc_old LDAP_P(( - Backend *be, const char *fname, int lineno, int argc, char **argv )); +LDAP_SLAPD_F (int) parse_cr LDAP_P(( + const char *fname, int lineno, char *line, char **argv )); LDAP_SLAPD_F (int) parse_oc LDAP_P(( const char *fname, int lineno, char *line, char **argv )); LDAP_SLAPD_F (int) parse_at LDAP_P(( diff --git a/servers/slapd/schema.c b/servers/slapd/schema.c index bc218fcca8..c9d4436e8b 100644 --- a/servers/slapd/schema.c +++ b/servers/slapd/schema.c @@ -115,7 +115,8 @@ schema_info( Entry **entry, const char **text ) || mr_schema_info( e ) || mru_schema_info( e ) || at_schema_info( e ) - || oc_schema_info( e ) ) + || oc_schema_info( e ) + || cr_schema_info( e ) ) { /* Out of memory, do something about it */ entry_free( e ); diff --git a/servers/slapd/schema_check.c b/servers/slapd/schema_check.c index f9b4e082b8..737a0eb4a1 100644 --- a/servers/slapd/schema_check.c +++ b/servers/slapd/schema_check.c @@ -38,6 +38,10 @@ entry_schema_check( { Attribute *a, *asc, *aoc; ObjectClass *sc, *oc; +#ifdef SLAP_EXTENDED_SCHEMA + AttributeType *at; + ContentRule *cr; +#endif int rc, i; struct berval nsc; AttributeDescription *ad_structuralObjectClass @@ -49,7 +53,9 @@ entry_schema_check( int collectiveSubentry = 0; #if 0 - if( subentry) collectiveSubentry = is_entry_collectiveAttributeSubentry( e ); + if( subentry ) { + collectiveSubentry = is_entry_collectiveAttributeSubentry( e ); + } #endif *text = textbuf; @@ -157,6 +163,23 @@ entry_schema_check( return LDAP_OTHER; } + if( sc->soc_obsolete ) { + snprintf( textbuf, textlen, + "structuralObjectClass '%s' is OBSOLETE", + asc->a_vals[0].bv_val ); + +#ifdef NEW_LOGGING + LDAP_LOG( OPERATION, INFO, + "entry_schema_check: dn (%s), %s\n", e->e_dn, textbuf, 0 ); +#else + Debug( LDAP_DEBUG_ANY, + "entry_check_schema(%s): %s\n", + e->e_dn, textbuf, 0 ); +#endif + + return LDAP_OBJECT_CLASS_VIOLATION; + } + /* find the object class attribute */ aoc = attr_find( e->e_attrs, ad_objectClass ); if ( aoc == NULL ) { @@ -196,6 +219,92 @@ entry_schema_check( return LDAP_NO_OBJECT_CLASS_MODS; } +#ifdef SLAP_EXTENDED_SCHEMA + /* 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( cr->scr_obsolete ) { + snprintf( textbuf, textlen, + "content rule '%s' is obsolete", + ldap_contentrule2name( &cr->scr_crule )); + +#ifdef NEW_LOGGING + LDAP_LOG( OPERATION, INFO, + "entry_schema_check: dn=\"%s\" %s", e->e_dn, textbuf, 0 ); +#else + Debug( LDAP_DEBUG_ANY, + "Entry (%s): %s\n", + e->e_dn, textbuf, 0 ); +#endif + + return LDAP_OBJECT_CLASS_VIOLATION; + } + + 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 ) { + snprintf( textbuf, textlen, + "content rule '%s' requires attribute '%s'", + ldap_contentrule2name( &cr->scr_crule ), + at->sat_cname.bv_val ); + +#ifdef NEW_LOGGING + LDAP_LOG( OPERATION, INFO, + "entry_schema_check: dn=\"%s\" %s", e->e_dn, textbuf, 0 ); +#else + Debug( LDAP_DEBUG_ANY, + "Entry (%s): %s\n", + e->e_dn, textbuf, 0 ); +#endif + + return LDAP_OBJECT_CLASS_VIOLATION; + } + } + + 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 ) { + snprintf( textbuf, textlen, + "content rule '%s' precluded attribute '%s'", + ldap_contentrule2name( &cr->scr_crule ), + at->sat_cname.bv_val ); + +#ifdef NEW_LOGGING + LDAP_LOG( OPERATION, INFO, + "entry_schema_check: dn=\"%s\" %s", e->e_dn, textbuf, 0 ); +#else + Debug( LDAP_DEBUG_ANY, + "Entry (%s): %s\n", + e->e_dn, textbuf, 0 ); +#endif + + return LDAP_OBJECT_CLASS_VIOLATION; + } + } + } +#endif /* SLAP_EXTENDED_SCHEMA */ + /* check that the entry has required attrs for each oc */ for ( i = 0; aoc->a_vals[i].bv_val != NULL; i++ ) { if ( (oc = oc_bvfind( &aoc->a_vals[i] )) == NULL ) { @@ -203,6 +312,24 @@ entry_schema_check( "unrecognized objectClass '%s'", aoc->a_vals[i].bv_val ); +#ifdef NEW_LOGGING + LDAP_LOG( OPERATION, INFO, + "entry_schema_check: dn (%s), %s\n", e->e_dn, textbuf, 0 ); +#else + Debug( LDAP_DEBUG_ANY, + "entry_check_schema(%s): %s\n", + e->e_dn, textbuf, 0 ); +#endif + + return LDAP_OBJECT_CLASS_VIOLATION; + } + + if ( oc->soc_obsolete ) { + /* disallow obsolete classes */ + snprintf( textbuf, textlen, + "objectClass '%s' is OBSOLETE", + aoc->a_vals[i].bv_val ); + #ifdef NEW_LOGGING LDAP_LOG( OPERATION, INFO, "entry_schema_check: dn (%s), %s\n", e->e_dn, textbuf, 0 ); @@ -286,8 +413,46 @@ entry_schema_check( } } else if ( oc->soc_kind != LDAP_SCHEMA_STRUCTURAL || oc == sc ) { - char *s = oc_check_required( e, oc, &aoc->a_vals[i] ); + char *s; + +#ifdef SLAP_EXTENDED_SCHEMA + if( oc->soc_kind == LDAP_SCHEMA_AUXILIARY ) { + int k=0; + if( cr ) { + if( cr->scr_auxiliaries ) { + for( ; cr->scr_auxiliaries[k]; k++ ) { + if( cr->scr_auxiliaries[k] == oc ) { + k=-1; + break; + } + } + } + } else if ( global_disallows & SLAP_DISALLOW_AUX_WO_CR ) { + k=-1; + } + + if( k == -1 ) { + snprintf( textbuf, textlen, + "content rule '%s' does not allow class '%s'", + ldap_contentrule2name( &cr->scr_crule ), + oc->soc_cname.bv_val ); + +#ifdef NEW_LOGGING + LDAP_LOG( OPERATION, INFO, + "entry_schema_check: dn=\"%s\" %s", + e->e_dn, textbuf, 0 ); +#else + Debug( LDAP_DEBUG_ANY, + "Entry (%s): %s\n", + e->e_dn, textbuf, 0 ); +#endif + + return LDAP_OBJECT_CLASS_VIOLATION; + } + } +#endif /* SLAP_EXTENDED_SCHEMA */ + s = oc_check_required( e, oc, &aoc->a_vals[i] ); if (s != NULL) { snprintf( textbuf, textlen, "object class '%s' requires attribute '%s'", @@ -317,7 +482,35 @@ entry_schema_check( /* check that each attr in the entry is allowed by some oc */ for ( a = e->e_attrs; a != NULL; a = a->a_next ) { - int ret = oc_check_allowed( a->a_desc->ad_type, aoc->a_vals, sc ); + int ret; + +#ifdef SLAP_EXTENDED_SCHEMA + ret = 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 ) { + ret = LDAP_SUCCESS; + break; + } + } + } + + if( ret != LDAP_SUCCESS && cr && cr->scr_allowed ) { + for( i=0; cr->scr_allowed[i]; i++ ) { + if( cr->scr_allowed[i] == a->a_desc->ad_type ) { + ret = LDAP_SUCCESS; + break; + } + } + } + + if( ret != LDAP_SUCCESS ) +#endif /* SLAP_EXTENDED_SCHEMA */ + { + ret = oc_check_allowed( a->a_desc->ad_type, aoc->a_vals, sc ); + } + if ( ret != LDAP_SUCCESS ) { char *type = a->a_desc->ad_cname.bv_val; diff --git a/servers/slapd/schema_prep.c b/servers/slapd/schema_prep.c index 7625eefed1..d50649f85e 100644 --- a/servers/slapd/schema_prep.c +++ b/servers/slapd/schema_prep.c @@ -301,7 +301,7 @@ static struct slap_schema_oc_map { "SUP top STRUCTURAL MAY cn )", rootDseObjectClass, SLAP_OC_OPERATIONAL, offsetof(struct slap_internal_schema, si_oc_rootdse) }, - { "subentry", "( 2.5.20.0 NAME 'subentry' " + { "subentry", "( 2.5.17.0 NAME 'subentry' " "SUP top STRUCTURAL " "MUST ( cn $ subtreeSpecification ) )", subentryObjectClass, SLAP_OC_SUBENTRY|SLAP_OC_OPERATIONAL, diff --git a/servers/slapd/schemaparse.c b/servers/slapd/schemaparse.c index cb5fca8f82..d0aca20d90 100644 --- a/servers/slapd/schemaparse.c +++ b/servers/slapd/schemaparse.c @@ -42,7 +42,11 @@ static char *const err2text[] = { "OID or name required", "Qualifier not supported", "Invalid NAME", - "OID could not be expanded" + "OID could not be expanded", + "Duplicate Content Rule", + "Content Rule not for STRUCTURAL object class", + "Content Rule AUX contains non-AUXILIARY object class" + "Content Rule attribute type list contains duplicate" }; char * @@ -92,6 +96,64 @@ dscompare(const char *s1, const char *s2, char delim) return 0; } +#ifdef SLAP_EXTENDED_SCHEMA + +static void +cr_usage( void ) +{ + fprintf( stderr, + "DITContentRuleDescription = \"(\" whsp\n" + " numericoid whsp ; StructuralObjectClass identifier\n" + " [ \"NAME\" qdescrs ]\n" + " [ \"DESC\" qdstring ]\n" + " [ \"OBSOLETE\" whsp ]\n" + " [ \"AUX\" oids ] ; Auxiliary ObjectClasses\n" + " [ \"MUST\" oids ] ; AttributeTypes\n" + " [ \"MAY\" oids ] ; AttributeTypes\n" + " [ \"NOT\" oids ] ; AttributeTypes\n" + " whsp \")\"\n" ); +} + +int +parse_cr( + const char *fname, + int lineno, + char *line, + char **argv +) +{ + LDAPContentRule *cr; + int code; + const char *err; + + cr = ldap_str2contentrule(line, &code, &err, LDAP_SCHEMA_ALLOW_ALL ); + if ( !cr ) { + fprintf( stderr, "%s: line %d: %s before %s\n", + fname, lineno, ldap_scherr2str(code), err ); + cr_usage(); + return 1; + } + + if ( cr->cr_oid == NULL ) { + fprintf( stderr, + "%s: line %d: Content rule has no OID\n", + fname, lineno ); + cr_usage(); + return 1; + } + + code = cr_add(cr,1,&err); + if ( code ) { + fprintf( stderr, "%s: line %d: %s: \"%s\"\n", + fname, lineno, scherr2str(code), err); + return 1; + } + + ldap_memfree(cr); + return 0; +} + +#endif int parse_oc( @@ -149,7 +211,6 @@ oc_usage( void ) " whsp \")\"\n" ); } - static void at_usage( void ) { diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index fc3eb5e8cf..055ffa6323 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -35,6 +35,8 @@ #include "ldap_pvt_thread.h" #include "ldap_queue.h" +#define SLAP_EXTENDED_SCHEMA 1 + LDAP_BEGIN_DECL /* * SLAPD Memory allocation macros @@ -164,6 +166,7 @@ typedef struct slap_ssf_set { slap_ssf_t sss_update_transport; slap_ssf_t sss_update_tls; slap_ssf_t sss_update_sasl; + slap_ssf_t sss_simple_bind; } slap_ssf_set_t; /* @@ -211,9 +214,11 @@ typedef struct slap_ssf_set { #define SLAP_INDEX_SUBSTR_FINAL_PREFIX '$' #define SLAP_INDEX_CONT_PREFIX '.' /* prefix for continuation keys */ -#define SLAP_SYNTAX_MATCHINGRULES_OID "1.3.6.1.4.1.1466.115.121.1.30" -#define SLAP_SYNTAX_ATTRIBUTETYPES_OID "1.3.6.1.4.1.1466.115.121.1.3" -#define SLAP_SYNTAX_OBJECTCLASSES_OID "1.3.6.1.4.1.1466.115.121.1.37" +#define SLAP_SYNTAX_MATCHINGRULES_OID "1.3.6.1.4.1.1466.115.121.1.30" +#define SLAP_SYNTAX_ATTRIBUTETYPES_OID "1.3.6.1.4.1.1466.115.121.1.3" +#define SLAP_SYNTAX_OBJECTCLASSES_OID "1.3.6.1.4.1.1466.115.121.1.37" +#define SLAP_SYNTAX_MATCHINGRULEUSES_OID "1.3.6.1.4.1.1466.115.121.1.31" +#define SLAP_SYNTAX_CONTENTRULE_OID "1.3.6.1.4.1.1466.115.121.1.16" #ifdef LDAP_CLIENT_UPDATE #define LCUP_COOKIE_OID "1.3.6.1.4.1.4203.666.10.1" @@ -242,7 +247,11 @@ typedef struct slap_ssf_set { #define SLAP_SCHERR_NOT_SUPPORTED 18 #define SLAP_SCHERR_BAD_DESCR 19 #define SLAP_SCHERR_OIDM 20 -#define SLAP_SCHERR_LAST SLAP_SCHERR_OIDM +#define SLAP_SCHERR_CR_DUP 21 +#define SLAP_SCHERR_CR_BAD_STRUCT 22 +#define SLAP_SCHERR_CR_BAD_AUX 23 +#define SLAP_SCHERR_CR_BAD_AT 24 +#define SLAP_SCHERR_LAST SLAP_SCHERR_CR_BAD_AT typedef union slap_sockaddr { struct sockaddr sa_addr; @@ -590,7 +599,6 @@ typedef struct slap_object_class { #define SLAP_OC_OPERATIONAL 0x4000 #define SLAP_OC_HIDE 0x8000 -#ifdef LDAP_EXTENDED_SCHEMA /* * DIT content rule */ @@ -601,16 +609,17 @@ typedef struct slap_content_rule { AttributeType **scr_required; /* optional */ AttributeType **scr_allowed; /* optional */ AttributeType **scr_precluded; /* optional */ -#define scr_oid scr_crule.cr_oid -#define scr_names scr_crule.cr_names -#define scr_desc scr_crule.cr_desc -#define scr_obsolete soc_oclass.cr_obsolete -#define scr_cr_oids_aux soc_oclass.cr_oc_oids_aux -#define scr_cr_oids_must soc_oclass.cr_at_oids_must -#define scr_cr_oids_may soc_oclass.cr_at_oids_may -#define scr_cr_oids_not soc_oclass.cr_at_oids_not +#define scr_oid scr_crule.cr_oid +#define scr_names scr_crule.cr_names +#define scr_desc scr_crule.cr_desc +#define scr_obsolete scr_crule.cr_obsolete +#define scr_oc_oids_aux scr_crule.cr_oc_oids_aux +#define scr_at_oids_must scr_crule.cr_at_oids_must +#define scr_at_oids_may scr_crule.cr_at_oids_may +#define scr_at_oids_not scr_crule.cr_at_oids_not + + struct slap_content_rule *scr_next; } ContentRule; -#endif /* * represents a recognized attribute description ( type + options ) @@ -1255,6 +1264,8 @@ struct slap_backend_db { #define SLAP_DISALLOW_TLS_2_ANON 0x0010U /* StartTLS -> Anonymous */ #define SLAP_DISALLOW_TLS_AUTHC 0x0020U /* TLS while authenticated */ +#define SLAP_DISALLOW_AUX_WO_CR 0x4000U + slap_mask_t be_requires; /* pre-operation requirements */ #define SLAP_REQUIRE_BIND 0x0001U /* bind before op */ #define SLAP_REQUIRE_LDAP_V3 0x0002U /* LDAPv3 before op */ -- 2.39.5