2 * Copyright 1999 The OpenLDAP Foundation, All Rights Reserved.
3 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5 * schema.c: parsing routines used by servers and clients to process
12 #include <ac/stdlib.h>
15 #include <ac/string.h>
20 #include <ldap_schema.h>
23 * When pretty printing the entities we will be appending to a buffer.
24 * Since checking for overflow, realloc'ing and checking if no error
25 * is extremely boring, we will use a protection layer that will let
26 * us blissfully ignore the error until the end. This layer is
27 * implemented with the help of the next type.
30 typedef struct safe_string {
38 new_safe_string(int size)
42 ss = LDAP_MALLOC(sizeof(safe_string));
46 ss->val = LDAP_MALLOC(size);
60 safe_string_free(safe_string * ss)
69 safe_string_val(safe_string * ss)
71 ss->val[ss->pos] = '\0';
76 append_to_safe_string(safe_string * ss, char * s)
82 * Some runaway process is trying to append to a string that
83 * overflowed and we could not extend.
88 /* We always make sure there is at least one position available */
89 if ( ss->pos + l >= ss->size-1 ) {
91 temp = LDAP_REALLOC(ss->val, ss->size);
93 /* Trouble, out of memory */
99 strncpy(&ss->val[ss->pos], s, l);
101 if ( ss->pos > 0 && isspace(ss->val[ss->pos-1]) )
110 print_literal(safe_string *ss, char *s)
112 return(append_to_safe_string(ss,s));
116 print_whsp(safe_string *ss)
119 return(append_to_safe_string(ss,""));
121 return(append_to_safe_string(ss," "));
125 print_numericoid(safe_string *ss, char *s)
128 return(append_to_safe_string(ss,s));
131 /* This one is identical to print_qdescr */
133 print_qdstring(safe_string *ss, char *s)
136 print_literal(ss,"'");
137 append_to_safe_string(ss,s);
138 print_literal(ss,"'");
139 return(print_whsp(ss));
143 print_qdescr(safe_string *ss, char *s)
146 print_literal(ss,"'");
147 append_to_safe_string(ss,s);
148 print_literal(ss,"'");
149 return(print_whsp(ss));
153 print_qdescrlist(safe_string *ss, char **sa)
158 for (sp=sa; *sp; sp++) {
159 ret = print_qdescr(ss,*sp);
161 /* If the list was empty, we return zero that is potentially
162 * incorrect, but since we will be still appending things, the
163 * overflow will be detected later. Maybe FIX.
169 print_qdescrs(safe_string *ss, char **sa)
171 /* The only way to represent an empty list is as a qdescrlist
172 * so, if the list is empty we treat it as a long list.
173 * Really, this is what the syntax mandates. We should not
174 * be here if the list was empty, but if it happens, a label
175 * has already been output and we cannot undo it.
177 if ( !sa[0] || ( sa[0] && sa[1] ) ) {
179 print_literal(ss,"(");
180 print_qdescrlist(ss,sa);
181 print_literal(ss,")");
182 return(print_whsp(ss));
184 return(print_qdescr(ss,*sa));
189 print_woid(safe_string *ss, char *s)
192 append_to_safe_string(ss,s);
193 return print_whsp(ss);
197 print_oidlist(safe_string *ss, char **sa)
201 for (sp=sa; *(sp+1); sp++) {
203 print_literal(ss,"$");
205 return(print_woid(ss,*sp));
209 print_oids(safe_string *ss, char **sa)
211 if ( sa[0] && sa[1] ) {
212 print_literal(ss,"(");
213 print_oidlist(ss,sa);
215 return(print_literal(ss,")"));
217 return(print_woid(ss,*sa));
222 print_noidlen(safe_string *ss, char *s, int l)
227 ret = print_numericoid(ss,s);
229 sprintf(buf,"{%d}",l);
230 ret = print_literal(ss,buf);
236 ldap_syntax2str( LDAP_SYNTAX * syn )
241 ss = new_safe_string(256);
245 print_literal(ss,"(");
248 print_numericoid(ss, syn->syn_oid);
251 if ( syn->syn_desc ) {
252 print_literal(ss,"DESC");
253 print_qdstring(ss,syn->syn_desc);
257 print_literal(ss,")");
259 retstring = LDAP_STRDUP(safe_string_val(ss));
260 safe_string_free(ss);
265 ldap_objectclass2str( LDAP_OBJECT_CLASS * oc )
270 ss = new_safe_string(256);
274 print_literal(ss,"(");
277 print_numericoid(ss, oc->oc_oid);
280 if ( oc->oc_names ) {
281 print_literal(ss,"NAME");
282 print_qdescrs(ss,oc->oc_names);
286 print_literal(ss,"DESC");
287 print_qdstring(ss,oc->oc_desc);
290 if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) {
291 print_literal(ss, "OBSOLETE");
295 if ( oc->oc_sup_oids ) {
296 print_literal(ss,"SUP");
298 print_oids(ss,oc->oc_sup_oids);
302 switch (oc->oc_kind) {
303 case LDAP_SCHEMA_ABSTRACT:
304 print_literal(ss,"ABSTRACT");
306 case LDAP_SCHEMA_STRUCTURAL:
307 print_literal(ss,"STRUCTURAL");
309 case LDAP_SCHEMA_AUXILIARY:
310 print_literal(ss,"AUXILIARY");
313 print_literal(ss,"KIND-UNKNOWN");
318 if ( oc->oc_at_oids_must ) {
319 print_literal(ss,"MUST");
321 print_oids(ss,oc->oc_at_oids_must);
325 if ( oc->oc_at_oids_may ) {
326 print_literal(ss,"MAY");
328 print_oids(ss,oc->oc_at_oids_may);
333 print_literal(ss,")");
335 retstring = LDAP_STRDUP(safe_string_val(ss));
336 safe_string_free(ss);
341 ldap_attributetype2str( LDAP_ATTRIBUTE_TYPE * at )
346 ss = new_safe_string(256);
350 print_literal(ss,"(");
353 print_numericoid(ss, at->at_oid);
356 if ( at->at_names ) {
357 print_literal(ss,"NAME");
358 print_qdescrs(ss,at->at_names);
362 print_literal(ss,"DESC");
363 print_qdstring(ss,at->at_desc);
366 if ( at->at_obsolete == LDAP_SCHEMA_YES ) {
367 print_literal(ss, "OBSOLETE");
371 if ( at->at_sup_oid ) {
372 print_literal(ss,"SUP");
373 print_woid(ss,at->at_sup_oid);
376 if ( at->at_equality_oid ) {
377 print_literal(ss,"EQUALITY");
378 print_woid(ss,at->at_equality_oid);
381 if ( at->at_ordering_oid ) {
382 print_literal(ss,"ORDERING");
383 print_woid(ss,at->at_ordering_oid);
386 if ( at->at_substr_oid ) {
387 print_literal(ss,"SUBSTR");
388 print_woid(ss,at->at_substr_oid);
391 if ( at->at_syntax_oid ) {
392 print_literal(ss,"SYNTAX");
394 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
398 if ( at->at_single_value == LDAP_SCHEMA_YES ) {
399 print_literal(ss,"SINGLE-VALUE");
403 if ( at->at_collective == LDAP_SCHEMA_YES ) {
404 print_literal(ss,"COLLECTIVE");
408 if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
409 print_literal(ss,"NO-USER-MODIFICATION");
413 if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
414 print_literal(ss,"USAGE");
416 switch (at->at_usage) {
417 case LDAP_SCHEMA_DIRECTORY_OPERATION:
418 print_literal(ss,"directoryOperation");
420 case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
421 print_literal(ss,"distributedOperation");
423 case LDAP_SCHEMA_DSA_OPERATION:
424 print_literal(ss,"dSAOperation");
427 print_literal(ss,"UNKNOWN");
433 print_literal(ss,")");
435 retstring = LDAP_STRDUP(safe_string_val(ss));
436 safe_string_free(ss);
441 * Now come the parsers. There is one parser for each entity type:
442 * objectclasses, attributetypes, etc.
444 * Each of them is written as a recursive-descent parser, except that
445 * none of them is really recursive. But the idea is kept: there
446 * is one routine per non-terminal that eithers gobbles lexical tokens
447 * or calls lower-level routines, etc.
449 * The scanner is implemented in the routine get_token. Actually,
450 * get_token is more than a scanner and will return tokens that are
451 * in fact non-terminals in the grammar. So you can see the whole
452 * approach as the combination of a low-level bottom-up recognizer
453 * combined with a scanner and a number of top-down parsers. Or just
454 * consider that the real grammars recognized by the parsers are not
455 * those of the standards. As a matter of fact, our parsers are more
456 * liberal than the spec when there is no ambiguity.
458 * The difference is pretty academic (modulo bugs or incorrect
459 * interpretation of the specs).
462 #define TK_NOENDQUOTE -2
463 #define TK_OUTOFMEM -1
465 #define TK_UNEXPCHAR 1
466 #define TK_BAREWORD 2
467 #define TK_QDSTRING 3
468 #define TK_LEFTPAREN 4
469 #define TK_RIGHTPAREN 5
471 #define TK_QDESCR TK_QDSTRING
479 get_token(char ** sp, char ** token_val)
496 kind = TK_RIGHTPAREN;
507 while ( **sp != '\'' && **sp != '\0' )
509 if ( **sp == '\'' ) {
511 res = LDAP_MALLOC(q-p+1);
521 kind = TK_NOENDQUOTE;
527 while ( !isspace(**sp) && **sp != '\0' )
530 res = LDAP_MALLOC(q-p+1);
539 /* kind = TK_UNEXPCHAR; */
546 /* Gobble optional whitespace */
548 parse_whsp(char **sp)
550 while (isspace(**sp))
555 * General note for all parsers: to guarantee the algorithm halts they
556 * must always advance the pointer even when an error is found. For
557 * this one is not that important since an error here is fatal at the
558 * upper layers, but it is a simple strategy that will not get in
562 /* Parse a sequence of dot-separated decimal strings */
564 parse_numericoid(char **sp, int *code)
570 /* Each iteration of this loop gets one decimal string */
572 if ( !isdigit(**sp) ) {
574 * Initial char is not a digit or char after dot is
577 *code = LDAP_SCHERR_NODIGIT;
581 while ( isdigit(**sp) )
585 /* Otherwise, gobble the dot and loop again */
588 /* Now *sp points at the char past the numericoid. Perfect. */
590 res = LDAP_MALLOC(len+1);
592 *code = LDAP_SCHERR_OUTOFMEM;
595 strncpy(res,start,len);
600 /* Parse a qdescr or a list of them enclosed in () */
602 parse_qdescrs(char **sp, int *code)
612 kind = get_token(sp,&sval);
613 if ( kind == TK_LEFTPAREN ) {
614 /* Let's presume there will be at least 2 entries */
616 res = LDAP_CALLOC(3,sizeof(char *));
618 *code = LDAP_SCHERR_OUTOFMEM;
624 kind = get_token(sp,&sval);
625 if ( kind == TK_RIGHTPAREN )
627 if ( kind == TK_QDESCR ) {
628 if ( pos == size-2 ) {
630 res1 = LDAP_REALLOC(res,size*sizeof(char *));
633 *code = LDAP_SCHERR_OUTOFMEM;
643 *code = LDAP_SCHERR_UNEXPTOKEN;
650 } else if ( kind == TK_QDESCR ) {
651 res = LDAP_CALLOC(2,sizeof(char *));
653 *code = LDAP_SCHERR_OUTOFMEM;
661 *code = LDAP_SCHERR_BADNAME;
668 parse_woid(char **sp, int *code)
674 kind = get_token(sp, &sval);
675 if ( kind != TK_BAREWORD ) {
676 *code = LDAP_SCHERR_UNEXPTOKEN;
683 /* Parse a noidlen */
685 parse_noidlen(char **sp, int *code, int *len, int be_liberal)
692 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
693 if ( be_liberal && **sp == '\'' ) {
697 sval = parse_numericoid(sp, code);
704 while ( isdigit(**sp) )
707 *code = LDAP_SCHERR_UNEXPTOKEN;
713 if ( be_liberal && quoted ) {
714 if ( **sp == '\'' ) {
717 *code = LDAP_SCHERR_UNEXPTOKEN;
726 * Next routine will accept a qdstring in place of an oid if
727 * be_liberal is set. This is necessary to interoperate with Netscape
728 * Directory server that will improperly quote each oid (at least
729 * those of the descr kind) in the SUP clause.
732 /* Parse a woid or a $-separated list of them enclosed in () */
734 parse_oids(char **sp, int *code, int be_liberal)
744 * Strictly speaking, doing this here accepts whsp before the
745 * ( at the begining of an oidlist, but this is harmless. Also,
746 * we are very liberal in what we accept as an OID. Maybe
750 kind = get_token(sp,&sval);
751 if ( kind == TK_LEFTPAREN ) {
752 /* Let's presume there will be at least 2 entries */
754 res = LDAP_CALLOC(3,sizeof(char *));
756 *code = LDAP_SCHERR_OUTOFMEM;
761 kind = get_token(sp,&sval);
762 if ( kind == TK_BAREWORD ||
763 ( be_liberal && kind == TK_QDSTRING ) ) {
767 *code = LDAP_SCHERR_UNEXPTOKEN;
773 kind = get_token(sp,&sval);
774 if ( kind == TK_RIGHTPAREN )
776 if ( kind == TK_DOLLAR ) {
778 kind = get_token(sp,&sval);
779 if ( kind == TK_BAREWORD ||
780 ( be_liberal && kind == TK_QDSTRING ) ) {
781 if ( pos == size-2 ) {
783 res1 = LDAP_REALLOC(res,size*sizeof(char *));
786 *code = LDAP_SCHERR_OUTOFMEM;
794 *code = LDAP_SCHERR_UNEXPTOKEN;
800 *code = LDAP_SCHERR_UNEXPTOKEN;
808 } else if ( kind == TK_BAREWORD ||
809 ( be_liberal && kind == TK_QDSTRING ) ) {
810 res = LDAP_CALLOC(2,sizeof(char *));
812 *code = LDAP_SCHERR_OUTOFMEM;
820 *code = LDAP_SCHERR_BADNAME;
826 ldap_syntax_free(LDAP_SYNTAX * syn)
828 LDAP_FREE(syn->syn_oid);
829 LDAP_FREE(syn->syn_desc);
834 ldap_str2syntax( char * s, int * code, char ** errp )
844 *code = LDAP_SCHERR_EMPTY;
850 syn = LDAP_CALLOC(1,sizeof(LDAP_SYNTAX));
853 *code = LDAP_SCHERR_OUTOFMEM;
857 kind = get_token(&ss,&sval);
858 if ( kind != TK_LEFTPAREN ) {
859 *code = LDAP_SCHERR_NOLEFTPAREN;
860 ldap_syntax_free(syn);
865 syn->syn_oid = parse_numericoid(&ss,code);
866 if ( !syn->syn_oid ) {
868 ldap_syntax_free(syn);
874 * Beyond this point we will be liberal and accept the items
878 kind = get_token(&ss,&sval);
881 *code = LDAP_SCHERR_NORIGHTPAREN;
883 ldap_syntax_free(syn);
888 if ( !strcmp(sval,"DESC") ) {
890 *code = LDAP_SCHERR_DUPOPT;
892 ldap_syntax_free(syn);
897 kind = get_token(&ss,&sval);
898 if ( kind != TK_QDSTRING ) {
899 *code = LDAP_SCHERR_UNEXPTOKEN;
901 ldap_syntax_free(syn);
904 syn->syn_desc = sval;
906 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
907 /* Should be parse_qdstrings */
908 ssdummy = parse_qdescrs(&ss, code);
911 ldap_syntax_free(syn);
915 *code = LDAP_SCHERR_UNEXPTOKEN;
917 ldap_syntax_free(syn);
922 *code = LDAP_SCHERR_UNEXPTOKEN;
924 ldap_syntax_free(syn);
931 ldap_attributetype_free(LDAP_ATTRIBUTE_TYPE * at)
933 LDAP_FREE(at->at_oid);
934 LDAP_VFREE(at->at_names);
935 LDAP_FREE(at->at_desc);
936 LDAP_FREE(at->at_sup_oid);
937 LDAP_FREE(at->at_equality_oid);
938 LDAP_FREE(at->at_ordering_oid);
939 LDAP_FREE(at->at_substr_oid);
940 LDAP_FREE(at->at_syntax_oid);
944 LDAP_ATTRIBUTE_TYPE *
945 ldap_str2attributetype( char * s, int * code, char ** errp )
950 int be_liberal = 1; /* Future additional argument */
953 int seen_obsolete = 0;
955 int seen_equality = 0;
956 int seen_ordering = 0;
963 LDAP_ATTRIBUTE_TYPE * at;
968 *code = LDAP_SCHERR_EMPTY;
974 at = LDAP_CALLOC(1,sizeof(LDAP_ATTRIBUTE_TYPE));
977 *code = LDAP_SCHERR_OUTOFMEM;
981 kind = get_token(&ss,&sval);
982 if ( kind != TK_LEFTPAREN ) {
983 *code = LDAP_SCHERR_NOLEFTPAREN;
984 ldap_attributetype_free(at);
989 * Definitions MUST begin with an OID in the numericoid format.
990 * However, this routine is used by clients to parse the response
991 * from servers and very well known servers will provide an OID
992 * in the wrong format or even no OID at all. We do our best to
993 * extract info from those servers.
997 at->at_oid = parse_numericoid(&ss,code);
1002 kind = get_token(&ss,&sval);
1003 if ( kind == TK_BAREWORD ) {
1004 if ( !strcmp(sval, "NAME") ||
1005 !strcmp(sval, "DESC") ||
1006 !strcmp(sval, "OBSOLETE") ||
1007 !strcmp(sval, "SUP") ||
1008 !strcmp(sval, "EQUALITY") ||
1009 !strcmp(sval, "ORDERING") ||
1010 !strcmp(sval, "SUBSTR") ||
1011 !strcmp(sval, "SYNTAX") ||
1012 !strcmp(sval, "SINGLE-VALUE") ||
1013 !strcmp(sval, "COLLECTIVE") ||
1014 !strcmp(sval, "NO-USER-MODIFICATION") ||
1015 !strcmp(sval, "USAGE") ||
1016 !strncmp(sval, "X-", 2) ) {
1017 /* Missing OID, backtrack */
1020 /* Non-numerical OID, ignore */
1025 ldap_attributetype_free(at);
1032 * Beyond this point we will be liberal and accept the items
1036 kind = get_token(&ss,&sval);
1039 *code = LDAP_SCHERR_NORIGHTPAREN;
1041 ldap_attributetype_free(at);
1046 if ( !strcmp(sval,"NAME") ) {
1048 *code = LDAP_SCHERR_DUPOPT;
1050 ldap_attributetype_free(at);
1054 at->at_names = parse_qdescrs(&ss,code);
1055 if ( !at->at_names ) {
1056 if ( *code != LDAP_SCHERR_OUTOFMEM )
1057 *code = LDAP_SCHERR_BADNAME;
1059 ldap_attributetype_free(at);
1062 } else if ( !strcmp(sval,"DESC") ) {
1064 *code = LDAP_SCHERR_DUPOPT;
1066 ldap_attributetype_free(at);
1071 kind = get_token(&ss,&sval);
1072 if ( kind != TK_QDSTRING ) {
1073 *code = LDAP_SCHERR_UNEXPTOKEN;
1075 ldap_attributetype_free(at);
1080 } else if ( !strcmp(sval,"OBSOLETE") ) {
1081 if ( seen_obsolete ) {
1082 *code = LDAP_SCHERR_DUPOPT;
1084 ldap_attributetype_free(at);
1088 at->at_obsolete = LDAP_SCHEMA_YES;
1090 } else if ( !strcmp(sval,"SUP") ) {
1092 *code = LDAP_SCHERR_DUPOPT;
1094 ldap_attributetype_free(at);
1098 at->at_sup_oid = parse_woid(&ss,code);
1099 if ( !at->at_sup_oid ) {
1101 ldap_attributetype_free(at);
1104 } else if ( !strcmp(sval,"EQUALITY") ) {
1105 if ( seen_equality ) {
1106 *code = LDAP_SCHERR_DUPOPT;
1108 ldap_attributetype_free(at);
1112 at->at_equality_oid = parse_woid(&ss,code);
1113 if ( !at->at_equality_oid ) {
1115 ldap_attributetype_free(at);
1118 } else if ( !strcmp(sval,"ORDERING") ) {
1119 if ( seen_ordering ) {
1120 *code = LDAP_SCHERR_DUPOPT;
1122 ldap_attributetype_free(at);
1126 at->at_ordering_oid = parse_woid(&ss,code);
1127 if ( !at->at_ordering_oid ) {
1129 ldap_attributetype_free(at);
1132 } else if ( !strcmp(sval,"SUBSTR") ) {
1133 if ( seen_substr ) {
1134 *code = LDAP_SCHERR_DUPOPT;
1136 ldap_attributetype_free(at);
1140 at->at_substr_oid = parse_woid(&ss,code);
1141 if ( !at->at_substr_oid ) {
1143 ldap_attributetype_free(at);
1146 } else if ( !strcmp(sval,"SYNTAX") ) {
1147 if ( seen_syntax ) {
1148 *code = LDAP_SCHERR_DUPOPT;
1150 ldap_attributetype_free(at);
1155 at->at_syntax_oid = parse_noidlen(&ss,code,&at->at_syntax_len,be_liberal);
1156 if ( !at->at_syntax_oid ) {
1158 ldap_attributetype_free(at);
1162 } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
1163 if ( at->at_single_value ) {
1164 *code = LDAP_SCHERR_DUPOPT;
1166 ldap_attributetype_free(at);
1169 at->at_single_value = LDAP_SCHEMA_YES;
1171 } else if ( !strcmp(sval,"COLLECTIVE") ) {
1172 if ( at->at_collective ) {
1173 *code = LDAP_SCHERR_DUPOPT;
1175 ldap_attributetype_free(at);
1178 at->at_collective = LDAP_SCHEMA_YES;
1180 } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
1181 if ( at->at_no_user_mod ) {
1182 *code = LDAP_SCHERR_DUPOPT;
1184 ldap_attributetype_free(at);
1187 at->at_no_user_mod = LDAP_SCHEMA_YES;
1189 } else if ( !strcmp(sval,"USAGE") ) {
1191 *code = LDAP_SCHERR_DUPOPT;
1193 ldap_attributetype_free(at);
1198 kind = get_token(&ss,&sval);
1199 if ( kind != TK_BAREWORD ) {
1200 *code = LDAP_SCHERR_UNEXPTOKEN;
1202 ldap_attributetype_free(at);
1205 if ( !strcasecmp(sval,"userApplications") )
1207 LDAP_SCHEMA_USER_APPLICATIONS;
1208 else if ( !strcasecmp(sval,"directoryOperation") )
1210 LDAP_SCHEMA_DIRECTORY_OPERATION;
1211 else if ( !strcasecmp(sval,"distributedOperation") )
1213 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
1214 else if ( !strcasecmp(sval,"dSAOperation") )
1216 LDAP_SCHEMA_DSA_OPERATION;
1218 *code = LDAP_SCHERR_UNEXPTOKEN;
1220 ldap_attributetype_free(at);
1224 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1225 /* Should be parse_qdstrings */
1226 ssdummy = parse_qdescrs(&ss, code);
1229 ldap_attributetype_free(at);
1233 *code = LDAP_SCHERR_UNEXPTOKEN;
1235 ldap_attributetype_free(at);
1240 *code = LDAP_SCHERR_UNEXPTOKEN;
1242 ldap_attributetype_free(at);
1249 ldap_objectclass_free(LDAP_OBJECT_CLASS * oc)
1251 LDAP_FREE(oc->oc_oid);
1252 LDAP_VFREE(oc->oc_names);
1253 LDAP_FREE(oc->oc_desc);
1254 LDAP_VFREE(oc->oc_sup_oids);
1255 LDAP_VFREE(oc->oc_at_oids_must);
1256 LDAP_VFREE(oc->oc_at_oids_may);
1261 ldap_str2objectclass( char * s, int * code, char ** errp )
1266 int be_liberal = 1; /* Future additional argument */
1269 int seen_obsolete = 0;
1274 LDAP_OBJECT_CLASS * oc;
1279 *code = LDAP_SCHERR_EMPTY;
1285 oc = LDAP_CALLOC(1,sizeof(LDAP_OBJECT_CLASS));
1288 *code = LDAP_SCHERR_OUTOFMEM;
1292 kind = get_token(&ss,&sval);
1293 if ( kind != TK_LEFTPAREN ) {
1294 *code = LDAP_SCHERR_NOLEFTPAREN;
1295 ldap_objectclass_free(oc);
1300 * Definitions MUST begin with an OID in the numericoid format.
1301 * However, this routine is used by clients to parse the response
1302 * from servers and very well known servers will provide an OID
1303 * in the wrong format or even no OID at all. We do our best to
1304 * extract info from those servers.
1308 oc->oc_oid = parse_numericoid(&ss,code);
1309 if ( !oc->oc_oid ) {
1313 kind = get_token(&ss,&sval);
1314 if ( kind == TK_BAREWORD ) {
1315 if ( !strcmp(sval, "NAME") ||
1316 !strcmp(sval, "DESC") ||
1317 !strcmp(sval, "OBSOLETE") ||
1318 !strcmp(sval, "SUP") ||
1319 !strcmp(sval, "ABSTRACT") ||
1320 !strcmp(sval, "STRUCTURAL") ||
1321 !strcmp(sval, "AUXILIARY") ||
1322 !strcmp(sval, "MUST") ||
1323 !strncmp(sval, "X-", 2) ) {
1324 /* Missing OID, backtrack */
1327 /* Non-numerical OID, ignore */
1332 ldap_objectclass_free(oc);
1339 * Beyond this point we will be liberal an accept the items
1343 kind = get_token(&ss,&sval);
1346 *code = LDAP_SCHERR_NORIGHTPAREN;
1348 ldap_objectclass_free(oc);
1353 if ( !strcmp(sval,"NAME") ) {
1355 *code = LDAP_SCHERR_DUPOPT;
1357 ldap_objectclass_free(oc);
1361 oc->oc_names = parse_qdescrs(&ss,code);
1362 if ( !oc->oc_names ) {
1363 if ( *code != LDAP_SCHERR_OUTOFMEM )
1364 *code = LDAP_SCHERR_BADNAME;
1366 ldap_objectclass_free(oc);
1369 } else if ( !strcmp(sval,"DESC") ) {
1371 *code = LDAP_SCHERR_DUPOPT;
1373 ldap_objectclass_free(oc);
1378 kind = get_token(&ss,&sval);
1379 if ( kind != TK_QDSTRING ) {
1380 *code = LDAP_SCHERR_UNEXPTOKEN;
1382 ldap_objectclass_free(oc);
1387 } else if ( !strcmp(sval,"OBSOLETE") ) {
1388 if ( seen_obsolete ) {
1389 *code = LDAP_SCHERR_DUPOPT;
1391 ldap_objectclass_free(oc);
1395 oc->oc_obsolete = LDAP_SCHEMA_YES;
1397 } else if ( !strcmp(sval,"SUP") ) {
1399 *code = LDAP_SCHERR_DUPOPT;
1401 ldap_objectclass_free(oc);
1405 oc->oc_sup_oids = parse_oids(&ss,code,be_liberal);
1406 if ( !oc->oc_sup_oids ) {
1408 ldap_objectclass_free(oc);
1411 } else if ( !strcmp(sval,"ABSTRACT") ) {
1413 *code = LDAP_SCHERR_DUPOPT;
1415 ldap_objectclass_free(oc);
1419 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
1421 } else if ( !strcmp(sval,"STRUCTURAL") ) {
1423 *code = LDAP_SCHERR_DUPOPT;
1425 ldap_objectclass_free(oc);
1429 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
1431 } else if ( !strcmp(sval,"AUXILIARY") ) {
1433 *code = LDAP_SCHERR_DUPOPT;
1435 ldap_objectclass_free(oc);
1439 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
1441 } else if ( !strcmp(sval,"MUST") ) {
1443 *code = LDAP_SCHERR_DUPOPT;
1445 ldap_objectclass_free(oc);
1449 oc->oc_at_oids_must = parse_oids(&ss,code,0);
1450 if ( !oc->oc_at_oids_must ) {
1452 ldap_objectclass_free(oc);
1456 } else if ( !strcmp(sval,"MAY") ) {
1458 *code = LDAP_SCHERR_DUPOPT;
1460 ldap_objectclass_free(oc);
1464 oc->oc_at_oids_may = parse_oids(&ss,code,0);
1465 if ( !oc->oc_at_oids_may ) {
1467 ldap_objectclass_free(oc);
1471 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1472 /* Should be parse_qdstrings */
1473 ssdummy = parse_qdescrs(&ss, code);
1476 ldap_objectclass_free(oc);
1480 *code = LDAP_SCHERR_UNEXPTOKEN;
1482 ldap_objectclass_free(oc);
1487 *code = LDAP_SCHERR_UNEXPTOKEN;
1489 ldap_objectclass_free(oc);
1495 static char *err2text[] = {
1499 "Missing opening parenthesis",
1500 "Missing closing parenthesis",
1506 "Unexpected end of data"
1510 ldap_scherr2str(int code)
1512 if ( code < 1 || code >= (sizeof(err2text)/sizeof(char *)) ) {
1513 return "Unknown error";
1515 return err2text[code];