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_attributetype2name( LDAPAttributeType * at )
44 return( choose_name( at->at_names, at->at_oid ) );
48 ldap_objectclass2name( LDAPObjectClass * oc )
50 return( choose_name( oc->oc_names, oc->oc_oid ) );
55 * When pretty printing the entities we will be appending to a buffer.
56 * Since checking for overflow, realloc'ing and checking if no error
57 * is extremely boring, we will use a protection layer that will let
58 * us blissfully ignore the error until the end. This layer is
59 * implemented with the help of the next type.
62 typedef struct safe_string {
70 new_safe_string(int size)
74 ss = LDAP_MALLOC(sizeof(safe_string));
78 ss->val = LDAP_MALLOC(size);
92 safe_string_free(safe_string * ss)
101 safe_string_val(safe_string * ss)
103 ss->val[ss->pos] = '\0';
108 append_to_safe_string(safe_string * ss, char * s)
114 * Some runaway process is trying to append to a string that
115 * overflowed and we could not extend.
120 /* We always make sure there is at least one position available */
121 if ( ss->pos + l >= ss->size-1 ) {
123 if ( ss->pos + l >= ss->size-1 ) {
124 ss->size = ss->pos + l + 1;
127 temp = LDAP_REALLOC(ss->val, ss->size);
129 /* Trouble, out of memory */
135 strncpy(&ss->val[ss->pos], s, l);
137 if ( ss->pos > 0 && LDAP_SPACE(ss->val[ss->pos-1]) )
146 print_literal(safe_string *ss, char *s)
148 return(append_to_safe_string(ss,s));
152 print_whsp(safe_string *ss)
155 return(append_to_safe_string(ss,""));
157 return(append_to_safe_string(ss," "));
161 print_numericoid(safe_string *ss, char *s)
164 return(append_to_safe_string(ss,s));
166 return(append_to_safe_string(ss,""));
169 /* This one is identical to print_qdescr */
171 print_qdstring(safe_string *ss, char *s)
174 print_literal(ss,"'");
175 append_to_safe_string(ss,s);
176 print_literal(ss,"'");
177 return(print_whsp(ss));
181 print_qdescr(safe_string *ss, char *s)
184 print_literal(ss,"'");
185 append_to_safe_string(ss,s);
186 print_literal(ss,"'");
187 return(print_whsp(ss));
191 print_qdescrlist(safe_string *ss, char **sa)
196 for (sp=sa; *sp; sp++) {
197 ret = print_qdescr(ss,*sp);
199 /* If the list was empty, we return zero that is potentially
200 * incorrect, but since we will be still appending things, the
201 * overflow will be detected later. Maybe FIX.
207 print_qdescrs(safe_string *ss, char **sa)
209 /* The only way to represent an empty list is as a qdescrlist
210 * so, if the list is empty we treat it as a long list.
211 * Really, this is what the syntax mandates. We should not
212 * be here if the list was empty, but if it happens, a label
213 * has already been output and we cannot undo it.
215 if ( !sa[0] || ( sa[0] && sa[1] ) ) {
217 print_literal(ss,"("/*)*/);
218 print_qdescrlist(ss,sa);
219 print_literal(ss,/*(*/")");
220 return(print_whsp(ss));
222 return(print_qdescr(ss,*sa));
227 print_woid(safe_string *ss, char *s)
230 append_to_safe_string(ss,s);
231 return print_whsp(ss);
235 print_oidlist(safe_string *ss, char **sa)
239 for (sp=sa; *(sp+1); sp++) {
241 print_literal(ss,"$");
243 return(print_woid(ss,*sp));
247 print_oids(safe_string *ss, char **sa)
249 if ( sa[0] && sa[1] ) {
250 print_literal(ss,"("/*)*/);
251 print_oidlist(ss,sa);
253 return(print_literal(ss,/*(*/")"));
255 return(print_woid(ss,*sa));
260 print_noidlen(safe_string *ss, char *s, int l)
265 ret = print_numericoid(ss,s);
267 sprintf(buf,"{%d}",l);
268 ret = print_literal(ss,buf);
274 print_extensions(safe_string *ss, LDAPSchemaExtensionItem **extensions)
276 LDAPSchemaExtensionItem **ext;
280 for ( ext = extensions; *ext != NULL; ext++ ) {
281 print_literal(ss, (*ext)->lsei_name);
283 /* Should be print_qdstrings */
284 print_qdescrs(ss, (*ext)->lsei_values);
293 ldap_syntax2str( const LDAPSyntax * syn )
298 ss = new_safe_string(256);
302 print_literal(ss,"("/*)*/);
305 print_numericoid(ss, syn->syn_oid);
308 if ( syn->syn_desc ) {
309 print_literal(ss,"DESC");
310 print_qdstring(ss,syn->syn_desc);
315 print_extensions(ss, syn->syn_extensions);
317 print_literal(ss,/*(*/ ")");
319 retstring = LDAP_STRDUP(safe_string_val(ss));
320 safe_string_free(ss);
325 ldap_matchingrule2str( const LDAPMatchingRule * mr )
330 ss = new_safe_string(256);
334 print_literal(ss,"(" /*)*/);
337 print_numericoid(ss, mr->mr_oid);
340 if ( mr->mr_names ) {
341 print_literal(ss,"NAME");
342 print_qdescrs(ss,mr->mr_names);
346 print_literal(ss,"DESC");
347 print_qdstring(ss,mr->mr_desc);
350 if ( mr->mr_obsolete == LDAP_SCHEMA_YES ) {
351 print_literal(ss, "OBSOLETE");
355 if ( mr->mr_syntax_oid ) {
356 print_literal(ss,"SYNTAX");
358 print_literal(ss, mr->mr_syntax_oid);
364 print_extensions(ss, mr->mr_extensions);
366 print_literal(ss,/*(*/")");
368 retstring = LDAP_STRDUP(safe_string_val(ss));
369 safe_string_free(ss);
374 ldap_objectclass2str( const LDAPObjectClass * oc )
379 ss = new_safe_string(256);
383 print_literal(ss,"("/*)*/);
386 print_numericoid(ss, oc->oc_oid);
389 if ( oc->oc_names ) {
390 print_literal(ss,"NAME");
391 print_qdescrs(ss,oc->oc_names);
395 print_literal(ss,"DESC");
396 print_qdstring(ss,oc->oc_desc);
399 if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) {
400 print_literal(ss, "OBSOLETE");
404 if ( oc->oc_sup_oids ) {
405 print_literal(ss,"SUP");
407 print_oids(ss,oc->oc_sup_oids);
411 switch (oc->oc_kind) {
412 case LDAP_SCHEMA_ABSTRACT:
413 print_literal(ss,"ABSTRACT");
415 case LDAP_SCHEMA_STRUCTURAL:
416 print_literal(ss,"STRUCTURAL");
418 case LDAP_SCHEMA_AUXILIARY:
419 print_literal(ss,"AUXILIARY");
422 print_literal(ss,"KIND-UNKNOWN");
427 if ( oc->oc_at_oids_must ) {
428 print_literal(ss,"MUST");
430 print_oids(ss,oc->oc_at_oids_must);
434 if ( oc->oc_at_oids_may ) {
435 print_literal(ss,"MAY");
437 print_oids(ss,oc->oc_at_oids_may);
443 print_extensions(ss, oc->oc_extensions);
445 print_literal(ss, /*(*/")");
447 retstring = LDAP_STRDUP(safe_string_val(ss));
448 safe_string_free(ss);
453 ldap_attributetype2str( const LDAPAttributeType * at )
458 ss = new_safe_string(256);
462 print_literal(ss,"("/*)*/);
465 print_numericoid(ss, at->at_oid);
468 if ( at->at_names ) {
469 print_literal(ss,"NAME");
470 print_qdescrs(ss,at->at_names);
474 print_literal(ss,"DESC");
475 print_qdstring(ss,at->at_desc);
478 if ( at->at_obsolete == LDAP_SCHEMA_YES ) {
479 print_literal(ss, "OBSOLETE");
483 if ( at->at_sup_oid ) {
484 print_literal(ss,"SUP");
485 print_woid(ss,at->at_sup_oid);
488 if ( at->at_equality_oid ) {
489 print_literal(ss,"EQUALITY");
490 print_woid(ss,at->at_equality_oid);
493 if ( at->at_ordering_oid ) {
494 print_literal(ss,"ORDERING");
495 print_woid(ss,at->at_ordering_oid);
498 if ( at->at_substr_oid ) {
499 print_literal(ss,"SUBSTR");
500 print_woid(ss,at->at_substr_oid);
503 if ( at->at_syntax_oid ) {
504 print_literal(ss,"SYNTAX");
506 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
510 if ( at->at_single_value == LDAP_SCHEMA_YES ) {
511 print_literal(ss,"SINGLE-VALUE");
515 if ( at->at_collective == LDAP_SCHEMA_YES ) {
516 print_literal(ss,"COLLECTIVE");
520 if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
521 print_literal(ss,"NO-USER-MODIFICATION");
525 if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
526 print_literal(ss,"USAGE");
528 switch (at->at_usage) {
529 case LDAP_SCHEMA_DIRECTORY_OPERATION:
530 print_literal(ss,"directoryOperation");
532 case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
533 print_literal(ss,"distributedOperation");
535 case LDAP_SCHEMA_DSA_OPERATION:
536 print_literal(ss,"dSAOperation");
539 print_literal(ss,"UNKNOWN");
546 print_extensions(ss, at->at_extensions);
548 print_literal(ss,/*(*/")");
550 retstring = LDAP_STRDUP(safe_string_val(ss));
551 safe_string_free(ss);
556 * Now come the parsers. There is one parser for each entity type:
557 * objectclasses, attributetypes, etc.
559 * Each of them is written as a recursive-descent parser, except that
560 * none of them is really recursive. But the idea is kept: there
561 * is one routine per non-terminal that eithers gobbles lexical tokens
562 * or calls lower-level routines, etc.
564 * The scanner is implemented in the routine get_token. Actually,
565 * get_token is more than a scanner and will return tokens that are
566 * in fact non-terminals in the grammar. So you can see the whole
567 * approach as the combination of a low-level bottom-up recognizer
568 * combined with a scanner and a number of top-down parsers. Or just
569 * consider that the real grammars recognized by the parsers are not
570 * those of the standards. As a matter of fact, our parsers are more
571 * liberal than the spec when there is no ambiguity.
573 * The difference is pretty academic (modulo bugs or incorrect
574 * interpretation of the specs).
577 #define TK_NOENDQUOTE -2
578 #define TK_OUTOFMEM -1
580 #define TK_UNEXPCHAR 1
581 #define TK_BAREWORD 2
582 #define TK_QDSTRING 3
583 #define TK_LEFTPAREN 4
584 #define TK_RIGHTPAREN 5
586 #define TK_QDESCR TK_QDSTRING
594 get_token(const char ** sp, char ** token_val)
612 kind = TK_RIGHTPAREN;
623 while ( **sp != '\'' && **sp != '\0' )
625 if ( **sp == '\'' ) {
627 res = LDAP_MALLOC(q-p+1);
637 kind = TK_NOENDQUOTE;
643 while ( !LDAP_SPACE(**sp) &&
651 res = LDAP_MALLOC(q-p+1);
660 /* kind = TK_UNEXPCHAR; */
667 /* Gobble optional whitespace */
669 parse_whsp(const char **sp)
671 while (LDAP_SPACE(**sp))
676 * General note for all parsers: to guarantee the algorithm halts they
677 * must always advance the pointer even when an error is found. For
678 * this one is not that important since an error here is fatal at the
679 * upper layers, but it is a simple strategy that will not get in
683 /* Parse a sequence of dot-separated decimal strings */
685 parse_numericoid(const char **sp, int *code, const int flags)
688 const char * start = *sp;
692 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
693 if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && **sp == '\'' ) {
698 /* Each iteration of this loop gets one decimal string */
700 if ( !LDAP_DIGIT(**sp) ) {
702 * Initial char is not a digit or char after dot is
705 *code = LDAP_SCHERR_NODIGIT;
709 while ( LDAP_DIGIT(**sp) )
713 /* Otherwise, gobble the dot and loop again */
716 /* Now *sp points at the char past the numericoid. Perfect. */
718 res = LDAP_MALLOC(len+1);
720 *code = LDAP_SCHERR_OUTOFMEM;
723 strncpy(res,start,len);
725 if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && quoted ) {
726 if ( **sp == '\'' ) {
729 *code = LDAP_SCHERR_UNEXPTOKEN;
737 /* Parse a qdescr or a list of them enclosed in () */
739 parse_qdescrs(const char **sp, int *code)
749 kind = get_token(sp,&sval);
750 if ( kind == TK_LEFTPAREN ) {
751 /* Let's presume there will be at least 2 entries */
753 res = LDAP_CALLOC(3,sizeof(char *));
755 *code = LDAP_SCHERR_OUTOFMEM;
761 kind = get_token(sp,&sval);
762 if ( kind == TK_RIGHTPAREN )
764 if ( kind == TK_QDESCR ) {
765 if ( pos == size-2 ) {
767 res1 = LDAP_REALLOC(res,size*sizeof(char *));
771 *code = LDAP_SCHERR_OUTOFMEM;
782 *code = LDAP_SCHERR_UNEXPTOKEN;
789 } else if ( kind == TK_QDESCR ) {
790 res = LDAP_CALLOC(2,sizeof(char *));
792 *code = LDAP_SCHERR_OUTOFMEM;
801 *code = LDAP_SCHERR_BADNAME;
808 parse_woid(const char **sp, int *code)
814 kind = get_token(sp, &sval);
815 if ( kind != TK_BAREWORD ) {
817 *code = LDAP_SCHERR_UNEXPTOKEN;
824 /* Parse a noidlen */
826 parse_noidlen(const char **sp, int *code, int *len, int allow_quoted)
832 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
833 if ( allow_quoted && **sp == '\'' ) {
837 sval = parse_numericoid(sp, code, 0);
841 if ( **sp == '{' /*}*/ ) {
844 while ( LDAP_DIGIT(**sp) )
846 if ( **sp != /*{*/ '}' ) {
847 *code = LDAP_SCHERR_UNEXPTOKEN;
853 if ( allow_quoted && quoted ) {
854 if ( **sp == '\'' ) {
857 *code = LDAP_SCHERR_UNEXPTOKEN;
866 * Next routine will accept a qdstring in place of an oid if
867 * allow_quoted is set. This is necessary to interoperate with
868 * Netscape Directory server that will improperly quote each oid (at
869 * least those of the descr kind) in the SUP clause.
872 /* Parse a woid or a $-separated list of them enclosed in () */
874 parse_oids(const char **sp, int *code, const int allow_quoted)
884 * Strictly speaking, doing this here accepts whsp before the
885 * ( at the begining of an oidlist, but this is harmless. Also,
886 * we are very liberal in what we accept as an OID. Maybe
890 kind = get_token(sp,&sval);
891 if ( kind == TK_LEFTPAREN ) {
892 /* Let's presume there will be at least 2 entries */
894 res = LDAP_CALLOC(3,sizeof(char *));
896 *code = LDAP_SCHERR_OUTOFMEM;
901 kind = get_token(sp,&sval);
902 if ( kind == TK_BAREWORD ||
903 ( allow_quoted && kind == TK_QDSTRING ) ) {
907 *code = LDAP_SCHERR_UNEXPTOKEN;
914 kind = get_token(sp,&sval);
915 if ( kind == TK_RIGHTPAREN )
917 if ( kind == TK_DOLLAR ) {
919 kind = get_token(sp,&sval);
920 if ( kind == TK_BAREWORD ||
922 kind == TK_QDSTRING ) ) {
923 if ( pos == size-2 ) {
925 res1 = LDAP_REALLOC(res,size*sizeof(char *));
929 *code = LDAP_SCHERR_OUTOFMEM;
937 *code = LDAP_SCHERR_UNEXPTOKEN;
944 *code = LDAP_SCHERR_UNEXPTOKEN;
953 } else if ( kind == TK_BAREWORD ||
954 ( allow_quoted && kind == TK_QDSTRING ) ) {
955 res = LDAP_CALLOC(2,sizeof(char *));
958 *code = LDAP_SCHERR_OUTOFMEM;
967 *code = LDAP_SCHERR_BADNAME;
973 add_extension(LDAPSchemaExtensionItem ***extensions,
974 char * name, char ** values)
977 LDAPSchemaExtensionItem **tmp, *ext;
979 ext = LDAP_CALLOC(1, sizeof(LDAPSchemaExtensionItem));
982 ext->lsei_name = name;
983 ext->lsei_values = values;
985 if ( !*extensions ) {
987 LDAP_CALLOC(2, sizeof(LDAPSchemaExtensionItem *));
992 for ( n=0; (*extensions)[n] != NULL; n++ )
994 tmp = LDAP_REALLOC(*extensions,
995 (n+2)*sizeof(LDAPSchemaExtensionItem *));
1000 (*extensions)[n] = ext;
1001 (*extensions)[n+1] = NULL;
1006 free_extensions(LDAPSchemaExtensionItem **extensions)
1008 LDAPSchemaExtensionItem **ext;
1011 for ( ext = extensions; *ext != NULL; ext++ ) {
1012 LDAP_FREE((*ext)->lsei_name);
1013 LDAP_VFREE((*ext)->lsei_values);
1016 LDAP_FREE(extensions);
1021 ldap_syntax_free( LDAPSyntax * syn )
1023 LDAP_FREE(syn->syn_oid);
1024 LDAP_VFREE(syn->syn_names);
1025 LDAP_FREE(syn->syn_desc);
1026 free_extensions(syn->syn_extensions);
1031 ldap_str2syntax( const char * s, int * code, const char ** errp, const int flags )
1034 const char * ss = s;
1042 *code = LDAP_SCHERR_EMPTY;
1048 syn = LDAP_CALLOC(1,sizeof(LDAPSyntax));
1051 *code = LDAP_SCHERR_OUTOFMEM;
1055 kind = get_token(&ss,&sval);
1056 if ( kind != TK_LEFTPAREN ) {
1058 *code = LDAP_SCHERR_NOLEFTPAREN;
1059 ldap_syntax_free(syn);
1064 syn->syn_oid = parse_numericoid(&ss,code,0);
1065 if ( !syn->syn_oid ) {
1067 ldap_syntax_free(syn);
1073 * Beyond this point we will be liberal and accept the items
1077 kind = get_token(&ss,&sval);
1080 *code = LDAP_SCHERR_NORIGHTPAREN;
1082 ldap_syntax_free(syn);
1087 if ( !strcmp(sval,"NAME") ) {
1090 *code = LDAP_SCHERR_DUPOPT;
1092 ldap_syntax_free(syn);
1096 syn->syn_names = parse_qdescrs(&ss,code);
1097 if ( !syn->syn_names ) {
1098 if ( *code != LDAP_SCHERR_OUTOFMEM )
1099 *code = LDAP_SCHERR_BADNAME;
1101 ldap_syntax_free(syn);
1104 } else if ( !strcmp(sval,"DESC") ) {
1107 *code = LDAP_SCHERR_DUPOPT;
1109 ldap_syntax_free(syn);
1114 kind = get_token(&ss,&sval);
1115 if ( kind != TK_QDSTRING ) {
1116 *code = LDAP_SCHERR_UNEXPTOKEN;
1119 ldap_syntax_free(syn);
1122 syn->syn_desc = sval;
1124 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1125 /* Should be parse_qdstrings */
1126 ext_vals = parse_qdescrs(&ss, code);
1129 ldap_syntax_free(syn);
1132 if ( add_extension(&syn->syn_extensions,
1134 *code = LDAP_SCHERR_OUTOFMEM;
1137 ldap_syntax_free(syn);
1141 *code = LDAP_SCHERR_UNEXPTOKEN;
1144 ldap_syntax_free(syn);
1149 *code = LDAP_SCHERR_UNEXPTOKEN;
1152 ldap_syntax_free(syn);
1159 ldap_matchingrule_free( LDAPMatchingRule * mr )
1161 LDAP_FREE(mr->mr_oid);
1162 LDAP_VFREE(mr->mr_names);
1163 LDAP_FREE(mr->mr_desc);
1164 LDAP_FREE(mr->mr_syntax_oid);
1165 free_extensions(mr->mr_extensions);
1170 ldap_str2matchingrule( const char * s, int * code, const char ** errp, const int flags )
1173 const char * ss = s;
1177 int seen_obsolete = 0;
1178 int seen_syntax = 0;
1179 LDAPMatchingRule * mr;
1181 const char * savepos;
1184 *code = LDAP_SCHERR_EMPTY;
1190 mr = LDAP_CALLOC(1,sizeof(LDAPMatchingRule));
1193 *code = LDAP_SCHERR_OUTOFMEM;
1197 kind = get_token(&ss,&sval);
1198 if ( kind != TK_LEFTPAREN ) {
1199 *code = LDAP_SCHERR_NOLEFTPAREN;
1201 ldap_matchingrule_free(mr);
1207 mr->mr_oid = parse_numericoid(&ss,code,flags);
1208 if ( !mr->mr_oid ) {
1209 if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
1212 kind = get_token(&ss,&sval);
1213 if ( kind == TK_BAREWORD ) {
1214 if ( !strcmp(sval, "NAME") ||
1215 !strcmp(sval, "DESC") ||
1216 !strcmp(sval, "OBSOLETE") ||
1217 !strcmp(sval, "SYNTAX") ||
1218 !strncmp(sval, "X-", 2) ) {
1219 /* Missing OID, backtrack */
1222 /* Non-numerical OID, ignore */
1228 ldap_matchingrule_free(mr);
1235 * Beyond this point we will be liberal and accept the items
1239 kind = get_token(&ss,&sval);
1242 *code = LDAP_SCHERR_NORIGHTPAREN;
1244 ldap_matchingrule_free(mr);
1249 if ( !strcmp(sval,"NAME") ) {
1252 *code = LDAP_SCHERR_DUPOPT;
1254 ldap_matchingrule_free(mr);
1258 mr->mr_names = parse_qdescrs(&ss,code);
1259 if ( !mr->mr_names ) {
1260 if ( *code != LDAP_SCHERR_OUTOFMEM )
1261 *code = LDAP_SCHERR_BADNAME;
1263 ldap_matchingrule_free(mr);
1266 } else if ( !strcmp(sval,"DESC") ) {
1269 *code = LDAP_SCHERR_DUPOPT;
1271 ldap_matchingrule_free(mr);
1276 kind = get_token(&ss,&sval);
1277 if ( kind != TK_QDSTRING ) {
1278 *code = LDAP_SCHERR_UNEXPTOKEN;
1281 ldap_matchingrule_free(mr);
1286 } else if ( !strcmp(sval,"OBSOLETE") ) {
1288 if ( seen_obsolete ) {
1289 *code = LDAP_SCHERR_DUPOPT;
1291 ldap_matchingrule_free(mr);
1295 mr->mr_obsolete = LDAP_SCHEMA_YES;
1297 } else if ( !strcmp(sval,"SYNTAX") ) {
1299 if ( seen_syntax ) {
1300 *code = LDAP_SCHERR_DUPOPT;
1302 ldap_matchingrule_free(mr);
1308 parse_numericoid(&ss,code,flags);
1309 if ( !mr->mr_syntax_oid ) {
1311 ldap_matchingrule_free(mr);
1315 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1316 /* Should be parse_qdstrings */
1317 ext_vals = parse_qdescrs(&ss, code);
1320 ldap_matchingrule_free(mr);
1323 if ( add_extension(&mr->mr_extensions,
1325 *code = LDAP_SCHERR_OUTOFMEM;
1328 ldap_matchingrule_free(mr);
1332 *code = LDAP_SCHERR_UNEXPTOKEN;
1335 ldap_matchingrule_free(mr);
1340 *code = LDAP_SCHERR_UNEXPTOKEN;
1343 ldap_matchingrule_free(mr);
1350 ldap_attributetype_free(LDAPAttributeType * at)
1352 LDAP_FREE(at->at_oid);
1353 LDAP_VFREE(at->at_names);
1354 LDAP_FREE(at->at_desc);
1355 LDAP_FREE(at->at_sup_oid);
1356 LDAP_FREE(at->at_equality_oid);
1357 LDAP_FREE(at->at_ordering_oid);
1358 LDAP_FREE(at->at_substr_oid);
1359 LDAP_FREE(at->at_syntax_oid);
1360 free_extensions(at->at_extensions);
1365 ldap_str2attributetype( const char * s, int * code, const char ** errp, const int flags )
1368 const char * ss = s;
1372 int seen_obsolete = 0;
1374 int seen_equality = 0;
1375 int seen_ordering = 0;
1376 int seen_substr = 0;
1377 int seen_syntax = 0;
1379 LDAPAttributeType * at;
1381 const char * savepos;
1384 *code = LDAP_SCHERR_EMPTY;
1390 at = LDAP_CALLOC(1,sizeof(LDAPAttributeType));
1393 *code = LDAP_SCHERR_OUTOFMEM;
1397 kind = get_token(&ss,&sval);
1398 if ( kind != TK_LEFTPAREN ) {
1399 *code = LDAP_SCHERR_NOLEFTPAREN;
1401 ldap_attributetype_free(at);
1406 * Definitions MUST begin with an OID in the numericoid format.
1407 * However, this routine is used by clients to parse the response
1408 * from servers and very well known servers will provide an OID
1409 * in the wrong format or even no OID at all. We do our best to
1410 * extract info from those servers.
1414 at->at_oid = parse_numericoid(&ss,code,0);
1415 if ( !at->at_oid ) {
1416 if ( ( flags & ( LDAP_SCHEMA_ALLOW_NO_OID
1417 | LDAP_SCHEMA_ALLOW_OID_MACRO ) )
1418 && (ss == savepos) ) {
1421 kind = get_token(&ss,&sval);
1422 if ( kind == TK_BAREWORD ) {
1423 if ( !strcmp(sval, "NAME") ||
1424 !strcmp(sval, "DESC") ||
1425 !strcmp(sval, "OBSOLETE") ||
1426 !strcmp(sval, "SUP") ||
1427 !strcmp(sval, "EQUALITY") ||
1428 !strcmp(sval, "ORDERING") ||
1429 !strcmp(sval, "SUBSTR") ||
1430 !strcmp(sval, "SYNTAX") ||
1431 !strcmp(sval, "SINGLE-VALUE") ||
1432 !strcmp(sval, "COLLECTIVE") ||
1433 !strcmp(sval, "NO-USER-MODIFICATION") ||
1434 !strcmp(sval, "USAGE") ||
1435 !strncmp(sval, "X-", 2) ) {
1436 /* Missing OID, backtrack */
1439 & LDAP_SCHEMA_ALLOW_OID_MACRO) {
1440 /* Non-numerical OID ... */
1441 int len = ss-savepos;
1442 at->at_oid = LDAP_MALLOC(len+1);
1443 strncpy(at->at_oid, savepos, len);
1444 at->at_oid[len] = 0;
1450 ldap_attributetype_free(at);
1457 * Beyond this point we will be liberal and accept the items
1461 kind = get_token(&ss,&sval);
1464 *code = LDAP_SCHERR_NORIGHTPAREN;
1466 ldap_attributetype_free(at);
1471 if ( !strcmp(sval,"NAME") ) {
1474 *code = LDAP_SCHERR_DUPOPT;
1476 ldap_attributetype_free(at);
1480 at->at_names = parse_qdescrs(&ss,code);
1481 if ( !at->at_names ) {
1482 if ( *code != LDAP_SCHERR_OUTOFMEM )
1483 *code = LDAP_SCHERR_BADNAME;
1485 ldap_attributetype_free(at);
1488 } else if ( !strcmp(sval,"DESC") ) {
1491 *code = LDAP_SCHERR_DUPOPT;
1493 ldap_attributetype_free(at);
1498 kind = get_token(&ss,&sval);
1499 if ( kind != TK_QDSTRING ) {
1500 *code = LDAP_SCHERR_UNEXPTOKEN;
1503 ldap_attributetype_free(at);
1508 } else if ( !strcmp(sval,"OBSOLETE") ) {
1510 if ( seen_obsolete ) {
1511 *code = LDAP_SCHERR_DUPOPT;
1513 ldap_attributetype_free(at);
1517 at->at_obsolete = LDAP_SCHEMA_YES;
1519 } else if ( !strcmp(sval,"SUP") ) {
1522 *code = LDAP_SCHERR_DUPOPT;
1524 ldap_attributetype_free(at);
1528 at->at_sup_oid = parse_woid(&ss,code);
1529 if ( !at->at_sup_oid ) {
1531 ldap_attributetype_free(at);
1534 } else if ( !strcmp(sval,"EQUALITY") ) {
1536 if ( seen_equality ) {
1537 *code = LDAP_SCHERR_DUPOPT;
1539 ldap_attributetype_free(at);
1543 at->at_equality_oid = parse_woid(&ss,code);
1544 if ( !at->at_equality_oid ) {
1546 ldap_attributetype_free(at);
1549 } else if ( !strcmp(sval,"ORDERING") ) {
1551 if ( seen_ordering ) {
1552 *code = LDAP_SCHERR_DUPOPT;
1554 ldap_attributetype_free(at);
1558 at->at_ordering_oid = parse_woid(&ss,code);
1559 if ( !at->at_ordering_oid ) {
1561 ldap_attributetype_free(at);
1564 } else if ( !strcmp(sval,"SUBSTR") ) {
1566 if ( seen_substr ) {
1567 *code = LDAP_SCHERR_DUPOPT;
1569 ldap_attributetype_free(at);
1573 at->at_substr_oid = parse_woid(&ss,code);
1574 if ( !at->at_substr_oid ) {
1576 ldap_attributetype_free(at);
1579 } else if ( !strcmp(sval,"SYNTAX") ) {
1581 if ( seen_syntax ) {
1582 *code = LDAP_SCHERR_DUPOPT;
1584 ldap_attributetype_free(at);
1595 if ( !at->at_syntax_oid ) {
1596 if ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO ) {
1597 kind = get_token(&ss,&sval);
1598 if (kind == TK_BAREWORD)
1600 char *sp = strchr(sval, '{');
1601 at->at_syntax_oid = sval;
1605 at->at_syntax_len = atoi(sp);
1606 while ( LDAP_DIGIT(*sp) )
1609 *code = LDAP_SCHERR_UNEXPTOKEN;
1611 ldap_attributetype_free(at);
1618 ldap_attributetype_free(at);
1623 } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
1625 if ( at->at_single_value ) {
1626 *code = LDAP_SCHERR_DUPOPT;
1628 ldap_attributetype_free(at);
1631 at->at_single_value = LDAP_SCHEMA_YES;
1633 } else if ( !strcmp(sval,"COLLECTIVE") ) {
1635 if ( at->at_collective ) {
1636 *code = LDAP_SCHERR_DUPOPT;
1638 ldap_attributetype_free(at);
1641 at->at_collective = LDAP_SCHEMA_YES;
1643 } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
1645 if ( at->at_no_user_mod ) {
1646 *code = LDAP_SCHERR_DUPOPT;
1648 ldap_attributetype_free(at);
1651 at->at_no_user_mod = LDAP_SCHEMA_YES;
1653 } else if ( !strcmp(sval,"USAGE") ) {
1656 *code = LDAP_SCHERR_DUPOPT;
1658 ldap_attributetype_free(at);
1663 kind = get_token(&ss,&sval);
1664 if ( kind != TK_BAREWORD ) {
1665 *code = LDAP_SCHERR_UNEXPTOKEN;
1668 ldap_attributetype_free(at);
1671 if ( !strcasecmp(sval,"userApplications") )
1673 LDAP_SCHEMA_USER_APPLICATIONS;
1674 else if ( !strcasecmp(sval,"directoryOperation") )
1676 LDAP_SCHEMA_DIRECTORY_OPERATION;
1677 else if ( !strcasecmp(sval,"distributedOperation") )
1679 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
1680 else if ( !strcasecmp(sval,"dSAOperation") )
1682 LDAP_SCHEMA_DSA_OPERATION;
1684 *code = LDAP_SCHERR_UNEXPTOKEN;
1687 ldap_attributetype_free(at);
1692 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1693 /* Should be parse_qdstrings */
1694 ext_vals = parse_qdescrs(&ss, code);
1697 ldap_attributetype_free(at);
1700 if ( add_extension(&at->at_extensions,
1702 *code = LDAP_SCHERR_OUTOFMEM;
1705 ldap_attributetype_free(at);
1709 *code = LDAP_SCHERR_UNEXPTOKEN;
1712 ldap_attributetype_free(at);
1717 *code = LDAP_SCHERR_UNEXPTOKEN;
1720 ldap_attributetype_free(at);
1727 ldap_objectclass_free(LDAPObjectClass * oc)
1729 LDAP_FREE(oc->oc_oid);
1730 LDAP_VFREE(oc->oc_names);
1731 LDAP_FREE(oc->oc_desc);
1732 LDAP_VFREE(oc->oc_sup_oids);
1733 LDAP_VFREE(oc->oc_at_oids_must);
1734 LDAP_VFREE(oc->oc_at_oids_may);
1735 free_extensions(oc->oc_extensions);
1740 ldap_str2objectclass( const char * s, int * code, const char ** errp, const int flags )
1743 const char * ss = s;
1747 int seen_obsolete = 0;
1752 LDAPObjectClass * oc;
1754 const char * savepos;
1757 *code = LDAP_SCHERR_EMPTY;
1763 oc = LDAP_CALLOC(1,sizeof(LDAPObjectClass));
1766 *code = LDAP_SCHERR_OUTOFMEM;
1769 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
1771 kind = get_token(&ss,&sval);
1772 if ( kind != TK_LEFTPAREN ) {
1773 *code = LDAP_SCHERR_NOLEFTPAREN;
1775 ldap_objectclass_free(oc);
1780 * Definitions MUST begin with an OID in the numericoid format.
1781 * However, this routine is used by clients to parse the response
1782 * from servers and very well known servers will provide an OID
1783 * in the wrong format or even no OID at all. We do our best to
1784 * extract info from those servers.
1788 oc->oc_oid = parse_numericoid(&ss,code,0);
1789 if ( !oc->oc_oid ) {
1790 if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) {
1793 kind = get_token(&ss,&sval);
1794 if ( kind == TK_BAREWORD ) {
1795 if ( !strcmp(sval, "NAME") ||
1796 !strcmp(sval, "DESC") ||
1797 !strcmp(sval, "OBSOLETE") ||
1798 !strcmp(sval, "SUP") ||
1799 !strcmp(sval, "ABSTRACT") ||
1800 !strcmp(sval, "STRUCTURAL") ||
1801 !strcmp(sval, "AUXILIARY") ||
1802 !strcmp(sval, "MUST") ||
1803 !strncmp(sval, "X-", 2) ) {
1804 /* Missing OID, backtrack */
1807 LDAP_SCHEMA_ALLOW_OID_MACRO ) {
1808 /* Non-numerical OID, ignore */
1809 int len = ss-savepos;
1810 oc->oc_oid = LDAP_MALLOC(len+1);
1811 strncpy(oc->oc_oid, savepos, len);
1812 oc->oc_oid[len] = 0;
1818 ldap_objectclass_free(oc);
1825 * Beyond this point we will be liberal an accept the items
1829 kind = get_token(&ss,&sval);
1832 *code = LDAP_SCHERR_NORIGHTPAREN;
1834 ldap_objectclass_free(oc);
1839 if ( !strcmp(sval,"NAME") ) {
1842 *code = LDAP_SCHERR_DUPOPT;
1844 ldap_objectclass_free(oc);
1848 oc->oc_names = parse_qdescrs(&ss,code);
1849 if ( !oc->oc_names ) {
1850 if ( *code != LDAP_SCHERR_OUTOFMEM )
1851 *code = LDAP_SCHERR_BADNAME;
1853 ldap_objectclass_free(oc);
1856 } else if ( !strcmp(sval,"DESC") ) {
1859 *code = LDAP_SCHERR_DUPOPT;
1861 ldap_objectclass_free(oc);
1866 kind = get_token(&ss,&sval);
1867 if ( kind != TK_QDSTRING ) {
1868 *code = LDAP_SCHERR_UNEXPTOKEN;
1871 ldap_objectclass_free(oc);
1876 } else if ( !strcmp(sval,"OBSOLETE") ) {
1878 if ( seen_obsolete ) {
1879 *code = LDAP_SCHERR_DUPOPT;
1881 ldap_objectclass_free(oc);
1885 oc->oc_obsolete = LDAP_SCHEMA_YES;
1887 } else if ( !strcmp(sval,"SUP") ) {
1890 *code = LDAP_SCHERR_DUPOPT;
1892 ldap_objectclass_free(oc);
1896 oc->oc_sup_oids = parse_oids(&ss,
1899 if ( !oc->oc_sup_oids ) {
1901 ldap_objectclass_free(oc);
1904 } else if ( !strcmp(sval,"ABSTRACT") ) {
1907 *code = LDAP_SCHERR_DUPOPT;
1909 ldap_objectclass_free(oc);
1913 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
1915 } else if ( !strcmp(sval,"STRUCTURAL") ) {
1918 *code = LDAP_SCHERR_DUPOPT;
1920 ldap_objectclass_free(oc);
1924 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
1926 } else if ( !strcmp(sval,"AUXILIARY") ) {
1929 *code = LDAP_SCHERR_DUPOPT;
1931 ldap_objectclass_free(oc);
1935 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
1937 } else if ( !strcmp(sval,"MUST") ) {
1940 *code = LDAP_SCHERR_DUPOPT;
1942 ldap_objectclass_free(oc);
1946 oc->oc_at_oids_must = parse_oids(&ss,code,0);
1947 if ( !oc->oc_at_oids_must ) {
1949 ldap_objectclass_free(oc);
1953 } else if ( !strcmp(sval,"MAY") ) {
1956 *code = LDAP_SCHERR_DUPOPT;
1958 ldap_objectclass_free(oc);
1962 oc->oc_at_oids_may = parse_oids(&ss,code,0);
1963 if ( !oc->oc_at_oids_may ) {
1965 ldap_objectclass_free(oc);
1969 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1970 /* Should be parse_qdstrings */
1971 ext_vals = parse_qdescrs(&ss, code);
1974 ldap_objectclass_free(oc);
1977 if ( add_extension(&oc->oc_extensions,
1979 *code = LDAP_SCHERR_OUTOFMEM;
1982 ldap_objectclass_free(oc);
1986 *code = LDAP_SCHERR_UNEXPTOKEN;
1989 ldap_objectclass_free(oc);
1994 *code = LDAP_SCHERR_UNEXPTOKEN;
1997 ldap_objectclass_free(oc);
2003 static char *const err2text[] = {
2007 "Missing opening parenthesis",
2008 "Missing closing parenthesis",
2014 "Unexpected end of data"
2018 ldap_scherr2str(int code)
2020 if ( code < 0 || code >= (sizeof(err2text)/sizeof(char *)) ) {
2021 return "Unknown error";
2023 return err2text[code];