From 7f357399cfc635c148789e9728087ee7472bc75b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Julio=20S=C3=A1nchez=20Fern=C3=A1ndez?= Date: Fri, 28 May 1999 14:27:07 +0000 Subject: [PATCH] First step in new schema support. --- servers/slapd/attr.c | 330 ++++++++++++++++++++++++++---- servers/slapd/back-bdb2/init.c | 10 +- servers/slapd/back-ldbm/init.c | 10 +- servers/slapd/config.c | 18 +- servers/slapd/proto-slap.h | 16 +- servers/slapd/schema.c | 353 +++++++++++++++++++++++++++++---- servers/slapd/schemaparse.c | 181 +++++++++++++++-- servers/slapd/slap.h | 39 +++- 8 files changed, 850 insertions(+), 107 deletions(-) diff --git a/servers/slapd/attr.c b/servers/slapd/attr.c index b26b7c34ba..3254b3d0aa 100644 --- a/servers/slapd/attr.c +++ b/servers/slapd/attr.c @@ -22,6 +22,10 @@ #include "slap.h" +#ifdef LDAP_DEBUG +static void at_index_print( void ); +#endif + void attr_free( Attribute *a ) { @@ -174,11 +178,11 @@ attr_delete( #define DEFAULT_SYNTAX SYNTAX_CIS +/* Force compilation errors by commenting out this struct asyntaxinfo { char **asi_names; int asi_syntax; }; - static Avlnode *attr_syntaxes = NULL; static int @@ -228,6 +232,8 @@ attr_syntax_dup( return( 1 ); } +*/ + /* * attr_syntax - return the syntax of attribute type */ @@ -235,14 +241,11 @@ attr_syntax_dup( int attr_syntax( char *type ) { - struct asyntaxinfo *asi = NULL; - - if ( (asi = (struct asyntaxinfo *) avl_find( attr_syntaxes, type, - (AVL_CMP) attr_syntax_name_cmp )) != NULL || - (asi = (struct asyntaxinfo *) avl_find_lin( attr_syntaxes, type, - (AVL_CMP) attr_syntax_names_cmp )) != NULL ) - { - return( asi->asi_syntax ); + AttributeType *sat; + + sat = at_find(type); + if ( sat ) { + return( sat->sat_syntax_compat ); } return( DEFAULT_SYNTAX ); @@ -261,8 +264,10 @@ attr_syntax_config( ) { char *save; - struct asyntaxinfo *a; + LDAP_ATTRIBUTE_TYPE *at; int lasti; + int code; + char *err; if ( argc < 2 ) { Debug( LDAP_DEBUG_ANY, @@ -271,23 +276,30 @@ attr_syntax_config( return; } - a = (struct asyntaxinfo *) ch_calloc( 1, sizeof(struct asyntaxinfo) ); + at = (LDAP_ATTRIBUTE_TYPE *) + ch_calloc( 1, sizeof(LDAP_ATTRIBUTE_TYPE) ); lasti = argc - 1; if ( strcasecmp( argv[lasti], "caseignorestring" ) == 0 || strcasecmp( argv[lasti], "cis" ) == 0 ) { - a->asi_syntax = SYNTAX_CIS; + at->at_syntax_oid = "1.3.6.1.4.1.1466.115.121.1.15"; + at->at_equality_oid = "2.5.13.2"; } else if ( strcasecmp( argv[lasti], "telephone" ) == 0 || strcasecmp( argv[lasti], "tel" ) == 0 ) { - a->asi_syntax = (SYNTAX_CIS | SYNTAX_TEL); + at->at_syntax_oid = "1.3.6.1.4.1.1466.115.121.1.50"; + at->at_equality_oid = "2.5.13.20"; } else if ( strcasecmp( argv[lasti], "dn" ) == 0 ) { - a->asi_syntax = (SYNTAX_CIS | SYNTAX_DN); + at->at_syntax_oid = "1.3.6.1.4.1.1466.115.121.1.12"; + at->at_equality_oid = "2.5.13.1"; } else if ( strcasecmp( argv[lasti], "caseexactstring" ) == 0 || strcasecmp( argv[lasti], "ces" ) == 0 ) { - a->asi_syntax = SYNTAX_CES; + at->at_syntax_oid = "1.3.6.1.4.1.1466.115.121.1.15"; + /* notice: this is caseExactIA5Match */ + at->at_equality_oid = "1.3.6.1.4.1.1466.109.114.1"; } else if ( strcasecmp( argv[lasti], "binary" ) == 0 || strcasecmp( argv[lasti], "bin" ) == 0 ) { - a->asi_syntax = SYNTAX_BIN; + at->at_syntax_oid = "1.3.6.1.4.1.1466.115.121.1.5"; + /* There is no match for binary syntax. Really */ } else { Debug( LDAP_DEBUG_ANY, "%s: line %d: unknown syntax \"%s\" in attribute line (ignored)\n", @@ -295,50 +307,292 @@ attr_syntax_config( Debug( LDAP_DEBUG_ANY, "possible syntaxes are \"cis\", \"ces\", \"tel\", \"dn\", or \"bin\"\n", 0, 0, 0 ); - free( (char *) a ); + free( (AttributeType *) at ); return; } + save = argv[lasti]; argv[lasti] = NULL; - a->asi_names = charray_dup( argv ); + at->at_names = charray_dup( argv ); argv[lasti] = save; - switch ( avl_insert( &attr_syntaxes, (caddr_t) a, - (AVL_CMP) attr_syntax_cmp, - (AVL_DUP) attr_syntax_dup ) ) { - case -1: /* duplicate - different syntaxes */ - Debug( LDAP_DEBUG_ARGS, "%s: line %d: duplicate attribute\n", - fname, lineno, 0 ); - /* FALL */ + code = at_add( at, &err ); + if ( code ) { + fprintf( stderr, "%s: line %d: %s %s\n", + fname, lineno, scherr2str(code), err); + exit( 1 ); + } + ldap_memfree(at); +} - case 1: /* duplicate - same syntaxes */ - charray_free( a->asi_names ); - free( (char *) a ); - break; +int +at_fake_if_needed( + char *name +) +{ + char *argv[3]; - default: /* inserted */ - break; + if ( at_find( name ) ) { + return 0; + } else { + argv[0] = name; + argv[1] = "cis"; + argv[2] = NULL; + attr_syntax_config( "implicit", 0, 2, argv ); + return 0; } } -#ifdef LDAP_DEBUG +struct aindexrec { + char *air_name; + AttributeType *air_at; +}; + +static Avlnode *attr_index = NULL; +static AttributeType *attr_list = NULL; + +static int +attr_index_cmp( + struct aindexrec *air1, + struct aindexrec *air2 +) +{ + return (strcasecmp( air1->air_name, air2->air_name )); +} static int -attr_syntax_printnode( struct asyntaxinfo *a ) +attr_index_name_cmp( + char *type, + struct aindexrec *air +) +{ + return (strcasecmp( type, air->air_name )); +} + +AttributeType * +at_find( + char *name +) +{ + struct aindexrec *air = NULL; + + if ( (air = (struct aindexrec *) avl_find( attr_index, name, + (AVL_CMP) attr_index_name_cmp )) != NULL ) { + return( air->air_at ); + } + return( NULL ); +} + +int +at_append_to_list( + AttributeType *sat, + AttributeType ***listp +) +{ + AttributeType **list; + AttributeType **list1; + int size; + + list = *listp; + if ( !list ) { + size = 2; + list = calloc(size, sizeof(AttributeType *)); + if ( !list ) { + return -1; + } + } else { + size = 0; + list1 = *listp; + while ( *list1 ) { + size++; + list1++; + } + size += 2; + list1 = realloc(list, size*sizeof(AttributeType *)); + if ( !list1 ) { + return -1; + } + list = list1; + } + list[size-2] = sat; + list[size-1] = NULL; + *listp = list; + return 0; +} + +int +at_delete_from_list( + int pos, + AttributeType ***listp +) +{ + AttributeType **list; + AttributeType **list1; + int i; + int j; + + if ( pos < 0 ) { + return -2; + } + list = *listp; + for ( i=0; list[i]; i++ ) + ; + if ( pos >= i ) { + return -2; + } + for ( i=pos, j=pos+1; list[j]; i++, j++ ) { + list[i] = list[j]; + } + list[i] = NULL; + /* Tell the runtime this can be shrinked */ + list1 = realloc(list, (i+1)*sizeof(AttributeType **)); + if ( !list1 ) { + return -1; + } + *listp = list1; + return 0; +} + +int +at_find_in_list( + AttributeType *sat, + AttributeType **list +) { int i; - printf( "syntax: 0x%x\n", a->asi_syntax ); - for ( i = 0; a->asi_names[i] != NULL; i++ ) { - printf( " name: %s\n", a->asi_names[i] ); + if ( !list ) { + return -1; + } + for ( i=0; list[i]; i++ ) { + if ( sat == list[i] ) { + return i; + } + } + return -1; +} + +static int +at_insert( + AttributeType *sat, + char **err +) +{ + AttributeType **atp; + struct aindexrec *air; + char **names; + + atp = &attr_list; + while ( *atp != NULL ) { + atp = &(*atp)->sat_next; } + *atp = sat; + + if ( sat->sat_atype.at_oid ) { + air = (struct aindexrec *) + ch_calloc( 1, sizeof(struct aindexrec) ); + air->air_name = sat->sat_atype.at_oid; + air->air_at = sat; + if ( avl_insert( &attr_index, (caddr_t) air, + (AVL_CMP) attr_index_cmp, + (AVL_DUP) avl_dup_error ) ) { + *err = sat->sat_atype.at_oid; + ldap_memfree(air); + return SLAP_SCHERR_DUP_ATTR; + } + /* FIX: temporal consistency check */ + at_find(air->air_name); + } + if ( (names = sat->sat_atype.at_names) ) { + while ( *names ) { + air = (struct aindexrec *) + ch_calloc( 1, sizeof(struct aindexrec) ); + air->air_name = ch_strdup(*names); + air->air_at = sat; + if ( avl_insert( &attr_index, (caddr_t) air, + (AVL_CMP) attr_index_cmp, + (AVL_DUP) avl_dup_error ) ) { + *err = *names; + ldap_memfree(air); + return SLAP_SCHERR_DUP_ATTR; + } + /* FIX: temporal consistency check */ + at_find(air->air_name); + names++; + } + } + + return 0; +} + +int +at_add( + LDAP_ATTRIBUTE_TYPE *at, + char **err +) +{ + AttributeType *sat; + AttributeType *sat1; + int code; + char *errattr; + + if ( at->at_names && at->at_names[0] ) { + errattr = at->at_names[0]; + } else { + errattr = at->at_oid; + } + sat = (AttributeType *) ch_calloc( 1, sizeof(AttributeType) ); + memcpy( &sat->sat_atype, at, sizeof(LDAP_ATTRIBUTE_TYPE)); + if ( at->at_sup_oid ) { + if ( (sat1 = at_find(at->at_sup_oid)) ) { + sat->sat_sup = sat1; + if ( at_append_to_list(sat, &sat1->sat_subtypes) ) { + *err = errattr; + return SLAP_SCHERR_OUTOFMEM; + } + } else { + *err = errattr; + return SLAP_SCHERR_ATTR_NOT_FOUND; + } + } + + if ( !strcmp(at->at_syntax_oid, "1.3.6.1.4.1.1466.115.121.1.15") ) { + if ( !strcmp(at->at_equality_oid, + "1.3.6.1.4.1.1466.109.114.1") ) { + sat->sat_syntax_compat = SYNTAX_CES; + } else { + sat->sat_syntax_compat = SYNTAX_CIS; + } + } else if ( !strcmp(at->at_syntax_oid, + "1.3.6.1.4.1.1466.115.121.1.50") ) { + sat->sat_syntax_compat = SYNTAX_CIS | SYNTAX_TEL; + } else if ( !strcmp(at->at_syntax_oid, "1.3.6.1.4.1.1466.115.121.1.12") ) { + sat->sat_syntax_compat = SYNTAX_CIS | SYNTAX_DN; + } else if ( !strcmp(at->at_syntax_oid, "1.3.6.1.4.1.1466.115.121.1.5") ) { + sat->sat_syntax_compat = SYNTAX_BIN; + } else { + sat->sat_syntax_compat = DEFAULT_SYNTAX; + } + + code = at_insert(sat,err); + return code; +} + +#ifdef LDAP_DEBUG + +static int +at_index_printnode( struct aindexrec *air ) +{ + + printf( "%s = %s\n", air->air_name, ldap_attributetype2str(&air->air_at->sat_atype) ); return( 0 ); } static void -attr_syntax_print( void ) +at_index_print( void ) { - (void) avl_apply( attr_syntaxes, (AVL_APPLY) attr_syntax_printnode, + printf("Printing attribute type index:\n"); + (void) avl_apply( attr_index, (AVL_APPLY) at_index_printnode, 0, -1, AVL_INORDER ); } diff --git a/servers/slapd/back-bdb2/init.c b/servers/slapd/back-bdb2/init.c index 4d75848953..396812ecda 100644 --- a/servers/slapd/back-bdb2/init.c +++ b/servers/slapd/back-bdb2/init.c @@ -150,10 +150,12 @@ bdb2i_back_db_init_internal( li->li_directory = DEFAULT_DB_DIRECTORY; /* always index dn, id2children, objectclass (used in some searches) */ - argv[ 0 ] = "dn"; - argv[ 1 ] = "dn"; - argv[ 2 ] = NULL; - attr_syntax_config( "ldbm dn initialization", 0, 2, argv ); + if ( !at_find( "dn" ) ) { + argv[ 0 ] = "dn"; + argv[ 1 ] = "dn"; + argv[ 2 ] = NULL; + attr_syntax_config( "ldbm dn initialization", 0, 2, argv ); + } argv[ 0 ] = "dn"; argv[ 1 ] = "sub"; argv[ 2 ] = "eq"; diff --git a/servers/slapd/back-ldbm/init.c b/servers/slapd/back-ldbm/init.c index 6ce5693399..34bceb7967 100644 --- a/servers/slapd/back-ldbm/init.c +++ b/servers/slapd/back-ldbm/init.c @@ -110,10 +110,12 @@ ldbm_back_db_init( li->li_directory = ch_strdup( DEFAULT_DB_DIRECTORY ); /* always index dn, id2children, objectclass (used in some searches) */ - argv[ 0 ] = "dn"; - argv[ 1 ] = "dn"; - argv[ 2 ] = NULL; - attr_syntax_config( "ldbm dn initialization", 0, 2, argv ); + if ( !at_find( "dn" ) ) { + argv[ 0 ] = "dn"; + argv[ 1 ] = "dn"; + argv[ 2 ] = NULL; + attr_syntax_config( "ldbm dn initialization", 0, 2, argv ); + } argv[ 0 ] = "dn"; argv[ 1 ] = "sub"; argv[ 2 ] = "eq"; diff --git a/servers/slapd/config.c b/servers/slapd/config.c index af5f0ee5a5..1e39a65e84 100644 --- a/servers/slapd/config.c +++ b/servers/slapd/config.c @@ -346,12 +346,24 @@ read_config( char *fname ) #endif /* specify an objectclass */ } else if ( strcasecmp( cargv[0], "objectclass" ) == 0 ) { - parse_oc( be, fname, lineno, cargc, cargv ); + if ( *cargv[1] == '(' ) { + char * p; + p = strchr(line,'('); + parse_oc( fname, lineno, p ); + } else { + parse_oc_old( be, fname, lineno, cargc, cargv ); + } /* specify an attribute */ } else if ( strcasecmp( cargv[0], "attribute" ) == 0 ) { - attr_syntax_config( fname, lineno, cargc - 1, - &cargv[1] ); + if ( *cargv[1] == '(' ) { + char * p; + p = strchr(line,'('); + parse_at( fname, lineno, p ); + } else { + attr_syntax_config( fname, lineno, cargc - 1, + &cargv[1] ); + } /* turn on/off schema checking */ } else if ( strcasecmp( cargv[0], "schemacheck" ) == 0 ) { diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index fe3775f12c..ccc7cc5742 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -46,6 +46,11 @@ Attribute * attr_find LDAP_P(( Attribute *a, char *type )); int attr_delete LDAP_P(( Attribute **attrs, char *type )); int attr_syntax LDAP_P(( char *type )); void attr_syntax_config LDAP_P(( char *fname, int lineno, int argc, char **argv )); +AttributeType * at_find LDAP_P(( char *name )); +int at_find_in_list LDAP_P(( AttributeType *sat, AttributeType **list )); +int at_append_to_list LDAP_P(( AttributeType *sat, AttributeType ***listp )); +int at_delete_from_list LDAP_P(( int pos, AttributeType ***listp )); +int at_fake_if_needed LDAP_P(( char *name )); /* * ava.c @@ -230,12 +235,17 @@ void send_ldap_search_result LDAP_P(( Connection *conn, Operation *op, int err, */ int oc_schema_check LDAP_P(( Entry *e )); +ObjectClass *oc_find LDAP_P((char *ocname)); +int oc_add LDAP_P((LDAP_OBJECT_CLASS *oc, char **err)); + /* * schemaparse.c */ -void parse_oc LDAP_P(( Backend *be, char *fname, int lineno, int argc, char **argv )); +void parse_oc_old LDAP_P(( Backend *be, char *fname, int lineno, int argc, char **argv )); +void parse_oc LDAP_P(( char *fname, int lineno, char * line )); +void parse_at LDAP_P(( char *fname, int lineno, char *line )); /* * str2filter.c @@ -311,8 +321,8 @@ extern ldap_pvt_thread_mutex_t crypt_mutex; #endif extern ldap_pvt_thread_mutex_t gmtime_mutex; -extern struct acl *global_acl; -extern struct objclass *global_oc; +extern struct acl *global_acl; +extern ObjectClass *global_oc; extern int slap_init LDAP_P((int mode, char* name)); extern int slap_startup LDAP_P((int dbnum)); diff --git a/servers/slapd/schema.c b/servers/slapd/schema.c index a20b3fab8b..a5b0a0519b 100644 --- a/servers/slapd/schema.c +++ b/servers/slapd/schema.c @@ -9,7 +9,6 @@ #include "slap.h" -static struct objclass *oc_find(char *ocname); static char * oc_check_required(Entry *e, char *ocname); static int oc_check_allowed(char *type, struct berval **ocl); @@ -64,9 +63,15 @@ oc_schema_check( Entry *e ) static char * oc_check_required( Entry *e, char *ocname ) { - struct objclass *oc; - int i; + ObjectClass *oc; + AttributeType *at; + int i, j; Attribute *a; + char **pp; + + Debug( LDAP_DEBUG_TRACE, + "oc_check_required entry (%s), objectclass \"%s\"\n", + e->e_dn, ocname, 0 ); /* find global oc defn. it we don't know about it assume it's ok */ if ( (oc = oc_find( ocname )) == NULL ) { @@ -74,23 +79,43 @@ oc_check_required( Entry *e, char *ocname ) } /* check for empty oc_required */ - if(oc->oc_required == NULL) { + if(oc->soc_required == NULL) { return( 0 ); } /* for each required attribute */ - for ( i = 0; oc->oc_required[i] != NULL; i++ ) { + for ( i = 0; oc->soc_required[i] != NULL; i++ ) { + at = oc->soc_required[i]; /* see if it's in the entry */ for ( a = e->e_attrs; a != NULL; a = a->a_next ) { - if ( strcasecmp( a->a_type, oc->oc_required[i] ) - == 0 ) { + if ( at->sat_atype.at_oid && + strcmp( a->a_type, at->sat_atype.at_oid ) == 0 ) { + break; + } + pp = at->sat_atype.at_names; + if ( pp == NULL ) { + /* Empty name list => not found */ + a = NULL; + break; + } + while ( *pp ) { + if ( strcasecmp( a->a_type, *pp ) == 0 ) { + break; + } + pp++; + } + if ( *pp ) { break; } } - /* not there => schema violation */ if ( a == NULL ) { - return oc->oc_required[i]; + if ( at->sat_atype.at_names && + at->sat_atype.at_names[0] ) { + return at->sat_atype.at_names[0]; + } else { + return at->sat_atype.at_oid; + } } } @@ -114,8 +139,13 @@ oc_check_operational( char *type ) static int oc_check_allowed( char *type, struct berval **ocl ) { - struct objclass *oc; + ObjectClass *oc; + AttributeType *at; int i, j; + char **pp; + + Debug( LDAP_DEBUG_TRACE, + "oc_check_allowed type \"%s\"\n", type, 0, 0 ); /* always allow objectclass attribute */ if ( strcasecmp( type, "objectclass" ) == 0 ) { @@ -131,22 +161,41 @@ oc_check_allowed( char *type, struct berval **ocl ) /* if we know about the oc */ if ( (oc = oc_find( ocl[i]->bv_val )) != NULL ) { /* does it require the type? */ - for ( j = 0; oc->oc_required != NULL && - oc->oc_required[j] != NULL; j++ ) { - if ( strcasecmp( oc->oc_required[j], type ) - == 0 ) { + for ( j = 0; oc->soc_required != NULL && + oc->soc_required[j] != NULL; j++ ) { + at = oc->soc_required[j]; + if ( at->sat_atype.at_oid && + strcmp(at->sat_atype.at_oid, type ) == 0 ) { return( 0 ); } + pp = at->sat_atype.at_names; + if ( pp == NULL ) + continue; + while ( *pp ) { + if ( strcasecmp( *pp, type ) == 0 ) { + return( 0 ); + } + pp++; + } } /* does it allow the type? */ - for ( j = 0; oc->oc_allowed != NULL && - oc->oc_allowed[j] != NULL; j++ ) { - if ( strcasecmp( oc->oc_allowed[j], type ) - == 0 || strcmp( oc->oc_allowed[j], "*" ) - == 0 ) - { + for ( j = 0; oc->soc_allowed != NULL && + oc->soc_allowed[j] != NULL; j++ ) { + at = oc->soc_allowed[j]; + if ( at->sat_atype.at_oid && + strcmp(at->sat_atype.at_oid, type ) == 0 ) { return( 0 ); } + pp = at->sat_atype.at_names; + if ( pp == NULL ) + continue; + while ( *pp ) { + if ( strcasecmp( *pp, type ) == 0 || + strcmp( *pp, "*" ) == 0 ) { + return( 0 ); + } + pp++; + } } /* maybe the next oc allows it */ @@ -160,39 +209,271 @@ oc_check_allowed( char *type, struct berval **ocl ) return( 1 ); } -static struct objclass * +struct oindexrec { + char *oir_name; + ObjectClass *oir_oc; +}; + +static Avlnode *oc_index = NULL; +static AttributeType *oc_list = NULL; + +static int +oc_index_cmp( + struct oindexrec *oir1, + struct oindexrec *oir2 +) +{ + return (strcasecmp( oir1->oir_name, oir2->oir_name )); +} + +static int +oc_index_name_cmp( + char *type, + struct oindexrec *oir +) +{ + return (strcasecmp( type, oir->oir_name )); +} + +ObjectClass * oc_find( char *ocname ) { - struct objclass *oc; + struct oindexrec *oir = NULL; + + if ( (oir = (struct oindexrec *) avl_find( oc_index, ocname, + (AVL_CMP) oc_index_name_cmp )) != NULL ) { + return( oir->oir_oc ); + } + return( NULL ); +} + +static int +oc_create_required( + ObjectClass *soc, + char **attrs, + char **err +) +{ + char **attrs1; + int nattrs; + AttributeType *sat; + AttributeType **satp; + int i; + + if ( attrs ) { + attrs1 = attrs; + while ( *attrs1 ) { + sat = at_find(*attrs1); + if ( !sat ) { + *err = *attrs1; + return SLAP_SCHERR_ATTR_NOT_FOUND; + } + if ( at_find_in_list(sat, soc->soc_required) < 0) { + if ( at_append_to_list(sat, &soc->soc_required) ) { + *err = *attrs1; + return SLAP_SCHERR_OUTOFMEM; + } + } + attrs1++; + } + /* Now delete duplicates from the allowed list */ + for ( satp = soc->soc_required; *satp; satp++ ) { + i = at_find_in_list(*satp,soc->soc_allowed); + if ( i >= 0 ) { + at_delete_from_list(i, &soc->soc_allowed); + } + } + } + return 0; +} + +static int +oc_create_allowed( + ObjectClass *soc, + char **attrs, + char **err +) +{ + char **attrs1; + int nattrs; + AttributeType *sat; + AttributeType **satp; + int i; - for ( oc = global_oc; oc != NULL; oc = oc->oc_next ) { - if ( strcasecmp( oc->oc_name, ocname ) == 0 ) { - return( oc ); + if ( attrs ) { + attrs1 = attrs; + while ( *attrs1 ) { + sat = at_find(*attrs1); + if ( !sat ) { + *err = *attrs1; + return SLAP_SCHERR_ATTR_NOT_FOUND; + } + if ( at_find_in_list(sat, soc->soc_required) < 0 && + at_find_in_list(sat, soc->soc_allowed) < 0 ) { + if ( at_append_to_list(sat, &soc->soc_allowed) ) { + *err = *attrs1; + return SLAP_SCHERR_OUTOFMEM; + } + } + attrs1++; } } + return 0; +} - return( NULL ); +static int +oc_add_sups( + ObjectClass *soc, + char **sups, + char **err +) +{ + int code; + ObjectClass *soc1; + int nsups; + char **sups1; + int add_sups = 0; + + if ( sups ) { + if ( !soc->soc_sups ) { + /* We are at the first recursive level */ + add_sups = 1; + nsups = 0; + sups1 = sups; + while ( *sups1 ) { + nsups++; + sups1++; + } + nsups++; + soc->soc_sups = (ObjectClass **)ch_calloc(1, + nsups*sizeof(ObjectClass *)); + } + nsups = 0; + sups1 = sups; + while ( *sups1 ) { + soc1 = oc_find(*sups1); + if ( !soc1 ) { + *err = *sups1; + return SLAP_SCHERR_CLASS_NOT_FOUND; + } + + if ( add_sups ) + soc->soc_sups[nsups] = soc1; + + code = oc_add_sups(soc,soc1->soc_oclass.oc_sup_oids, + err); + if ( code ) + return code; + + if ( code = oc_create_required(soc, + soc1->soc_oclass.oc_at_oids_must,err) ) + return code; + if ( code = oc_create_allowed(soc, + soc1->soc_oclass.oc_at_oids_may,err) ) + return code; + nsups++; + sups1++; + } + } + return 0; +} + +static int +oc_insert( + ObjectClass *soc, + char **err +) +{ + ObjectClass **ocp; + struct oindexrec *oir; + char **names; + + ocp = &global_oc; + while ( *ocp != NULL ) { + ocp = &(*ocp)->soc_next; + } + *ocp = soc; + + if ( soc->soc_oclass.oc_oid ) { + oir = (struct oindexrec *) + ch_calloc( 1, sizeof(struct oindexrec) ); + oir->oir_name = soc->soc_oclass.oc_oid; + oir->oir_oc = soc; + if ( avl_insert( &oc_index, (caddr_t) oir, + (AVL_CMP) oc_index_cmp, + (AVL_DUP) avl_dup_error ) ) { + *err = soc->soc_oclass.oc_oid; + ldap_memfree(oir); + return SLAP_SCHERR_DUP_CLASS; + } + /* FIX: temporal consistency check */ + oc_find(oir->oir_name); + } + if ( (names = soc->soc_oclass.oc_names) ) { + while ( *names ) { + oir = (struct oindexrec *) + ch_calloc( 1, sizeof(struct oindexrec) ); + oir->oir_name = ch_strdup(*names); + oir->oir_oc = soc; + if ( avl_insert( &oc_index, (caddr_t) oir, + (AVL_CMP) oc_index_cmp, + (AVL_DUP) avl_dup_error ) ) { + *err = *names; + ldap_memfree(oir); + return SLAP_SCHERR_DUP_CLASS; + } + /* FIX: temporal consistency check */ + oc_find(oir->oir_name); + names++; + } + } + return 0; +} + +int +oc_add( + LDAP_OBJECT_CLASS *oc, + char **err +) +{ + ObjectClass *soc; + int code; + + soc = (ObjectClass *) ch_calloc( 1, sizeof(ObjectClass) ); + memcpy( &soc->soc_oclass, oc, sizeof(LDAP_OBJECT_CLASS)); + if ( code = oc_add_sups(soc,soc->soc_oclass.oc_sup_oids,err) ) + return code; + if ( code = oc_create_required(soc,soc->soc_oclass.oc_at_oids_must,err) ) + return code; + if ( code = oc_create_allowed(soc,soc->soc_oclass.oc_at_oids_may,err) ) + return code; + code = oc_insert(soc,err); + return code; } #ifdef LDAP_DEBUG static void -oc_print( struct objclass *oc ) +oc_print( ObjectClass *oc ) { int i; - printf( "objectclass %s\n", oc->oc_name ); - if ( oc->oc_required != NULL ) { - printf( "\trequires %s", oc->oc_required[0] ); - for ( i = 1; oc->oc_required[i] != NULL; i++ ) { - printf( ",%s", oc->oc_required[i] ); + if ( oc->soc_oclass.oc_names && oc->soc_oclass.oc_names[0] ) { + printf( "objectclass %s\n", oc->soc_oclass.oc_names[0] ); + } else { + printf( "objectclass %s\n", oc->soc_oclass.oc_oid ); + } + 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] ); } printf( "\n" ); } - if ( oc->oc_allowed != NULL ) { - printf( "\tallows %s", oc->oc_allowed[0] ); - for ( i = 1; oc->oc_allowed[i] != NULL; i++ ) { - printf( ",%s", oc->oc_allowed[i] ); + 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] ); } printf( "\n" ); } diff --git a/servers/slapd/schemaparse.c b/servers/slapd/schemaparse.c index 23efb7fbad..83865d488b 100644 --- a/servers/slapd/schemaparse.c +++ b/servers/slapd/schemaparse.c @@ -8,14 +8,38 @@ #include #include "slap.h" +#include "ldap_schema.h" -struct objclass *global_oc; +ObjectClass *global_oc; +static Avlnode *object_classes = NULL; + +AttributeType *global_at; int global_schemacheck = 1; /* schemacheck on is default */ +static void oc_usage_old(void); static void oc_usage(void); +static char *err2text[] = { + "", + "Out of memory", + "Objectclass not found", + "Attribute type not found", + "Duplicate objectclass", + "Duplicate attributetype" +}; + +char * +scherr2str(int code) +{ + if ( code < 1 || code >= (sizeof(err2text)/sizeof(char *)) ) { + return "Unknown error"; + } else { + return err2text[code]; + } +} + void -parse_oc( +parse_oc_old( Backend *be, char *fname, int lineno, @@ -25,11 +49,15 @@ parse_oc( { int i; char last; - struct objclass *oc; - struct objclass **ocp; + LDAP_OBJECT_CLASS *oc; + int code; + char *err; + char **namep; - oc = (struct objclass *) ch_calloc( 1, sizeof(struct objclass) ); - oc->oc_name = ch_strdup( argv[1] ); + oc = (LDAP_OBJECT_CLASS *) ch_calloc( 1, sizeof(LDAP_OBJECT_CLASS) ); + oc->oc_names = ch_calloc( 2, sizeof(char *) ); + oc->oc_names[0] = ch_strdup( argv[1] ); + oc->oc_names[1] = NULL; for ( i = 2; i < argc; i++ ) { /* required attributes */ if ( strcasecmp( argv[i], "requires" ) == 0 ) { @@ -38,7 +66,7 @@ parse_oc( if ( i < argc ) { char **s = str2charray( argv[i], "," ); last = argv[i][strlen( argv[i] ) - 1]; - charray_merge( &oc->oc_required, s ); + charray_merge( &oc->oc_at_oids_must, s ); charray_free( s ); } } while ( i < argc && last == ',' ); @@ -51,7 +79,7 @@ parse_oc( char **s = str2charray( argv[i], "," ); last = argv[i][strlen( argv[i] ) - 1]; - charray_merge( &oc->oc_allowed, s ); + charray_merge( &oc->oc_at_oids_may, s ); charray_free( s ); } } while ( i < argc && last == ',' ); @@ -60,19 +88,95 @@ parse_oc( fprintf( stderr, "%s: line %d: expecting \"requires\" or \"allows\" got \"%s\"\n", fname, lineno, argv[i] ); - oc_usage(); + oc_usage_old(); } } - ocp = &global_oc; - while ( *ocp != NULL ) { - ocp = &(*ocp)->oc_next; + /* + * There was no requirement in the old schema that all attributes + * types were defined before use and they would just default to + * SYNTAX_CIS. To support this, we need to make attribute types + * out of thin air. + */ + if ( oc->oc_at_oids_must ) { + namep = oc->oc_at_oids_must; + while ( *namep ) { + code = at_fake_if_needed( *namep ); + if ( code ) { + fprintf( stderr, "%s: line %d: %s %s\n", + fname, lineno, scherr2str(code), *namep); + exit( 1 ); + } + namep++; + } + } + if ( oc->oc_at_oids_may ) { + namep = oc->oc_at_oids_may; + while ( *namep ) { + code = at_fake_if_needed( *namep ); + if ( code ) { + fprintf( stderr, "%s: line %d: %s %s\n", + fname, lineno, scherr2str(code), *namep); + exit( 1 ); + } + namep++; + } + } + + code = oc_add(oc,&err); + if ( code ) { + fprintf( stderr, "%s: line %d: %s %s\n", + fname, lineno, scherr2str(code), err); + exit( 1 ); } - *ocp = oc; + ldap_memfree(oc); +} + +void +parse_oc( + char *fname, + int lineno, + char *line +) +{ + LDAP_OBJECT_CLASS *oc; + int code; + char *err; + + oc = ldap_str2objectclass(line,&code,&err); + if ( !oc ) { + fprintf( stderr, "%s: line %d: %s before %s\n", + fname, lineno, ldap_scherr2str(code), err ); + oc_usage(); + } + code = oc_add(oc,&err); + if ( code ) { + fprintf( stderr, "%s: line %d: %s %s\n", + fname, lineno, scherr2str(code), err); + exit( 1 ); + } + ldap_memfree(oc); } static void oc_usage( void ) +{ + fprintf( stderr, "ObjectClassDescription = \"(\" whsp\n"); + fprintf( stderr, " numericoid whsp ; ObjectClass identifier\n"); + fprintf( stderr, " [ \"NAME\" qdescrs ]\n"); + fprintf( stderr, " [ \"DESC\" qdstring ]\n"); + fprintf( stderr, " [ \"OBSOLETE\" whsp ]\n"); + fprintf( stderr, " [ \"SUP\" oids ] ; Superior ObjectClasses\n"); + fprintf( stderr, " [ ( \"ABSTRACT\" / \"STRUCTURAL\" / \"AUXILIARY\" ) whsp ]\n"); + fprintf( stderr, " ; default structural\n"); + fprintf( stderr, " [ \"MUST\" oids ] ; AttributeTypes\n"); + fprintf( stderr, " [ \"MAY\" oids ] ; AttributeTypes\n"); + fprintf( stderr, "whsp \")\"\n"); + exit( 1 ); +} + +static void +oc_usage_old( void ) { fprintf( stderr, " ::= objectclass \n" ); fprintf( stderr, " [ requires ]\n" ); @@ -80,3 +184,54 @@ oc_usage( void ) exit( 1 ); } +static void +at_usage( void ) +{ + fprintf( stderr, "AttributeTypeDescription = \"(\" whsp\n"); + fprintf( stderr, " numericoid whsp ; AttributeType identifier\n"); + fprintf( stderr, " [ \"NAME\" qdescrs ] ; name used in AttributeType\n"); + fprintf( stderr, " [ \"DESC\" qdstring ] ; description\n"); + fprintf( stderr, " [ \"OBSOLETE\" whsp ]\n"); + fprintf( stderr, " [ \"SUP\" woid ] ; derived from this other\n"); + fprintf( stderr, " ; AttributeType\n"); + fprintf( stderr, " [ \"EQUALITY\" woid ] ; Matching Rule name\n"); + fprintf( stderr, " [ \"ORDERING\" woid ] ; Matching Rule name\n"); + fprintf( stderr, " [ \"SUBSTR\" woid ] ; Matching Rule name\n"); + fprintf( stderr, " [ \"SYNTAX\" whsp noidlen whsp ] ; see section 4.3\n"); + fprintf( stderr, " [ \"SINGLE-VALUE\" whsp ] ; default multi-valued\n"); + fprintf( stderr, " [ \"COLLECTIVE\" whsp ] ; default not collective\n"); + fprintf( stderr, " [ \"NO-USER-MODIFICATION\" whsp ]; default user modifiable\n"); + fprintf( stderr, " [ \"USAGE\" whsp AttributeUsage ]; default userApplications\n"); + fprintf( stderr, " ; userApplications\n"); + fprintf( stderr, " ; directoryOperation\n"); + fprintf( stderr, " ; distributedOperation\n"); + fprintf( stderr, " ; dSAOperation\n"); + fprintf( stderr, "whsp \")\"\n"); + exit( 1 ); +} + +void +parse_at( + char *fname, + int lineno, + char *line +) +{ + LDAP_ATTRIBUTE_TYPE *at; + int code; + char *err; + + at = ldap_str2attributetype(line,&code,&err); + if ( !at ) { + fprintf( stderr, "%s: line %d: %s before %s\n", + fname, lineno, ldap_scherr2str(code), err ); + at_usage(); + } + code = at_add(at,&err); + if ( code ) { + fprintf( stderr, "%s: line %d: %s %s\n", + fname, lineno, scherr2str(code), err); + exit( 1 ); + } + ldap_memfree(at); +} diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index cdbc05c316..fb857e8da4 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -9,6 +9,7 @@ #include #include #include /* needed by LDAP_CONNECTIONLESS */ +#include #include "avl.h" @@ -51,6 +52,12 @@ #define SPACE(c) ((c) == ' ' || (c) == '\n') #define NEEDSESCAPE(c) ((c) == '\\' || (c) == '"') +#define SLAP_SCHERR_OUTOFMEM 1 +#define SLAP_SCHERR_CLASS_NOT_FOUND 2 +#define SLAP_SCHERR_ATTR_NOT_FOUND 3 +#define SLAP_SCHERR_DUP_CLASS 4 +#define SLAP_SCHERR_DUP_ATTR 5 + LDAP_BEGIN_DECL extern int slap_debug; @@ -209,12 +216,32 @@ typedef struct ldapmodlist { * represents schema information for a database */ -struct objclass { - char *oc_name; - char **oc_required; - char **oc_allowed; - struct objclass *oc_next; -}; +typedef struct slap_matching_rule { + int dummy; +} MatchingRule; + +typedef struct slap_attribute_type { + LDAP_ATTRIBUTE_TYPE sat_atype; + struct slap_attribute_type *sat_sup; + struct slap_attribute_type **sat_subtypes; + MatchingRule *sat_equality; + MatchingRule *sat_ordering; + MatchingRule *sat_substr; + /* + Syntax *sat_syntax; + */ + /* The next one is created to help in the transition */ + int sat_syntax_compat; + struct slap_attribute_type *sat_next; +} AttributeType; + +typedef struct slap_object_class { + LDAP_OBJECT_CLASS soc_oclass; + struct slap_object_class **soc_sups; + AttributeType **soc_required; + AttributeType **soc_allowed; + struct slap_object_class *soc_next; +} ObjectClass; /* * Backend-info -- 2.39.5