2 * Copyright 1999 The OpenLDAP Foundation, All Rights Reserved.
3 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5 * schema.c: parsing routines used by servers and clients to process
12 #include <ac/stdlib.h>
15 #include <ac/string.h>
20 #include <ldap_schema.h>
23 * When pretty printing the entities we will be appending to a buffer.
24 * Since checking for overflow, realloc'ing and checking if no error
25 * is extremely boring, we will use a protection layer that will let
26 * us blissfully ignore the error until the end. This layer is
27 * implemented with the help of the next type.
30 typedef struct safe_string {
38 new_safe_string(int size)
42 ss = LDAP_MALLOC(sizeof(safe_string));
46 ss->val = LDAP_MALLOC(size);
60 safe_string_free(safe_string * ss)
69 safe_string_val(safe_string * ss)
71 ss->val[ss->pos] = '\0';
76 append_to_safe_string(safe_string * ss, char * s)
82 * Some runaway process is trying to append to a string that
83 * overflowed and we could not extend.
88 /* We always make sure there is at least one position available */
89 if ( ss->pos + l >= ss->size-1 ) {
91 temp = LDAP_REALLOC(ss->val, ss->size);
93 /* Trouble, out of memory */
99 strncpy(&ss->val[ss->pos], s, l);
101 if ( ss->pos > 0 && isspace(ss->val[ss->pos-1]) )
110 print_literal(safe_string *ss, char *s)
112 return(append_to_safe_string(ss,s));
116 print_whsp(safe_string *ss)
119 return(append_to_safe_string(ss,""));
121 return(append_to_safe_string(ss," "));
125 print_numericoid(safe_string *ss, char *s)
128 return(append_to_safe_string(ss,s));
130 return(append_to_safe_string(ss,""));
133 /* This one is identical to print_qdescr */
135 print_qdstring(safe_string *ss, char *s)
138 print_literal(ss,"'");
139 append_to_safe_string(ss,s);
140 print_literal(ss,"'");
141 return(print_whsp(ss));
145 print_qdescr(safe_string *ss, char *s)
148 print_literal(ss,"'");
149 append_to_safe_string(ss,s);
150 print_literal(ss,"'");
151 return(print_whsp(ss));
155 print_qdescrlist(safe_string *ss, char **sa)
160 for (sp=sa; *sp; sp++) {
161 ret = print_qdescr(ss,*sp);
163 /* If the list was empty, we return zero that is potentially
164 * incorrect, but since we will be still appending things, the
165 * overflow will be detected later. Maybe FIX.
171 print_qdescrs(safe_string *ss, char **sa)
173 /* The only way to represent an empty list is as a qdescrlist
174 * so, if the list is empty we treat it as a long list.
175 * Really, this is what the syntax mandates. We should not
176 * be here if the list was empty, but if it happens, a label
177 * has already been output and we cannot undo it.
179 if ( !sa[0] || ( sa[0] && sa[1] ) ) {
181 print_literal(ss,"(");
182 print_qdescrlist(ss,sa);
183 print_literal(ss,")");
184 return(print_whsp(ss));
186 return(print_qdescr(ss,*sa));
191 print_woid(safe_string *ss, char *s)
194 append_to_safe_string(ss,s);
195 return print_whsp(ss);
199 print_oidlist(safe_string *ss, char **sa)
203 for (sp=sa; *(sp+1); sp++) {
205 print_literal(ss,"$");
207 return(print_woid(ss,*sp));
211 print_oids(safe_string *ss, char **sa)
213 if ( sa[0] && sa[1] ) {
214 print_literal(ss,"(");
215 print_oidlist(ss,sa);
217 return(print_literal(ss,")"));
219 return(print_woid(ss,*sa));
224 print_noidlen(safe_string *ss, char *s, int l)
229 ret = print_numericoid(ss,s);
231 sprintf(buf,"{%d}",l);
232 ret = print_literal(ss,buf);
238 ldap_syntax2str( const LDAP_SYNTAX * syn )
243 ss = new_safe_string(256);
247 print_literal(ss,"(");
250 print_numericoid(ss, syn->syn_oid);
253 if ( syn->syn_desc ) {
254 print_literal(ss,"DESC");
255 print_qdstring(ss,syn->syn_desc);
259 print_literal(ss,")");
261 retstring = LDAP_STRDUP(safe_string_val(ss));
262 safe_string_free(ss);
267 ldap_matchingrule2str( const LDAP_MATCHING_RULE * mr )
272 ss = new_safe_string(256);
276 print_literal(ss,"(");
279 print_numericoid(ss, mr->mr_oid);
282 if ( mr->mr_names ) {
283 print_literal(ss,"NAME");
284 print_qdescrs(ss,mr->mr_names);
288 print_literal(ss,"DESC");
289 print_qdstring(ss,mr->mr_desc);
292 if ( mr->mr_obsolete == LDAP_SCHEMA_YES ) {
293 print_literal(ss, "OBSOLETE");
297 if ( mr->mr_syntax_oid ) {
298 print_literal(ss,"SYNTAX");
300 print_literal(ss, mr->mr_syntax_oid);
305 print_literal(ss,")");
307 retstring = LDAP_STRDUP(safe_string_val(ss));
308 safe_string_free(ss);
313 ldap_objectclass2str( const LDAP_OBJECT_CLASS * oc )
318 ss = new_safe_string(256);
322 print_literal(ss,"(");
325 print_numericoid(ss, oc->oc_oid);
328 if ( oc->oc_names ) {
329 print_literal(ss,"NAME");
330 print_qdescrs(ss,oc->oc_names);
334 print_literal(ss,"DESC");
335 print_qdstring(ss,oc->oc_desc);
338 if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) {
339 print_literal(ss, "OBSOLETE");
343 if ( oc->oc_sup_oids ) {
344 print_literal(ss,"SUP");
346 print_oids(ss,oc->oc_sup_oids);
350 switch (oc->oc_kind) {
351 case LDAP_SCHEMA_ABSTRACT:
352 print_literal(ss,"ABSTRACT");
354 case LDAP_SCHEMA_STRUCTURAL:
355 print_literal(ss,"STRUCTURAL");
357 case LDAP_SCHEMA_AUXILIARY:
358 print_literal(ss,"AUXILIARY");
361 print_literal(ss,"KIND-UNKNOWN");
366 if ( oc->oc_at_oids_must ) {
367 print_literal(ss,"MUST");
369 print_oids(ss,oc->oc_at_oids_must);
373 if ( oc->oc_at_oids_may ) {
374 print_literal(ss,"MAY");
376 print_oids(ss,oc->oc_at_oids_may);
381 print_literal(ss,")");
383 retstring = LDAP_STRDUP(safe_string_val(ss));
384 safe_string_free(ss);
389 ldap_attributetype2str( const LDAP_ATTRIBUTE_TYPE * at )
394 ss = new_safe_string(256);
398 print_literal(ss,"(");
401 print_numericoid(ss, at->at_oid);
404 if ( at->at_names ) {
405 print_literal(ss,"NAME");
406 print_qdescrs(ss,at->at_names);
410 print_literal(ss,"DESC");
411 print_qdstring(ss,at->at_desc);
414 if ( at->at_obsolete == LDAP_SCHEMA_YES ) {
415 print_literal(ss, "OBSOLETE");
419 if ( at->at_sup_oid ) {
420 print_literal(ss,"SUP");
421 print_woid(ss,at->at_sup_oid);
424 if ( at->at_equality_oid ) {
425 print_literal(ss,"EQUALITY");
426 print_woid(ss,at->at_equality_oid);
429 if ( at->at_ordering_oid ) {
430 print_literal(ss,"ORDERING");
431 print_woid(ss,at->at_ordering_oid);
434 if ( at->at_substr_oid ) {
435 print_literal(ss,"SUBSTR");
436 print_woid(ss,at->at_substr_oid);
439 if ( at->at_syntax_oid ) {
440 print_literal(ss,"SYNTAX");
442 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
446 if ( at->at_single_value == LDAP_SCHEMA_YES ) {
447 print_literal(ss,"SINGLE-VALUE");
451 if ( at->at_collective == LDAP_SCHEMA_YES ) {
452 print_literal(ss,"COLLECTIVE");
456 if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
457 print_literal(ss,"NO-USER-MODIFICATION");
461 if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
462 print_literal(ss,"USAGE");
464 switch (at->at_usage) {
465 case LDAP_SCHEMA_DIRECTORY_OPERATION:
466 print_literal(ss,"directoryOperation");
468 case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
469 print_literal(ss,"distributedOperation");
471 case LDAP_SCHEMA_DSA_OPERATION:
472 print_literal(ss,"dSAOperation");
475 print_literal(ss,"UNKNOWN");
481 print_literal(ss,")");
483 retstring = LDAP_STRDUP(safe_string_val(ss));
484 safe_string_free(ss);
489 * Now come the parsers. There is one parser for each entity type:
490 * objectclasses, attributetypes, etc.
492 * Each of them is written as a recursive-descent parser, except that
493 * none of them is really recursive. But the idea is kept: there
494 * is one routine per non-terminal that eithers gobbles lexical tokens
495 * or calls lower-level routines, etc.
497 * The scanner is implemented in the routine get_token. Actually,
498 * get_token is more than a scanner and will return tokens that are
499 * in fact non-terminals in the grammar. So you can see the whole
500 * approach as the combination of a low-level bottom-up recognizer
501 * combined with a scanner and a number of top-down parsers. Or just
502 * consider that the real grammars recognized by the parsers are not
503 * those of the standards. As a matter of fact, our parsers are more
504 * liberal than the spec when there is no ambiguity.
506 * The difference is pretty academic (modulo bugs or incorrect
507 * interpretation of the specs).
510 #define TK_NOENDQUOTE -2
511 #define TK_OUTOFMEM -1
513 #define TK_UNEXPCHAR 1
514 #define TK_BAREWORD 2
515 #define TK_QDSTRING 3
516 #define TK_LEFTPAREN 4
517 #define TK_RIGHTPAREN 5
519 #define TK_QDESCR TK_QDSTRING
527 get_token(const char ** sp, char ** token_val)
545 kind = TK_RIGHTPAREN;
556 while ( **sp != '\'' && **sp != '\0' )
558 if ( **sp == '\'' ) {
560 res = LDAP_MALLOC(q-p+1);
570 kind = TK_NOENDQUOTE;
576 while ( !isspace(**sp) &&
584 res = LDAP_MALLOC(q-p+1);
593 /* kind = TK_UNEXPCHAR; */
600 /* Gobble optional whitespace */
602 parse_whsp(const char **sp)
604 while (isspace(**sp))
609 * General note for all parsers: to guarantee the algorithm halts they
610 * must always advance the pointer even when an error is found. For
611 * this one is not that important since an error here is fatal at the
612 * upper layers, but it is a simple strategy that will not get in
616 /* Parse a sequence of dot-separated decimal strings */
618 parse_numericoid(const char **sp, int *code, const int allow_quoted)
621 const char * start = *sp;
625 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
626 if ( allow_quoted && **sp == '\'' ) {
631 /* Each iteration of this loop gets one decimal string */
633 if ( !isdigit(**sp) ) {
635 * Initial char is not a digit or char after dot is
638 *code = LDAP_SCHERR_NODIGIT;
642 while ( isdigit(**sp) )
646 /* Otherwise, gobble the dot and loop again */
649 /* Now *sp points at the char past the numericoid. Perfect. */
651 res = LDAP_MALLOC(len+1);
653 *code = LDAP_SCHERR_OUTOFMEM;
656 strncpy(res,start,len);
658 if ( allow_quoted && quoted ) {
659 if ( **sp == '\'' ) {
662 *code = LDAP_SCHERR_UNEXPTOKEN;
670 /* Parse a qdescr or a list of them enclosed in () */
672 parse_qdescrs(const char **sp, int *code)
682 kind = get_token(sp,&sval);
683 if ( kind == TK_LEFTPAREN ) {
684 /* Let's presume there will be at least 2 entries */
686 res = LDAP_CALLOC(3,sizeof(char *));
688 *code = LDAP_SCHERR_OUTOFMEM;
694 kind = get_token(sp,&sval);
695 if ( kind == TK_RIGHTPAREN )
697 if ( kind == TK_QDESCR ) {
698 if ( pos == size-2 ) {
700 res1 = LDAP_REALLOC(res,size*sizeof(char *));
704 *code = LDAP_SCHERR_OUTOFMEM;
715 *code = LDAP_SCHERR_UNEXPTOKEN;
722 } else if ( kind == TK_QDESCR ) {
723 res = LDAP_CALLOC(2,sizeof(char *));
725 *code = LDAP_SCHERR_OUTOFMEM;
734 *code = LDAP_SCHERR_BADNAME;
741 parse_woid(const char **sp, int *code)
747 kind = get_token(sp, &sval);
748 if ( kind != TK_BAREWORD ) {
750 *code = LDAP_SCHERR_UNEXPTOKEN;
757 /* Parse a noidlen */
759 parse_noidlen(const char **sp, int *code, int *len, int allow_quoted)
765 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
766 if ( allow_quoted && **sp == '\'' ) {
770 sval = parse_numericoid(sp, code, 0);
777 while ( isdigit(**sp) )
780 *code = LDAP_SCHERR_UNEXPTOKEN;
786 if ( allow_quoted && quoted ) {
787 if ( **sp == '\'' ) {
790 *code = LDAP_SCHERR_UNEXPTOKEN;
799 * Next routine will accept a qdstring in place of an oid if
800 * allow_quoted is set. This is necessary to interoperate with
801 * Netscape Directory server that will improperly quote each oid (at
802 * least those of the descr kind) in the SUP clause.
805 /* Parse a woid or a $-separated list of them enclosed in () */
807 parse_oids(const char **sp, int *code, const int allow_quoted)
817 * Strictly speaking, doing this here accepts whsp before the
818 * ( at the begining of an oidlist, but this is harmless. Also,
819 * we are very liberal in what we accept as an OID. Maybe
823 kind = get_token(sp,&sval);
824 if ( kind == TK_LEFTPAREN ) {
825 /* Let's presume there will be at least 2 entries */
827 res = LDAP_CALLOC(3,sizeof(char *));
829 *code = LDAP_SCHERR_OUTOFMEM;
834 kind = get_token(sp,&sval);
835 if ( kind == TK_BAREWORD ||
836 ( allow_quoted && kind == TK_QDSTRING ) ) {
840 *code = LDAP_SCHERR_UNEXPTOKEN;
847 kind = get_token(sp,&sval);
848 if ( kind == TK_RIGHTPAREN )
850 if ( kind == TK_DOLLAR ) {
852 kind = get_token(sp,&sval);
853 if ( kind == TK_BAREWORD ||
855 kind == TK_QDSTRING ) ) {
856 if ( pos == size-2 ) {
858 res1 = LDAP_REALLOC(res,size*sizeof(char *));
862 *code = LDAP_SCHERR_OUTOFMEM;
870 *code = LDAP_SCHERR_UNEXPTOKEN;
877 *code = LDAP_SCHERR_UNEXPTOKEN;
886 } else if ( kind == TK_BAREWORD ||
887 ( allow_quoted && kind == TK_QDSTRING ) ) {
888 res = LDAP_CALLOC(2,sizeof(char *));
891 *code = LDAP_SCHERR_OUTOFMEM;
900 *code = LDAP_SCHERR_BADNAME;
906 ldap_syntax_free( LDAP_SYNTAX * syn )
908 LDAP_FREE(syn->syn_oid);
909 LDAP_FREE(syn->syn_desc);
914 ldap_str2syntax( const char * s, int * code, const char ** errp )
924 *code = LDAP_SCHERR_EMPTY;
930 syn = LDAP_CALLOC(1,sizeof(LDAP_SYNTAX));
933 *code = LDAP_SCHERR_OUTOFMEM;
937 kind = get_token(&ss,&sval);
938 if ( kind != TK_LEFTPAREN ) {
940 *code = LDAP_SCHERR_NOLEFTPAREN;
941 ldap_syntax_free(syn);
946 syn->syn_oid = parse_numericoid(&ss,code,0);
947 if ( !syn->syn_oid ) {
949 ldap_syntax_free(syn);
955 * Beyond this point we will be liberal and accept the items
959 kind = get_token(&ss,&sval);
962 *code = LDAP_SCHERR_NORIGHTPAREN;
964 ldap_syntax_free(syn);
969 if ( !strcmp(sval,"DESC") ) {
972 *code = LDAP_SCHERR_DUPOPT;
974 ldap_syntax_free(syn);
979 kind = get_token(&ss,&sval);
980 if ( kind != TK_QDSTRING ) {
981 *code = LDAP_SCHERR_UNEXPTOKEN;
984 ldap_syntax_free(syn);
987 syn->syn_desc = sval;
989 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
991 /* Should be parse_qdstrings */
992 ssdummy = parse_qdescrs(&ss, code);
995 ldap_syntax_free(syn);
999 *code = LDAP_SCHERR_UNEXPTOKEN;
1002 ldap_syntax_free(syn);
1007 *code = LDAP_SCHERR_UNEXPTOKEN;
1010 ldap_syntax_free(syn);
1017 ldap_matchingrule_free( LDAP_MATCHING_RULE * mr )
1019 LDAP_FREE(mr->mr_oid);
1020 LDAP_VFREE(mr->mr_names);
1021 LDAP_FREE(mr->mr_desc);
1022 LDAP_FREE(mr->mr_syntax_oid);
1026 LDAP_MATCHING_RULE *
1027 ldap_str2matchingrule( const char * s, int * code, const char ** errp )
1030 const char * ss = s;
1032 int be_liberal = 1; /* Future additional argument */
1035 int seen_obsolete = 0;
1036 int seen_syntax = 0;
1037 LDAP_MATCHING_RULE * mr;
1039 const char * savepos;
1042 *code = LDAP_SCHERR_EMPTY;
1048 mr = LDAP_CALLOC(1,sizeof(LDAP_MATCHING_RULE));
1051 *code = LDAP_SCHERR_OUTOFMEM;
1055 kind = get_token(&ss,&sval);
1056 if ( kind != TK_LEFTPAREN ) {
1057 *code = LDAP_SCHERR_NOLEFTPAREN;
1059 ldap_matchingrule_free(mr);
1065 mr->mr_oid = parse_numericoid(&ss,code,be_liberal);
1066 if ( !mr->mr_oid ) {
1070 kind = get_token(&ss,&sval);
1071 if ( kind == TK_BAREWORD ) {
1072 if ( !strcmp(sval, "NAME") ||
1073 !strcmp(sval, "DESC") ||
1074 !strcmp(sval, "OBSOLETE") ||
1075 !strcmp(sval, "SYNTAX") ||
1076 !strncmp(sval, "X-", 2) ) {
1077 /* Missing OID, backtrack */
1080 /* Non-numerical OID, ignore */
1086 ldap_matchingrule_free(mr);
1093 * Beyond this point we will be liberal and accept the items
1097 kind = get_token(&ss,&sval);
1100 *code = LDAP_SCHERR_NORIGHTPAREN;
1102 ldap_matchingrule_free(mr);
1107 if ( !strcmp(sval,"NAME") ) {
1110 *code = LDAP_SCHERR_DUPOPT;
1112 ldap_matchingrule_free(mr);
1116 mr->mr_names = parse_qdescrs(&ss,code);
1117 if ( !mr->mr_names ) {
1118 if ( *code != LDAP_SCHERR_OUTOFMEM )
1119 *code = LDAP_SCHERR_BADNAME;
1121 ldap_matchingrule_free(mr);
1124 } else if ( !strcmp(sval,"DESC") ) {
1127 *code = LDAP_SCHERR_DUPOPT;
1129 ldap_matchingrule_free(mr);
1134 kind = get_token(&ss,&sval);
1135 if ( kind != TK_QDSTRING ) {
1136 *code = LDAP_SCHERR_UNEXPTOKEN;
1139 ldap_matchingrule_free(mr);
1144 } else if ( !strcmp(sval,"OBSOLETE") ) {
1146 if ( seen_obsolete ) {
1147 *code = LDAP_SCHERR_DUPOPT;
1149 ldap_matchingrule_free(mr);
1153 mr->mr_obsolete = LDAP_SCHEMA_YES;
1155 } else if ( !strcmp(sval,"SYNTAX") ) {
1157 if ( seen_syntax ) {
1158 *code = LDAP_SCHERR_DUPOPT;
1160 ldap_matchingrule_free(mr);
1166 parse_numericoid(&ss,code,be_liberal);
1167 if ( !mr->mr_syntax_oid ) {
1169 ldap_matchingrule_free(mr);
1173 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1175 /* Should be parse_qdstrings */
1176 ssdummy = parse_qdescrs(&ss, code);
1179 ldap_matchingrule_free(mr);
1183 *code = LDAP_SCHERR_UNEXPTOKEN;
1186 ldap_matchingrule_free(mr);
1191 *code = LDAP_SCHERR_UNEXPTOKEN;
1194 ldap_matchingrule_free(mr);
1201 ldap_attributetype_free(LDAP_ATTRIBUTE_TYPE * at)
1203 LDAP_FREE(at->at_oid);
1204 LDAP_VFREE(at->at_names);
1205 LDAP_FREE(at->at_desc);
1206 LDAP_FREE(at->at_sup_oid);
1207 LDAP_FREE(at->at_equality_oid);
1208 LDAP_FREE(at->at_ordering_oid);
1209 LDAP_FREE(at->at_substr_oid);
1210 LDAP_FREE(at->at_syntax_oid);
1214 LDAP_ATTRIBUTE_TYPE *
1215 ldap_str2attributetype( const char * s, int * code, const char ** errp )
1218 const char * ss = s;
1220 int be_liberal = 1; /* Future additional argument */
1223 int seen_obsolete = 0;
1225 int seen_equality = 0;
1226 int seen_ordering = 0;
1227 int seen_substr = 0;
1228 int seen_syntax = 0;
1233 LDAP_ATTRIBUTE_TYPE * at;
1235 const char * savepos;
1238 *code = LDAP_SCHERR_EMPTY;
1244 at = LDAP_CALLOC(1,sizeof(LDAP_ATTRIBUTE_TYPE));
1247 *code = LDAP_SCHERR_OUTOFMEM;
1251 kind = get_token(&ss,&sval);
1252 if ( kind != TK_LEFTPAREN ) {
1253 *code = LDAP_SCHERR_NOLEFTPAREN;
1255 ldap_attributetype_free(at);
1260 * Definitions MUST begin with an OID in the numericoid format.
1261 * However, this routine is used by clients to parse the response
1262 * from servers and very well known servers will provide an OID
1263 * in the wrong format or even no OID at all. We do our best to
1264 * extract info from those servers.
1268 at->at_oid = parse_numericoid(&ss,code,0);
1269 if ( !at->at_oid ) {
1273 kind = get_token(&ss,&sval);
1274 if ( kind == TK_BAREWORD ) {
1275 if ( !strcmp(sval, "NAME") ||
1276 !strcmp(sval, "DESC") ||
1277 !strcmp(sval, "OBSOLETE") ||
1278 !strcmp(sval, "SUP") ||
1279 !strcmp(sval, "EQUALITY") ||
1280 !strcmp(sval, "ORDERING") ||
1281 !strcmp(sval, "SUBSTR") ||
1282 !strcmp(sval, "SYNTAX") ||
1283 !strcmp(sval, "SINGLE-VALUE") ||
1284 !strcmp(sval, "COLLECTIVE") ||
1285 !strcmp(sval, "NO-USER-MODIFICATION") ||
1286 !strcmp(sval, "USAGE") ||
1287 !strncmp(sval, "X-", 2) ) {
1288 /* Missing OID, backtrack */
1291 /* Non-numerical OID, ignore */
1297 ldap_attributetype_free(at);
1304 * Beyond this point we will be liberal and accept the items
1308 kind = get_token(&ss,&sval);
1311 *code = LDAP_SCHERR_NORIGHTPAREN;
1313 ldap_attributetype_free(at);
1318 if ( !strcmp(sval,"NAME") ) {
1321 *code = LDAP_SCHERR_DUPOPT;
1323 ldap_attributetype_free(at);
1327 at->at_names = parse_qdescrs(&ss,code);
1328 if ( !at->at_names ) {
1329 if ( *code != LDAP_SCHERR_OUTOFMEM )
1330 *code = LDAP_SCHERR_BADNAME;
1332 ldap_attributetype_free(at);
1335 } else if ( !strcmp(sval,"DESC") ) {
1338 *code = LDAP_SCHERR_DUPOPT;
1340 ldap_attributetype_free(at);
1345 kind = get_token(&ss,&sval);
1346 if ( kind != TK_QDSTRING ) {
1347 *code = LDAP_SCHERR_UNEXPTOKEN;
1350 ldap_attributetype_free(at);
1355 } else if ( !strcmp(sval,"OBSOLETE") ) {
1357 if ( seen_obsolete ) {
1358 *code = LDAP_SCHERR_DUPOPT;
1360 ldap_attributetype_free(at);
1364 at->at_obsolete = LDAP_SCHEMA_YES;
1366 } else if ( !strcmp(sval,"SUP") ) {
1369 *code = LDAP_SCHERR_DUPOPT;
1371 ldap_attributetype_free(at);
1375 at->at_sup_oid = parse_woid(&ss,code);
1376 if ( !at->at_sup_oid ) {
1378 ldap_attributetype_free(at);
1381 } else if ( !strcmp(sval,"EQUALITY") ) {
1383 if ( seen_equality ) {
1384 *code = LDAP_SCHERR_DUPOPT;
1386 ldap_attributetype_free(at);
1390 at->at_equality_oid = parse_woid(&ss,code);
1391 if ( !at->at_equality_oid ) {
1393 ldap_attributetype_free(at);
1396 } else if ( !strcmp(sval,"ORDERING") ) {
1398 if ( seen_ordering ) {
1399 *code = LDAP_SCHERR_DUPOPT;
1401 ldap_attributetype_free(at);
1405 at->at_ordering_oid = parse_woid(&ss,code);
1406 if ( !at->at_ordering_oid ) {
1408 ldap_attributetype_free(at);
1411 } else if ( !strcmp(sval,"SUBSTR") ) {
1413 if ( seen_substr ) {
1414 *code = LDAP_SCHERR_DUPOPT;
1416 ldap_attributetype_free(at);
1420 at->at_substr_oid = parse_woid(&ss,code);
1421 if ( !at->at_substr_oid ) {
1423 ldap_attributetype_free(at);
1426 } else if ( !strcmp(sval,"SYNTAX") ) {
1428 if ( seen_syntax ) {
1429 *code = LDAP_SCHERR_DUPOPT;
1431 ldap_attributetype_free(at);
1441 if ( !at->at_syntax_oid ) {
1443 ldap_attributetype_free(at);
1447 } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
1449 if ( at->at_single_value ) {
1450 *code = LDAP_SCHERR_DUPOPT;
1452 ldap_attributetype_free(at);
1455 at->at_single_value = LDAP_SCHEMA_YES;
1457 } else if ( !strcmp(sval,"COLLECTIVE") ) {
1459 if ( at->at_collective ) {
1460 *code = LDAP_SCHERR_DUPOPT;
1462 ldap_attributetype_free(at);
1465 at->at_collective = LDAP_SCHEMA_YES;
1467 } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
1469 if ( at->at_no_user_mod ) {
1470 *code = LDAP_SCHERR_DUPOPT;
1472 ldap_attributetype_free(at);
1475 at->at_no_user_mod = LDAP_SCHEMA_YES;
1477 } else if ( !strcmp(sval,"USAGE") ) {
1480 *code = LDAP_SCHERR_DUPOPT;
1482 ldap_attributetype_free(at);
1487 kind = get_token(&ss,&sval);
1488 if ( kind != TK_BAREWORD ) {
1489 *code = LDAP_SCHERR_UNEXPTOKEN;
1492 ldap_attributetype_free(at);
1495 if ( !strcasecmp(sval,"userApplications") )
1497 LDAP_SCHEMA_USER_APPLICATIONS;
1498 else if ( !strcasecmp(sval,"directoryOperation") )
1500 LDAP_SCHEMA_DIRECTORY_OPERATION;
1501 else if ( !strcasecmp(sval,"distributedOperation") )
1503 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
1504 else if ( !strcasecmp(sval,"dSAOperation") )
1506 LDAP_SCHEMA_DSA_OPERATION;
1508 *code = LDAP_SCHERR_UNEXPTOKEN;
1511 ldap_attributetype_free(at);
1516 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1518 /* Should be parse_qdstrings */
1519 ssdummy = parse_qdescrs(&ss, code);
1522 ldap_attributetype_free(at);
1526 *code = LDAP_SCHERR_UNEXPTOKEN;
1529 ldap_attributetype_free(at);
1534 *code = LDAP_SCHERR_UNEXPTOKEN;
1537 ldap_attributetype_free(at);
1544 ldap_objectclass_free(LDAP_OBJECT_CLASS * oc)
1546 LDAP_FREE(oc->oc_oid);
1547 LDAP_VFREE(oc->oc_names);
1548 LDAP_FREE(oc->oc_desc);
1549 LDAP_VFREE(oc->oc_sup_oids);
1550 LDAP_VFREE(oc->oc_at_oids_must);
1551 LDAP_VFREE(oc->oc_at_oids_may);
1556 ldap_str2objectclass( const char * s, int * code, const char ** errp )
1559 const char * ss = s;
1561 int be_liberal = 1; /* Future additional argument */
1564 int seen_obsolete = 0;
1569 LDAP_OBJECT_CLASS * oc;
1571 const char * savepos;
1574 *code = LDAP_SCHERR_EMPTY;
1580 oc = LDAP_CALLOC(1,sizeof(LDAP_OBJECT_CLASS));
1583 *code = LDAP_SCHERR_OUTOFMEM;
1587 kind = get_token(&ss,&sval);
1588 if ( kind != TK_LEFTPAREN ) {
1589 *code = LDAP_SCHERR_NOLEFTPAREN;
1591 ldap_objectclass_free(oc);
1596 * Definitions MUST begin with an OID in the numericoid format.
1597 * However, this routine is used by clients to parse the response
1598 * from servers and very well known servers will provide an OID
1599 * in the wrong format or even no OID at all. We do our best to
1600 * extract info from those servers.
1604 oc->oc_oid = parse_numericoid(&ss,code,0);
1605 if ( !oc->oc_oid ) {
1609 kind = get_token(&ss,&sval);
1610 if ( kind == TK_BAREWORD ) {
1611 if ( !strcmp(sval, "NAME") ||
1612 !strcmp(sval, "DESC") ||
1613 !strcmp(sval, "OBSOLETE") ||
1614 !strcmp(sval, "SUP") ||
1615 !strcmp(sval, "ABSTRACT") ||
1616 !strcmp(sval, "STRUCTURAL") ||
1617 !strcmp(sval, "AUXILIARY") ||
1618 !strcmp(sval, "MUST") ||
1619 !strncmp(sval, "X-", 2) ) {
1620 /* Missing OID, backtrack */
1623 /* Non-numerical OID, ignore */
1629 ldap_objectclass_free(oc);
1636 * Beyond this point we will be liberal an accept the items
1640 kind = get_token(&ss,&sval);
1643 *code = LDAP_SCHERR_NORIGHTPAREN;
1645 ldap_objectclass_free(oc);
1650 if ( !strcmp(sval,"NAME") ) {
1653 *code = LDAP_SCHERR_DUPOPT;
1655 ldap_objectclass_free(oc);
1659 oc->oc_names = parse_qdescrs(&ss,code);
1660 if ( !oc->oc_names ) {
1661 if ( *code != LDAP_SCHERR_OUTOFMEM )
1662 *code = LDAP_SCHERR_BADNAME;
1664 ldap_objectclass_free(oc);
1667 } else if ( !strcmp(sval,"DESC") ) {
1670 *code = LDAP_SCHERR_DUPOPT;
1672 ldap_objectclass_free(oc);
1677 kind = get_token(&ss,&sval);
1678 if ( kind != TK_QDSTRING ) {
1679 *code = LDAP_SCHERR_UNEXPTOKEN;
1682 ldap_objectclass_free(oc);
1687 } else if ( !strcmp(sval,"OBSOLETE") ) {
1689 if ( seen_obsolete ) {
1690 *code = LDAP_SCHERR_DUPOPT;
1692 ldap_objectclass_free(oc);
1696 oc->oc_obsolete = LDAP_SCHEMA_YES;
1698 } else if ( !strcmp(sval,"SUP") ) {
1701 *code = LDAP_SCHERR_DUPOPT;
1703 ldap_objectclass_free(oc);
1707 oc->oc_sup_oids = parse_oids(&ss,
1710 if ( !oc->oc_sup_oids ) {
1712 ldap_objectclass_free(oc);
1715 } else if ( !strcmp(sval,"ABSTRACT") ) {
1718 *code = LDAP_SCHERR_DUPOPT;
1720 ldap_objectclass_free(oc);
1724 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
1726 } else if ( !strcmp(sval,"STRUCTURAL") ) {
1729 *code = LDAP_SCHERR_DUPOPT;
1731 ldap_objectclass_free(oc);
1735 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
1737 } else if ( !strcmp(sval,"AUXILIARY") ) {
1740 *code = LDAP_SCHERR_DUPOPT;
1742 ldap_objectclass_free(oc);
1746 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
1748 } else if ( !strcmp(sval,"MUST") ) {
1751 *code = LDAP_SCHERR_DUPOPT;
1753 ldap_objectclass_free(oc);
1757 oc->oc_at_oids_must = parse_oids(&ss,code,0);
1758 if ( !oc->oc_at_oids_must ) {
1760 ldap_objectclass_free(oc);
1764 } else if ( !strcmp(sval,"MAY") ) {
1767 *code = LDAP_SCHERR_DUPOPT;
1769 ldap_objectclass_free(oc);
1773 oc->oc_at_oids_may = parse_oids(&ss,code,0);
1774 if ( !oc->oc_at_oids_may ) {
1776 ldap_objectclass_free(oc);
1780 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1782 /* Should be parse_qdstrings */
1783 ssdummy = parse_qdescrs(&ss, code);
1786 ldap_objectclass_free(oc);
1790 *code = LDAP_SCHERR_UNEXPTOKEN;
1793 ldap_objectclass_free(oc);
1798 *code = LDAP_SCHERR_UNEXPTOKEN;
1801 ldap_objectclass_free(oc);
1807 static char *err2text[] = {
1811 "Missing opening parenthesis",
1812 "Missing closing parenthesis",
1818 "Unexpected end of data"
1822 ldap_scherr2str(int code)
1824 if ( code < 1 || code >= (sizeof(err2text)/sizeof(char *)) ) {
1825 return "Unknown error";
1827 return err2text[code];