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 ) )
1663 && (ss == savepos) ) {
1666 kind = get_token(&ss,&sval);
1667 if ( kind == TK_BAREWORD ) {
1668 if ( !strcmp(sval, "NAME") ||
1669 !strcmp(sval, "DESC") ||
1670 !strcmp(sval, "OBSOLETE") ||
1671 !strcmp(sval, "SUP") ||
1672 !strcmp(sval, "EQUALITY") ||
1673 !strcmp(sval, "ORDERING") ||
1674 !strcmp(sval, "SUBSTR") ||
1675 !strcmp(sval, "SYNTAX") ||
1676 !strcmp(sval, "SINGLE-VALUE") ||
1677 !strcmp(sval, "COLLECTIVE") ||
1678 !strcmp(sval, "NO-USER-MODIFICATION") ||
1679 !strcmp(sval, "USAGE") ||
1680 !strncmp(sval, "X-", 2) ) {
1681 /* Missing OID, backtrack */
1684 & LDAP_SCHEMA_ALLOW_OID_MACRO) {
1685 /* Non-numerical OID ... */
1686 int len = ss-savepos;
1687 at->at_oid = LDAP_MALLOC(len+1);
1688 strncpy(at->at_oid, savepos, len);
1689 at->at_oid[len] = 0;
1695 ldap_attributetype_free(at);
1702 * Beyond this point we will be liberal and accept the items
1706 kind = get_token(&ss,&sval);
1709 *code = LDAP_SCHERR_NORIGHTPAREN;
1711 ldap_attributetype_free(at);
1716 if ( !strcmp(sval,"NAME") ) {
1719 *code = LDAP_SCHERR_DUPOPT;
1721 ldap_attributetype_free(at);
1725 at->at_names = parse_qdescrs(&ss,code);
1726 if ( !at->at_names ) {
1727 if ( *code != LDAP_SCHERR_OUTOFMEM )
1728 *code = LDAP_SCHERR_BADNAME;
1730 ldap_attributetype_free(at);
1733 } else if ( !strcmp(sval,"DESC") ) {
1736 *code = LDAP_SCHERR_DUPOPT;
1738 ldap_attributetype_free(at);
1743 kind = get_token(&ss,&sval);
1744 if ( kind != TK_QDSTRING ) {
1745 *code = LDAP_SCHERR_UNEXPTOKEN;
1748 ldap_attributetype_free(at);
1753 } else if ( !strcmp(sval,"OBSOLETE") ) {
1755 if ( seen_obsolete ) {
1756 *code = LDAP_SCHERR_DUPOPT;
1758 ldap_attributetype_free(at);
1762 at->at_obsolete = LDAP_SCHEMA_YES;
1764 } else if ( !strcmp(sval,"SUP") ) {
1767 *code = LDAP_SCHERR_DUPOPT;
1769 ldap_attributetype_free(at);
1773 at->at_sup_oid = parse_woid(&ss,code);
1774 if ( !at->at_sup_oid ) {
1776 ldap_attributetype_free(at);
1779 } else if ( !strcmp(sval,"EQUALITY") ) {
1781 if ( seen_equality ) {
1782 *code = LDAP_SCHERR_DUPOPT;
1784 ldap_attributetype_free(at);
1788 at->at_equality_oid = parse_woid(&ss,code);
1789 if ( !at->at_equality_oid ) {
1791 ldap_attributetype_free(at);
1794 } else if ( !strcmp(sval,"ORDERING") ) {
1796 if ( seen_ordering ) {
1797 *code = LDAP_SCHERR_DUPOPT;
1799 ldap_attributetype_free(at);
1803 at->at_ordering_oid = parse_woid(&ss,code);
1804 if ( !at->at_ordering_oid ) {
1806 ldap_attributetype_free(at);
1809 } else if ( !strcmp(sval,"SUBSTR") ) {
1811 if ( seen_substr ) {
1812 *code = LDAP_SCHERR_DUPOPT;
1814 ldap_attributetype_free(at);
1818 at->at_substr_oid = parse_woid(&ss,code);
1819 if ( !at->at_substr_oid ) {
1821 ldap_attributetype_free(at);
1824 } else if ( !strcmp(sval,"SYNTAX") ) {
1826 if ( seen_syntax ) {
1827 *code = LDAP_SCHERR_DUPOPT;
1829 ldap_attributetype_free(at);
1840 if ( !at->at_syntax_oid ) {
1841 if ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO ) {
1842 kind = get_token(&ss,&sval);
1843 if (kind == TK_BAREWORD)
1845 char *sp = strchr(sval, '{');
1846 at->at_syntax_oid = sval;
1850 at->at_syntax_len = atoi(sp);
1851 while ( LDAP_DIGIT(*sp) )
1854 *code = LDAP_SCHERR_UNEXPTOKEN;
1856 ldap_attributetype_free(at);
1863 ldap_attributetype_free(at);
1868 } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
1870 if ( at->at_single_value ) {
1871 *code = LDAP_SCHERR_DUPOPT;
1873 ldap_attributetype_free(at);
1876 at->at_single_value = LDAP_SCHEMA_YES;
1878 } else if ( !strcmp(sval,"COLLECTIVE") ) {
1880 if ( at->at_collective ) {
1881 *code = LDAP_SCHERR_DUPOPT;
1883 ldap_attributetype_free(at);
1886 at->at_collective = LDAP_SCHEMA_YES;
1888 } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
1890 if ( at->at_no_user_mod ) {
1891 *code = LDAP_SCHERR_DUPOPT;
1893 ldap_attributetype_free(at);
1896 at->at_no_user_mod = LDAP_SCHEMA_YES;
1898 } else if ( !strcmp(sval,"USAGE") ) {
1901 *code = LDAP_SCHERR_DUPOPT;
1903 ldap_attributetype_free(at);
1908 kind = get_token(&ss,&sval);
1909 if ( kind != TK_BAREWORD ) {
1910 *code = LDAP_SCHERR_UNEXPTOKEN;
1913 ldap_attributetype_free(at);
1916 if ( !strcasecmp(sval,"userApplications") )
1918 LDAP_SCHEMA_USER_APPLICATIONS;
1919 else if ( !strcasecmp(sval,"directoryOperation") )
1921 LDAP_SCHEMA_DIRECTORY_OPERATION;
1922 else if ( !strcasecmp(sval,"distributedOperation") )
1924 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
1925 else if ( !strcasecmp(sval,"dSAOperation") )
1927 LDAP_SCHEMA_DSA_OPERATION;
1929 *code = LDAP_SCHERR_UNEXPTOKEN;
1932 ldap_attributetype_free(at);
1937 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1938 /* Should be parse_qdstrings */
1939 ext_vals = parse_qdescrs(&ss, code);
1942 ldap_attributetype_free(at);
1945 if ( add_extension(&at->at_extensions,
1947 *code = LDAP_SCHERR_OUTOFMEM;
1950 ldap_attributetype_free(at);
1954 *code = LDAP_SCHERR_UNEXPTOKEN;
1957 ldap_attributetype_free(at);
1962 *code = LDAP_SCHERR_UNEXPTOKEN;
1965 ldap_attributetype_free(at);
1972 ldap_objectclass_free(LDAPObjectClass * oc)
1974 LDAP_FREE(oc->oc_oid);
1975 LDAP_VFREE(oc->oc_names);
1976 LDAP_FREE(oc->oc_desc);
1977 LDAP_VFREE(oc->oc_sup_oids);
1978 LDAP_VFREE(oc->oc_at_oids_must);
1979 LDAP_VFREE(oc->oc_at_oids_may);
1980 free_extensions(oc->oc_extensions);
1985 ldap_str2objectclass( const char * s, int * code, const char ** errp, const int flags )
1988 const char * ss = s;
1992 int seen_obsolete = 0;
1997 LDAPObjectClass * oc;
1999 const char * savepos;
2002 *code = LDAP_SCHERR_EMPTY;
2008 oc = LDAP_CALLOC(1,sizeof(LDAPObjectClass));
2011 *code = LDAP_SCHERR_OUTOFMEM;
2014 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
2016 kind = get_token(&ss,&sval);
2017 if ( kind != TK_LEFTPAREN ) {
2018 *code = LDAP_SCHERR_NOLEFTPAREN;
2020 ldap_objectclass_free(oc);
2025 * Definitions MUST begin with an OID in the numericoid format.
2026 * However, this routine is used by clients to parse the response
2027 * from servers and very well known servers will provide an OID
2028 * in the wrong format or even no OID at all. We do our best to
2029 * extract info from those servers.
2033 oc->oc_oid = parse_numericoid(&ss,code,0);
2034 if ( !oc->oc_oid ) {
2035 if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) {
2038 kind = get_token(&ss,&sval);
2039 if ( kind == TK_BAREWORD ) {
2040 if ( !strcmp(sval, "NAME") ||
2041 !strcmp(sval, "DESC") ||
2042 !strcmp(sval, "OBSOLETE") ||
2043 !strcmp(sval, "SUP") ||
2044 !strcmp(sval, "ABSTRACT") ||
2045 !strcmp(sval, "STRUCTURAL") ||
2046 !strcmp(sval, "AUXILIARY") ||
2047 !strcmp(sval, "MUST") ||
2048 !strncmp(sval, "X-", 2) ) {
2049 /* Missing OID, backtrack */
2052 LDAP_SCHEMA_ALLOW_OID_MACRO ) {
2053 /* Non-numerical OID, ignore */
2054 int len = ss-savepos;
2055 oc->oc_oid = LDAP_MALLOC(len+1);
2056 strncpy(oc->oc_oid, savepos, len);
2057 oc->oc_oid[len] = 0;
2063 ldap_objectclass_free(oc);
2070 * Beyond this point we will be liberal an accept the items
2074 kind = get_token(&ss,&sval);
2077 *code = LDAP_SCHERR_NORIGHTPAREN;
2079 ldap_objectclass_free(oc);
2084 if ( !strcmp(sval,"NAME") ) {
2087 *code = LDAP_SCHERR_DUPOPT;
2089 ldap_objectclass_free(oc);
2093 oc->oc_names = parse_qdescrs(&ss,code);
2094 if ( !oc->oc_names ) {
2095 if ( *code != LDAP_SCHERR_OUTOFMEM )
2096 *code = LDAP_SCHERR_BADNAME;
2098 ldap_objectclass_free(oc);
2101 } else if ( !strcmp(sval,"DESC") ) {
2104 *code = LDAP_SCHERR_DUPOPT;
2106 ldap_objectclass_free(oc);
2111 kind = get_token(&ss,&sval);
2112 if ( kind != TK_QDSTRING ) {
2113 *code = LDAP_SCHERR_UNEXPTOKEN;
2116 ldap_objectclass_free(oc);
2121 } else if ( !strcmp(sval,"OBSOLETE") ) {
2123 if ( seen_obsolete ) {
2124 *code = LDAP_SCHERR_DUPOPT;
2126 ldap_objectclass_free(oc);
2130 oc->oc_obsolete = LDAP_SCHEMA_YES;
2132 } else if ( !strcmp(sval,"SUP") ) {
2135 *code = LDAP_SCHERR_DUPOPT;
2137 ldap_objectclass_free(oc);
2141 oc->oc_sup_oids = parse_oids(&ss,
2144 if ( !oc->oc_sup_oids ) {
2146 ldap_objectclass_free(oc);
2149 } else if ( !strcmp(sval,"ABSTRACT") ) {
2152 *code = LDAP_SCHERR_DUPOPT;
2154 ldap_objectclass_free(oc);
2158 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
2160 } else if ( !strcmp(sval,"STRUCTURAL") ) {
2163 *code = LDAP_SCHERR_DUPOPT;
2165 ldap_objectclass_free(oc);
2169 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
2171 } else if ( !strcmp(sval,"AUXILIARY") ) {
2174 *code = LDAP_SCHERR_DUPOPT;
2176 ldap_objectclass_free(oc);
2180 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
2182 } else if ( !strcmp(sval,"MUST") ) {
2185 *code = LDAP_SCHERR_DUPOPT;
2187 ldap_objectclass_free(oc);
2191 oc->oc_at_oids_must = parse_oids(&ss,code,0);
2192 if ( !oc->oc_at_oids_must ) {
2194 ldap_objectclass_free(oc);
2198 } else if ( !strcmp(sval,"MAY") ) {
2201 *code = LDAP_SCHERR_DUPOPT;
2203 ldap_objectclass_free(oc);
2207 oc->oc_at_oids_may = parse_oids(&ss,code,0);
2208 if ( !oc->oc_at_oids_may ) {
2210 ldap_objectclass_free(oc);
2214 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
2215 /* Should be parse_qdstrings */
2216 ext_vals = parse_qdescrs(&ss, code);
2219 ldap_objectclass_free(oc);
2222 if ( add_extension(&oc->oc_extensions,
2224 *code = LDAP_SCHERR_OUTOFMEM;
2227 ldap_objectclass_free(oc);
2231 *code = LDAP_SCHERR_UNEXPTOKEN;
2234 ldap_objectclass_free(oc);
2239 *code = LDAP_SCHERR_UNEXPTOKEN;
2242 ldap_objectclass_free(oc);
2248 static char *const err2text[] = {
2252 "Missing opening parenthesis",
2253 "Missing closing parenthesis",
2259 "Unexpected end of data"
2263 ldap_scherr2str(int code)
2265 if ( code < 0 || code >= (sizeof(err2text)/sizeof(char *)) ) {
2266 return "Unknown error";
2268 return err2text[code];