2 * Copyright 1999 The OpenLDAP Foundation, All Rights Reserved.
3 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6 * schema.c: parsing routines used by servers and clients to process
13 #include <ac/stdlib.h>
16 #include <ac/string.h>
21 #include <ldap_schema.h>
24 static LDAP_CONST char *
25 choose_name( char *names[], LDAP_CONST char *fallback )
27 return( (names != NULL && names[0] != NULL) ? names[0] : fallback );
31 ldap_syntax2name( LDAP_SYNTAX * syn )
33 return( syn->syn_oid );
37 ldap_matchingrule2name( LDAP_MATCHING_RULE * mr )
39 return( choose_name( mr->mr_names, mr->mr_oid ) );
43 ldap_attributetype2name( LDAP_ATTRIBUTE_TYPE * at )
45 return( choose_name( at->at_names, at->at_oid ) );
49 ldap_objectclass2name( LDAP_OBJECT_CLASS * oc )
51 return( choose_name( oc->oc_names, oc->oc_oid ) );
56 * When pretty printing the entities we will be appending to a buffer.
57 * Since checking for overflow, realloc'ing and checking if no error
58 * is extremely boring, we will use a protection layer that will let
59 * us blissfully ignore the error until the end. This layer is
60 * implemented with the help of the next type.
63 typedef struct safe_string {
71 new_safe_string(int size)
75 ss = LDAP_MALLOC(sizeof(safe_string));
79 ss->val = LDAP_MALLOC(size);
93 safe_string_free(safe_string * ss)
102 safe_string_val(safe_string * ss)
104 ss->val[ss->pos] = '\0';
109 append_to_safe_string(safe_string * ss, char * s)
115 * Some runaway process is trying to append to a string that
116 * overflowed and we could not extend.
121 /* We always make sure there is at least one position available */
122 if ( ss->pos + l >= ss->size-1 ) {
124 temp = LDAP_REALLOC(ss->val, ss->size);
126 /* Trouble, out of memory */
132 strncpy(&ss->val[ss->pos], s, l);
134 if ( ss->pos > 0 && isspace(ss->val[ss->pos-1]) )
143 print_literal(safe_string *ss, char *s)
145 return(append_to_safe_string(ss,s));
149 print_whsp(safe_string *ss)
152 return(append_to_safe_string(ss,""));
154 return(append_to_safe_string(ss," "));
158 print_numericoid(safe_string *ss, char *s)
161 return(append_to_safe_string(ss,s));
163 return(append_to_safe_string(ss,""));
166 /* This one is identical to print_qdescr */
168 print_qdstring(safe_string *ss, char *s)
171 print_literal(ss,"'");
172 append_to_safe_string(ss,s);
173 print_literal(ss,"'");
174 return(print_whsp(ss));
178 print_qdescr(safe_string *ss, char *s)
181 print_literal(ss,"'");
182 append_to_safe_string(ss,s);
183 print_literal(ss,"'");
184 return(print_whsp(ss));
188 print_qdescrlist(safe_string *ss, char **sa)
193 for (sp=sa; *sp; sp++) {
194 ret = print_qdescr(ss,*sp);
196 /* If the list was empty, we return zero that is potentially
197 * incorrect, but since we will be still appending things, the
198 * overflow will be detected later. Maybe FIX.
204 print_qdescrs(safe_string *ss, char **sa)
206 /* The only way to represent an empty list is as a qdescrlist
207 * so, if the list is empty we treat it as a long list.
208 * Really, this is what the syntax mandates. We should not
209 * be here if the list was empty, but if it happens, a label
210 * has already been output and we cannot undo it.
212 if ( !sa[0] || ( sa[0] && sa[1] ) ) {
214 print_literal(ss,"(");
215 print_qdescrlist(ss,sa);
216 print_literal(ss,")");
217 return(print_whsp(ss));
219 return(print_qdescr(ss,*sa));
224 print_woid(safe_string *ss, char *s)
227 append_to_safe_string(ss,s);
228 return print_whsp(ss);
232 print_oidlist(safe_string *ss, char **sa)
236 for (sp=sa; *(sp+1); sp++) {
238 print_literal(ss,"$");
240 return(print_woid(ss,*sp));
244 print_oids(safe_string *ss, char **sa)
246 if ( sa[0] && sa[1] ) {
247 print_literal(ss,"(");
248 print_oidlist(ss,sa);
250 return(print_literal(ss,")"));
252 return(print_woid(ss,*sa));
257 print_noidlen(safe_string *ss, char *s, int l)
262 ret = print_numericoid(ss,s);
264 sprintf(buf,"{%d}",l);
265 ret = print_literal(ss,buf);
271 ldap_syntax2str( const LDAP_SYNTAX * syn )
276 ss = new_safe_string(256);
280 print_literal(ss,"(");
283 print_numericoid(ss, syn->syn_oid);
286 if ( syn->syn_desc ) {
287 print_literal(ss,"DESC");
288 print_qdstring(ss,syn->syn_desc);
292 print_literal(ss,")");
294 retstring = LDAP_STRDUP(safe_string_val(ss));
295 safe_string_free(ss);
300 ldap_matchingrule2str( const LDAP_MATCHING_RULE * mr )
305 ss = new_safe_string(256);
309 print_literal(ss,"(");
312 print_numericoid(ss, mr->mr_oid);
315 if ( mr->mr_names ) {
316 print_literal(ss,"NAME");
317 print_qdescrs(ss,mr->mr_names);
321 print_literal(ss,"DESC");
322 print_qdstring(ss,mr->mr_desc);
325 if ( mr->mr_obsolete == LDAP_SCHEMA_YES ) {
326 print_literal(ss, "OBSOLETE");
330 if ( mr->mr_syntax_oid ) {
331 print_literal(ss,"SYNTAX");
333 print_literal(ss, mr->mr_syntax_oid);
338 print_literal(ss,")");
340 retstring = LDAP_STRDUP(safe_string_val(ss));
341 safe_string_free(ss);
346 ldap_objectclass2str( const LDAP_OBJECT_CLASS * oc )
351 ss = new_safe_string(256);
355 print_literal(ss,"(");
358 print_numericoid(ss, oc->oc_oid);
361 if ( oc->oc_names ) {
362 print_literal(ss,"NAME");
363 print_qdescrs(ss,oc->oc_names);
367 print_literal(ss,"DESC");
368 print_qdstring(ss,oc->oc_desc);
371 if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) {
372 print_literal(ss, "OBSOLETE");
376 if ( oc->oc_sup_oids ) {
377 print_literal(ss,"SUP");
379 print_oids(ss,oc->oc_sup_oids);
383 switch (oc->oc_kind) {
384 case LDAP_SCHEMA_ABSTRACT:
385 print_literal(ss,"ABSTRACT");
387 case LDAP_SCHEMA_STRUCTURAL:
388 print_literal(ss,"STRUCTURAL");
390 case LDAP_SCHEMA_AUXILIARY:
391 print_literal(ss,"AUXILIARY");
394 print_literal(ss,"KIND-UNKNOWN");
399 if ( oc->oc_at_oids_must ) {
400 print_literal(ss,"MUST");
402 print_oids(ss,oc->oc_at_oids_must);
406 if ( oc->oc_at_oids_may ) {
407 print_literal(ss,"MAY");
409 print_oids(ss,oc->oc_at_oids_may);
414 print_literal(ss,")");
416 retstring = LDAP_STRDUP(safe_string_val(ss));
417 safe_string_free(ss);
422 ldap_attributetype2str( const LDAP_ATTRIBUTE_TYPE * at )
427 ss = new_safe_string(256);
431 print_literal(ss,"(");
434 print_numericoid(ss, at->at_oid);
437 if ( at->at_names ) {
438 print_literal(ss,"NAME");
439 print_qdescrs(ss,at->at_names);
443 print_literal(ss,"DESC");
444 print_qdstring(ss,at->at_desc);
447 if ( at->at_obsolete == LDAP_SCHEMA_YES ) {
448 print_literal(ss, "OBSOLETE");
452 if ( at->at_sup_oid ) {
453 print_literal(ss,"SUP");
454 print_woid(ss,at->at_sup_oid);
457 if ( at->at_equality_oid ) {
458 print_literal(ss,"EQUALITY");
459 print_woid(ss,at->at_equality_oid);
462 if ( at->at_ordering_oid ) {
463 print_literal(ss,"ORDERING");
464 print_woid(ss,at->at_ordering_oid);
467 if ( at->at_substr_oid ) {
468 print_literal(ss,"SUBSTR");
469 print_woid(ss,at->at_substr_oid);
472 if ( at->at_syntax_oid ) {
473 print_literal(ss,"SYNTAX");
475 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
479 if ( at->at_single_value == LDAP_SCHEMA_YES ) {
480 print_literal(ss,"SINGLE-VALUE");
484 if ( at->at_collective == LDAP_SCHEMA_YES ) {
485 print_literal(ss,"COLLECTIVE");
489 if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
490 print_literal(ss,"NO-USER-MODIFICATION");
494 if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
495 print_literal(ss,"USAGE");
497 switch (at->at_usage) {
498 case LDAP_SCHEMA_DIRECTORY_OPERATION:
499 print_literal(ss,"directoryOperation");
501 case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
502 print_literal(ss,"distributedOperation");
504 case LDAP_SCHEMA_DSA_OPERATION:
505 print_literal(ss,"dSAOperation");
508 print_literal(ss,"UNKNOWN");
514 print_literal(ss,")");
516 retstring = LDAP_STRDUP(safe_string_val(ss));
517 safe_string_free(ss);
522 * Now come the parsers. There is one parser for each entity type:
523 * objectclasses, attributetypes, etc.
525 * Each of them is written as a recursive-descent parser, except that
526 * none of them is really recursive. But the idea is kept: there
527 * is one routine per non-terminal that eithers gobbles lexical tokens
528 * or calls lower-level routines, etc.
530 * The scanner is implemented in the routine get_token. Actually,
531 * get_token is more than a scanner and will return tokens that are
532 * in fact non-terminals in the grammar. So you can see the whole
533 * approach as the combination of a low-level bottom-up recognizer
534 * combined with a scanner and a number of top-down parsers. Or just
535 * consider that the real grammars recognized by the parsers are not
536 * those of the standards. As a matter of fact, our parsers are more
537 * liberal than the spec when there is no ambiguity.
539 * The difference is pretty academic (modulo bugs or incorrect
540 * interpretation of the specs).
543 #define TK_NOENDQUOTE -2
544 #define TK_OUTOFMEM -1
546 #define TK_UNEXPCHAR 1
547 #define TK_BAREWORD 2
548 #define TK_QDSTRING 3
549 #define TK_LEFTPAREN 4
550 #define TK_RIGHTPAREN 5
552 #define TK_QDESCR TK_QDSTRING
560 get_token(const char ** sp, char ** token_val)
578 kind = TK_RIGHTPAREN;
589 while ( **sp != '\'' && **sp != '\0' )
591 if ( **sp == '\'' ) {
593 res = LDAP_MALLOC(q-p+1);
603 kind = TK_NOENDQUOTE;
609 while ( !isspace(**sp) &&
617 res = LDAP_MALLOC(q-p+1);
626 /* kind = TK_UNEXPCHAR; */
633 /* Gobble optional whitespace */
635 parse_whsp(const char **sp)
637 while (isspace(**sp))
642 * General note for all parsers: to guarantee the algorithm halts they
643 * must always advance the pointer even when an error is found. For
644 * this one is not that important since an error here is fatal at the
645 * upper layers, but it is a simple strategy that will not get in
649 /* Parse a sequence of dot-separated decimal strings */
651 parse_numericoid(const char **sp, int *code, const int allow_quoted)
654 const char * start = *sp;
658 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
659 if ( allow_quoted && **sp == '\'' ) {
664 /* Each iteration of this loop gets one decimal string */
666 if ( !isdigit(**sp) ) {
668 * Initial char is not a digit or char after dot is
671 *code = LDAP_SCHERR_NODIGIT;
675 while ( isdigit(**sp) )
679 /* Otherwise, gobble the dot and loop again */
682 /* Now *sp points at the char past the numericoid. Perfect. */
684 res = LDAP_MALLOC(len+1);
686 *code = LDAP_SCHERR_OUTOFMEM;
689 strncpy(res,start,len);
691 if ( allow_quoted && quoted ) {
692 if ( **sp == '\'' ) {
695 *code = LDAP_SCHERR_UNEXPTOKEN;
703 /* Parse a qdescr or a list of them enclosed in () */
705 parse_qdescrs(const char **sp, int *code)
715 kind = get_token(sp,&sval);
716 if ( kind == TK_LEFTPAREN ) {
717 /* Let's presume there will be at least 2 entries */
719 res = LDAP_CALLOC(3,sizeof(char *));
721 *code = LDAP_SCHERR_OUTOFMEM;
727 kind = get_token(sp,&sval);
728 if ( kind == TK_RIGHTPAREN )
730 if ( kind == TK_QDESCR ) {
731 if ( pos == size-2 ) {
733 res1 = LDAP_REALLOC(res,size*sizeof(char *));
737 *code = LDAP_SCHERR_OUTOFMEM;
748 *code = LDAP_SCHERR_UNEXPTOKEN;
755 } else if ( kind == TK_QDESCR ) {
756 res = LDAP_CALLOC(2,sizeof(char *));
758 *code = LDAP_SCHERR_OUTOFMEM;
767 *code = LDAP_SCHERR_BADNAME;
774 parse_woid(const char **sp, int *code)
780 kind = get_token(sp, &sval);
781 if ( kind != TK_BAREWORD ) {
783 *code = LDAP_SCHERR_UNEXPTOKEN;
790 /* Parse a noidlen */
792 parse_noidlen(const char **sp, int *code, int *len, int allow_quoted)
798 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
799 if ( allow_quoted && **sp == '\'' ) {
803 sval = parse_numericoid(sp, code, 0);
810 while ( isdigit(**sp) )
813 *code = LDAP_SCHERR_UNEXPTOKEN;
819 if ( allow_quoted && quoted ) {
820 if ( **sp == '\'' ) {
823 *code = LDAP_SCHERR_UNEXPTOKEN;
832 * Next routine will accept a qdstring in place of an oid if
833 * allow_quoted is set. This is necessary to interoperate with
834 * Netscape Directory server that will improperly quote each oid (at
835 * least those of the descr kind) in the SUP clause.
838 /* Parse a woid or a $-separated list of them enclosed in () */
840 parse_oids(const char **sp, int *code, const int allow_quoted)
850 * Strictly speaking, doing this here accepts whsp before the
851 * ( at the begining of an oidlist, but this is harmless. Also,
852 * we are very liberal in what we accept as an OID. Maybe
856 kind = get_token(sp,&sval);
857 if ( kind == TK_LEFTPAREN ) {
858 /* Let's presume there will be at least 2 entries */
860 res = LDAP_CALLOC(3,sizeof(char *));
862 *code = LDAP_SCHERR_OUTOFMEM;
867 kind = get_token(sp,&sval);
868 if ( kind == TK_BAREWORD ||
869 ( allow_quoted && kind == TK_QDSTRING ) ) {
873 *code = LDAP_SCHERR_UNEXPTOKEN;
880 kind = get_token(sp,&sval);
881 if ( kind == TK_RIGHTPAREN )
883 if ( kind == TK_DOLLAR ) {
885 kind = get_token(sp,&sval);
886 if ( kind == TK_BAREWORD ||
888 kind == TK_QDSTRING ) ) {
889 if ( pos == size-2 ) {
891 res1 = LDAP_REALLOC(res,size*sizeof(char *));
895 *code = LDAP_SCHERR_OUTOFMEM;
903 *code = LDAP_SCHERR_UNEXPTOKEN;
910 *code = LDAP_SCHERR_UNEXPTOKEN;
919 } else if ( kind == TK_BAREWORD ||
920 ( allow_quoted && kind == TK_QDSTRING ) ) {
921 res = LDAP_CALLOC(2,sizeof(char *));
924 *code = LDAP_SCHERR_OUTOFMEM;
933 *code = LDAP_SCHERR_BADNAME;
939 ldap_syntax_free( LDAP_SYNTAX * syn )
941 LDAP_FREE(syn->syn_oid);
942 LDAP_FREE(syn->syn_desc);
947 ldap_str2syntax( const char * s, int * code, const char ** errp )
957 *code = LDAP_SCHERR_EMPTY;
963 syn = LDAP_CALLOC(1,sizeof(LDAP_SYNTAX));
966 *code = LDAP_SCHERR_OUTOFMEM;
970 kind = get_token(&ss,&sval);
971 if ( kind != TK_LEFTPAREN ) {
973 *code = LDAP_SCHERR_NOLEFTPAREN;
974 ldap_syntax_free(syn);
979 syn->syn_oid = parse_numericoid(&ss,code,0);
980 if ( !syn->syn_oid ) {
982 ldap_syntax_free(syn);
988 * Beyond this point we will be liberal and accept the items
992 kind = get_token(&ss,&sval);
995 *code = LDAP_SCHERR_NORIGHTPAREN;
997 ldap_syntax_free(syn);
1002 if ( !strcmp(sval,"DESC") ) {
1005 *code = LDAP_SCHERR_DUPOPT;
1007 ldap_syntax_free(syn);
1012 kind = get_token(&ss,&sval);
1013 if ( kind != TK_QDSTRING ) {
1014 *code = LDAP_SCHERR_UNEXPTOKEN;
1017 ldap_syntax_free(syn);
1020 syn->syn_desc = sval;
1022 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1024 /* Should be parse_qdstrings */
1025 ssdummy = parse_qdescrs(&ss, code);
1028 ldap_syntax_free(syn);
1032 *code = LDAP_SCHERR_UNEXPTOKEN;
1035 ldap_syntax_free(syn);
1040 *code = LDAP_SCHERR_UNEXPTOKEN;
1043 ldap_syntax_free(syn);
1050 ldap_matchingrule_free( LDAP_MATCHING_RULE * mr )
1052 LDAP_FREE(mr->mr_oid);
1053 LDAP_VFREE(mr->mr_names);
1054 LDAP_FREE(mr->mr_desc);
1055 LDAP_FREE(mr->mr_syntax_oid);
1059 LDAP_MATCHING_RULE *
1060 ldap_str2matchingrule( const char * s, int * code, const char ** errp )
1063 const char * ss = s;
1065 int be_liberal = 1; /* Future additional argument */
1068 int seen_obsolete = 0;
1069 int seen_syntax = 0;
1070 LDAP_MATCHING_RULE * mr;
1072 const char * savepos;
1075 *code = LDAP_SCHERR_EMPTY;
1081 mr = LDAP_CALLOC(1,sizeof(LDAP_MATCHING_RULE));
1084 *code = LDAP_SCHERR_OUTOFMEM;
1088 kind = get_token(&ss,&sval);
1089 if ( kind != TK_LEFTPAREN ) {
1090 *code = LDAP_SCHERR_NOLEFTPAREN;
1092 ldap_matchingrule_free(mr);
1098 mr->mr_oid = parse_numericoid(&ss,code,be_liberal);
1099 if ( !mr->mr_oid ) {
1103 kind = get_token(&ss,&sval);
1104 if ( kind == TK_BAREWORD ) {
1105 if ( !strcmp(sval, "NAME") ||
1106 !strcmp(sval, "DESC") ||
1107 !strcmp(sval, "OBSOLETE") ||
1108 !strcmp(sval, "SYNTAX") ||
1109 !strncmp(sval, "X-", 2) ) {
1110 /* Missing OID, backtrack */
1113 /* Non-numerical OID, ignore */
1119 ldap_matchingrule_free(mr);
1126 * Beyond this point we will be liberal and accept the items
1130 kind = get_token(&ss,&sval);
1133 *code = LDAP_SCHERR_NORIGHTPAREN;
1135 ldap_matchingrule_free(mr);
1140 if ( !strcmp(sval,"NAME") ) {
1143 *code = LDAP_SCHERR_DUPOPT;
1145 ldap_matchingrule_free(mr);
1149 mr->mr_names = parse_qdescrs(&ss,code);
1150 if ( !mr->mr_names ) {
1151 if ( *code != LDAP_SCHERR_OUTOFMEM )
1152 *code = LDAP_SCHERR_BADNAME;
1154 ldap_matchingrule_free(mr);
1157 } else if ( !strcmp(sval,"DESC") ) {
1160 *code = LDAP_SCHERR_DUPOPT;
1162 ldap_matchingrule_free(mr);
1167 kind = get_token(&ss,&sval);
1168 if ( kind != TK_QDSTRING ) {
1169 *code = LDAP_SCHERR_UNEXPTOKEN;
1172 ldap_matchingrule_free(mr);
1177 } else if ( !strcmp(sval,"OBSOLETE") ) {
1179 if ( seen_obsolete ) {
1180 *code = LDAP_SCHERR_DUPOPT;
1182 ldap_matchingrule_free(mr);
1186 mr->mr_obsolete = LDAP_SCHEMA_YES;
1188 } else if ( !strcmp(sval,"SYNTAX") ) {
1190 if ( seen_syntax ) {
1191 *code = LDAP_SCHERR_DUPOPT;
1193 ldap_matchingrule_free(mr);
1199 parse_numericoid(&ss,code,be_liberal);
1200 if ( !mr->mr_syntax_oid ) {
1202 ldap_matchingrule_free(mr);
1206 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1208 /* Should be parse_qdstrings */
1209 ssdummy = parse_qdescrs(&ss, code);
1212 ldap_matchingrule_free(mr);
1216 *code = LDAP_SCHERR_UNEXPTOKEN;
1219 ldap_matchingrule_free(mr);
1224 *code = LDAP_SCHERR_UNEXPTOKEN;
1227 ldap_matchingrule_free(mr);
1234 ldap_attributetype_free(LDAP_ATTRIBUTE_TYPE * at)
1236 LDAP_FREE(at->at_oid);
1237 LDAP_VFREE(at->at_names);
1238 LDAP_FREE(at->at_desc);
1239 LDAP_FREE(at->at_sup_oid);
1240 LDAP_FREE(at->at_equality_oid);
1241 LDAP_FREE(at->at_ordering_oid);
1242 LDAP_FREE(at->at_substr_oid);
1243 LDAP_FREE(at->at_syntax_oid);
1247 LDAP_ATTRIBUTE_TYPE *
1248 ldap_str2attributetype( const char * s, int * code, const char ** errp )
1251 const char * ss = s;
1253 int be_liberal = 1; /* Future additional argument */
1256 int seen_obsolete = 0;
1258 int seen_equality = 0;
1259 int seen_ordering = 0;
1260 int seen_substr = 0;
1261 int seen_syntax = 0;
1263 LDAP_ATTRIBUTE_TYPE * at;
1265 const char * savepos;
1268 *code = LDAP_SCHERR_EMPTY;
1274 at = LDAP_CALLOC(1,sizeof(LDAP_ATTRIBUTE_TYPE));
1277 *code = LDAP_SCHERR_OUTOFMEM;
1281 kind = get_token(&ss,&sval);
1282 if ( kind != TK_LEFTPAREN ) {
1283 *code = LDAP_SCHERR_NOLEFTPAREN;
1285 ldap_attributetype_free(at);
1290 * Definitions MUST begin with an OID in the numericoid format.
1291 * However, this routine is used by clients to parse the response
1292 * from servers and very well known servers will provide an OID
1293 * in the wrong format or even no OID at all. We do our best to
1294 * extract info from those servers.
1298 at->at_oid = parse_numericoid(&ss,code,0);
1299 if ( !at->at_oid ) {
1303 kind = get_token(&ss,&sval);
1304 if ( kind == TK_BAREWORD ) {
1305 if ( !strcmp(sval, "NAME") ||
1306 !strcmp(sval, "DESC") ||
1307 !strcmp(sval, "OBSOLETE") ||
1308 !strcmp(sval, "SUP") ||
1309 !strcmp(sval, "EQUALITY") ||
1310 !strcmp(sval, "ORDERING") ||
1311 !strcmp(sval, "SUBSTR") ||
1312 !strcmp(sval, "SYNTAX") ||
1313 !strcmp(sval, "SINGLE-VALUE") ||
1314 !strcmp(sval, "COLLECTIVE") ||
1315 !strcmp(sval, "NO-USER-MODIFICATION") ||
1316 !strcmp(sval, "USAGE") ||
1317 !strncmp(sval, "X-", 2) ) {
1318 /* Missing OID, backtrack */
1321 /* Non-numerical OID, ignore */
1327 ldap_attributetype_free(at);
1334 * Beyond this point we will be liberal and accept the items
1338 kind = get_token(&ss,&sval);
1341 *code = LDAP_SCHERR_NORIGHTPAREN;
1343 ldap_attributetype_free(at);
1348 if ( !strcmp(sval,"NAME") ) {
1351 *code = LDAP_SCHERR_DUPOPT;
1353 ldap_attributetype_free(at);
1357 at->at_names = parse_qdescrs(&ss,code);
1358 if ( !at->at_names ) {
1359 if ( *code != LDAP_SCHERR_OUTOFMEM )
1360 *code = LDAP_SCHERR_BADNAME;
1362 ldap_attributetype_free(at);
1365 } else if ( !strcmp(sval,"DESC") ) {
1368 *code = LDAP_SCHERR_DUPOPT;
1370 ldap_attributetype_free(at);
1375 kind = get_token(&ss,&sval);
1376 if ( kind != TK_QDSTRING ) {
1377 *code = LDAP_SCHERR_UNEXPTOKEN;
1380 ldap_attributetype_free(at);
1385 } else if ( !strcmp(sval,"OBSOLETE") ) {
1387 if ( seen_obsolete ) {
1388 *code = LDAP_SCHERR_DUPOPT;
1390 ldap_attributetype_free(at);
1394 at->at_obsolete = LDAP_SCHEMA_YES;
1396 } else if ( !strcmp(sval,"SUP") ) {
1399 *code = LDAP_SCHERR_DUPOPT;
1401 ldap_attributetype_free(at);
1405 at->at_sup_oid = parse_woid(&ss,code);
1406 if ( !at->at_sup_oid ) {
1408 ldap_attributetype_free(at);
1411 } else if ( !strcmp(sval,"EQUALITY") ) {
1413 if ( seen_equality ) {
1414 *code = LDAP_SCHERR_DUPOPT;
1416 ldap_attributetype_free(at);
1420 at->at_equality_oid = parse_woid(&ss,code);
1421 if ( !at->at_equality_oid ) {
1423 ldap_attributetype_free(at);
1426 } else if ( !strcmp(sval,"ORDERING") ) {
1428 if ( seen_ordering ) {
1429 *code = LDAP_SCHERR_DUPOPT;
1431 ldap_attributetype_free(at);
1435 at->at_ordering_oid = parse_woid(&ss,code);
1436 if ( !at->at_ordering_oid ) {
1438 ldap_attributetype_free(at);
1441 } else if ( !strcmp(sval,"SUBSTR") ) {
1443 if ( seen_substr ) {
1444 *code = LDAP_SCHERR_DUPOPT;
1446 ldap_attributetype_free(at);
1450 at->at_substr_oid = parse_woid(&ss,code);
1451 if ( !at->at_substr_oid ) {
1453 ldap_attributetype_free(at);
1456 } else if ( !strcmp(sval,"SYNTAX") ) {
1458 if ( seen_syntax ) {
1459 *code = LDAP_SCHERR_DUPOPT;
1461 ldap_attributetype_free(at);
1471 if ( !at->at_syntax_oid ) {
1473 ldap_attributetype_free(at);
1477 } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
1479 if ( at->at_single_value ) {
1480 *code = LDAP_SCHERR_DUPOPT;
1482 ldap_attributetype_free(at);
1485 at->at_single_value = LDAP_SCHEMA_YES;
1487 } else if ( !strcmp(sval,"COLLECTIVE") ) {
1489 if ( at->at_collective ) {
1490 *code = LDAP_SCHERR_DUPOPT;
1492 ldap_attributetype_free(at);
1495 at->at_collective = LDAP_SCHEMA_YES;
1497 } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
1499 if ( at->at_no_user_mod ) {
1500 *code = LDAP_SCHERR_DUPOPT;
1502 ldap_attributetype_free(at);
1505 at->at_no_user_mod = LDAP_SCHEMA_YES;
1507 } else if ( !strcmp(sval,"USAGE") ) {
1510 *code = LDAP_SCHERR_DUPOPT;
1512 ldap_attributetype_free(at);
1517 kind = get_token(&ss,&sval);
1518 if ( kind != TK_BAREWORD ) {
1519 *code = LDAP_SCHERR_UNEXPTOKEN;
1522 ldap_attributetype_free(at);
1525 if ( !strcasecmp(sval,"userApplications") )
1527 LDAP_SCHEMA_USER_APPLICATIONS;
1528 else if ( !strcasecmp(sval,"directoryOperation") )
1530 LDAP_SCHEMA_DIRECTORY_OPERATION;
1531 else if ( !strcasecmp(sval,"distributedOperation") )
1533 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
1534 else if ( !strcasecmp(sval,"dSAOperation") )
1536 LDAP_SCHEMA_DSA_OPERATION;
1538 *code = LDAP_SCHERR_UNEXPTOKEN;
1541 ldap_attributetype_free(at);
1546 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1548 /* Should be parse_qdstrings */
1549 ssdummy = parse_qdescrs(&ss, code);
1552 ldap_attributetype_free(at);
1556 *code = LDAP_SCHERR_UNEXPTOKEN;
1559 ldap_attributetype_free(at);
1564 *code = LDAP_SCHERR_UNEXPTOKEN;
1567 ldap_attributetype_free(at);
1574 ldap_objectclass_free(LDAP_OBJECT_CLASS * oc)
1576 LDAP_FREE(oc->oc_oid);
1577 LDAP_VFREE(oc->oc_names);
1578 LDAP_FREE(oc->oc_desc);
1579 LDAP_VFREE(oc->oc_sup_oids);
1580 LDAP_VFREE(oc->oc_at_oids_must);
1581 LDAP_VFREE(oc->oc_at_oids_may);
1586 ldap_str2objectclass( const char * s, int * code, const char ** errp )
1589 const char * ss = s;
1591 int be_liberal = 1; /* Future additional argument */
1594 int seen_obsolete = 0;
1599 LDAP_OBJECT_CLASS * oc;
1601 const char * savepos;
1604 *code = LDAP_SCHERR_EMPTY;
1610 oc = LDAP_CALLOC(1,sizeof(LDAP_OBJECT_CLASS));
1613 *code = LDAP_SCHERR_OUTOFMEM;
1617 kind = get_token(&ss,&sval);
1618 if ( kind != TK_LEFTPAREN ) {
1619 *code = LDAP_SCHERR_NOLEFTPAREN;
1621 ldap_objectclass_free(oc);
1626 * Definitions MUST begin with an OID in the numericoid format.
1627 * However, this routine is used by clients to parse the response
1628 * from servers and very well known servers will provide an OID
1629 * in the wrong format or even no OID at all. We do our best to
1630 * extract info from those servers.
1634 oc->oc_oid = parse_numericoid(&ss,code,0);
1635 if ( !oc->oc_oid ) {
1639 kind = get_token(&ss,&sval);
1640 if ( kind == TK_BAREWORD ) {
1641 if ( !strcmp(sval, "NAME") ||
1642 !strcmp(sval, "DESC") ||
1643 !strcmp(sval, "OBSOLETE") ||
1644 !strcmp(sval, "SUP") ||
1645 !strcmp(sval, "ABSTRACT") ||
1646 !strcmp(sval, "STRUCTURAL") ||
1647 !strcmp(sval, "AUXILIARY") ||
1648 !strcmp(sval, "MUST") ||
1649 !strncmp(sval, "X-", 2) ) {
1650 /* Missing OID, backtrack */
1653 /* Non-numerical OID, ignore */
1659 ldap_objectclass_free(oc);
1666 * Beyond this point we will be liberal an accept the items
1670 kind = get_token(&ss,&sval);
1673 *code = LDAP_SCHERR_NORIGHTPAREN;
1675 ldap_objectclass_free(oc);
1680 if ( !strcmp(sval,"NAME") ) {
1683 *code = LDAP_SCHERR_DUPOPT;
1685 ldap_objectclass_free(oc);
1689 oc->oc_names = parse_qdescrs(&ss,code);
1690 if ( !oc->oc_names ) {
1691 if ( *code != LDAP_SCHERR_OUTOFMEM )
1692 *code = LDAP_SCHERR_BADNAME;
1694 ldap_objectclass_free(oc);
1697 } else if ( !strcmp(sval,"DESC") ) {
1700 *code = LDAP_SCHERR_DUPOPT;
1702 ldap_objectclass_free(oc);
1707 kind = get_token(&ss,&sval);
1708 if ( kind != TK_QDSTRING ) {
1709 *code = LDAP_SCHERR_UNEXPTOKEN;
1712 ldap_objectclass_free(oc);
1717 } else if ( !strcmp(sval,"OBSOLETE") ) {
1719 if ( seen_obsolete ) {
1720 *code = LDAP_SCHERR_DUPOPT;
1722 ldap_objectclass_free(oc);
1726 oc->oc_obsolete = LDAP_SCHEMA_YES;
1728 } else if ( !strcmp(sval,"SUP") ) {
1731 *code = LDAP_SCHERR_DUPOPT;
1733 ldap_objectclass_free(oc);
1737 oc->oc_sup_oids = parse_oids(&ss,
1740 if ( !oc->oc_sup_oids ) {
1742 ldap_objectclass_free(oc);
1745 } else if ( !strcmp(sval,"ABSTRACT") ) {
1748 *code = LDAP_SCHERR_DUPOPT;
1750 ldap_objectclass_free(oc);
1754 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
1756 } else if ( !strcmp(sval,"STRUCTURAL") ) {
1759 *code = LDAP_SCHERR_DUPOPT;
1761 ldap_objectclass_free(oc);
1765 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
1767 } else if ( !strcmp(sval,"AUXILIARY") ) {
1770 *code = LDAP_SCHERR_DUPOPT;
1772 ldap_objectclass_free(oc);
1776 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
1778 } else if ( !strcmp(sval,"MUST") ) {
1781 *code = LDAP_SCHERR_DUPOPT;
1783 ldap_objectclass_free(oc);
1787 oc->oc_at_oids_must = parse_oids(&ss,code,0);
1788 if ( !oc->oc_at_oids_must ) {
1790 ldap_objectclass_free(oc);
1794 } else if ( !strcmp(sval,"MAY") ) {
1797 *code = LDAP_SCHERR_DUPOPT;
1799 ldap_objectclass_free(oc);
1803 oc->oc_at_oids_may = parse_oids(&ss,code,0);
1804 if ( !oc->oc_at_oids_may ) {
1806 ldap_objectclass_free(oc);
1810 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1812 /* Should be parse_qdstrings */
1813 ssdummy = parse_qdescrs(&ss, code);
1816 ldap_objectclass_free(oc);
1820 *code = LDAP_SCHERR_UNEXPTOKEN;
1823 ldap_objectclass_free(oc);
1828 *code = LDAP_SCHERR_UNEXPTOKEN;
1831 ldap_objectclass_free(oc);
1837 static char *const err2text[] = {
1841 "Missing opening parenthesis",
1842 "Missing closing parenthesis",
1848 "Unexpected end of data"
1852 ldap_scherr2str(int code)
1854 if ( code < 1 || code >= (sizeof(err2text)/sizeof(char *)) ) {
1855 return "Unknown error";
1857 return err2text[code];