3 * Copyright 1999-2002 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 snprintf(buf, sizeof 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 ldap_int_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 if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && quoted ) {
835 if ( **sp == '\'' ) {
838 *code = LDAP_SCHERR_UNEXPTOKEN;
842 if (flags & LDAP_SCHEMA_SKIP) {
845 res = LDAP_MALLOC(len+1);
847 *code = LDAP_SCHERR_OUTOFMEM;
850 strncpy(res,start,len);
856 /* Parse a qdescr or a list of them enclosed in () */
858 parse_qdescrs(const char **sp, int *code)
868 kind = get_token(sp,&sval);
869 if ( kind == TK_LEFTPAREN ) {
870 /* Let's presume there will be at least 2 entries */
872 res = LDAP_CALLOC(3,sizeof(char *));
874 *code = LDAP_SCHERR_OUTOFMEM;
880 kind = get_token(sp,&sval);
881 if ( kind == TK_RIGHTPAREN )
883 if ( kind == TK_QDESCR ) {
884 if ( pos == size-2 ) {
886 res1 = LDAP_REALLOC(res,size*sizeof(char *));
890 *code = LDAP_SCHERR_OUTOFMEM;
901 *code = LDAP_SCHERR_UNEXPTOKEN;
908 } else if ( kind == TK_QDESCR ) {
909 res = LDAP_CALLOC(2,sizeof(char *));
911 *code = LDAP_SCHERR_OUTOFMEM;
920 *code = LDAP_SCHERR_BADNAME;
927 parse_woid(const char **sp, int *code)
933 kind = get_token(sp, &sval);
934 if ( kind != TK_BAREWORD ) {
936 *code = LDAP_SCHERR_UNEXPTOKEN;
943 /* Parse a noidlen */
945 parse_noidlen(const char **sp, int *code, int *len, int allow_quoted)
951 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
952 if ( allow_quoted && **sp == '\'' ) {
956 sval = ldap_int_parse_numericoid(sp, code, 0);
960 if ( **sp == '{' /*}*/ ) {
963 while ( LDAP_DIGIT(**sp) )
965 if ( **sp != /*{*/ '}' ) {
966 *code = LDAP_SCHERR_UNEXPTOKEN;
972 if ( allow_quoted && quoted ) {
973 if ( **sp == '\'' ) {
976 *code = LDAP_SCHERR_UNEXPTOKEN;
985 * Next routine will accept a qdstring in place of an oid if
986 * allow_quoted is set. This is necessary to interoperate with
987 * Netscape Directory server that will improperly quote each oid (at
988 * least those of the descr kind) in the SUP clause.
991 /* Parse a woid or a $-separated list of them enclosed in () */
993 parse_oids(const char **sp, int *code, const int allow_quoted)
1003 * Strictly speaking, doing this here accepts whsp before the
1004 * ( at the begining of an oidlist, but this is harmless. Also,
1005 * we are very liberal in what we accept as an OID. Maybe
1009 kind = get_token(sp,&sval);
1010 if ( kind == TK_LEFTPAREN ) {
1011 /* Let's presume there will be at least 2 entries */
1013 res = LDAP_CALLOC(3,sizeof(char *));
1015 *code = LDAP_SCHERR_OUTOFMEM;
1020 kind = get_token(sp,&sval);
1021 if ( kind == TK_BAREWORD ||
1022 ( allow_quoted && kind == TK_QDSTRING ) ) {
1026 *code = LDAP_SCHERR_UNEXPTOKEN;
1033 kind = get_token(sp,&sval);
1034 if ( kind == TK_RIGHTPAREN )
1036 if ( kind == TK_DOLLAR ) {
1038 kind = get_token(sp,&sval);
1039 if ( kind == TK_BAREWORD ||
1041 kind == TK_QDSTRING ) ) {
1042 if ( pos == size-2 ) {
1044 res1 = LDAP_REALLOC(res,size*sizeof(char *));
1048 *code = LDAP_SCHERR_OUTOFMEM;
1056 *code = LDAP_SCHERR_UNEXPTOKEN;
1063 *code = LDAP_SCHERR_UNEXPTOKEN;
1072 } else if ( kind == TK_BAREWORD ||
1073 ( allow_quoted && kind == TK_QDSTRING ) ) {
1074 res = LDAP_CALLOC(2,sizeof(char *));
1077 *code = LDAP_SCHERR_OUTOFMEM;
1086 *code = LDAP_SCHERR_BADNAME;
1092 add_extension(LDAPSchemaExtensionItem ***extensions,
1093 char * name, char ** values)
1096 LDAPSchemaExtensionItem **tmp, *ext;
1098 ext = LDAP_CALLOC(1, sizeof(LDAPSchemaExtensionItem));
1101 ext->lsei_name = name;
1102 ext->lsei_values = values;
1104 if ( !*extensions ) {
1106 LDAP_CALLOC(2, sizeof(LDAPSchemaExtensionItem *));
1111 for ( n=0; (*extensions)[n] != NULL; n++ )
1113 tmp = LDAP_REALLOC(*extensions,
1114 (n+2)*sizeof(LDAPSchemaExtensionItem *));
1119 (*extensions)[n] = ext;
1120 (*extensions)[n+1] = NULL;
1125 free_extensions(LDAPSchemaExtensionItem **extensions)
1127 LDAPSchemaExtensionItem **ext;
1130 for ( ext = extensions; *ext != NULL; ext++ ) {
1131 LDAP_FREE((*ext)->lsei_name);
1132 LDAP_VFREE((*ext)->lsei_values);
1135 LDAP_FREE(extensions);
1140 ldap_syntax_free( LDAPSyntax * syn )
1142 LDAP_FREE(syn->syn_oid);
1143 if (syn->syn_names) LDAP_VFREE(syn->syn_names);
1144 if (syn->syn_desc) LDAP_FREE(syn->syn_desc);
1145 free_extensions(syn->syn_extensions);
1150 ldap_str2syntax( LDAP_CONST char * s,
1152 LDAP_CONST char ** errp,
1153 LDAP_CONST int flags )
1156 const char * ss = s;
1164 *code = LDAP_SCHERR_EMPTY;
1170 syn = LDAP_CALLOC(1,sizeof(LDAPSyntax));
1173 *code = LDAP_SCHERR_OUTOFMEM;
1177 kind = get_token(&ss,&sval);
1178 if ( kind != TK_LEFTPAREN ) {
1180 *code = LDAP_SCHERR_NOLEFTPAREN;
1181 ldap_syntax_free(syn);
1186 syn->syn_oid = ldap_int_parse_numericoid(&ss,code,0);
1187 if ( !syn->syn_oid ) {
1189 ldap_syntax_free(syn);
1195 * Beyond this point we will be liberal and accept the items
1199 kind = get_token(&ss,&sval);
1202 *code = LDAP_SCHERR_NORIGHTPAREN;
1204 ldap_syntax_free(syn);
1209 if ( !strcmp(sval,"NAME") ) {
1212 *code = LDAP_SCHERR_DUPOPT;
1214 ldap_syntax_free(syn);
1218 syn->syn_names = parse_qdescrs(&ss,code);
1219 if ( !syn->syn_names ) {
1220 if ( *code != LDAP_SCHERR_OUTOFMEM )
1221 *code = LDAP_SCHERR_BADNAME;
1223 ldap_syntax_free(syn);
1226 } else if ( !strcmp(sval,"DESC") ) {
1229 *code = LDAP_SCHERR_DUPOPT;
1231 ldap_syntax_free(syn);
1236 kind = get_token(&ss,&sval);
1237 if ( kind != TK_QDSTRING ) {
1238 *code = LDAP_SCHERR_UNEXPTOKEN;
1241 ldap_syntax_free(syn);
1244 syn->syn_desc = sval;
1246 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1247 /* Should be parse_qdstrings */
1248 ext_vals = parse_qdescrs(&ss, code);
1251 ldap_syntax_free(syn);
1254 if ( add_extension(&syn->syn_extensions,
1256 *code = LDAP_SCHERR_OUTOFMEM;
1259 ldap_syntax_free(syn);
1263 *code = LDAP_SCHERR_UNEXPTOKEN;
1266 ldap_syntax_free(syn);
1271 *code = LDAP_SCHERR_UNEXPTOKEN;
1274 ldap_syntax_free(syn);
1281 ldap_matchingrule_free( LDAPMatchingRule * mr )
1283 LDAP_FREE(mr->mr_oid);
1284 if (mr->mr_names) LDAP_VFREE(mr->mr_names);
1285 if (mr->mr_desc) LDAP_FREE(mr->mr_desc);
1286 if (mr->mr_syntax_oid) LDAP_FREE(mr->mr_syntax_oid);
1287 free_extensions(mr->mr_extensions);
1292 ldap_str2matchingrule( LDAP_CONST char * s,
1294 LDAP_CONST char ** errp,
1295 LDAP_CONST int flags )
1298 const char * ss = s;
1302 int seen_obsolete = 0;
1303 int seen_syntax = 0;
1304 LDAPMatchingRule * mr;
1306 const char * savepos;
1309 *code = LDAP_SCHERR_EMPTY;
1315 mr = LDAP_CALLOC(1,sizeof(LDAPMatchingRule));
1318 *code = LDAP_SCHERR_OUTOFMEM;
1322 kind = get_token(&ss,&sval);
1323 if ( kind != TK_LEFTPAREN ) {
1324 *code = LDAP_SCHERR_NOLEFTPAREN;
1326 ldap_matchingrule_free(mr);
1332 mr->mr_oid = ldap_int_parse_numericoid(&ss,code,flags);
1333 if ( !mr->mr_oid ) {
1334 if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
1337 kind = get_token(&ss,&sval);
1338 if ( kind == TK_BAREWORD ) {
1339 if ( !strcmp(sval, "NAME") ||
1340 !strcmp(sval, "DESC") ||
1341 !strcmp(sval, "OBSOLETE") ||
1342 !strcmp(sval, "SYNTAX") ||
1343 !strncmp(sval, "X-", 2) ) {
1344 /* Missing OID, backtrack */
1347 /* Non-numerical OID, ignore */
1353 ldap_matchingrule_free(mr);
1360 * Beyond this point we will be liberal and accept the items
1364 kind = get_token(&ss,&sval);
1367 *code = LDAP_SCHERR_NORIGHTPAREN;
1369 ldap_matchingrule_free(mr);
1374 if ( !strcmp(sval,"NAME") ) {
1377 *code = LDAP_SCHERR_DUPOPT;
1379 ldap_matchingrule_free(mr);
1383 mr->mr_names = parse_qdescrs(&ss,code);
1384 if ( !mr->mr_names ) {
1385 if ( *code != LDAP_SCHERR_OUTOFMEM )
1386 *code = LDAP_SCHERR_BADNAME;
1388 ldap_matchingrule_free(mr);
1391 } else if ( !strcmp(sval,"DESC") ) {
1394 *code = LDAP_SCHERR_DUPOPT;
1396 ldap_matchingrule_free(mr);
1401 kind = get_token(&ss,&sval);
1402 if ( kind != TK_QDSTRING ) {
1403 *code = LDAP_SCHERR_UNEXPTOKEN;
1406 ldap_matchingrule_free(mr);
1411 } else if ( !strcmp(sval,"OBSOLETE") ) {
1413 if ( seen_obsolete ) {
1414 *code = LDAP_SCHERR_DUPOPT;
1416 ldap_matchingrule_free(mr);
1420 mr->mr_obsolete = LDAP_SCHEMA_YES;
1422 } else if ( !strcmp(sval,"SYNTAX") ) {
1424 if ( seen_syntax ) {
1425 *code = LDAP_SCHERR_DUPOPT;
1427 ldap_matchingrule_free(mr);
1433 ldap_int_parse_numericoid(&ss,code,flags);
1434 if ( !mr->mr_syntax_oid ) {
1436 ldap_matchingrule_free(mr);
1440 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1441 /* Should be parse_qdstrings */
1442 ext_vals = parse_qdescrs(&ss, code);
1445 ldap_matchingrule_free(mr);
1448 if ( add_extension(&mr->mr_extensions,
1450 *code = LDAP_SCHERR_OUTOFMEM;
1453 ldap_matchingrule_free(mr);
1457 *code = LDAP_SCHERR_UNEXPTOKEN;
1460 ldap_matchingrule_free(mr);
1465 *code = LDAP_SCHERR_UNEXPTOKEN;
1468 ldap_matchingrule_free(mr);
1475 ldap_matchingruleuse_free( LDAPMatchingRuleUse * mru )
1477 LDAP_FREE(mru->mru_oid);
1478 if (mru->mru_names) LDAP_VFREE(mru->mru_names);
1479 if (mru->mru_desc) LDAP_FREE(mru->mru_desc);
1480 if (mru->mru_applies_oids) LDAP_VFREE(mru->mru_applies_oids);
1481 free_extensions(mru->mru_extensions);
1485 LDAPMatchingRuleUse *
1486 ldap_str2matchingruleuse( LDAP_CONST char * s,
1488 LDAP_CONST char ** errp,
1489 LDAP_CONST int flags )
1492 const char * ss = s;
1496 int seen_obsolete = 0;
1497 int seen_applies = 0;
1498 LDAPMatchingRuleUse * mru;
1500 const char * savepos;
1503 *code = LDAP_SCHERR_EMPTY;
1509 mru = LDAP_CALLOC(1,sizeof(LDAPMatchingRuleUse));
1512 *code = LDAP_SCHERR_OUTOFMEM;
1516 kind = get_token(&ss,&sval);
1517 if ( kind != TK_LEFTPAREN ) {
1518 *code = LDAP_SCHERR_NOLEFTPAREN;
1520 ldap_matchingruleuse_free(mru);
1526 mru->mru_oid = ldap_int_parse_numericoid(&ss,code,flags);
1527 if ( !mru->mru_oid ) {
1528 if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
1531 kind = get_token(&ss,&sval);
1532 if ( kind == TK_BAREWORD ) {
1533 if ( !strcmp(sval, "NAME") ||
1534 !strcmp(sval, "DESC") ||
1535 !strcmp(sval, "OBSOLETE") ||
1536 !strcmp(sval, "APPLIES") ||
1537 !strncmp(sval, "X-", 2) ) {
1538 /* Missing OID, backtrack */
1541 /* Non-numerical OID, ignore */
1547 ldap_matchingruleuse_free(mru);
1554 * Beyond this point we will be liberal and accept the items
1558 kind = get_token(&ss,&sval);
1561 *code = LDAP_SCHERR_NORIGHTPAREN;
1563 ldap_matchingruleuse_free(mru);
1568 if ( !strcmp(sval,"NAME") ) {
1571 *code = LDAP_SCHERR_DUPOPT;
1573 ldap_matchingruleuse_free(mru);
1577 mru->mru_names = parse_qdescrs(&ss,code);
1578 if ( !mru->mru_names ) {
1579 if ( *code != LDAP_SCHERR_OUTOFMEM )
1580 *code = LDAP_SCHERR_BADNAME;
1582 ldap_matchingruleuse_free(mru);
1585 } else if ( !strcmp(sval,"DESC") ) {
1588 *code = LDAP_SCHERR_DUPOPT;
1590 ldap_matchingruleuse_free(mru);
1595 kind = get_token(&ss,&sval);
1596 if ( kind != TK_QDSTRING ) {
1597 *code = LDAP_SCHERR_UNEXPTOKEN;
1600 ldap_matchingruleuse_free(mru);
1603 mru->mru_desc = sval;
1605 } else if ( !strcmp(sval,"OBSOLETE") ) {
1607 if ( seen_obsolete ) {
1608 *code = LDAP_SCHERR_DUPOPT;
1610 ldap_matchingruleuse_free(mru);
1614 mru->mru_obsolete = LDAP_SCHEMA_YES;
1616 } else if ( !strcmp(sval,"APPLIES") ) {
1618 if ( seen_applies ) {
1619 *code = LDAP_SCHERR_DUPOPT;
1621 ldap_matchingruleuse_free(mru);
1625 mru->mru_applies_oids = parse_oids(&ss,
1628 if ( !mru->mru_applies_oids ) {
1630 ldap_matchingruleuse_free(mru);
1633 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1634 /* Should be parse_qdstrings */
1635 ext_vals = parse_qdescrs(&ss, code);
1638 ldap_matchingruleuse_free(mru);
1641 if ( add_extension(&mru->mru_extensions,
1643 *code = LDAP_SCHERR_OUTOFMEM;
1646 ldap_matchingruleuse_free(mru);
1650 *code = LDAP_SCHERR_UNEXPTOKEN;
1653 ldap_matchingruleuse_free(mru);
1658 *code = LDAP_SCHERR_UNEXPTOKEN;
1661 ldap_matchingruleuse_free(mru);
1668 ldap_attributetype_free(LDAPAttributeType * at)
1670 LDAP_FREE(at->at_oid);
1671 if (at->at_names) LDAP_VFREE(at->at_names);
1672 if (at->at_desc) LDAP_FREE(at->at_desc);
1673 if (at->at_sup_oid) LDAP_FREE(at->at_sup_oid);
1674 if (at->at_equality_oid) LDAP_FREE(at->at_equality_oid);
1675 if (at->at_ordering_oid) LDAP_FREE(at->at_ordering_oid);
1676 if (at->at_substr_oid) LDAP_FREE(at->at_substr_oid);
1677 if (at->at_syntax_oid) LDAP_FREE(at->at_syntax_oid);
1678 free_extensions(at->at_extensions);
1683 ldap_str2attributetype( LDAP_CONST char * s,
1685 LDAP_CONST char ** errp,
1686 LDAP_CONST int flags )
1689 const char * ss = s;
1693 int seen_obsolete = 0;
1695 int seen_equality = 0;
1696 int seen_ordering = 0;
1697 int seen_substr = 0;
1698 int seen_syntax = 0;
1700 LDAPAttributeType * at;
1702 const char * savepos;
1705 *code = LDAP_SCHERR_EMPTY;
1711 at = LDAP_CALLOC(1,sizeof(LDAPAttributeType));
1714 *code = LDAP_SCHERR_OUTOFMEM;
1718 kind = get_token(&ss,&sval);
1719 if ( kind != TK_LEFTPAREN ) {
1720 *code = LDAP_SCHERR_NOLEFTPAREN;
1722 ldap_attributetype_free(at);
1727 * Definitions MUST begin with an OID in the numericoid format.
1728 * However, this routine is used by clients to parse the response
1729 * from servers and very well known servers will provide an OID
1730 * in the wrong format or even no OID at all. We do our best to
1731 * extract info from those servers.
1735 at->at_oid = ldap_int_parse_numericoid(&ss,code,0);
1736 if ( !at->at_oid ) {
1737 if ( ( flags & ( LDAP_SCHEMA_ALLOW_NO_OID
1738 | LDAP_SCHEMA_ALLOW_OID_MACRO ) )
1739 && (ss == savepos) ) {
1742 kind = get_token(&ss,&sval);
1743 if ( kind == TK_BAREWORD ) {
1744 if ( !strcmp(sval, "NAME") ||
1745 !strcmp(sval, "DESC") ||
1746 !strcmp(sval, "OBSOLETE") ||
1747 !strcmp(sval, "SUP") ||
1748 !strcmp(sval, "EQUALITY") ||
1749 !strcmp(sval, "ORDERING") ||
1750 !strcmp(sval, "SUBSTR") ||
1751 !strcmp(sval, "SYNTAX") ||
1752 !strcmp(sval, "SINGLE-VALUE") ||
1753 !strcmp(sval, "COLLECTIVE") ||
1754 !strcmp(sval, "NO-USER-MODIFICATION") ||
1755 !strcmp(sval, "USAGE") ||
1756 !strncmp(sval, "X-", 2) ) {
1757 /* Missing OID, backtrack */
1760 & LDAP_SCHEMA_ALLOW_OID_MACRO) {
1761 /* Non-numerical OID ... */
1762 int len = ss-savepos;
1763 at->at_oid = LDAP_MALLOC(len+1);
1764 strncpy(at->at_oid, savepos, len);
1765 at->at_oid[len] = 0;
1771 ldap_attributetype_free(at);
1778 * Beyond this point we will be liberal and accept the items
1782 kind = get_token(&ss,&sval);
1785 *code = LDAP_SCHERR_NORIGHTPAREN;
1787 ldap_attributetype_free(at);
1792 if ( !strcmp(sval,"NAME") ) {
1795 *code = LDAP_SCHERR_DUPOPT;
1797 ldap_attributetype_free(at);
1801 at->at_names = parse_qdescrs(&ss,code);
1802 if ( !at->at_names ) {
1803 if ( *code != LDAP_SCHERR_OUTOFMEM )
1804 *code = LDAP_SCHERR_BADNAME;
1806 ldap_attributetype_free(at);
1809 } else if ( !strcmp(sval,"DESC") ) {
1812 *code = LDAP_SCHERR_DUPOPT;
1814 ldap_attributetype_free(at);
1819 kind = get_token(&ss,&sval);
1820 if ( kind != TK_QDSTRING ) {
1821 *code = LDAP_SCHERR_UNEXPTOKEN;
1824 ldap_attributetype_free(at);
1829 } else if ( !strcmp(sval,"OBSOLETE") ) {
1831 if ( seen_obsolete ) {
1832 *code = LDAP_SCHERR_DUPOPT;
1834 ldap_attributetype_free(at);
1838 at->at_obsolete = LDAP_SCHEMA_YES;
1840 } else if ( !strcmp(sval,"SUP") ) {
1843 *code = LDAP_SCHERR_DUPOPT;
1845 ldap_attributetype_free(at);
1849 at->at_sup_oid = parse_woid(&ss,code);
1850 if ( !at->at_sup_oid ) {
1852 ldap_attributetype_free(at);
1855 } else if ( !strcmp(sval,"EQUALITY") ) {
1857 if ( seen_equality ) {
1858 *code = LDAP_SCHERR_DUPOPT;
1860 ldap_attributetype_free(at);
1864 at->at_equality_oid = parse_woid(&ss,code);
1865 if ( !at->at_equality_oid ) {
1867 ldap_attributetype_free(at);
1870 } else if ( !strcmp(sval,"ORDERING") ) {
1872 if ( seen_ordering ) {
1873 *code = LDAP_SCHERR_DUPOPT;
1875 ldap_attributetype_free(at);
1879 at->at_ordering_oid = parse_woid(&ss,code);
1880 if ( !at->at_ordering_oid ) {
1882 ldap_attributetype_free(at);
1885 } else if ( !strcmp(sval,"SUBSTR") ) {
1887 if ( seen_substr ) {
1888 *code = LDAP_SCHERR_DUPOPT;
1890 ldap_attributetype_free(at);
1894 at->at_substr_oid = parse_woid(&ss,code);
1895 if ( !at->at_substr_oid ) {
1897 ldap_attributetype_free(at);
1900 } else if ( !strcmp(sval,"SYNTAX") ) {
1902 if ( seen_syntax ) {
1903 *code = LDAP_SCHERR_DUPOPT;
1905 ldap_attributetype_free(at);
1916 if ( !at->at_syntax_oid ) {
1917 if ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO ) {
1918 kind = get_token(&ss,&sval);
1919 if (kind == TK_BAREWORD)
1921 char *sp = strchr(sval, '{');
1922 at->at_syntax_oid = sval;
1926 at->at_syntax_len = atoi(sp);
1927 while ( LDAP_DIGIT(*sp) )
1930 *code = LDAP_SCHERR_UNEXPTOKEN;
1932 ldap_attributetype_free(at);
1939 ldap_attributetype_free(at);
1944 } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
1946 if ( at->at_single_value ) {
1947 *code = LDAP_SCHERR_DUPOPT;
1949 ldap_attributetype_free(at);
1952 at->at_single_value = LDAP_SCHEMA_YES;
1954 } else if ( !strcmp(sval,"COLLECTIVE") ) {
1956 if ( at->at_collective ) {
1957 *code = LDAP_SCHERR_DUPOPT;
1959 ldap_attributetype_free(at);
1962 at->at_collective = LDAP_SCHEMA_YES;
1964 } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
1966 if ( at->at_no_user_mod ) {
1967 *code = LDAP_SCHERR_DUPOPT;
1969 ldap_attributetype_free(at);
1972 at->at_no_user_mod = LDAP_SCHEMA_YES;
1974 } else if ( !strcmp(sval,"USAGE") ) {
1977 *code = LDAP_SCHERR_DUPOPT;
1979 ldap_attributetype_free(at);
1984 kind = get_token(&ss,&sval);
1985 if ( kind != TK_BAREWORD ) {
1986 *code = LDAP_SCHERR_UNEXPTOKEN;
1989 ldap_attributetype_free(at);
1992 if ( !strcasecmp(sval,"userApplications") )
1994 LDAP_SCHEMA_USER_APPLICATIONS;
1995 else if ( !strcasecmp(sval,"directoryOperation") )
1997 LDAP_SCHEMA_DIRECTORY_OPERATION;
1998 else if ( !strcasecmp(sval,"distributedOperation") )
2000 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
2001 else if ( !strcasecmp(sval,"dSAOperation") )
2003 LDAP_SCHEMA_DSA_OPERATION;
2005 *code = LDAP_SCHERR_UNEXPTOKEN;
2008 ldap_attributetype_free(at);
2013 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
2014 /* Should be parse_qdstrings */
2015 ext_vals = parse_qdescrs(&ss, code);
2018 ldap_attributetype_free(at);
2021 if ( add_extension(&at->at_extensions,
2023 *code = LDAP_SCHERR_OUTOFMEM;
2026 ldap_attributetype_free(at);
2030 *code = LDAP_SCHERR_UNEXPTOKEN;
2033 ldap_attributetype_free(at);
2038 *code = LDAP_SCHERR_UNEXPTOKEN;
2041 ldap_attributetype_free(at);
2048 ldap_objectclass_free(LDAPObjectClass * oc)
2050 LDAP_FREE(oc->oc_oid);
2051 if (oc->oc_names) LDAP_VFREE(oc->oc_names);
2052 if (oc->oc_desc) LDAP_FREE(oc->oc_desc);
2053 if (oc->oc_sup_oids) LDAP_VFREE(oc->oc_sup_oids);
2054 if (oc->oc_at_oids_must) LDAP_VFREE(oc->oc_at_oids_must);
2055 if (oc->oc_at_oids_may) LDAP_VFREE(oc->oc_at_oids_may);
2056 free_extensions(oc->oc_extensions);
2061 ldap_str2objectclass( LDAP_CONST char * s,
2063 LDAP_CONST char ** errp,
2064 LDAP_CONST int flags )
2067 const char * ss = s;
2071 int seen_obsolete = 0;
2076 LDAPObjectClass * oc;
2078 const char * savepos;
2081 *code = LDAP_SCHERR_EMPTY;
2087 oc = LDAP_CALLOC(1,sizeof(LDAPObjectClass));
2090 *code = LDAP_SCHERR_OUTOFMEM;
2093 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
2095 kind = get_token(&ss,&sval);
2096 if ( kind != TK_LEFTPAREN ) {
2097 *code = LDAP_SCHERR_NOLEFTPAREN;
2099 ldap_objectclass_free(oc);
2104 * Definitions MUST begin with an OID in the numericoid format.
2105 * However, this routine is used by clients to parse the response
2106 * from servers and very well known servers will provide an OID
2107 * in the wrong format or even no OID at all. We do our best to
2108 * extract info from those servers.
2112 oc->oc_oid = ldap_int_parse_numericoid(&ss,code,0);
2113 if ( !oc->oc_oid ) {
2114 if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) {
2117 kind = get_token(&ss,&sval);
2118 if ( kind == TK_BAREWORD ) {
2119 if ( !strcmp(sval, "NAME") ||
2120 !strcmp(sval, "DESC") ||
2121 !strcmp(sval, "OBSOLETE") ||
2122 !strcmp(sval, "SUP") ||
2123 !strcmp(sval, "ABSTRACT") ||
2124 !strcmp(sval, "STRUCTURAL") ||
2125 !strcmp(sval, "AUXILIARY") ||
2126 !strcmp(sval, "MUST") ||
2127 !strncmp(sval, "X-", 2) ) {
2128 /* Missing OID, backtrack */
2131 LDAP_SCHEMA_ALLOW_OID_MACRO ) {
2132 /* Non-numerical OID, ignore */
2133 int len = ss-savepos;
2134 oc->oc_oid = LDAP_MALLOC(len+1);
2135 strncpy(oc->oc_oid, savepos, len);
2136 oc->oc_oid[len] = 0;
2142 ldap_objectclass_free(oc);
2149 * Beyond this point we will be liberal an accept the items
2153 kind = get_token(&ss,&sval);
2156 *code = LDAP_SCHERR_NORIGHTPAREN;
2158 ldap_objectclass_free(oc);
2163 if ( !strcmp(sval,"NAME") ) {
2166 *code = LDAP_SCHERR_DUPOPT;
2168 ldap_objectclass_free(oc);
2172 oc->oc_names = parse_qdescrs(&ss,code);
2173 if ( !oc->oc_names ) {
2174 if ( *code != LDAP_SCHERR_OUTOFMEM )
2175 *code = LDAP_SCHERR_BADNAME;
2177 ldap_objectclass_free(oc);
2180 } else if ( !strcmp(sval,"DESC") ) {
2183 *code = LDAP_SCHERR_DUPOPT;
2185 ldap_objectclass_free(oc);
2190 kind = get_token(&ss,&sval);
2191 if ( kind != TK_QDSTRING ) {
2192 *code = LDAP_SCHERR_UNEXPTOKEN;
2195 ldap_objectclass_free(oc);
2200 } else if ( !strcmp(sval,"OBSOLETE") ) {
2202 if ( seen_obsolete ) {
2203 *code = LDAP_SCHERR_DUPOPT;
2205 ldap_objectclass_free(oc);
2209 oc->oc_obsolete = LDAP_SCHEMA_YES;
2211 } else if ( !strcmp(sval,"SUP") ) {
2214 *code = LDAP_SCHERR_DUPOPT;
2216 ldap_objectclass_free(oc);
2220 oc->oc_sup_oids = parse_oids(&ss,
2223 if ( !oc->oc_sup_oids ) {
2225 ldap_objectclass_free(oc);
2228 } else if ( !strcmp(sval,"ABSTRACT") ) {
2231 *code = LDAP_SCHERR_DUPOPT;
2233 ldap_objectclass_free(oc);
2237 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
2239 } else if ( !strcmp(sval,"STRUCTURAL") ) {
2242 *code = LDAP_SCHERR_DUPOPT;
2244 ldap_objectclass_free(oc);
2248 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
2250 } else if ( !strcmp(sval,"AUXILIARY") ) {
2253 *code = LDAP_SCHERR_DUPOPT;
2255 ldap_objectclass_free(oc);
2259 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
2261 } else if ( !strcmp(sval,"MUST") ) {
2264 *code = LDAP_SCHERR_DUPOPT;
2266 ldap_objectclass_free(oc);
2270 oc->oc_at_oids_must = parse_oids(&ss,code,0);
2271 if ( !oc->oc_at_oids_must ) {
2273 ldap_objectclass_free(oc);
2277 } else if ( !strcmp(sval,"MAY") ) {
2280 *code = LDAP_SCHERR_DUPOPT;
2282 ldap_objectclass_free(oc);
2286 oc->oc_at_oids_may = parse_oids(&ss,code,0);
2287 if ( !oc->oc_at_oids_may ) {
2289 ldap_objectclass_free(oc);
2293 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
2294 /* Should be parse_qdstrings */
2295 ext_vals = parse_qdescrs(&ss, code);
2298 ldap_objectclass_free(oc);
2301 if ( add_extension(&oc->oc_extensions,
2303 *code = LDAP_SCHERR_OUTOFMEM;
2306 ldap_objectclass_free(oc);
2310 *code = LDAP_SCHERR_UNEXPTOKEN;
2313 ldap_objectclass_free(oc);
2318 *code = LDAP_SCHERR_UNEXPTOKEN;
2321 ldap_objectclass_free(oc);
2327 static char *const err2text[] = {
2331 "Missing opening parenthesis",
2332 "Missing closing parenthesis",
2338 "Unexpected end of data"
2342 ldap_scherr2str(int code)
2344 if ( code < 0 || code >= (int)(sizeof(err2text)/sizeof(char *)) ) {
2345 return "Unknown error";
2347 return err2text[code];