3 * Copyright 1999 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 ldap_syntax2str( const LDAP_SYNTAX * syn )
277 ss = new_safe_string(256);
281 print_literal(ss,"(");
284 print_numericoid(ss, syn->syn_oid);
287 if ( syn->syn_desc ) {
288 print_literal(ss,"DESC");
289 print_qdstring(ss,syn->syn_desc);
293 print_literal(ss,")");
295 retstring = LDAP_STRDUP(safe_string_val(ss));
296 safe_string_free(ss);
301 ldap_matchingrule2str( const LDAP_MATCHING_RULE * mr )
306 ss = new_safe_string(256);
310 print_literal(ss,"(");
313 print_numericoid(ss, mr->mr_oid);
316 if ( mr->mr_names ) {
317 print_literal(ss,"NAME");
318 print_qdescrs(ss,mr->mr_names);
322 print_literal(ss,"DESC");
323 print_qdstring(ss,mr->mr_desc);
326 if ( mr->mr_obsolete == LDAP_SCHEMA_YES ) {
327 print_literal(ss, "OBSOLETE");
331 if ( mr->mr_syntax_oid ) {
332 print_literal(ss,"SYNTAX");
334 print_literal(ss, mr->mr_syntax_oid);
339 print_literal(ss,")");
341 retstring = LDAP_STRDUP(safe_string_val(ss));
342 safe_string_free(ss);
347 ldap_objectclass2str( const LDAP_OBJECT_CLASS * oc )
352 ss = new_safe_string(256);
356 print_literal(ss,"(");
359 print_numericoid(ss, oc->oc_oid);
362 if ( oc->oc_names ) {
363 print_literal(ss,"NAME");
364 print_qdescrs(ss,oc->oc_names);
368 print_literal(ss,"DESC");
369 print_qdstring(ss,oc->oc_desc);
372 if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) {
373 print_literal(ss, "OBSOLETE");
377 if ( oc->oc_sup_oids ) {
378 print_literal(ss,"SUP");
380 print_oids(ss,oc->oc_sup_oids);
384 switch (oc->oc_kind) {
385 case LDAP_SCHEMA_ABSTRACT:
386 print_literal(ss,"ABSTRACT");
388 case LDAP_SCHEMA_STRUCTURAL:
389 print_literal(ss,"STRUCTURAL");
391 case LDAP_SCHEMA_AUXILIARY:
392 print_literal(ss,"AUXILIARY");
395 print_literal(ss,"KIND-UNKNOWN");
400 if ( oc->oc_at_oids_must ) {
401 print_literal(ss,"MUST");
403 print_oids(ss,oc->oc_at_oids_must);
407 if ( oc->oc_at_oids_may ) {
408 print_literal(ss,"MAY");
410 print_oids(ss,oc->oc_at_oids_may);
415 print_literal(ss,")");
417 retstring = LDAP_STRDUP(safe_string_val(ss));
418 safe_string_free(ss);
423 ldap_attributetype2str( const LDAP_ATTRIBUTE_TYPE * at )
428 ss = new_safe_string(256);
432 print_literal(ss,"(");
435 print_numericoid(ss, at->at_oid);
438 if ( at->at_names ) {
439 print_literal(ss,"NAME");
440 print_qdescrs(ss,at->at_names);
444 print_literal(ss,"DESC");
445 print_qdstring(ss,at->at_desc);
448 if ( at->at_obsolete == LDAP_SCHEMA_YES ) {
449 print_literal(ss, "OBSOLETE");
453 if ( at->at_sup_oid ) {
454 print_literal(ss,"SUP");
455 print_woid(ss,at->at_sup_oid);
458 if ( at->at_equality_oid ) {
459 print_literal(ss,"EQUALITY");
460 print_woid(ss,at->at_equality_oid);
463 if ( at->at_ordering_oid ) {
464 print_literal(ss,"ORDERING");
465 print_woid(ss,at->at_ordering_oid);
468 if ( at->at_substr_oid ) {
469 print_literal(ss,"SUBSTR");
470 print_woid(ss,at->at_substr_oid);
473 if ( at->at_syntax_oid ) {
474 print_literal(ss,"SYNTAX");
476 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
480 if ( at->at_single_value == LDAP_SCHEMA_YES ) {
481 print_literal(ss,"SINGLE-VALUE");
485 if ( at->at_collective == LDAP_SCHEMA_YES ) {
486 print_literal(ss,"COLLECTIVE");
490 if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
491 print_literal(ss,"NO-USER-MODIFICATION");
495 if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
496 print_literal(ss,"USAGE");
498 switch (at->at_usage) {
499 case LDAP_SCHEMA_DIRECTORY_OPERATION:
500 print_literal(ss,"directoryOperation");
502 case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
503 print_literal(ss,"distributedOperation");
505 case LDAP_SCHEMA_DSA_OPERATION:
506 print_literal(ss,"dSAOperation");
509 print_literal(ss,"UNKNOWN");
515 print_literal(ss,")");
517 retstring = LDAP_STRDUP(safe_string_val(ss));
518 safe_string_free(ss);
523 * Now come the parsers. There is one parser for each entity type:
524 * objectclasses, attributetypes, etc.
526 * Each of them is written as a recursive-descent parser, except that
527 * none of them is really recursive. But the idea is kept: there
528 * is one routine per non-terminal that eithers gobbles lexical tokens
529 * or calls lower-level routines, etc.
531 * The scanner is implemented in the routine get_token. Actually,
532 * get_token is more than a scanner and will return tokens that are
533 * in fact non-terminals in the grammar. So you can see the whole
534 * approach as the combination of a low-level bottom-up recognizer
535 * combined with a scanner and a number of top-down parsers. Or just
536 * consider that the real grammars recognized by the parsers are not
537 * those of the standards. As a matter of fact, our parsers are more
538 * liberal than the spec when there is no ambiguity.
540 * The difference is pretty academic (modulo bugs or incorrect
541 * interpretation of the specs).
544 #define TK_NOENDQUOTE -2
545 #define TK_OUTOFMEM -1
547 #define TK_UNEXPCHAR 1
548 #define TK_BAREWORD 2
549 #define TK_QDSTRING 3
550 #define TK_LEFTPAREN 4
551 #define TK_RIGHTPAREN 5
553 #define TK_QDESCR TK_QDSTRING
561 get_token(const char ** sp, char ** token_val)
579 kind = TK_RIGHTPAREN;
590 while ( **sp != '\'' && **sp != '\0' )
592 if ( **sp == '\'' ) {
594 res = LDAP_MALLOC(q-p+1);
604 kind = TK_NOENDQUOTE;
610 while ( !isspace(**sp) &&
618 res = LDAP_MALLOC(q-p+1);
627 /* kind = TK_UNEXPCHAR; */
634 /* Gobble optional whitespace */
636 parse_whsp(const char **sp)
638 while (isspace(**sp))
643 * General note for all parsers: to guarantee the algorithm halts they
644 * must always advance the pointer even when an error is found. For
645 * this one is not that important since an error here is fatal at the
646 * upper layers, but it is a simple strategy that will not get in
650 /* Parse a sequence of dot-separated decimal strings */
652 parse_numericoid(const char **sp, int *code, const int allow_quoted)
655 const char * start = *sp;
659 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
660 if ( allow_quoted && **sp == '\'' ) {
665 /* Each iteration of this loop gets one decimal string */
667 if ( !isdigit(**sp) ) {
669 * Initial char is not a digit or char after dot is
672 *code = LDAP_SCHERR_NODIGIT;
676 while ( isdigit(**sp) )
680 /* Otherwise, gobble the dot and loop again */
683 /* Now *sp points at the char past the numericoid. Perfect. */
685 res = LDAP_MALLOC(len+1);
687 *code = LDAP_SCHERR_OUTOFMEM;
690 strncpy(res,start,len);
692 if ( allow_quoted && quoted ) {
693 if ( **sp == '\'' ) {
696 *code = LDAP_SCHERR_UNEXPTOKEN;
704 /* Parse a qdescr or a list of them enclosed in () */
706 parse_qdescrs(const char **sp, int *code)
716 kind = get_token(sp,&sval);
717 if ( kind == TK_LEFTPAREN ) {
718 /* Let's presume there will be at least 2 entries */
720 res = LDAP_CALLOC(3,sizeof(char *));
722 *code = LDAP_SCHERR_OUTOFMEM;
728 kind = get_token(sp,&sval);
729 if ( kind == TK_RIGHTPAREN )
731 if ( kind == TK_QDESCR ) {
732 if ( pos == size-2 ) {
734 res1 = LDAP_REALLOC(res,size*sizeof(char *));
738 *code = LDAP_SCHERR_OUTOFMEM;
749 *code = LDAP_SCHERR_UNEXPTOKEN;
756 } else if ( kind == TK_QDESCR ) {
757 res = LDAP_CALLOC(2,sizeof(char *));
759 *code = LDAP_SCHERR_OUTOFMEM;
768 *code = LDAP_SCHERR_BADNAME;
775 parse_woid(const char **sp, int *code)
781 kind = get_token(sp, &sval);
782 if ( kind != TK_BAREWORD ) {
784 *code = LDAP_SCHERR_UNEXPTOKEN;
791 /* Parse a noidlen */
793 parse_noidlen(const char **sp, int *code, int *len, int allow_quoted)
799 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
800 if ( allow_quoted && **sp == '\'' ) {
804 sval = parse_numericoid(sp, code, 0);
811 while ( isdigit(**sp) )
814 *code = LDAP_SCHERR_UNEXPTOKEN;
820 if ( allow_quoted && quoted ) {
821 if ( **sp == '\'' ) {
824 *code = LDAP_SCHERR_UNEXPTOKEN;
833 * Next routine will accept a qdstring in place of an oid if
834 * allow_quoted is set. This is necessary to interoperate with
835 * Netscape Directory server that will improperly quote each oid (at
836 * least those of the descr kind) in the SUP clause.
839 /* Parse a woid or a $-separated list of them enclosed in () */
841 parse_oids(const char **sp, int *code, const int allow_quoted)
851 * Strictly speaking, doing this here accepts whsp before the
852 * ( at the begining of an oidlist, but this is harmless. Also,
853 * we are very liberal in what we accept as an OID. Maybe
857 kind = get_token(sp,&sval);
858 if ( kind == TK_LEFTPAREN ) {
859 /* Let's presume there will be at least 2 entries */
861 res = LDAP_CALLOC(3,sizeof(char *));
863 *code = LDAP_SCHERR_OUTOFMEM;
868 kind = get_token(sp,&sval);
869 if ( kind == TK_BAREWORD ||
870 ( allow_quoted && kind == TK_QDSTRING ) ) {
874 *code = LDAP_SCHERR_UNEXPTOKEN;
881 kind = get_token(sp,&sval);
882 if ( kind == TK_RIGHTPAREN )
884 if ( kind == TK_DOLLAR ) {
886 kind = get_token(sp,&sval);
887 if ( kind == TK_BAREWORD ||
889 kind == TK_QDSTRING ) ) {
890 if ( pos == size-2 ) {
892 res1 = LDAP_REALLOC(res,size*sizeof(char *));
896 *code = LDAP_SCHERR_OUTOFMEM;
904 *code = LDAP_SCHERR_UNEXPTOKEN;
911 *code = LDAP_SCHERR_UNEXPTOKEN;
920 } else if ( kind == TK_BAREWORD ||
921 ( allow_quoted && kind == TK_QDSTRING ) ) {
922 res = LDAP_CALLOC(2,sizeof(char *));
925 *code = LDAP_SCHERR_OUTOFMEM;
934 *code = LDAP_SCHERR_BADNAME;
940 ldap_syntax_free( LDAP_SYNTAX * syn )
942 LDAP_FREE(syn->syn_oid);
943 LDAP_FREE(syn->syn_desc);
948 ldap_str2syntax( const char * s, int * code, const char ** errp )
958 *code = LDAP_SCHERR_EMPTY;
964 syn = LDAP_CALLOC(1,sizeof(LDAP_SYNTAX));
967 *code = LDAP_SCHERR_OUTOFMEM;
971 kind = get_token(&ss,&sval);
972 if ( kind != TK_LEFTPAREN ) {
974 *code = LDAP_SCHERR_NOLEFTPAREN;
975 ldap_syntax_free(syn);
980 syn->syn_oid = parse_numericoid(&ss,code,0);
981 if ( !syn->syn_oid ) {
983 ldap_syntax_free(syn);
989 * Beyond this point we will be liberal and accept the items
993 kind = get_token(&ss,&sval);
996 *code = LDAP_SCHERR_NORIGHTPAREN;
998 ldap_syntax_free(syn);
1003 if ( !strcmp(sval,"DESC") ) {
1006 *code = LDAP_SCHERR_DUPOPT;
1008 ldap_syntax_free(syn);
1013 kind = get_token(&ss,&sval);
1014 if ( kind != TK_QDSTRING ) {
1015 *code = LDAP_SCHERR_UNEXPTOKEN;
1018 ldap_syntax_free(syn);
1021 syn->syn_desc = sval;
1023 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1025 /* Should be parse_qdstrings */
1026 ssdummy = parse_qdescrs(&ss, code);
1029 ldap_syntax_free(syn);
1033 *code = LDAP_SCHERR_UNEXPTOKEN;
1036 ldap_syntax_free(syn);
1041 *code = LDAP_SCHERR_UNEXPTOKEN;
1044 ldap_syntax_free(syn);
1051 ldap_matchingrule_free( LDAP_MATCHING_RULE * mr )
1053 LDAP_FREE(mr->mr_oid);
1054 LDAP_VFREE(mr->mr_names);
1055 LDAP_FREE(mr->mr_desc);
1056 LDAP_FREE(mr->mr_syntax_oid);
1060 LDAP_MATCHING_RULE *
1061 ldap_str2matchingrule( const char * s, int * code, const char ** errp )
1064 const char * ss = s;
1066 int be_liberal = 1; /* Future additional argument */
1069 int seen_obsolete = 0;
1070 int seen_syntax = 0;
1071 LDAP_MATCHING_RULE * mr;
1073 const char * savepos;
1076 *code = LDAP_SCHERR_EMPTY;
1082 mr = LDAP_CALLOC(1,sizeof(LDAP_MATCHING_RULE));
1085 *code = LDAP_SCHERR_OUTOFMEM;
1089 kind = get_token(&ss,&sval);
1090 if ( kind != TK_LEFTPAREN ) {
1091 *code = LDAP_SCHERR_NOLEFTPAREN;
1093 ldap_matchingrule_free(mr);
1099 mr->mr_oid = parse_numericoid(&ss,code,be_liberal);
1100 if ( !mr->mr_oid ) {
1104 kind = get_token(&ss,&sval);
1105 if ( kind == TK_BAREWORD ) {
1106 if ( !strcmp(sval, "NAME") ||
1107 !strcmp(sval, "DESC") ||
1108 !strcmp(sval, "OBSOLETE") ||
1109 !strcmp(sval, "SYNTAX") ||
1110 !strncmp(sval, "X-", 2) ) {
1111 /* Missing OID, backtrack */
1114 /* Non-numerical OID, ignore */
1120 ldap_matchingrule_free(mr);
1127 * Beyond this point we will be liberal and accept the items
1131 kind = get_token(&ss,&sval);
1134 *code = LDAP_SCHERR_NORIGHTPAREN;
1136 ldap_matchingrule_free(mr);
1141 if ( !strcmp(sval,"NAME") ) {
1144 *code = LDAP_SCHERR_DUPOPT;
1146 ldap_matchingrule_free(mr);
1150 mr->mr_names = parse_qdescrs(&ss,code);
1151 if ( !mr->mr_names ) {
1152 if ( *code != LDAP_SCHERR_OUTOFMEM )
1153 *code = LDAP_SCHERR_BADNAME;
1155 ldap_matchingrule_free(mr);
1158 } else if ( !strcmp(sval,"DESC") ) {
1161 *code = LDAP_SCHERR_DUPOPT;
1163 ldap_matchingrule_free(mr);
1168 kind = get_token(&ss,&sval);
1169 if ( kind != TK_QDSTRING ) {
1170 *code = LDAP_SCHERR_UNEXPTOKEN;
1173 ldap_matchingrule_free(mr);
1178 } else if ( !strcmp(sval,"OBSOLETE") ) {
1180 if ( seen_obsolete ) {
1181 *code = LDAP_SCHERR_DUPOPT;
1183 ldap_matchingrule_free(mr);
1187 mr->mr_obsolete = LDAP_SCHEMA_YES;
1189 } else if ( !strcmp(sval,"SYNTAX") ) {
1191 if ( seen_syntax ) {
1192 *code = LDAP_SCHERR_DUPOPT;
1194 ldap_matchingrule_free(mr);
1200 parse_numericoid(&ss,code,be_liberal);
1201 if ( !mr->mr_syntax_oid ) {
1203 ldap_matchingrule_free(mr);
1207 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1209 /* Should be parse_qdstrings */
1210 ssdummy = parse_qdescrs(&ss, code);
1213 ldap_matchingrule_free(mr);
1217 *code = LDAP_SCHERR_UNEXPTOKEN;
1220 ldap_matchingrule_free(mr);
1225 *code = LDAP_SCHERR_UNEXPTOKEN;
1228 ldap_matchingrule_free(mr);
1235 ldap_attributetype_free(LDAP_ATTRIBUTE_TYPE * at)
1237 LDAP_FREE(at->at_oid);
1238 LDAP_VFREE(at->at_names);
1239 LDAP_FREE(at->at_desc);
1240 LDAP_FREE(at->at_sup_oid);
1241 LDAP_FREE(at->at_equality_oid);
1242 LDAP_FREE(at->at_ordering_oid);
1243 LDAP_FREE(at->at_substr_oid);
1244 LDAP_FREE(at->at_syntax_oid);
1248 LDAP_ATTRIBUTE_TYPE *
1249 ldap_str2attributetype( const char * s, int * code, const char ** errp )
1252 const char * ss = s;
1254 int be_liberal = 1; /* Future additional argument */
1257 int seen_obsolete = 0;
1259 int seen_equality = 0;
1260 int seen_ordering = 0;
1261 int seen_substr = 0;
1262 int seen_syntax = 0;
1264 LDAP_ATTRIBUTE_TYPE * at;
1266 const char * savepos;
1269 *code = LDAP_SCHERR_EMPTY;
1275 at = LDAP_CALLOC(1,sizeof(LDAP_ATTRIBUTE_TYPE));
1278 *code = LDAP_SCHERR_OUTOFMEM;
1282 kind = get_token(&ss,&sval);
1283 if ( kind != TK_LEFTPAREN ) {
1284 *code = LDAP_SCHERR_NOLEFTPAREN;
1286 ldap_attributetype_free(at);
1291 * Definitions MUST begin with an OID in the numericoid format.
1292 * However, this routine is used by clients to parse the response
1293 * from servers and very well known servers will provide an OID
1294 * in the wrong format or even no OID at all. We do our best to
1295 * extract info from those servers.
1299 at->at_oid = parse_numericoid(&ss,code,0);
1300 if ( !at->at_oid ) {
1304 kind = get_token(&ss,&sval);
1305 if ( kind == TK_BAREWORD ) {
1306 if ( !strcmp(sval, "NAME") ||
1307 !strcmp(sval, "DESC") ||
1308 !strcmp(sval, "OBSOLETE") ||
1309 !strcmp(sval, "SUP") ||
1310 !strcmp(sval, "EQUALITY") ||
1311 !strcmp(sval, "ORDERING") ||
1312 !strcmp(sval, "SUBSTR") ||
1313 !strcmp(sval, "SYNTAX") ||
1314 !strcmp(sval, "SINGLE-VALUE") ||
1315 !strcmp(sval, "COLLECTIVE") ||
1316 !strcmp(sval, "NO-USER-MODIFICATION") ||
1317 !strcmp(sval, "USAGE") ||
1318 !strncmp(sval, "X-", 2) ) {
1319 /* Missing OID, backtrack */
1322 /* Non-numerical OID, ignore */
1328 ldap_attributetype_free(at);
1335 * Beyond this point we will be liberal and accept the items
1339 kind = get_token(&ss,&sval);
1342 *code = LDAP_SCHERR_NORIGHTPAREN;
1344 ldap_attributetype_free(at);
1349 if ( !strcmp(sval,"NAME") ) {
1352 *code = LDAP_SCHERR_DUPOPT;
1354 ldap_attributetype_free(at);
1358 at->at_names = parse_qdescrs(&ss,code);
1359 if ( !at->at_names ) {
1360 if ( *code != LDAP_SCHERR_OUTOFMEM )
1361 *code = LDAP_SCHERR_BADNAME;
1363 ldap_attributetype_free(at);
1366 } else if ( !strcmp(sval,"DESC") ) {
1369 *code = LDAP_SCHERR_DUPOPT;
1371 ldap_attributetype_free(at);
1376 kind = get_token(&ss,&sval);
1377 if ( kind != TK_QDSTRING ) {
1378 *code = LDAP_SCHERR_UNEXPTOKEN;
1381 ldap_attributetype_free(at);
1386 } else if ( !strcmp(sval,"OBSOLETE") ) {
1388 if ( seen_obsolete ) {
1389 *code = LDAP_SCHERR_DUPOPT;
1391 ldap_attributetype_free(at);
1395 at->at_obsolete = LDAP_SCHEMA_YES;
1397 } else if ( !strcmp(sval,"SUP") ) {
1400 *code = LDAP_SCHERR_DUPOPT;
1402 ldap_attributetype_free(at);
1406 at->at_sup_oid = parse_woid(&ss,code);
1407 if ( !at->at_sup_oid ) {
1409 ldap_attributetype_free(at);
1412 } else if ( !strcmp(sval,"EQUALITY") ) {
1414 if ( seen_equality ) {
1415 *code = LDAP_SCHERR_DUPOPT;
1417 ldap_attributetype_free(at);
1421 at->at_equality_oid = parse_woid(&ss,code);
1422 if ( !at->at_equality_oid ) {
1424 ldap_attributetype_free(at);
1427 } else if ( !strcmp(sval,"ORDERING") ) {
1429 if ( seen_ordering ) {
1430 *code = LDAP_SCHERR_DUPOPT;
1432 ldap_attributetype_free(at);
1436 at->at_ordering_oid = parse_woid(&ss,code);
1437 if ( !at->at_ordering_oid ) {
1439 ldap_attributetype_free(at);
1442 } else if ( !strcmp(sval,"SUBSTR") ) {
1444 if ( seen_substr ) {
1445 *code = LDAP_SCHERR_DUPOPT;
1447 ldap_attributetype_free(at);
1451 at->at_substr_oid = parse_woid(&ss,code);
1452 if ( !at->at_substr_oid ) {
1454 ldap_attributetype_free(at);
1457 } else if ( !strcmp(sval,"SYNTAX") ) {
1459 if ( seen_syntax ) {
1460 *code = LDAP_SCHERR_DUPOPT;
1462 ldap_attributetype_free(at);
1472 if ( !at->at_syntax_oid ) {
1474 ldap_attributetype_free(at);
1478 } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
1480 if ( at->at_single_value ) {
1481 *code = LDAP_SCHERR_DUPOPT;
1483 ldap_attributetype_free(at);
1486 at->at_single_value = LDAP_SCHEMA_YES;
1488 } else if ( !strcmp(sval,"COLLECTIVE") ) {
1490 if ( at->at_collective ) {
1491 *code = LDAP_SCHERR_DUPOPT;
1493 ldap_attributetype_free(at);
1496 at->at_collective = LDAP_SCHEMA_YES;
1498 } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
1500 if ( at->at_no_user_mod ) {
1501 *code = LDAP_SCHERR_DUPOPT;
1503 ldap_attributetype_free(at);
1506 at->at_no_user_mod = LDAP_SCHEMA_YES;
1508 } else if ( !strcmp(sval,"USAGE") ) {
1511 *code = LDAP_SCHERR_DUPOPT;
1513 ldap_attributetype_free(at);
1518 kind = get_token(&ss,&sval);
1519 if ( kind != TK_BAREWORD ) {
1520 *code = LDAP_SCHERR_UNEXPTOKEN;
1523 ldap_attributetype_free(at);
1526 if ( !strcasecmp(sval,"userApplications") )
1528 LDAP_SCHEMA_USER_APPLICATIONS;
1529 else if ( !strcasecmp(sval,"directoryOperation") )
1531 LDAP_SCHEMA_DIRECTORY_OPERATION;
1532 else if ( !strcasecmp(sval,"distributedOperation") )
1534 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
1535 else if ( !strcasecmp(sval,"dSAOperation") )
1537 LDAP_SCHEMA_DSA_OPERATION;
1539 *code = LDAP_SCHERR_UNEXPTOKEN;
1542 ldap_attributetype_free(at);
1547 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1549 /* Should be parse_qdstrings */
1550 ssdummy = parse_qdescrs(&ss, code);
1553 ldap_attributetype_free(at);
1557 *code = LDAP_SCHERR_UNEXPTOKEN;
1560 ldap_attributetype_free(at);
1565 *code = LDAP_SCHERR_UNEXPTOKEN;
1568 ldap_attributetype_free(at);
1575 ldap_objectclass_free(LDAP_OBJECT_CLASS * oc)
1577 LDAP_FREE(oc->oc_oid);
1578 LDAP_VFREE(oc->oc_names);
1579 LDAP_FREE(oc->oc_desc);
1580 LDAP_VFREE(oc->oc_sup_oids);
1581 LDAP_VFREE(oc->oc_at_oids_must);
1582 LDAP_VFREE(oc->oc_at_oids_may);
1587 ldap_str2objectclass( const char * s, int * code, const char ** errp )
1590 const char * ss = s;
1592 int be_liberal = 1; /* Future additional argument */
1595 int seen_obsolete = 0;
1600 LDAP_OBJECT_CLASS * oc;
1602 const char * savepos;
1605 *code = LDAP_SCHERR_EMPTY;
1611 oc = LDAP_CALLOC(1,sizeof(LDAP_OBJECT_CLASS));
1614 *code = LDAP_SCHERR_OUTOFMEM;
1618 kind = get_token(&ss,&sval);
1619 if ( kind != TK_LEFTPAREN ) {
1620 *code = LDAP_SCHERR_NOLEFTPAREN;
1622 ldap_objectclass_free(oc);
1627 * Definitions MUST begin with an OID in the numericoid format.
1628 * However, this routine is used by clients to parse the response
1629 * from servers and very well known servers will provide an OID
1630 * in the wrong format or even no OID at all. We do our best to
1631 * extract info from those servers.
1635 oc->oc_oid = parse_numericoid(&ss,code,0);
1636 if ( !oc->oc_oid ) {
1640 kind = get_token(&ss,&sval);
1641 if ( kind == TK_BAREWORD ) {
1642 if ( !strcmp(sval, "NAME") ||
1643 !strcmp(sval, "DESC") ||
1644 !strcmp(sval, "OBSOLETE") ||
1645 !strcmp(sval, "SUP") ||
1646 !strcmp(sval, "ABSTRACT") ||
1647 !strcmp(sval, "STRUCTURAL") ||
1648 !strcmp(sval, "AUXILIARY") ||
1649 !strcmp(sval, "MUST") ||
1650 !strncmp(sval, "X-", 2) ) {
1651 /* Missing OID, backtrack */
1654 /* Non-numerical OID, ignore */
1660 ldap_objectclass_free(oc);
1667 * Beyond this point we will be liberal an accept the items
1671 kind = get_token(&ss,&sval);
1674 *code = LDAP_SCHERR_NORIGHTPAREN;
1676 ldap_objectclass_free(oc);
1681 if ( !strcmp(sval,"NAME") ) {
1684 *code = LDAP_SCHERR_DUPOPT;
1686 ldap_objectclass_free(oc);
1690 oc->oc_names = parse_qdescrs(&ss,code);
1691 if ( !oc->oc_names ) {
1692 if ( *code != LDAP_SCHERR_OUTOFMEM )
1693 *code = LDAP_SCHERR_BADNAME;
1695 ldap_objectclass_free(oc);
1698 } else if ( !strcmp(sval,"DESC") ) {
1701 *code = LDAP_SCHERR_DUPOPT;
1703 ldap_objectclass_free(oc);
1708 kind = get_token(&ss,&sval);
1709 if ( kind != TK_QDSTRING ) {
1710 *code = LDAP_SCHERR_UNEXPTOKEN;
1713 ldap_objectclass_free(oc);
1718 } else if ( !strcmp(sval,"OBSOLETE") ) {
1720 if ( seen_obsolete ) {
1721 *code = LDAP_SCHERR_DUPOPT;
1723 ldap_objectclass_free(oc);
1727 oc->oc_obsolete = LDAP_SCHEMA_YES;
1729 } else if ( !strcmp(sval,"SUP") ) {
1732 *code = LDAP_SCHERR_DUPOPT;
1734 ldap_objectclass_free(oc);
1738 oc->oc_sup_oids = parse_oids(&ss,
1741 if ( !oc->oc_sup_oids ) {
1743 ldap_objectclass_free(oc);
1746 } else if ( !strcmp(sval,"ABSTRACT") ) {
1749 *code = LDAP_SCHERR_DUPOPT;
1751 ldap_objectclass_free(oc);
1755 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
1757 } else if ( !strcmp(sval,"STRUCTURAL") ) {
1760 *code = LDAP_SCHERR_DUPOPT;
1762 ldap_objectclass_free(oc);
1766 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
1768 } else if ( !strcmp(sval,"AUXILIARY") ) {
1771 *code = LDAP_SCHERR_DUPOPT;
1773 ldap_objectclass_free(oc);
1777 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
1779 } else if ( !strcmp(sval,"MUST") ) {
1782 *code = LDAP_SCHERR_DUPOPT;
1784 ldap_objectclass_free(oc);
1788 oc->oc_at_oids_must = parse_oids(&ss,code,0);
1789 if ( !oc->oc_at_oids_must ) {
1791 ldap_objectclass_free(oc);
1795 } else if ( !strcmp(sval,"MAY") ) {
1798 *code = LDAP_SCHERR_DUPOPT;
1800 ldap_objectclass_free(oc);
1804 oc->oc_at_oids_may = parse_oids(&ss,code,0);
1805 if ( !oc->oc_at_oids_may ) {
1807 ldap_objectclass_free(oc);
1811 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1813 /* Should be parse_qdstrings */
1814 ssdummy = parse_qdescrs(&ss, code);
1817 ldap_objectclass_free(oc);
1821 *code = LDAP_SCHERR_UNEXPTOKEN;
1824 ldap_objectclass_free(oc);
1829 *code = LDAP_SCHERR_UNEXPTOKEN;
1832 ldap_objectclass_free(oc);
1838 static char *const err2text[] = {
1842 "Missing opening parenthesis",
1843 "Missing closing parenthesis",
1849 "Unexpected end of data"
1853 ldap_scherr2str(int code)
1855 if ( code < 1 || code >= (sizeof(err2text)/sizeof(char *)) ) {
1856 return "Unknown error";
1858 return err2text[code];