3 * Copyright 1999-2000 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
7 * schema.c: parsing routines used by servers and clients to process
14 #include <ac/stdlib.h>
16 #include <ac/string.h>
21 #include <ldap_schema.h>
23 static LDAP_CONST char *
24 choose_name( char *names[], LDAP_CONST char *fallback )
26 return( (names != NULL && names[0] != NULL) ? names[0] : fallback );
30 ldap_syntax2name( LDAPSyntax * syn )
32 return( syn->syn_oid );
36 ldap_matchingrule2name( LDAPMatchingRule * mr )
38 return( choose_name( mr->mr_names, mr->mr_oid ) );
42 ldap_matchingruleuse2name( LDAPMatchingRuleUse * mru )
44 return( choose_name( mru->mru_names, mru->mru_oid ) );
48 ldap_attributetype2name( LDAPAttributeType * at )
50 return( choose_name( at->at_names, at->at_oid ) );
54 ldap_objectclass2name( LDAPObjectClass * oc )
56 return( choose_name( oc->oc_names, oc->oc_oid ) );
61 * When pretty printing the entities we will be appending to a buffer.
62 * Since checking for overflow, realloc'ing and checking if no error
63 * is extremely boring, we will use a protection layer that will let
64 * us blissfully ignore the error until the end. This layer is
65 * implemented with the help of the next type.
68 typedef struct safe_string {
76 new_safe_string(int size)
80 ss = LDAP_MALLOC(sizeof(safe_string));
84 ss->val = LDAP_MALLOC(size);
98 safe_string_free(safe_string * ss)
107 safe_string_val(safe_string * ss)
109 ss->val[ss->pos] = '\0';
114 append_to_safe_string(safe_string * ss, char * s)
120 * Some runaway process is trying to append to a string that
121 * overflowed and we could not extend.
126 /* We always make sure there is at least one position available */
127 if ( ss->pos + l >= ss->size-1 ) {
129 temp = LDAP_REALLOC(ss->val, ss->size);
131 /* Trouble, out of memory */
137 strncpy(&ss->val[ss->pos], s, l);
139 if ( ss->pos > 0 && LDAP_SPACE(ss->val[ss->pos-1]) )
148 print_literal(safe_string *ss, char *s)
150 return(append_to_safe_string(ss,s));
154 print_whsp(safe_string *ss)
157 return(append_to_safe_string(ss,""));
159 return(append_to_safe_string(ss," "));
163 print_numericoid(safe_string *ss, char *s)
166 return(append_to_safe_string(ss,s));
168 return(append_to_safe_string(ss,""));
171 /* This one is identical to print_qdescr */
173 print_qdstring(safe_string *ss, char *s)
176 print_literal(ss,"'");
177 append_to_safe_string(ss,s);
178 print_literal(ss,"'");
179 return(print_whsp(ss));
183 print_qdescr(safe_string *ss, char *s)
186 print_literal(ss,"'");
187 append_to_safe_string(ss,s);
188 print_literal(ss,"'");
189 return(print_whsp(ss));
193 print_qdescrlist(safe_string *ss, char **sa)
198 for (sp=sa; *sp; sp++) {
199 ret = print_qdescr(ss,*sp);
201 /* If the list was empty, we return zero that is potentially
202 * incorrect, but since we will be still appending things, the
203 * overflow will be detected later. Maybe FIX.
209 print_qdescrs(safe_string *ss, char **sa)
211 /* The only way to represent an empty list is as a qdescrlist
212 * so, if the list is empty we treat it as a long list.
213 * Really, this is what the syntax mandates. We should not
214 * be here if the list was empty, but if it happens, a label
215 * has already been output and we cannot undo it.
217 if ( !sa[0] || ( sa[0] && sa[1] ) ) {
219 print_literal(ss,"("/*)*/);
220 print_qdescrlist(ss,sa);
221 print_literal(ss,/*(*/")");
222 return(print_whsp(ss));
224 return(print_qdescr(ss,*sa));
229 print_woid(safe_string *ss, char *s)
232 append_to_safe_string(ss,s);
233 return print_whsp(ss);
237 print_oidlist(safe_string *ss, char **sa)
241 for (sp=sa; *(sp+1); sp++) {
243 print_literal(ss,"$");
245 return(print_woid(ss,*sp));
249 print_oids(safe_string *ss, char **sa)
251 if ( sa[0] && sa[1] ) {
252 print_literal(ss,"("/*)*/);
253 print_oidlist(ss,sa);
255 return(print_literal(ss,/*(*/")"));
257 return(print_woid(ss,*sa));
262 print_noidlen(safe_string *ss, char *s, int l)
267 ret = print_numericoid(ss,s);
269 sprintf(buf,"{%d}",l);
270 ret = print_literal(ss,buf);
276 print_extensions(safe_string *ss, LDAPSchemaExtensionItem **extensions)
278 LDAPSchemaExtensionItem **ext;
282 for ( ext = extensions; *ext != NULL; ext++ ) {
283 print_literal(ss, (*ext)->lsei_name);
285 /* Should be print_qdstrings */
286 print_qdescrs(ss, (*ext)->lsei_values);
295 ldap_syntax2str( const LDAPSyntax * syn )
300 ss = new_safe_string(256);
304 print_literal(ss,"("/*)*/);
307 print_numericoid(ss, syn->syn_oid);
310 if ( syn->syn_desc ) {
311 print_literal(ss,"DESC");
312 print_qdstring(ss,syn->syn_desc);
317 print_extensions(ss, syn->syn_extensions);
319 print_literal(ss,/*(*/ ")");
321 retstring = LDAP_STRDUP(safe_string_val(ss));
322 safe_string_free(ss);
327 ldap_matchingrule2str( const LDAPMatchingRule * mr )
332 ss = new_safe_string(256);
336 print_literal(ss,"(" /*)*/);
339 print_numericoid(ss, mr->mr_oid);
342 if ( mr->mr_names ) {
343 print_literal(ss,"NAME");
344 print_qdescrs(ss,mr->mr_names);
348 print_literal(ss,"DESC");
349 print_qdstring(ss,mr->mr_desc);
352 if ( mr->mr_obsolete == LDAP_SCHEMA_YES ) {
353 print_literal(ss, "OBSOLETE");
357 if ( mr->mr_syntax_oid ) {
358 print_literal(ss,"SYNTAX");
360 print_literal(ss, mr->mr_syntax_oid);
366 print_extensions(ss, mr->mr_extensions);
368 print_literal(ss,/*(*/")");
370 retstring = LDAP_STRDUP(safe_string_val(ss));
371 safe_string_free(ss);
376 ldap_matchingruleuse2str( const LDAPMatchingRuleUse * mru )
381 ss = new_safe_string(256);
385 print_literal(ss,"(" /*)*/);
388 print_numericoid(ss, mru->mru_oid);
391 if ( mru->mru_names ) {
392 print_literal(ss,"NAME");
393 print_qdescrs(ss,mru->mru_names);
396 if ( mru->mru_desc ) {
397 print_literal(ss,"DESC");
398 print_qdstring(ss,mru->mru_desc);
401 if ( mru->mru_obsolete == LDAP_SCHEMA_YES ) {
402 print_literal(ss, "OBSOLETE");
406 if ( mru->mru_applies_oids ) {
407 print_literal(ss,"APPLIES");
409 print_oids(ss, mru->mru_applies_oids);
415 print_extensions(ss, mru->mru_extensions);
417 print_literal(ss,/*(*/")");
419 retstring = LDAP_STRDUP(safe_string_val(ss));
420 safe_string_free(ss);
425 ldap_objectclass2str( const LDAPObjectClass * oc )
430 ss = new_safe_string(256);
434 print_literal(ss,"("/*)*/);
437 print_numericoid(ss, oc->oc_oid);
440 if ( oc->oc_names ) {
441 print_literal(ss,"NAME");
442 print_qdescrs(ss,oc->oc_names);
446 print_literal(ss,"DESC");
447 print_qdstring(ss,oc->oc_desc);
450 if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) {
451 print_literal(ss, "OBSOLETE");
455 if ( oc->oc_sup_oids ) {
456 print_literal(ss,"SUP");
458 print_oids(ss,oc->oc_sup_oids);
462 switch (oc->oc_kind) {
463 case LDAP_SCHEMA_ABSTRACT:
464 print_literal(ss,"ABSTRACT");
466 case LDAP_SCHEMA_STRUCTURAL:
467 print_literal(ss,"STRUCTURAL");
469 case LDAP_SCHEMA_AUXILIARY:
470 print_literal(ss,"AUXILIARY");
473 print_literal(ss,"KIND-UNKNOWN");
478 if ( oc->oc_at_oids_must ) {
479 print_literal(ss,"MUST");
481 print_oids(ss,oc->oc_at_oids_must);
485 if ( oc->oc_at_oids_may ) {
486 print_literal(ss,"MAY");
488 print_oids(ss,oc->oc_at_oids_may);
494 print_extensions(ss, oc->oc_extensions);
496 print_literal(ss, /*(*/")");
498 retstring = LDAP_STRDUP(safe_string_val(ss));
499 safe_string_free(ss);
504 ldap_attributetype2str( const LDAPAttributeType * at )
509 ss = new_safe_string(256);
513 print_literal(ss,"("/*)*/);
516 print_numericoid(ss, at->at_oid);
519 if ( at->at_names ) {
520 print_literal(ss,"NAME");
521 print_qdescrs(ss,at->at_names);
525 print_literal(ss,"DESC");
526 print_qdstring(ss,at->at_desc);
529 if ( at->at_obsolete == LDAP_SCHEMA_YES ) {
530 print_literal(ss, "OBSOLETE");
534 if ( at->at_sup_oid ) {
535 print_literal(ss,"SUP");
536 print_woid(ss,at->at_sup_oid);
539 if ( at->at_equality_oid ) {
540 print_literal(ss,"EQUALITY");
541 print_woid(ss,at->at_equality_oid);
544 if ( at->at_ordering_oid ) {
545 print_literal(ss,"ORDERING");
546 print_woid(ss,at->at_ordering_oid);
549 if ( at->at_substr_oid ) {
550 print_literal(ss,"SUBSTR");
551 print_woid(ss,at->at_substr_oid);
554 if ( at->at_syntax_oid ) {
555 print_literal(ss,"SYNTAX");
557 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
561 if ( at->at_single_value == LDAP_SCHEMA_YES ) {
562 print_literal(ss,"SINGLE-VALUE");
566 if ( at->at_collective == LDAP_SCHEMA_YES ) {
567 print_literal(ss,"COLLECTIVE");
571 if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
572 print_literal(ss,"NO-USER-MODIFICATION");
576 if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
577 print_literal(ss,"USAGE");
579 switch (at->at_usage) {
580 case LDAP_SCHEMA_DIRECTORY_OPERATION:
581 print_literal(ss,"directoryOperation");
583 case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
584 print_literal(ss,"distributedOperation");
586 case LDAP_SCHEMA_DSA_OPERATION:
587 print_literal(ss,"dSAOperation");
590 print_literal(ss,"UNKNOWN");
597 print_extensions(ss, at->at_extensions);
599 print_literal(ss,/*(*/")");
601 retstring = LDAP_STRDUP(safe_string_val(ss));
602 safe_string_free(ss);
607 * Now come the parsers. There is one parser for each entity type:
608 * objectclasses, attributetypes, etc.
610 * Each of them is written as a recursive-descent parser, except that
611 * none of them is really recursive. But the idea is kept: there
612 * is one routine per non-terminal that eithers gobbles lexical tokens
613 * or calls lower-level routines, etc.
615 * The scanner is implemented in the routine get_token. Actually,
616 * get_token is more than a scanner and will return tokens that are
617 * in fact non-terminals in the grammar. So you can see the whole
618 * approach as the combination of a low-level bottom-up recognizer
619 * combined with a scanner and a number of top-down parsers. Or just
620 * consider that the real grammars recognized by the parsers are not
621 * those of the standards. As a matter of fact, our parsers are more
622 * liberal than the spec when there is no ambiguity.
624 * The difference is pretty academic (modulo bugs or incorrect
625 * interpretation of the specs).
628 #define TK_NOENDQUOTE -2
629 #define TK_OUTOFMEM -1
631 #define TK_UNEXPCHAR 1
632 #define TK_BAREWORD 2
633 #define TK_QDSTRING 3
634 #define TK_LEFTPAREN 4
635 #define TK_RIGHTPAREN 5
637 #define TK_QDESCR TK_QDSTRING
645 get_token(const char ** sp, char ** token_val)
663 kind = TK_RIGHTPAREN;
674 while ( **sp != '\'' && **sp != '\0' )
676 if ( **sp == '\'' ) {
678 res = LDAP_MALLOC(q-p+1);
688 kind = TK_NOENDQUOTE;
694 while ( !LDAP_SPACE(**sp) &&
702 res = LDAP_MALLOC(q-p+1);
711 /* kind = TK_UNEXPCHAR; */
718 /* Gobble optional whitespace */
720 parse_whsp(const char **sp)
722 while (LDAP_SPACE(**sp))
727 * General note for all parsers: to guarantee the algorithm halts they
728 * must always advance the pointer even when an error is found. For
729 * this one is not that important since an error here is fatal at the
730 * upper layers, but it is a simple strategy that will not get in
734 /* Parse a sequence of dot-separated decimal strings */
736 parse_numericoid(const char **sp, int *code, const int flags)
739 const char * start = *sp;
743 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
744 if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && **sp == '\'' ) {
749 /* Each iteration of this loop gets one decimal string */
751 if ( !LDAP_DIGIT(**sp) ) {
753 * Initial char is not a digit or char after dot is
756 *code = LDAP_SCHERR_NODIGIT;
760 while ( LDAP_DIGIT(**sp) )
764 /* Otherwise, gobble the dot and loop again */
767 /* Now *sp points at the char past the numericoid. Perfect. */
769 res = LDAP_MALLOC(len+1);
771 *code = LDAP_SCHERR_OUTOFMEM;
774 strncpy(res,start,len);
776 if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && quoted ) {
777 if ( **sp == '\'' ) {
780 *code = LDAP_SCHERR_UNEXPTOKEN;
788 /* Parse a qdescr or a list of them enclosed in () */
790 parse_qdescrs(const char **sp, int *code)
800 kind = get_token(sp,&sval);
801 if ( kind == TK_LEFTPAREN ) {
802 /* Let's presume there will be at least 2 entries */
804 res = LDAP_CALLOC(3,sizeof(char *));
806 *code = LDAP_SCHERR_OUTOFMEM;
812 kind = get_token(sp,&sval);
813 if ( kind == TK_RIGHTPAREN )
815 if ( kind == TK_QDESCR ) {
816 if ( pos == size-2 ) {
818 res1 = LDAP_REALLOC(res,size*sizeof(char *));
822 *code = LDAP_SCHERR_OUTOFMEM;
833 *code = LDAP_SCHERR_UNEXPTOKEN;
840 } else if ( kind == TK_QDESCR ) {
841 res = LDAP_CALLOC(2,sizeof(char *));
843 *code = LDAP_SCHERR_OUTOFMEM;
852 *code = LDAP_SCHERR_BADNAME;
859 parse_woid(const char **sp, int *code)
865 kind = get_token(sp, &sval);
866 if ( kind != TK_BAREWORD ) {
868 *code = LDAP_SCHERR_UNEXPTOKEN;
875 /* Parse a noidlen */
877 parse_noidlen(const char **sp, int *code, int *len, int allow_quoted)
883 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
884 if ( allow_quoted && **sp == '\'' ) {
888 sval = parse_numericoid(sp, code, 0);
892 if ( **sp == '{' /*}*/ ) {
895 while ( LDAP_DIGIT(**sp) )
897 if ( **sp != /*{*/ '}' ) {
898 *code = LDAP_SCHERR_UNEXPTOKEN;
904 if ( allow_quoted && quoted ) {
905 if ( **sp == '\'' ) {
908 *code = LDAP_SCHERR_UNEXPTOKEN;
917 * Next routine will accept a qdstring in place of an oid if
918 * allow_quoted is set. This is necessary to interoperate with
919 * Netscape Directory server that will improperly quote each oid (at
920 * least those of the descr kind) in the SUP clause.
923 /* Parse a woid or a $-separated list of them enclosed in () */
925 parse_oids(const char **sp, int *code, const int allow_quoted)
935 * Strictly speaking, doing this here accepts whsp before the
936 * ( at the begining of an oidlist, but this is harmless. Also,
937 * we are very liberal in what we accept as an OID. Maybe
941 kind = get_token(sp,&sval);
942 if ( kind == TK_LEFTPAREN ) {
943 /* Let's presume there will be at least 2 entries */
945 res = LDAP_CALLOC(3,sizeof(char *));
947 *code = LDAP_SCHERR_OUTOFMEM;
952 kind = get_token(sp,&sval);
953 if ( kind == TK_BAREWORD ||
954 ( allow_quoted && kind == TK_QDSTRING ) ) {
958 *code = LDAP_SCHERR_UNEXPTOKEN;
965 kind = get_token(sp,&sval);
966 if ( kind == TK_RIGHTPAREN )
968 if ( kind == TK_DOLLAR ) {
970 kind = get_token(sp,&sval);
971 if ( kind == TK_BAREWORD ||
973 kind == TK_QDSTRING ) ) {
974 if ( pos == size-2 ) {
976 res1 = LDAP_REALLOC(res,size*sizeof(char *));
980 *code = LDAP_SCHERR_OUTOFMEM;
988 *code = LDAP_SCHERR_UNEXPTOKEN;
995 *code = LDAP_SCHERR_UNEXPTOKEN;
1004 } else if ( kind == TK_BAREWORD ||
1005 ( allow_quoted && kind == TK_QDSTRING ) ) {
1006 res = LDAP_CALLOC(2,sizeof(char *));
1009 *code = LDAP_SCHERR_OUTOFMEM;
1018 *code = LDAP_SCHERR_BADNAME;
1024 add_extension(LDAPSchemaExtensionItem ***extensions,
1025 char * name, char ** values)
1028 LDAPSchemaExtensionItem **tmp, *ext;
1030 ext = LDAP_CALLOC(1, sizeof(LDAPSchemaExtensionItem));
1033 ext->lsei_name = name;
1034 ext->lsei_values = values;
1036 if ( !*extensions ) {
1038 LDAP_CALLOC(2, sizeof(LDAPSchemaExtensionItem *));
1043 for ( n=0; (*extensions)[n] != NULL; n++ )
1045 tmp = LDAP_REALLOC(*extensions,
1046 (n+2)*sizeof(LDAPSchemaExtensionItem *));
1051 (*extensions)[n] = ext;
1052 (*extensions)[n+1] = NULL;
1057 free_extensions(LDAPSchemaExtensionItem **extensions)
1059 LDAPSchemaExtensionItem **ext;
1062 for ( ext = extensions; *ext != NULL; ext++ ) {
1063 LDAP_FREE((*ext)->lsei_name);
1064 LDAP_VFREE((*ext)->lsei_values);
1067 LDAP_FREE(extensions);
1072 ldap_syntax_free( LDAPSyntax * syn )
1074 LDAP_FREE(syn->syn_oid);
1075 LDAP_VFREE(syn->syn_names);
1076 LDAP_FREE(syn->syn_desc);
1077 free_extensions(syn->syn_extensions);
1082 ldap_str2syntax( const char * s, int * code, const char ** errp, const int flags )
1085 const char * ss = s;
1093 *code = LDAP_SCHERR_EMPTY;
1099 syn = LDAP_CALLOC(1,sizeof(LDAPSyntax));
1102 *code = LDAP_SCHERR_OUTOFMEM;
1106 kind = get_token(&ss,&sval);
1107 if ( kind != TK_LEFTPAREN ) {
1109 *code = LDAP_SCHERR_NOLEFTPAREN;
1110 ldap_syntax_free(syn);
1115 syn->syn_oid = parse_numericoid(&ss,code,0);
1116 if ( !syn->syn_oid ) {
1118 ldap_syntax_free(syn);
1124 * Beyond this point we will be liberal and accept the items
1128 kind = get_token(&ss,&sval);
1131 *code = LDAP_SCHERR_NORIGHTPAREN;
1133 ldap_syntax_free(syn);
1138 if ( !strcmp(sval,"NAME") ) {
1141 *code = LDAP_SCHERR_DUPOPT;
1143 ldap_syntax_free(syn);
1147 syn->syn_names = parse_qdescrs(&ss,code);
1148 if ( !syn->syn_names ) {
1149 if ( *code != LDAP_SCHERR_OUTOFMEM )
1150 *code = LDAP_SCHERR_BADNAME;
1152 ldap_syntax_free(syn);
1155 } else if ( !strcmp(sval,"DESC") ) {
1158 *code = LDAP_SCHERR_DUPOPT;
1160 ldap_syntax_free(syn);
1165 kind = get_token(&ss,&sval);
1166 if ( kind != TK_QDSTRING ) {
1167 *code = LDAP_SCHERR_UNEXPTOKEN;
1170 ldap_syntax_free(syn);
1173 syn->syn_desc = sval;
1175 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1176 /* Should be parse_qdstrings */
1177 ext_vals = parse_qdescrs(&ss, code);
1180 ldap_syntax_free(syn);
1183 if ( add_extension(&syn->syn_extensions,
1185 *code = LDAP_SCHERR_OUTOFMEM;
1188 ldap_syntax_free(syn);
1192 *code = LDAP_SCHERR_UNEXPTOKEN;
1195 ldap_syntax_free(syn);
1200 *code = LDAP_SCHERR_UNEXPTOKEN;
1203 ldap_syntax_free(syn);
1210 ldap_matchingrule_free( LDAPMatchingRule * mr )
1212 LDAP_FREE(mr->mr_oid);
1213 LDAP_VFREE(mr->mr_names);
1214 LDAP_FREE(mr->mr_desc);
1215 LDAP_FREE(mr->mr_syntax_oid);
1216 free_extensions(mr->mr_extensions);
1221 ldap_str2matchingrule( const char * s, int * code, const char ** errp, const int flags )
1224 const char * ss = s;
1228 int seen_obsolete = 0;
1229 int seen_syntax = 0;
1230 LDAPMatchingRule * mr;
1232 const char * savepos;
1235 *code = LDAP_SCHERR_EMPTY;
1241 mr = LDAP_CALLOC(1,sizeof(LDAPMatchingRule));
1244 *code = LDAP_SCHERR_OUTOFMEM;
1248 kind = get_token(&ss,&sval);
1249 if ( kind != TK_LEFTPAREN ) {
1250 *code = LDAP_SCHERR_NOLEFTPAREN;
1252 ldap_matchingrule_free(mr);
1258 mr->mr_oid = parse_numericoid(&ss,code,flags);
1259 if ( !mr->mr_oid ) {
1260 if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
1263 kind = get_token(&ss,&sval);
1264 if ( kind == TK_BAREWORD ) {
1265 if ( !strcmp(sval, "NAME") ||
1266 !strcmp(sval, "DESC") ||
1267 !strcmp(sval, "OBSOLETE") ||
1268 !strcmp(sval, "SYNTAX") ||
1269 !strncmp(sval, "X-", 2) ) {
1270 /* Missing OID, backtrack */
1273 /* Non-numerical OID, ignore */
1279 ldap_matchingrule_free(mr);
1286 * Beyond this point we will be liberal and accept the items
1290 kind = get_token(&ss,&sval);
1293 *code = LDAP_SCHERR_NORIGHTPAREN;
1295 ldap_matchingrule_free(mr);
1300 if ( !strcmp(sval,"NAME") ) {
1303 *code = LDAP_SCHERR_DUPOPT;
1305 ldap_matchingrule_free(mr);
1309 mr->mr_names = parse_qdescrs(&ss,code);
1310 if ( !mr->mr_names ) {
1311 if ( *code != LDAP_SCHERR_OUTOFMEM )
1312 *code = LDAP_SCHERR_BADNAME;
1314 ldap_matchingrule_free(mr);
1317 } else if ( !strcmp(sval,"DESC") ) {
1320 *code = LDAP_SCHERR_DUPOPT;
1322 ldap_matchingrule_free(mr);
1327 kind = get_token(&ss,&sval);
1328 if ( kind != TK_QDSTRING ) {
1329 *code = LDAP_SCHERR_UNEXPTOKEN;
1332 ldap_matchingrule_free(mr);
1337 } else if ( !strcmp(sval,"OBSOLETE") ) {
1339 if ( seen_obsolete ) {
1340 *code = LDAP_SCHERR_DUPOPT;
1342 ldap_matchingrule_free(mr);
1346 mr->mr_obsolete = LDAP_SCHEMA_YES;
1348 } else if ( !strcmp(sval,"SYNTAX") ) {
1350 if ( seen_syntax ) {
1351 *code = LDAP_SCHERR_DUPOPT;
1353 ldap_matchingrule_free(mr);
1359 parse_numericoid(&ss,code,flags);
1360 if ( !mr->mr_syntax_oid ) {
1362 ldap_matchingrule_free(mr);
1366 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1367 /* Should be parse_qdstrings */
1368 ext_vals = parse_qdescrs(&ss, code);
1371 ldap_matchingrule_free(mr);
1374 if ( add_extension(&mr->mr_extensions,
1376 *code = LDAP_SCHERR_OUTOFMEM;
1379 ldap_matchingrule_free(mr);
1383 *code = LDAP_SCHERR_UNEXPTOKEN;
1386 ldap_matchingrule_free(mr);
1391 *code = LDAP_SCHERR_UNEXPTOKEN;
1394 ldap_matchingrule_free(mr);
1401 ldap_matchingruleuse_free( LDAPMatchingRuleUse * mru )
1403 LDAP_FREE(mru->mru_oid);
1404 LDAP_VFREE(mru->mru_names);
1405 LDAP_FREE(mru->mru_desc);
1406 LDAP_VFREE(mru->mru_applies_oids);
1407 free_extensions(mru->mru_extensions);
1411 LDAPMatchingRuleUse *
1412 ldap_str2matchingruleuse( const char * s, int * code, const char ** errp, const int flags )
1415 const char * ss = s;
1419 int seen_obsolete = 0;
1420 int seen_applies = 0;
1421 LDAPMatchingRuleUse * mru;
1423 const char * savepos;
1426 *code = LDAP_SCHERR_EMPTY;
1432 mru = LDAP_CALLOC(1,sizeof(LDAPMatchingRuleUse));
1435 *code = LDAP_SCHERR_OUTOFMEM;
1439 kind = get_token(&ss,&sval);
1440 if ( kind != TK_LEFTPAREN ) {
1441 *code = LDAP_SCHERR_NOLEFTPAREN;
1443 ldap_matchingruleuse_free(mru);
1449 mru->mru_oid = parse_numericoid(&ss,code,flags);
1450 if ( !mru->mru_oid ) {
1451 if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
1454 kind = get_token(&ss,&sval);
1455 if ( kind == TK_BAREWORD ) {
1456 if ( !strcmp(sval, "NAME") ||
1457 !strcmp(sval, "DESC") ||
1458 !strcmp(sval, "OBSOLETE") ||
1459 !strcmp(sval, "APPLIES") ||
1460 !strncmp(sval, "X-", 2) ) {
1461 /* Missing OID, backtrack */
1464 /* Non-numerical OID, ignore */
1470 ldap_matchingruleuse_free(mru);
1477 * Beyond this point we will be liberal and accept the items
1481 kind = get_token(&ss,&sval);
1484 *code = LDAP_SCHERR_NORIGHTPAREN;
1486 ldap_matchingruleuse_free(mru);
1491 if ( !strcmp(sval,"NAME") ) {
1494 *code = LDAP_SCHERR_DUPOPT;
1496 ldap_matchingruleuse_free(mru);
1500 mru->mru_names = parse_qdescrs(&ss,code);
1501 if ( !mru->mru_names ) {
1502 if ( *code != LDAP_SCHERR_OUTOFMEM )
1503 *code = LDAP_SCHERR_BADNAME;
1505 ldap_matchingruleuse_free(mru);
1508 } else if ( !strcmp(sval,"DESC") ) {
1511 *code = LDAP_SCHERR_DUPOPT;
1513 ldap_matchingruleuse_free(mru);
1518 kind = get_token(&ss,&sval);
1519 if ( kind != TK_QDSTRING ) {
1520 *code = LDAP_SCHERR_UNEXPTOKEN;
1523 ldap_matchingruleuse_free(mru);
1526 mru->mru_desc = sval;
1528 } else if ( !strcmp(sval,"OBSOLETE") ) {
1530 if ( seen_obsolete ) {
1531 *code = LDAP_SCHERR_DUPOPT;
1533 ldap_matchingruleuse_free(mru);
1537 mru->mru_obsolete = LDAP_SCHEMA_YES;
1539 } else if ( !strcmp(sval,"APPLIES") ) {
1541 if ( seen_applies ) {
1542 *code = LDAP_SCHERR_DUPOPT;
1544 ldap_matchingruleuse_free(mru);
1548 mru->mru_applies_oids = parse_oids(&ss,
1551 if ( !mru->mru_applies_oids ) {
1553 ldap_matchingruleuse_free(mru);
1556 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1557 /* Should be parse_qdstrings */
1558 ext_vals = parse_qdescrs(&ss, code);
1561 ldap_matchingruleuse_free(mru);
1564 if ( add_extension(&mru->mru_extensions,
1566 *code = LDAP_SCHERR_OUTOFMEM;
1569 ldap_matchingruleuse_free(mru);
1573 *code = LDAP_SCHERR_UNEXPTOKEN;
1576 ldap_matchingruleuse_free(mru);
1581 *code = LDAP_SCHERR_UNEXPTOKEN;
1584 ldap_matchingruleuse_free(mru);
1591 ldap_attributetype_free(LDAPAttributeType * at)
1593 LDAP_FREE(at->at_oid);
1594 LDAP_VFREE(at->at_names);
1595 LDAP_FREE(at->at_desc);
1596 LDAP_FREE(at->at_sup_oid);
1597 LDAP_FREE(at->at_equality_oid);
1598 LDAP_FREE(at->at_ordering_oid);
1599 LDAP_FREE(at->at_substr_oid);
1600 LDAP_FREE(at->at_syntax_oid);
1601 free_extensions(at->at_extensions);
1606 ldap_str2attributetype( const char * s, int * code, const char ** errp, const int flags )
1609 const char * ss = s;
1613 int seen_obsolete = 0;
1615 int seen_equality = 0;
1616 int seen_ordering = 0;
1617 int seen_substr = 0;
1618 int seen_syntax = 0;
1620 LDAPAttributeType * at;
1622 const char * savepos;
1625 *code = LDAP_SCHERR_EMPTY;
1631 at = LDAP_CALLOC(1,sizeof(LDAPAttributeType));
1634 *code = LDAP_SCHERR_OUTOFMEM;
1638 kind = get_token(&ss,&sval);
1639 if ( kind != TK_LEFTPAREN ) {
1640 *code = LDAP_SCHERR_NOLEFTPAREN;
1642 ldap_attributetype_free(at);
1647 * Definitions MUST begin with an OID in the numericoid format.
1648 * However, this routine is used by clients to parse the response
1649 * from servers and very well known servers will provide an OID
1650 * in the wrong format or even no OID at all. We do our best to
1651 * extract info from those servers.
1655 at->at_oid = parse_numericoid(&ss,code,0);
1656 if ( !at->at_oid ) {
1657 if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
1660 kind = get_token(&ss,&sval);
1661 if ( kind == TK_BAREWORD ) {
1662 if ( !strcmp(sval, "NAME") ||
1663 !strcmp(sval, "DESC") ||
1664 !strcmp(sval, "OBSOLETE") ||
1665 !strcmp(sval, "SUP") ||
1666 !strcmp(sval, "EQUALITY") ||
1667 !strcmp(sval, "ORDERING") ||
1668 !strcmp(sval, "SUBSTR") ||
1669 !strcmp(sval, "SYNTAX") ||
1670 !strcmp(sval, "SINGLE-VALUE") ||
1671 !strcmp(sval, "COLLECTIVE") ||
1672 !strcmp(sval, "NO-USER-MODIFICATION") ||
1673 !strcmp(sval, "USAGE") ||
1674 !strncmp(sval, "X-", 2) ) {
1675 /* Missing OID, backtrack */
1678 /* Non-numerical OID, ignore */
1684 ldap_attributetype_free(at);
1691 * Beyond this point we will be liberal and accept the items
1695 kind = get_token(&ss,&sval);
1698 *code = LDAP_SCHERR_NORIGHTPAREN;
1700 ldap_attributetype_free(at);
1705 if ( !strcmp(sval,"NAME") ) {
1708 *code = LDAP_SCHERR_DUPOPT;
1710 ldap_attributetype_free(at);
1714 at->at_names = parse_qdescrs(&ss,code);
1715 if ( !at->at_names ) {
1716 if ( *code != LDAP_SCHERR_OUTOFMEM )
1717 *code = LDAP_SCHERR_BADNAME;
1719 ldap_attributetype_free(at);
1722 } else if ( !strcmp(sval,"DESC") ) {
1725 *code = LDAP_SCHERR_DUPOPT;
1727 ldap_attributetype_free(at);
1732 kind = get_token(&ss,&sval);
1733 if ( kind != TK_QDSTRING ) {
1734 *code = LDAP_SCHERR_UNEXPTOKEN;
1737 ldap_attributetype_free(at);
1742 } else if ( !strcmp(sval,"OBSOLETE") ) {
1744 if ( seen_obsolete ) {
1745 *code = LDAP_SCHERR_DUPOPT;
1747 ldap_attributetype_free(at);
1751 at->at_obsolete = LDAP_SCHEMA_YES;
1753 } else if ( !strcmp(sval,"SUP") ) {
1756 *code = LDAP_SCHERR_DUPOPT;
1758 ldap_attributetype_free(at);
1762 at->at_sup_oid = parse_woid(&ss,code);
1763 if ( !at->at_sup_oid ) {
1765 ldap_attributetype_free(at);
1768 } else if ( !strcmp(sval,"EQUALITY") ) {
1770 if ( seen_equality ) {
1771 *code = LDAP_SCHERR_DUPOPT;
1773 ldap_attributetype_free(at);
1777 at->at_equality_oid = parse_woid(&ss,code);
1778 if ( !at->at_equality_oid ) {
1780 ldap_attributetype_free(at);
1783 } else if ( !strcmp(sval,"ORDERING") ) {
1785 if ( seen_ordering ) {
1786 *code = LDAP_SCHERR_DUPOPT;
1788 ldap_attributetype_free(at);
1792 at->at_ordering_oid = parse_woid(&ss,code);
1793 if ( !at->at_ordering_oid ) {
1795 ldap_attributetype_free(at);
1798 } else if ( !strcmp(sval,"SUBSTR") ) {
1800 if ( seen_substr ) {
1801 *code = LDAP_SCHERR_DUPOPT;
1803 ldap_attributetype_free(at);
1807 at->at_substr_oid = parse_woid(&ss,code);
1808 if ( !at->at_substr_oid ) {
1810 ldap_attributetype_free(at);
1813 } else if ( !strcmp(sval,"SYNTAX") ) {
1815 if ( seen_syntax ) {
1816 *code = LDAP_SCHERR_DUPOPT;
1818 ldap_attributetype_free(at);
1828 if ( !at->at_syntax_oid ) {
1830 ldap_attributetype_free(at);
1834 } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
1836 if ( at->at_single_value ) {
1837 *code = LDAP_SCHERR_DUPOPT;
1839 ldap_attributetype_free(at);
1842 at->at_single_value = LDAP_SCHEMA_YES;
1844 } else if ( !strcmp(sval,"COLLECTIVE") ) {
1846 if ( at->at_collective ) {
1847 *code = LDAP_SCHERR_DUPOPT;
1849 ldap_attributetype_free(at);
1852 at->at_collective = LDAP_SCHEMA_YES;
1854 } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
1856 if ( at->at_no_user_mod ) {
1857 *code = LDAP_SCHERR_DUPOPT;
1859 ldap_attributetype_free(at);
1862 at->at_no_user_mod = LDAP_SCHEMA_YES;
1864 } else if ( !strcmp(sval,"USAGE") ) {
1867 *code = LDAP_SCHERR_DUPOPT;
1869 ldap_attributetype_free(at);
1874 kind = get_token(&ss,&sval);
1875 if ( kind != TK_BAREWORD ) {
1876 *code = LDAP_SCHERR_UNEXPTOKEN;
1879 ldap_attributetype_free(at);
1882 if ( !strcasecmp(sval,"userApplications") )
1884 LDAP_SCHEMA_USER_APPLICATIONS;
1885 else if ( !strcasecmp(sval,"directoryOperation") )
1887 LDAP_SCHEMA_DIRECTORY_OPERATION;
1888 else if ( !strcasecmp(sval,"distributedOperation") )
1890 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
1891 else if ( !strcasecmp(sval,"dSAOperation") )
1893 LDAP_SCHEMA_DSA_OPERATION;
1895 *code = LDAP_SCHERR_UNEXPTOKEN;
1898 ldap_attributetype_free(at);
1903 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1904 /* Should be parse_qdstrings */
1905 ext_vals = parse_qdescrs(&ss, code);
1908 ldap_attributetype_free(at);
1911 if ( add_extension(&at->at_extensions,
1913 *code = LDAP_SCHERR_OUTOFMEM;
1916 ldap_attributetype_free(at);
1920 *code = LDAP_SCHERR_UNEXPTOKEN;
1923 ldap_attributetype_free(at);
1928 *code = LDAP_SCHERR_UNEXPTOKEN;
1931 ldap_attributetype_free(at);
1938 ldap_objectclass_free(LDAPObjectClass * oc)
1940 LDAP_FREE(oc->oc_oid);
1941 LDAP_VFREE(oc->oc_names);
1942 LDAP_FREE(oc->oc_desc);
1943 LDAP_VFREE(oc->oc_sup_oids);
1944 LDAP_VFREE(oc->oc_at_oids_must);
1945 LDAP_VFREE(oc->oc_at_oids_may);
1946 free_extensions(oc->oc_extensions);
1951 ldap_str2objectclass( const char * s, int * code, const char ** errp, const int flags )
1954 const char * ss = s;
1958 int seen_obsolete = 0;
1963 LDAPObjectClass * oc;
1965 const char * savepos;
1968 *code = LDAP_SCHERR_EMPTY;
1974 oc = LDAP_CALLOC(1,sizeof(LDAPObjectClass));
1977 *code = LDAP_SCHERR_OUTOFMEM;
1981 kind = get_token(&ss,&sval);
1982 if ( kind != TK_LEFTPAREN ) {
1983 *code = LDAP_SCHERR_NOLEFTPAREN;
1985 ldap_objectclass_free(oc);
1990 * Definitions MUST begin with an OID in the numericoid format.
1991 * However, this routine is used by clients to parse the response
1992 * from servers and very well known servers will provide an OID
1993 * in the wrong format or even no OID at all. We do our best to
1994 * extract info from those servers.
1998 oc->oc_oid = parse_numericoid(&ss,code,0);
1999 if ( !oc->oc_oid ) {
2000 if ( flags & LDAP_SCHEMA_ALLOW_ALL ) {
2003 kind = get_token(&ss,&sval);
2004 if ( kind == TK_BAREWORD ) {
2005 if ( !strcmp(sval, "NAME") ||
2006 !strcmp(sval, "DESC") ||
2007 !strcmp(sval, "OBSOLETE") ||
2008 !strcmp(sval, "SUP") ||
2009 !strcmp(sval, "ABSTRACT") ||
2010 !strcmp(sval, "STRUCTURAL") ||
2011 !strcmp(sval, "AUXILIARY") ||
2012 !strcmp(sval, "MUST") ||
2013 !strncmp(sval, "X-", 2) ) {
2014 /* Missing OID, backtrack */
2017 /* Non-numerical OID, ignore */
2023 ldap_objectclass_free(oc);
2030 * Beyond this point we will be liberal an accept the items
2034 kind = get_token(&ss,&sval);
2037 *code = LDAP_SCHERR_NORIGHTPAREN;
2039 ldap_objectclass_free(oc);
2044 if ( !strcmp(sval,"NAME") ) {
2047 *code = LDAP_SCHERR_DUPOPT;
2049 ldap_objectclass_free(oc);
2053 oc->oc_names = parse_qdescrs(&ss,code);
2054 if ( !oc->oc_names ) {
2055 if ( *code != LDAP_SCHERR_OUTOFMEM )
2056 *code = LDAP_SCHERR_BADNAME;
2058 ldap_objectclass_free(oc);
2061 } else if ( !strcmp(sval,"DESC") ) {
2064 *code = LDAP_SCHERR_DUPOPT;
2066 ldap_objectclass_free(oc);
2071 kind = get_token(&ss,&sval);
2072 if ( kind != TK_QDSTRING ) {
2073 *code = LDAP_SCHERR_UNEXPTOKEN;
2076 ldap_objectclass_free(oc);
2081 } else if ( !strcmp(sval,"OBSOLETE") ) {
2083 if ( seen_obsolete ) {
2084 *code = LDAP_SCHERR_DUPOPT;
2086 ldap_objectclass_free(oc);
2090 oc->oc_obsolete = LDAP_SCHEMA_YES;
2092 } else if ( !strcmp(sval,"SUP") ) {
2095 *code = LDAP_SCHERR_DUPOPT;
2097 ldap_objectclass_free(oc);
2101 oc->oc_sup_oids = parse_oids(&ss,
2104 if ( !oc->oc_sup_oids ) {
2106 ldap_objectclass_free(oc);
2109 } else if ( !strcmp(sval,"ABSTRACT") ) {
2112 *code = LDAP_SCHERR_DUPOPT;
2114 ldap_objectclass_free(oc);
2118 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
2120 } else if ( !strcmp(sval,"STRUCTURAL") ) {
2123 *code = LDAP_SCHERR_DUPOPT;
2125 ldap_objectclass_free(oc);
2129 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
2131 } else if ( !strcmp(sval,"AUXILIARY") ) {
2134 *code = LDAP_SCHERR_DUPOPT;
2136 ldap_objectclass_free(oc);
2140 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
2142 } else if ( !strcmp(sval,"MUST") ) {
2145 *code = LDAP_SCHERR_DUPOPT;
2147 ldap_objectclass_free(oc);
2151 oc->oc_at_oids_must = parse_oids(&ss,code,0);
2152 if ( !oc->oc_at_oids_must ) {
2154 ldap_objectclass_free(oc);
2158 } else if ( !strcmp(sval,"MAY") ) {
2161 *code = LDAP_SCHERR_DUPOPT;
2163 ldap_objectclass_free(oc);
2167 oc->oc_at_oids_may = parse_oids(&ss,code,0);
2168 if ( !oc->oc_at_oids_may ) {
2170 ldap_objectclass_free(oc);
2174 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
2175 /* Should be parse_qdstrings */
2176 ext_vals = parse_qdescrs(&ss, code);
2179 ldap_objectclass_free(oc);
2182 if ( add_extension(&oc->oc_extensions,
2184 *code = LDAP_SCHERR_OUTOFMEM;
2187 ldap_objectclass_free(oc);
2191 *code = LDAP_SCHERR_UNEXPTOKEN;
2194 ldap_objectclass_free(oc);
2199 *code = LDAP_SCHERR_UNEXPTOKEN;
2202 ldap_objectclass_free(oc);
2208 static char *const err2text[] = {
2212 "Missing opening parenthesis",
2213 "Missing closing parenthesis",
2219 "Unexpected end of data"
2223 ldap_scherr2str(int code)
2225 if ( code < 0 || code >= (sizeof(err2text)/sizeof(char *)) ) {
2226 return "Unknown error";
2228 return err2text[code];