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));
130 return(append_to_safe_string(ss,""));
133 /* This one is identical to print_qdescr */
135 print_qdstring(safe_string *ss, char *s)
138 print_literal(ss,"'");
139 append_to_safe_string(ss,s);
140 print_literal(ss,"'");
141 return(print_whsp(ss));
145 print_qdescr(safe_string *ss, char *s)
148 print_literal(ss,"'");
149 append_to_safe_string(ss,s);
150 print_literal(ss,"'");
151 return(print_whsp(ss));
155 print_qdescrlist(safe_string *ss, char **sa)
160 for (sp=sa; *sp; sp++) {
161 ret = print_qdescr(ss,*sp);
163 /* If the list was empty, we return zero that is potentially
164 * incorrect, but since we will be still appending things, the
165 * overflow will be detected later. Maybe FIX.
171 print_qdescrs(safe_string *ss, char **sa)
173 /* The only way to represent an empty list is as a qdescrlist
174 * so, if the list is empty we treat it as a long list.
175 * Really, this is what the syntax mandates. We should not
176 * be here if the list was empty, but if it happens, a label
177 * has already been output and we cannot undo it.
179 if ( !sa[0] || ( sa[0] && sa[1] ) ) {
181 print_literal(ss,"(");
182 print_qdescrlist(ss,sa);
183 print_literal(ss,")");
184 return(print_whsp(ss));
186 return(print_qdescr(ss,*sa));
191 print_woid(safe_string *ss, char *s)
194 append_to_safe_string(ss,s);
195 return print_whsp(ss);
199 print_oidlist(safe_string *ss, char **sa)
203 for (sp=sa; *(sp+1); sp++) {
205 print_literal(ss,"$");
207 return(print_woid(ss,*sp));
211 print_oids(safe_string *ss, char **sa)
213 if ( sa[0] && sa[1] ) {
214 print_literal(ss,"(");
215 print_oidlist(ss,sa);
217 return(print_literal(ss,")"));
219 return(print_woid(ss,*sa));
224 print_noidlen(safe_string *ss, char *s, int l)
229 ret = print_numericoid(ss,s);
231 sprintf(buf,"{%d}",l);
232 ret = print_literal(ss,buf);
238 ldap_syntax2str( const LDAP_SYNTAX * syn )
243 ss = new_safe_string(256);
247 print_literal(ss,"(");
250 print_numericoid(ss, syn->syn_oid);
253 if ( syn->syn_desc ) {
254 print_literal(ss,"DESC");
255 print_qdstring(ss,syn->syn_desc);
259 print_literal(ss,")");
261 retstring = LDAP_STRDUP(safe_string_val(ss));
262 safe_string_free(ss);
267 ldap_matchingrule2str( const LDAP_MATCHING_RULE * mr )
272 ss = new_safe_string(256);
276 print_literal(ss,"(");
279 print_numericoid(ss, mr->mr_oid);
282 if ( mr->mr_names ) {
283 print_literal(ss,"NAME");
284 print_qdescrs(ss,mr->mr_names);
288 print_literal(ss,"DESC");
289 print_qdstring(ss,mr->mr_desc);
292 if ( mr->mr_obsolete == LDAP_SCHEMA_YES ) {
293 print_literal(ss, "OBSOLETE");
297 if ( mr->mr_syntax_oid ) {
298 print_literal(ss,"SYNTAX");
300 print_literal(ss, mr->mr_syntax_oid);
305 print_literal(ss,")");
307 retstring = LDAP_STRDUP(safe_string_val(ss));
308 safe_string_free(ss);
313 ldap_objectclass2str( const LDAP_OBJECT_CLASS * oc )
318 ss = new_safe_string(256);
322 print_literal(ss,"(");
325 print_numericoid(ss, oc->oc_oid);
328 if ( oc->oc_names ) {
329 print_literal(ss,"NAME");
330 print_qdescrs(ss,oc->oc_names);
334 print_literal(ss,"DESC");
335 print_qdstring(ss,oc->oc_desc);
338 if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) {
339 print_literal(ss, "OBSOLETE");
343 if ( oc->oc_sup_oids ) {
344 print_literal(ss,"SUP");
346 print_oids(ss,oc->oc_sup_oids);
350 switch (oc->oc_kind) {
351 case LDAP_SCHEMA_ABSTRACT:
352 print_literal(ss,"ABSTRACT");
354 case LDAP_SCHEMA_STRUCTURAL:
355 print_literal(ss,"STRUCTURAL");
357 case LDAP_SCHEMA_AUXILIARY:
358 print_literal(ss,"AUXILIARY");
361 print_literal(ss,"KIND-UNKNOWN");
366 if ( oc->oc_at_oids_must ) {
367 print_literal(ss,"MUST");
369 print_oids(ss,oc->oc_at_oids_must);
373 if ( oc->oc_at_oids_may ) {
374 print_literal(ss,"MAY");
376 print_oids(ss,oc->oc_at_oids_may);
381 print_literal(ss,")");
383 retstring = LDAP_STRDUP(safe_string_val(ss));
384 safe_string_free(ss);
389 ldap_attributetype2str( const LDAP_ATTRIBUTE_TYPE * at )
394 ss = new_safe_string(256);
398 print_literal(ss,"(");
401 print_numericoid(ss, at->at_oid);
404 if ( at->at_names ) {
405 print_literal(ss,"NAME");
406 print_qdescrs(ss,at->at_names);
410 print_literal(ss,"DESC");
411 print_qdstring(ss,at->at_desc);
414 if ( at->at_obsolete == LDAP_SCHEMA_YES ) {
415 print_literal(ss, "OBSOLETE");
419 if ( at->at_sup_oid ) {
420 print_literal(ss,"SUP");
421 print_woid(ss,at->at_sup_oid);
424 if ( at->at_equality_oid ) {
425 print_literal(ss,"EQUALITY");
426 print_woid(ss,at->at_equality_oid);
429 if ( at->at_ordering_oid ) {
430 print_literal(ss,"ORDERING");
431 print_woid(ss,at->at_ordering_oid);
434 if ( at->at_substr_oid ) {
435 print_literal(ss,"SUBSTR");
436 print_woid(ss,at->at_substr_oid);
439 if ( at->at_syntax_oid ) {
440 print_literal(ss,"SYNTAX");
442 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
446 if ( at->at_single_value == LDAP_SCHEMA_YES ) {
447 print_literal(ss,"SINGLE-VALUE");
451 if ( at->at_collective == LDAP_SCHEMA_YES ) {
452 print_literal(ss,"COLLECTIVE");
456 if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
457 print_literal(ss,"NO-USER-MODIFICATION");
461 if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
462 print_literal(ss,"USAGE");
464 switch (at->at_usage) {
465 case LDAP_SCHEMA_DIRECTORY_OPERATION:
466 print_literal(ss,"directoryOperation");
468 case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
469 print_literal(ss,"distributedOperation");
471 case LDAP_SCHEMA_DSA_OPERATION:
472 print_literal(ss,"dSAOperation");
475 print_literal(ss,"UNKNOWN");
481 print_literal(ss,")");
483 retstring = LDAP_STRDUP(safe_string_val(ss));
484 safe_string_free(ss);
489 * Now come the parsers. There is one parser for each entity type:
490 * objectclasses, attributetypes, etc.
492 * Each of them is written as a recursive-descent parser, except that
493 * none of them is really recursive. But the idea is kept: there
494 * is one routine per non-terminal that eithers gobbles lexical tokens
495 * or calls lower-level routines, etc.
497 * The scanner is implemented in the routine get_token. Actually,
498 * get_token is more than a scanner and will return tokens that are
499 * in fact non-terminals in the grammar. So you can see the whole
500 * approach as the combination of a low-level bottom-up recognizer
501 * combined with a scanner and a number of top-down parsers. Or just
502 * consider that the real grammars recognized by the parsers are not
503 * those of the standards. As a matter of fact, our parsers are more
504 * liberal than the spec when there is no ambiguity.
506 * The difference is pretty academic (modulo bugs or incorrect
507 * interpretation of the specs).
510 #define TK_NOENDQUOTE -2
511 #define TK_OUTOFMEM -1
513 #define TK_UNEXPCHAR 1
514 #define TK_BAREWORD 2
515 #define TK_QDSTRING 3
516 #define TK_LEFTPAREN 4
517 #define TK_RIGHTPAREN 5
519 #define TK_QDESCR TK_QDSTRING
527 get_token(const char ** sp, char ** token_val)
544 kind = TK_RIGHTPAREN;
555 while ( **sp != '\'' && **sp != '\0' )
557 if ( **sp == '\'' ) {
559 res = LDAP_MALLOC(q-p+1);
569 kind = TK_NOENDQUOTE;
575 while ( !isspace(**sp) && **sp != '\0' )
578 res = LDAP_MALLOC(q-p+1);
587 /* kind = TK_UNEXPCHAR; */
594 /* Gobble optional whitespace */
596 parse_whsp(const char **sp)
598 while (isspace(**sp))
603 * General note for all parsers: to guarantee the algorithm halts they
604 * must always advance the pointer even when an error is found. For
605 * this one is not that important since an error here is fatal at the
606 * upper layers, but it is a simple strategy that will not get in
610 /* Parse a sequence of dot-separated decimal strings */
612 parse_numericoid(const char **sp, int *code, const int allow_quoted)
615 const char * start = *sp;
619 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
620 if ( allow_quoted && **sp == '\'' ) {
625 /* Each iteration of this loop gets one decimal string */
627 if ( !isdigit(**sp) ) {
629 * Initial char is not a digit or char after dot is
632 *code = LDAP_SCHERR_NODIGIT;
636 while ( isdigit(**sp) )
640 /* Otherwise, gobble the dot and loop again */
643 /* Now *sp points at the char past the numericoid. Perfect. */
645 res = LDAP_MALLOC(len+1);
647 *code = LDAP_SCHERR_OUTOFMEM;
650 strncpy(res,start,len);
652 if ( allow_quoted && quoted ) {
653 if ( **sp == '\'' ) {
656 *code = LDAP_SCHERR_UNEXPTOKEN;
664 /* Parse a qdescr or a list of them enclosed in () */
666 parse_qdescrs(const char **sp, int *code)
676 kind = get_token(sp,&sval);
677 if ( kind == TK_LEFTPAREN ) {
678 /* Let's presume there will be at least 2 entries */
680 res = LDAP_CALLOC(3,sizeof(char *));
682 *code = LDAP_SCHERR_OUTOFMEM;
688 kind = get_token(sp,&sval);
689 if ( kind == TK_RIGHTPAREN )
691 if ( kind == TK_QDESCR ) {
692 if ( pos == size-2 ) {
694 res1 = LDAP_REALLOC(res,size*sizeof(char *));
697 *code = LDAP_SCHERR_OUTOFMEM;
707 *code = LDAP_SCHERR_UNEXPTOKEN;
714 } else if ( kind == TK_QDESCR ) {
715 res = LDAP_CALLOC(2,sizeof(char *));
717 *code = LDAP_SCHERR_OUTOFMEM;
725 *code = LDAP_SCHERR_BADNAME;
732 parse_woid(const char **sp, int *code)
738 kind = get_token(sp, &sval);
739 if ( kind != TK_BAREWORD ) {
740 *code = LDAP_SCHERR_UNEXPTOKEN;
747 /* Parse a noidlen */
749 parse_noidlen(const char **sp, int *code, int *len, int allow_quoted)
755 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
756 if ( allow_quoted && **sp == '\'' ) {
760 sval = parse_numericoid(sp, code, 0);
767 while ( isdigit(**sp) )
770 *code = LDAP_SCHERR_UNEXPTOKEN;
776 if ( allow_quoted && quoted ) {
777 if ( **sp == '\'' ) {
780 *code = LDAP_SCHERR_UNEXPTOKEN;
789 * Next routine will accept a qdstring in place of an oid if
790 * allow_quoted is set. This is necessary to interoperate with
791 * Netscape Directory server that will improperly quote each oid (at
792 * least those of the descr kind) in the SUP clause.
795 /* Parse a woid or a $-separated list of them enclosed in () */
797 parse_oids(const char **sp, int *code, const int allow_quoted)
807 * Strictly speaking, doing this here accepts whsp before the
808 * ( at the begining of an oidlist, but this is harmless. Also,
809 * we are very liberal in what we accept as an OID. Maybe
813 kind = get_token(sp,&sval);
814 if ( kind == TK_LEFTPAREN ) {
815 /* Let's presume there will be at least 2 entries */
817 res = LDAP_CALLOC(3,sizeof(char *));
819 *code = LDAP_SCHERR_OUTOFMEM;
824 kind = get_token(sp,&sval);
825 if ( kind == TK_BAREWORD ||
826 ( allow_quoted && kind == TK_QDSTRING ) ) {
830 *code = LDAP_SCHERR_UNEXPTOKEN;
836 kind = get_token(sp,&sval);
837 if ( kind == TK_RIGHTPAREN )
839 if ( kind == TK_DOLLAR ) {
841 kind = get_token(sp,&sval);
842 if ( kind == TK_BAREWORD ||
844 kind == TK_QDSTRING ) ) {
845 if ( pos == size-2 ) {
847 res1 = LDAP_REALLOC(res,size*sizeof(char *));
850 *code = LDAP_SCHERR_OUTOFMEM;
858 *code = LDAP_SCHERR_UNEXPTOKEN;
864 *code = LDAP_SCHERR_UNEXPTOKEN;
872 } else if ( kind == TK_BAREWORD ||
873 ( allow_quoted && kind == TK_QDSTRING ) ) {
874 res = LDAP_CALLOC(2,sizeof(char *));
876 *code = LDAP_SCHERR_OUTOFMEM;
884 *code = LDAP_SCHERR_BADNAME;
890 ldap_syntax_free( LDAP_SYNTAX * syn )
892 LDAP_FREE(syn->syn_oid);
893 LDAP_FREE(syn->syn_desc);
898 ldap_str2syntax( const char * s, int * code, const char ** errp )
908 *code = LDAP_SCHERR_EMPTY;
914 syn = LDAP_CALLOC(1,sizeof(LDAP_SYNTAX));
917 *code = LDAP_SCHERR_OUTOFMEM;
921 kind = get_token(&ss,&sval);
922 if ( kind != TK_LEFTPAREN ) {
923 *code = LDAP_SCHERR_NOLEFTPAREN;
924 ldap_syntax_free(syn);
929 syn->syn_oid = parse_numericoid(&ss,code,0);
930 if ( !syn->syn_oid ) {
932 ldap_syntax_free(syn);
938 * Beyond this point we will be liberal and accept the items
942 kind = get_token(&ss,&sval);
945 *code = LDAP_SCHERR_NORIGHTPAREN;
947 ldap_syntax_free(syn);
952 if ( !strcmp(sval,"DESC") ) {
954 *code = LDAP_SCHERR_DUPOPT;
956 ldap_syntax_free(syn);
961 kind = get_token(&ss,&sval);
962 if ( kind != TK_QDSTRING ) {
963 *code = LDAP_SCHERR_UNEXPTOKEN;
965 ldap_syntax_free(syn);
968 syn->syn_desc = sval;
970 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
971 /* Should be parse_qdstrings */
972 ssdummy = parse_qdescrs(&ss, code);
975 ldap_syntax_free(syn);
979 *code = LDAP_SCHERR_UNEXPTOKEN;
981 ldap_syntax_free(syn);
986 *code = LDAP_SCHERR_UNEXPTOKEN;
988 ldap_syntax_free(syn);
995 ldap_matchingrule_free( LDAP_MATCHING_RULE * mr )
997 LDAP_FREE(mr->mr_oid);
998 LDAP_VFREE(mr->mr_names);
999 LDAP_FREE(mr->mr_desc);
1000 LDAP_FREE(mr->mr_syntax_oid);
1004 LDAP_MATCHING_RULE *
1005 ldap_str2matchingrule( const char * s, int * code, const char ** errp )
1008 const char * ss = s;
1010 int be_liberal = 1; /* Future additional argument */
1013 int seen_obsolete = 0;
1014 int seen_syntax = 0;
1015 LDAP_MATCHING_RULE * mr;
1017 const char * savepos;
1020 *code = LDAP_SCHERR_EMPTY;
1026 mr = LDAP_CALLOC(1,sizeof(LDAP_MATCHING_RULE));
1029 *code = LDAP_SCHERR_OUTOFMEM;
1033 kind = get_token(&ss,&sval);
1034 if ( kind != TK_LEFTPAREN ) {
1035 *code = LDAP_SCHERR_NOLEFTPAREN;
1036 ldap_matchingrule_free(mr);
1042 mr->mr_oid = parse_numericoid(&ss,code,be_liberal);
1043 if ( !mr->mr_oid ) {
1047 kind = get_token(&ss,&sval);
1048 if ( kind == TK_BAREWORD ) {
1049 if ( !strcmp(sval, "NAME") ||
1050 !strcmp(sval, "DESC") ||
1051 !strcmp(sval, "OBSOLETE") ||
1052 !strcmp(sval, "SYNTAX") ||
1053 !strncmp(sval, "X-", 2) ) {
1054 /* Missing OID, backtrack */
1057 /* Non-numerical OID, ignore */
1062 ldap_matchingrule_free(mr);
1069 * Beyond this point we will be liberal and accept the items
1073 kind = get_token(&ss,&sval);
1076 *code = LDAP_SCHERR_NORIGHTPAREN;
1078 ldap_matchingrule_free(mr);
1083 if ( !strcmp(sval,"NAME") ) {
1085 *code = LDAP_SCHERR_DUPOPT;
1087 ldap_matchingrule_free(mr);
1091 mr->mr_names = parse_qdescrs(&ss,code);
1092 if ( !mr->mr_names ) {
1093 if ( *code != LDAP_SCHERR_OUTOFMEM )
1094 *code = LDAP_SCHERR_BADNAME;
1096 ldap_matchingrule_free(mr);
1099 } else if ( !strcmp(sval,"DESC") ) {
1101 *code = LDAP_SCHERR_DUPOPT;
1103 ldap_matchingrule_free(mr);
1108 kind = get_token(&ss,&sval);
1109 if ( kind != TK_QDSTRING ) {
1110 *code = LDAP_SCHERR_UNEXPTOKEN;
1112 ldap_matchingrule_free(mr);
1117 } else if ( !strcmp(sval,"OBSOLETE") ) {
1118 if ( seen_obsolete ) {
1119 *code = LDAP_SCHERR_DUPOPT;
1121 ldap_matchingrule_free(mr);
1125 mr->mr_obsolete = LDAP_SCHEMA_YES;
1127 } else if ( !strcmp(sval,"SYNTAX") ) {
1128 if ( seen_syntax ) {
1129 *code = LDAP_SCHERR_DUPOPT;
1131 ldap_matchingrule_free(mr);
1137 parse_numericoid(&ss,code,be_liberal);
1138 if ( !mr->mr_syntax_oid ) {
1140 ldap_matchingrule_free(mr);
1144 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1145 /* Should be parse_qdstrings */
1146 ssdummy = parse_qdescrs(&ss, code);
1149 ldap_matchingrule_free(mr);
1153 *code = LDAP_SCHERR_UNEXPTOKEN;
1155 ldap_matchingrule_free(mr);
1160 *code = LDAP_SCHERR_UNEXPTOKEN;
1162 ldap_matchingrule_free(mr);
1169 ldap_attributetype_free(LDAP_ATTRIBUTE_TYPE * at)
1171 LDAP_FREE(at->at_oid);
1172 LDAP_VFREE(at->at_names);
1173 LDAP_FREE(at->at_desc);
1174 LDAP_FREE(at->at_sup_oid);
1175 LDAP_FREE(at->at_equality_oid);
1176 LDAP_FREE(at->at_ordering_oid);
1177 LDAP_FREE(at->at_substr_oid);
1178 LDAP_FREE(at->at_syntax_oid);
1182 LDAP_ATTRIBUTE_TYPE *
1183 ldap_str2attributetype( const char * s, int * code, const char ** errp )
1186 const char * ss = s;
1188 int be_liberal = 1; /* Future additional argument */
1191 int seen_obsolete = 0;
1193 int seen_equality = 0;
1194 int seen_ordering = 0;
1195 int seen_substr = 0;
1196 int seen_syntax = 0;
1201 LDAP_ATTRIBUTE_TYPE * at;
1203 const char * savepos;
1206 *code = LDAP_SCHERR_EMPTY;
1212 at = LDAP_CALLOC(1,sizeof(LDAP_ATTRIBUTE_TYPE));
1215 *code = LDAP_SCHERR_OUTOFMEM;
1219 kind = get_token(&ss,&sval);
1220 if ( kind != TK_LEFTPAREN ) {
1221 *code = LDAP_SCHERR_NOLEFTPAREN;
1222 ldap_attributetype_free(at);
1227 * Definitions MUST begin with an OID in the numericoid format.
1228 * However, this routine is used by clients to parse the response
1229 * from servers and very well known servers will provide an OID
1230 * in the wrong format or even no OID at all. We do our best to
1231 * extract info from those servers.
1235 at->at_oid = parse_numericoid(&ss,code,0);
1236 if ( !at->at_oid ) {
1240 kind = get_token(&ss,&sval);
1241 if ( kind == TK_BAREWORD ) {
1242 if ( !strcmp(sval, "NAME") ||
1243 !strcmp(sval, "DESC") ||
1244 !strcmp(sval, "OBSOLETE") ||
1245 !strcmp(sval, "SUP") ||
1246 !strcmp(sval, "EQUALITY") ||
1247 !strcmp(sval, "ORDERING") ||
1248 !strcmp(sval, "SUBSTR") ||
1249 !strcmp(sval, "SYNTAX") ||
1250 !strcmp(sval, "SINGLE-VALUE") ||
1251 !strcmp(sval, "COLLECTIVE") ||
1252 !strcmp(sval, "NO-USER-MODIFICATION") ||
1253 !strcmp(sval, "USAGE") ||
1254 !strncmp(sval, "X-", 2) ) {
1255 /* Missing OID, backtrack */
1258 /* Non-numerical OID, ignore */
1263 ldap_attributetype_free(at);
1270 * Beyond this point we will be liberal and accept the items
1274 kind = get_token(&ss,&sval);
1277 *code = LDAP_SCHERR_NORIGHTPAREN;
1279 ldap_attributetype_free(at);
1284 if ( !strcmp(sval,"NAME") ) {
1286 *code = LDAP_SCHERR_DUPOPT;
1288 ldap_attributetype_free(at);
1292 at->at_names = parse_qdescrs(&ss,code);
1293 if ( !at->at_names ) {
1294 if ( *code != LDAP_SCHERR_OUTOFMEM )
1295 *code = LDAP_SCHERR_BADNAME;
1297 ldap_attributetype_free(at);
1300 } else if ( !strcmp(sval,"DESC") ) {
1302 *code = LDAP_SCHERR_DUPOPT;
1304 ldap_attributetype_free(at);
1309 kind = get_token(&ss,&sval);
1310 if ( kind != TK_QDSTRING ) {
1311 *code = LDAP_SCHERR_UNEXPTOKEN;
1313 ldap_attributetype_free(at);
1318 } else if ( !strcmp(sval,"OBSOLETE") ) {
1319 if ( seen_obsolete ) {
1320 *code = LDAP_SCHERR_DUPOPT;
1322 ldap_attributetype_free(at);
1326 at->at_obsolete = LDAP_SCHEMA_YES;
1328 } else if ( !strcmp(sval,"SUP") ) {
1330 *code = LDAP_SCHERR_DUPOPT;
1332 ldap_attributetype_free(at);
1336 at->at_sup_oid = parse_woid(&ss,code);
1337 if ( !at->at_sup_oid ) {
1339 ldap_attributetype_free(at);
1342 } else if ( !strcmp(sval,"EQUALITY") ) {
1343 if ( seen_equality ) {
1344 *code = LDAP_SCHERR_DUPOPT;
1346 ldap_attributetype_free(at);
1350 at->at_equality_oid = parse_woid(&ss,code);
1351 if ( !at->at_equality_oid ) {
1353 ldap_attributetype_free(at);
1356 } else if ( !strcmp(sval,"ORDERING") ) {
1357 if ( seen_ordering ) {
1358 *code = LDAP_SCHERR_DUPOPT;
1360 ldap_attributetype_free(at);
1364 at->at_ordering_oid = parse_woid(&ss,code);
1365 if ( !at->at_ordering_oid ) {
1367 ldap_attributetype_free(at);
1370 } else if ( !strcmp(sval,"SUBSTR") ) {
1371 if ( seen_substr ) {
1372 *code = LDAP_SCHERR_DUPOPT;
1374 ldap_attributetype_free(at);
1378 at->at_substr_oid = parse_woid(&ss,code);
1379 if ( !at->at_substr_oid ) {
1381 ldap_attributetype_free(at);
1384 } else if ( !strcmp(sval,"SYNTAX") ) {
1385 if ( seen_syntax ) {
1386 *code = LDAP_SCHERR_DUPOPT;
1388 ldap_attributetype_free(at);
1398 if ( !at->at_syntax_oid ) {
1400 ldap_attributetype_free(at);
1404 } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
1405 if ( at->at_single_value ) {
1406 *code = LDAP_SCHERR_DUPOPT;
1408 ldap_attributetype_free(at);
1411 at->at_single_value = LDAP_SCHEMA_YES;
1413 } else if ( !strcmp(sval,"COLLECTIVE") ) {
1414 if ( at->at_collective ) {
1415 *code = LDAP_SCHERR_DUPOPT;
1417 ldap_attributetype_free(at);
1420 at->at_collective = LDAP_SCHEMA_YES;
1422 } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
1423 if ( at->at_no_user_mod ) {
1424 *code = LDAP_SCHERR_DUPOPT;
1426 ldap_attributetype_free(at);
1429 at->at_no_user_mod = LDAP_SCHEMA_YES;
1431 } else if ( !strcmp(sval,"USAGE") ) {
1433 *code = LDAP_SCHERR_DUPOPT;
1435 ldap_attributetype_free(at);
1440 kind = get_token(&ss,&sval);
1441 if ( kind != TK_BAREWORD ) {
1442 *code = LDAP_SCHERR_UNEXPTOKEN;
1444 ldap_attributetype_free(at);
1447 if ( !strcasecmp(sval,"userApplications") )
1449 LDAP_SCHEMA_USER_APPLICATIONS;
1450 else if ( !strcasecmp(sval,"directoryOperation") )
1452 LDAP_SCHEMA_DIRECTORY_OPERATION;
1453 else if ( !strcasecmp(sval,"distributedOperation") )
1455 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
1456 else if ( !strcasecmp(sval,"dSAOperation") )
1458 LDAP_SCHEMA_DSA_OPERATION;
1460 *code = LDAP_SCHERR_UNEXPTOKEN;
1462 ldap_attributetype_free(at);
1466 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1467 /* Should be parse_qdstrings */
1468 ssdummy = parse_qdescrs(&ss, code);
1471 ldap_attributetype_free(at);
1475 *code = LDAP_SCHERR_UNEXPTOKEN;
1477 ldap_attributetype_free(at);
1482 *code = LDAP_SCHERR_UNEXPTOKEN;
1484 ldap_attributetype_free(at);
1491 ldap_objectclass_free(LDAP_OBJECT_CLASS * oc)
1493 LDAP_FREE(oc->oc_oid);
1494 LDAP_VFREE(oc->oc_names);
1495 LDAP_FREE(oc->oc_desc);
1496 LDAP_VFREE(oc->oc_sup_oids);
1497 LDAP_VFREE(oc->oc_at_oids_must);
1498 LDAP_VFREE(oc->oc_at_oids_may);
1503 ldap_str2objectclass( const char * s, int * code, const char ** errp )
1506 const char * ss = s;
1508 int be_liberal = 1; /* Future additional argument */
1511 int seen_obsolete = 0;
1516 LDAP_OBJECT_CLASS * oc;
1518 const char * savepos;
1521 *code = LDAP_SCHERR_EMPTY;
1527 oc = LDAP_CALLOC(1,sizeof(LDAP_OBJECT_CLASS));
1530 *code = LDAP_SCHERR_OUTOFMEM;
1534 kind = get_token(&ss,&sval);
1535 if ( kind != TK_LEFTPAREN ) {
1536 *code = LDAP_SCHERR_NOLEFTPAREN;
1537 ldap_objectclass_free(oc);
1542 * Definitions MUST begin with an OID in the numericoid format.
1543 * However, this routine is used by clients to parse the response
1544 * from servers and very well known servers will provide an OID
1545 * in the wrong format or even no OID at all. We do our best to
1546 * extract info from those servers.
1550 oc->oc_oid = parse_numericoid(&ss,code,0);
1551 if ( !oc->oc_oid ) {
1555 kind = get_token(&ss,&sval);
1556 if ( kind == TK_BAREWORD ) {
1557 if ( !strcmp(sval, "NAME") ||
1558 !strcmp(sval, "DESC") ||
1559 !strcmp(sval, "OBSOLETE") ||
1560 !strcmp(sval, "SUP") ||
1561 !strcmp(sval, "ABSTRACT") ||
1562 !strcmp(sval, "STRUCTURAL") ||
1563 !strcmp(sval, "AUXILIARY") ||
1564 !strcmp(sval, "MUST") ||
1565 !strncmp(sval, "X-", 2) ) {
1566 /* Missing OID, backtrack */
1569 /* Non-numerical OID, ignore */
1574 ldap_objectclass_free(oc);
1581 * Beyond this point we will be liberal an accept the items
1585 kind = get_token(&ss,&sval);
1588 *code = LDAP_SCHERR_NORIGHTPAREN;
1590 ldap_objectclass_free(oc);
1595 if ( !strcmp(sval,"NAME") ) {
1597 *code = LDAP_SCHERR_DUPOPT;
1599 ldap_objectclass_free(oc);
1603 oc->oc_names = parse_qdescrs(&ss,code);
1604 if ( !oc->oc_names ) {
1605 if ( *code != LDAP_SCHERR_OUTOFMEM )
1606 *code = LDAP_SCHERR_BADNAME;
1608 ldap_objectclass_free(oc);
1611 } else if ( !strcmp(sval,"DESC") ) {
1613 *code = LDAP_SCHERR_DUPOPT;
1615 ldap_objectclass_free(oc);
1620 kind = get_token(&ss,&sval);
1621 if ( kind != TK_QDSTRING ) {
1622 *code = LDAP_SCHERR_UNEXPTOKEN;
1624 ldap_objectclass_free(oc);
1629 } else if ( !strcmp(sval,"OBSOLETE") ) {
1630 if ( seen_obsolete ) {
1631 *code = LDAP_SCHERR_DUPOPT;
1633 ldap_objectclass_free(oc);
1637 oc->oc_obsolete = LDAP_SCHEMA_YES;
1639 } else if ( !strcmp(sval,"SUP") ) {
1641 *code = LDAP_SCHERR_DUPOPT;
1643 ldap_objectclass_free(oc);
1647 oc->oc_sup_oids = parse_oids(&ss,
1650 if ( !oc->oc_sup_oids ) {
1652 ldap_objectclass_free(oc);
1655 } else if ( !strcmp(sval,"ABSTRACT") ) {
1657 *code = LDAP_SCHERR_DUPOPT;
1659 ldap_objectclass_free(oc);
1663 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
1665 } else if ( !strcmp(sval,"STRUCTURAL") ) {
1667 *code = LDAP_SCHERR_DUPOPT;
1669 ldap_objectclass_free(oc);
1673 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
1675 } else if ( !strcmp(sval,"AUXILIARY") ) {
1677 *code = LDAP_SCHERR_DUPOPT;
1679 ldap_objectclass_free(oc);
1683 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
1685 } else if ( !strcmp(sval,"MUST") ) {
1687 *code = LDAP_SCHERR_DUPOPT;
1689 ldap_objectclass_free(oc);
1693 oc->oc_at_oids_must = parse_oids(&ss,code,0);
1694 if ( !oc->oc_at_oids_must ) {
1696 ldap_objectclass_free(oc);
1700 } else if ( !strcmp(sval,"MAY") ) {
1702 *code = LDAP_SCHERR_DUPOPT;
1704 ldap_objectclass_free(oc);
1708 oc->oc_at_oids_may = parse_oids(&ss,code,0);
1709 if ( !oc->oc_at_oids_may ) {
1711 ldap_objectclass_free(oc);
1715 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1716 /* Should be parse_qdstrings */
1717 ssdummy = parse_qdescrs(&ss, code);
1720 ldap_objectclass_free(oc);
1724 *code = LDAP_SCHERR_UNEXPTOKEN;
1726 ldap_objectclass_free(oc);
1731 *code = LDAP_SCHERR_UNEXPTOKEN;
1733 ldap_objectclass_free(oc);
1739 static char *err2text[] = {
1743 "Missing opening parenthesis",
1744 "Missing closing parenthesis",
1750 "Unexpected end of data"
1754 ldap_scherr2str(int code)
1756 if ( code < 1 || code >= (sizeof(err2text)/sizeof(char *)) ) {
1757 return "Unknown error";
1759 return err2text[code];