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>
17 #include <ac/string.h>
22 #include <ldap_schema.h>
25 static LDAP_CONST char *
26 choose_name( char *names[], LDAP_CONST char *fallback )
28 return( (names != NULL && names[0] != NULL) ? names[0] : fallback );
32 ldap_syntax2name( LDAP_SYNTAX * syn )
34 return( syn->syn_oid );
38 ldap_matchingrule2name( LDAP_MATCHING_RULE * mr )
40 return( choose_name( mr->mr_names, mr->mr_oid ) );
44 ldap_attributetype2name( LDAP_ATTRIBUTE_TYPE * at )
46 return( choose_name( at->at_names, at->at_oid ) );
50 ldap_objectclass2name( LDAP_OBJECT_CLASS * oc )
52 return( choose_name( oc->oc_names, oc->oc_oid ) );
57 * When pretty printing the entities we will be appending to a buffer.
58 * Since checking for overflow, realloc'ing and checking if no error
59 * is extremely boring, we will use a protection layer that will let
60 * us blissfully ignore the error until the end. This layer is
61 * implemented with the help of the next type.
64 typedef struct safe_string {
72 new_safe_string(int size)
76 ss = LDAP_MALLOC(sizeof(safe_string));
80 ss->val = LDAP_MALLOC(size);
94 safe_string_free(safe_string * ss)
103 safe_string_val(safe_string * ss)
105 ss->val[ss->pos] = '\0';
110 append_to_safe_string(safe_string * ss, char * s)
116 * Some runaway process is trying to append to a string that
117 * overflowed and we could not extend.
122 /* We always make sure there is at least one position available */
123 if ( ss->pos + l >= ss->size-1 ) {
125 temp = LDAP_REALLOC(ss->val, ss->size);
127 /* Trouble, out of memory */
133 strncpy(&ss->val[ss->pos], s, l);
135 if ( ss->pos > 0 && isspace(ss->val[ss->pos-1]) )
144 print_literal(safe_string *ss, char *s)
146 return(append_to_safe_string(ss,s));
150 print_whsp(safe_string *ss)
153 return(append_to_safe_string(ss,""));
155 return(append_to_safe_string(ss," "));
159 print_numericoid(safe_string *ss, char *s)
162 return(append_to_safe_string(ss,s));
164 return(append_to_safe_string(ss,""));
167 /* This one is identical to print_qdescr */
169 print_qdstring(safe_string *ss, char *s)
172 print_literal(ss,"'");
173 append_to_safe_string(ss,s);
174 print_literal(ss,"'");
175 return(print_whsp(ss));
179 print_qdescr(safe_string *ss, char *s)
182 print_literal(ss,"'");
183 append_to_safe_string(ss,s);
184 print_literal(ss,"'");
185 return(print_whsp(ss));
189 print_qdescrlist(safe_string *ss, char **sa)
194 for (sp=sa; *sp; sp++) {
195 ret = print_qdescr(ss,*sp);
197 /* If the list was empty, we return zero that is potentially
198 * incorrect, but since we will be still appending things, the
199 * overflow will be detected later. Maybe FIX.
205 print_qdescrs(safe_string *ss, char **sa)
207 /* The only way to represent an empty list is as a qdescrlist
208 * so, if the list is empty we treat it as a long list.
209 * Really, this is what the syntax mandates. We should not
210 * be here if the list was empty, but if it happens, a label
211 * has already been output and we cannot undo it.
213 if ( !sa[0] || ( sa[0] && sa[1] ) ) {
215 print_literal(ss,"("/*)*/);
216 print_qdescrlist(ss,sa);
217 print_literal(ss,/*(*/")");
218 return(print_whsp(ss));
220 return(print_qdescr(ss,*sa));
225 print_woid(safe_string *ss, char *s)
228 append_to_safe_string(ss,s);
229 return print_whsp(ss);
233 print_oidlist(safe_string *ss, char **sa)
237 for (sp=sa; *(sp+1); sp++) {
239 print_literal(ss,"$");
241 return(print_woid(ss,*sp));
245 print_oids(safe_string *ss, char **sa)
247 if ( sa[0] && sa[1] ) {
248 print_literal(ss,"("/*)*/);
249 print_oidlist(ss,sa);
251 return(print_literal(ss,/*(*/")"));
253 return(print_woid(ss,*sa));
258 print_noidlen(safe_string *ss, char *s, int l)
263 ret = print_numericoid(ss,s);
265 sprintf(buf,"{%d}",l);
266 ret = print_literal(ss,buf);
272 print_extensions(safe_string *ss, LDAP_SCHEMA_EXTENSION_ITEM **extensions)
274 LDAP_SCHEMA_EXTENSION_ITEM **ext;
278 for ( ext = extensions; *ext != NULL; ext++ ) {
279 print_literal(ss, (*ext)->lsei_name);
281 /* Should be print_qdstrings */
282 print_qdescrs(ss, (*ext)->lsei_values);
291 ldap_syntax2str( const LDAP_SYNTAX * syn )
296 ss = new_safe_string(256);
300 print_literal(ss,"("/*)*/);
303 print_numericoid(ss, syn->syn_oid);
306 if ( syn->syn_desc ) {
307 print_literal(ss,"DESC");
308 print_qdstring(ss,syn->syn_desc);
313 print_extensions(ss, syn->syn_extensions);
315 print_literal(ss,/*(*/ ")");
317 retstring = LDAP_STRDUP(safe_string_val(ss));
318 safe_string_free(ss);
323 ldap_matchingrule2str( const LDAP_MATCHING_RULE * mr )
328 ss = new_safe_string(256);
332 print_literal(ss,"(" /*)*/);
335 print_numericoid(ss, mr->mr_oid);
338 if ( mr->mr_names ) {
339 print_literal(ss,"NAME");
340 print_qdescrs(ss,mr->mr_names);
344 print_literal(ss,"DESC");
345 print_qdstring(ss,mr->mr_desc);
348 if ( mr->mr_obsolete == LDAP_SCHEMA_YES ) {
349 print_literal(ss, "OBSOLETE");
353 if ( mr->mr_syntax_oid ) {
354 print_literal(ss,"SYNTAX");
356 print_literal(ss, mr->mr_syntax_oid);
362 print_extensions(ss, mr->mr_extensions);
364 print_literal(ss,/*(*/")");
366 retstring = LDAP_STRDUP(safe_string_val(ss));
367 safe_string_free(ss);
372 ldap_objectclass2str( const LDAP_OBJECT_CLASS * oc )
377 ss = new_safe_string(256);
381 print_literal(ss,"("/*)*/);
384 print_numericoid(ss, oc->oc_oid);
387 if ( oc->oc_names ) {
388 print_literal(ss,"NAME");
389 print_qdescrs(ss,oc->oc_names);
393 print_literal(ss,"DESC");
394 print_qdstring(ss,oc->oc_desc);
397 if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) {
398 print_literal(ss, "OBSOLETE");
402 if ( oc->oc_sup_oids ) {
403 print_literal(ss,"SUP");
405 print_oids(ss,oc->oc_sup_oids);
409 switch (oc->oc_kind) {
410 case LDAP_SCHEMA_ABSTRACT:
411 print_literal(ss,"ABSTRACT");
413 case LDAP_SCHEMA_STRUCTURAL:
414 print_literal(ss,"STRUCTURAL");
416 case LDAP_SCHEMA_AUXILIARY:
417 print_literal(ss,"AUXILIARY");
420 print_literal(ss,"KIND-UNKNOWN");
425 if ( oc->oc_at_oids_must ) {
426 print_literal(ss,"MUST");
428 print_oids(ss,oc->oc_at_oids_must);
432 if ( oc->oc_at_oids_may ) {
433 print_literal(ss,"MAY");
435 print_oids(ss,oc->oc_at_oids_may);
441 print_extensions(ss, oc->oc_extensions);
443 print_literal(ss, /*(*/")");
445 retstring = LDAP_STRDUP(safe_string_val(ss));
446 safe_string_free(ss);
451 ldap_attributetype2str( const LDAP_ATTRIBUTE_TYPE * at )
456 ss = new_safe_string(256);
460 print_literal(ss,"("/*)*/);
463 print_numericoid(ss, at->at_oid);
466 if ( at->at_names ) {
467 print_literal(ss,"NAME");
468 print_qdescrs(ss,at->at_names);
472 print_literal(ss,"DESC");
473 print_qdstring(ss,at->at_desc);
476 if ( at->at_obsolete == LDAP_SCHEMA_YES ) {
477 print_literal(ss, "OBSOLETE");
481 if ( at->at_sup_oid ) {
482 print_literal(ss,"SUP");
483 print_woid(ss,at->at_sup_oid);
486 if ( at->at_equality_oid ) {
487 print_literal(ss,"EQUALITY");
488 print_woid(ss,at->at_equality_oid);
491 if ( at->at_ordering_oid ) {
492 print_literal(ss,"ORDERING");
493 print_woid(ss,at->at_ordering_oid);
496 if ( at->at_substr_oid ) {
497 print_literal(ss,"SUBSTR");
498 print_woid(ss,at->at_substr_oid);
501 if ( at->at_syntax_oid ) {
502 print_literal(ss,"SYNTAX");
504 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
508 if ( at->at_single_value == LDAP_SCHEMA_YES ) {
509 print_literal(ss,"SINGLE-VALUE");
513 if ( at->at_collective == LDAP_SCHEMA_YES ) {
514 print_literal(ss,"COLLECTIVE");
518 if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
519 print_literal(ss,"NO-USER-MODIFICATION");
523 if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
524 print_literal(ss,"USAGE");
526 switch (at->at_usage) {
527 case LDAP_SCHEMA_DIRECTORY_OPERATION:
528 print_literal(ss,"directoryOperation");
530 case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
531 print_literal(ss,"distributedOperation");
533 case LDAP_SCHEMA_DSA_OPERATION:
534 print_literal(ss,"dSAOperation");
537 print_literal(ss,"UNKNOWN");
544 print_extensions(ss, at->at_extensions);
546 print_literal(ss,/*(*/")");
548 retstring = LDAP_STRDUP(safe_string_val(ss));
549 safe_string_free(ss);
554 * Now come the parsers. There is one parser for each entity type:
555 * objectclasses, attributetypes, etc.
557 * Each of them is written as a recursive-descent parser, except that
558 * none of them is really recursive. But the idea is kept: there
559 * is one routine per non-terminal that eithers gobbles lexical tokens
560 * or calls lower-level routines, etc.
562 * The scanner is implemented in the routine get_token. Actually,
563 * get_token is more than a scanner and will return tokens that are
564 * in fact non-terminals in the grammar. So you can see the whole
565 * approach as the combination of a low-level bottom-up recognizer
566 * combined with a scanner and a number of top-down parsers. Or just
567 * consider that the real grammars recognized by the parsers are not
568 * those of the standards. As a matter of fact, our parsers are more
569 * liberal than the spec when there is no ambiguity.
571 * The difference is pretty academic (modulo bugs or incorrect
572 * interpretation of the specs).
575 #define TK_NOENDQUOTE -2
576 #define TK_OUTOFMEM -1
578 #define TK_UNEXPCHAR 1
579 #define TK_BAREWORD 2
580 #define TK_QDSTRING 3
581 #define TK_LEFTPAREN 4
582 #define TK_RIGHTPAREN 5
584 #define TK_QDESCR TK_QDSTRING
592 get_token(const char ** sp, char ** token_val)
610 kind = TK_RIGHTPAREN;
621 while ( **sp != '\'' && **sp != '\0' )
623 if ( **sp == '\'' ) {
625 res = LDAP_MALLOC(q-p+1);
635 kind = TK_NOENDQUOTE;
641 while ( !isspace(**sp) &&
649 res = LDAP_MALLOC(q-p+1);
658 /* kind = TK_UNEXPCHAR; */
665 /* Gobble optional whitespace */
667 parse_whsp(const char **sp)
669 while (isspace(**sp))
674 * General note for all parsers: to guarantee the algorithm halts they
675 * must always advance the pointer even when an error is found. For
676 * this one is not that important since an error here is fatal at the
677 * upper layers, but it is a simple strategy that will not get in
681 /* Parse a sequence of dot-separated decimal strings */
683 parse_numericoid(const char **sp, int *code, const int allow_quoted)
686 const char * start = *sp;
690 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
691 if ( allow_quoted && **sp == '\'' ) {
696 /* Each iteration of this loop gets one decimal string */
698 if ( !isdigit(**sp) ) {
700 * Initial char is not a digit or char after dot is
703 *code = LDAP_SCHERR_NODIGIT;
707 while ( isdigit(**sp) )
711 /* Otherwise, gobble the dot and loop again */
714 /* Now *sp points at the char past the numericoid. Perfect. */
716 res = LDAP_MALLOC(len+1);
718 *code = LDAP_SCHERR_OUTOFMEM;
721 strncpy(res,start,len);
723 if ( allow_quoted && quoted ) {
724 if ( **sp == '\'' ) {
727 *code = LDAP_SCHERR_UNEXPTOKEN;
735 /* Parse a qdescr or a list of them enclosed in () */
737 parse_qdescrs(const char **sp, int *code)
747 kind = get_token(sp,&sval);
748 if ( kind == TK_LEFTPAREN ) {
749 /* Let's presume there will be at least 2 entries */
751 res = LDAP_CALLOC(3,sizeof(char *));
753 *code = LDAP_SCHERR_OUTOFMEM;
759 kind = get_token(sp,&sval);
760 if ( kind == TK_RIGHTPAREN )
762 if ( kind == TK_QDESCR ) {
763 if ( pos == size-2 ) {
765 res1 = LDAP_REALLOC(res,size*sizeof(char *));
769 *code = LDAP_SCHERR_OUTOFMEM;
780 *code = LDAP_SCHERR_UNEXPTOKEN;
787 } else if ( kind == TK_QDESCR ) {
788 res = LDAP_CALLOC(2,sizeof(char *));
790 *code = LDAP_SCHERR_OUTOFMEM;
799 *code = LDAP_SCHERR_BADNAME;
806 parse_woid(const char **sp, int *code)
812 kind = get_token(sp, &sval);
813 if ( kind != TK_BAREWORD ) {
815 *code = LDAP_SCHERR_UNEXPTOKEN;
822 /* Parse a noidlen */
824 parse_noidlen(const char **sp, int *code, int *len, int allow_quoted)
830 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
831 if ( allow_quoted && **sp == '\'' ) {
835 sval = parse_numericoid(sp, code, 0);
839 if ( **sp == '{' /*}*/ ) {
842 while ( isdigit(**sp) )
844 if ( **sp != /*{*/ '}' ) {
845 *code = LDAP_SCHERR_UNEXPTOKEN;
851 if ( allow_quoted && quoted ) {
852 if ( **sp == '\'' ) {
855 *code = LDAP_SCHERR_UNEXPTOKEN;
864 * Next routine will accept a qdstring in place of an oid if
865 * allow_quoted is set. This is necessary to interoperate with
866 * Netscape Directory server that will improperly quote each oid (at
867 * least those of the descr kind) in the SUP clause.
870 /* Parse a woid or a $-separated list of them enclosed in () */
872 parse_oids(const char **sp, int *code, const int allow_quoted)
882 * Strictly speaking, doing this here accepts whsp before the
883 * ( at the begining of an oidlist, but this is harmless. Also,
884 * we are very liberal in what we accept as an OID. Maybe
888 kind = get_token(sp,&sval);
889 if ( kind == TK_LEFTPAREN ) {
890 /* Let's presume there will be at least 2 entries */
892 res = LDAP_CALLOC(3,sizeof(char *));
894 *code = LDAP_SCHERR_OUTOFMEM;
899 kind = get_token(sp,&sval);
900 if ( kind == TK_BAREWORD ||
901 ( allow_quoted && kind == TK_QDSTRING ) ) {
905 *code = LDAP_SCHERR_UNEXPTOKEN;
912 kind = get_token(sp,&sval);
913 if ( kind == TK_RIGHTPAREN )
915 if ( kind == TK_DOLLAR ) {
917 kind = get_token(sp,&sval);
918 if ( kind == TK_BAREWORD ||
920 kind == TK_QDSTRING ) ) {
921 if ( pos == size-2 ) {
923 res1 = LDAP_REALLOC(res,size*sizeof(char *));
927 *code = LDAP_SCHERR_OUTOFMEM;
935 *code = LDAP_SCHERR_UNEXPTOKEN;
942 *code = LDAP_SCHERR_UNEXPTOKEN;
951 } else if ( kind == TK_BAREWORD ||
952 ( allow_quoted && kind == TK_QDSTRING ) ) {
953 res = LDAP_CALLOC(2,sizeof(char *));
956 *code = LDAP_SCHERR_OUTOFMEM;
965 *code = LDAP_SCHERR_BADNAME;
971 add_extension(LDAP_SCHEMA_EXTENSION_ITEM ***extensions,
972 char * name, char ** values)
975 LDAP_SCHEMA_EXTENSION_ITEM **tmp, *ext;
977 ext = LDAP_CALLOC(1, sizeof(LDAP_SCHEMA_EXTENSION_ITEM));
980 ext->lsei_name = name;
981 ext->lsei_values = values;
983 if ( !*extensions ) {
985 LDAP_CALLOC(2, sizeof(LDAP_SCHEMA_EXTENSION_ITEM *));
990 for ( n=0; (*extensions)[n] != NULL; n++ )
992 tmp = LDAP_REALLOC(*extensions,
993 (n+2)*sizeof(LDAP_SCHEMA_EXTENSION_ITEM *));
998 (*extensions)[n] = ext;
999 (*extensions)[n+1] = NULL;
1004 free_extensions(LDAP_SCHEMA_EXTENSION_ITEM **extensions)
1006 LDAP_SCHEMA_EXTENSION_ITEM **ext;
1009 for ( ext = extensions; *ext != NULL; ext++ ) {
1010 LDAP_FREE((*ext)->lsei_name);
1011 LDAP_VFREE((*ext)->lsei_values);
1014 LDAP_FREE(extensions);
1019 ldap_syntax_free( LDAP_SYNTAX * syn )
1021 LDAP_FREE(syn->syn_oid);
1022 LDAP_FREE(syn->syn_desc);
1023 free_extensions(syn->syn_extensions);
1028 ldap_str2syntax( const char * s, int * code, const char ** errp )
1031 const char * ss = s;
1038 *code = LDAP_SCHERR_EMPTY;
1044 syn = LDAP_CALLOC(1,sizeof(LDAP_SYNTAX));
1047 *code = LDAP_SCHERR_OUTOFMEM;
1051 kind = get_token(&ss,&sval);
1052 if ( kind != TK_LEFTPAREN ) {
1054 *code = LDAP_SCHERR_NOLEFTPAREN;
1055 ldap_syntax_free(syn);
1060 syn->syn_oid = parse_numericoid(&ss,code,0);
1061 if ( !syn->syn_oid ) {
1063 ldap_syntax_free(syn);
1069 * Beyond this point we will be liberal and accept the items
1073 kind = get_token(&ss,&sval);
1076 *code = LDAP_SCHERR_NORIGHTPAREN;
1078 ldap_syntax_free(syn);
1083 if ( !strcmp(sval,"DESC") ) {
1086 *code = LDAP_SCHERR_DUPOPT;
1088 ldap_syntax_free(syn);
1093 kind = get_token(&ss,&sval);
1094 if ( kind != TK_QDSTRING ) {
1095 *code = LDAP_SCHERR_UNEXPTOKEN;
1098 ldap_syntax_free(syn);
1101 syn->syn_desc = sval;
1103 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1104 /* Should be parse_qdstrings */
1105 ext_vals = parse_qdescrs(&ss, code);
1108 ldap_syntax_free(syn);
1111 if ( add_extension(&syn->syn_extensions,
1113 *code = LDAP_SCHERR_OUTOFMEM;
1116 ldap_syntax_free(syn);
1120 *code = LDAP_SCHERR_UNEXPTOKEN;
1123 ldap_syntax_free(syn);
1128 *code = LDAP_SCHERR_UNEXPTOKEN;
1131 ldap_syntax_free(syn);
1138 ldap_matchingrule_free( LDAP_MATCHING_RULE * mr )
1140 LDAP_FREE(mr->mr_oid);
1141 LDAP_VFREE(mr->mr_names);
1142 LDAP_FREE(mr->mr_desc);
1143 LDAP_FREE(mr->mr_syntax_oid);
1144 free_extensions(mr->mr_extensions);
1148 LDAP_MATCHING_RULE *
1149 ldap_str2matchingrule( const char * s, int * code, const char ** errp )
1152 const char * ss = s;
1154 int be_liberal = 1; /* Future additional argument */
1157 int seen_obsolete = 0;
1158 int seen_syntax = 0;
1159 LDAP_MATCHING_RULE * mr;
1161 const char * savepos;
1164 *code = LDAP_SCHERR_EMPTY;
1170 mr = LDAP_CALLOC(1,sizeof(LDAP_MATCHING_RULE));
1173 *code = LDAP_SCHERR_OUTOFMEM;
1177 kind = get_token(&ss,&sval);
1178 if ( kind != TK_LEFTPAREN ) {
1179 *code = LDAP_SCHERR_NOLEFTPAREN;
1181 ldap_matchingrule_free(mr);
1187 mr->mr_oid = parse_numericoid(&ss,code,be_liberal);
1188 if ( !mr->mr_oid ) {
1192 kind = get_token(&ss,&sval);
1193 if ( kind == TK_BAREWORD ) {
1194 if ( !strcmp(sval, "NAME") ||
1195 !strcmp(sval, "DESC") ||
1196 !strcmp(sval, "OBSOLETE") ||
1197 !strcmp(sval, "SYNTAX") ||
1198 !strncmp(sval, "X-", 2) ) {
1199 /* Missing OID, backtrack */
1202 /* Non-numerical OID, ignore */
1208 ldap_matchingrule_free(mr);
1215 * Beyond this point we will be liberal and accept the items
1219 kind = get_token(&ss,&sval);
1222 *code = LDAP_SCHERR_NORIGHTPAREN;
1224 ldap_matchingrule_free(mr);
1229 if ( !strcmp(sval,"NAME") ) {
1232 *code = LDAP_SCHERR_DUPOPT;
1234 ldap_matchingrule_free(mr);
1238 mr->mr_names = parse_qdescrs(&ss,code);
1239 if ( !mr->mr_names ) {
1240 if ( *code != LDAP_SCHERR_OUTOFMEM )
1241 *code = LDAP_SCHERR_BADNAME;
1243 ldap_matchingrule_free(mr);
1246 } else if ( !strcmp(sval,"DESC") ) {
1249 *code = LDAP_SCHERR_DUPOPT;
1251 ldap_matchingrule_free(mr);
1256 kind = get_token(&ss,&sval);
1257 if ( kind != TK_QDSTRING ) {
1258 *code = LDAP_SCHERR_UNEXPTOKEN;
1261 ldap_matchingrule_free(mr);
1266 } else if ( !strcmp(sval,"OBSOLETE") ) {
1268 if ( seen_obsolete ) {
1269 *code = LDAP_SCHERR_DUPOPT;
1271 ldap_matchingrule_free(mr);
1275 mr->mr_obsolete = LDAP_SCHEMA_YES;
1277 } else if ( !strcmp(sval,"SYNTAX") ) {
1279 if ( seen_syntax ) {
1280 *code = LDAP_SCHERR_DUPOPT;
1282 ldap_matchingrule_free(mr);
1288 parse_numericoid(&ss,code,be_liberal);
1289 if ( !mr->mr_syntax_oid ) {
1291 ldap_matchingrule_free(mr);
1295 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1296 /* Should be parse_qdstrings */
1297 ext_vals = parse_qdescrs(&ss, code);
1300 ldap_matchingrule_free(mr);
1303 if ( add_extension(&mr->mr_extensions,
1305 *code = LDAP_SCHERR_OUTOFMEM;
1308 ldap_matchingrule_free(mr);
1312 *code = LDAP_SCHERR_UNEXPTOKEN;
1315 ldap_matchingrule_free(mr);
1320 *code = LDAP_SCHERR_UNEXPTOKEN;
1323 ldap_matchingrule_free(mr);
1330 ldap_attributetype_free(LDAP_ATTRIBUTE_TYPE * at)
1332 LDAP_FREE(at->at_oid);
1333 LDAP_VFREE(at->at_names);
1334 LDAP_FREE(at->at_desc);
1335 LDAP_FREE(at->at_sup_oid);
1336 LDAP_FREE(at->at_equality_oid);
1337 LDAP_FREE(at->at_ordering_oid);
1338 LDAP_FREE(at->at_substr_oid);
1339 LDAP_FREE(at->at_syntax_oid);
1340 free_extensions(at->at_extensions);
1344 LDAP_ATTRIBUTE_TYPE *
1345 ldap_str2attributetype( const char * s, int * code, const char ** errp )
1348 const char * ss = s;
1350 int be_liberal = 1; /* Future additional argument */
1353 int seen_obsolete = 0;
1355 int seen_equality = 0;
1356 int seen_ordering = 0;
1357 int seen_substr = 0;
1358 int seen_syntax = 0;
1360 LDAP_ATTRIBUTE_TYPE * at;
1362 const char * savepos;
1365 *code = LDAP_SCHERR_EMPTY;
1371 at = LDAP_CALLOC(1,sizeof(LDAP_ATTRIBUTE_TYPE));
1374 *code = LDAP_SCHERR_OUTOFMEM;
1378 kind = get_token(&ss,&sval);
1379 if ( kind != TK_LEFTPAREN ) {
1380 *code = LDAP_SCHERR_NOLEFTPAREN;
1382 ldap_attributetype_free(at);
1387 * Definitions MUST begin with an OID in the numericoid format.
1388 * However, this routine is used by clients to parse the response
1389 * from servers and very well known servers will provide an OID
1390 * in the wrong format or even no OID at all. We do our best to
1391 * extract info from those servers.
1395 at->at_oid = parse_numericoid(&ss,code,0);
1396 if ( !at->at_oid ) {
1400 kind = get_token(&ss,&sval);
1401 if ( kind == TK_BAREWORD ) {
1402 if ( !strcmp(sval, "NAME") ||
1403 !strcmp(sval, "DESC") ||
1404 !strcmp(sval, "OBSOLETE") ||
1405 !strcmp(sval, "SUP") ||
1406 !strcmp(sval, "EQUALITY") ||
1407 !strcmp(sval, "ORDERING") ||
1408 !strcmp(sval, "SUBSTR") ||
1409 !strcmp(sval, "SYNTAX") ||
1410 !strcmp(sval, "SINGLE-VALUE") ||
1411 !strcmp(sval, "COLLECTIVE") ||
1412 !strcmp(sval, "NO-USER-MODIFICATION") ||
1413 !strcmp(sval, "USAGE") ||
1414 !strncmp(sval, "X-", 2) ) {
1415 /* Missing OID, backtrack */
1418 /* Non-numerical OID, ignore */
1424 ldap_attributetype_free(at);
1431 * Beyond this point we will be liberal and accept the items
1435 kind = get_token(&ss,&sval);
1438 *code = LDAP_SCHERR_NORIGHTPAREN;
1440 ldap_attributetype_free(at);
1445 if ( !strcmp(sval,"NAME") ) {
1448 *code = LDAP_SCHERR_DUPOPT;
1450 ldap_attributetype_free(at);
1454 at->at_names = parse_qdescrs(&ss,code);
1455 if ( !at->at_names ) {
1456 if ( *code != LDAP_SCHERR_OUTOFMEM )
1457 *code = LDAP_SCHERR_BADNAME;
1459 ldap_attributetype_free(at);
1462 } else if ( !strcmp(sval,"DESC") ) {
1465 *code = LDAP_SCHERR_DUPOPT;
1467 ldap_attributetype_free(at);
1472 kind = get_token(&ss,&sval);
1473 if ( kind != TK_QDSTRING ) {
1474 *code = LDAP_SCHERR_UNEXPTOKEN;
1477 ldap_attributetype_free(at);
1482 } else if ( !strcmp(sval,"OBSOLETE") ) {
1484 if ( seen_obsolete ) {
1485 *code = LDAP_SCHERR_DUPOPT;
1487 ldap_attributetype_free(at);
1491 at->at_obsolete = LDAP_SCHEMA_YES;
1493 } else if ( !strcmp(sval,"SUP") ) {
1496 *code = LDAP_SCHERR_DUPOPT;
1498 ldap_attributetype_free(at);
1502 at->at_sup_oid = parse_woid(&ss,code);
1503 if ( !at->at_sup_oid ) {
1505 ldap_attributetype_free(at);
1508 } else if ( !strcmp(sval,"EQUALITY") ) {
1510 if ( seen_equality ) {
1511 *code = LDAP_SCHERR_DUPOPT;
1513 ldap_attributetype_free(at);
1517 at->at_equality_oid = parse_woid(&ss,code);
1518 if ( !at->at_equality_oid ) {
1520 ldap_attributetype_free(at);
1523 } else if ( !strcmp(sval,"ORDERING") ) {
1525 if ( seen_ordering ) {
1526 *code = LDAP_SCHERR_DUPOPT;
1528 ldap_attributetype_free(at);
1532 at->at_ordering_oid = parse_woid(&ss,code);
1533 if ( !at->at_ordering_oid ) {
1535 ldap_attributetype_free(at);
1538 } else if ( !strcmp(sval,"SUBSTR") ) {
1540 if ( seen_substr ) {
1541 *code = LDAP_SCHERR_DUPOPT;
1543 ldap_attributetype_free(at);
1547 at->at_substr_oid = parse_woid(&ss,code);
1548 if ( !at->at_substr_oid ) {
1550 ldap_attributetype_free(at);
1553 } else if ( !strcmp(sval,"SYNTAX") ) {
1555 if ( seen_syntax ) {
1556 *code = LDAP_SCHERR_DUPOPT;
1558 ldap_attributetype_free(at);
1568 if ( !at->at_syntax_oid ) {
1570 ldap_attributetype_free(at);
1574 } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
1576 if ( at->at_single_value ) {
1577 *code = LDAP_SCHERR_DUPOPT;
1579 ldap_attributetype_free(at);
1582 at->at_single_value = LDAP_SCHEMA_YES;
1584 } else if ( !strcmp(sval,"COLLECTIVE") ) {
1586 if ( at->at_collective ) {
1587 *code = LDAP_SCHERR_DUPOPT;
1589 ldap_attributetype_free(at);
1592 at->at_collective = LDAP_SCHEMA_YES;
1594 } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
1596 if ( at->at_no_user_mod ) {
1597 *code = LDAP_SCHERR_DUPOPT;
1599 ldap_attributetype_free(at);
1602 at->at_no_user_mod = LDAP_SCHEMA_YES;
1604 } else if ( !strcmp(sval,"USAGE") ) {
1607 *code = LDAP_SCHERR_DUPOPT;
1609 ldap_attributetype_free(at);
1614 kind = get_token(&ss,&sval);
1615 if ( kind != TK_BAREWORD ) {
1616 *code = LDAP_SCHERR_UNEXPTOKEN;
1619 ldap_attributetype_free(at);
1622 if ( !strcasecmp(sval,"userApplications") )
1624 LDAP_SCHEMA_USER_APPLICATIONS;
1625 else if ( !strcasecmp(sval,"directoryOperation") )
1627 LDAP_SCHEMA_DIRECTORY_OPERATION;
1628 else if ( !strcasecmp(sval,"distributedOperation") )
1630 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
1631 else if ( !strcasecmp(sval,"dSAOperation") )
1633 LDAP_SCHEMA_DSA_OPERATION;
1635 *code = LDAP_SCHERR_UNEXPTOKEN;
1638 ldap_attributetype_free(at);
1643 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1644 /* Should be parse_qdstrings */
1645 ext_vals = parse_qdescrs(&ss, code);
1648 ldap_attributetype_free(at);
1651 if ( add_extension(&at->at_extensions,
1653 *code = LDAP_SCHERR_OUTOFMEM;
1656 ldap_attributetype_free(at);
1660 *code = LDAP_SCHERR_UNEXPTOKEN;
1663 ldap_attributetype_free(at);
1668 *code = LDAP_SCHERR_UNEXPTOKEN;
1671 ldap_attributetype_free(at);
1678 ldap_objectclass_free(LDAP_OBJECT_CLASS * oc)
1680 LDAP_FREE(oc->oc_oid);
1681 LDAP_VFREE(oc->oc_names);
1682 LDAP_FREE(oc->oc_desc);
1683 LDAP_VFREE(oc->oc_sup_oids);
1684 LDAP_VFREE(oc->oc_at_oids_must);
1685 LDAP_VFREE(oc->oc_at_oids_may);
1686 free_extensions(oc->oc_extensions);
1691 ldap_str2objectclass( const char * s, int * code, const char ** errp )
1694 const char * ss = s;
1696 int be_liberal = 1; /* Future additional argument */
1699 int seen_obsolete = 0;
1704 LDAP_OBJECT_CLASS * oc;
1706 const char * savepos;
1709 *code = LDAP_SCHERR_EMPTY;
1715 oc = LDAP_CALLOC(1,sizeof(LDAP_OBJECT_CLASS));
1718 *code = LDAP_SCHERR_OUTOFMEM;
1722 kind = get_token(&ss,&sval);
1723 if ( kind != TK_LEFTPAREN ) {
1724 *code = LDAP_SCHERR_NOLEFTPAREN;
1726 ldap_objectclass_free(oc);
1731 * Definitions MUST begin with an OID in the numericoid format.
1732 * However, this routine is used by clients to parse the response
1733 * from servers and very well known servers will provide an OID
1734 * in the wrong format or even no OID at all. We do our best to
1735 * extract info from those servers.
1739 oc->oc_oid = parse_numericoid(&ss,code,0);
1740 if ( !oc->oc_oid ) {
1744 kind = get_token(&ss,&sval);
1745 if ( kind == TK_BAREWORD ) {
1746 if ( !strcmp(sval, "NAME") ||
1747 !strcmp(sval, "DESC") ||
1748 !strcmp(sval, "OBSOLETE") ||
1749 !strcmp(sval, "SUP") ||
1750 !strcmp(sval, "ABSTRACT") ||
1751 !strcmp(sval, "STRUCTURAL") ||
1752 !strcmp(sval, "AUXILIARY") ||
1753 !strcmp(sval, "MUST") ||
1754 !strncmp(sval, "X-", 2) ) {
1755 /* Missing OID, backtrack */
1758 /* Non-numerical OID, ignore */
1764 ldap_objectclass_free(oc);
1771 * Beyond this point we will be liberal an accept the items
1775 kind = get_token(&ss,&sval);
1778 *code = LDAP_SCHERR_NORIGHTPAREN;
1780 ldap_objectclass_free(oc);
1785 if ( !strcmp(sval,"NAME") ) {
1788 *code = LDAP_SCHERR_DUPOPT;
1790 ldap_objectclass_free(oc);
1794 oc->oc_names = parse_qdescrs(&ss,code);
1795 if ( !oc->oc_names ) {
1796 if ( *code != LDAP_SCHERR_OUTOFMEM )
1797 *code = LDAP_SCHERR_BADNAME;
1799 ldap_objectclass_free(oc);
1802 } else if ( !strcmp(sval,"DESC") ) {
1805 *code = LDAP_SCHERR_DUPOPT;
1807 ldap_objectclass_free(oc);
1812 kind = get_token(&ss,&sval);
1813 if ( kind != TK_QDSTRING ) {
1814 *code = LDAP_SCHERR_UNEXPTOKEN;
1817 ldap_objectclass_free(oc);
1822 } else if ( !strcmp(sval,"OBSOLETE") ) {
1824 if ( seen_obsolete ) {
1825 *code = LDAP_SCHERR_DUPOPT;
1827 ldap_objectclass_free(oc);
1831 oc->oc_obsolete = LDAP_SCHEMA_YES;
1833 } else if ( !strcmp(sval,"SUP") ) {
1836 *code = LDAP_SCHERR_DUPOPT;
1838 ldap_objectclass_free(oc);
1842 oc->oc_sup_oids = parse_oids(&ss,
1845 if ( !oc->oc_sup_oids ) {
1847 ldap_objectclass_free(oc);
1850 } else if ( !strcmp(sval,"ABSTRACT") ) {
1853 *code = LDAP_SCHERR_DUPOPT;
1855 ldap_objectclass_free(oc);
1859 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
1861 } else if ( !strcmp(sval,"STRUCTURAL") ) {
1864 *code = LDAP_SCHERR_DUPOPT;
1866 ldap_objectclass_free(oc);
1870 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
1872 } else if ( !strcmp(sval,"AUXILIARY") ) {
1875 *code = LDAP_SCHERR_DUPOPT;
1877 ldap_objectclass_free(oc);
1881 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
1883 } else if ( !strcmp(sval,"MUST") ) {
1886 *code = LDAP_SCHERR_DUPOPT;
1888 ldap_objectclass_free(oc);
1892 oc->oc_at_oids_must = parse_oids(&ss,code,0);
1893 if ( !oc->oc_at_oids_must ) {
1895 ldap_objectclass_free(oc);
1899 } else if ( !strcmp(sval,"MAY") ) {
1902 *code = LDAP_SCHERR_DUPOPT;
1904 ldap_objectclass_free(oc);
1908 oc->oc_at_oids_may = parse_oids(&ss,code,0);
1909 if ( !oc->oc_at_oids_may ) {
1911 ldap_objectclass_free(oc);
1915 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1916 /* Should be parse_qdstrings */
1917 ext_vals = parse_qdescrs(&ss, code);
1920 ldap_objectclass_free(oc);
1923 if ( add_extension(&oc->oc_extensions,
1925 *code = LDAP_SCHERR_OUTOFMEM;
1928 ldap_objectclass_free(oc);
1932 *code = LDAP_SCHERR_UNEXPTOKEN;
1935 ldap_objectclass_free(oc);
1940 *code = LDAP_SCHERR_UNEXPTOKEN;
1943 ldap_objectclass_free(oc);
1949 static char *const err2text[] = {
1953 "Missing opening parenthesis",
1954 "Missing closing parenthesis",
1960 "Unexpected end of data"
1964 ldap_scherr2str(int code)
1966 if ( code < 1 || code >= (sizeof(err2text)/sizeof(char *)) ) {
1967 return "Unknown error";
1969 return err2text[code];