]> git.sur5r.net Git - openldap/commitdiff
First step in new schema support.
authorJulio Sánchez Fernández <jsanchez@openldap.org>
Fri, 28 May 1999 14:27:07 +0000 (14:27 +0000)
committerJulio Sánchez Fernández <jsanchez@openldap.org>
Fri, 28 May 1999 14:27:07 +0000 (14:27 +0000)
servers/slapd/attr.c
servers/slapd/back-bdb2/init.c
servers/slapd/back-ldbm/init.c
servers/slapd/config.c
servers/slapd/proto-slap.h
servers/slapd/schema.c
servers/slapd/schemaparse.c
servers/slapd/slap.h

index b26b7c34ba5f60d333c5dfadca32af474ad7b1dd..3254b3d0aad99b868859d4895450556caaedf826 100644 (file)
 
 #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 );
 }
 
index 4d75848953e7185df54a32f0129fdb6c75e108e8..396812ecda07c9a0af95161e60b79ebe21733b76 100644 (file)
@@ -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";
index 6ce569339905ff252a0652d1caec9de279f60bc5..34bceb7967a1dfade18a5ee929b31166a27a464a 100644 (file)
@@ -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";
index af5f0ee5a5fbb3e22e2cbaa4b18e9c3e738fab66..1e39a65e8455c0a083275b78b5bd18a1267fd371 100644 (file)
@@ -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 ) {
index fe3775f12cf4fb6fbd8a959fe34162cea1e6a38a..ccc7cc5742a630559c3d82438ff7df59fc62170d 100644 (file)
@@ -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));
index a20b3fab8be4b670b0485252b136b7c5499c77da..a5b0a0519b5183e3116dd0cf2677fd47e751aef3 100644 (file)
@@ -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" );
        }
index 23efb7fbaded02331796c6a002a3c6f36d0797d6..83865d488bf30e197cc93926df4f20f6fdc3e576 100644 (file)
@@ -8,14 +8,38 @@
 #include <ac/socket.h>
 
 #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, "<oc clause> ::= objectclass <ocname>\n" );
        fprintf( stderr, "                [ requires <attrlist> ]\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);
+}
index cdbc05c316092a9c3fb5999ca1f0d75347c34098..fb857e8da4892e109ded62263e14abb428b238f4 100644 (file)
@@ -9,6 +9,7 @@
 #include <ac/syslog.h>
 #include <ac/regex.h>
 #include <ac/socket.h>                 /* needed by LDAP_CONNECTIONLESS */
+#include <ldap_schema.h>
 
 #include "avl.h"
 
 #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