3 * Copyright 1999-2000 The OpenLDAP Foundation, All Rights Reserved.
4 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
7 * schema.c: parsing routines used by servers and clients to process
14 #include <ac/stdlib.h>
16 #include <ac/string.h>
21 #include <ldap_schema.h>
23 static LDAP_CONST char *
24 choose_name( char *names[], LDAP_CONST char *fallback )
26 return( (names != NULL && names[0] != NULL) ? names[0] : fallback );
30 ldap_syntax2name( LDAP_SYNTAX * syn )
32 return( syn->syn_oid );
36 ldap_matchingrule2name( LDAP_MATCHING_RULE * mr )
38 return( choose_name( mr->mr_names, mr->mr_oid ) );
42 ldap_attributetype2name( LDAP_ATTRIBUTE_TYPE * at )
44 return( choose_name( at->at_names, at->at_oid ) );
48 ldap_objectclass2name( LDAP_OBJECT_CLASS * oc )
50 return( choose_name( oc->oc_names, oc->oc_oid ) );
55 * When pretty printing the entities we will be appending to a buffer.
56 * Since checking for overflow, realloc'ing and checking if no error
57 * is extremely boring, we will use a protection layer that will let
58 * us blissfully ignore the error until the end. This layer is
59 * implemented with the help of the next type.
62 typedef struct safe_string {
70 new_safe_string(int size)
74 ss = LDAP_MALLOC(sizeof(safe_string));
78 ss->val = LDAP_MALLOC(size);
92 safe_string_free(safe_string * ss)
101 safe_string_val(safe_string * ss)
103 ss->val[ss->pos] = '\0';
108 append_to_safe_string(safe_string * ss, char * s)
114 * Some runaway process is trying to append to a string that
115 * overflowed and we could not extend.
120 /* We always make sure there is at least one position available */
121 if ( ss->pos + l >= ss->size-1 ) {
123 temp = LDAP_REALLOC(ss->val, ss->size);
125 /* Trouble, out of memory */
131 strncpy(&ss->val[ss->pos], s, l);
133 if ( ss->pos > 0 && LDAP_SPACE(ss->val[ss->pos-1]) )
142 print_literal(safe_string *ss, char *s)
144 return(append_to_safe_string(ss,s));
148 print_whsp(safe_string *ss)
151 return(append_to_safe_string(ss,""));
153 return(append_to_safe_string(ss," "));
157 print_numericoid(safe_string *ss, char *s)
160 return(append_to_safe_string(ss,s));
162 return(append_to_safe_string(ss,""));
165 /* This one is identical to print_qdescr */
167 print_qdstring(safe_string *ss, char *s)
170 print_literal(ss,"'");
171 append_to_safe_string(ss,s);
172 print_literal(ss,"'");
173 return(print_whsp(ss));
177 print_qdescr(safe_string *ss, char *s)
180 print_literal(ss,"'");
181 append_to_safe_string(ss,s);
182 print_literal(ss,"'");
183 return(print_whsp(ss));
187 print_qdescrlist(safe_string *ss, char **sa)
192 for (sp=sa; *sp; sp++) {
193 ret = print_qdescr(ss,*sp);
195 /* If the list was empty, we return zero that is potentially
196 * incorrect, but since we will be still appending things, the
197 * overflow will be detected later. Maybe FIX.
203 print_qdescrs(safe_string *ss, char **sa)
205 /* The only way to represent an empty list is as a qdescrlist
206 * so, if the list is empty we treat it as a long list.
207 * Really, this is what the syntax mandates. We should not
208 * be here if the list was empty, but if it happens, a label
209 * has already been output and we cannot undo it.
211 if ( !sa[0] || ( sa[0] && sa[1] ) ) {
213 print_literal(ss,"("/*)*/);
214 print_qdescrlist(ss,sa);
215 print_literal(ss,/*(*/")");
216 return(print_whsp(ss));
218 return(print_qdescr(ss,*sa));
223 print_woid(safe_string *ss, char *s)
226 append_to_safe_string(ss,s);
227 return print_whsp(ss);
231 print_oidlist(safe_string *ss, char **sa)
235 for (sp=sa; *(sp+1); sp++) {
237 print_literal(ss,"$");
239 return(print_woid(ss,*sp));
243 print_oids(safe_string *ss, char **sa)
245 if ( sa[0] && sa[1] ) {
246 print_literal(ss,"("/*)*/);
247 print_oidlist(ss,sa);
249 return(print_literal(ss,/*(*/")"));
251 return(print_woid(ss,*sa));
256 print_noidlen(safe_string *ss, char *s, int l)
261 ret = print_numericoid(ss,s);
263 sprintf(buf,"{%d}",l);
264 ret = print_literal(ss,buf);
270 print_extensions(safe_string *ss, LDAP_SCHEMA_EXTENSION_ITEM **extensions)
272 LDAP_SCHEMA_EXTENSION_ITEM **ext;
276 for ( ext = extensions; *ext != NULL; ext++ ) {
277 print_literal(ss, (*ext)->lsei_name);
279 /* Should be print_qdstrings */
280 print_qdescrs(ss, (*ext)->lsei_values);
289 ldap_syntax2str( const LDAP_SYNTAX * syn )
294 ss = new_safe_string(256);
298 print_literal(ss,"("/*)*/);
301 print_numericoid(ss, syn->syn_oid);
304 if ( syn->syn_desc ) {
305 print_literal(ss,"DESC");
306 print_qdstring(ss,syn->syn_desc);
311 print_extensions(ss, syn->syn_extensions);
313 print_literal(ss,/*(*/ ")");
315 retstring = LDAP_STRDUP(safe_string_val(ss));
316 safe_string_free(ss);
321 ldap_matchingrule2str( const LDAP_MATCHING_RULE * mr )
326 ss = new_safe_string(256);
330 print_literal(ss,"(" /*)*/);
333 print_numericoid(ss, mr->mr_oid);
336 if ( mr->mr_names ) {
337 print_literal(ss,"NAME");
338 print_qdescrs(ss,mr->mr_names);
342 print_literal(ss,"DESC");
343 print_qdstring(ss,mr->mr_desc);
346 if ( mr->mr_obsolete == LDAP_SCHEMA_YES ) {
347 print_literal(ss, "OBSOLETE");
351 if ( mr->mr_syntax_oid ) {
352 print_literal(ss,"SYNTAX");
354 print_literal(ss, mr->mr_syntax_oid);
360 print_extensions(ss, mr->mr_extensions);
362 print_literal(ss,/*(*/")");
364 retstring = LDAP_STRDUP(safe_string_val(ss));
365 safe_string_free(ss);
370 ldap_objectclass2str( const LDAP_OBJECT_CLASS * oc )
375 ss = new_safe_string(256);
379 print_literal(ss,"("/*)*/);
382 print_numericoid(ss, oc->oc_oid);
385 if ( oc->oc_names ) {
386 print_literal(ss,"NAME");
387 print_qdescrs(ss,oc->oc_names);
391 print_literal(ss,"DESC");
392 print_qdstring(ss,oc->oc_desc);
395 if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) {
396 print_literal(ss, "OBSOLETE");
400 if ( oc->oc_sup_oids ) {
401 print_literal(ss,"SUP");
403 print_oids(ss,oc->oc_sup_oids);
407 switch (oc->oc_kind) {
408 case LDAP_SCHEMA_ABSTRACT:
409 print_literal(ss,"ABSTRACT");
411 case LDAP_SCHEMA_STRUCTURAL:
412 print_literal(ss,"STRUCTURAL");
414 case LDAP_SCHEMA_AUXILIARY:
415 print_literal(ss,"AUXILIARY");
418 print_literal(ss,"KIND-UNKNOWN");
423 if ( oc->oc_at_oids_must ) {
424 print_literal(ss,"MUST");
426 print_oids(ss,oc->oc_at_oids_must);
430 if ( oc->oc_at_oids_may ) {
431 print_literal(ss,"MAY");
433 print_oids(ss,oc->oc_at_oids_may);
439 print_extensions(ss, oc->oc_extensions);
441 print_literal(ss, /*(*/")");
443 retstring = LDAP_STRDUP(safe_string_val(ss));
444 safe_string_free(ss);
449 ldap_attributetype2str( const LDAP_ATTRIBUTE_TYPE * at )
454 ss = new_safe_string(256);
458 print_literal(ss,"("/*)*/);
461 print_numericoid(ss, at->at_oid);
464 if ( at->at_names ) {
465 print_literal(ss,"NAME");
466 print_qdescrs(ss,at->at_names);
470 print_literal(ss,"DESC");
471 print_qdstring(ss,at->at_desc);
474 if ( at->at_obsolete == LDAP_SCHEMA_YES ) {
475 print_literal(ss, "OBSOLETE");
479 if ( at->at_sup_oid ) {
480 print_literal(ss,"SUP");
481 print_woid(ss,at->at_sup_oid);
484 if ( at->at_equality_oid ) {
485 print_literal(ss,"EQUALITY");
486 print_woid(ss,at->at_equality_oid);
489 if ( at->at_ordering_oid ) {
490 print_literal(ss,"ORDERING");
491 print_woid(ss,at->at_ordering_oid);
494 if ( at->at_substr_oid ) {
495 print_literal(ss,"SUBSTR");
496 print_woid(ss,at->at_substr_oid);
499 if ( at->at_syntax_oid ) {
500 print_literal(ss,"SYNTAX");
502 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
506 if ( at->at_single_value == LDAP_SCHEMA_YES ) {
507 print_literal(ss,"SINGLE-VALUE");
511 if ( at->at_collective == LDAP_SCHEMA_YES ) {
512 print_literal(ss,"COLLECTIVE");
516 if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
517 print_literal(ss,"NO-USER-MODIFICATION");
521 if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
522 print_literal(ss,"USAGE");
524 switch (at->at_usage) {
525 case LDAP_SCHEMA_DIRECTORY_OPERATION:
526 print_literal(ss,"directoryOperation");
528 case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
529 print_literal(ss,"distributedOperation");
531 case LDAP_SCHEMA_DSA_OPERATION:
532 print_literal(ss,"dSAOperation");
535 print_literal(ss,"UNKNOWN");
542 print_extensions(ss, at->at_extensions);
544 print_literal(ss,/*(*/")");
546 retstring = LDAP_STRDUP(safe_string_val(ss));
547 safe_string_free(ss);
552 * Now come the parsers. There is one parser for each entity type:
553 * objectclasses, attributetypes, etc.
555 * Each of them is written as a recursive-descent parser, except that
556 * none of them is really recursive. But the idea is kept: there
557 * is one routine per non-terminal that eithers gobbles lexical tokens
558 * or calls lower-level routines, etc.
560 * The scanner is implemented in the routine get_token. Actually,
561 * get_token is more than a scanner and will return tokens that are
562 * in fact non-terminals in the grammar. So you can see the whole
563 * approach as the combination of a low-level bottom-up recognizer
564 * combined with a scanner and a number of top-down parsers. Or just
565 * consider that the real grammars recognized by the parsers are not
566 * those of the standards. As a matter of fact, our parsers are more
567 * liberal than the spec when there is no ambiguity.
569 * The difference is pretty academic (modulo bugs or incorrect
570 * interpretation of the specs).
573 #define TK_NOENDQUOTE -2
574 #define TK_OUTOFMEM -1
576 #define TK_UNEXPCHAR 1
577 #define TK_BAREWORD 2
578 #define TK_QDSTRING 3
579 #define TK_LEFTPAREN 4
580 #define TK_RIGHTPAREN 5
582 #define TK_QDESCR TK_QDSTRING
590 get_token(const char ** sp, char ** token_val)
608 kind = TK_RIGHTPAREN;
619 while ( **sp != '\'' && **sp != '\0' )
621 if ( **sp == '\'' ) {
623 res = LDAP_MALLOC(q-p+1);
633 kind = TK_NOENDQUOTE;
639 while ( !LDAP_SPACE(**sp) &&
647 res = LDAP_MALLOC(q-p+1);
656 /* kind = TK_UNEXPCHAR; */
663 /* Gobble optional whitespace */
665 parse_whsp(const char **sp)
667 while (LDAP_SPACE(**sp))
672 * General note for all parsers: to guarantee the algorithm halts they
673 * must always advance the pointer even when an error is found. For
674 * this one is not that important since an error here is fatal at the
675 * upper layers, but it is a simple strategy that will not get in
679 /* Parse a sequence of dot-separated decimal strings */
681 parse_numericoid(const char **sp, int *code, const int flags)
684 const char * start = *sp;
688 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
689 if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && **sp == '\'' ) {
694 /* Each iteration of this loop gets one decimal string */
696 if ( !LDAP_DIGIT(**sp) ) {
698 * Initial char is not a digit or char after dot is
701 *code = LDAP_SCHERR_NODIGIT;
705 while ( LDAP_DIGIT(**sp) )
709 /* Otherwise, gobble the dot and loop again */
712 /* Now *sp points at the char past the numericoid. Perfect. */
714 res = LDAP_MALLOC(len+1);
716 *code = LDAP_SCHERR_OUTOFMEM;
719 strncpy(res,start,len);
721 if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && quoted ) {
722 if ( **sp == '\'' ) {
725 *code = LDAP_SCHERR_UNEXPTOKEN;
733 /* Parse a qdescr or a list of them enclosed in () */
735 parse_qdescrs(const char **sp, int *code)
745 kind = get_token(sp,&sval);
746 if ( kind == TK_LEFTPAREN ) {
747 /* Let's presume there will be at least 2 entries */
749 res = LDAP_CALLOC(3,sizeof(char *));
751 *code = LDAP_SCHERR_OUTOFMEM;
757 kind = get_token(sp,&sval);
758 if ( kind == TK_RIGHTPAREN )
760 if ( kind == TK_QDESCR ) {
761 if ( pos == size-2 ) {
763 res1 = LDAP_REALLOC(res,size*sizeof(char *));
767 *code = LDAP_SCHERR_OUTOFMEM;
778 *code = LDAP_SCHERR_UNEXPTOKEN;
785 } else if ( kind == TK_QDESCR ) {
786 res = LDAP_CALLOC(2,sizeof(char *));
788 *code = LDAP_SCHERR_OUTOFMEM;
797 *code = LDAP_SCHERR_BADNAME;
804 parse_woid(const char **sp, int *code)
810 kind = get_token(sp, &sval);
811 if ( kind != TK_BAREWORD ) {
813 *code = LDAP_SCHERR_UNEXPTOKEN;
820 /* Parse a noidlen */
822 parse_noidlen(const char **sp, int *code, int *len, int allow_quoted)
828 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
829 if ( allow_quoted && **sp == '\'' ) {
833 sval = parse_numericoid(sp, code, 0);
837 if ( **sp == '{' /*}*/ ) {
840 while ( LDAP_DIGIT(**sp) )
842 if ( **sp != /*{*/ '}' ) {
843 *code = LDAP_SCHERR_UNEXPTOKEN;
849 if ( allow_quoted && quoted ) {
850 if ( **sp == '\'' ) {
853 *code = LDAP_SCHERR_UNEXPTOKEN;
862 * Next routine will accept a qdstring in place of an oid if
863 * allow_quoted is set. This is necessary to interoperate with
864 * Netscape Directory server that will improperly quote each oid (at
865 * least those of the descr kind) in the SUP clause.
868 /* Parse a woid or a $-separated list of them enclosed in () */
870 parse_oids(const char **sp, int *code, const int allow_quoted)
880 * Strictly speaking, doing this here accepts whsp before the
881 * ( at the begining of an oidlist, but this is harmless. Also,
882 * we are very liberal in what we accept as an OID. Maybe
886 kind = get_token(sp,&sval);
887 if ( kind == TK_LEFTPAREN ) {
888 /* Let's presume there will be at least 2 entries */
890 res = LDAP_CALLOC(3,sizeof(char *));
892 *code = LDAP_SCHERR_OUTOFMEM;
897 kind = get_token(sp,&sval);
898 if ( kind == TK_BAREWORD ||
899 ( allow_quoted && kind == TK_QDSTRING ) ) {
903 *code = LDAP_SCHERR_UNEXPTOKEN;
910 kind = get_token(sp,&sval);
911 if ( kind == TK_RIGHTPAREN )
913 if ( kind == TK_DOLLAR ) {
915 kind = get_token(sp,&sval);
916 if ( kind == TK_BAREWORD ||
918 kind == TK_QDSTRING ) ) {
919 if ( pos == size-2 ) {
921 res1 = LDAP_REALLOC(res,size*sizeof(char *));
925 *code = LDAP_SCHERR_OUTOFMEM;
933 *code = LDAP_SCHERR_UNEXPTOKEN;
940 *code = LDAP_SCHERR_UNEXPTOKEN;
949 } else if ( kind == TK_BAREWORD ||
950 ( allow_quoted && kind == TK_QDSTRING ) ) {
951 res = LDAP_CALLOC(2,sizeof(char *));
954 *code = LDAP_SCHERR_OUTOFMEM;
963 *code = LDAP_SCHERR_BADNAME;
969 add_extension(LDAP_SCHEMA_EXTENSION_ITEM ***extensions,
970 char * name, char ** values)
973 LDAP_SCHEMA_EXTENSION_ITEM **tmp, *ext;
975 ext = LDAP_CALLOC(1, sizeof(LDAP_SCHEMA_EXTENSION_ITEM));
978 ext->lsei_name = name;
979 ext->lsei_values = values;
981 if ( !*extensions ) {
983 LDAP_CALLOC(2, sizeof(LDAP_SCHEMA_EXTENSION_ITEM *));
988 for ( n=0; (*extensions)[n] != NULL; n++ )
990 tmp = LDAP_REALLOC(*extensions,
991 (n+2)*sizeof(LDAP_SCHEMA_EXTENSION_ITEM *));
996 (*extensions)[n] = ext;
997 (*extensions)[n+1] = NULL;
1002 free_extensions(LDAP_SCHEMA_EXTENSION_ITEM **extensions)
1004 LDAP_SCHEMA_EXTENSION_ITEM **ext;
1007 for ( ext = extensions; *ext != NULL; ext++ ) {
1008 LDAP_FREE((*ext)->lsei_name);
1009 LDAP_VFREE((*ext)->lsei_values);
1012 LDAP_FREE(extensions);
1017 ldap_syntax_free( LDAP_SYNTAX * syn )
1019 LDAP_FREE(syn->syn_oid);
1020 LDAP_FREE(syn->syn_desc);
1021 free_extensions(syn->syn_extensions);
1026 ldap_str2syntax( const char * s, int * code, const char ** errp, const int flags )
1029 const char * ss = s;
1037 *code = LDAP_SCHERR_EMPTY;
1043 syn = LDAP_CALLOC(1,sizeof(LDAP_SYNTAX));
1046 *code = LDAP_SCHERR_OUTOFMEM;
1050 kind = get_token(&ss,&sval);
1051 if ( kind != TK_LEFTPAREN ) {
1053 *code = LDAP_SCHERR_NOLEFTPAREN;
1054 ldap_syntax_free(syn);
1059 syn->syn_oid = parse_numericoid(&ss,code,0);
1060 if ( !syn->syn_oid ) {
1062 ldap_syntax_free(syn);
1068 * Beyond this point we will be liberal and accept the items
1072 kind = get_token(&ss,&sval);
1075 *code = LDAP_SCHERR_NORIGHTPAREN;
1077 ldap_syntax_free(syn);
1082 if ( !strcmp(sval,"NAME") ) {
1085 *code = LDAP_SCHERR_DUPOPT;
1087 ldap_syntax_free(syn);
1091 syn->syn_names = parse_qdescrs(&ss,code);
1092 if ( !syn->syn_names ) {
1093 if ( *code != LDAP_SCHERR_OUTOFMEM )
1094 *code = LDAP_SCHERR_BADNAME;
1096 ldap_syntax_free(syn);
1099 } else if ( !strcmp(sval,"DESC") ) {
1102 *code = LDAP_SCHERR_DUPOPT;
1104 ldap_syntax_free(syn);
1109 kind = get_token(&ss,&sval);
1110 if ( kind != TK_QDSTRING ) {
1111 *code = LDAP_SCHERR_UNEXPTOKEN;
1114 ldap_syntax_free(syn);
1117 syn->syn_desc = sval;
1119 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1120 /* Should be parse_qdstrings */
1121 ext_vals = parse_qdescrs(&ss, code);
1124 ldap_syntax_free(syn);
1127 if ( add_extension(&syn->syn_extensions,
1129 *code = LDAP_SCHERR_OUTOFMEM;
1132 ldap_syntax_free(syn);
1136 *code = LDAP_SCHERR_UNEXPTOKEN;
1139 ldap_syntax_free(syn);
1144 *code = LDAP_SCHERR_UNEXPTOKEN;
1147 ldap_syntax_free(syn);
1154 ldap_matchingrule_free( LDAP_MATCHING_RULE * mr )
1156 LDAP_FREE(mr->mr_oid);
1157 LDAP_VFREE(mr->mr_names);
1158 LDAP_FREE(mr->mr_desc);
1159 LDAP_FREE(mr->mr_syntax_oid);
1160 free_extensions(mr->mr_extensions);
1164 LDAP_MATCHING_RULE *
1165 ldap_str2matchingrule( const char * s, int * code, const char ** errp, const int flags )
1168 const char * ss = s;
1172 int seen_obsolete = 0;
1173 int seen_syntax = 0;
1174 LDAP_MATCHING_RULE * mr;
1176 const char * savepos;
1179 *code = LDAP_SCHERR_EMPTY;
1185 mr = LDAP_CALLOC(1,sizeof(LDAP_MATCHING_RULE));
1188 *code = LDAP_SCHERR_OUTOFMEM;
1192 kind = get_token(&ss,&sval);
1193 if ( kind != TK_LEFTPAREN ) {
1194 *code = LDAP_SCHERR_NOLEFTPAREN;
1196 ldap_matchingrule_free(mr);
1202 mr->mr_oid = parse_numericoid(&ss,code,flags);
1203 if ( !mr->mr_oid ) {
1204 if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
1207 kind = get_token(&ss,&sval);
1208 if ( kind == TK_BAREWORD ) {
1209 if ( !strcmp(sval, "NAME") ||
1210 !strcmp(sval, "DESC") ||
1211 !strcmp(sval, "OBSOLETE") ||
1212 !strcmp(sval, "SYNTAX") ||
1213 !strncmp(sval, "X-", 2) ) {
1214 /* Missing OID, backtrack */
1217 /* Non-numerical OID, ignore */
1223 ldap_matchingrule_free(mr);
1230 * Beyond this point we will be liberal and accept the items
1234 kind = get_token(&ss,&sval);
1237 *code = LDAP_SCHERR_NORIGHTPAREN;
1239 ldap_matchingrule_free(mr);
1244 if ( !strcmp(sval,"NAME") ) {
1247 *code = LDAP_SCHERR_DUPOPT;
1249 ldap_matchingrule_free(mr);
1253 mr->mr_names = parse_qdescrs(&ss,code);
1254 if ( !mr->mr_names ) {
1255 if ( *code != LDAP_SCHERR_OUTOFMEM )
1256 *code = LDAP_SCHERR_BADNAME;
1258 ldap_matchingrule_free(mr);
1261 } else if ( !strcmp(sval,"DESC") ) {
1264 *code = LDAP_SCHERR_DUPOPT;
1266 ldap_matchingrule_free(mr);
1271 kind = get_token(&ss,&sval);
1272 if ( kind != TK_QDSTRING ) {
1273 *code = LDAP_SCHERR_UNEXPTOKEN;
1276 ldap_matchingrule_free(mr);
1281 } else if ( !strcmp(sval,"OBSOLETE") ) {
1283 if ( seen_obsolete ) {
1284 *code = LDAP_SCHERR_DUPOPT;
1286 ldap_matchingrule_free(mr);
1290 mr->mr_obsolete = LDAP_SCHEMA_YES;
1292 } else if ( !strcmp(sval,"SYNTAX") ) {
1294 if ( seen_syntax ) {
1295 *code = LDAP_SCHERR_DUPOPT;
1297 ldap_matchingrule_free(mr);
1303 parse_numericoid(&ss,code,flags);
1304 if ( !mr->mr_syntax_oid ) {
1306 ldap_matchingrule_free(mr);
1310 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1311 /* Should be parse_qdstrings */
1312 ext_vals = parse_qdescrs(&ss, code);
1315 ldap_matchingrule_free(mr);
1318 if ( add_extension(&mr->mr_extensions,
1320 *code = LDAP_SCHERR_OUTOFMEM;
1323 ldap_matchingrule_free(mr);
1327 *code = LDAP_SCHERR_UNEXPTOKEN;
1330 ldap_matchingrule_free(mr);
1335 *code = LDAP_SCHERR_UNEXPTOKEN;
1338 ldap_matchingrule_free(mr);
1345 ldap_attributetype_free(LDAP_ATTRIBUTE_TYPE * at)
1347 LDAP_FREE(at->at_oid);
1348 LDAP_VFREE(at->at_names);
1349 LDAP_FREE(at->at_desc);
1350 LDAP_FREE(at->at_sup_oid);
1351 LDAP_FREE(at->at_equality_oid);
1352 LDAP_FREE(at->at_ordering_oid);
1353 LDAP_FREE(at->at_substr_oid);
1354 LDAP_FREE(at->at_syntax_oid);
1355 free_extensions(at->at_extensions);
1359 LDAP_ATTRIBUTE_TYPE *
1360 ldap_str2attributetype( const char * s, int * code, const char ** errp, const int flags )
1363 const char * ss = s;
1367 int seen_obsolete = 0;
1369 int seen_equality = 0;
1370 int seen_ordering = 0;
1371 int seen_substr = 0;
1372 int seen_syntax = 0;
1374 LDAP_ATTRIBUTE_TYPE * at;
1376 const char * savepos;
1379 *code = LDAP_SCHERR_EMPTY;
1385 at = LDAP_CALLOC(1,sizeof(LDAP_ATTRIBUTE_TYPE));
1388 *code = LDAP_SCHERR_OUTOFMEM;
1392 kind = get_token(&ss,&sval);
1393 if ( kind != TK_LEFTPAREN ) {
1394 *code = LDAP_SCHERR_NOLEFTPAREN;
1396 ldap_attributetype_free(at);
1401 * Definitions MUST begin with an OID in the numericoid format.
1402 * However, this routine is used by clients to parse the response
1403 * from servers and very well known servers will provide an OID
1404 * in the wrong format or even no OID at all. We do our best to
1405 * extract info from those servers.
1409 at->at_oid = parse_numericoid(&ss,code,0);
1410 if ( !at->at_oid ) {
1411 if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
1414 kind = get_token(&ss,&sval);
1415 if ( kind == TK_BAREWORD ) {
1416 if ( !strcmp(sval, "NAME") ||
1417 !strcmp(sval, "DESC") ||
1418 !strcmp(sval, "OBSOLETE") ||
1419 !strcmp(sval, "SUP") ||
1420 !strcmp(sval, "EQUALITY") ||
1421 !strcmp(sval, "ORDERING") ||
1422 !strcmp(sval, "SUBSTR") ||
1423 !strcmp(sval, "SYNTAX") ||
1424 !strcmp(sval, "SINGLE-VALUE") ||
1425 !strcmp(sval, "COLLECTIVE") ||
1426 !strcmp(sval, "NO-USER-MODIFICATION") ||
1427 !strcmp(sval, "USAGE") ||
1428 !strncmp(sval, "X-", 2) ) {
1429 /* Missing OID, backtrack */
1432 /* Non-numerical OID, ignore */
1438 ldap_attributetype_free(at);
1445 * Beyond this point we will be liberal and accept the items
1449 kind = get_token(&ss,&sval);
1452 *code = LDAP_SCHERR_NORIGHTPAREN;
1454 ldap_attributetype_free(at);
1459 if ( !strcmp(sval,"NAME") ) {
1462 *code = LDAP_SCHERR_DUPOPT;
1464 ldap_attributetype_free(at);
1468 at->at_names = parse_qdescrs(&ss,code);
1469 if ( !at->at_names ) {
1470 if ( *code != LDAP_SCHERR_OUTOFMEM )
1471 *code = LDAP_SCHERR_BADNAME;
1473 ldap_attributetype_free(at);
1476 } else if ( !strcmp(sval,"DESC") ) {
1479 *code = LDAP_SCHERR_DUPOPT;
1481 ldap_attributetype_free(at);
1486 kind = get_token(&ss,&sval);
1487 if ( kind != TK_QDSTRING ) {
1488 *code = LDAP_SCHERR_UNEXPTOKEN;
1491 ldap_attributetype_free(at);
1496 } else if ( !strcmp(sval,"OBSOLETE") ) {
1498 if ( seen_obsolete ) {
1499 *code = LDAP_SCHERR_DUPOPT;
1501 ldap_attributetype_free(at);
1505 at->at_obsolete = LDAP_SCHEMA_YES;
1507 } else if ( !strcmp(sval,"SUP") ) {
1510 *code = LDAP_SCHERR_DUPOPT;
1512 ldap_attributetype_free(at);
1516 at->at_sup_oid = parse_woid(&ss,code);
1517 if ( !at->at_sup_oid ) {
1519 ldap_attributetype_free(at);
1522 } else if ( !strcmp(sval,"EQUALITY") ) {
1524 if ( seen_equality ) {
1525 *code = LDAP_SCHERR_DUPOPT;
1527 ldap_attributetype_free(at);
1531 at->at_equality_oid = parse_woid(&ss,code);
1532 if ( !at->at_equality_oid ) {
1534 ldap_attributetype_free(at);
1537 } else if ( !strcmp(sval,"ORDERING") ) {
1539 if ( seen_ordering ) {
1540 *code = LDAP_SCHERR_DUPOPT;
1542 ldap_attributetype_free(at);
1546 at->at_ordering_oid = parse_woid(&ss,code);
1547 if ( !at->at_ordering_oid ) {
1549 ldap_attributetype_free(at);
1552 } else if ( !strcmp(sval,"SUBSTR") ) {
1554 if ( seen_substr ) {
1555 *code = LDAP_SCHERR_DUPOPT;
1557 ldap_attributetype_free(at);
1561 at->at_substr_oid = parse_woid(&ss,code);
1562 if ( !at->at_substr_oid ) {
1564 ldap_attributetype_free(at);
1567 } else if ( !strcmp(sval,"SYNTAX") ) {
1569 if ( seen_syntax ) {
1570 *code = LDAP_SCHERR_DUPOPT;
1572 ldap_attributetype_free(at);
1582 if ( !at->at_syntax_oid ) {
1584 ldap_attributetype_free(at);
1588 } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
1590 if ( at->at_single_value ) {
1591 *code = LDAP_SCHERR_DUPOPT;
1593 ldap_attributetype_free(at);
1596 at->at_single_value = LDAP_SCHEMA_YES;
1598 } else if ( !strcmp(sval,"COLLECTIVE") ) {
1600 if ( at->at_collective ) {
1601 *code = LDAP_SCHERR_DUPOPT;
1603 ldap_attributetype_free(at);
1606 at->at_collective = LDAP_SCHEMA_YES;
1608 } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
1610 if ( at->at_no_user_mod ) {
1611 *code = LDAP_SCHERR_DUPOPT;
1613 ldap_attributetype_free(at);
1616 at->at_no_user_mod = LDAP_SCHEMA_YES;
1618 } else if ( !strcmp(sval,"USAGE") ) {
1621 *code = LDAP_SCHERR_DUPOPT;
1623 ldap_attributetype_free(at);
1628 kind = get_token(&ss,&sval);
1629 if ( kind != TK_BAREWORD ) {
1630 *code = LDAP_SCHERR_UNEXPTOKEN;
1633 ldap_attributetype_free(at);
1636 if ( !strcasecmp(sval,"userApplications") )
1638 LDAP_SCHEMA_USER_APPLICATIONS;
1639 else if ( !strcasecmp(sval,"directoryOperation") )
1641 LDAP_SCHEMA_DIRECTORY_OPERATION;
1642 else if ( !strcasecmp(sval,"distributedOperation") )
1644 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
1645 else if ( !strcasecmp(sval,"dSAOperation") )
1647 LDAP_SCHEMA_DSA_OPERATION;
1649 *code = LDAP_SCHERR_UNEXPTOKEN;
1652 ldap_attributetype_free(at);
1657 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1658 /* Should be parse_qdstrings */
1659 ext_vals = parse_qdescrs(&ss, code);
1662 ldap_attributetype_free(at);
1665 if ( add_extension(&at->at_extensions,
1667 *code = LDAP_SCHERR_OUTOFMEM;
1670 ldap_attributetype_free(at);
1674 *code = LDAP_SCHERR_UNEXPTOKEN;
1677 ldap_attributetype_free(at);
1682 *code = LDAP_SCHERR_UNEXPTOKEN;
1685 ldap_attributetype_free(at);
1692 ldap_objectclass_free(LDAP_OBJECT_CLASS * oc)
1694 LDAP_FREE(oc->oc_oid);
1695 LDAP_VFREE(oc->oc_names);
1696 LDAP_FREE(oc->oc_desc);
1697 LDAP_VFREE(oc->oc_sup_oids);
1698 LDAP_VFREE(oc->oc_at_oids_must);
1699 LDAP_VFREE(oc->oc_at_oids_may);
1700 free_extensions(oc->oc_extensions);
1705 ldap_str2objectclass( const char * s, int * code, const char ** errp, const int flags )
1708 const char * ss = s;
1712 int seen_obsolete = 0;
1717 LDAP_OBJECT_CLASS * oc;
1719 const char * savepos;
1722 *code = LDAP_SCHERR_EMPTY;
1728 oc = LDAP_CALLOC(1,sizeof(LDAP_OBJECT_CLASS));
1731 *code = LDAP_SCHERR_OUTOFMEM;
1735 kind = get_token(&ss,&sval);
1736 if ( kind != TK_LEFTPAREN ) {
1737 *code = LDAP_SCHERR_NOLEFTPAREN;
1739 ldap_objectclass_free(oc);
1744 * Definitions MUST begin with an OID in the numericoid format.
1745 * However, this routine is used by clients to parse the response
1746 * from servers and very well known servers will provide an OID
1747 * in the wrong format or even no OID at all. We do our best to
1748 * extract info from those servers.
1752 oc->oc_oid = parse_numericoid(&ss,code,0);
1753 if ( !oc->oc_oid ) {
1754 if ( flags & LDAP_SCHEMA_ALLOW_ALL ) {
1757 kind = get_token(&ss,&sval);
1758 if ( kind == TK_BAREWORD ) {
1759 if ( !strcmp(sval, "NAME") ||
1760 !strcmp(sval, "DESC") ||
1761 !strcmp(sval, "OBSOLETE") ||
1762 !strcmp(sval, "SUP") ||
1763 !strcmp(sval, "ABSTRACT") ||
1764 !strcmp(sval, "STRUCTURAL") ||
1765 !strcmp(sval, "AUXILIARY") ||
1766 !strcmp(sval, "MUST") ||
1767 !strncmp(sval, "X-", 2) ) {
1768 /* Missing OID, backtrack */
1771 /* Non-numerical OID, ignore */
1777 ldap_objectclass_free(oc);
1784 * Beyond this point we will be liberal an accept the items
1788 kind = get_token(&ss,&sval);
1791 *code = LDAP_SCHERR_NORIGHTPAREN;
1793 ldap_objectclass_free(oc);
1798 if ( !strcmp(sval,"NAME") ) {
1801 *code = LDAP_SCHERR_DUPOPT;
1803 ldap_objectclass_free(oc);
1807 oc->oc_names = parse_qdescrs(&ss,code);
1808 if ( !oc->oc_names ) {
1809 if ( *code != LDAP_SCHERR_OUTOFMEM )
1810 *code = LDAP_SCHERR_BADNAME;
1812 ldap_objectclass_free(oc);
1815 } else if ( !strcmp(sval,"DESC") ) {
1818 *code = LDAP_SCHERR_DUPOPT;
1820 ldap_objectclass_free(oc);
1825 kind = get_token(&ss,&sval);
1826 if ( kind != TK_QDSTRING ) {
1827 *code = LDAP_SCHERR_UNEXPTOKEN;
1830 ldap_objectclass_free(oc);
1835 } else if ( !strcmp(sval,"OBSOLETE") ) {
1837 if ( seen_obsolete ) {
1838 *code = LDAP_SCHERR_DUPOPT;
1840 ldap_objectclass_free(oc);
1844 oc->oc_obsolete = LDAP_SCHEMA_YES;
1846 } else if ( !strcmp(sval,"SUP") ) {
1849 *code = LDAP_SCHERR_DUPOPT;
1851 ldap_objectclass_free(oc);
1855 oc->oc_sup_oids = parse_oids(&ss,
1858 if ( !oc->oc_sup_oids ) {
1860 ldap_objectclass_free(oc);
1863 } else if ( !strcmp(sval,"ABSTRACT") ) {
1866 *code = LDAP_SCHERR_DUPOPT;
1868 ldap_objectclass_free(oc);
1872 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
1874 } else if ( !strcmp(sval,"STRUCTURAL") ) {
1877 *code = LDAP_SCHERR_DUPOPT;
1879 ldap_objectclass_free(oc);
1883 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
1885 } else if ( !strcmp(sval,"AUXILIARY") ) {
1888 *code = LDAP_SCHERR_DUPOPT;
1890 ldap_objectclass_free(oc);
1894 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
1896 } else if ( !strcmp(sval,"MUST") ) {
1899 *code = LDAP_SCHERR_DUPOPT;
1901 ldap_objectclass_free(oc);
1905 oc->oc_at_oids_must = parse_oids(&ss,code,0);
1906 if ( !oc->oc_at_oids_must ) {
1908 ldap_objectclass_free(oc);
1912 } else if ( !strcmp(sval,"MAY") ) {
1915 *code = LDAP_SCHERR_DUPOPT;
1917 ldap_objectclass_free(oc);
1921 oc->oc_at_oids_may = parse_oids(&ss,code,0);
1922 if ( !oc->oc_at_oids_may ) {
1924 ldap_objectclass_free(oc);
1928 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1929 /* Should be parse_qdstrings */
1930 ext_vals = parse_qdescrs(&ss, code);
1933 ldap_objectclass_free(oc);
1936 if ( add_extension(&oc->oc_extensions,
1938 *code = LDAP_SCHERR_OUTOFMEM;
1941 ldap_objectclass_free(oc);
1945 *code = LDAP_SCHERR_UNEXPTOKEN;
1948 ldap_objectclass_free(oc);
1953 *code = LDAP_SCHERR_UNEXPTOKEN;
1956 ldap_objectclass_free(oc);
1962 static char *const err2text[] = {
1966 "Missing opening parenthesis",
1967 "Missing closing parenthesis",
1973 "Unexpected end of data"
1977 ldap_scherr2str(int code)
1979 if ( code < 0 || code >= (sizeof(err2text)/sizeof(char *)) ) {
1980 return "Unknown error";
1982 return err2text[code];