]> git.sur5r.net Git - openldap/blobdiff - libraries/libldap/schema.c
rename ldap_pvt_init_utils() to ldap_int_utils_init() and provide
[openldap] / libraries / libldap / schema.c
index 6ff131316e70796a7a72fd7a56597ea777c77734..e404a32724717ae0b9290723c49588d3f56ad420 100644 (file)
@@ -64,6 +64,7 @@ safe_string_free(safe_string * ss)
 static char *
 safe_string_val(safe_string * ss)
 {
+       ss->val[ss->pos] = '\0';
        return(ss->val);
 }
 
@@ -119,7 +120,8 @@ print_whsp(safe_string *ss)
 static int
 print_numericoid(safe_string *ss, char *s)
 {
-       return(append_to_safe_string(ss,s));
+       if ( s )
+               return(append_to_safe_string(ss,s));
 }
 
 /* This one is identical to print_qdescr */
@@ -250,7 +252,7 @@ ldap_objectclass2str( LDAP_OBJECT_CLASS * oc )
                print_qdstring(ss,oc->oc_desc);
        }
 
-       if ( oc->oc_obsolete ) {
+       if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) {
                print_literal(ss, "OBSOLETE");
                print_whsp(ss);
        }
@@ -261,13 +263,13 @@ ldap_objectclass2str( LDAP_OBJECT_CLASS * oc )
        }
 
        switch (oc->oc_kind) {
-       case 0:
+       case LDAP_SCHEMA_ABSTRACT:
                print_literal(ss,"ABSTRACT");
                break;
-       case 1:
+       case LDAP_SCHEMA_STRUCTURAL:
                print_literal(ss,"STRUCTURAL");
                break;
-       case 2:
+       case LDAP_SCHEMA_AUXILIARY:
                print_literal(ss,"AUXILIARY");
                break;
        default:
@@ -324,7 +326,7 @@ ldap_attributetype2str( LDAP_ATTRIBUTE_TYPE * at )
                print_qdstring(ss,at->at_desc);
        }
 
-       if ( at->at_obsolete ) {
+       if ( at->at_obsolete == LDAP_SCHEMA_YES ) {
                print_literal(ss, "OBSOLETE");
                print_whsp(ss);
        }
@@ -351,35 +353,36 @@ ldap_attributetype2str( LDAP_ATTRIBUTE_TYPE * at )
 
        if ( at->at_syntax_oid ) {
                print_literal(ss,"SYNTAX");
+               print_whsp(ss);
                print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
        }
 
-       if ( at->at_single_value ) {
+       if ( at->at_single_value == LDAP_SCHEMA_YES ) {
                print_literal(ss,"SINGLE-VALUE");
                print_whsp(ss);
        }
 
-       if ( at->at_collective ) {
+       if ( at->at_collective == LDAP_SCHEMA_YES ) {
                print_literal(ss,"COLLECTIVE");
                print_whsp(ss);
        }
 
-       if ( at->at_no_user_mod ) {
+       if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
                print_literal(ss,"NO-USER-MODIFICATION");
                print_whsp(ss);
        }
 
-       if ( at->at_usage ) {
+       if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
                print_literal(ss,"USAGE");
                print_whsp(ss);
                switch (at->at_usage) {
-               case 1:
+               case LDAP_SCHEMA_DIRECTORY_OPERATION:
                        print_literal(ss,"directoryOperation");
                        break;
-               case 2:
+               case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
                        print_literal(ss,"distributedOperation");
                        break;
-               case 3:
+               case LDAP_SCHEMA_DSA_OPERATION:
                        print_literal(ss,"dSAOperation");
                        break;
                default:
@@ -417,6 +420,28 @@ charray_free( char **array )
        free( (char *) array );
 }
 
+/*
+ * Now come the parsers.  There is one parser for each entity type:
+ * objectclasses, attributetypes, etc.
+ *
+ * Each of them is written as a recursive-descent parser, except that
+ * none of them is really recursive.  But the idea is kept: there
+ * is one routine per non-terminal that eithers gobbles lexical tokens
+ * or calls lower-level routines, etc.
+ *
+ * The scanner is implemented in the routine get_token.  Actually,
+ * get_token is more than a scanner and will return tokens that are
+ * in fact non-terminals in the grammar.  So you can see the whole
+ * approach as the combination of a low-level bottom-up recognizer
+ * combined with a scanner and a number of top-down parsers.  Or just
+ * consider that the real grammars recognized by the parsers are not
+ * those of the standards.  As a matter of fact, our parsers are more
+ * liberal than the spec when there is no ambiguity.
+ *
+ * The difference is pretty academic (modulo bugs or incorrect
+ * interpretation of the specs).
+ */
+
 #define TK_NOENDQUOTE  -2
 #define TK_OUTOFMEM    -1
 #define TK_EOS         0
@@ -529,7 +554,7 @@ parse_numericoid(char **sp, int *code)
        while (**sp) {
                if ( !isdigit(**sp) ) {
                        /* Initial char is not a digit or char after dot is not a digit */
-                       *code = SCHEMA_ERR_NODIGIT;
+                       *code = LDAP_SCHERR_NODIGIT;
                        return NULL;
                }
                (*sp)++;
@@ -544,7 +569,7 @@ parse_numericoid(char **sp, int *code)
        len = *sp - start;
        res = malloc(len+1);
        if (!res) {
-         *code = SCHEMA_ERR_OUTOFMEM;
+         *code = LDAP_SCHERR_OUTOFMEM;
          return(NULL);
        }
        strncpy(res,start,len);
@@ -570,7 +595,7 @@ parse_qdescrs(char **sp, int *code)
                size = 3;
                res = calloc(3,sizeof(char *));
                if ( !res ) {
-                       *code = SCHEMA_ERR_OUTOFMEM;
+                       *code = LDAP_SCHERR_OUTOFMEM;
                        return NULL;
                }
                pos = 0;
@@ -585,7 +610,7 @@ parse_qdescrs(char **sp, int *code)
                                        res1 = realloc(res,size*sizeof(char *));
                                        if ( !res1 ) {
                                                charray_free(res);
-                                               *code = SCHEMA_ERR_OUTOFMEM;
+                                               *code = LDAP_SCHERR_OUTOFMEM;
                                                return(NULL);
                                        }
                                        res = res1;
@@ -595,7 +620,7 @@ parse_qdescrs(char **sp, int *code)
                                parse_whsp(sp);
                        } else {
                                charray_free(res);
-                               *code = SCHEMA_ERR_UNEXPTOKEN;
+                               *code = LDAP_SCHERR_UNEXPTOKEN;
                                return(NULL);
                        }
                }
@@ -605,7 +630,7 @@ parse_qdescrs(char **sp, int *code)
        } else if ( kind == TK_QDESCR ) {
                res = calloc(2,sizeof(char *));
                if ( !res ) {
-                       *code = SCHEMA_ERR_OUTOFMEM;
+                       *code = LDAP_SCHERR_OUTOFMEM;
                        return NULL;
                }
                res[0] = sval;
@@ -613,9 +638,55 @@ parse_qdescrs(char **sp, int *code)
                parse_whsp(sp);
                return res;
        } else {
-               *code = SCHEMA_ERR_BADNAME;
+               *code = LDAP_SCHERR_BADNAME;
+               return NULL;
+       }
+}
+
+/* Parse a woid */
+static char *
+parse_woid(char **sp, int *code)
+{
+       char * sval;
+       int kind;
+
+       parse_whsp(sp);
+       kind = get_token(sp, &sval);
+       if ( kind != TK_BAREWORD ) {
+               *code = LDAP_SCHERR_UNEXPTOKEN;
+               return NULL;
+       }
+       parse_whsp(sp);
+       return sval;
+}
+
+/* Parse a noidlen */
+static char *
+parse_noidlen(char **sp, int *code, int *len)
+{
+       char * sval;
+       int kind;
+
+       *len = 0;
+       kind = get_token(sp, &sval);
+       if ( kind != TK_BAREWORD ) {
+               *code = LDAP_SCHERR_UNEXPTOKEN;
                return NULL;
        }
+       if ( **sp == '{' ) {
+               (*sp)++;
+               *len = atoi(**sp);
+               while ( isdigit(**sp) )
+                       (*sp)++;
+               (*sp)++;
+               if ( **sp != '}' ) {
+                       *code = LDAP_SCHERR_UNEXPTOKEN;
+                       ldap_memfree(sval);
+                       return NULL;
+               }
+               (*sp)++;
+       }               
+       return sval;
 }
 
 /* Parse a woid or a $-separated list of them enclosed in () */
@@ -642,7 +713,7 @@ parse_oids(char **sp, int *code)
                size = 3;
                res = calloc(3,sizeof(char *));
                if ( !res ) {
-                       *code = SCHEMA_ERR_OUTOFMEM;
+                       *code = LDAP_SCHERR_OUTOFMEM;
                        return NULL;
                }
                pos = 0;
@@ -652,7 +723,7 @@ parse_oids(char **sp, int *code)
                        res[pos] = sval;
                        pos++;
                } else {
-                       *code = SCHEMA_ERR_UNEXPTOKEN;
+                       *code = LDAP_SCHERR_UNEXPTOKEN;
                        charray_free(res);
                        return NULL;
                }
@@ -670,7 +741,7 @@ parse_oids(char **sp, int *code)
                                                res1 = realloc(res,size*sizeof(char *));
                                                if ( !res1 ) {
                                                  charray_free(res);
-                                                 *code = SCHEMA_ERR_OUTOFMEM;
+                                                 *code = LDAP_SCHERR_OUTOFMEM;
                                                  return(NULL);
                                                }
                                                res = res1;
@@ -678,13 +749,13 @@ parse_oids(char **sp, int *code)
                                        res[pos] = sval;
                                        pos++;
                                } else {
-                                       *code = SCHEMA_ERR_UNEXPTOKEN;
+                                       *code = LDAP_SCHERR_UNEXPTOKEN;
                                        charray_free(res);
                                        return NULL;
                                }
                                parse_whsp(sp);
                        } else {
-                               *code = SCHEMA_ERR_UNEXPTOKEN;
+                               *code = LDAP_SCHERR_UNEXPTOKEN;
                                charray_free(res);
                                return NULL;
                        }
@@ -695,7 +766,7 @@ parse_oids(char **sp, int *code)
        } else if ( kind == TK_BAREWORD ) {
                res = calloc(2,sizeof(char *));
                if ( !res ) {
-                       *code = SCHEMA_ERR_OUTOFMEM;
+                       *code = LDAP_SCHERR_OUTOFMEM;
                        return NULL;
                }
                res[0] = sval;
@@ -703,9 +774,270 @@ parse_oids(char **sp, int *code)
                parse_whsp(sp);
                return res;
        } else {
-               *code = SCHEMA_ERR_BADNAME;
+               *code = LDAP_SCHERR_BADNAME;
+               return NULL;
+       }
+}
+
+static void
+free_at(LDAP_ATTRIBUTE_TYPE * at)
+{
+       ldap_memfree(at->at_oid);
+       charray_free(at->at_names);
+       ldap_memfree(at->at_desc);
+       ldap_memfree(at->at_sup_oid);
+       ldap_memfree(at->at_equality_oid);
+       ldap_memfree(at->at_ordering_oid);
+       ldap_memfree(at->at_substr_oid);
+       ldap_memfree(at->at_syntax_oid);
+       ldap_memfree(at);
+}
+
+LDAP_ATTRIBUTE_TYPE *
+ldap_str2attributetype( char * s, int * code, char ** errp )
+{
+       int kind;
+       char * ss = s;
+       char * sval;
+       int seen_name = 0;
+       int seen_desc = 0;
+       int seen_obsolete = 0;
+       int seen_sup = 0;
+       int seen_equality = 0;
+       int seen_ordering = 0;
+       int seen_substr = 0;
+       int seen_syntax = 0;
+       int seen_usage = 0;
+       int seen_kind = 0;
+       int seen_must = 0;
+       int seen_may = 0;
+       LDAP_ATTRIBUTE_TYPE * at;
+
+       *errp = s;
+       at = calloc(1,sizeof(LDAP_ATTRIBUTE_TYPE));
+
+       if ( !at ) {
+               *code = LDAP_SCHERR_OUTOFMEM;
                return NULL;
        }
+
+       kind = get_token(&ss,&sval);
+       if ( kind != TK_LEFTPAREN ) {
+               *code = LDAP_SCHERR_NOLEFTPAREN;
+               free_at(at);
+               return NULL;
+       }
+
+       parse_whsp(&ss);
+       at->at_oid = parse_numericoid(&ss,code);
+       if ( !at->at_oid ) {
+               *errp = ss;
+               free_at(at);
+               return NULL;
+       }
+       parse_whsp(&ss);
+
+       /*
+        * Beyond this point we will be liberal an accept the items
+        * in any order.
+        */
+       while (1) {
+               kind = get_token(&ss,&sval);
+               switch (kind) {
+               case TK_EOS:
+                       *code = LDAP_SCHERR_NORIGHTPAREN;
+                       *errp = ss;
+                       free_at(at);
+                       return NULL;
+               case TK_RIGHTPAREN:
+                       return at;
+               case TK_BAREWORD:
+                       if ( !strcmp(sval,"NAME") ) {
+                               if ( seen_name ) {
+                                       *code = LDAP_SCHERR_DUPOPT;
+                                       *errp = ss;
+                                       free_at(at);
+                                       return(NULL);
+                               }
+                               seen_name = 1;
+                               at->at_names = parse_qdescrs(&ss,code);
+                               if ( !at->at_names ) {
+                                       if ( *code != LDAP_SCHERR_OUTOFMEM )
+                                               *code = LDAP_SCHERR_BADNAME;
+                                       *errp = ss;
+                                       free_at(at);
+                                       return NULL;
+                               }
+                       } else if ( !strcmp(sval,"DESC") ) {
+                               if ( seen_desc ) {
+                                       *code = LDAP_SCHERR_DUPOPT;
+                                       *errp = ss;
+                                       free_at(at);
+                                       return(NULL);
+                               }
+                               seen_desc = 1;
+                               parse_whsp(&ss);
+                               kind = get_token(&ss,&sval);
+                               if ( kind != TK_QDSTRING ) {
+                                       *code = LDAP_SCHERR_UNEXPTOKEN;
+                                       *errp = ss;
+                                       free_at(at);
+                                       return NULL;
+                               }
+                               at->at_desc = sval;
+                               parse_whsp(&ss);
+                       } else if ( !strcmp(sval,"OBSOLETE") ) {
+                               if ( seen_obsolete ) {
+                                       *code = LDAP_SCHERR_DUPOPT;
+                                       *errp = ss;
+                                       free_at(at);
+                                       return(NULL);
+                               }
+                               seen_obsolete = 1;
+                               at->at_obsolete = LDAP_SCHEMA_YES;
+                               parse_whsp(&ss);
+                       } else if ( !strcmp(sval,"SUP") ) {
+                               if ( seen_sup ) {
+                                       *code = LDAP_SCHERR_DUPOPT;
+                                       *errp = ss;
+                                       free_at(at);
+                                       return(NULL);
+                               }
+                               seen_sup = 1;
+                               at->at_sup_oid = parse_woid(&ss,code);
+                               if ( !at->at_sup_oid ) {
+                                       *errp = ss;
+                                       free_at(at);
+                                       return NULL;
+                               }
+                       } else if ( !strcmp(sval,"EQUALITY") ) {
+                               if ( seen_equality ) {
+                                       *code = LDAP_SCHERR_DUPOPT;
+                                       *errp = ss;
+                                       free_at(at);
+                                       return(NULL);
+                               }
+                               seen_equality = 1;
+                               at->at_equality_oid = parse_woid(&ss,code);
+                               if ( !at->at_equality_oid ) {
+                                       *errp = ss;
+                                       free_at(at);
+                                       return NULL;
+                               }
+                       } else if ( !strcmp(sval,"ORDERING") ) {
+                               if ( seen_ordering ) {
+                                       *code = LDAP_SCHERR_DUPOPT;
+                                       *errp = ss;
+                                       free_at(at);
+                                       return(NULL);
+                               }
+                               seen_ordering = 1;
+                               at->at_ordering_oid = parse_woid(&ss,code);
+                               if ( !at->at_ordering_oid ) {
+                                       *errp = ss;
+                                       free_at(at);
+                                       return NULL;
+                               }
+                       } else if ( !strcmp(sval,"SUBSTR") ) {
+                               if ( seen_substr ) {
+                                       *code = LDAP_SCHERR_DUPOPT;
+                                       *errp = ss;
+                                       free_at(at);
+                                       return(NULL);
+                               }
+                               seen_substr = 1;
+                               at->at_substr_oid = parse_woid(&ss,code);
+                               if ( !at->at_substr_oid ) {
+                                       *errp = ss;
+                                       free_at(at);
+                                       return NULL;
+                               }
+                       } else if ( !strcmp(sval,"SYNTAX") ) {
+                               if ( seen_syntax ) {
+                                       *code = LDAP_SCHERR_DUPOPT;
+                                       *errp = ss;
+                                       free_at(at);
+                                       return(NULL);
+                               }
+                               seen_syntax = 1;
+                               parse_whsp(&ss);
+                               at->at_syntax_oid = parse_noidlen(&ss,code,&at->at_syntax_len);
+                               if ( !at->at_syntax_oid ) {
+                                       *errp = ss;
+                                       free_at(at);
+                                       return NULL;
+                               }
+                       } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
+                               if ( at->at_single_value ) {
+                                       *code = LDAP_SCHERR_DUPOPT;
+                                       *errp = ss;
+                                       free_at(at);
+                                       return(NULL);
+                               }
+                               at->at_single_value = LDAP_SCHEMA_YES;
+                               parse_whsp(&ss);
+                       } else if ( !strcmp(sval,"COLLECTIVE") ) {
+                               if ( at->at_collective ) {
+                                       *code = LDAP_SCHERR_DUPOPT;
+                                       *errp = ss;
+                                       free_at(at);
+                                       return(NULL);
+                               }
+                               at->at_collective = LDAP_SCHEMA_YES;
+                               parse_whsp(&ss);
+                       } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
+                               if ( at->at_no_user_mod ) {
+                                       *code = LDAP_SCHERR_DUPOPT;
+                                       *errp = ss;
+                                       free_at(at);
+                                       return(NULL);
+                               }
+                               at->at_no_user_mod = LDAP_SCHEMA_YES;
+                               parse_whsp(&ss);
+                       } else if ( !strcmp(sval,"USAGE") ) {
+                               if ( seen_usage ) {
+                                       *code = LDAP_SCHERR_DUPOPT;
+                                       *errp = ss;
+                                       free_at(at);
+                                       return(NULL);
+                               }
+                               seen_usage = 1;
+                               parse_whsp(&ss);
+                               kind = get_token(&ss,&sval);
+                               if ( kind != TK_BAREWORD ) {
+                                       *code = LDAP_SCHERR_UNEXPTOKEN;
+                                       *errp = ss;
+                                       free_at(at);
+                                       return NULL;
+                               }
+                               if ( !strcasecmp(sval,"userApplications") )
+                                       at->at_usage = LDAP_SCHEMA_USER_APPLICATIONS;
+                               else if ( !strcasecmp(sval,"directoryOperation") )
+                                       at->at_usage = LDAP_SCHEMA_DIRECTORY_OPERATION;
+                               else if ( !strcasecmp(sval,"distributedOperation") )
+                                       at->at_usage = LDAP_SCHEMA_DISTRIBUTED_OPERATION;
+                               else if ( !strcasecmp(sval,"dSAOperation") )
+                                       at->at_usage = LDAP_SCHEMA_DSA_OPERATION;
+                               else {
+                                       *code = LDAP_SCHERR_UNEXPTOKEN;
+                                       *errp = ss;
+                                       free_at(at);
+                                       return NULL;
+                               }
+                       } else {
+                               *code = LDAP_SCHERR_UNEXPTOKEN;
+                               *errp = ss;
+                               free_at(at);
+                               return NULL;
+                       }
+                       break;
+               default:
+                       *code = LDAP_SCHERR_UNEXPTOKEN;
+                       *errp = ss;
+                       free_at(at);
+                       return NULL;
+               }
+       }
 }
 
 static void
@@ -739,13 +1071,13 @@ ldap_str2objectclass( char * s, int * code, char ** errp )
        oc = calloc(1,sizeof(LDAP_OBJECT_CLASS));
 
        if ( !oc ) {
-               *code = SCHEMA_ERR_OUTOFMEM;
+               *code = LDAP_SCHERR_OUTOFMEM;
                return NULL;
        }
 
        kind = get_token(&ss,&sval);
        if ( kind != TK_LEFTPAREN ) {
-               *code = SCHEMA_ERR_NOLEFTPAREN;
+               *code = LDAP_SCHERR_NOLEFTPAREN;
                free_oc(oc);
                return NULL;
        }
@@ -767,7 +1099,7 @@ ldap_str2objectclass( char * s, int * code, char ** errp )
                kind = get_token(&ss,&sval);
                switch (kind) {
                case TK_EOS:
-                       *code = SCHEMA_ERR_NORIGHTPAREN;
+                       *code = LDAP_SCHERR_NORIGHTPAREN;
                        *errp = ss;
                        free_oc(oc);
                        return NULL;
@@ -776,7 +1108,7 @@ ldap_str2objectclass( char * s, int * code, char ** errp )
                case TK_BAREWORD:
                        if ( !strcmp(sval,"NAME") ) {
                                if ( seen_name ) {
-                                       *code = SCHEMA_ERR_DUPOPT;
+                                       *code = LDAP_SCHERR_DUPOPT;
                                        *errp = ss;
                                        free_oc(oc);
                                        return(NULL);
@@ -784,15 +1116,15 @@ ldap_str2objectclass( char * s, int * code, char ** errp )
                                seen_name = 1;
                                oc->oc_names = parse_qdescrs(&ss,code);
                                if ( !oc->oc_names ) {
-                                       if ( *code != SCHEMA_ERR_OUTOFMEM )
-                                               *code = SCHEMA_ERR_BADNAME;
+                                       if ( *code != LDAP_SCHERR_OUTOFMEM )
+                                               *code = LDAP_SCHERR_BADNAME;
                                        *errp = ss;
                                        free_oc(oc);
                                        return NULL;
                                }
                        } else if ( !strcmp(sval,"DESC") ) {
                                if ( seen_desc ) {
-                                       *code = SCHEMA_ERR_DUPOPT;
+                                       *code = LDAP_SCHERR_DUPOPT;
                                        *errp = ss;
                                        free_oc(oc);
                                        return(NULL);
@@ -801,26 +1133,26 @@ ldap_str2objectclass( char * s, int * code, char ** errp )
                                parse_whsp(&ss);
                                kind = get_token(&ss,&sval);
                                if ( kind != TK_QDSTRING ) {
-                                       *code = SCHEMA_ERR_UNEXPTOKEN;
+                                       *code = LDAP_SCHERR_UNEXPTOKEN;
                                        *errp = ss;
-                                       free(oc);
+                                       free_oc(oc);
                                        return NULL;
                                }
                                oc->oc_desc = sval;
                                parse_whsp(&ss);
                        } else if ( !strcmp(sval,"OBSOLETE") ) {
                                if ( seen_obsolete ) {
-                                       *code = SCHEMA_ERR_DUPOPT;
+                                       *code = LDAP_SCHERR_DUPOPT;
                                        *errp = ss;
                                        free_oc(oc);
                                        return(NULL);
                                }
                                seen_obsolete = 1;
-                               oc->oc_obsolete = 1;
+                               oc->oc_obsolete = LDAP_SCHEMA_YES;
                                parse_whsp(&ss);
                        } else if ( !strcmp(sval,"SUP") ) {
                                if ( seen_sup ) {
-                                       *code = SCHEMA_ERR_DUPOPT;
+                                       *code = LDAP_SCHERR_DUPOPT;
                                        *errp = ss;
                                        free_oc(oc);
                                        return(NULL);
@@ -837,37 +1169,37 @@ ldap_str2objectclass( char * s, int * code, char ** errp )
                                }
                        } else if ( !strcmp(sval,"ABSTRACT") ) {
                                if ( seen_kind ) {
-                                       *code = SCHEMA_ERR_DUPOPT;
+                                       *code = LDAP_SCHERR_DUPOPT;
                                        *errp = ss;
                                        free_oc(oc);
                                        return(NULL);
                                }
                                seen_kind = 1;
-                               oc->oc_kind = 0;
+                               oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
                                parse_whsp(&ss);
                        } else if ( !strcmp(sval,"STRUCTURAL") ) {
                                if ( seen_kind ) {
-                                       *code = SCHEMA_ERR_DUPOPT;
+                                       *code = LDAP_SCHERR_DUPOPT;
                                        *errp = ss;
                                        free_oc(oc);
                                        return(NULL);
                                }
                                seen_kind = 1;
-                               oc->oc_kind = 1;
+                               oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
                                parse_whsp(&ss);
                        } else if ( !strcmp(sval,"AUXILIARY") ) {
                                if ( seen_kind ) {
-                                       *code = SCHEMA_ERR_DUPOPT;
+                                       *code = LDAP_SCHERR_DUPOPT;
                                        *errp = ss;
                                        free_oc(oc);
                                        return(NULL);
                                }
                                seen_kind = 1;
-                               oc->oc_kind = 2;
+                               oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
                                parse_whsp(&ss);
                        } else if ( !strcmp(sval,"MUST") ) {
                                if ( seen_must ) {
-                                       *code = SCHEMA_ERR_DUPOPT;
+                                       *code = LDAP_SCHERR_DUPOPT;
                                        *errp = ss;
                                        free_oc(oc);
                                        return(NULL);
@@ -882,7 +1214,7 @@ ldap_str2objectclass( char * s, int * code, char ** errp )
                                parse_whsp(&ss);
                        } else if ( !strcmp(sval,"MAY") ) {
                                if ( seen_may ) {
-                                       *code = SCHEMA_ERR_DUPOPT;
+                                       *code = LDAP_SCHERR_DUPOPT;
                                        *errp = ss;
                                        free_oc(oc);
                                        return(NULL);
@@ -896,14 +1228,14 @@ ldap_str2objectclass( char * s, int * code, char ** errp )
                                }
                                parse_whsp(&ss);
                        } else {
-                               *code = SCHEMA_ERR_UNEXPTOKEN;
+                               *code = LDAP_SCHERR_UNEXPTOKEN;
                                *errp = ss;
                                free_oc(oc);
                                return NULL;
                        }
                        break;
                default:
-                       *code = SCHEMA_ERR_UNEXPTOKEN;
+                       *code = LDAP_SCHERR_UNEXPTOKEN;
                        *errp = ss;
                        free_oc(oc);
                        return NULL;
@@ -911,4 +1243,25 @@ ldap_str2objectclass( char * s, int * code, char ** errp )
        }
 }
 
+static char *err2text[] = {
+       "",
+       "Out of memory",
+       "Unexpected token",
+       "Missing opening parenthesis",
+       "Missing closing parenthesis",
+       "Expecting digit",
+       "Expecting a name",
+       "Bad description",
+       "Bad superiors",
+       "Duplicate option"
+};
 
+char *
+ldap_scherr2str(int code)
+{
+       if ( code < 1 || code >= (sizeof(err2text)/sizeof(char *)) ) {
+               return "Unknown error";
+       } else {
+               return err2text[code];
+       }
+}