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>
24 choose_name( char *names[], 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( 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( 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( 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( 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( 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( LDAP_CONST char * s,
1088 LDAP_CONST char ** errp,
1089 LDAP_CONST int flags )
1092 const char * ss = s;
1100 *code = LDAP_SCHERR_EMPTY;
1106 syn = LDAP_CALLOC(1,sizeof(LDAPSyntax));
1109 *code = LDAP_SCHERR_OUTOFMEM;
1113 kind = get_token(&ss,&sval);
1114 if ( kind != TK_LEFTPAREN ) {
1116 *code = LDAP_SCHERR_NOLEFTPAREN;
1117 ldap_syntax_free(syn);
1122 syn->syn_oid = parse_numericoid(&ss,code,0);
1123 if ( !syn->syn_oid ) {
1125 ldap_syntax_free(syn);
1131 * Beyond this point we will be liberal and accept the items
1135 kind = get_token(&ss,&sval);
1138 *code = LDAP_SCHERR_NORIGHTPAREN;
1140 ldap_syntax_free(syn);
1145 if ( !strcmp(sval,"NAME") ) {
1148 *code = LDAP_SCHERR_DUPOPT;
1150 ldap_syntax_free(syn);
1154 syn->syn_names = parse_qdescrs(&ss,code);
1155 if ( !syn->syn_names ) {
1156 if ( *code != LDAP_SCHERR_OUTOFMEM )
1157 *code = LDAP_SCHERR_BADNAME;
1159 ldap_syntax_free(syn);
1162 } else if ( !strcmp(sval,"DESC") ) {
1165 *code = LDAP_SCHERR_DUPOPT;
1167 ldap_syntax_free(syn);
1172 kind = get_token(&ss,&sval);
1173 if ( kind != TK_QDSTRING ) {
1174 *code = LDAP_SCHERR_UNEXPTOKEN;
1177 ldap_syntax_free(syn);
1180 syn->syn_desc = sval;
1182 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1183 /* Should be parse_qdstrings */
1184 ext_vals = parse_qdescrs(&ss, code);
1187 ldap_syntax_free(syn);
1190 if ( add_extension(&syn->syn_extensions,
1192 *code = LDAP_SCHERR_OUTOFMEM;
1195 ldap_syntax_free(syn);
1199 *code = LDAP_SCHERR_UNEXPTOKEN;
1202 ldap_syntax_free(syn);
1207 *code = LDAP_SCHERR_UNEXPTOKEN;
1210 ldap_syntax_free(syn);
1217 ldap_matchingrule_free( LDAPMatchingRule * mr )
1219 LDAP_FREE(mr->mr_oid);
1220 LDAP_VFREE(mr->mr_names);
1221 LDAP_FREE(mr->mr_desc);
1222 LDAP_FREE(mr->mr_syntax_oid);
1223 free_extensions(mr->mr_extensions);
1228 ldap_str2matchingrule( LDAP_CONST char * s,
1230 LDAP_CONST char ** errp,
1231 LDAP_CONST int flags )
1234 const char * ss = s;
1238 int seen_obsolete = 0;
1239 int seen_syntax = 0;
1240 LDAPMatchingRule * mr;
1242 const char * savepos;
1245 *code = LDAP_SCHERR_EMPTY;
1251 mr = LDAP_CALLOC(1,sizeof(LDAPMatchingRule));
1254 *code = LDAP_SCHERR_OUTOFMEM;
1258 kind = get_token(&ss,&sval);
1259 if ( kind != TK_LEFTPAREN ) {
1260 *code = LDAP_SCHERR_NOLEFTPAREN;
1262 ldap_matchingrule_free(mr);
1268 mr->mr_oid = parse_numericoid(&ss,code,flags);
1269 if ( !mr->mr_oid ) {
1270 if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
1273 kind = get_token(&ss,&sval);
1274 if ( kind == TK_BAREWORD ) {
1275 if ( !strcmp(sval, "NAME") ||
1276 !strcmp(sval, "DESC") ||
1277 !strcmp(sval, "OBSOLETE") ||
1278 !strcmp(sval, "SYNTAX") ||
1279 !strncmp(sval, "X-", 2) ) {
1280 /* Missing OID, backtrack */
1283 /* Non-numerical OID, ignore */
1289 ldap_matchingrule_free(mr);
1296 * Beyond this point we will be liberal and accept the items
1300 kind = get_token(&ss,&sval);
1303 *code = LDAP_SCHERR_NORIGHTPAREN;
1305 ldap_matchingrule_free(mr);
1310 if ( !strcmp(sval,"NAME") ) {
1313 *code = LDAP_SCHERR_DUPOPT;
1315 ldap_matchingrule_free(mr);
1319 mr->mr_names = parse_qdescrs(&ss,code);
1320 if ( !mr->mr_names ) {
1321 if ( *code != LDAP_SCHERR_OUTOFMEM )
1322 *code = LDAP_SCHERR_BADNAME;
1324 ldap_matchingrule_free(mr);
1327 } else if ( !strcmp(sval,"DESC") ) {
1330 *code = LDAP_SCHERR_DUPOPT;
1332 ldap_matchingrule_free(mr);
1337 kind = get_token(&ss,&sval);
1338 if ( kind != TK_QDSTRING ) {
1339 *code = LDAP_SCHERR_UNEXPTOKEN;
1342 ldap_matchingrule_free(mr);
1347 } else if ( !strcmp(sval,"OBSOLETE") ) {
1349 if ( seen_obsolete ) {
1350 *code = LDAP_SCHERR_DUPOPT;
1352 ldap_matchingrule_free(mr);
1356 mr->mr_obsolete = LDAP_SCHEMA_YES;
1358 } else if ( !strcmp(sval,"SYNTAX") ) {
1360 if ( seen_syntax ) {
1361 *code = LDAP_SCHERR_DUPOPT;
1363 ldap_matchingrule_free(mr);
1369 parse_numericoid(&ss,code,flags);
1370 if ( !mr->mr_syntax_oid ) {
1372 ldap_matchingrule_free(mr);
1376 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1377 /* Should be parse_qdstrings */
1378 ext_vals = parse_qdescrs(&ss, code);
1381 ldap_matchingrule_free(mr);
1384 if ( add_extension(&mr->mr_extensions,
1386 *code = LDAP_SCHERR_OUTOFMEM;
1389 ldap_matchingrule_free(mr);
1393 *code = LDAP_SCHERR_UNEXPTOKEN;
1396 ldap_matchingrule_free(mr);
1401 *code = LDAP_SCHERR_UNEXPTOKEN;
1404 ldap_matchingrule_free(mr);
1411 ldap_matchingruleuse_free( LDAPMatchingRuleUse * mru )
1413 LDAP_FREE(mru->mru_oid);
1414 LDAP_VFREE(mru->mru_names);
1415 LDAP_FREE(mru->mru_desc);
1416 LDAP_VFREE(mru->mru_applies_oids);
1417 free_extensions(mru->mru_extensions);
1421 LDAPMatchingRuleUse *
1422 ldap_str2matchingruleuse( LDAP_CONST char * s,
1424 LDAP_CONST char ** errp,
1425 LDAP_CONST int flags )
1428 const char * ss = s;
1432 int seen_obsolete = 0;
1433 int seen_applies = 0;
1434 LDAPMatchingRuleUse * mru;
1436 const char * savepos;
1439 *code = LDAP_SCHERR_EMPTY;
1445 mru = LDAP_CALLOC(1,sizeof(LDAPMatchingRuleUse));
1448 *code = LDAP_SCHERR_OUTOFMEM;
1452 kind = get_token(&ss,&sval);
1453 if ( kind != TK_LEFTPAREN ) {
1454 *code = LDAP_SCHERR_NOLEFTPAREN;
1456 ldap_matchingruleuse_free(mru);
1462 mru->mru_oid = parse_numericoid(&ss,code,flags);
1463 if ( !mru->mru_oid ) {
1464 if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
1467 kind = get_token(&ss,&sval);
1468 if ( kind == TK_BAREWORD ) {
1469 if ( !strcmp(sval, "NAME") ||
1470 !strcmp(sval, "DESC") ||
1471 !strcmp(sval, "OBSOLETE") ||
1472 !strcmp(sval, "APPLIES") ||
1473 !strncmp(sval, "X-", 2) ) {
1474 /* Missing OID, backtrack */
1477 /* Non-numerical OID, ignore */
1483 ldap_matchingruleuse_free(mru);
1490 * Beyond this point we will be liberal and accept the items
1494 kind = get_token(&ss,&sval);
1497 *code = LDAP_SCHERR_NORIGHTPAREN;
1499 ldap_matchingruleuse_free(mru);
1504 if ( !strcmp(sval,"NAME") ) {
1507 *code = LDAP_SCHERR_DUPOPT;
1509 ldap_matchingruleuse_free(mru);
1513 mru->mru_names = parse_qdescrs(&ss,code);
1514 if ( !mru->mru_names ) {
1515 if ( *code != LDAP_SCHERR_OUTOFMEM )
1516 *code = LDAP_SCHERR_BADNAME;
1518 ldap_matchingruleuse_free(mru);
1521 } else if ( !strcmp(sval,"DESC") ) {
1524 *code = LDAP_SCHERR_DUPOPT;
1526 ldap_matchingruleuse_free(mru);
1531 kind = get_token(&ss,&sval);
1532 if ( kind != TK_QDSTRING ) {
1533 *code = LDAP_SCHERR_UNEXPTOKEN;
1536 ldap_matchingruleuse_free(mru);
1539 mru->mru_desc = sval;
1541 } else if ( !strcmp(sval,"OBSOLETE") ) {
1543 if ( seen_obsolete ) {
1544 *code = LDAP_SCHERR_DUPOPT;
1546 ldap_matchingruleuse_free(mru);
1550 mru->mru_obsolete = LDAP_SCHEMA_YES;
1552 } else if ( !strcmp(sval,"APPLIES") ) {
1554 if ( seen_applies ) {
1555 *code = LDAP_SCHERR_DUPOPT;
1557 ldap_matchingruleuse_free(mru);
1561 mru->mru_applies_oids = parse_oids(&ss,
1564 if ( !mru->mru_applies_oids ) {
1566 ldap_matchingruleuse_free(mru);
1569 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1570 /* Should be parse_qdstrings */
1571 ext_vals = parse_qdescrs(&ss, code);
1574 ldap_matchingruleuse_free(mru);
1577 if ( add_extension(&mru->mru_extensions,
1579 *code = LDAP_SCHERR_OUTOFMEM;
1582 ldap_matchingruleuse_free(mru);
1586 *code = LDAP_SCHERR_UNEXPTOKEN;
1589 ldap_matchingruleuse_free(mru);
1594 *code = LDAP_SCHERR_UNEXPTOKEN;
1597 ldap_matchingruleuse_free(mru);
1604 ldap_attributetype_free(LDAPAttributeType * at)
1606 LDAP_FREE(at->at_oid);
1607 LDAP_VFREE(at->at_names);
1608 LDAP_FREE(at->at_desc);
1609 LDAP_FREE(at->at_sup_oid);
1610 LDAP_FREE(at->at_equality_oid);
1611 LDAP_FREE(at->at_ordering_oid);
1612 LDAP_FREE(at->at_substr_oid);
1613 LDAP_FREE(at->at_syntax_oid);
1614 free_extensions(at->at_extensions);
1619 ldap_str2attributetype( LDAP_CONST char * s,
1621 LDAP_CONST char ** errp,
1622 LDAP_CONST int flags )
1625 const char * ss = s;
1629 int seen_obsolete = 0;
1631 int seen_equality = 0;
1632 int seen_ordering = 0;
1633 int seen_substr = 0;
1634 int seen_syntax = 0;
1636 LDAPAttributeType * at;
1638 const char * savepos;
1641 *code = LDAP_SCHERR_EMPTY;
1647 at = LDAP_CALLOC(1,sizeof(LDAPAttributeType));
1650 *code = LDAP_SCHERR_OUTOFMEM;
1654 kind = get_token(&ss,&sval);
1655 if ( kind != TK_LEFTPAREN ) {
1656 *code = LDAP_SCHERR_NOLEFTPAREN;
1658 ldap_attributetype_free(at);
1663 * Definitions MUST begin with an OID in the numericoid format.
1664 * However, this routine is used by clients to parse the response
1665 * from servers and very well known servers will provide an OID
1666 * in the wrong format or even no OID at all. We do our best to
1667 * extract info from those servers.
1671 at->at_oid = parse_numericoid(&ss,code,0);
1672 if ( !at->at_oid ) {
1673 if ( ( flags & ( LDAP_SCHEMA_ALLOW_NO_OID
1674 | LDAP_SCHEMA_ALLOW_OID_MACRO ) )
1675 && (ss == savepos) ) {
1678 kind = get_token(&ss,&sval);
1679 if ( kind == TK_BAREWORD ) {
1680 if ( !strcmp(sval, "NAME") ||
1681 !strcmp(sval, "DESC") ||
1682 !strcmp(sval, "OBSOLETE") ||
1683 !strcmp(sval, "SUP") ||
1684 !strcmp(sval, "EQUALITY") ||
1685 !strcmp(sval, "ORDERING") ||
1686 !strcmp(sval, "SUBSTR") ||
1687 !strcmp(sval, "SYNTAX") ||
1688 !strcmp(sval, "SINGLE-VALUE") ||
1689 !strcmp(sval, "COLLECTIVE") ||
1690 !strcmp(sval, "NO-USER-MODIFICATION") ||
1691 !strcmp(sval, "USAGE") ||
1692 !strncmp(sval, "X-", 2) ) {
1693 /* Missing OID, backtrack */
1696 & LDAP_SCHEMA_ALLOW_OID_MACRO) {
1697 /* Non-numerical OID ... */
1698 int len = ss-savepos;
1699 at->at_oid = LDAP_MALLOC(len+1);
1700 strncpy(at->at_oid, savepos, len);
1701 at->at_oid[len] = 0;
1707 ldap_attributetype_free(at);
1714 * Beyond this point we will be liberal and accept the items
1718 kind = get_token(&ss,&sval);
1721 *code = LDAP_SCHERR_NORIGHTPAREN;
1723 ldap_attributetype_free(at);
1728 if ( !strcmp(sval,"NAME") ) {
1731 *code = LDAP_SCHERR_DUPOPT;
1733 ldap_attributetype_free(at);
1737 at->at_names = parse_qdescrs(&ss,code);
1738 if ( !at->at_names ) {
1739 if ( *code != LDAP_SCHERR_OUTOFMEM )
1740 *code = LDAP_SCHERR_BADNAME;
1742 ldap_attributetype_free(at);
1745 } else if ( !strcmp(sval,"DESC") ) {
1748 *code = LDAP_SCHERR_DUPOPT;
1750 ldap_attributetype_free(at);
1755 kind = get_token(&ss,&sval);
1756 if ( kind != TK_QDSTRING ) {
1757 *code = LDAP_SCHERR_UNEXPTOKEN;
1760 ldap_attributetype_free(at);
1765 } else if ( !strcmp(sval,"OBSOLETE") ) {
1767 if ( seen_obsolete ) {
1768 *code = LDAP_SCHERR_DUPOPT;
1770 ldap_attributetype_free(at);
1774 at->at_obsolete = LDAP_SCHEMA_YES;
1776 } else if ( !strcmp(sval,"SUP") ) {
1779 *code = LDAP_SCHERR_DUPOPT;
1781 ldap_attributetype_free(at);
1785 at->at_sup_oid = parse_woid(&ss,code);
1786 if ( !at->at_sup_oid ) {
1788 ldap_attributetype_free(at);
1791 } else if ( !strcmp(sval,"EQUALITY") ) {
1793 if ( seen_equality ) {
1794 *code = LDAP_SCHERR_DUPOPT;
1796 ldap_attributetype_free(at);
1800 at->at_equality_oid = parse_woid(&ss,code);
1801 if ( !at->at_equality_oid ) {
1803 ldap_attributetype_free(at);
1806 } else if ( !strcmp(sval,"ORDERING") ) {
1808 if ( seen_ordering ) {
1809 *code = LDAP_SCHERR_DUPOPT;
1811 ldap_attributetype_free(at);
1815 at->at_ordering_oid = parse_woid(&ss,code);
1816 if ( !at->at_ordering_oid ) {
1818 ldap_attributetype_free(at);
1821 } else if ( !strcmp(sval,"SUBSTR") ) {
1823 if ( seen_substr ) {
1824 *code = LDAP_SCHERR_DUPOPT;
1826 ldap_attributetype_free(at);
1830 at->at_substr_oid = parse_woid(&ss,code);
1831 if ( !at->at_substr_oid ) {
1833 ldap_attributetype_free(at);
1836 } else if ( !strcmp(sval,"SYNTAX") ) {
1838 if ( seen_syntax ) {
1839 *code = LDAP_SCHERR_DUPOPT;
1841 ldap_attributetype_free(at);
1852 if ( !at->at_syntax_oid ) {
1853 if ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO ) {
1854 kind = get_token(&ss,&sval);
1855 if (kind == TK_BAREWORD)
1857 char *sp = strchr(sval, '{');
1858 at->at_syntax_oid = sval;
1862 at->at_syntax_len = atoi(sp);
1863 while ( LDAP_DIGIT(*sp) )
1866 *code = LDAP_SCHERR_UNEXPTOKEN;
1868 ldap_attributetype_free(at);
1875 ldap_attributetype_free(at);
1880 } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
1882 if ( at->at_single_value ) {
1883 *code = LDAP_SCHERR_DUPOPT;
1885 ldap_attributetype_free(at);
1888 at->at_single_value = LDAP_SCHEMA_YES;
1890 } else if ( !strcmp(sval,"COLLECTIVE") ) {
1892 if ( at->at_collective ) {
1893 *code = LDAP_SCHERR_DUPOPT;
1895 ldap_attributetype_free(at);
1898 at->at_collective = LDAP_SCHEMA_YES;
1900 } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
1902 if ( at->at_no_user_mod ) {
1903 *code = LDAP_SCHERR_DUPOPT;
1905 ldap_attributetype_free(at);
1908 at->at_no_user_mod = LDAP_SCHEMA_YES;
1910 } else if ( !strcmp(sval,"USAGE") ) {
1913 *code = LDAP_SCHERR_DUPOPT;
1915 ldap_attributetype_free(at);
1920 kind = get_token(&ss,&sval);
1921 if ( kind != TK_BAREWORD ) {
1922 *code = LDAP_SCHERR_UNEXPTOKEN;
1925 ldap_attributetype_free(at);
1928 if ( !strcasecmp(sval,"userApplications") )
1930 LDAP_SCHEMA_USER_APPLICATIONS;
1931 else if ( !strcasecmp(sval,"directoryOperation") )
1933 LDAP_SCHEMA_DIRECTORY_OPERATION;
1934 else if ( !strcasecmp(sval,"distributedOperation") )
1936 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
1937 else if ( !strcasecmp(sval,"dSAOperation") )
1939 LDAP_SCHEMA_DSA_OPERATION;
1941 *code = LDAP_SCHERR_UNEXPTOKEN;
1944 ldap_attributetype_free(at);
1949 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1950 /* Should be parse_qdstrings */
1951 ext_vals = parse_qdescrs(&ss, code);
1954 ldap_attributetype_free(at);
1957 if ( add_extension(&at->at_extensions,
1959 *code = LDAP_SCHERR_OUTOFMEM;
1962 ldap_attributetype_free(at);
1966 *code = LDAP_SCHERR_UNEXPTOKEN;
1969 ldap_attributetype_free(at);
1974 *code = LDAP_SCHERR_UNEXPTOKEN;
1977 ldap_attributetype_free(at);
1984 ldap_objectclass_free(LDAPObjectClass * oc)
1986 LDAP_FREE(oc->oc_oid);
1987 LDAP_VFREE(oc->oc_names);
1988 LDAP_FREE(oc->oc_desc);
1989 LDAP_VFREE(oc->oc_sup_oids);
1990 LDAP_VFREE(oc->oc_at_oids_must);
1991 LDAP_VFREE(oc->oc_at_oids_may);
1992 free_extensions(oc->oc_extensions);
1997 ldap_str2objectclass( LDAP_CONST char * s,
1999 LDAP_CONST char ** errp,
2000 LDAP_CONST int flags )
2003 const char * ss = s;
2007 int seen_obsolete = 0;
2012 LDAPObjectClass * oc;
2014 const char * savepos;
2017 *code = LDAP_SCHERR_EMPTY;
2023 oc = LDAP_CALLOC(1,sizeof(LDAPObjectClass));
2026 *code = LDAP_SCHERR_OUTOFMEM;
2029 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
2031 kind = get_token(&ss,&sval);
2032 if ( kind != TK_LEFTPAREN ) {
2033 *code = LDAP_SCHERR_NOLEFTPAREN;
2035 ldap_objectclass_free(oc);
2040 * Definitions MUST begin with an OID in the numericoid format.
2041 * However, this routine is used by clients to parse the response
2042 * from servers and very well known servers will provide an OID
2043 * in the wrong format or even no OID at all. We do our best to
2044 * extract info from those servers.
2048 oc->oc_oid = parse_numericoid(&ss,code,0);
2049 if ( !oc->oc_oid ) {
2050 if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) {
2053 kind = get_token(&ss,&sval);
2054 if ( kind == TK_BAREWORD ) {
2055 if ( !strcmp(sval, "NAME") ||
2056 !strcmp(sval, "DESC") ||
2057 !strcmp(sval, "OBSOLETE") ||
2058 !strcmp(sval, "SUP") ||
2059 !strcmp(sval, "ABSTRACT") ||
2060 !strcmp(sval, "STRUCTURAL") ||
2061 !strcmp(sval, "AUXILIARY") ||
2062 !strcmp(sval, "MUST") ||
2063 !strncmp(sval, "X-", 2) ) {
2064 /* Missing OID, backtrack */
2067 LDAP_SCHEMA_ALLOW_OID_MACRO ) {
2068 /* Non-numerical OID, ignore */
2069 int len = ss-savepos;
2070 oc->oc_oid = LDAP_MALLOC(len+1);
2071 strncpy(oc->oc_oid, savepos, len);
2072 oc->oc_oid[len] = 0;
2078 ldap_objectclass_free(oc);
2085 * Beyond this point we will be liberal an accept the items
2089 kind = get_token(&ss,&sval);
2092 *code = LDAP_SCHERR_NORIGHTPAREN;
2094 ldap_objectclass_free(oc);
2099 if ( !strcmp(sval,"NAME") ) {
2102 *code = LDAP_SCHERR_DUPOPT;
2104 ldap_objectclass_free(oc);
2108 oc->oc_names = parse_qdescrs(&ss,code);
2109 if ( !oc->oc_names ) {
2110 if ( *code != LDAP_SCHERR_OUTOFMEM )
2111 *code = LDAP_SCHERR_BADNAME;
2113 ldap_objectclass_free(oc);
2116 } else if ( !strcmp(sval,"DESC") ) {
2119 *code = LDAP_SCHERR_DUPOPT;
2121 ldap_objectclass_free(oc);
2126 kind = get_token(&ss,&sval);
2127 if ( kind != TK_QDSTRING ) {
2128 *code = LDAP_SCHERR_UNEXPTOKEN;
2131 ldap_objectclass_free(oc);
2136 } else if ( !strcmp(sval,"OBSOLETE") ) {
2138 if ( seen_obsolete ) {
2139 *code = LDAP_SCHERR_DUPOPT;
2141 ldap_objectclass_free(oc);
2145 oc->oc_obsolete = LDAP_SCHEMA_YES;
2147 } else if ( !strcmp(sval,"SUP") ) {
2150 *code = LDAP_SCHERR_DUPOPT;
2152 ldap_objectclass_free(oc);
2156 oc->oc_sup_oids = parse_oids(&ss,
2159 if ( !oc->oc_sup_oids ) {
2161 ldap_objectclass_free(oc);
2164 } else if ( !strcmp(sval,"ABSTRACT") ) {
2167 *code = LDAP_SCHERR_DUPOPT;
2169 ldap_objectclass_free(oc);
2173 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
2175 } else if ( !strcmp(sval,"STRUCTURAL") ) {
2178 *code = LDAP_SCHERR_DUPOPT;
2180 ldap_objectclass_free(oc);
2184 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
2186 } else if ( !strcmp(sval,"AUXILIARY") ) {
2189 *code = LDAP_SCHERR_DUPOPT;
2191 ldap_objectclass_free(oc);
2195 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
2197 } else if ( !strcmp(sval,"MUST") ) {
2200 *code = LDAP_SCHERR_DUPOPT;
2202 ldap_objectclass_free(oc);
2206 oc->oc_at_oids_must = parse_oids(&ss,code,0);
2207 if ( !oc->oc_at_oids_must ) {
2209 ldap_objectclass_free(oc);
2213 } else if ( !strcmp(sval,"MAY") ) {
2216 *code = LDAP_SCHERR_DUPOPT;
2218 ldap_objectclass_free(oc);
2222 oc->oc_at_oids_may = parse_oids(&ss,code,0);
2223 if ( !oc->oc_at_oids_may ) {
2225 ldap_objectclass_free(oc);
2229 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
2230 /* Should be parse_qdstrings */
2231 ext_vals = parse_qdescrs(&ss, code);
2234 ldap_objectclass_free(oc);
2237 if ( add_extension(&oc->oc_extensions,
2239 *code = LDAP_SCHERR_OUTOFMEM;
2242 ldap_objectclass_free(oc);
2246 *code = LDAP_SCHERR_UNEXPTOKEN;
2249 ldap_objectclass_free(oc);
2254 *code = LDAP_SCHERR_UNEXPTOKEN;
2257 ldap_objectclass_free(oc);
2263 static char *const err2text[] = {
2267 "Missing opening parenthesis",
2268 "Missing closing parenthesis",
2274 "Unexpected end of data"
2278 ldap_scherr2str(int code)
2280 if ( code < 0 || code >= (sizeof(err2text)/sizeof(char *)) ) {
2281 return "Unknown error";
2283 return err2text[code];