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 if ( ss->pos + l >= ss->size-1 ) {
130 ss->size = ss->pos + l + 1;
133 temp = LDAP_REALLOC(ss->val, ss->size);
135 /* Trouble, out of memory */
141 strncpy(&ss->val[ss->pos], s, l);
143 if ( ss->pos > 0 && LDAP_SPACE(ss->val[ss->pos-1]) )
152 print_literal(safe_string *ss, char *s)
154 return(append_to_safe_string(ss,s));
158 print_whsp(safe_string *ss)
161 return(append_to_safe_string(ss,""));
163 return(append_to_safe_string(ss," "));
167 print_numericoid(safe_string *ss, char *s)
170 return(append_to_safe_string(ss,s));
172 return(append_to_safe_string(ss,""));
175 /* This one is identical to print_qdescr */
177 print_qdstring(safe_string *ss, char *s)
180 print_literal(ss,"'");
181 append_to_safe_string(ss,s);
182 print_literal(ss,"'");
183 return(print_whsp(ss));
187 print_qdescr(safe_string *ss, char *s)
190 print_literal(ss,"'");
191 append_to_safe_string(ss,s);
192 print_literal(ss,"'");
193 return(print_whsp(ss));
197 print_qdescrlist(safe_string *ss, char **sa)
202 for (sp=sa; *sp; sp++) {
203 ret = print_qdescr(ss,*sp);
205 /* If the list was empty, we return zero that is potentially
206 * incorrect, but since we will be still appending things, the
207 * overflow will be detected later. Maybe FIX.
213 print_qdescrs(safe_string *ss, char **sa)
215 /* The only way to represent an empty list is as a qdescrlist
216 * so, if the list is empty we treat it as a long list.
217 * Really, this is what the syntax mandates. We should not
218 * be here if the list was empty, but if it happens, a label
219 * has already been output and we cannot undo it.
221 if ( !sa[0] || ( sa[0] && sa[1] ) ) {
223 print_literal(ss,"("/*)*/);
224 print_qdescrlist(ss,sa);
225 print_literal(ss,/*(*/")");
226 return(print_whsp(ss));
228 return(print_qdescr(ss,*sa));
233 print_woid(safe_string *ss, char *s)
236 append_to_safe_string(ss,s);
237 return print_whsp(ss);
241 print_oidlist(safe_string *ss, char **sa)
245 for (sp=sa; *(sp+1); sp++) {
247 print_literal(ss,"$");
249 return(print_woid(ss,*sp));
253 print_oids(safe_string *ss, char **sa)
255 if ( sa[0] && sa[1] ) {
256 print_literal(ss,"("/*)*/);
257 print_oidlist(ss,sa);
259 return(print_literal(ss,/*(*/")"));
261 return(print_woid(ss,*sa));
266 print_noidlen(safe_string *ss, char *s, int l)
271 ret = print_numericoid(ss,s);
273 sprintf(buf,"{%d}",l);
274 ret = print_literal(ss,buf);
280 print_extensions(safe_string *ss, LDAPSchemaExtensionItem **extensions)
282 LDAPSchemaExtensionItem **ext;
286 for ( ext = extensions; *ext != NULL; ext++ ) {
287 print_literal(ss, (*ext)->lsei_name);
289 /* Should be print_qdstrings */
290 print_qdescrs(ss, (*ext)->lsei_values);
299 ldap_syntax2str( const LDAPSyntax * syn )
304 ss = new_safe_string(256);
308 print_literal(ss,"("/*)*/);
311 print_numericoid(ss, syn->syn_oid);
314 if ( syn->syn_desc ) {
315 print_literal(ss,"DESC");
316 print_qdstring(ss,syn->syn_desc);
321 print_extensions(ss, syn->syn_extensions);
323 print_literal(ss,/*(*/ ")");
325 retstring = LDAP_STRDUP(safe_string_val(ss));
326 safe_string_free(ss);
331 ldap_matchingrule2str( const LDAPMatchingRule * mr )
336 ss = new_safe_string(256);
340 print_literal(ss,"(" /*)*/);
343 print_numericoid(ss, mr->mr_oid);
346 if ( mr->mr_names ) {
347 print_literal(ss,"NAME");
348 print_qdescrs(ss,mr->mr_names);
352 print_literal(ss,"DESC");
353 print_qdstring(ss,mr->mr_desc);
356 if ( mr->mr_obsolete == LDAP_SCHEMA_YES ) {
357 print_literal(ss, "OBSOLETE");
361 if ( mr->mr_syntax_oid ) {
362 print_literal(ss,"SYNTAX");
364 print_literal(ss, mr->mr_syntax_oid);
370 print_extensions(ss, mr->mr_extensions);
372 print_literal(ss,/*(*/")");
374 retstring = LDAP_STRDUP(safe_string_val(ss));
375 safe_string_free(ss);
380 ldap_matchingruleuse2str( const LDAPMatchingRuleUse * mru )
385 ss = new_safe_string(256);
389 print_literal(ss,"(" /*)*/);
392 print_numericoid(ss, mru->mru_oid);
395 if ( mru->mru_names ) {
396 print_literal(ss,"NAME");
397 print_qdescrs(ss,mru->mru_names);
400 if ( mru->mru_desc ) {
401 print_literal(ss,"DESC");
402 print_qdstring(ss,mru->mru_desc);
405 if ( mru->mru_obsolete == LDAP_SCHEMA_YES ) {
406 print_literal(ss, "OBSOLETE");
410 if ( mru->mru_applies_oids ) {
411 print_literal(ss,"APPLIES");
413 print_oids(ss, mru->mru_applies_oids);
419 print_extensions(ss, mru->mru_extensions);
421 print_literal(ss,/*(*/")");
423 retstring = LDAP_STRDUP(safe_string_val(ss));
424 safe_string_free(ss);
429 ldap_objectclass2str( const LDAPObjectClass * oc )
434 ss = new_safe_string(256);
438 print_literal(ss,"("/*)*/);
441 print_numericoid(ss, oc->oc_oid);
444 if ( oc->oc_names ) {
445 print_literal(ss,"NAME");
446 print_qdescrs(ss,oc->oc_names);
450 print_literal(ss,"DESC");
451 print_qdstring(ss,oc->oc_desc);
454 if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) {
455 print_literal(ss, "OBSOLETE");
459 if ( oc->oc_sup_oids ) {
460 print_literal(ss,"SUP");
462 print_oids(ss,oc->oc_sup_oids);
466 switch (oc->oc_kind) {
467 case LDAP_SCHEMA_ABSTRACT:
468 print_literal(ss,"ABSTRACT");
470 case LDAP_SCHEMA_STRUCTURAL:
471 print_literal(ss,"STRUCTURAL");
473 case LDAP_SCHEMA_AUXILIARY:
474 print_literal(ss,"AUXILIARY");
477 print_literal(ss,"KIND-UNKNOWN");
482 if ( oc->oc_at_oids_must ) {
483 print_literal(ss,"MUST");
485 print_oids(ss,oc->oc_at_oids_must);
489 if ( oc->oc_at_oids_may ) {
490 print_literal(ss,"MAY");
492 print_oids(ss,oc->oc_at_oids_may);
498 print_extensions(ss, oc->oc_extensions);
500 print_literal(ss, /*(*/")");
502 retstring = LDAP_STRDUP(safe_string_val(ss));
503 safe_string_free(ss);
508 ldap_attributetype2str( const LDAPAttributeType * at )
513 ss = new_safe_string(256);
517 print_literal(ss,"("/*)*/);
520 print_numericoid(ss, at->at_oid);
523 if ( at->at_names ) {
524 print_literal(ss,"NAME");
525 print_qdescrs(ss,at->at_names);
529 print_literal(ss,"DESC");
530 print_qdstring(ss,at->at_desc);
533 if ( at->at_obsolete == LDAP_SCHEMA_YES ) {
534 print_literal(ss, "OBSOLETE");
538 if ( at->at_sup_oid ) {
539 print_literal(ss,"SUP");
540 print_woid(ss,at->at_sup_oid);
543 if ( at->at_equality_oid ) {
544 print_literal(ss,"EQUALITY");
545 print_woid(ss,at->at_equality_oid);
548 if ( at->at_ordering_oid ) {
549 print_literal(ss,"ORDERING");
550 print_woid(ss,at->at_ordering_oid);
553 if ( at->at_substr_oid ) {
554 print_literal(ss,"SUBSTR");
555 print_woid(ss,at->at_substr_oid);
558 if ( at->at_syntax_oid ) {
559 print_literal(ss,"SYNTAX");
561 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
565 if ( at->at_single_value == LDAP_SCHEMA_YES ) {
566 print_literal(ss,"SINGLE-VALUE");
570 if ( at->at_collective == LDAP_SCHEMA_YES ) {
571 print_literal(ss,"COLLECTIVE");
575 if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
576 print_literal(ss,"NO-USER-MODIFICATION");
580 if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
581 print_literal(ss,"USAGE");
583 switch (at->at_usage) {
584 case LDAP_SCHEMA_DIRECTORY_OPERATION:
585 print_literal(ss,"directoryOperation");
587 case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
588 print_literal(ss,"distributedOperation");
590 case LDAP_SCHEMA_DSA_OPERATION:
591 print_literal(ss,"dSAOperation");
594 print_literal(ss,"UNKNOWN");
601 print_extensions(ss, at->at_extensions);
603 print_literal(ss,/*(*/")");
605 retstring = LDAP_STRDUP(safe_string_val(ss));
606 safe_string_free(ss);
611 * Now come the parsers. There is one parser for each entity type:
612 * objectclasses, attributetypes, etc.
614 * Each of them is written as a recursive-descent parser, except that
615 * none of them is really recursive. But the idea is kept: there
616 * is one routine per non-terminal that eithers gobbles lexical tokens
617 * or calls lower-level routines, etc.
619 * The scanner is implemented in the routine get_token. Actually,
620 * get_token is more than a scanner and will return tokens that are
621 * in fact non-terminals in the grammar. So you can see the whole
622 * approach as the combination of a low-level bottom-up recognizer
623 * combined with a scanner and a number of top-down parsers. Or just
624 * consider that the real grammars recognized by the parsers are not
625 * those of the standards. As a matter of fact, our parsers are more
626 * liberal than the spec when there is no ambiguity.
628 * The difference is pretty academic (modulo bugs or incorrect
629 * interpretation of the specs).
632 #define TK_NOENDQUOTE -2
633 #define TK_OUTOFMEM -1
635 #define TK_UNEXPCHAR 1
636 #define TK_BAREWORD 2
637 #define TK_QDSTRING 3
638 #define TK_LEFTPAREN 4
639 #define TK_RIGHTPAREN 5
641 #define TK_QDESCR TK_QDSTRING
649 get_token(const char ** sp, char ** token_val)
667 kind = TK_RIGHTPAREN;
678 while ( **sp != '\'' && **sp != '\0' )
680 if ( **sp == '\'' ) {
682 res = LDAP_MALLOC(q-p+1);
692 kind = TK_NOENDQUOTE;
698 while ( !LDAP_SPACE(**sp) &&
706 res = LDAP_MALLOC(q-p+1);
715 /* kind = TK_UNEXPCHAR; */
722 /* Gobble optional whitespace */
724 parse_whsp(const char **sp)
726 while (LDAP_SPACE(**sp))
731 * General note for all parsers: to guarantee the algorithm halts they
732 * must always advance the pointer even when an error is found. For
733 * this one is not that important since an error here is fatal at the
734 * upper layers, but it is a simple strategy that will not get in
738 /* Parse a sequence of dot-separated decimal strings */
740 parse_numericoid(const char **sp, int *code, const int flags)
743 const char * start = *sp;
747 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
748 if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && **sp == '\'' ) {
753 /* Each iteration of this loop gets one decimal string */
755 if ( !LDAP_DIGIT(**sp) ) {
757 * Initial char is not a digit or char after dot is
760 *code = LDAP_SCHERR_NODIGIT;
764 while ( LDAP_DIGIT(**sp) )
768 /* Otherwise, gobble the dot and loop again */
771 /* Now *sp points at the char past the numericoid. Perfect. */
773 res = LDAP_MALLOC(len+1);
775 *code = LDAP_SCHERR_OUTOFMEM;
778 strncpy(res,start,len);
780 if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && quoted ) {
781 if ( **sp == '\'' ) {
784 *code = LDAP_SCHERR_UNEXPTOKEN;
792 /* Parse a qdescr or a list of them enclosed in () */
794 parse_qdescrs(const char **sp, int *code)
804 kind = get_token(sp,&sval);
805 if ( kind == TK_LEFTPAREN ) {
806 /* Let's presume there will be at least 2 entries */
808 res = LDAP_CALLOC(3,sizeof(char *));
810 *code = LDAP_SCHERR_OUTOFMEM;
816 kind = get_token(sp,&sval);
817 if ( kind == TK_RIGHTPAREN )
819 if ( kind == TK_QDESCR ) {
820 if ( pos == size-2 ) {
822 res1 = LDAP_REALLOC(res,size*sizeof(char *));
826 *code = LDAP_SCHERR_OUTOFMEM;
837 *code = LDAP_SCHERR_UNEXPTOKEN;
844 } else if ( kind == TK_QDESCR ) {
845 res = LDAP_CALLOC(2,sizeof(char *));
847 *code = LDAP_SCHERR_OUTOFMEM;
856 *code = LDAP_SCHERR_BADNAME;
863 parse_woid(const char **sp, int *code)
869 kind = get_token(sp, &sval);
870 if ( kind != TK_BAREWORD ) {
872 *code = LDAP_SCHERR_UNEXPTOKEN;
879 /* Parse a noidlen */
881 parse_noidlen(const char **sp, int *code, int *len, int allow_quoted)
887 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
888 if ( allow_quoted && **sp == '\'' ) {
892 sval = parse_numericoid(sp, code, 0);
896 if ( **sp == '{' /*}*/ ) {
899 while ( LDAP_DIGIT(**sp) )
901 if ( **sp != /*{*/ '}' ) {
902 *code = LDAP_SCHERR_UNEXPTOKEN;
908 if ( allow_quoted && quoted ) {
909 if ( **sp == '\'' ) {
912 *code = LDAP_SCHERR_UNEXPTOKEN;
921 * Next routine will accept a qdstring in place of an oid if
922 * allow_quoted is set. This is necessary to interoperate with
923 * Netscape Directory server that will improperly quote each oid (at
924 * least those of the descr kind) in the SUP clause.
927 /* Parse a woid or a $-separated list of them enclosed in () */
929 parse_oids(const char **sp, int *code, const int allow_quoted)
939 * Strictly speaking, doing this here accepts whsp before the
940 * ( at the begining of an oidlist, but this is harmless. Also,
941 * we are very liberal in what we accept as an OID. Maybe
945 kind = get_token(sp,&sval);
946 if ( kind == TK_LEFTPAREN ) {
947 /* Let's presume there will be at least 2 entries */
949 res = LDAP_CALLOC(3,sizeof(char *));
951 *code = LDAP_SCHERR_OUTOFMEM;
956 kind = get_token(sp,&sval);
957 if ( kind == TK_BAREWORD ||
958 ( allow_quoted && kind == TK_QDSTRING ) ) {
962 *code = LDAP_SCHERR_UNEXPTOKEN;
969 kind = get_token(sp,&sval);
970 if ( kind == TK_RIGHTPAREN )
972 if ( kind == TK_DOLLAR ) {
974 kind = get_token(sp,&sval);
975 if ( kind == TK_BAREWORD ||
977 kind == TK_QDSTRING ) ) {
978 if ( pos == size-2 ) {
980 res1 = LDAP_REALLOC(res,size*sizeof(char *));
984 *code = LDAP_SCHERR_OUTOFMEM;
992 *code = LDAP_SCHERR_UNEXPTOKEN;
999 *code = LDAP_SCHERR_UNEXPTOKEN;
1008 } else if ( kind == TK_BAREWORD ||
1009 ( allow_quoted && kind == TK_QDSTRING ) ) {
1010 res = LDAP_CALLOC(2,sizeof(char *));
1013 *code = LDAP_SCHERR_OUTOFMEM;
1022 *code = LDAP_SCHERR_BADNAME;
1028 add_extension(LDAPSchemaExtensionItem ***extensions,
1029 char * name, char ** values)
1032 LDAPSchemaExtensionItem **tmp, *ext;
1034 ext = LDAP_CALLOC(1, sizeof(LDAPSchemaExtensionItem));
1037 ext->lsei_name = name;
1038 ext->lsei_values = values;
1040 if ( !*extensions ) {
1042 LDAP_CALLOC(2, sizeof(LDAPSchemaExtensionItem *));
1047 for ( n=0; (*extensions)[n] != NULL; n++ )
1049 tmp = LDAP_REALLOC(*extensions,
1050 (n+2)*sizeof(LDAPSchemaExtensionItem *));
1055 (*extensions)[n] = ext;
1056 (*extensions)[n+1] = NULL;
1061 free_extensions(LDAPSchemaExtensionItem **extensions)
1063 LDAPSchemaExtensionItem **ext;
1066 for ( ext = extensions; *ext != NULL; ext++ ) {
1067 LDAP_FREE((*ext)->lsei_name);
1068 LDAP_VFREE((*ext)->lsei_values);
1071 LDAP_FREE(extensions);
1076 ldap_syntax_free( LDAPSyntax * syn )
1078 LDAP_FREE(syn->syn_oid);
1079 LDAP_VFREE(syn->syn_names);
1080 LDAP_FREE(syn->syn_desc);
1081 free_extensions(syn->syn_extensions);
1086 ldap_str2syntax( const char * s, int * code, const char ** errp, const int flags )
1089 const char * ss = s;
1097 *code = LDAP_SCHERR_EMPTY;
1103 syn = LDAP_CALLOC(1,sizeof(LDAPSyntax));
1106 *code = LDAP_SCHERR_OUTOFMEM;
1110 kind = get_token(&ss,&sval);
1111 if ( kind != TK_LEFTPAREN ) {
1113 *code = LDAP_SCHERR_NOLEFTPAREN;
1114 ldap_syntax_free(syn);
1119 syn->syn_oid = parse_numericoid(&ss,code,0);
1120 if ( !syn->syn_oid ) {
1122 ldap_syntax_free(syn);
1128 * Beyond this point we will be liberal and accept the items
1132 kind = get_token(&ss,&sval);
1135 *code = LDAP_SCHERR_NORIGHTPAREN;
1137 ldap_syntax_free(syn);
1142 if ( !strcmp(sval,"NAME") ) {
1145 *code = LDAP_SCHERR_DUPOPT;
1147 ldap_syntax_free(syn);
1151 syn->syn_names = parse_qdescrs(&ss,code);
1152 if ( !syn->syn_names ) {
1153 if ( *code != LDAP_SCHERR_OUTOFMEM )
1154 *code = LDAP_SCHERR_BADNAME;
1156 ldap_syntax_free(syn);
1159 } else if ( !strcmp(sval,"DESC") ) {
1162 *code = LDAP_SCHERR_DUPOPT;
1164 ldap_syntax_free(syn);
1169 kind = get_token(&ss,&sval);
1170 if ( kind != TK_QDSTRING ) {
1171 *code = LDAP_SCHERR_UNEXPTOKEN;
1174 ldap_syntax_free(syn);
1177 syn->syn_desc = sval;
1179 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1180 /* Should be parse_qdstrings */
1181 ext_vals = parse_qdescrs(&ss, code);
1184 ldap_syntax_free(syn);
1187 if ( add_extension(&syn->syn_extensions,
1189 *code = LDAP_SCHERR_OUTOFMEM;
1192 ldap_syntax_free(syn);
1196 *code = LDAP_SCHERR_UNEXPTOKEN;
1199 ldap_syntax_free(syn);
1204 *code = LDAP_SCHERR_UNEXPTOKEN;
1207 ldap_syntax_free(syn);
1214 ldap_matchingrule_free( LDAPMatchingRule * mr )
1216 LDAP_FREE(mr->mr_oid);
1217 LDAP_VFREE(mr->mr_names);
1218 LDAP_FREE(mr->mr_desc);
1219 LDAP_FREE(mr->mr_syntax_oid);
1220 free_extensions(mr->mr_extensions);
1225 ldap_str2matchingrule( const char * s, int * code, const char ** errp, const int flags )
1228 const char * ss = s;
1232 int seen_obsolete = 0;
1233 int seen_syntax = 0;
1234 LDAPMatchingRule * mr;
1236 const char * savepos;
1239 *code = LDAP_SCHERR_EMPTY;
1245 mr = LDAP_CALLOC(1,sizeof(LDAPMatchingRule));
1248 *code = LDAP_SCHERR_OUTOFMEM;
1252 kind = get_token(&ss,&sval);
1253 if ( kind != TK_LEFTPAREN ) {
1254 *code = LDAP_SCHERR_NOLEFTPAREN;
1256 ldap_matchingrule_free(mr);
1262 mr->mr_oid = parse_numericoid(&ss,code,flags);
1263 if ( !mr->mr_oid ) {
1264 if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
1267 kind = get_token(&ss,&sval);
1268 if ( kind == TK_BAREWORD ) {
1269 if ( !strcmp(sval, "NAME") ||
1270 !strcmp(sval, "DESC") ||
1271 !strcmp(sval, "OBSOLETE") ||
1272 !strcmp(sval, "SYNTAX") ||
1273 !strncmp(sval, "X-", 2) ) {
1274 /* Missing OID, backtrack */
1277 /* Non-numerical OID, ignore */
1283 ldap_matchingrule_free(mr);
1290 * Beyond this point we will be liberal and accept the items
1294 kind = get_token(&ss,&sval);
1297 *code = LDAP_SCHERR_NORIGHTPAREN;
1299 ldap_matchingrule_free(mr);
1304 if ( !strcmp(sval,"NAME") ) {
1307 *code = LDAP_SCHERR_DUPOPT;
1309 ldap_matchingrule_free(mr);
1313 mr->mr_names = parse_qdescrs(&ss,code);
1314 if ( !mr->mr_names ) {
1315 if ( *code != LDAP_SCHERR_OUTOFMEM )
1316 *code = LDAP_SCHERR_BADNAME;
1318 ldap_matchingrule_free(mr);
1321 } else if ( !strcmp(sval,"DESC") ) {
1324 *code = LDAP_SCHERR_DUPOPT;
1326 ldap_matchingrule_free(mr);
1331 kind = get_token(&ss,&sval);
1332 if ( kind != TK_QDSTRING ) {
1333 *code = LDAP_SCHERR_UNEXPTOKEN;
1336 ldap_matchingrule_free(mr);
1341 } else if ( !strcmp(sval,"OBSOLETE") ) {
1343 if ( seen_obsolete ) {
1344 *code = LDAP_SCHERR_DUPOPT;
1346 ldap_matchingrule_free(mr);
1350 mr->mr_obsolete = LDAP_SCHEMA_YES;
1352 } else if ( !strcmp(sval,"SYNTAX") ) {
1354 if ( seen_syntax ) {
1355 *code = LDAP_SCHERR_DUPOPT;
1357 ldap_matchingrule_free(mr);
1363 parse_numericoid(&ss,code,flags);
1364 if ( !mr->mr_syntax_oid ) {
1366 ldap_matchingrule_free(mr);
1370 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1371 /* Should be parse_qdstrings */
1372 ext_vals = parse_qdescrs(&ss, code);
1375 ldap_matchingrule_free(mr);
1378 if ( add_extension(&mr->mr_extensions,
1380 *code = LDAP_SCHERR_OUTOFMEM;
1383 ldap_matchingrule_free(mr);
1387 *code = LDAP_SCHERR_UNEXPTOKEN;
1390 ldap_matchingrule_free(mr);
1395 *code = LDAP_SCHERR_UNEXPTOKEN;
1398 ldap_matchingrule_free(mr);
1405 ldap_matchingruleuse_free( LDAPMatchingRuleUse * mru )
1407 LDAP_FREE(mru->mru_oid);
1408 LDAP_VFREE(mru->mru_names);
1409 LDAP_FREE(mru->mru_desc);
1410 LDAP_VFREE(mru->mru_applies_oids);
1411 free_extensions(mru->mru_extensions);
1415 LDAPMatchingRuleUse *
1416 ldap_str2matchingruleuse( const char * s, int * code, const char ** errp, const int flags )
1419 const char * ss = s;
1423 int seen_obsolete = 0;
1424 int seen_applies = 0;
1425 LDAPMatchingRuleUse * mru;
1427 const char * savepos;
1430 *code = LDAP_SCHERR_EMPTY;
1436 mru = LDAP_CALLOC(1,sizeof(LDAPMatchingRuleUse));
1439 *code = LDAP_SCHERR_OUTOFMEM;
1443 kind = get_token(&ss,&sval);
1444 if ( kind != TK_LEFTPAREN ) {
1445 *code = LDAP_SCHERR_NOLEFTPAREN;
1447 ldap_matchingruleuse_free(mru);
1453 mru->mru_oid = parse_numericoid(&ss,code,flags);
1454 if ( !mru->mru_oid ) {
1455 if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
1458 kind = get_token(&ss,&sval);
1459 if ( kind == TK_BAREWORD ) {
1460 if ( !strcmp(sval, "NAME") ||
1461 !strcmp(sval, "DESC") ||
1462 !strcmp(sval, "OBSOLETE") ||
1463 !strcmp(sval, "APPLIES") ||
1464 !strncmp(sval, "X-", 2) ) {
1465 /* Missing OID, backtrack */
1468 /* Non-numerical OID, ignore */
1474 ldap_matchingruleuse_free(mru);
1481 * Beyond this point we will be liberal and accept the items
1485 kind = get_token(&ss,&sval);
1488 *code = LDAP_SCHERR_NORIGHTPAREN;
1490 ldap_matchingruleuse_free(mru);
1495 if ( !strcmp(sval,"NAME") ) {
1498 *code = LDAP_SCHERR_DUPOPT;
1500 ldap_matchingruleuse_free(mru);
1504 mru->mru_names = parse_qdescrs(&ss,code);
1505 if ( !mru->mru_names ) {
1506 if ( *code != LDAP_SCHERR_OUTOFMEM )
1507 *code = LDAP_SCHERR_BADNAME;
1509 ldap_matchingruleuse_free(mru);
1512 } else if ( !strcmp(sval,"DESC") ) {
1515 *code = LDAP_SCHERR_DUPOPT;
1517 ldap_matchingruleuse_free(mru);
1522 kind = get_token(&ss,&sval);
1523 if ( kind != TK_QDSTRING ) {
1524 *code = LDAP_SCHERR_UNEXPTOKEN;
1527 ldap_matchingruleuse_free(mru);
1530 mru->mru_desc = sval;
1532 } else if ( !strcmp(sval,"OBSOLETE") ) {
1534 if ( seen_obsolete ) {
1535 *code = LDAP_SCHERR_DUPOPT;
1537 ldap_matchingruleuse_free(mru);
1541 mru->mru_obsolete = LDAP_SCHEMA_YES;
1543 } else if ( !strcmp(sval,"APPLIES") ) {
1545 if ( seen_applies ) {
1546 *code = LDAP_SCHERR_DUPOPT;
1548 ldap_matchingruleuse_free(mru);
1552 mru->mru_applies_oids = parse_oids(&ss,
1555 if ( !mru->mru_applies_oids ) {
1557 ldap_matchingruleuse_free(mru);
1560 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1561 /* Should be parse_qdstrings */
1562 ext_vals = parse_qdescrs(&ss, code);
1565 ldap_matchingruleuse_free(mru);
1568 if ( add_extension(&mru->mru_extensions,
1570 *code = LDAP_SCHERR_OUTOFMEM;
1573 ldap_matchingruleuse_free(mru);
1577 *code = LDAP_SCHERR_UNEXPTOKEN;
1580 ldap_matchingruleuse_free(mru);
1585 *code = LDAP_SCHERR_UNEXPTOKEN;
1588 ldap_matchingruleuse_free(mru);
1595 ldap_attributetype_free(LDAPAttributeType * at)
1597 LDAP_FREE(at->at_oid);
1598 LDAP_VFREE(at->at_names);
1599 LDAP_FREE(at->at_desc);
1600 LDAP_FREE(at->at_sup_oid);
1601 LDAP_FREE(at->at_equality_oid);
1602 LDAP_FREE(at->at_ordering_oid);
1603 LDAP_FREE(at->at_substr_oid);
1604 LDAP_FREE(at->at_syntax_oid);
1605 free_extensions(at->at_extensions);
1610 ldap_str2attributetype( const char * s, int * code, const char ** errp, const int flags )
1613 const char * ss = s;
1617 int seen_obsolete = 0;
1619 int seen_equality = 0;
1620 int seen_ordering = 0;
1621 int seen_substr = 0;
1622 int seen_syntax = 0;
1624 LDAPAttributeType * at;
1626 const char * savepos;
1629 *code = LDAP_SCHERR_EMPTY;
1635 at = LDAP_CALLOC(1,sizeof(LDAPAttributeType));
1638 *code = LDAP_SCHERR_OUTOFMEM;
1642 kind = get_token(&ss,&sval);
1643 if ( kind != TK_LEFTPAREN ) {
1644 *code = LDAP_SCHERR_NOLEFTPAREN;
1646 ldap_attributetype_free(at);
1651 * Definitions MUST begin with an OID in the numericoid format.
1652 * However, this routine is used by clients to parse the response
1653 * from servers and very well known servers will provide an OID
1654 * in the wrong format or even no OID at all. We do our best to
1655 * extract info from those servers.
1659 at->at_oid = parse_numericoid(&ss,code,0);
1660 if ( !at->at_oid ) {
1661 if ( flags & ( LDAP_SCHEMA_ALLOW_NO_OID
1662 | LDAP_SCHEMA_ALLOW_OID_MACRO ) ) {
1665 kind = get_token(&ss,&sval);
1666 if ( kind == TK_BAREWORD ) {
1667 if ( !strcmp(sval, "NAME") ||
1668 !strcmp(sval, "DESC") ||
1669 !strcmp(sval, "OBSOLETE") ||
1670 !strcmp(sval, "SUP") ||
1671 !strcmp(sval, "EQUALITY") ||
1672 !strcmp(sval, "ORDERING") ||
1673 !strcmp(sval, "SUBSTR") ||
1674 !strcmp(sval, "SYNTAX") ||
1675 !strcmp(sval, "SINGLE-VALUE") ||
1676 !strcmp(sval, "COLLECTIVE") ||
1677 !strcmp(sval, "NO-USER-MODIFICATION") ||
1678 !strcmp(sval, "USAGE") ||
1679 !strncmp(sval, "X-", 2) ) {
1680 /* Missing OID, backtrack */
1683 & LDAP_SCHEMA_ALLOW_OID_MACRO) {
1684 /* Non-numerical OID ... */
1685 int len = ss-savepos;
1686 at->at_oid = LDAP_MALLOC(len+1);
1687 strncpy(at->at_oid, savepos, len);
1688 at->at_oid[len] = 0;
1694 ldap_attributetype_free(at);
1701 * Beyond this point we will be liberal and accept the items
1705 kind = get_token(&ss,&sval);
1708 *code = LDAP_SCHERR_NORIGHTPAREN;
1710 ldap_attributetype_free(at);
1715 if ( !strcmp(sval,"NAME") ) {
1718 *code = LDAP_SCHERR_DUPOPT;
1720 ldap_attributetype_free(at);
1724 at->at_names = parse_qdescrs(&ss,code);
1725 if ( !at->at_names ) {
1726 if ( *code != LDAP_SCHERR_OUTOFMEM )
1727 *code = LDAP_SCHERR_BADNAME;
1729 ldap_attributetype_free(at);
1732 } else if ( !strcmp(sval,"DESC") ) {
1735 *code = LDAP_SCHERR_DUPOPT;
1737 ldap_attributetype_free(at);
1742 kind = get_token(&ss,&sval);
1743 if ( kind != TK_QDSTRING ) {
1744 *code = LDAP_SCHERR_UNEXPTOKEN;
1747 ldap_attributetype_free(at);
1752 } else if ( !strcmp(sval,"OBSOLETE") ) {
1754 if ( seen_obsolete ) {
1755 *code = LDAP_SCHERR_DUPOPT;
1757 ldap_attributetype_free(at);
1761 at->at_obsolete = LDAP_SCHEMA_YES;
1763 } else if ( !strcmp(sval,"SUP") ) {
1766 *code = LDAP_SCHERR_DUPOPT;
1768 ldap_attributetype_free(at);
1772 at->at_sup_oid = parse_woid(&ss,code);
1773 if ( !at->at_sup_oid ) {
1775 ldap_attributetype_free(at);
1778 } else if ( !strcmp(sval,"EQUALITY") ) {
1780 if ( seen_equality ) {
1781 *code = LDAP_SCHERR_DUPOPT;
1783 ldap_attributetype_free(at);
1787 at->at_equality_oid = parse_woid(&ss,code);
1788 if ( !at->at_equality_oid ) {
1790 ldap_attributetype_free(at);
1793 } else if ( !strcmp(sval,"ORDERING") ) {
1795 if ( seen_ordering ) {
1796 *code = LDAP_SCHERR_DUPOPT;
1798 ldap_attributetype_free(at);
1802 at->at_ordering_oid = parse_woid(&ss,code);
1803 if ( !at->at_ordering_oid ) {
1805 ldap_attributetype_free(at);
1808 } else if ( !strcmp(sval,"SUBSTR") ) {
1810 if ( seen_substr ) {
1811 *code = LDAP_SCHERR_DUPOPT;
1813 ldap_attributetype_free(at);
1817 at->at_substr_oid = parse_woid(&ss,code);
1818 if ( !at->at_substr_oid ) {
1820 ldap_attributetype_free(at);
1823 } else if ( !strcmp(sval,"SYNTAX") ) {
1825 if ( seen_syntax ) {
1826 *code = LDAP_SCHERR_DUPOPT;
1828 ldap_attributetype_free(at);
1839 if ( !at->at_syntax_oid ) {
1840 if ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO ) {
1841 kind = get_token(&ss,&sval);
1842 if (kind == TK_BAREWORD)
1844 char *sp = strchr(sval, '{');
1845 at->at_syntax_oid = sval;
1849 at->at_syntax_len = atoi(sp);
1850 while ( LDAP_DIGIT(*sp) )
1853 *code = LDAP_SCHERR_UNEXPTOKEN;
1855 ldap_attributetype_free(at);
1862 ldap_attributetype_free(at);
1867 } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
1869 if ( at->at_single_value ) {
1870 *code = LDAP_SCHERR_DUPOPT;
1872 ldap_attributetype_free(at);
1875 at->at_single_value = LDAP_SCHEMA_YES;
1877 } else if ( !strcmp(sval,"COLLECTIVE") ) {
1879 if ( at->at_collective ) {
1880 *code = LDAP_SCHERR_DUPOPT;
1882 ldap_attributetype_free(at);
1885 at->at_collective = LDAP_SCHEMA_YES;
1887 } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
1889 if ( at->at_no_user_mod ) {
1890 *code = LDAP_SCHERR_DUPOPT;
1892 ldap_attributetype_free(at);
1895 at->at_no_user_mod = LDAP_SCHEMA_YES;
1897 } else if ( !strcmp(sval,"USAGE") ) {
1900 *code = LDAP_SCHERR_DUPOPT;
1902 ldap_attributetype_free(at);
1907 kind = get_token(&ss,&sval);
1908 if ( kind != TK_BAREWORD ) {
1909 *code = LDAP_SCHERR_UNEXPTOKEN;
1912 ldap_attributetype_free(at);
1915 if ( !strcasecmp(sval,"userApplications") )
1917 LDAP_SCHEMA_USER_APPLICATIONS;
1918 else if ( !strcasecmp(sval,"directoryOperation") )
1920 LDAP_SCHEMA_DIRECTORY_OPERATION;
1921 else if ( !strcasecmp(sval,"distributedOperation") )
1923 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
1924 else if ( !strcasecmp(sval,"dSAOperation") )
1926 LDAP_SCHEMA_DSA_OPERATION;
1928 *code = LDAP_SCHERR_UNEXPTOKEN;
1931 ldap_attributetype_free(at);
1936 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1937 /* Should be parse_qdstrings */
1938 ext_vals = parse_qdescrs(&ss, code);
1941 ldap_attributetype_free(at);
1944 if ( add_extension(&at->at_extensions,
1946 *code = LDAP_SCHERR_OUTOFMEM;
1949 ldap_attributetype_free(at);
1953 *code = LDAP_SCHERR_UNEXPTOKEN;
1956 ldap_attributetype_free(at);
1961 *code = LDAP_SCHERR_UNEXPTOKEN;
1964 ldap_attributetype_free(at);
1971 ldap_objectclass_free(LDAPObjectClass * oc)
1973 LDAP_FREE(oc->oc_oid);
1974 LDAP_VFREE(oc->oc_names);
1975 LDAP_FREE(oc->oc_desc);
1976 LDAP_VFREE(oc->oc_sup_oids);
1977 LDAP_VFREE(oc->oc_at_oids_must);
1978 LDAP_VFREE(oc->oc_at_oids_may);
1979 free_extensions(oc->oc_extensions);
1984 ldap_str2objectclass( const char * s, int * code, const char ** errp, const int flags )
1987 const char * ss = s;
1991 int seen_obsolete = 0;
1996 LDAPObjectClass * oc;
1998 const char * savepos;
2001 *code = LDAP_SCHERR_EMPTY;
2007 oc = LDAP_CALLOC(1,sizeof(LDAPObjectClass));
2010 *code = LDAP_SCHERR_OUTOFMEM;
2013 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
2015 kind = get_token(&ss,&sval);
2016 if ( kind != TK_LEFTPAREN ) {
2017 *code = LDAP_SCHERR_NOLEFTPAREN;
2019 ldap_objectclass_free(oc);
2024 * Definitions MUST begin with an OID in the numericoid format.
2025 * However, this routine is used by clients to parse the response
2026 * from servers and very well known servers will provide an OID
2027 * in the wrong format or even no OID at all. We do our best to
2028 * extract info from those servers.
2032 oc->oc_oid = parse_numericoid(&ss,code,0);
2033 if ( !oc->oc_oid ) {
2034 if ( flags & LDAP_SCHEMA_ALLOW_ALL ) {
2037 kind = get_token(&ss,&sval);
2038 if ( kind == TK_BAREWORD ) {
2039 if ( !strcmp(sval, "NAME") ||
2040 !strcmp(sval, "DESC") ||
2041 !strcmp(sval, "OBSOLETE") ||
2042 !strcmp(sval, "SUP") ||
2043 !strcmp(sval, "ABSTRACT") ||
2044 !strcmp(sval, "STRUCTURAL") ||
2045 !strcmp(sval, "AUXILIARY") ||
2046 !strcmp(sval, "MUST") ||
2047 !strncmp(sval, "X-", 2) ) {
2048 /* Missing OID, backtrack */
2051 LDAP_SCHEMA_ALLOW_OID_MACRO ) {
2052 /* Non-numerical OID, ignore */
2053 int len = ss-savepos;
2054 oc->oc_oid = LDAP_MALLOC(len+1);
2055 strncpy(oc->oc_oid, savepos, len);
2056 oc->oc_oid[len] = 0;
2062 ldap_objectclass_free(oc);
2069 * Beyond this point we will be liberal an accept the items
2073 kind = get_token(&ss,&sval);
2076 *code = LDAP_SCHERR_NORIGHTPAREN;
2078 ldap_objectclass_free(oc);
2083 if ( !strcmp(sval,"NAME") ) {
2086 *code = LDAP_SCHERR_DUPOPT;
2088 ldap_objectclass_free(oc);
2092 oc->oc_names = parse_qdescrs(&ss,code);
2093 if ( !oc->oc_names ) {
2094 if ( *code != LDAP_SCHERR_OUTOFMEM )
2095 *code = LDAP_SCHERR_BADNAME;
2097 ldap_objectclass_free(oc);
2100 } else if ( !strcmp(sval,"DESC") ) {
2103 *code = LDAP_SCHERR_DUPOPT;
2105 ldap_objectclass_free(oc);
2110 kind = get_token(&ss,&sval);
2111 if ( kind != TK_QDSTRING ) {
2112 *code = LDAP_SCHERR_UNEXPTOKEN;
2115 ldap_objectclass_free(oc);
2120 } else if ( !strcmp(sval,"OBSOLETE") ) {
2122 if ( seen_obsolete ) {
2123 *code = LDAP_SCHERR_DUPOPT;
2125 ldap_objectclass_free(oc);
2129 oc->oc_obsolete = LDAP_SCHEMA_YES;
2131 } else if ( !strcmp(sval,"SUP") ) {
2134 *code = LDAP_SCHERR_DUPOPT;
2136 ldap_objectclass_free(oc);
2140 oc->oc_sup_oids = parse_oids(&ss,
2143 if ( !oc->oc_sup_oids ) {
2145 ldap_objectclass_free(oc);
2148 } else if ( !strcmp(sval,"ABSTRACT") ) {
2151 *code = LDAP_SCHERR_DUPOPT;
2153 ldap_objectclass_free(oc);
2157 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
2159 } else if ( !strcmp(sval,"STRUCTURAL") ) {
2162 *code = LDAP_SCHERR_DUPOPT;
2164 ldap_objectclass_free(oc);
2168 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
2170 } else if ( !strcmp(sval,"AUXILIARY") ) {
2173 *code = LDAP_SCHERR_DUPOPT;
2175 ldap_objectclass_free(oc);
2179 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
2181 } else if ( !strcmp(sval,"MUST") ) {
2184 *code = LDAP_SCHERR_DUPOPT;
2186 ldap_objectclass_free(oc);
2190 oc->oc_at_oids_must = parse_oids(&ss,code,0);
2191 if ( !oc->oc_at_oids_must ) {
2193 ldap_objectclass_free(oc);
2197 } else if ( !strcmp(sval,"MAY") ) {
2200 *code = LDAP_SCHERR_DUPOPT;
2202 ldap_objectclass_free(oc);
2206 oc->oc_at_oids_may = parse_oids(&ss,code,0);
2207 if ( !oc->oc_at_oids_may ) {
2209 ldap_objectclass_free(oc);
2213 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
2214 /* Should be parse_qdstrings */
2215 ext_vals = parse_qdescrs(&ss, code);
2218 ldap_objectclass_free(oc);
2221 if ( add_extension(&oc->oc_extensions,
2223 *code = LDAP_SCHERR_OUTOFMEM;
2226 ldap_objectclass_free(oc);
2230 *code = LDAP_SCHERR_UNEXPTOKEN;
2233 ldap_objectclass_free(oc);
2238 *code = LDAP_SCHERR_UNEXPTOKEN;
2241 ldap_objectclass_free(oc);
2247 static char *const err2text[] = {
2251 "Missing opening parenthesis",
2252 "Missing closing parenthesis",
2258 "Unexpected end of data"
2262 ldap_scherr2str(int code)
2264 if ( code < 0 || code >= (sizeof(err2text)/sizeof(char *)) ) {
2265 return "Unknown error";
2267 return err2text[code];