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 print_qdescrs(ss, (*ext)->lsei_values);
290 ldap_syntax2str( const LDAP_SYNTAX * syn )
295 ss = new_safe_string(256);
299 print_literal(ss,"("/*)*/);
302 print_numericoid(ss, syn->syn_oid);
305 if ( syn->syn_desc ) {
306 print_literal(ss,"DESC");
307 print_qdstring(ss,syn->syn_desc);
312 print_extensions(ss, syn->syn_extensions);
314 print_literal(ss,/*(*/ ")");
316 retstring = LDAP_STRDUP(safe_string_val(ss));
317 safe_string_free(ss);
322 ldap_matchingrule2str( const LDAP_MATCHING_RULE * mr )
327 ss = new_safe_string(256);
331 print_literal(ss,"(" /*)*/);
334 print_numericoid(ss, mr->mr_oid);
337 if ( mr->mr_names ) {
338 print_literal(ss,"NAME");
339 print_qdescrs(ss,mr->mr_names);
343 print_literal(ss,"DESC");
344 print_qdstring(ss,mr->mr_desc);
347 if ( mr->mr_obsolete == LDAP_SCHEMA_YES ) {
348 print_literal(ss, "OBSOLETE");
352 if ( mr->mr_syntax_oid ) {
353 print_literal(ss,"SYNTAX");
355 print_literal(ss, mr->mr_syntax_oid);
361 print_extensions(ss, mr->mr_extensions);
363 print_literal(ss,/*(*/")");
365 retstring = LDAP_STRDUP(safe_string_val(ss));
366 safe_string_free(ss);
371 ldap_objectclass2str( const LDAP_OBJECT_CLASS * oc )
376 ss = new_safe_string(256);
380 print_literal(ss,"("/*)*/);
383 print_numericoid(ss, oc->oc_oid);
386 if ( oc->oc_names ) {
387 print_literal(ss,"NAME");
388 print_qdescrs(ss,oc->oc_names);
392 print_literal(ss,"DESC");
393 print_qdstring(ss,oc->oc_desc);
396 if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) {
397 print_literal(ss, "OBSOLETE");
401 if ( oc->oc_sup_oids ) {
402 print_literal(ss,"SUP");
404 print_oids(ss,oc->oc_sup_oids);
408 switch (oc->oc_kind) {
409 case LDAP_SCHEMA_ABSTRACT:
410 print_literal(ss,"ABSTRACT");
412 case LDAP_SCHEMA_STRUCTURAL:
413 print_literal(ss,"STRUCTURAL");
415 case LDAP_SCHEMA_AUXILIARY:
416 print_literal(ss,"AUXILIARY");
419 print_literal(ss,"KIND-UNKNOWN");
424 if ( oc->oc_at_oids_must ) {
425 print_literal(ss,"MUST");
427 print_oids(ss,oc->oc_at_oids_must);
431 if ( oc->oc_at_oids_may ) {
432 print_literal(ss,"MAY");
434 print_oids(ss,oc->oc_at_oids_may);
440 print_extensions(ss, oc->oc_extensions);
442 print_literal(ss, /*(*/")");
444 retstring = LDAP_STRDUP(safe_string_val(ss));
445 safe_string_free(ss);
450 ldap_attributetype2str( const LDAP_ATTRIBUTE_TYPE * at )
455 ss = new_safe_string(256);
459 print_literal(ss,"("/*)*/);
462 print_numericoid(ss, at->at_oid);
465 if ( at->at_names ) {
466 print_literal(ss,"NAME");
467 print_qdescrs(ss,at->at_names);
471 print_literal(ss,"DESC");
472 print_qdstring(ss,at->at_desc);
475 if ( at->at_obsolete == LDAP_SCHEMA_YES ) {
476 print_literal(ss, "OBSOLETE");
480 if ( at->at_sup_oid ) {
481 print_literal(ss,"SUP");
482 print_woid(ss,at->at_sup_oid);
485 if ( at->at_equality_oid ) {
486 print_literal(ss,"EQUALITY");
487 print_woid(ss,at->at_equality_oid);
490 if ( at->at_ordering_oid ) {
491 print_literal(ss,"ORDERING");
492 print_woid(ss,at->at_ordering_oid);
495 if ( at->at_substr_oid ) {
496 print_literal(ss,"SUBSTR");
497 print_woid(ss,at->at_substr_oid);
500 if ( at->at_syntax_oid ) {
501 print_literal(ss,"SYNTAX");
503 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
507 if ( at->at_single_value == LDAP_SCHEMA_YES ) {
508 print_literal(ss,"SINGLE-VALUE");
512 if ( at->at_collective == LDAP_SCHEMA_YES ) {
513 print_literal(ss,"COLLECTIVE");
517 if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
518 print_literal(ss,"NO-USER-MODIFICATION");
522 if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
523 print_literal(ss,"USAGE");
525 switch (at->at_usage) {
526 case LDAP_SCHEMA_DIRECTORY_OPERATION:
527 print_literal(ss,"directoryOperation");
529 case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
530 print_literal(ss,"distributedOperation");
532 case LDAP_SCHEMA_DSA_OPERATION:
533 print_literal(ss,"dSAOperation");
536 print_literal(ss,"UNKNOWN");
543 print_extensions(ss, at->at_extensions);
545 print_literal(ss,/*(*/")");
547 retstring = LDAP_STRDUP(safe_string_val(ss));
548 safe_string_free(ss);
553 * Now come the parsers. There is one parser for each entity type:
554 * objectclasses, attributetypes, etc.
556 * Each of them is written as a recursive-descent parser, except that
557 * none of them is really recursive. But the idea is kept: there
558 * is one routine per non-terminal that eithers gobbles lexical tokens
559 * or calls lower-level routines, etc.
561 * The scanner is implemented in the routine get_token. Actually,
562 * get_token is more than a scanner and will return tokens that are
563 * in fact non-terminals in the grammar. So you can see the whole
564 * approach as the combination of a low-level bottom-up recognizer
565 * combined with a scanner and a number of top-down parsers. Or just
566 * consider that the real grammars recognized by the parsers are not
567 * those of the standards. As a matter of fact, our parsers are more
568 * liberal than the spec when there is no ambiguity.
570 * The difference is pretty academic (modulo bugs or incorrect
571 * interpretation of the specs).
574 #define TK_NOENDQUOTE -2
575 #define TK_OUTOFMEM -1
577 #define TK_UNEXPCHAR 1
578 #define TK_BAREWORD 2
579 #define TK_QDSTRING 3
580 #define TK_LEFTPAREN 4
581 #define TK_RIGHTPAREN 5
583 #define TK_QDESCR TK_QDSTRING
591 get_token(const char ** sp, char ** token_val)
609 kind = TK_RIGHTPAREN;
620 while ( **sp != '\'' && **sp != '\0' )
622 if ( **sp == '\'' ) {
624 res = LDAP_MALLOC(q-p+1);
634 kind = TK_NOENDQUOTE;
640 while ( !isspace(**sp) &&
648 res = LDAP_MALLOC(q-p+1);
657 /* kind = TK_UNEXPCHAR; */
664 /* Gobble optional whitespace */
666 parse_whsp(const char **sp)
668 while (isspace(**sp))
673 * General note for all parsers: to guarantee the algorithm halts they
674 * must always advance the pointer even when an error is found. For
675 * this one is not that important since an error here is fatal at the
676 * upper layers, but it is a simple strategy that will not get in
680 /* Parse a sequence of dot-separated decimal strings */
682 parse_numericoid(const char **sp, int *code, const int allow_quoted)
685 const char * start = *sp;
689 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
690 if ( allow_quoted && **sp == '\'' ) {
695 /* Each iteration of this loop gets one decimal string */
697 if ( !isdigit(**sp) ) {
699 * Initial char is not a digit or char after dot is
702 *code = LDAP_SCHERR_NODIGIT;
706 while ( isdigit(**sp) )
710 /* Otherwise, gobble the dot and loop again */
713 /* Now *sp points at the char past the numericoid. Perfect. */
715 res = LDAP_MALLOC(len+1);
717 *code = LDAP_SCHERR_OUTOFMEM;
720 strncpy(res,start,len);
722 if ( allow_quoted && quoted ) {
723 if ( **sp == '\'' ) {
726 *code = LDAP_SCHERR_UNEXPTOKEN;
734 /* Parse a qdescr or a list of them enclosed in () */
736 parse_qdescrs(const char **sp, int *code)
746 kind = get_token(sp,&sval);
747 if ( kind == TK_LEFTPAREN ) {
748 /* Let's presume there will be at least 2 entries */
750 res = LDAP_CALLOC(3,sizeof(char *));
752 *code = LDAP_SCHERR_OUTOFMEM;
758 kind = get_token(sp,&sval);
759 if ( kind == TK_RIGHTPAREN )
761 if ( kind == TK_QDESCR ) {
762 if ( pos == size-2 ) {
764 res1 = LDAP_REALLOC(res,size*sizeof(char *));
768 *code = LDAP_SCHERR_OUTOFMEM;
779 *code = LDAP_SCHERR_UNEXPTOKEN;
786 } else if ( kind == TK_QDESCR ) {
787 res = LDAP_CALLOC(2,sizeof(char *));
789 *code = LDAP_SCHERR_OUTOFMEM;
798 *code = LDAP_SCHERR_BADNAME;
805 parse_woid(const char **sp, int *code)
811 kind = get_token(sp, &sval);
812 if ( kind != TK_BAREWORD ) {
814 *code = LDAP_SCHERR_UNEXPTOKEN;
821 /* Parse a noidlen */
823 parse_noidlen(const char **sp, int *code, int *len, int allow_quoted)
829 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
830 if ( allow_quoted && **sp == '\'' ) {
834 sval = parse_numericoid(sp, code, 0);
838 if ( **sp == '{' /*}*/ ) {
841 while ( isdigit(**sp) )
843 if ( **sp != /*{*/ '}' ) {
844 *code = LDAP_SCHERR_UNEXPTOKEN;
850 if ( allow_quoted && quoted ) {
851 if ( **sp == '\'' ) {
854 *code = LDAP_SCHERR_UNEXPTOKEN;
863 * Next routine will accept a qdstring in place of an oid if
864 * allow_quoted is set. This is necessary to interoperate with
865 * Netscape Directory server that will improperly quote each oid (at
866 * least those of the descr kind) in the SUP clause.
869 /* Parse a woid or a $-separated list of them enclosed in () */
871 parse_oids(const char **sp, int *code, const int allow_quoted)
881 * Strictly speaking, doing this here accepts whsp before the
882 * ( at the begining of an oidlist, but this is harmless. Also,
883 * we are very liberal in what we accept as an OID. Maybe
887 kind = get_token(sp,&sval);
888 if ( kind == TK_LEFTPAREN ) {
889 /* Let's presume there will be at least 2 entries */
891 res = LDAP_CALLOC(3,sizeof(char *));
893 *code = LDAP_SCHERR_OUTOFMEM;
898 kind = get_token(sp,&sval);
899 if ( kind == TK_BAREWORD ||
900 ( allow_quoted && kind == TK_QDSTRING ) ) {
904 *code = LDAP_SCHERR_UNEXPTOKEN;
911 kind = get_token(sp,&sval);
912 if ( kind == TK_RIGHTPAREN )
914 if ( kind == TK_DOLLAR ) {
916 kind = get_token(sp,&sval);
917 if ( kind == TK_BAREWORD ||
919 kind == TK_QDSTRING ) ) {
920 if ( pos == size-2 ) {
922 res1 = LDAP_REALLOC(res,size*sizeof(char *));
926 *code = LDAP_SCHERR_OUTOFMEM;
934 *code = LDAP_SCHERR_UNEXPTOKEN;
941 *code = LDAP_SCHERR_UNEXPTOKEN;
950 } else if ( kind == TK_BAREWORD ||
951 ( allow_quoted && kind == TK_QDSTRING ) ) {
952 res = LDAP_CALLOC(2,sizeof(char *));
955 *code = LDAP_SCHERR_OUTOFMEM;
964 *code = LDAP_SCHERR_BADNAME;
970 add_extension(LDAP_SCHEMA_EXTENSION_ITEM ***extensions,
971 char * name, char ** values)
974 LDAP_SCHEMA_EXTENSION_ITEM **tmp, *ext;
976 ext = LDAP_CALLOC(1, sizeof(LDAP_SCHEMA_EXTENSION_ITEM));
979 ext->lsei_name = name;
980 ext->lsei_values = values;
982 if ( !*extensions ) {
984 LDAP_CALLOC(2, sizeof(LDAP_SCHEMA_EXTENSION_ITEM *));
989 for ( n=0; (*extensions)[n] != NULL; n++ )
991 tmp = LDAP_REALLOC(*extensions,
992 (n+2)*sizeof(LDAP_SCHEMA_EXTENSION_ITEM *));
997 (*extensions)[n] = ext;
998 (*extensions)[n+1] = NULL;
1003 free_extensions(LDAP_SCHEMA_EXTENSION_ITEM **extensions)
1005 LDAP_SCHEMA_EXTENSION_ITEM **ext;
1008 for ( ext = extensions; *ext != NULL; ext++ ) {
1009 LDAP_FREE((*ext)->lsei_name);
1010 LDAP_VFREE((*ext)->lsei_values);
1013 LDAP_FREE(extensions);
1018 ldap_syntax_free( LDAP_SYNTAX * syn )
1020 LDAP_FREE(syn->syn_oid);
1021 LDAP_FREE(syn->syn_desc);
1022 free_extensions(syn->syn_extensions);
1027 ldap_str2syntax( const char * s, int * code, const char ** errp )
1030 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,"DESC") ) {
1085 *code = LDAP_SCHERR_DUPOPT;
1087 ldap_syntax_free(syn);
1092 kind = get_token(&ss,&sval);
1093 if ( kind != TK_QDSTRING ) {
1094 *code = LDAP_SCHERR_UNEXPTOKEN;
1097 ldap_syntax_free(syn);
1100 syn->syn_desc = sval;
1102 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1104 /* Should be parse_qdstrings */
1105 ssdummy = parse_qdescrs(&ss, code);
1108 ldap_syntax_free(syn);
1112 *code = LDAP_SCHERR_UNEXPTOKEN;
1115 ldap_syntax_free(syn);
1120 *code = LDAP_SCHERR_UNEXPTOKEN;
1123 ldap_syntax_free(syn);
1130 ldap_matchingrule_free( LDAP_MATCHING_RULE * mr )
1132 LDAP_FREE(mr->mr_oid);
1133 LDAP_VFREE(mr->mr_names);
1134 LDAP_FREE(mr->mr_desc);
1135 LDAP_FREE(mr->mr_syntax_oid);
1136 free_extensions(mr->mr_extensions);
1140 LDAP_MATCHING_RULE *
1141 ldap_str2matchingrule( const char * s, int * code, const char ** errp )
1144 const char * ss = s;
1146 int be_liberal = 1; /* Future additional argument */
1149 int seen_obsolete = 0;
1150 int seen_syntax = 0;
1151 LDAP_MATCHING_RULE * mr;
1153 const char * savepos;
1156 *code = LDAP_SCHERR_EMPTY;
1162 mr = LDAP_CALLOC(1,sizeof(LDAP_MATCHING_RULE));
1165 *code = LDAP_SCHERR_OUTOFMEM;
1169 kind = get_token(&ss,&sval);
1170 if ( kind != TK_LEFTPAREN ) {
1171 *code = LDAP_SCHERR_NOLEFTPAREN;
1173 ldap_matchingrule_free(mr);
1179 mr->mr_oid = parse_numericoid(&ss,code,be_liberal);
1180 if ( !mr->mr_oid ) {
1184 kind = get_token(&ss,&sval);
1185 if ( kind == TK_BAREWORD ) {
1186 if ( !strcmp(sval, "NAME") ||
1187 !strcmp(sval, "DESC") ||
1188 !strcmp(sval, "OBSOLETE") ||
1189 !strcmp(sval, "SYNTAX") ||
1190 !strncmp(sval, "X-", 2) ) {
1191 /* Missing OID, backtrack */
1194 /* Non-numerical OID, ignore */
1200 ldap_matchingrule_free(mr);
1207 * Beyond this point we will be liberal and accept the items
1211 kind = get_token(&ss,&sval);
1214 *code = LDAP_SCHERR_NORIGHTPAREN;
1216 ldap_matchingrule_free(mr);
1221 if ( !strcmp(sval,"NAME") ) {
1224 *code = LDAP_SCHERR_DUPOPT;
1226 ldap_matchingrule_free(mr);
1230 mr->mr_names = parse_qdescrs(&ss,code);
1231 if ( !mr->mr_names ) {
1232 if ( *code != LDAP_SCHERR_OUTOFMEM )
1233 *code = LDAP_SCHERR_BADNAME;
1235 ldap_matchingrule_free(mr);
1238 } else if ( !strcmp(sval,"DESC") ) {
1241 *code = LDAP_SCHERR_DUPOPT;
1243 ldap_matchingrule_free(mr);
1248 kind = get_token(&ss,&sval);
1249 if ( kind != TK_QDSTRING ) {
1250 *code = LDAP_SCHERR_UNEXPTOKEN;
1253 ldap_matchingrule_free(mr);
1258 } else if ( !strcmp(sval,"OBSOLETE") ) {
1260 if ( seen_obsolete ) {
1261 *code = LDAP_SCHERR_DUPOPT;
1263 ldap_matchingrule_free(mr);
1267 mr->mr_obsolete = LDAP_SCHEMA_YES;
1269 } else if ( !strcmp(sval,"SYNTAX") ) {
1271 if ( seen_syntax ) {
1272 *code = LDAP_SCHERR_DUPOPT;
1274 ldap_matchingrule_free(mr);
1280 parse_numericoid(&ss,code,be_liberal);
1281 if ( !mr->mr_syntax_oid ) {
1283 ldap_matchingrule_free(mr);
1287 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1289 /* Should be parse_qdstrings */
1290 ssdummy = parse_qdescrs(&ss, code);
1293 ldap_matchingrule_free(mr);
1297 *code = LDAP_SCHERR_UNEXPTOKEN;
1300 ldap_matchingrule_free(mr);
1305 *code = LDAP_SCHERR_UNEXPTOKEN;
1308 ldap_matchingrule_free(mr);
1315 ldap_attributetype_free(LDAP_ATTRIBUTE_TYPE * at)
1317 LDAP_FREE(at->at_oid);
1318 LDAP_VFREE(at->at_names);
1319 LDAP_FREE(at->at_desc);
1320 LDAP_FREE(at->at_sup_oid);
1321 LDAP_FREE(at->at_equality_oid);
1322 LDAP_FREE(at->at_ordering_oid);
1323 LDAP_FREE(at->at_substr_oid);
1324 LDAP_FREE(at->at_syntax_oid);
1325 free_extensions(at->at_extensions);
1329 LDAP_ATTRIBUTE_TYPE *
1330 ldap_str2attributetype( const char * s, int * code, const char ** errp )
1333 const char * ss = s;
1335 int be_liberal = 1; /* Future additional argument */
1338 int seen_obsolete = 0;
1340 int seen_equality = 0;
1341 int seen_ordering = 0;
1342 int seen_substr = 0;
1343 int seen_syntax = 0;
1345 LDAP_ATTRIBUTE_TYPE * at;
1347 const char * savepos;
1350 *code = LDAP_SCHERR_EMPTY;
1356 at = LDAP_CALLOC(1,sizeof(LDAP_ATTRIBUTE_TYPE));
1359 *code = LDAP_SCHERR_OUTOFMEM;
1363 kind = get_token(&ss,&sval);
1364 if ( kind != TK_LEFTPAREN ) {
1365 *code = LDAP_SCHERR_NOLEFTPAREN;
1367 ldap_attributetype_free(at);
1372 * Definitions MUST begin with an OID in the numericoid format.
1373 * However, this routine is used by clients to parse the response
1374 * from servers and very well known servers will provide an OID
1375 * in the wrong format or even no OID at all. We do our best to
1376 * extract info from those servers.
1380 at->at_oid = parse_numericoid(&ss,code,0);
1381 if ( !at->at_oid ) {
1385 kind = get_token(&ss,&sval);
1386 if ( kind == TK_BAREWORD ) {
1387 if ( !strcmp(sval, "NAME") ||
1388 !strcmp(sval, "DESC") ||
1389 !strcmp(sval, "OBSOLETE") ||
1390 !strcmp(sval, "SUP") ||
1391 !strcmp(sval, "EQUALITY") ||
1392 !strcmp(sval, "ORDERING") ||
1393 !strcmp(sval, "SUBSTR") ||
1394 !strcmp(sval, "SYNTAX") ||
1395 !strcmp(sval, "SINGLE-VALUE") ||
1396 !strcmp(sval, "COLLECTIVE") ||
1397 !strcmp(sval, "NO-USER-MODIFICATION") ||
1398 !strcmp(sval, "USAGE") ||
1399 !strncmp(sval, "X-", 2) ) {
1400 /* Missing OID, backtrack */
1403 /* Non-numerical OID, ignore */
1409 ldap_attributetype_free(at);
1416 * Beyond this point we will be liberal and accept the items
1420 kind = get_token(&ss,&sval);
1423 *code = LDAP_SCHERR_NORIGHTPAREN;
1425 ldap_attributetype_free(at);
1430 if ( !strcmp(sval,"NAME") ) {
1433 *code = LDAP_SCHERR_DUPOPT;
1435 ldap_attributetype_free(at);
1439 at->at_names = parse_qdescrs(&ss,code);
1440 if ( !at->at_names ) {
1441 if ( *code != LDAP_SCHERR_OUTOFMEM )
1442 *code = LDAP_SCHERR_BADNAME;
1444 ldap_attributetype_free(at);
1447 } else if ( !strcmp(sval,"DESC") ) {
1450 *code = LDAP_SCHERR_DUPOPT;
1452 ldap_attributetype_free(at);
1457 kind = get_token(&ss,&sval);
1458 if ( kind != TK_QDSTRING ) {
1459 *code = LDAP_SCHERR_UNEXPTOKEN;
1462 ldap_attributetype_free(at);
1467 } else if ( !strcmp(sval,"OBSOLETE") ) {
1469 if ( seen_obsolete ) {
1470 *code = LDAP_SCHERR_DUPOPT;
1472 ldap_attributetype_free(at);
1476 at->at_obsolete = LDAP_SCHEMA_YES;
1478 } else if ( !strcmp(sval,"SUP") ) {
1481 *code = LDAP_SCHERR_DUPOPT;
1483 ldap_attributetype_free(at);
1487 at->at_sup_oid = parse_woid(&ss,code);
1488 if ( !at->at_sup_oid ) {
1490 ldap_attributetype_free(at);
1493 } else if ( !strcmp(sval,"EQUALITY") ) {
1495 if ( seen_equality ) {
1496 *code = LDAP_SCHERR_DUPOPT;
1498 ldap_attributetype_free(at);
1502 at->at_equality_oid = parse_woid(&ss,code);
1503 if ( !at->at_equality_oid ) {
1505 ldap_attributetype_free(at);
1508 } else if ( !strcmp(sval,"ORDERING") ) {
1510 if ( seen_ordering ) {
1511 *code = LDAP_SCHERR_DUPOPT;
1513 ldap_attributetype_free(at);
1517 at->at_ordering_oid = parse_woid(&ss,code);
1518 if ( !at->at_ordering_oid ) {
1520 ldap_attributetype_free(at);
1523 } else if ( !strcmp(sval,"SUBSTR") ) {
1525 if ( seen_substr ) {
1526 *code = LDAP_SCHERR_DUPOPT;
1528 ldap_attributetype_free(at);
1532 at->at_substr_oid = parse_woid(&ss,code);
1533 if ( !at->at_substr_oid ) {
1535 ldap_attributetype_free(at);
1538 } else if ( !strcmp(sval,"SYNTAX") ) {
1540 if ( seen_syntax ) {
1541 *code = LDAP_SCHERR_DUPOPT;
1543 ldap_attributetype_free(at);
1553 if ( !at->at_syntax_oid ) {
1555 ldap_attributetype_free(at);
1559 } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
1561 if ( at->at_single_value ) {
1562 *code = LDAP_SCHERR_DUPOPT;
1564 ldap_attributetype_free(at);
1567 at->at_single_value = LDAP_SCHEMA_YES;
1569 } else if ( !strcmp(sval,"COLLECTIVE") ) {
1571 if ( at->at_collective ) {
1572 *code = LDAP_SCHERR_DUPOPT;
1574 ldap_attributetype_free(at);
1577 at->at_collective = LDAP_SCHEMA_YES;
1579 } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
1581 if ( at->at_no_user_mod ) {
1582 *code = LDAP_SCHERR_DUPOPT;
1584 ldap_attributetype_free(at);
1587 at->at_no_user_mod = LDAP_SCHEMA_YES;
1589 } else if ( !strcmp(sval,"USAGE") ) {
1592 *code = LDAP_SCHERR_DUPOPT;
1594 ldap_attributetype_free(at);
1599 kind = get_token(&ss,&sval);
1600 if ( kind != TK_BAREWORD ) {
1601 *code = LDAP_SCHERR_UNEXPTOKEN;
1604 ldap_attributetype_free(at);
1607 if ( !strcasecmp(sval,"userApplications") )
1609 LDAP_SCHEMA_USER_APPLICATIONS;
1610 else if ( !strcasecmp(sval,"directoryOperation") )
1612 LDAP_SCHEMA_DIRECTORY_OPERATION;
1613 else if ( !strcasecmp(sval,"distributedOperation") )
1615 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
1616 else if ( !strcasecmp(sval,"dSAOperation") )
1618 LDAP_SCHEMA_DSA_OPERATION;
1620 *code = LDAP_SCHERR_UNEXPTOKEN;
1623 ldap_attributetype_free(at);
1628 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1629 /* Should be parse_qdstrings */
1630 ext_vals = parse_qdescrs(&ss, code);
1633 ldap_attributetype_free(at);
1636 if ( add_extension(&at->at_extensions,
1638 *code = LDAP_SCHERR_OUTOFMEM;
1641 ldap_attributetype_free(at);
1645 *code = LDAP_SCHERR_UNEXPTOKEN;
1648 ldap_attributetype_free(at);
1653 *code = LDAP_SCHERR_UNEXPTOKEN;
1656 ldap_attributetype_free(at);
1663 ldap_objectclass_free(LDAP_OBJECT_CLASS * oc)
1665 LDAP_FREE(oc->oc_oid);
1666 LDAP_VFREE(oc->oc_names);
1667 LDAP_FREE(oc->oc_desc);
1668 LDAP_VFREE(oc->oc_sup_oids);
1669 LDAP_VFREE(oc->oc_at_oids_must);
1670 LDAP_VFREE(oc->oc_at_oids_may);
1671 free_extensions(oc->oc_extensions);
1676 ldap_str2objectclass( const char * s, int * code, const char ** errp )
1679 const char * ss = s;
1681 int be_liberal = 1; /* Future additional argument */
1684 int seen_obsolete = 0;
1689 LDAP_OBJECT_CLASS * oc;
1691 const char * savepos;
1694 *code = LDAP_SCHERR_EMPTY;
1700 oc = LDAP_CALLOC(1,sizeof(LDAP_OBJECT_CLASS));
1703 *code = LDAP_SCHERR_OUTOFMEM;
1707 kind = get_token(&ss,&sval);
1708 if ( kind != TK_LEFTPAREN ) {
1709 *code = LDAP_SCHERR_NOLEFTPAREN;
1711 ldap_objectclass_free(oc);
1716 * Definitions MUST begin with an OID in the numericoid format.
1717 * However, this routine is used by clients to parse the response
1718 * from servers and very well known servers will provide an OID
1719 * in the wrong format or even no OID at all. We do our best to
1720 * extract info from those servers.
1724 oc->oc_oid = parse_numericoid(&ss,code,0);
1725 if ( !oc->oc_oid ) {
1729 kind = get_token(&ss,&sval);
1730 if ( kind == TK_BAREWORD ) {
1731 if ( !strcmp(sval, "NAME") ||
1732 !strcmp(sval, "DESC") ||
1733 !strcmp(sval, "OBSOLETE") ||
1734 !strcmp(sval, "SUP") ||
1735 !strcmp(sval, "ABSTRACT") ||
1736 !strcmp(sval, "STRUCTURAL") ||
1737 !strcmp(sval, "AUXILIARY") ||
1738 !strcmp(sval, "MUST") ||
1739 !strncmp(sval, "X-", 2) ) {
1740 /* Missing OID, backtrack */
1743 /* Non-numerical OID, ignore */
1749 ldap_objectclass_free(oc);
1756 * Beyond this point we will be liberal an accept the items
1760 kind = get_token(&ss,&sval);
1763 *code = LDAP_SCHERR_NORIGHTPAREN;
1765 ldap_objectclass_free(oc);
1770 if ( !strcmp(sval,"NAME") ) {
1773 *code = LDAP_SCHERR_DUPOPT;
1775 ldap_objectclass_free(oc);
1779 oc->oc_names = parse_qdescrs(&ss,code);
1780 if ( !oc->oc_names ) {
1781 if ( *code != LDAP_SCHERR_OUTOFMEM )
1782 *code = LDAP_SCHERR_BADNAME;
1784 ldap_objectclass_free(oc);
1787 } else if ( !strcmp(sval,"DESC") ) {
1790 *code = LDAP_SCHERR_DUPOPT;
1792 ldap_objectclass_free(oc);
1797 kind = get_token(&ss,&sval);
1798 if ( kind != TK_QDSTRING ) {
1799 *code = LDAP_SCHERR_UNEXPTOKEN;
1802 ldap_objectclass_free(oc);
1807 } else if ( !strcmp(sval,"OBSOLETE") ) {
1809 if ( seen_obsolete ) {
1810 *code = LDAP_SCHERR_DUPOPT;
1812 ldap_objectclass_free(oc);
1816 oc->oc_obsolete = LDAP_SCHEMA_YES;
1818 } else if ( !strcmp(sval,"SUP") ) {
1821 *code = LDAP_SCHERR_DUPOPT;
1823 ldap_objectclass_free(oc);
1827 oc->oc_sup_oids = parse_oids(&ss,
1830 if ( !oc->oc_sup_oids ) {
1832 ldap_objectclass_free(oc);
1835 } else if ( !strcmp(sval,"ABSTRACT") ) {
1838 *code = LDAP_SCHERR_DUPOPT;
1840 ldap_objectclass_free(oc);
1844 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
1846 } else if ( !strcmp(sval,"STRUCTURAL") ) {
1849 *code = LDAP_SCHERR_DUPOPT;
1851 ldap_objectclass_free(oc);
1855 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
1857 } else if ( !strcmp(sval,"AUXILIARY") ) {
1860 *code = LDAP_SCHERR_DUPOPT;
1862 ldap_objectclass_free(oc);
1866 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
1868 } else if ( !strcmp(sval,"MUST") ) {
1871 *code = LDAP_SCHERR_DUPOPT;
1873 ldap_objectclass_free(oc);
1877 oc->oc_at_oids_must = parse_oids(&ss,code,0);
1878 if ( !oc->oc_at_oids_must ) {
1880 ldap_objectclass_free(oc);
1884 } else if ( !strcmp(sval,"MAY") ) {
1887 *code = LDAP_SCHERR_DUPOPT;
1889 ldap_objectclass_free(oc);
1893 oc->oc_at_oids_may = parse_oids(&ss,code,0);
1894 if ( !oc->oc_at_oids_may ) {
1896 ldap_objectclass_free(oc);
1900 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1902 /* Should be parse_qdstrings */
1903 ssdummy = parse_qdescrs(&ss, code);
1906 ldap_objectclass_free(oc);
1910 *code = LDAP_SCHERR_UNEXPTOKEN;
1913 ldap_objectclass_free(oc);
1918 *code = LDAP_SCHERR_UNEXPTOKEN;
1921 ldap_objectclass_free(oc);
1927 static char *const err2text[] = {
1931 "Missing opening parenthesis",
1932 "Missing closing parenthesis",
1938 "Unexpected end of data"
1942 ldap_scherr2str(int code)
1944 if ( code < 1 || code >= (sizeof(err2text)/sizeof(char *)) ) {
1945 return "Unknown error";
1947 return err2text[code];