2 * Copyright 1999 The OpenLDAP Foundation, All Rights Reserved.
3 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6 * schema.c: parsing routines used by servers and clients to process
13 #include <ac/stdlib.h>
16 #include <ac/string.h>
21 #include <ldap_schema.h>
24 * When pretty printing the entities we will be appending to a buffer.
25 * Since checking for overflow, realloc'ing and checking if no error
26 * is extremely boring, we will use a protection layer that will let
27 * us blissfully ignore the error until the end. This layer is
28 * implemented with the help of the next type.
31 typedef struct safe_string {
39 new_safe_string(int size)
43 ss = LDAP_MALLOC(sizeof(safe_string));
47 ss->val = LDAP_MALLOC(size);
61 safe_string_free(safe_string * ss)
70 safe_string_val(safe_string * ss)
72 ss->val[ss->pos] = '\0';
77 append_to_safe_string(safe_string * ss, char * s)
83 * Some runaway process is trying to append to a string that
84 * overflowed and we could not extend.
89 /* We always make sure there is at least one position available */
90 if ( ss->pos + l >= ss->size-1 ) {
92 temp = LDAP_REALLOC(ss->val, ss->size);
94 /* Trouble, out of memory */
100 strncpy(&ss->val[ss->pos], s, l);
102 if ( ss->pos > 0 && isspace(ss->val[ss->pos-1]) )
111 print_literal(safe_string *ss, char *s)
113 return(append_to_safe_string(ss,s));
117 print_whsp(safe_string *ss)
120 return(append_to_safe_string(ss,""));
122 return(append_to_safe_string(ss," "));
126 print_numericoid(safe_string *ss, char *s)
129 return(append_to_safe_string(ss,s));
131 return(append_to_safe_string(ss,""));
134 /* This one is identical to print_qdescr */
136 print_qdstring(safe_string *ss, char *s)
139 print_literal(ss,"'");
140 append_to_safe_string(ss,s);
141 print_literal(ss,"'");
142 return(print_whsp(ss));
146 print_qdescr(safe_string *ss, char *s)
149 print_literal(ss,"'");
150 append_to_safe_string(ss,s);
151 print_literal(ss,"'");
152 return(print_whsp(ss));
156 print_qdescrlist(safe_string *ss, char **sa)
161 for (sp=sa; *sp; sp++) {
162 ret = print_qdescr(ss,*sp);
164 /* If the list was empty, we return zero that is potentially
165 * incorrect, but since we will be still appending things, the
166 * overflow will be detected later. Maybe FIX.
172 print_qdescrs(safe_string *ss, char **sa)
174 /* The only way to represent an empty list is as a qdescrlist
175 * so, if the list is empty we treat it as a long list.
176 * Really, this is what the syntax mandates. We should not
177 * be here if the list was empty, but if it happens, a label
178 * has already been output and we cannot undo it.
180 if ( !sa[0] || ( sa[0] && sa[1] ) ) {
182 print_literal(ss,"(");
183 print_qdescrlist(ss,sa);
184 print_literal(ss,")");
185 return(print_whsp(ss));
187 return(print_qdescr(ss,*sa));
192 print_woid(safe_string *ss, char *s)
195 append_to_safe_string(ss,s);
196 return print_whsp(ss);
200 print_oidlist(safe_string *ss, char **sa)
204 for (sp=sa; *(sp+1); sp++) {
206 print_literal(ss,"$");
208 return(print_woid(ss,*sp));
212 print_oids(safe_string *ss, char **sa)
214 if ( sa[0] && sa[1] ) {
215 print_literal(ss,"(");
216 print_oidlist(ss,sa);
218 return(print_literal(ss,")"));
220 return(print_woid(ss,*sa));
225 print_noidlen(safe_string *ss, char *s, int l)
230 ret = print_numericoid(ss,s);
232 sprintf(buf,"{%d}",l);
233 ret = print_literal(ss,buf);
239 ldap_syntax2str( const LDAP_SYNTAX * syn )
244 ss = new_safe_string(256);
248 print_literal(ss,"(");
251 print_numericoid(ss, syn->syn_oid);
254 if ( syn->syn_desc ) {
255 print_literal(ss,"DESC");
256 print_qdstring(ss,syn->syn_desc);
260 print_literal(ss,")");
262 retstring = LDAP_STRDUP(safe_string_val(ss));
263 safe_string_free(ss);
268 ldap_matchingrule2str( const LDAP_MATCHING_RULE * mr )
273 ss = new_safe_string(256);
277 print_literal(ss,"(");
280 print_numericoid(ss, mr->mr_oid);
283 if ( mr->mr_names ) {
284 print_literal(ss,"NAME");
285 print_qdescrs(ss,mr->mr_names);
289 print_literal(ss,"DESC");
290 print_qdstring(ss,mr->mr_desc);
293 if ( mr->mr_obsolete == LDAP_SCHEMA_YES ) {
294 print_literal(ss, "OBSOLETE");
298 if ( mr->mr_syntax_oid ) {
299 print_literal(ss,"SYNTAX");
301 print_literal(ss, mr->mr_syntax_oid);
306 print_literal(ss,")");
308 retstring = LDAP_STRDUP(safe_string_val(ss));
309 safe_string_free(ss);
314 ldap_objectclass2str( const LDAP_OBJECT_CLASS * oc )
319 ss = new_safe_string(256);
323 print_literal(ss,"(");
326 print_numericoid(ss, oc->oc_oid);
329 if ( oc->oc_names ) {
330 print_literal(ss,"NAME");
331 print_qdescrs(ss,oc->oc_names);
335 print_literal(ss,"DESC");
336 print_qdstring(ss,oc->oc_desc);
339 if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) {
340 print_literal(ss, "OBSOLETE");
344 if ( oc->oc_sup_oids ) {
345 print_literal(ss,"SUP");
347 print_oids(ss,oc->oc_sup_oids);
351 switch (oc->oc_kind) {
352 case LDAP_SCHEMA_ABSTRACT:
353 print_literal(ss,"ABSTRACT");
355 case LDAP_SCHEMA_STRUCTURAL:
356 print_literal(ss,"STRUCTURAL");
358 case LDAP_SCHEMA_AUXILIARY:
359 print_literal(ss,"AUXILIARY");
362 print_literal(ss,"KIND-UNKNOWN");
367 if ( oc->oc_at_oids_must ) {
368 print_literal(ss,"MUST");
370 print_oids(ss,oc->oc_at_oids_must);
374 if ( oc->oc_at_oids_may ) {
375 print_literal(ss,"MAY");
377 print_oids(ss,oc->oc_at_oids_may);
382 print_literal(ss,")");
384 retstring = LDAP_STRDUP(safe_string_val(ss));
385 safe_string_free(ss);
390 ldap_attributetype2str( const LDAP_ATTRIBUTE_TYPE * at )
395 ss = new_safe_string(256);
399 print_literal(ss,"(");
402 print_numericoid(ss, at->at_oid);
405 if ( at->at_names ) {
406 print_literal(ss,"NAME");
407 print_qdescrs(ss,at->at_names);
411 print_literal(ss,"DESC");
412 print_qdstring(ss,at->at_desc);
415 if ( at->at_obsolete == LDAP_SCHEMA_YES ) {
416 print_literal(ss, "OBSOLETE");
420 if ( at->at_sup_oid ) {
421 print_literal(ss,"SUP");
422 print_woid(ss,at->at_sup_oid);
425 if ( at->at_equality_oid ) {
426 print_literal(ss,"EQUALITY");
427 print_woid(ss,at->at_equality_oid);
430 if ( at->at_ordering_oid ) {
431 print_literal(ss,"ORDERING");
432 print_woid(ss,at->at_ordering_oid);
435 if ( at->at_substr_oid ) {
436 print_literal(ss,"SUBSTR");
437 print_woid(ss,at->at_substr_oid);
440 if ( at->at_syntax_oid ) {
441 print_literal(ss,"SYNTAX");
443 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
447 if ( at->at_single_value == LDAP_SCHEMA_YES ) {
448 print_literal(ss,"SINGLE-VALUE");
452 if ( at->at_collective == LDAP_SCHEMA_YES ) {
453 print_literal(ss,"COLLECTIVE");
457 if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
458 print_literal(ss,"NO-USER-MODIFICATION");
462 if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
463 print_literal(ss,"USAGE");
465 switch (at->at_usage) {
466 case LDAP_SCHEMA_DIRECTORY_OPERATION:
467 print_literal(ss,"directoryOperation");
469 case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
470 print_literal(ss,"distributedOperation");
472 case LDAP_SCHEMA_DSA_OPERATION:
473 print_literal(ss,"dSAOperation");
476 print_literal(ss,"UNKNOWN");
482 print_literal(ss,")");
484 retstring = LDAP_STRDUP(safe_string_val(ss));
485 safe_string_free(ss);
490 * Now come the parsers. There is one parser for each entity type:
491 * objectclasses, attributetypes, etc.
493 * Each of them is written as a recursive-descent parser, except that
494 * none of them is really recursive. But the idea is kept: there
495 * is one routine per non-terminal that eithers gobbles lexical tokens
496 * or calls lower-level routines, etc.
498 * The scanner is implemented in the routine get_token. Actually,
499 * get_token is more than a scanner and will return tokens that are
500 * in fact non-terminals in the grammar. So you can see the whole
501 * approach as the combination of a low-level bottom-up recognizer
502 * combined with a scanner and a number of top-down parsers. Or just
503 * consider that the real grammars recognized by the parsers are not
504 * those of the standards. As a matter of fact, our parsers are more
505 * liberal than the spec when there is no ambiguity.
507 * The difference is pretty academic (modulo bugs or incorrect
508 * interpretation of the specs).
511 #define TK_NOENDQUOTE -2
512 #define TK_OUTOFMEM -1
514 #define TK_UNEXPCHAR 1
515 #define TK_BAREWORD 2
516 #define TK_QDSTRING 3
517 #define TK_LEFTPAREN 4
518 #define TK_RIGHTPAREN 5
520 #define TK_QDESCR TK_QDSTRING
528 get_token(const char ** sp, char ** token_val)
546 kind = TK_RIGHTPAREN;
557 while ( **sp != '\'' && **sp != '\0' )
559 if ( **sp == '\'' ) {
561 res = LDAP_MALLOC(q-p+1);
571 kind = TK_NOENDQUOTE;
577 while ( !isspace(**sp) &&
585 res = LDAP_MALLOC(q-p+1);
594 /* kind = TK_UNEXPCHAR; */
601 /* Gobble optional whitespace */
603 parse_whsp(const char **sp)
605 while (isspace(**sp))
610 * General note for all parsers: to guarantee the algorithm halts they
611 * must always advance the pointer even when an error is found. For
612 * this one is not that important since an error here is fatal at the
613 * upper layers, but it is a simple strategy that will not get in
617 /* Parse a sequence of dot-separated decimal strings */
619 parse_numericoid(const char **sp, int *code, const int allow_quoted)
622 const char * start = *sp;
626 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
627 if ( allow_quoted && **sp == '\'' ) {
632 /* Each iteration of this loop gets one decimal string */
634 if ( !isdigit(**sp) ) {
636 * Initial char is not a digit or char after dot is
639 *code = LDAP_SCHERR_NODIGIT;
643 while ( isdigit(**sp) )
647 /* Otherwise, gobble the dot and loop again */
650 /* Now *sp points at the char past the numericoid. Perfect. */
652 res = LDAP_MALLOC(len+1);
654 *code = LDAP_SCHERR_OUTOFMEM;
657 strncpy(res,start,len);
659 if ( allow_quoted && quoted ) {
660 if ( **sp == '\'' ) {
663 *code = LDAP_SCHERR_UNEXPTOKEN;
671 /* Parse a qdescr or a list of them enclosed in () */
673 parse_qdescrs(const char **sp, int *code)
683 kind = get_token(sp,&sval);
684 if ( kind == TK_LEFTPAREN ) {
685 /* Let's presume there will be at least 2 entries */
687 res = LDAP_CALLOC(3,sizeof(char *));
689 *code = LDAP_SCHERR_OUTOFMEM;
695 kind = get_token(sp,&sval);
696 if ( kind == TK_RIGHTPAREN )
698 if ( kind == TK_QDESCR ) {
699 if ( pos == size-2 ) {
701 res1 = LDAP_REALLOC(res,size*sizeof(char *));
705 *code = LDAP_SCHERR_OUTOFMEM;
716 *code = LDAP_SCHERR_UNEXPTOKEN;
723 } else if ( kind == TK_QDESCR ) {
724 res = LDAP_CALLOC(2,sizeof(char *));
726 *code = LDAP_SCHERR_OUTOFMEM;
735 *code = LDAP_SCHERR_BADNAME;
742 parse_woid(const char **sp, int *code)
748 kind = get_token(sp, &sval);
749 if ( kind != TK_BAREWORD ) {
751 *code = LDAP_SCHERR_UNEXPTOKEN;
758 /* Parse a noidlen */
760 parse_noidlen(const char **sp, int *code, int *len, int allow_quoted)
766 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
767 if ( allow_quoted && **sp == '\'' ) {
771 sval = parse_numericoid(sp, code, 0);
778 while ( isdigit(**sp) )
781 *code = LDAP_SCHERR_UNEXPTOKEN;
787 if ( allow_quoted && quoted ) {
788 if ( **sp == '\'' ) {
791 *code = LDAP_SCHERR_UNEXPTOKEN;
800 * Next routine will accept a qdstring in place of an oid if
801 * allow_quoted is set. This is necessary to interoperate with
802 * Netscape Directory server that will improperly quote each oid (at
803 * least those of the descr kind) in the SUP clause.
806 /* Parse a woid or a $-separated list of them enclosed in () */
808 parse_oids(const char **sp, int *code, const int allow_quoted)
818 * Strictly speaking, doing this here accepts whsp before the
819 * ( at the begining of an oidlist, but this is harmless. Also,
820 * we are very liberal in what we accept as an OID. Maybe
824 kind = get_token(sp,&sval);
825 if ( kind == TK_LEFTPAREN ) {
826 /* Let's presume there will be at least 2 entries */
828 res = LDAP_CALLOC(3,sizeof(char *));
830 *code = LDAP_SCHERR_OUTOFMEM;
835 kind = get_token(sp,&sval);
836 if ( kind == TK_BAREWORD ||
837 ( allow_quoted && kind == TK_QDSTRING ) ) {
841 *code = LDAP_SCHERR_UNEXPTOKEN;
848 kind = get_token(sp,&sval);
849 if ( kind == TK_RIGHTPAREN )
851 if ( kind == TK_DOLLAR ) {
853 kind = get_token(sp,&sval);
854 if ( kind == TK_BAREWORD ||
856 kind == TK_QDSTRING ) ) {
857 if ( pos == size-2 ) {
859 res1 = LDAP_REALLOC(res,size*sizeof(char *));
863 *code = LDAP_SCHERR_OUTOFMEM;
871 *code = LDAP_SCHERR_UNEXPTOKEN;
878 *code = LDAP_SCHERR_UNEXPTOKEN;
887 } else if ( kind == TK_BAREWORD ||
888 ( allow_quoted && kind == TK_QDSTRING ) ) {
889 res = LDAP_CALLOC(2,sizeof(char *));
892 *code = LDAP_SCHERR_OUTOFMEM;
901 *code = LDAP_SCHERR_BADNAME;
907 ldap_syntax_free( LDAP_SYNTAX * syn )
909 LDAP_FREE(syn->syn_oid);
910 LDAP_FREE(syn->syn_desc);
915 ldap_str2syntax( const char * s, int * code, const char ** errp )
925 *code = LDAP_SCHERR_EMPTY;
931 syn = LDAP_CALLOC(1,sizeof(LDAP_SYNTAX));
934 *code = LDAP_SCHERR_OUTOFMEM;
938 kind = get_token(&ss,&sval);
939 if ( kind != TK_LEFTPAREN ) {
941 *code = LDAP_SCHERR_NOLEFTPAREN;
942 ldap_syntax_free(syn);
947 syn->syn_oid = parse_numericoid(&ss,code,0);
948 if ( !syn->syn_oid ) {
950 ldap_syntax_free(syn);
956 * Beyond this point we will be liberal and accept the items
960 kind = get_token(&ss,&sval);
963 *code = LDAP_SCHERR_NORIGHTPAREN;
965 ldap_syntax_free(syn);
970 if ( !strcmp(sval,"DESC") ) {
973 *code = LDAP_SCHERR_DUPOPT;
975 ldap_syntax_free(syn);
980 kind = get_token(&ss,&sval);
981 if ( kind != TK_QDSTRING ) {
982 *code = LDAP_SCHERR_UNEXPTOKEN;
985 ldap_syntax_free(syn);
988 syn->syn_desc = sval;
990 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
992 /* Should be parse_qdstrings */
993 ssdummy = parse_qdescrs(&ss, code);
996 ldap_syntax_free(syn);
1000 *code = LDAP_SCHERR_UNEXPTOKEN;
1003 ldap_syntax_free(syn);
1008 *code = LDAP_SCHERR_UNEXPTOKEN;
1011 ldap_syntax_free(syn);
1018 ldap_matchingrule_free( LDAP_MATCHING_RULE * mr )
1020 LDAP_FREE(mr->mr_oid);
1021 LDAP_VFREE(mr->mr_names);
1022 LDAP_FREE(mr->mr_desc);
1023 LDAP_FREE(mr->mr_syntax_oid);
1027 LDAP_MATCHING_RULE *
1028 ldap_str2matchingrule( const char * s, int * code, const char ** errp )
1031 const char * ss = s;
1033 int be_liberal = 1; /* Future additional argument */
1036 int seen_obsolete = 0;
1037 int seen_syntax = 0;
1038 LDAP_MATCHING_RULE * mr;
1040 const char * savepos;
1043 *code = LDAP_SCHERR_EMPTY;
1049 mr = LDAP_CALLOC(1,sizeof(LDAP_MATCHING_RULE));
1052 *code = LDAP_SCHERR_OUTOFMEM;
1056 kind = get_token(&ss,&sval);
1057 if ( kind != TK_LEFTPAREN ) {
1058 *code = LDAP_SCHERR_NOLEFTPAREN;
1060 ldap_matchingrule_free(mr);
1066 mr->mr_oid = parse_numericoid(&ss,code,be_liberal);
1067 if ( !mr->mr_oid ) {
1071 kind = get_token(&ss,&sval);
1072 if ( kind == TK_BAREWORD ) {
1073 if ( !strcmp(sval, "NAME") ||
1074 !strcmp(sval, "DESC") ||
1075 !strcmp(sval, "OBSOLETE") ||
1076 !strcmp(sval, "SYNTAX") ||
1077 !strncmp(sval, "X-", 2) ) {
1078 /* Missing OID, backtrack */
1081 /* Non-numerical OID, ignore */
1087 ldap_matchingrule_free(mr);
1094 * Beyond this point we will be liberal and accept the items
1098 kind = get_token(&ss,&sval);
1101 *code = LDAP_SCHERR_NORIGHTPAREN;
1103 ldap_matchingrule_free(mr);
1108 if ( !strcmp(sval,"NAME") ) {
1111 *code = LDAP_SCHERR_DUPOPT;
1113 ldap_matchingrule_free(mr);
1117 mr->mr_names = parse_qdescrs(&ss,code);
1118 if ( !mr->mr_names ) {
1119 if ( *code != LDAP_SCHERR_OUTOFMEM )
1120 *code = LDAP_SCHERR_BADNAME;
1122 ldap_matchingrule_free(mr);
1125 } else if ( !strcmp(sval,"DESC") ) {
1128 *code = LDAP_SCHERR_DUPOPT;
1130 ldap_matchingrule_free(mr);
1135 kind = get_token(&ss,&sval);
1136 if ( kind != TK_QDSTRING ) {
1137 *code = LDAP_SCHERR_UNEXPTOKEN;
1140 ldap_matchingrule_free(mr);
1145 } else if ( !strcmp(sval,"OBSOLETE") ) {
1147 if ( seen_obsolete ) {
1148 *code = LDAP_SCHERR_DUPOPT;
1150 ldap_matchingrule_free(mr);
1154 mr->mr_obsolete = LDAP_SCHEMA_YES;
1156 } else if ( !strcmp(sval,"SYNTAX") ) {
1158 if ( seen_syntax ) {
1159 *code = LDAP_SCHERR_DUPOPT;
1161 ldap_matchingrule_free(mr);
1167 parse_numericoid(&ss,code,be_liberal);
1168 if ( !mr->mr_syntax_oid ) {
1170 ldap_matchingrule_free(mr);
1174 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1176 /* Should be parse_qdstrings */
1177 ssdummy = parse_qdescrs(&ss, code);
1180 ldap_matchingrule_free(mr);
1184 *code = LDAP_SCHERR_UNEXPTOKEN;
1187 ldap_matchingrule_free(mr);
1192 *code = LDAP_SCHERR_UNEXPTOKEN;
1195 ldap_matchingrule_free(mr);
1202 ldap_attributetype_free(LDAP_ATTRIBUTE_TYPE * at)
1204 LDAP_FREE(at->at_oid);
1205 LDAP_VFREE(at->at_names);
1206 LDAP_FREE(at->at_desc);
1207 LDAP_FREE(at->at_sup_oid);
1208 LDAP_FREE(at->at_equality_oid);
1209 LDAP_FREE(at->at_ordering_oid);
1210 LDAP_FREE(at->at_substr_oid);
1211 LDAP_FREE(at->at_syntax_oid);
1215 LDAP_ATTRIBUTE_TYPE *
1216 ldap_str2attributetype( const char * s, int * code, const char ** errp )
1219 const char * ss = s;
1221 int be_liberal = 1; /* Future additional argument */
1224 int seen_obsolete = 0;
1226 int seen_equality = 0;
1227 int seen_ordering = 0;
1228 int seen_substr = 0;
1229 int seen_syntax = 0;
1234 LDAP_ATTRIBUTE_TYPE * at;
1236 const char * savepos;
1239 *code = LDAP_SCHERR_EMPTY;
1245 at = LDAP_CALLOC(1,sizeof(LDAP_ATTRIBUTE_TYPE));
1248 *code = LDAP_SCHERR_OUTOFMEM;
1252 kind = get_token(&ss,&sval);
1253 if ( kind != TK_LEFTPAREN ) {
1254 *code = LDAP_SCHERR_NOLEFTPAREN;
1256 ldap_attributetype_free(at);
1261 * Definitions MUST begin with an OID in the numericoid format.
1262 * However, this routine is used by clients to parse the response
1263 * from servers and very well known servers will provide an OID
1264 * in the wrong format or even no OID at all. We do our best to
1265 * extract info from those servers.
1269 at->at_oid = parse_numericoid(&ss,code,0);
1270 if ( !at->at_oid ) {
1274 kind = get_token(&ss,&sval);
1275 if ( kind == TK_BAREWORD ) {
1276 if ( !strcmp(sval, "NAME") ||
1277 !strcmp(sval, "DESC") ||
1278 !strcmp(sval, "OBSOLETE") ||
1279 !strcmp(sval, "SUP") ||
1280 !strcmp(sval, "EQUALITY") ||
1281 !strcmp(sval, "ORDERING") ||
1282 !strcmp(sval, "SUBSTR") ||
1283 !strcmp(sval, "SYNTAX") ||
1284 !strcmp(sval, "SINGLE-VALUE") ||
1285 !strcmp(sval, "COLLECTIVE") ||
1286 !strcmp(sval, "NO-USER-MODIFICATION") ||
1287 !strcmp(sval, "USAGE") ||
1288 !strncmp(sval, "X-", 2) ) {
1289 /* Missing OID, backtrack */
1292 /* Non-numerical OID, ignore */
1298 ldap_attributetype_free(at);
1305 * Beyond this point we will be liberal and accept the items
1309 kind = get_token(&ss,&sval);
1312 *code = LDAP_SCHERR_NORIGHTPAREN;
1314 ldap_attributetype_free(at);
1319 if ( !strcmp(sval,"NAME") ) {
1322 *code = LDAP_SCHERR_DUPOPT;
1324 ldap_attributetype_free(at);
1328 at->at_names = parse_qdescrs(&ss,code);
1329 if ( !at->at_names ) {
1330 if ( *code != LDAP_SCHERR_OUTOFMEM )
1331 *code = LDAP_SCHERR_BADNAME;
1333 ldap_attributetype_free(at);
1336 } else if ( !strcmp(sval,"DESC") ) {
1339 *code = LDAP_SCHERR_DUPOPT;
1341 ldap_attributetype_free(at);
1346 kind = get_token(&ss,&sval);
1347 if ( kind != TK_QDSTRING ) {
1348 *code = LDAP_SCHERR_UNEXPTOKEN;
1351 ldap_attributetype_free(at);
1356 } else if ( !strcmp(sval,"OBSOLETE") ) {
1358 if ( seen_obsolete ) {
1359 *code = LDAP_SCHERR_DUPOPT;
1361 ldap_attributetype_free(at);
1365 at->at_obsolete = LDAP_SCHEMA_YES;
1367 } else if ( !strcmp(sval,"SUP") ) {
1370 *code = LDAP_SCHERR_DUPOPT;
1372 ldap_attributetype_free(at);
1376 at->at_sup_oid = parse_woid(&ss,code);
1377 if ( !at->at_sup_oid ) {
1379 ldap_attributetype_free(at);
1382 } else if ( !strcmp(sval,"EQUALITY") ) {
1384 if ( seen_equality ) {
1385 *code = LDAP_SCHERR_DUPOPT;
1387 ldap_attributetype_free(at);
1391 at->at_equality_oid = parse_woid(&ss,code);
1392 if ( !at->at_equality_oid ) {
1394 ldap_attributetype_free(at);
1397 } else if ( !strcmp(sval,"ORDERING") ) {
1399 if ( seen_ordering ) {
1400 *code = LDAP_SCHERR_DUPOPT;
1402 ldap_attributetype_free(at);
1406 at->at_ordering_oid = parse_woid(&ss,code);
1407 if ( !at->at_ordering_oid ) {
1409 ldap_attributetype_free(at);
1412 } else if ( !strcmp(sval,"SUBSTR") ) {
1414 if ( seen_substr ) {
1415 *code = LDAP_SCHERR_DUPOPT;
1417 ldap_attributetype_free(at);
1421 at->at_substr_oid = parse_woid(&ss,code);
1422 if ( !at->at_substr_oid ) {
1424 ldap_attributetype_free(at);
1427 } else if ( !strcmp(sval,"SYNTAX") ) {
1429 if ( seen_syntax ) {
1430 *code = LDAP_SCHERR_DUPOPT;
1432 ldap_attributetype_free(at);
1442 if ( !at->at_syntax_oid ) {
1444 ldap_attributetype_free(at);
1448 } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
1450 if ( at->at_single_value ) {
1451 *code = LDAP_SCHERR_DUPOPT;
1453 ldap_attributetype_free(at);
1456 at->at_single_value = LDAP_SCHEMA_YES;
1458 } else if ( !strcmp(sval,"COLLECTIVE") ) {
1460 if ( at->at_collective ) {
1461 *code = LDAP_SCHERR_DUPOPT;
1463 ldap_attributetype_free(at);
1466 at->at_collective = LDAP_SCHEMA_YES;
1468 } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
1470 if ( at->at_no_user_mod ) {
1471 *code = LDAP_SCHERR_DUPOPT;
1473 ldap_attributetype_free(at);
1476 at->at_no_user_mod = LDAP_SCHEMA_YES;
1478 } else if ( !strcmp(sval,"USAGE") ) {
1481 *code = LDAP_SCHERR_DUPOPT;
1483 ldap_attributetype_free(at);
1488 kind = get_token(&ss,&sval);
1489 if ( kind != TK_BAREWORD ) {
1490 *code = LDAP_SCHERR_UNEXPTOKEN;
1493 ldap_attributetype_free(at);
1496 if ( !strcasecmp(sval,"userApplications") )
1498 LDAP_SCHEMA_USER_APPLICATIONS;
1499 else if ( !strcasecmp(sval,"directoryOperation") )
1501 LDAP_SCHEMA_DIRECTORY_OPERATION;
1502 else if ( !strcasecmp(sval,"distributedOperation") )
1504 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
1505 else if ( !strcasecmp(sval,"dSAOperation") )
1507 LDAP_SCHEMA_DSA_OPERATION;
1509 *code = LDAP_SCHERR_UNEXPTOKEN;
1512 ldap_attributetype_free(at);
1517 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1519 /* Should be parse_qdstrings */
1520 ssdummy = parse_qdescrs(&ss, code);
1523 ldap_attributetype_free(at);
1527 *code = LDAP_SCHERR_UNEXPTOKEN;
1530 ldap_attributetype_free(at);
1535 *code = LDAP_SCHERR_UNEXPTOKEN;
1538 ldap_attributetype_free(at);
1545 ldap_objectclass_free(LDAP_OBJECT_CLASS * oc)
1547 LDAP_FREE(oc->oc_oid);
1548 LDAP_VFREE(oc->oc_names);
1549 LDAP_FREE(oc->oc_desc);
1550 LDAP_VFREE(oc->oc_sup_oids);
1551 LDAP_VFREE(oc->oc_at_oids_must);
1552 LDAP_VFREE(oc->oc_at_oids_may);
1557 ldap_str2objectclass( const char * s, int * code, const char ** errp )
1560 const char * ss = s;
1562 int be_liberal = 1; /* Future additional argument */
1565 int seen_obsolete = 0;
1570 LDAP_OBJECT_CLASS * oc;
1572 const char * savepos;
1575 *code = LDAP_SCHERR_EMPTY;
1581 oc = LDAP_CALLOC(1,sizeof(LDAP_OBJECT_CLASS));
1584 *code = LDAP_SCHERR_OUTOFMEM;
1588 kind = get_token(&ss,&sval);
1589 if ( kind != TK_LEFTPAREN ) {
1590 *code = LDAP_SCHERR_NOLEFTPAREN;
1592 ldap_objectclass_free(oc);
1597 * Definitions MUST begin with an OID in the numericoid format.
1598 * However, this routine is used by clients to parse the response
1599 * from servers and very well known servers will provide an OID
1600 * in the wrong format or even no OID at all. We do our best to
1601 * extract info from those servers.
1605 oc->oc_oid = parse_numericoid(&ss,code,0);
1606 if ( !oc->oc_oid ) {
1610 kind = get_token(&ss,&sval);
1611 if ( kind == TK_BAREWORD ) {
1612 if ( !strcmp(sval, "NAME") ||
1613 !strcmp(sval, "DESC") ||
1614 !strcmp(sval, "OBSOLETE") ||
1615 !strcmp(sval, "SUP") ||
1616 !strcmp(sval, "ABSTRACT") ||
1617 !strcmp(sval, "STRUCTURAL") ||
1618 !strcmp(sval, "AUXILIARY") ||
1619 !strcmp(sval, "MUST") ||
1620 !strncmp(sval, "X-", 2) ) {
1621 /* Missing OID, backtrack */
1624 /* Non-numerical OID, ignore */
1630 ldap_objectclass_free(oc);
1637 * Beyond this point we will be liberal an accept the items
1641 kind = get_token(&ss,&sval);
1644 *code = LDAP_SCHERR_NORIGHTPAREN;
1646 ldap_objectclass_free(oc);
1651 if ( !strcmp(sval,"NAME") ) {
1654 *code = LDAP_SCHERR_DUPOPT;
1656 ldap_objectclass_free(oc);
1660 oc->oc_names = parse_qdescrs(&ss,code);
1661 if ( !oc->oc_names ) {
1662 if ( *code != LDAP_SCHERR_OUTOFMEM )
1663 *code = LDAP_SCHERR_BADNAME;
1665 ldap_objectclass_free(oc);
1668 } else if ( !strcmp(sval,"DESC") ) {
1671 *code = LDAP_SCHERR_DUPOPT;
1673 ldap_objectclass_free(oc);
1678 kind = get_token(&ss,&sval);
1679 if ( kind != TK_QDSTRING ) {
1680 *code = LDAP_SCHERR_UNEXPTOKEN;
1683 ldap_objectclass_free(oc);
1688 } else if ( !strcmp(sval,"OBSOLETE") ) {
1690 if ( seen_obsolete ) {
1691 *code = LDAP_SCHERR_DUPOPT;
1693 ldap_objectclass_free(oc);
1697 oc->oc_obsolete = LDAP_SCHEMA_YES;
1699 } else if ( !strcmp(sval,"SUP") ) {
1702 *code = LDAP_SCHERR_DUPOPT;
1704 ldap_objectclass_free(oc);
1708 oc->oc_sup_oids = parse_oids(&ss,
1711 if ( !oc->oc_sup_oids ) {
1713 ldap_objectclass_free(oc);
1716 } else if ( !strcmp(sval,"ABSTRACT") ) {
1719 *code = LDAP_SCHERR_DUPOPT;
1721 ldap_objectclass_free(oc);
1725 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
1727 } else if ( !strcmp(sval,"STRUCTURAL") ) {
1730 *code = LDAP_SCHERR_DUPOPT;
1732 ldap_objectclass_free(oc);
1736 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
1738 } else if ( !strcmp(sval,"AUXILIARY") ) {
1741 *code = LDAP_SCHERR_DUPOPT;
1743 ldap_objectclass_free(oc);
1747 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
1749 } else if ( !strcmp(sval,"MUST") ) {
1752 *code = LDAP_SCHERR_DUPOPT;
1754 ldap_objectclass_free(oc);
1758 oc->oc_at_oids_must = parse_oids(&ss,code,0);
1759 if ( !oc->oc_at_oids_must ) {
1761 ldap_objectclass_free(oc);
1765 } else if ( !strcmp(sval,"MAY") ) {
1768 *code = LDAP_SCHERR_DUPOPT;
1770 ldap_objectclass_free(oc);
1774 oc->oc_at_oids_may = parse_oids(&ss,code,0);
1775 if ( !oc->oc_at_oids_may ) {
1777 ldap_objectclass_free(oc);
1781 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1783 /* Should be parse_qdstrings */
1784 ssdummy = parse_qdescrs(&ss, code);
1787 ldap_objectclass_free(oc);
1791 *code = LDAP_SCHERR_UNEXPTOKEN;
1794 ldap_objectclass_free(oc);
1799 *code = LDAP_SCHERR_UNEXPTOKEN;
1802 ldap_objectclass_free(oc);
1808 static char *err2text[] = {
1812 "Missing opening parenthesis",
1813 "Missing closing parenthesis",
1819 "Unexpected end of data"
1823 ldap_scherr2str(int code)
1825 if ( code < 1 || code >= (sizeof(err2text)/sizeof(char *)) ) {
1826 return "Unknown error";
1828 return err2text[code];