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 safe_strdup(safe_string * ss)
116 char *ret = LDAP_MALLOC(ss->pos+1);
119 AC_MEMCPY(ret, ss->val, ss->pos);
125 append_to_safe_string(safe_string * ss, char * s)
131 * Some runaway process is trying to append to a string that
132 * overflowed and we could not extend.
137 /* We always make sure there is at least one position available */
138 if ( ss->pos + l >= ss->size-1 ) {
140 if ( ss->pos + l >= ss->size-1 ) {
141 ss->size = ss->pos + l + 1;
144 temp = LDAP_REALLOC(ss->val, ss->size);
146 /* Trouble, out of memory */
152 strncpy(&ss->val[ss->pos], s, l);
154 if ( ss->pos > 0 && LDAP_SPACE(ss->val[ss->pos-1]) )
163 print_literal(safe_string *ss, char *s)
165 return(append_to_safe_string(ss,s));
169 print_whsp(safe_string *ss)
172 return(append_to_safe_string(ss,""));
174 return(append_to_safe_string(ss," "));
178 print_numericoid(safe_string *ss, char *s)
181 return(append_to_safe_string(ss,s));
183 return(append_to_safe_string(ss,""));
186 /* This one is identical to print_qdescr */
188 print_qdstring(safe_string *ss, char *s)
191 print_literal(ss,"'");
192 append_to_safe_string(ss,s);
193 print_literal(ss,"'");
194 return(print_whsp(ss));
198 print_qdescr(safe_string *ss, char *s)
201 print_literal(ss,"'");
202 append_to_safe_string(ss,s);
203 print_literal(ss,"'");
204 return(print_whsp(ss));
208 print_qdescrlist(safe_string *ss, char **sa)
213 for (sp=sa; *sp; sp++) {
214 ret = print_qdescr(ss,*sp);
216 /* If the list was empty, we return zero that is potentially
217 * incorrect, but since we will be still appending things, the
218 * overflow will be detected later. Maybe FIX.
224 print_qdescrs(safe_string *ss, char **sa)
226 /* The only way to represent an empty list is as a qdescrlist
227 * so, if the list is empty we treat it as a long list.
228 * Really, this is what the syntax mandates. We should not
229 * be here if the list was empty, but if it happens, a label
230 * has already been output and we cannot undo it.
232 if ( !sa[0] || ( sa[0] && sa[1] ) ) {
234 print_literal(ss,"("/*)*/);
235 print_qdescrlist(ss,sa);
236 print_literal(ss,/*(*/")");
237 return(print_whsp(ss));
239 return(print_qdescr(ss,*sa));
244 print_woid(safe_string *ss, char *s)
247 append_to_safe_string(ss,s);
248 return print_whsp(ss);
252 print_oidlist(safe_string *ss, char **sa)
256 for (sp=sa; *(sp+1); sp++) {
258 print_literal(ss,"$");
260 return(print_woid(ss,*sp));
264 print_oids(safe_string *ss, char **sa)
266 if ( sa[0] && sa[1] ) {
267 print_literal(ss,"("/*)*/);
268 print_oidlist(ss,sa);
270 return(print_literal(ss,/*(*/")"));
272 return(print_woid(ss,*sa));
277 print_noidlen(safe_string *ss, char *s, int l)
282 ret = print_numericoid(ss,s);
284 sprintf(buf,"{%d}",l);
285 ret = print_literal(ss,buf);
291 print_extensions(safe_string *ss, LDAPSchemaExtensionItem **extensions)
293 LDAPSchemaExtensionItem **ext;
297 for ( ext = extensions; *ext != NULL; ext++ ) {
298 print_literal(ss, (*ext)->lsei_name);
300 /* Should be print_qdstrings */
301 print_qdescrs(ss, (*ext)->lsei_values);
310 ldap_syntax2str( LDAPSyntax * syn )
313 if (ldap_syntax2bv( syn, &bv ))
320 ldap_syntax2bv( LDAPSyntax * syn, struct berval *bv )
324 ss = new_safe_string(256);
328 print_literal(ss,"("/*)*/);
331 print_numericoid(ss, syn->syn_oid);
334 if ( syn->syn_desc ) {
335 print_literal(ss,"DESC");
336 print_qdstring(ss,syn->syn_desc);
341 print_extensions(ss, syn->syn_extensions);
343 print_literal(ss,/*(*/ ")");
345 bv->bv_val = safe_strdup(ss);
346 bv->bv_len = ss->pos;
347 safe_string_free(ss);
352 ldap_matchingrule2str( LDAPMatchingRule * mr )
355 if (ldap_matchingrule2bv( mr, &bv ))
362 ldap_matchingrule2bv( LDAPMatchingRule * mr, struct berval *bv )
366 ss = new_safe_string(256);
370 print_literal(ss,"(" /*)*/);
373 print_numericoid(ss, mr->mr_oid);
376 if ( mr->mr_names ) {
377 print_literal(ss,"NAME");
378 print_qdescrs(ss,mr->mr_names);
382 print_literal(ss,"DESC");
383 print_qdstring(ss,mr->mr_desc);
386 if ( mr->mr_obsolete == LDAP_SCHEMA_YES ) {
387 print_literal(ss, "OBSOLETE");
391 if ( mr->mr_syntax_oid ) {
392 print_literal(ss,"SYNTAX");
394 print_literal(ss, mr->mr_syntax_oid);
400 print_extensions(ss, mr->mr_extensions);
402 print_literal(ss,/*(*/")");
404 bv->bv_val = safe_strdup(ss);
405 bv->bv_len = ss->pos;
406 safe_string_free(ss);
411 ldap_matchingruleuse2str( LDAPMatchingRuleUse * mru )
414 if (ldap_matchingruleuse2bv( mru, &bv ))
421 ldap_matchingruleuse2bv( LDAPMatchingRuleUse * mru, struct berval *bv )
425 ss = new_safe_string(256);
429 print_literal(ss,"(" /*)*/);
432 print_numericoid(ss, mru->mru_oid);
435 if ( mru->mru_names ) {
436 print_literal(ss,"NAME");
437 print_qdescrs(ss,mru->mru_names);
440 if ( mru->mru_desc ) {
441 print_literal(ss,"DESC");
442 print_qdstring(ss,mru->mru_desc);
445 if ( mru->mru_obsolete == LDAP_SCHEMA_YES ) {
446 print_literal(ss, "OBSOLETE");
450 if ( mru->mru_applies_oids ) {
451 print_literal(ss,"APPLIES");
453 print_oids(ss, mru->mru_applies_oids);
459 print_extensions(ss, mru->mru_extensions);
461 print_literal(ss,/*(*/")");
463 bv->bv_val = safe_strdup(ss);
464 bv->bv_len = ss->pos;
465 safe_string_free(ss);
470 ldap_objectclass2str( LDAPObjectClass * oc )
473 if (ldap_objectclass2bv( oc, &bv ))
480 ldap_objectclass2bv( LDAPObjectClass * oc, struct berval *bv )
484 ss = new_safe_string(256);
488 print_literal(ss,"("/*)*/);
491 print_numericoid(ss, oc->oc_oid);
494 if ( oc->oc_names ) {
495 print_literal(ss,"NAME");
496 print_qdescrs(ss,oc->oc_names);
500 print_literal(ss,"DESC");
501 print_qdstring(ss,oc->oc_desc);
504 if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) {
505 print_literal(ss, "OBSOLETE");
509 if ( oc->oc_sup_oids ) {
510 print_literal(ss,"SUP");
512 print_oids(ss,oc->oc_sup_oids);
516 switch (oc->oc_kind) {
517 case LDAP_SCHEMA_ABSTRACT:
518 print_literal(ss,"ABSTRACT");
520 case LDAP_SCHEMA_STRUCTURAL:
521 print_literal(ss,"STRUCTURAL");
523 case LDAP_SCHEMA_AUXILIARY:
524 print_literal(ss,"AUXILIARY");
527 print_literal(ss,"KIND-UNKNOWN");
532 if ( oc->oc_at_oids_must ) {
533 print_literal(ss,"MUST");
535 print_oids(ss,oc->oc_at_oids_must);
539 if ( oc->oc_at_oids_may ) {
540 print_literal(ss,"MAY");
542 print_oids(ss,oc->oc_at_oids_may);
548 print_extensions(ss, oc->oc_extensions);
550 print_literal(ss, /*(*/")");
552 bv->bv_val = safe_strdup(ss);
553 bv->bv_len = ss->pos;
554 safe_string_free(ss);
559 ldap_attributetype2str( LDAPAttributeType * at )
562 if (ldap_attributetype2bv( at, &bv ))
569 ldap_attributetype2bv( LDAPAttributeType * at, struct berval *bv )
573 ss = new_safe_string(256);
577 print_literal(ss,"("/*)*/);
580 print_numericoid(ss, at->at_oid);
583 if ( at->at_names ) {
584 print_literal(ss,"NAME");
585 print_qdescrs(ss,at->at_names);
589 print_literal(ss,"DESC");
590 print_qdstring(ss,at->at_desc);
593 if ( at->at_obsolete == LDAP_SCHEMA_YES ) {
594 print_literal(ss, "OBSOLETE");
598 if ( at->at_sup_oid ) {
599 print_literal(ss,"SUP");
600 print_woid(ss,at->at_sup_oid);
603 if ( at->at_equality_oid ) {
604 print_literal(ss,"EQUALITY");
605 print_woid(ss,at->at_equality_oid);
608 if ( at->at_ordering_oid ) {
609 print_literal(ss,"ORDERING");
610 print_woid(ss,at->at_ordering_oid);
613 if ( at->at_substr_oid ) {
614 print_literal(ss,"SUBSTR");
615 print_woid(ss,at->at_substr_oid);
618 if ( at->at_syntax_oid ) {
619 print_literal(ss,"SYNTAX");
621 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
625 if ( at->at_single_value == LDAP_SCHEMA_YES ) {
626 print_literal(ss,"SINGLE-VALUE");
630 if ( at->at_collective == LDAP_SCHEMA_YES ) {
631 print_literal(ss,"COLLECTIVE");
635 if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
636 print_literal(ss,"NO-USER-MODIFICATION");
640 if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
641 print_literal(ss,"USAGE");
643 switch (at->at_usage) {
644 case LDAP_SCHEMA_DIRECTORY_OPERATION:
645 print_literal(ss,"directoryOperation");
647 case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
648 print_literal(ss,"distributedOperation");
650 case LDAP_SCHEMA_DSA_OPERATION:
651 print_literal(ss,"dSAOperation");
654 print_literal(ss,"UNKNOWN");
661 print_extensions(ss, at->at_extensions);
663 print_literal(ss,/*(*/")");
665 bv->bv_val = safe_strdup(ss);
666 bv->bv_len = ss->pos;
667 safe_string_free(ss);
672 * Now come the parsers. There is one parser for each entity type:
673 * objectclasses, attributetypes, etc.
675 * Each of them is written as a recursive-descent parser, except that
676 * none of them is really recursive. But the idea is kept: there
677 * is one routine per non-terminal that eithers gobbles lexical tokens
678 * or calls lower-level routines, etc.
680 * The scanner is implemented in the routine get_token. Actually,
681 * get_token is more than a scanner and will return tokens that are
682 * in fact non-terminals in the grammar. So you can see the whole
683 * approach as the combination of a low-level bottom-up recognizer
684 * combined with a scanner and a number of top-down parsers. Or just
685 * consider that the real grammars recognized by the parsers are not
686 * those of the standards. As a matter of fact, our parsers are more
687 * liberal than the spec when there is no ambiguity.
689 * The difference is pretty academic (modulo bugs or incorrect
690 * interpretation of the specs).
693 #define TK_NOENDQUOTE -2
694 #define TK_OUTOFMEM -1
696 #define TK_UNEXPCHAR 1
697 #define TK_BAREWORD 2
698 #define TK_QDSTRING 3
699 #define TK_LEFTPAREN 4
700 #define TK_RIGHTPAREN 5
702 #define TK_QDESCR TK_QDSTRING
710 get_token( const char ** sp, char ** token_val )
728 kind = TK_RIGHTPAREN;
739 while ( **sp != '\'' && **sp != '\0' )
741 if ( **sp == '\'' ) {
743 res = LDAP_MALLOC(q-p+1);
753 kind = TK_NOENDQUOTE;
759 while ( !LDAP_SPACE(**sp) &&
767 res = LDAP_MALLOC(q-p+1);
776 /* kind = TK_UNEXPCHAR; */
783 /* Gobble optional whitespace */
785 parse_whsp(const char **sp)
787 while (LDAP_SPACE(**sp))
792 * General note for all parsers: to guarantee the algorithm halts they
793 * must always advance the pointer even when an error is found. For
794 * this one is not that important since an error here is fatal at the
795 * upper layers, but it is a simple strategy that will not get in
799 /* Parse a sequence of dot-separated decimal strings */
801 parse_numericoid(const char **sp, int *code, const int flags)
804 const char * start = *sp;
808 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
809 if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && **sp == '\'' ) {
814 /* Each iteration of this loop gets one decimal string */
816 if ( !LDAP_DIGIT(**sp) ) {
818 * Initial char is not a digit or char after dot is
821 *code = LDAP_SCHERR_NODIGIT;
825 while ( LDAP_DIGIT(**sp) )
829 /* Otherwise, gobble the dot and loop again */
832 /* Now *sp points at the char past the numericoid. Perfect. */
834 res = LDAP_MALLOC(len+1);
836 *code = LDAP_SCHERR_OUTOFMEM;
839 strncpy(res,start,len);
841 if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && quoted ) {
842 if ( **sp == '\'' ) {
845 *code = LDAP_SCHERR_UNEXPTOKEN;
853 /* Parse a qdescr or a list of them enclosed in () */
855 parse_qdescrs(const char **sp, int *code)
865 kind = get_token(sp,&sval);
866 if ( kind == TK_LEFTPAREN ) {
867 /* Let's presume there will be at least 2 entries */
869 res = LDAP_CALLOC(3,sizeof(char *));
871 *code = LDAP_SCHERR_OUTOFMEM;
877 kind = get_token(sp,&sval);
878 if ( kind == TK_RIGHTPAREN )
880 if ( kind == TK_QDESCR ) {
881 if ( pos == size-2 ) {
883 res1 = LDAP_REALLOC(res,size*sizeof(char *));
887 *code = LDAP_SCHERR_OUTOFMEM;
898 *code = LDAP_SCHERR_UNEXPTOKEN;
905 } else if ( kind == TK_QDESCR ) {
906 res = LDAP_CALLOC(2,sizeof(char *));
908 *code = LDAP_SCHERR_OUTOFMEM;
917 *code = LDAP_SCHERR_BADNAME;
924 parse_woid(const char **sp, int *code)
930 kind = get_token(sp, &sval);
931 if ( kind != TK_BAREWORD ) {
933 *code = LDAP_SCHERR_UNEXPTOKEN;
940 /* Parse a noidlen */
942 parse_noidlen(const char **sp, int *code, int *len, int allow_quoted)
948 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
949 if ( allow_quoted && **sp == '\'' ) {
953 sval = parse_numericoid(sp, code, 0);
957 if ( **sp == '{' /*}*/ ) {
960 while ( LDAP_DIGIT(**sp) )
962 if ( **sp != /*{*/ '}' ) {
963 *code = LDAP_SCHERR_UNEXPTOKEN;
969 if ( allow_quoted && quoted ) {
970 if ( **sp == '\'' ) {
973 *code = LDAP_SCHERR_UNEXPTOKEN;
982 * Next routine will accept a qdstring in place of an oid if
983 * allow_quoted is set. This is necessary to interoperate with
984 * Netscape Directory server that will improperly quote each oid (at
985 * least those of the descr kind) in the SUP clause.
988 /* Parse a woid or a $-separated list of them enclosed in () */
990 parse_oids(const char **sp, int *code, const int allow_quoted)
1000 * Strictly speaking, doing this here accepts whsp before the
1001 * ( at the begining of an oidlist, but this is harmless. Also,
1002 * we are very liberal in what we accept as an OID. Maybe
1006 kind = get_token(sp,&sval);
1007 if ( kind == TK_LEFTPAREN ) {
1008 /* Let's presume there will be at least 2 entries */
1010 res = LDAP_CALLOC(3,sizeof(char *));
1012 *code = LDAP_SCHERR_OUTOFMEM;
1017 kind = get_token(sp,&sval);
1018 if ( kind == TK_BAREWORD ||
1019 ( allow_quoted && kind == TK_QDSTRING ) ) {
1023 *code = LDAP_SCHERR_UNEXPTOKEN;
1030 kind = get_token(sp,&sval);
1031 if ( kind == TK_RIGHTPAREN )
1033 if ( kind == TK_DOLLAR ) {
1035 kind = get_token(sp,&sval);
1036 if ( kind == TK_BAREWORD ||
1038 kind == TK_QDSTRING ) ) {
1039 if ( pos == size-2 ) {
1041 res1 = LDAP_REALLOC(res,size*sizeof(char *));
1045 *code = LDAP_SCHERR_OUTOFMEM;
1053 *code = LDAP_SCHERR_UNEXPTOKEN;
1060 *code = LDAP_SCHERR_UNEXPTOKEN;
1069 } else if ( kind == TK_BAREWORD ||
1070 ( allow_quoted && kind == TK_QDSTRING ) ) {
1071 res = LDAP_CALLOC(2,sizeof(char *));
1074 *code = LDAP_SCHERR_OUTOFMEM;
1083 *code = LDAP_SCHERR_BADNAME;
1089 add_extension(LDAPSchemaExtensionItem ***extensions,
1090 char * name, char ** values)
1093 LDAPSchemaExtensionItem **tmp, *ext;
1095 ext = LDAP_CALLOC(1, sizeof(LDAPSchemaExtensionItem));
1098 ext->lsei_name = name;
1099 ext->lsei_values = values;
1101 if ( !*extensions ) {
1103 LDAP_CALLOC(2, sizeof(LDAPSchemaExtensionItem *));
1108 for ( n=0; (*extensions)[n] != NULL; n++ )
1110 tmp = LDAP_REALLOC(*extensions,
1111 (n+2)*sizeof(LDAPSchemaExtensionItem *));
1116 (*extensions)[n] = ext;
1117 (*extensions)[n+1] = NULL;
1122 free_extensions(LDAPSchemaExtensionItem **extensions)
1124 LDAPSchemaExtensionItem **ext;
1127 for ( ext = extensions; *ext != NULL; ext++ ) {
1128 LDAP_FREE((*ext)->lsei_name);
1129 LDAP_VFREE((*ext)->lsei_values);
1132 LDAP_FREE(extensions);
1137 ldap_syntax_free( LDAPSyntax * syn )
1139 LDAP_FREE(syn->syn_oid);
1140 LDAP_VFREE(syn->syn_names);
1141 LDAP_FREE(syn->syn_desc);
1142 free_extensions(syn->syn_extensions);
1147 ldap_str2syntax( LDAP_CONST char * s,
1149 LDAP_CONST char ** errp,
1150 LDAP_CONST int flags )
1153 const char * ss = s;
1161 *code = LDAP_SCHERR_EMPTY;
1167 syn = LDAP_CALLOC(1,sizeof(LDAPSyntax));
1170 *code = LDAP_SCHERR_OUTOFMEM;
1174 kind = get_token(&ss,&sval);
1175 if ( kind != TK_LEFTPAREN ) {
1177 *code = LDAP_SCHERR_NOLEFTPAREN;
1178 ldap_syntax_free(syn);
1183 syn->syn_oid = parse_numericoid(&ss,code,0);
1184 if ( !syn->syn_oid ) {
1186 ldap_syntax_free(syn);
1192 * Beyond this point we will be liberal and accept the items
1196 kind = get_token(&ss,&sval);
1199 *code = LDAP_SCHERR_NORIGHTPAREN;
1201 ldap_syntax_free(syn);
1206 if ( !strcmp(sval,"NAME") ) {
1209 *code = LDAP_SCHERR_DUPOPT;
1211 ldap_syntax_free(syn);
1215 syn->syn_names = parse_qdescrs(&ss,code);
1216 if ( !syn->syn_names ) {
1217 if ( *code != LDAP_SCHERR_OUTOFMEM )
1218 *code = LDAP_SCHERR_BADNAME;
1220 ldap_syntax_free(syn);
1223 } else if ( !strcmp(sval,"DESC") ) {
1226 *code = LDAP_SCHERR_DUPOPT;
1228 ldap_syntax_free(syn);
1233 kind = get_token(&ss,&sval);
1234 if ( kind != TK_QDSTRING ) {
1235 *code = LDAP_SCHERR_UNEXPTOKEN;
1238 ldap_syntax_free(syn);
1241 syn->syn_desc = sval;
1243 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1244 /* Should be parse_qdstrings */
1245 ext_vals = parse_qdescrs(&ss, code);
1248 ldap_syntax_free(syn);
1251 if ( add_extension(&syn->syn_extensions,
1253 *code = LDAP_SCHERR_OUTOFMEM;
1256 ldap_syntax_free(syn);
1260 *code = LDAP_SCHERR_UNEXPTOKEN;
1263 ldap_syntax_free(syn);
1268 *code = LDAP_SCHERR_UNEXPTOKEN;
1271 ldap_syntax_free(syn);
1278 ldap_matchingrule_free( LDAPMatchingRule * mr )
1280 LDAP_FREE(mr->mr_oid);
1281 LDAP_VFREE(mr->mr_names);
1282 LDAP_FREE(mr->mr_desc);
1283 LDAP_FREE(mr->mr_syntax_oid);
1284 free_extensions(mr->mr_extensions);
1289 ldap_str2matchingrule( LDAP_CONST char * s,
1291 LDAP_CONST char ** errp,
1292 LDAP_CONST int flags )
1295 const char * ss = s;
1299 int seen_obsolete = 0;
1300 int seen_syntax = 0;
1301 LDAPMatchingRule * mr;
1303 const char * savepos;
1306 *code = LDAP_SCHERR_EMPTY;
1312 mr = LDAP_CALLOC(1,sizeof(LDAPMatchingRule));
1315 *code = LDAP_SCHERR_OUTOFMEM;
1319 kind = get_token(&ss,&sval);
1320 if ( kind != TK_LEFTPAREN ) {
1321 *code = LDAP_SCHERR_NOLEFTPAREN;
1323 ldap_matchingrule_free(mr);
1329 mr->mr_oid = parse_numericoid(&ss,code,flags);
1330 if ( !mr->mr_oid ) {
1331 if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
1334 kind = get_token(&ss,&sval);
1335 if ( kind == TK_BAREWORD ) {
1336 if ( !strcmp(sval, "NAME") ||
1337 !strcmp(sval, "DESC") ||
1338 !strcmp(sval, "OBSOLETE") ||
1339 !strcmp(sval, "SYNTAX") ||
1340 !strncmp(sval, "X-", 2) ) {
1341 /* Missing OID, backtrack */
1344 /* Non-numerical OID, ignore */
1350 ldap_matchingrule_free(mr);
1357 * Beyond this point we will be liberal and accept the items
1361 kind = get_token(&ss,&sval);
1364 *code = LDAP_SCHERR_NORIGHTPAREN;
1366 ldap_matchingrule_free(mr);
1371 if ( !strcmp(sval,"NAME") ) {
1374 *code = LDAP_SCHERR_DUPOPT;
1376 ldap_matchingrule_free(mr);
1380 mr->mr_names = parse_qdescrs(&ss,code);
1381 if ( !mr->mr_names ) {
1382 if ( *code != LDAP_SCHERR_OUTOFMEM )
1383 *code = LDAP_SCHERR_BADNAME;
1385 ldap_matchingrule_free(mr);
1388 } else if ( !strcmp(sval,"DESC") ) {
1391 *code = LDAP_SCHERR_DUPOPT;
1393 ldap_matchingrule_free(mr);
1398 kind = get_token(&ss,&sval);
1399 if ( kind != TK_QDSTRING ) {
1400 *code = LDAP_SCHERR_UNEXPTOKEN;
1403 ldap_matchingrule_free(mr);
1408 } else if ( !strcmp(sval,"OBSOLETE") ) {
1410 if ( seen_obsolete ) {
1411 *code = LDAP_SCHERR_DUPOPT;
1413 ldap_matchingrule_free(mr);
1417 mr->mr_obsolete = LDAP_SCHEMA_YES;
1419 } else if ( !strcmp(sval,"SYNTAX") ) {
1421 if ( seen_syntax ) {
1422 *code = LDAP_SCHERR_DUPOPT;
1424 ldap_matchingrule_free(mr);
1430 parse_numericoid(&ss,code,flags);
1431 if ( !mr->mr_syntax_oid ) {
1433 ldap_matchingrule_free(mr);
1437 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1438 /* Should be parse_qdstrings */
1439 ext_vals = parse_qdescrs(&ss, code);
1442 ldap_matchingrule_free(mr);
1445 if ( add_extension(&mr->mr_extensions,
1447 *code = LDAP_SCHERR_OUTOFMEM;
1450 ldap_matchingrule_free(mr);
1454 *code = LDAP_SCHERR_UNEXPTOKEN;
1457 ldap_matchingrule_free(mr);
1462 *code = LDAP_SCHERR_UNEXPTOKEN;
1465 ldap_matchingrule_free(mr);
1472 ldap_matchingruleuse_free( LDAPMatchingRuleUse * mru )
1474 LDAP_FREE(mru->mru_oid);
1475 LDAP_VFREE(mru->mru_names);
1476 LDAP_FREE(mru->mru_desc);
1477 LDAP_VFREE(mru->mru_applies_oids);
1478 free_extensions(mru->mru_extensions);
1482 LDAPMatchingRuleUse *
1483 ldap_str2matchingruleuse( LDAP_CONST char * s,
1485 LDAP_CONST char ** errp,
1486 LDAP_CONST int flags )
1489 const char * ss = s;
1493 int seen_obsolete = 0;
1494 int seen_applies = 0;
1495 LDAPMatchingRuleUse * mru;
1497 const char * savepos;
1500 *code = LDAP_SCHERR_EMPTY;
1506 mru = LDAP_CALLOC(1,sizeof(LDAPMatchingRuleUse));
1509 *code = LDAP_SCHERR_OUTOFMEM;
1513 kind = get_token(&ss,&sval);
1514 if ( kind != TK_LEFTPAREN ) {
1515 *code = LDAP_SCHERR_NOLEFTPAREN;
1517 ldap_matchingruleuse_free(mru);
1523 mru->mru_oid = parse_numericoid(&ss,code,flags);
1524 if ( !mru->mru_oid ) {
1525 if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
1528 kind = get_token(&ss,&sval);
1529 if ( kind == TK_BAREWORD ) {
1530 if ( !strcmp(sval, "NAME") ||
1531 !strcmp(sval, "DESC") ||
1532 !strcmp(sval, "OBSOLETE") ||
1533 !strcmp(sval, "APPLIES") ||
1534 !strncmp(sval, "X-", 2) ) {
1535 /* Missing OID, backtrack */
1538 /* Non-numerical OID, ignore */
1544 ldap_matchingruleuse_free(mru);
1551 * Beyond this point we will be liberal and accept the items
1555 kind = get_token(&ss,&sval);
1558 *code = LDAP_SCHERR_NORIGHTPAREN;
1560 ldap_matchingruleuse_free(mru);
1565 if ( !strcmp(sval,"NAME") ) {
1568 *code = LDAP_SCHERR_DUPOPT;
1570 ldap_matchingruleuse_free(mru);
1574 mru->mru_names = parse_qdescrs(&ss,code);
1575 if ( !mru->mru_names ) {
1576 if ( *code != LDAP_SCHERR_OUTOFMEM )
1577 *code = LDAP_SCHERR_BADNAME;
1579 ldap_matchingruleuse_free(mru);
1582 } else if ( !strcmp(sval,"DESC") ) {
1585 *code = LDAP_SCHERR_DUPOPT;
1587 ldap_matchingruleuse_free(mru);
1592 kind = get_token(&ss,&sval);
1593 if ( kind != TK_QDSTRING ) {
1594 *code = LDAP_SCHERR_UNEXPTOKEN;
1597 ldap_matchingruleuse_free(mru);
1600 mru->mru_desc = sval;
1602 } else if ( !strcmp(sval,"OBSOLETE") ) {
1604 if ( seen_obsolete ) {
1605 *code = LDAP_SCHERR_DUPOPT;
1607 ldap_matchingruleuse_free(mru);
1611 mru->mru_obsolete = LDAP_SCHEMA_YES;
1613 } else if ( !strcmp(sval,"APPLIES") ) {
1615 if ( seen_applies ) {
1616 *code = LDAP_SCHERR_DUPOPT;
1618 ldap_matchingruleuse_free(mru);
1622 mru->mru_applies_oids = parse_oids(&ss,
1625 if ( !mru->mru_applies_oids ) {
1627 ldap_matchingruleuse_free(mru);
1630 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1631 /* Should be parse_qdstrings */
1632 ext_vals = parse_qdescrs(&ss, code);
1635 ldap_matchingruleuse_free(mru);
1638 if ( add_extension(&mru->mru_extensions,
1640 *code = LDAP_SCHERR_OUTOFMEM;
1643 ldap_matchingruleuse_free(mru);
1647 *code = LDAP_SCHERR_UNEXPTOKEN;
1650 ldap_matchingruleuse_free(mru);
1655 *code = LDAP_SCHERR_UNEXPTOKEN;
1658 ldap_matchingruleuse_free(mru);
1665 ldap_attributetype_free(LDAPAttributeType * at)
1667 LDAP_FREE(at->at_oid);
1668 LDAP_VFREE(at->at_names);
1669 LDAP_FREE(at->at_desc);
1670 LDAP_FREE(at->at_sup_oid);
1671 LDAP_FREE(at->at_equality_oid);
1672 LDAP_FREE(at->at_ordering_oid);
1673 LDAP_FREE(at->at_substr_oid);
1674 LDAP_FREE(at->at_syntax_oid);
1675 free_extensions(at->at_extensions);
1680 ldap_str2attributetype( LDAP_CONST char * s,
1682 LDAP_CONST char ** errp,
1683 LDAP_CONST int flags )
1686 const char * ss = s;
1690 int seen_obsolete = 0;
1692 int seen_equality = 0;
1693 int seen_ordering = 0;
1694 int seen_substr = 0;
1695 int seen_syntax = 0;
1697 LDAPAttributeType * at;
1699 const char * savepos;
1702 *code = LDAP_SCHERR_EMPTY;
1708 at = LDAP_CALLOC(1,sizeof(LDAPAttributeType));
1711 *code = LDAP_SCHERR_OUTOFMEM;
1715 kind = get_token(&ss,&sval);
1716 if ( kind != TK_LEFTPAREN ) {
1717 *code = LDAP_SCHERR_NOLEFTPAREN;
1719 ldap_attributetype_free(at);
1724 * Definitions MUST begin with an OID in the numericoid format.
1725 * However, this routine is used by clients to parse the response
1726 * from servers and very well known servers will provide an OID
1727 * in the wrong format or even no OID at all. We do our best to
1728 * extract info from those servers.
1732 at->at_oid = parse_numericoid(&ss,code,0);
1733 if ( !at->at_oid ) {
1734 if ( ( flags & ( LDAP_SCHEMA_ALLOW_NO_OID
1735 | LDAP_SCHEMA_ALLOW_OID_MACRO ) )
1736 && (ss == savepos) ) {
1739 kind = get_token(&ss,&sval);
1740 if ( kind == TK_BAREWORD ) {
1741 if ( !strcmp(sval, "NAME") ||
1742 !strcmp(sval, "DESC") ||
1743 !strcmp(sval, "OBSOLETE") ||
1744 !strcmp(sval, "SUP") ||
1745 !strcmp(sval, "EQUALITY") ||
1746 !strcmp(sval, "ORDERING") ||
1747 !strcmp(sval, "SUBSTR") ||
1748 !strcmp(sval, "SYNTAX") ||
1749 !strcmp(sval, "SINGLE-VALUE") ||
1750 !strcmp(sval, "COLLECTIVE") ||
1751 !strcmp(sval, "NO-USER-MODIFICATION") ||
1752 !strcmp(sval, "USAGE") ||
1753 !strncmp(sval, "X-", 2) ) {
1754 /* Missing OID, backtrack */
1757 & LDAP_SCHEMA_ALLOW_OID_MACRO) {
1758 /* Non-numerical OID ... */
1759 int len = ss-savepos;
1760 at->at_oid = LDAP_MALLOC(len+1);
1761 strncpy(at->at_oid, savepos, len);
1762 at->at_oid[len] = 0;
1768 ldap_attributetype_free(at);
1775 * Beyond this point we will be liberal and accept the items
1779 kind = get_token(&ss,&sval);
1782 *code = LDAP_SCHERR_NORIGHTPAREN;
1784 ldap_attributetype_free(at);
1789 if ( !strcmp(sval,"NAME") ) {
1792 *code = LDAP_SCHERR_DUPOPT;
1794 ldap_attributetype_free(at);
1798 at->at_names = parse_qdescrs(&ss,code);
1799 if ( !at->at_names ) {
1800 if ( *code != LDAP_SCHERR_OUTOFMEM )
1801 *code = LDAP_SCHERR_BADNAME;
1803 ldap_attributetype_free(at);
1806 } else if ( !strcmp(sval,"DESC") ) {
1809 *code = LDAP_SCHERR_DUPOPT;
1811 ldap_attributetype_free(at);
1816 kind = get_token(&ss,&sval);
1817 if ( kind != TK_QDSTRING ) {
1818 *code = LDAP_SCHERR_UNEXPTOKEN;
1821 ldap_attributetype_free(at);
1826 } else if ( !strcmp(sval,"OBSOLETE") ) {
1828 if ( seen_obsolete ) {
1829 *code = LDAP_SCHERR_DUPOPT;
1831 ldap_attributetype_free(at);
1835 at->at_obsolete = LDAP_SCHEMA_YES;
1837 } else if ( !strcmp(sval,"SUP") ) {
1840 *code = LDAP_SCHERR_DUPOPT;
1842 ldap_attributetype_free(at);
1846 at->at_sup_oid = parse_woid(&ss,code);
1847 if ( !at->at_sup_oid ) {
1849 ldap_attributetype_free(at);
1852 } else if ( !strcmp(sval,"EQUALITY") ) {
1854 if ( seen_equality ) {
1855 *code = LDAP_SCHERR_DUPOPT;
1857 ldap_attributetype_free(at);
1861 at->at_equality_oid = parse_woid(&ss,code);
1862 if ( !at->at_equality_oid ) {
1864 ldap_attributetype_free(at);
1867 } else if ( !strcmp(sval,"ORDERING") ) {
1869 if ( seen_ordering ) {
1870 *code = LDAP_SCHERR_DUPOPT;
1872 ldap_attributetype_free(at);
1876 at->at_ordering_oid = parse_woid(&ss,code);
1877 if ( !at->at_ordering_oid ) {
1879 ldap_attributetype_free(at);
1882 } else if ( !strcmp(sval,"SUBSTR") ) {
1884 if ( seen_substr ) {
1885 *code = LDAP_SCHERR_DUPOPT;
1887 ldap_attributetype_free(at);
1891 at->at_substr_oid = parse_woid(&ss,code);
1892 if ( !at->at_substr_oid ) {
1894 ldap_attributetype_free(at);
1897 } else if ( !strcmp(sval,"SYNTAX") ) {
1899 if ( seen_syntax ) {
1900 *code = LDAP_SCHERR_DUPOPT;
1902 ldap_attributetype_free(at);
1913 if ( !at->at_syntax_oid ) {
1914 if ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO ) {
1915 kind = get_token(&ss,&sval);
1916 if (kind == TK_BAREWORD)
1918 char *sp = strchr(sval, '{');
1919 at->at_syntax_oid = sval;
1923 at->at_syntax_len = atoi(sp);
1924 while ( LDAP_DIGIT(*sp) )
1927 *code = LDAP_SCHERR_UNEXPTOKEN;
1929 ldap_attributetype_free(at);
1936 ldap_attributetype_free(at);
1941 } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
1943 if ( at->at_single_value ) {
1944 *code = LDAP_SCHERR_DUPOPT;
1946 ldap_attributetype_free(at);
1949 at->at_single_value = LDAP_SCHEMA_YES;
1951 } else if ( !strcmp(sval,"COLLECTIVE") ) {
1953 if ( at->at_collective ) {
1954 *code = LDAP_SCHERR_DUPOPT;
1956 ldap_attributetype_free(at);
1959 at->at_collective = LDAP_SCHEMA_YES;
1961 } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
1963 if ( at->at_no_user_mod ) {
1964 *code = LDAP_SCHERR_DUPOPT;
1966 ldap_attributetype_free(at);
1969 at->at_no_user_mod = LDAP_SCHEMA_YES;
1971 } else if ( !strcmp(sval,"USAGE") ) {
1974 *code = LDAP_SCHERR_DUPOPT;
1976 ldap_attributetype_free(at);
1981 kind = get_token(&ss,&sval);
1982 if ( kind != TK_BAREWORD ) {
1983 *code = LDAP_SCHERR_UNEXPTOKEN;
1986 ldap_attributetype_free(at);
1989 if ( !strcasecmp(sval,"userApplications") )
1991 LDAP_SCHEMA_USER_APPLICATIONS;
1992 else if ( !strcasecmp(sval,"directoryOperation") )
1994 LDAP_SCHEMA_DIRECTORY_OPERATION;
1995 else if ( !strcasecmp(sval,"distributedOperation") )
1997 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
1998 else if ( !strcasecmp(sval,"dSAOperation") )
2000 LDAP_SCHEMA_DSA_OPERATION;
2002 *code = LDAP_SCHERR_UNEXPTOKEN;
2005 ldap_attributetype_free(at);
2010 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
2011 /* Should be parse_qdstrings */
2012 ext_vals = parse_qdescrs(&ss, code);
2015 ldap_attributetype_free(at);
2018 if ( add_extension(&at->at_extensions,
2020 *code = LDAP_SCHERR_OUTOFMEM;
2023 ldap_attributetype_free(at);
2027 *code = LDAP_SCHERR_UNEXPTOKEN;
2030 ldap_attributetype_free(at);
2035 *code = LDAP_SCHERR_UNEXPTOKEN;
2038 ldap_attributetype_free(at);
2045 ldap_objectclass_free(LDAPObjectClass * oc)
2047 LDAP_FREE(oc->oc_oid);
2048 LDAP_VFREE(oc->oc_names);
2049 LDAP_FREE(oc->oc_desc);
2050 LDAP_VFREE(oc->oc_sup_oids);
2051 LDAP_VFREE(oc->oc_at_oids_must);
2052 LDAP_VFREE(oc->oc_at_oids_may);
2053 free_extensions(oc->oc_extensions);
2058 ldap_str2objectclass( LDAP_CONST char * s,
2060 LDAP_CONST char ** errp,
2061 LDAP_CONST int flags )
2064 const char * ss = s;
2068 int seen_obsolete = 0;
2073 LDAPObjectClass * oc;
2075 const char * savepos;
2078 *code = LDAP_SCHERR_EMPTY;
2084 oc = LDAP_CALLOC(1,sizeof(LDAPObjectClass));
2087 *code = LDAP_SCHERR_OUTOFMEM;
2090 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
2092 kind = get_token(&ss,&sval);
2093 if ( kind != TK_LEFTPAREN ) {
2094 *code = LDAP_SCHERR_NOLEFTPAREN;
2096 ldap_objectclass_free(oc);
2101 * Definitions MUST begin with an OID in the numericoid format.
2102 * However, this routine is used by clients to parse the response
2103 * from servers and very well known servers will provide an OID
2104 * in the wrong format or even no OID at all. We do our best to
2105 * extract info from those servers.
2109 oc->oc_oid = parse_numericoid(&ss,code,0);
2110 if ( !oc->oc_oid ) {
2111 if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) {
2114 kind = get_token(&ss,&sval);
2115 if ( kind == TK_BAREWORD ) {
2116 if ( !strcmp(sval, "NAME") ||
2117 !strcmp(sval, "DESC") ||
2118 !strcmp(sval, "OBSOLETE") ||
2119 !strcmp(sval, "SUP") ||
2120 !strcmp(sval, "ABSTRACT") ||
2121 !strcmp(sval, "STRUCTURAL") ||
2122 !strcmp(sval, "AUXILIARY") ||
2123 !strcmp(sval, "MUST") ||
2124 !strncmp(sval, "X-", 2) ) {
2125 /* Missing OID, backtrack */
2128 LDAP_SCHEMA_ALLOW_OID_MACRO ) {
2129 /* Non-numerical OID, ignore */
2130 int len = ss-savepos;
2131 oc->oc_oid = LDAP_MALLOC(len+1);
2132 strncpy(oc->oc_oid, savepos, len);
2133 oc->oc_oid[len] = 0;
2139 ldap_objectclass_free(oc);
2146 * Beyond this point we will be liberal an accept the items
2150 kind = get_token(&ss,&sval);
2153 *code = LDAP_SCHERR_NORIGHTPAREN;
2155 ldap_objectclass_free(oc);
2160 if ( !strcmp(sval,"NAME") ) {
2163 *code = LDAP_SCHERR_DUPOPT;
2165 ldap_objectclass_free(oc);
2169 oc->oc_names = parse_qdescrs(&ss,code);
2170 if ( !oc->oc_names ) {
2171 if ( *code != LDAP_SCHERR_OUTOFMEM )
2172 *code = LDAP_SCHERR_BADNAME;
2174 ldap_objectclass_free(oc);
2177 } else if ( !strcmp(sval,"DESC") ) {
2180 *code = LDAP_SCHERR_DUPOPT;
2182 ldap_objectclass_free(oc);
2187 kind = get_token(&ss,&sval);
2188 if ( kind != TK_QDSTRING ) {
2189 *code = LDAP_SCHERR_UNEXPTOKEN;
2192 ldap_objectclass_free(oc);
2197 } else if ( !strcmp(sval,"OBSOLETE") ) {
2199 if ( seen_obsolete ) {
2200 *code = LDAP_SCHERR_DUPOPT;
2202 ldap_objectclass_free(oc);
2206 oc->oc_obsolete = LDAP_SCHEMA_YES;
2208 } else if ( !strcmp(sval,"SUP") ) {
2211 *code = LDAP_SCHERR_DUPOPT;
2213 ldap_objectclass_free(oc);
2217 oc->oc_sup_oids = parse_oids(&ss,
2220 if ( !oc->oc_sup_oids ) {
2222 ldap_objectclass_free(oc);
2225 } else if ( !strcmp(sval,"ABSTRACT") ) {
2228 *code = LDAP_SCHERR_DUPOPT;
2230 ldap_objectclass_free(oc);
2234 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
2236 } else if ( !strcmp(sval,"STRUCTURAL") ) {
2239 *code = LDAP_SCHERR_DUPOPT;
2241 ldap_objectclass_free(oc);
2245 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
2247 } else if ( !strcmp(sval,"AUXILIARY") ) {
2250 *code = LDAP_SCHERR_DUPOPT;
2252 ldap_objectclass_free(oc);
2256 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
2258 } else if ( !strcmp(sval,"MUST") ) {
2261 *code = LDAP_SCHERR_DUPOPT;
2263 ldap_objectclass_free(oc);
2267 oc->oc_at_oids_must = parse_oids(&ss,code,0);
2268 if ( !oc->oc_at_oids_must ) {
2270 ldap_objectclass_free(oc);
2274 } else if ( !strcmp(sval,"MAY") ) {
2277 *code = LDAP_SCHERR_DUPOPT;
2279 ldap_objectclass_free(oc);
2283 oc->oc_at_oids_may = parse_oids(&ss,code,0);
2284 if ( !oc->oc_at_oids_may ) {
2286 ldap_objectclass_free(oc);
2290 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
2291 /* Should be parse_qdstrings */
2292 ext_vals = parse_qdescrs(&ss, code);
2295 ldap_objectclass_free(oc);
2298 if ( add_extension(&oc->oc_extensions,
2300 *code = LDAP_SCHERR_OUTOFMEM;
2303 ldap_objectclass_free(oc);
2307 *code = LDAP_SCHERR_UNEXPTOKEN;
2310 ldap_objectclass_free(oc);
2315 *code = LDAP_SCHERR_UNEXPTOKEN;
2318 ldap_objectclass_free(oc);
2324 static char *const err2text[] = {
2328 "Missing opening parenthesis",
2329 "Missing closing parenthesis",
2335 "Unexpected end of data"
2339 ldap_scherr2str(int code)
2341 if ( code < 0 || code >= (sizeof(err2text)/sizeof(char *)) ) {
2342 return "Unknown error";
2344 return err2text[code];