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( const 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_matchingrule2str( const LDAP_MATCHING_RULE * mr )
270 ss = new_safe_string(256);
274 print_literal(ss,"(");
277 print_numericoid(ss, mr->mr_oid);
280 if ( mr->mr_names ) {
281 print_literal(ss,"NAME");
282 print_qdescrs(ss,mr->mr_names);
286 print_literal(ss,"DESC");
287 print_qdstring(ss,mr->mr_desc);
290 if ( mr->mr_obsolete == LDAP_SCHEMA_YES ) {
291 print_literal(ss, "OBSOLETE");
295 if ( mr->mr_syntax_oid ) {
296 print_literal(ss,"SYNTAX");
298 print_literal(ss, mr->mr_syntax_oid);
303 print_literal(ss,")");
305 retstring = LDAP_STRDUP(safe_string_val(ss));
306 safe_string_free(ss);
311 ldap_objectclass2str( const LDAP_OBJECT_CLASS * oc )
316 ss = new_safe_string(256);
320 print_literal(ss,"(");
323 print_numericoid(ss, oc->oc_oid);
326 if ( oc->oc_names ) {
327 print_literal(ss,"NAME");
328 print_qdescrs(ss,oc->oc_names);
332 print_literal(ss,"DESC");
333 print_qdstring(ss,oc->oc_desc);
336 if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) {
337 print_literal(ss, "OBSOLETE");
341 if ( oc->oc_sup_oids ) {
342 print_literal(ss,"SUP");
344 print_oids(ss,oc->oc_sup_oids);
348 switch (oc->oc_kind) {
349 case LDAP_SCHEMA_ABSTRACT:
350 print_literal(ss,"ABSTRACT");
352 case LDAP_SCHEMA_STRUCTURAL:
353 print_literal(ss,"STRUCTURAL");
355 case LDAP_SCHEMA_AUXILIARY:
356 print_literal(ss,"AUXILIARY");
359 print_literal(ss,"KIND-UNKNOWN");
364 if ( oc->oc_at_oids_must ) {
365 print_literal(ss,"MUST");
367 print_oids(ss,oc->oc_at_oids_must);
371 if ( oc->oc_at_oids_may ) {
372 print_literal(ss,"MAY");
374 print_oids(ss,oc->oc_at_oids_may);
379 print_literal(ss,")");
381 retstring = LDAP_STRDUP(safe_string_val(ss));
382 safe_string_free(ss);
387 ldap_attributetype2str( const LDAP_ATTRIBUTE_TYPE * at )
392 ss = new_safe_string(256);
396 print_literal(ss,"(");
399 print_numericoid(ss, at->at_oid);
402 if ( at->at_names ) {
403 print_literal(ss,"NAME");
404 print_qdescrs(ss,at->at_names);
408 print_literal(ss,"DESC");
409 print_qdstring(ss,at->at_desc);
412 if ( at->at_obsolete == LDAP_SCHEMA_YES ) {
413 print_literal(ss, "OBSOLETE");
417 if ( at->at_sup_oid ) {
418 print_literal(ss,"SUP");
419 print_woid(ss,at->at_sup_oid);
422 if ( at->at_equality_oid ) {
423 print_literal(ss,"EQUALITY");
424 print_woid(ss,at->at_equality_oid);
427 if ( at->at_ordering_oid ) {
428 print_literal(ss,"ORDERING");
429 print_woid(ss,at->at_ordering_oid);
432 if ( at->at_substr_oid ) {
433 print_literal(ss,"SUBSTR");
434 print_woid(ss,at->at_substr_oid);
437 if ( at->at_syntax_oid ) {
438 print_literal(ss,"SYNTAX");
440 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
444 if ( at->at_single_value == LDAP_SCHEMA_YES ) {
445 print_literal(ss,"SINGLE-VALUE");
449 if ( at->at_collective == LDAP_SCHEMA_YES ) {
450 print_literal(ss,"COLLECTIVE");
454 if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
455 print_literal(ss,"NO-USER-MODIFICATION");
459 if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
460 print_literal(ss,"USAGE");
462 switch (at->at_usage) {
463 case LDAP_SCHEMA_DIRECTORY_OPERATION:
464 print_literal(ss,"directoryOperation");
466 case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
467 print_literal(ss,"distributedOperation");
469 case LDAP_SCHEMA_DSA_OPERATION:
470 print_literal(ss,"dSAOperation");
473 print_literal(ss,"UNKNOWN");
479 print_literal(ss,")");
481 retstring = LDAP_STRDUP(safe_string_val(ss));
482 safe_string_free(ss);
487 * Now come the parsers. There is one parser for each entity type:
488 * objectclasses, attributetypes, etc.
490 * Each of them is written as a recursive-descent parser, except that
491 * none of them is really recursive. But the idea is kept: there
492 * is one routine per non-terminal that eithers gobbles lexical tokens
493 * or calls lower-level routines, etc.
495 * The scanner is implemented in the routine get_token. Actually,
496 * get_token is more than a scanner and will return tokens that are
497 * in fact non-terminals in the grammar. So you can see the whole
498 * approach as the combination of a low-level bottom-up recognizer
499 * combined with a scanner and a number of top-down parsers. Or just
500 * consider that the real grammars recognized by the parsers are not
501 * those of the standards. As a matter of fact, our parsers are more
502 * liberal than the spec when there is no ambiguity.
504 * The difference is pretty academic (modulo bugs or incorrect
505 * interpretation of the specs).
508 #define TK_NOENDQUOTE -2
509 #define TK_OUTOFMEM -1
511 #define TK_UNEXPCHAR 1
512 #define TK_BAREWORD 2
513 #define TK_QDSTRING 3
514 #define TK_LEFTPAREN 4
515 #define TK_RIGHTPAREN 5
517 #define TK_QDESCR TK_QDSTRING
525 get_token(const char ** sp, char ** token_val)
542 kind = TK_RIGHTPAREN;
553 while ( **sp != '\'' && **sp != '\0' )
555 if ( **sp == '\'' ) {
557 res = LDAP_MALLOC(q-p+1);
567 kind = TK_NOENDQUOTE;
573 while ( !isspace(**sp) && **sp != '\0' )
576 res = LDAP_MALLOC(q-p+1);
585 /* kind = TK_UNEXPCHAR; */
592 /* Gobble optional whitespace */
594 parse_whsp(const char **sp)
596 while (isspace(**sp))
601 * General note for all parsers: to guarantee the algorithm halts they
602 * must always advance the pointer even when an error is found. For
603 * this one is not that important since an error here is fatal at the
604 * upper layers, but it is a simple strategy that will not get in
608 /* Parse a sequence of dot-separated decimal strings */
610 parse_numericoid(const char **sp, int *code, const int allow_quoted)
613 const char * start = *sp;
617 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
618 if ( allow_quoted && **sp == '\'' ) {
623 /* Each iteration of this loop gets one decimal string */
625 if ( !isdigit(**sp) ) {
627 * Initial char is not a digit or char after dot is
630 *code = LDAP_SCHERR_NODIGIT;
634 while ( isdigit(**sp) )
638 /* Otherwise, gobble the dot and loop again */
641 /* Now *sp points at the char past the numericoid. Perfect. */
643 res = LDAP_MALLOC(len+1);
645 *code = LDAP_SCHERR_OUTOFMEM;
648 strncpy(res,start,len);
650 if ( allow_quoted && quoted ) {
651 if ( **sp == '\'' ) {
654 *code = LDAP_SCHERR_UNEXPTOKEN;
662 /* Parse a qdescr or a list of them enclosed in () */
664 parse_qdescrs(const char **sp, int *code)
674 kind = get_token(sp,&sval);
675 if ( kind == TK_LEFTPAREN ) {
676 /* Let's presume there will be at least 2 entries */
678 res = LDAP_CALLOC(3,sizeof(char *));
680 *code = LDAP_SCHERR_OUTOFMEM;
686 kind = get_token(sp,&sval);
687 if ( kind == TK_RIGHTPAREN )
689 if ( kind == TK_QDESCR ) {
690 if ( pos == size-2 ) {
692 res1 = LDAP_REALLOC(res,size*sizeof(char *));
695 *code = LDAP_SCHERR_OUTOFMEM;
705 *code = LDAP_SCHERR_UNEXPTOKEN;
712 } else if ( kind == TK_QDESCR ) {
713 res = LDAP_CALLOC(2,sizeof(char *));
715 *code = LDAP_SCHERR_OUTOFMEM;
723 *code = LDAP_SCHERR_BADNAME;
730 parse_woid(const char **sp, int *code)
736 kind = get_token(sp, &sval);
737 if ( kind != TK_BAREWORD ) {
738 *code = LDAP_SCHERR_UNEXPTOKEN;
745 /* Parse a noidlen */
747 parse_noidlen(const char **sp, int *code, int *len, int allow_quoted)
754 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
755 if ( allow_quoted && **sp == '\'' ) {
759 sval = parse_numericoid(sp, code, 0);
766 while ( isdigit(**sp) )
769 *code = LDAP_SCHERR_UNEXPTOKEN;
775 if ( allow_quoted && quoted ) {
776 if ( **sp == '\'' ) {
779 *code = LDAP_SCHERR_UNEXPTOKEN;
788 * Next routine will accept a qdstring in place of an oid if
789 * allow_quoted is set. This is necessary to interoperate with
790 * Netscape Directory server that will improperly quote each oid (at
791 * least those of the descr kind) in the SUP clause.
794 /* Parse a woid or a $-separated list of them enclosed in () */
796 parse_oids(const char **sp, int *code, const int allow_quoted)
806 * Strictly speaking, doing this here accepts whsp before the
807 * ( at the begining of an oidlist, but this is harmless. Also,
808 * we are very liberal in what we accept as an OID. Maybe
812 kind = get_token(sp,&sval);
813 if ( kind == TK_LEFTPAREN ) {
814 /* Let's presume there will be at least 2 entries */
816 res = LDAP_CALLOC(3,sizeof(char *));
818 *code = LDAP_SCHERR_OUTOFMEM;
823 kind = get_token(sp,&sval);
824 if ( kind == TK_BAREWORD ||
825 ( allow_quoted && kind == TK_QDSTRING ) ) {
829 *code = LDAP_SCHERR_UNEXPTOKEN;
835 kind = get_token(sp,&sval);
836 if ( kind == TK_RIGHTPAREN )
838 if ( kind == TK_DOLLAR ) {
840 kind = get_token(sp,&sval);
841 if ( kind == TK_BAREWORD ||
843 kind == TK_QDSTRING ) ) {
844 if ( pos == size-2 ) {
846 res1 = LDAP_REALLOC(res,size*sizeof(char *));
849 *code = LDAP_SCHERR_OUTOFMEM;
857 *code = LDAP_SCHERR_UNEXPTOKEN;
863 *code = LDAP_SCHERR_UNEXPTOKEN;
871 } else if ( kind == TK_BAREWORD ||
872 ( allow_quoted && kind == TK_QDSTRING ) ) {
873 res = LDAP_CALLOC(2,sizeof(char *));
875 *code = LDAP_SCHERR_OUTOFMEM;
883 *code = LDAP_SCHERR_BADNAME;
889 ldap_syntax_free( LDAP_SYNTAX * syn )
891 LDAP_FREE(syn->syn_oid);
892 LDAP_FREE(syn->syn_desc);
897 ldap_str2syntax( const char * s, int * code, const char ** errp )
907 *code = LDAP_SCHERR_EMPTY;
913 syn = LDAP_CALLOC(1,sizeof(LDAP_SYNTAX));
916 *code = LDAP_SCHERR_OUTOFMEM;
920 kind = get_token(&ss,&sval);
921 if ( kind != TK_LEFTPAREN ) {
922 *code = LDAP_SCHERR_NOLEFTPAREN;
923 ldap_syntax_free(syn);
928 syn->syn_oid = parse_numericoid(&ss,code,0);
929 if ( !syn->syn_oid ) {
931 ldap_syntax_free(syn);
937 * Beyond this point we will be liberal and accept the items
941 kind = get_token(&ss,&sval);
944 *code = LDAP_SCHERR_NORIGHTPAREN;
946 ldap_syntax_free(syn);
951 if ( !strcmp(sval,"DESC") ) {
953 *code = LDAP_SCHERR_DUPOPT;
955 ldap_syntax_free(syn);
960 kind = get_token(&ss,&sval);
961 if ( kind != TK_QDSTRING ) {
962 *code = LDAP_SCHERR_UNEXPTOKEN;
964 ldap_syntax_free(syn);
967 syn->syn_desc = sval;
969 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
970 /* Should be parse_qdstrings */
971 ssdummy = parse_qdescrs(&ss, code);
974 ldap_syntax_free(syn);
978 *code = LDAP_SCHERR_UNEXPTOKEN;
980 ldap_syntax_free(syn);
985 *code = LDAP_SCHERR_UNEXPTOKEN;
987 ldap_syntax_free(syn);
994 ldap_matchingrule_free( LDAP_MATCHING_RULE * mr )
996 LDAP_FREE(mr->mr_oid);
997 LDAP_VFREE(mr->mr_names);
998 LDAP_FREE(mr->mr_desc);
999 LDAP_FREE(mr->mr_syntax_oid);
1003 LDAP_MATCHING_RULE *
1004 ldap_str2matchingrule( const char * s, int * code, const char ** errp )
1007 const char * ss = s;
1009 int be_liberal = 1; /* Future additional argument */
1012 int seen_obsolete = 0;
1013 int seen_syntax = 0;
1014 LDAP_MATCHING_RULE * mr;
1016 const char * savepos;
1019 *code = LDAP_SCHERR_EMPTY;
1025 mr = LDAP_CALLOC(1,sizeof(LDAP_MATCHING_RULE));
1028 *code = LDAP_SCHERR_OUTOFMEM;
1032 kind = get_token(&ss,&sval);
1033 if ( kind != TK_LEFTPAREN ) {
1034 *code = LDAP_SCHERR_NOLEFTPAREN;
1035 ldap_matchingrule_free(mr);
1041 mr->mr_oid = parse_numericoid(&ss,code,be_liberal);
1042 if ( !mr->mr_oid ) {
1046 kind = get_token(&ss,&sval);
1047 if ( kind == TK_BAREWORD ) {
1048 if ( !strcmp(sval, "NAME") ||
1049 !strcmp(sval, "DESC") ||
1050 !strcmp(sval, "OBSOLETE") ||
1051 !strcmp(sval, "SYNTAX") ||
1052 !strncmp(sval, "X-", 2) ) {
1053 /* Missing OID, backtrack */
1056 /* Non-numerical OID, ignore */
1061 ldap_matchingrule_free(mr);
1068 * Beyond this point we will be liberal and accept the items
1072 kind = get_token(&ss,&sval);
1075 *code = LDAP_SCHERR_NORIGHTPAREN;
1077 ldap_matchingrule_free(mr);
1082 if ( !strcmp(sval,"NAME") ) {
1084 *code = LDAP_SCHERR_DUPOPT;
1086 ldap_matchingrule_free(mr);
1090 mr->mr_names = parse_qdescrs(&ss,code);
1091 if ( !mr->mr_names ) {
1092 if ( *code != LDAP_SCHERR_OUTOFMEM )
1093 *code = LDAP_SCHERR_BADNAME;
1095 ldap_matchingrule_free(mr);
1098 } else if ( !strcmp(sval,"DESC") ) {
1100 *code = LDAP_SCHERR_DUPOPT;
1102 ldap_matchingrule_free(mr);
1107 kind = get_token(&ss,&sval);
1108 if ( kind != TK_QDSTRING ) {
1109 *code = LDAP_SCHERR_UNEXPTOKEN;
1111 ldap_matchingrule_free(mr);
1116 } else if ( !strcmp(sval,"OBSOLETE") ) {
1117 if ( seen_obsolete ) {
1118 *code = LDAP_SCHERR_DUPOPT;
1120 ldap_matchingrule_free(mr);
1124 mr->mr_obsolete = LDAP_SCHEMA_YES;
1126 } else if ( !strcmp(sval,"SYNTAX") ) {
1127 if ( seen_syntax ) {
1128 *code = LDAP_SCHERR_DUPOPT;
1130 ldap_matchingrule_free(mr);
1136 parse_numericoid(&ss,code,be_liberal);
1137 if ( !mr->mr_syntax_oid ) {
1139 ldap_matchingrule_free(mr);
1143 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1144 /* Should be parse_qdstrings */
1145 ssdummy = parse_qdescrs(&ss, code);
1148 ldap_matchingrule_free(mr);
1152 *code = LDAP_SCHERR_UNEXPTOKEN;
1154 ldap_matchingrule_free(mr);
1159 *code = LDAP_SCHERR_UNEXPTOKEN;
1161 ldap_matchingrule_free(mr);
1168 ldap_attributetype_free(LDAP_ATTRIBUTE_TYPE * at)
1170 LDAP_FREE(at->at_oid);
1171 LDAP_VFREE(at->at_names);
1172 LDAP_FREE(at->at_desc);
1173 LDAP_FREE(at->at_sup_oid);
1174 LDAP_FREE(at->at_equality_oid);
1175 LDAP_FREE(at->at_ordering_oid);
1176 LDAP_FREE(at->at_substr_oid);
1177 LDAP_FREE(at->at_syntax_oid);
1181 LDAP_ATTRIBUTE_TYPE *
1182 ldap_str2attributetype( const char * s, int * code, const char ** errp )
1185 const char * ss = s;
1187 int be_liberal = 1; /* Future additional argument */
1190 int seen_obsolete = 0;
1192 int seen_equality = 0;
1193 int seen_ordering = 0;
1194 int seen_substr = 0;
1195 int seen_syntax = 0;
1200 LDAP_ATTRIBUTE_TYPE * at;
1202 const char * savepos;
1205 *code = LDAP_SCHERR_EMPTY;
1211 at = LDAP_CALLOC(1,sizeof(LDAP_ATTRIBUTE_TYPE));
1214 *code = LDAP_SCHERR_OUTOFMEM;
1218 kind = get_token(&ss,&sval);
1219 if ( kind != TK_LEFTPAREN ) {
1220 *code = LDAP_SCHERR_NOLEFTPAREN;
1221 ldap_attributetype_free(at);
1226 * Definitions MUST begin with an OID in the numericoid format.
1227 * However, this routine is used by clients to parse the response
1228 * from servers and very well known servers will provide an OID
1229 * in the wrong format or even no OID at all. We do our best to
1230 * extract info from those servers.
1234 at->at_oid = parse_numericoid(&ss,code,0);
1235 if ( !at->at_oid ) {
1239 kind = get_token(&ss,&sval);
1240 if ( kind == TK_BAREWORD ) {
1241 if ( !strcmp(sval, "NAME") ||
1242 !strcmp(sval, "DESC") ||
1243 !strcmp(sval, "OBSOLETE") ||
1244 !strcmp(sval, "SUP") ||
1245 !strcmp(sval, "EQUALITY") ||
1246 !strcmp(sval, "ORDERING") ||
1247 !strcmp(sval, "SUBSTR") ||
1248 !strcmp(sval, "SYNTAX") ||
1249 !strcmp(sval, "SINGLE-VALUE") ||
1250 !strcmp(sval, "COLLECTIVE") ||
1251 !strcmp(sval, "NO-USER-MODIFICATION") ||
1252 !strcmp(sval, "USAGE") ||
1253 !strncmp(sval, "X-", 2) ) {
1254 /* Missing OID, backtrack */
1257 /* Non-numerical OID, ignore */
1262 ldap_attributetype_free(at);
1269 * Beyond this point we will be liberal and accept the items
1273 kind = get_token(&ss,&sval);
1276 *code = LDAP_SCHERR_NORIGHTPAREN;
1278 ldap_attributetype_free(at);
1283 if ( !strcmp(sval,"NAME") ) {
1285 *code = LDAP_SCHERR_DUPOPT;
1287 ldap_attributetype_free(at);
1291 at->at_names = parse_qdescrs(&ss,code);
1292 if ( !at->at_names ) {
1293 if ( *code != LDAP_SCHERR_OUTOFMEM )
1294 *code = LDAP_SCHERR_BADNAME;
1296 ldap_attributetype_free(at);
1299 } else if ( !strcmp(sval,"DESC") ) {
1301 *code = LDAP_SCHERR_DUPOPT;
1303 ldap_attributetype_free(at);
1308 kind = get_token(&ss,&sval);
1309 if ( kind != TK_QDSTRING ) {
1310 *code = LDAP_SCHERR_UNEXPTOKEN;
1312 ldap_attributetype_free(at);
1317 } else if ( !strcmp(sval,"OBSOLETE") ) {
1318 if ( seen_obsolete ) {
1319 *code = LDAP_SCHERR_DUPOPT;
1321 ldap_attributetype_free(at);
1325 at->at_obsolete = LDAP_SCHEMA_YES;
1327 } else if ( !strcmp(sval,"SUP") ) {
1329 *code = LDAP_SCHERR_DUPOPT;
1331 ldap_attributetype_free(at);
1335 at->at_sup_oid = parse_woid(&ss,code);
1336 if ( !at->at_sup_oid ) {
1338 ldap_attributetype_free(at);
1341 } else if ( !strcmp(sval,"EQUALITY") ) {
1342 if ( seen_equality ) {
1343 *code = LDAP_SCHERR_DUPOPT;
1345 ldap_attributetype_free(at);
1349 at->at_equality_oid = parse_woid(&ss,code);
1350 if ( !at->at_equality_oid ) {
1352 ldap_attributetype_free(at);
1355 } else if ( !strcmp(sval,"ORDERING") ) {
1356 if ( seen_ordering ) {
1357 *code = LDAP_SCHERR_DUPOPT;
1359 ldap_attributetype_free(at);
1363 at->at_ordering_oid = parse_woid(&ss,code);
1364 if ( !at->at_ordering_oid ) {
1366 ldap_attributetype_free(at);
1369 } else if ( !strcmp(sval,"SUBSTR") ) {
1370 if ( seen_substr ) {
1371 *code = LDAP_SCHERR_DUPOPT;
1373 ldap_attributetype_free(at);
1377 at->at_substr_oid = parse_woid(&ss,code);
1378 if ( !at->at_substr_oid ) {
1380 ldap_attributetype_free(at);
1383 } else if ( !strcmp(sval,"SYNTAX") ) {
1384 if ( seen_syntax ) {
1385 *code = LDAP_SCHERR_DUPOPT;
1387 ldap_attributetype_free(at);
1397 if ( !at->at_syntax_oid ) {
1399 ldap_attributetype_free(at);
1403 } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
1404 if ( at->at_single_value ) {
1405 *code = LDAP_SCHERR_DUPOPT;
1407 ldap_attributetype_free(at);
1410 at->at_single_value = LDAP_SCHEMA_YES;
1412 } else if ( !strcmp(sval,"COLLECTIVE") ) {
1413 if ( at->at_collective ) {
1414 *code = LDAP_SCHERR_DUPOPT;
1416 ldap_attributetype_free(at);
1419 at->at_collective = LDAP_SCHEMA_YES;
1421 } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
1422 if ( at->at_no_user_mod ) {
1423 *code = LDAP_SCHERR_DUPOPT;
1425 ldap_attributetype_free(at);
1428 at->at_no_user_mod = LDAP_SCHEMA_YES;
1430 } else if ( !strcmp(sval,"USAGE") ) {
1432 *code = LDAP_SCHERR_DUPOPT;
1434 ldap_attributetype_free(at);
1439 kind = get_token(&ss,&sval);
1440 if ( kind != TK_BAREWORD ) {
1441 *code = LDAP_SCHERR_UNEXPTOKEN;
1443 ldap_attributetype_free(at);
1446 if ( !strcasecmp(sval,"userApplications") )
1448 LDAP_SCHEMA_USER_APPLICATIONS;
1449 else if ( !strcasecmp(sval,"directoryOperation") )
1451 LDAP_SCHEMA_DIRECTORY_OPERATION;
1452 else if ( !strcasecmp(sval,"distributedOperation") )
1454 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
1455 else if ( !strcasecmp(sval,"dSAOperation") )
1457 LDAP_SCHEMA_DSA_OPERATION;
1459 *code = LDAP_SCHERR_UNEXPTOKEN;
1461 ldap_attributetype_free(at);
1465 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1466 /* Should be parse_qdstrings */
1467 ssdummy = parse_qdescrs(&ss, code);
1470 ldap_attributetype_free(at);
1474 *code = LDAP_SCHERR_UNEXPTOKEN;
1476 ldap_attributetype_free(at);
1481 *code = LDAP_SCHERR_UNEXPTOKEN;
1483 ldap_attributetype_free(at);
1490 ldap_objectclass_free(LDAP_OBJECT_CLASS * oc)
1492 LDAP_FREE(oc->oc_oid);
1493 LDAP_VFREE(oc->oc_names);
1494 LDAP_FREE(oc->oc_desc);
1495 LDAP_VFREE(oc->oc_sup_oids);
1496 LDAP_VFREE(oc->oc_at_oids_must);
1497 LDAP_VFREE(oc->oc_at_oids_may);
1502 ldap_str2objectclass( const char * s, int * code, const char ** errp )
1505 const char * ss = s;
1507 int be_liberal = 1; /* Future additional argument */
1510 int seen_obsolete = 0;
1515 LDAP_OBJECT_CLASS * oc;
1517 const char * savepos;
1520 *code = LDAP_SCHERR_EMPTY;
1526 oc = LDAP_CALLOC(1,sizeof(LDAP_OBJECT_CLASS));
1529 *code = LDAP_SCHERR_OUTOFMEM;
1533 kind = get_token(&ss,&sval);
1534 if ( kind != TK_LEFTPAREN ) {
1535 *code = LDAP_SCHERR_NOLEFTPAREN;
1536 ldap_objectclass_free(oc);
1541 * Definitions MUST begin with an OID in the numericoid format.
1542 * However, this routine is used by clients to parse the response
1543 * from servers and very well known servers will provide an OID
1544 * in the wrong format or even no OID at all. We do our best to
1545 * extract info from those servers.
1549 oc->oc_oid = parse_numericoid(&ss,code,0);
1550 if ( !oc->oc_oid ) {
1554 kind = get_token(&ss,&sval);
1555 if ( kind == TK_BAREWORD ) {
1556 if ( !strcmp(sval, "NAME") ||
1557 !strcmp(sval, "DESC") ||
1558 !strcmp(sval, "OBSOLETE") ||
1559 !strcmp(sval, "SUP") ||
1560 !strcmp(sval, "ABSTRACT") ||
1561 !strcmp(sval, "STRUCTURAL") ||
1562 !strcmp(sval, "AUXILIARY") ||
1563 !strcmp(sval, "MUST") ||
1564 !strncmp(sval, "X-", 2) ) {
1565 /* Missing OID, backtrack */
1568 /* Non-numerical OID, ignore */
1573 ldap_objectclass_free(oc);
1580 * Beyond this point we will be liberal an accept the items
1584 kind = get_token(&ss,&sval);
1587 *code = LDAP_SCHERR_NORIGHTPAREN;
1589 ldap_objectclass_free(oc);
1594 if ( !strcmp(sval,"NAME") ) {
1596 *code = LDAP_SCHERR_DUPOPT;
1598 ldap_objectclass_free(oc);
1602 oc->oc_names = parse_qdescrs(&ss,code);
1603 if ( !oc->oc_names ) {
1604 if ( *code != LDAP_SCHERR_OUTOFMEM )
1605 *code = LDAP_SCHERR_BADNAME;
1607 ldap_objectclass_free(oc);
1610 } else if ( !strcmp(sval,"DESC") ) {
1612 *code = LDAP_SCHERR_DUPOPT;
1614 ldap_objectclass_free(oc);
1619 kind = get_token(&ss,&sval);
1620 if ( kind != TK_QDSTRING ) {
1621 *code = LDAP_SCHERR_UNEXPTOKEN;
1623 ldap_objectclass_free(oc);
1628 } else if ( !strcmp(sval,"OBSOLETE") ) {
1629 if ( seen_obsolete ) {
1630 *code = LDAP_SCHERR_DUPOPT;
1632 ldap_objectclass_free(oc);
1636 oc->oc_obsolete = LDAP_SCHEMA_YES;
1638 } else if ( !strcmp(sval,"SUP") ) {
1640 *code = LDAP_SCHERR_DUPOPT;
1642 ldap_objectclass_free(oc);
1646 oc->oc_sup_oids = parse_oids(&ss,
1649 if ( !oc->oc_sup_oids ) {
1651 ldap_objectclass_free(oc);
1654 } else if ( !strcmp(sval,"ABSTRACT") ) {
1656 *code = LDAP_SCHERR_DUPOPT;
1658 ldap_objectclass_free(oc);
1662 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
1664 } else if ( !strcmp(sval,"STRUCTURAL") ) {
1666 *code = LDAP_SCHERR_DUPOPT;
1668 ldap_objectclass_free(oc);
1672 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
1674 } else if ( !strcmp(sval,"AUXILIARY") ) {
1676 *code = LDAP_SCHERR_DUPOPT;
1678 ldap_objectclass_free(oc);
1682 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
1684 } else if ( !strcmp(sval,"MUST") ) {
1686 *code = LDAP_SCHERR_DUPOPT;
1688 ldap_objectclass_free(oc);
1692 oc->oc_at_oids_must = parse_oids(&ss,code,0);
1693 if ( !oc->oc_at_oids_must ) {
1695 ldap_objectclass_free(oc);
1699 } else if ( !strcmp(sval,"MAY") ) {
1701 *code = LDAP_SCHERR_DUPOPT;
1703 ldap_objectclass_free(oc);
1707 oc->oc_at_oids_may = parse_oids(&ss,code,0);
1708 if ( !oc->oc_at_oids_may ) {
1710 ldap_objectclass_free(oc);
1714 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1715 /* Should be parse_qdstrings */
1716 ssdummy = parse_qdescrs(&ss, code);
1719 ldap_objectclass_free(oc);
1723 *code = LDAP_SCHERR_UNEXPTOKEN;
1725 ldap_objectclass_free(oc);
1730 *code = LDAP_SCHERR_UNEXPTOKEN;
1732 ldap_objectclass_free(oc);
1738 static char *err2text[] = {
1742 "Missing opening parenthesis",
1743 "Missing closing parenthesis",
1749 "Unexpected end of data"
1753 ldap_scherr2str(int code)
1755 if ( code < 1 || code >= (sizeof(err2text)/sizeof(char *)) ) {
1756 return "Unknown error";
1758 return err2text[code];