No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / openldap / dist / libraries / libldap / schema.c
blobe12cffecb44bb1331f0c9e86ce632a0a01dc207e
1 /* $OpenLDAP: pkg/ldap/libraries/libldap/schema.c,v 1.77.2.4 2008/04/14 22:32:48 quanah Exp $ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2008 The OpenLDAP Foundation.
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
9 * Public License.
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
17 * schema.c: parsing routines used by servers and clients to process
18 * schema definitions
21 #include "portable.h"
23 #include <stdio.h>
24 #include <ac/stdlib.h>
26 #include <ac/string.h>
27 #include <ac/time.h>
29 #include "ldap-int.h"
31 #include <ldap_schema.h>
33 static const char EndOfInput[] = "end of input";
35 static const char *
36 choose_name( char *names[], const char *fallback )
38 return (names != NULL && names[0] != NULL) ? names[0] : fallback;
41 LDAP_CONST char *
42 ldap_syntax2name( LDAPSyntax * syn )
44 return( syn->syn_oid );
47 LDAP_CONST char *
48 ldap_matchingrule2name( LDAPMatchingRule * mr )
50 return( choose_name( mr->mr_names, mr->mr_oid ) );
53 LDAP_CONST char *
54 ldap_matchingruleuse2name( LDAPMatchingRuleUse * mru )
56 return( choose_name( mru->mru_names, mru->mru_oid ) );
59 LDAP_CONST char *
60 ldap_attributetype2name( LDAPAttributeType * at )
62 return( choose_name( at->at_names, at->at_oid ) );
65 LDAP_CONST char *
66 ldap_objectclass2name( LDAPObjectClass * oc )
68 return( choose_name( oc->oc_names, oc->oc_oid ) );
71 LDAP_CONST char *
72 ldap_contentrule2name( LDAPContentRule * cr )
74 return( choose_name( cr->cr_names, cr->cr_oid ) );
77 LDAP_CONST char *
78 ldap_nameform2name( LDAPNameForm * nf )
80 return( choose_name( nf->nf_names, nf->nf_oid ) );
83 LDAP_CONST char *
84 ldap_structurerule2name( LDAPStructureRule * sr )
86 return( choose_name( sr->sr_names, NULL ) );
90 * When pretty printing the entities we will be appending to a buffer.
91 * Since checking for overflow, realloc'ing and checking if no error
92 * is extremely boring, we will use a protection layer that will let
93 * us blissfully ignore the error until the end. This layer is
94 * implemented with the help of the next type.
97 typedef struct safe_string {
98 char * val;
99 ber_len_t size;
100 ber_len_t pos;
101 int at_whsp;
102 } safe_string;
104 static safe_string *
105 new_safe_string(int size)
107 safe_string * ss;
109 ss = LDAP_MALLOC(sizeof(safe_string));
110 if ( !ss )
111 return(NULL);
113 ss->val = LDAP_MALLOC(size);
114 if ( !ss->val ) {
115 LDAP_FREE(ss);
116 return(NULL);
119 ss->size = size;
120 ss->pos = 0;
121 ss->at_whsp = 0;
123 return ss;
126 static void
127 safe_string_free(safe_string * ss)
129 if ( !ss )
130 return;
131 LDAP_FREE(ss->val);
132 LDAP_FREE(ss);
135 #if 0 /* unused */
136 static char *
137 safe_string_val(safe_string * ss)
139 ss->val[ss->pos] = '\0';
140 return(ss->val);
142 #endif
144 static char *
145 safe_strdup(safe_string * ss)
147 char *ret = LDAP_MALLOC(ss->pos+1);
148 if (!ret)
149 return NULL;
150 AC_MEMCPY(ret, ss->val, ss->pos);
151 ret[ss->pos] = '\0';
152 return ret;
155 static int
156 append_to_safe_string(safe_string * ss, char * s)
158 int l = strlen(s);
159 char * temp;
162 * Some runaway process is trying to append to a string that
163 * overflowed and we could not extend.
165 if ( !ss->val )
166 return -1;
168 /* We always make sure there is at least one position available */
169 if ( ss->pos + l >= ss->size-1 ) {
170 ss->size *= 2;
171 if ( ss->pos + l >= ss->size-1 ) {
172 ss->size = ss->pos + l + 1;
175 temp = LDAP_REALLOC(ss->val, ss->size);
176 if ( !temp ) {
177 /* Trouble, out of memory */
178 LDAP_FREE(ss->val);
179 return -1;
181 ss->val = temp;
183 strncpy(&ss->val[ss->pos], s, l);
184 ss->pos += l;
185 if ( ss->pos > 0 && LDAP_SPACE(ss->val[ss->pos-1]) )
186 ss->at_whsp = 1;
187 else
188 ss->at_whsp = 0;
190 return 0;
193 static int
194 print_literal(safe_string *ss, char *s)
196 return(append_to_safe_string(ss,s));
199 static int
200 print_whsp(safe_string *ss)
202 if ( ss->at_whsp )
203 return(append_to_safe_string(ss,""));
204 else
205 return(append_to_safe_string(ss," "));
208 static int
209 print_numericoid(safe_string *ss, char *s)
211 if ( s )
212 return(append_to_safe_string(ss,s));
213 else
214 return(append_to_safe_string(ss,""));
217 /* This one is identical to print_qdescr */
218 static int
219 print_qdstring(safe_string *ss, char *s)
221 print_whsp(ss);
222 print_literal(ss,"'");
223 append_to_safe_string(ss,s);
224 print_literal(ss,"'");
225 return(print_whsp(ss));
228 static int
229 print_qdescr(safe_string *ss, char *s)
231 print_whsp(ss);
232 print_literal(ss,"'");
233 append_to_safe_string(ss,s);
234 print_literal(ss,"'");
235 return(print_whsp(ss));
238 static int
239 print_qdescrlist(safe_string *ss, char **sa)
241 char **sp;
242 int ret = 0;
244 for (sp=sa; *sp; sp++) {
245 ret = print_qdescr(ss,*sp);
247 /* If the list was empty, we return zero that is potentially
248 * incorrect, but since we will be still appending things, the
249 * overflow will be detected later. Maybe FIX.
251 return(ret);
254 static int
255 print_qdescrs(safe_string *ss, char **sa)
257 /* The only way to represent an empty list is as a qdescrlist
258 * so, if the list is empty we treat it as a long list.
259 * Really, this is what the syntax mandates. We should not
260 * be here if the list was empty, but if it happens, a label
261 * has already been output and we cannot undo it.
263 if ( !sa[0] || ( sa[0] && sa[1] ) ) {
264 print_whsp(ss);
265 print_literal(ss,"("/*)*/);
266 print_qdescrlist(ss,sa);
267 print_literal(ss,/*(*/")");
268 return(print_whsp(ss));
269 } else {
270 return(print_qdescr(ss,*sa));
274 static int
275 print_woid(safe_string *ss, char *s)
277 print_whsp(ss);
278 append_to_safe_string(ss,s);
279 return print_whsp(ss);
282 static int
283 print_oidlist(safe_string *ss, char **sa)
285 char **sp;
287 for (sp=sa; *(sp+1); sp++) {
288 print_woid(ss,*sp);
289 print_literal(ss,"$");
291 return(print_woid(ss,*sp));
294 static int
295 print_oids(safe_string *ss, char **sa)
297 if ( sa[0] && sa[1] ) {
298 print_literal(ss,"("/*)*/);
299 print_oidlist(ss,sa);
300 print_whsp(ss);
301 return(print_literal(ss,/*(*/")"));
302 } else {
303 return(print_woid(ss,*sa));
307 static int
308 print_noidlen(safe_string *ss, char *s, int l)
310 char buf[64];
311 int ret;
313 ret = print_numericoid(ss,s);
314 if ( l ) {
315 snprintf(buf, sizeof buf, "{%d}",l);
316 ret = print_literal(ss,buf);
318 return(ret);
321 static int
322 print_ruleid(safe_string *ss, int rid)
324 char buf[64];
325 snprintf(buf, sizeof buf, "%d", rid);
326 return print_literal(ss,buf);
329 static int
330 print_ruleids(safe_string *ss, int n, int *rids)
332 int i;
334 if( n == 1 ) {
335 print_ruleid(ss,rids[0]);
336 return print_whsp(ss);
337 } else {
338 print_literal(ss,"("/*)*/);
339 for( i=0; i<n; i++ ) {
340 print_whsp(ss);
341 print_ruleid(ss,rids[i]);
343 print_whsp(ss);
344 return print_literal(ss,/*(*/")");
349 static int
350 print_extensions(safe_string *ss, LDAPSchemaExtensionItem **extensions)
352 LDAPSchemaExtensionItem **ext;
354 if ( extensions ) {
355 print_whsp(ss);
356 for ( ext = extensions; *ext != NULL; ext++ ) {
357 print_literal(ss, (*ext)->lsei_name);
358 print_whsp(ss);
359 /* Should be print_qdstrings */
360 print_qdescrs(ss, (*ext)->lsei_values);
361 print_whsp(ss);
365 return 0;
368 char *
369 ldap_syntax2str( LDAPSyntax * syn )
371 struct berval bv;
372 if (ldap_syntax2bv( syn, &bv ))
373 return(bv.bv_val);
374 else
375 return NULL;
378 struct berval *
379 ldap_syntax2bv( LDAPSyntax * syn, struct berval *bv )
381 safe_string * ss;
383 ss = new_safe_string(256);
384 if ( !ss )
385 return NULL;
387 print_literal(ss,"("/*)*/);
388 print_whsp(ss);
390 print_numericoid(ss, syn->syn_oid);
391 print_whsp(ss);
393 if ( syn->syn_desc ) {
394 print_literal(ss,"DESC");
395 print_qdstring(ss,syn->syn_desc);
398 print_whsp(ss);
400 print_extensions(ss, syn->syn_extensions);
402 print_literal(ss,/*(*/ ")");
404 bv->bv_val = safe_strdup(ss);
405 bv->bv_len = ss->pos;
406 safe_string_free(ss);
407 return(bv);
410 char *
411 ldap_matchingrule2str( LDAPMatchingRule * mr )
413 struct berval bv;
414 if (ldap_matchingrule2bv( mr, &bv ))
415 return(bv.bv_val);
416 else
417 return NULL;
420 struct berval *
421 ldap_matchingrule2bv( LDAPMatchingRule * mr, struct berval *bv )
423 safe_string * ss;
425 ss = new_safe_string(256);
426 if ( !ss )
427 return NULL;
429 print_literal(ss,"(" /*)*/);
430 print_whsp(ss);
432 print_numericoid(ss, mr->mr_oid);
433 print_whsp(ss);
435 if ( mr->mr_names ) {
436 print_literal(ss,"NAME");
437 print_qdescrs(ss,mr->mr_names);
440 if ( mr->mr_desc ) {
441 print_literal(ss,"DESC");
442 print_qdstring(ss,mr->mr_desc);
445 if ( mr->mr_obsolete ) {
446 print_literal(ss, "OBSOLETE");
447 print_whsp(ss);
450 if ( mr->mr_syntax_oid ) {
451 print_literal(ss,"SYNTAX");
452 print_whsp(ss);
453 print_literal(ss, mr->mr_syntax_oid);
454 print_whsp(ss);
457 print_whsp(ss);
459 print_extensions(ss, mr->mr_extensions);
461 print_literal(ss,/*(*/")");
463 bv->bv_val = safe_strdup(ss);
464 bv->bv_len = ss->pos;
465 safe_string_free(ss);
466 return(bv);
469 char *
470 ldap_matchingruleuse2str( LDAPMatchingRuleUse * mru )
472 struct berval bv;
473 if (ldap_matchingruleuse2bv( mru, &bv ))
474 return(bv.bv_val);
475 else
476 return NULL;
479 struct berval *
480 ldap_matchingruleuse2bv( LDAPMatchingRuleUse * mru, struct berval *bv )
482 safe_string * ss;
484 ss = new_safe_string(256);
485 if ( !ss )
486 return NULL;
488 print_literal(ss,"(" /*)*/);
489 print_whsp(ss);
491 print_numericoid(ss, mru->mru_oid);
492 print_whsp(ss);
494 if ( mru->mru_names ) {
495 print_literal(ss,"NAME");
496 print_qdescrs(ss,mru->mru_names);
499 if ( mru->mru_desc ) {
500 print_literal(ss,"DESC");
501 print_qdstring(ss,mru->mru_desc);
504 if ( mru->mru_obsolete ) {
505 print_literal(ss, "OBSOLETE");
506 print_whsp(ss);
509 if ( mru->mru_applies_oids ) {
510 print_literal(ss,"APPLIES");
511 print_whsp(ss);
512 print_oids(ss, mru->mru_applies_oids);
513 print_whsp(ss);
516 print_whsp(ss);
518 print_extensions(ss, mru->mru_extensions);
520 print_literal(ss,/*(*/")");
522 bv->bv_val = safe_strdup(ss);
523 bv->bv_len = ss->pos;
524 safe_string_free(ss);
525 return(bv);
528 char *
529 ldap_objectclass2str( LDAPObjectClass * oc )
531 struct berval bv;
532 if (ldap_objectclass2bv( oc, &bv ))
533 return(bv.bv_val);
534 else
535 return NULL;
538 struct berval *
539 ldap_objectclass2bv( LDAPObjectClass * oc, struct berval *bv )
541 safe_string * ss;
543 ss = new_safe_string(256);
544 if ( !ss )
545 return NULL;
547 print_literal(ss,"("/*)*/);
548 print_whsp(ss);
550 print_numericoid(ss, oc->oc_oid);
551 print_whsp(ss);
553 if ( oc->oc_names ) {
554 print_literal(ss,"NAME");
555 print_qdescrs(ss,oc->oc_names);
558 if ( oc->oc_desc ) {
559 print_literal(ss,"DESC");
560 print_qdstring(ss,oc->oc_desc);
563 if ( oc->oc_obsolete ) {
564 print_literal(ss, "OBSOLETE");
565 print_whsp(ss);
568 if ( oc->oc_sup_oids ) {
569 print_literal(ss,"SUP");
570 print_whsp(ss);
571 print_oids(ss,oc->oc_sup_oids);
572 print_whsp(ss);
575 switch (oc->oc_kind) {
576 case LDAP_SCHEMA_ABSTRACT:
577 print_literal(ss,"ABSTRACT");
578 break;
579 case LDAP_SCHEMA_STRUCTURAL:
580 print_literal(ss,"STRUCTURAL");
581 break;
582 case LDAP_SCHEMA_AUXILIARY:
583 print_literal(ss,"AUXILIARY");
584 break;
585 default:
586 print_literal(ss,"KIND-UNKNOWN");
587 break;
589 print_whsp(ss);
591 if ( oc->oc_at_oids_must ) {
592 print_literal(ss,"MUST");
593 print_whsp(ss);
594 print_oids(ss,oc->oc_at_oids_must);
595 print_whsp(ss);
598 if ( oc->oc_at_oids_may ) {
599 print_literal(ss,"MAY");
600 print_whsp(ss);
601 print_oids(ss,oc->oc_at_oids_may);
602 print_whsp(ss);
605 print_whsp(ss);
607 print_extensions(ss, oc->oc_extensions);
609 print_literal(ss, /*(*/")");
611 bv->bv_val = safe_strdup(ss);
612 bv->bv_len = ss->pos;
613 safe_string_free(ss);
614 return(bv);
617 char *
618 ldap_contentrule2str( LDAPContentRule * cr )
620 struct berval bv;
621 if (ldap_contentrule2bv( cr, &bv ))
622 return(bv.bv_val);
623 else
624 return NULL;
627 struct berval *
628 ldap_contentrule2bv( LDAPContentRule * cr, struct berval *bv )
630 safe_string * ss;
632 ss = new_safe_string(256);
633 if ( !ss )
634 return NULL;
636 print_literal(ss,"("/*)*/);
637 print_whsp(ss);
639 print_numericoid(ss, cr->cr_oid);
640 print_whsp(ss);
642 if ( cr->cr_names ) {
643 print_literal(ss,"NAME");
644 print_qdescrs(ss,cr->cr_names);
647 if ( cr->cr_desc ) {
648 print_literal(ss,"DESC");
649 print_qdstring(ss,cr->cr_desc);
652 if ( cr->cr_obsolete ) {
653 print_literal(ss, "OBSOLETE");
654 print_whsp(ss);
657 if ( cr->cr_oc_oids_aux ) {
658 print_literal(ss,"AUX");
659 print_whsp(ss);
660 print_oids(ss,cr->cr_oc_oids_aux);
661 print_whsp(ss);
664 if ( cr->cr_at_oids_must ) {
665 print_literal(ss,"MUST");
666 print_whsp(ss);
667 print_oids(ss,cr->cr_at_oids_must);
668 print_whsp(ss);
671 if ( cr->cr_at_oids_may ) {
672 print_literal(ss,"MAY");
673 print_whsp(ss);
674 print_oids(ss,cr->cr_at_oids_may);
675 print_whsp(ss);
678 if ( cr->cr_at_oids_not ) {
679 print_literal(ss,"NOT");
680 print_whsp(ss);
681 print_oids(ss,cr->cr_at_oids_not);
682 print_whsp(ss);
685 print_whsp(ss);
686 print_extensions(ss, cr->cr_extensions);
688 print_literal(ss, /*(*/")");
690 bv->bv_val = safe_strdup(ss);
691 bv->bv_len = ss->pos;
692 safe_string_free(ss);
693 return(bv);
696 char *
697 ldap_structurerule2str( LDAPStructureRule * sr )
699 struct berval bv;
700 if (ldap_structurerule2bv( sr, &bv ))
701 return(bv.bv_val);
702 else
703 return NULL;
706 struct berval *
707 ldap_structurerule2bv( LDAPStructureRule * sr, struct berval *bv )
709 safe_string * ss;
711 ss = new_safe_string(256);
712 if ( !ss )
713 return NULL;
715 print_literal(ss,"("/*)*/);
716 print_whsp(ss);
718 print_ruleid(ss, sr->sr_ruleid);
719 print_whsp(ss);
721 if ( sr->sr_names ) {
722 print_literal(ss,"NAME");
723 print_qdescrs(ss,sr->sr_names);
726 if ( sr->sr_desc ) {
727 print_literal(ss,"DESC");
728 print_qdstring(ss,sr->sr_desc);
731 if ( sr->sr_obsolete ) {
732 print_literal(ss, "OBSOLETE");
733 print_whsp(ss);
736 print_literal(ss,"FORM");
737 print_whsp(ss);
738 print_woid(ss,sr->sr_nameform);
739 print_whsp(ss);
741 if ( sr->sr_nsup_ruleids ) {
742 print_literal(ss,"SUP");
743 print_whsp(ss);
744 print_ruleids(ss,sr->sr_nsup_ruleids,sr->sr_sup_ruleids);
745 print_whsp(ss);
748 print_whsp(ss);
749 print_extensions(ss, sr->sr_extensions);
751 print_literal(ss, /*(*/")");
753 bv->bv_val = safe_strdup(ss);
754 bv->bv_len = ss->pos;
755 safe_string_free(ss);
756 return(bv);
760 char *
761 ldap_nameform2str( LDAPNameForm * nf )
763 struct berval bv;
764 if (ldap_nameform2bv( nf, &bv ))
765 return(bv.bv_val);
766 else
767 return NULL;
770 struct berval *
771 ldap_nameform2bv( LDAPNameForm * nf, struct berval *bv )
773 safe_string * ss;
775 ss = new_safe_string(256);
776 if ( !ss )
777 return NULL;
779 print_literal(ss,"("/*)*/);
780 print_whsp(ss);
782 print_numericoid(ss, nf->nf_oid);
783 print_whsp(ss);
785 if ( nf->nf_names ) {
786 print_literal(ss,"NAME");
787 print_qdescrs(ss,nf->nf_names);
790 if ( nf->nf_desc ) {
791 print_literal(ss,"DESC");
792 print_qdstring(ss,nf->nf_desc);
795 if ( nf->nf_obsolete ) {
796 print_literal(ss, "OBSOLETE");
797 print_whsp(ss);
800 print_literal(ss,"OC");
801 print_whsp(ss);
802 print_woid(ss,nf->nf_objectclass);
803 print_whsp(ss);
805 print_literal(ss,"MUST");
806 print_whsp(ss);
807 print_oids(ss,nf->nf_at_oids_must);
808 print_whsp(ss);
811 if ( nf->nf_at_oids_may ) {
812 print_literal(ss,"MAY");
813 print_whsp(ss);
814 print_oids(ss,nf->nf_at_oids_may);
815 print_whsp(ss);
818 print_whsp(ss);
819 print_extensions(ss, nf->nf_extensions);
821 print_literal(ss, /*(*/")");
823 bv->bv_val = safe_strdup(ss);
824 bv->bv_len = ss->pos;
825 safe_string_free(ss);
826 return(bv);
829 char *
830 ldap_attributetype2str( LDAPAttributeType * at )
832 struct berval bv;
833 if (ldap_attributetype2bv( at, &bv ))
834 return(bv.bv_val);
835 else
836 return NULL;
839 struct berval *
840 ldap_attributetype2bv( LDAPAttributeType * at, struct berval *bv )
842 safe_string * ss;
844 ss = new_safe_string(256);
845 if ( !ss )
846 return NULL;
848 print_literal(ss,"("/*)*/);
849 print_whsp(ss);
851 print_numericoid(ss, at->at_oid);
852 print_whsp(ss);
854 if ( at->at_names ) {
855 print_literal(ss,"NAME");
856 print_qdescrs(ss,at->at_names);
859 if ( at->at_desc ) {
860 print_literal(ss,"DESC");
861 print_qdstring(ss,at->at_desc);
864 if ( at->at_obsolete ) {
865 print_literal(ss, "OBSOLETE");
866 print_whsp(ss);
869 if ( at->at_sup_oid ) {
870 print_literal(ss,"SUP");
871 print_woid(ss,at->at_sup_oid);
874 if ( at->at_equality_oid ) {
875 print_literal(ss,"EQUALITY");
876 print_woid(ss,at->at_equality_oid);
879 if ( at->at_ordering_oid ) {
880 print_literal(ss,"ORDERING");
881 print_woid(ss,at->at_ordering_oid);
884 if ( at->at_substr_oid ) {
885 print_literal(ss,"SUBSTR");
886 print_woid(ss,at->at_substr_oid);
889 if ( at->at_syntax_oid ) {
890 print_literal(ss,"SYNTAX");
891 print_whsp(ss);
892 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
893 print_whsp(ss);
896 if ( at->at_single_value == LDAP_SCHEMA_YES ) {
897 print_literal(ss,"SINGLE-VALUE");
898 print_whsp(ss);
901 if ( at->at_collective == LDAP_SCHEMA_YES ) {
902 print_literal(ss,"COLLECTIVE");
903 print_whsp(ss);
906 if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
907 print_literal(ss,"NO-USER-MODIFICATION");
908 print_whsp(ss);
911 if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
912 print_literal(ss,"USAGE");
913 print_whsp(ss);
914 switch (at->at_usage) {
915 case LDAP_SCHEMA_DIRECTORY_OPERATION:
916 print_literal(ss,"directoryOperation");
917 break;
918 case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
919 print_literal(ss,"distributedOperation");
920 break;
921 case LDAP_SCHEMA_DSA_OPERATION:
922 print_literal(ss,"dSAOperation");
923 break;
924 default:
925 print_literal(ss,"UNKNOWN");
926 break;
930 print_whsp(ss);
932 print_extensions(ss, at->at_extensions);
934 print_literal(ss,/*(*/")");
936 bv->bv_val = safe_strdup(ss);
937 bv->bv_len = ss->pos;
938 safe_string_free(ss);
939 return(bv);
943 * Now come the parsers. There is one parser for each entity type:
944 * objectclasses, attributetypes, etc.
946 * Each of them is written as a recursive-descent parser, except that
947 * none of them is really recursive. But the idea is kept: there
948 * is one routine per non-terminal that eithers gobbles lexical tokens
949 * or calls lower-level routines, etc.
951 * The scanner is implemented in the routine get_token. Actually,
952 * get_token is more than a scanner and will return tokens that are
953 * in fact non-terminals in the grammar. So you can see the whole
954 * approach as the combination of a low-level bottom-up recognizer
955 * combined with a scanner and a number of top-down parsers. Or just
956 * consider that the real grammars recognized by the parsers are not
957 * those of the standards. As a matter of fact, our parsers are more
958 * liberal than the spec when there is no ambiguity.
960 * The difference is pretty academic (modulo bugs or incorrect
961 * interpretation of the specs).
964 typedef enum tk_t {
965 TK_NOENDQUOTE = -2,
966 TK_OUTOFMEM = -1,
967 TK_EOS = 0,
968 TK_UNEXPCHAR = 1,
969 TK_BAREWORD = 2,
970 TK_QDSTRING = 3,
971 TK_LEFTPAREN = 4,
972 TK_RIGHTPAREN = 5,
973 TK_DOLLAR = 6,
974 TK_QDESCR = TK_QDSTRING
975 } tk_t;
977 static tk_t
978 get_token( const char ** sp, char ** token_val )
980 tk_t kind;
981 const char * p;
982 const char * q;
983 char * res;
985 *token_val = NULL;
986 switch (**sp) {
987 case '\0':
988 kind = TK_EOS;
989 (*sp)++;
990 break;
991 case '(':
992 kind = TK_LEFTPAREN;
993 (*sp)++;
994 break;
995 case ')':
996 kind = TK_RIGHTPAREN;
997 (*sp)++;
998 break;
999 case '$':
1000 kind = TK_DOLLAR;
1001 (*sp)++;
1002 break;
1003 case '\'':
1004 kind = TK_QDSTRING;
1005 (*sp)++;
1006 p = *sp;
1007 while ( **sp != '\'' && **sp != '\0' )
1008 (*sp)++;
1009 if ( **sp == '\'' ) {
1010 q = *sp;
1011 res = LDAP_MALLOC(q-p+1);
1012 if ( !res ) {
1013 kind = TK_OUTOFMEM;
1014 } else {
1015 strncpy(res,p,q-p);
1016 res[q-p] = '\0';
1017 *token_val = res;
1019 (*sp)++;
1020 } else {
1021 kind = TK_NOENDQUOTE;
1023 break;
1024 default:
1025 kind = TK_BAREWORD;
1026 p = *sp;
1027 while ( !LDAP_SPACE(**sp) &&
1028 **sp != '(' &&
1029 **sp != ')' &&
1030 **sp != '$' &&
1031 **sp != '\'' &&
1032 /* for suggested minimum upper bound on the number
1033 * of characters (RFC 4517) */
1034 **sp != '{' &&
1035 **sp != '\0' )
1036 (*sp)++;
1037 q = *sp;
1038 res = LDAP_MALLOC(q-p+1);
1039 if ( !res ) {
1040 kind = TK_OUTOFMEM;
1041 } else {
1042 strncpy(res,p,q-p);
1043 res[q-p] = '\0';
1044 *token_val = res;
1046 break;
1047 /* kind = TK_UNEXPCHAR; */
1048 /* break; */
1051 return kind;
1054 /* Gobble optional whitespace */
1055 static void
1056 parse_whsp(const char **sp)
1058 while (LDAP_SPACE(**sp))
1059 (*sp)++;
1062 /* TBC:!!
1063 * General note for all parsers: to guarantee the algorithm halts they
1064 * must always advance the pointer even when an error is found. For
1065 * this one is not that important since an error here is fatal at the
1066 * upper layers, but it is a simple strategy that will not get in
1067 * endless loops.
1070 /* Parse a sequence of dot-separated decimal strings */
1071 char *
1072 ldap_int_parse_numericoid(const char **sp, int *code, const int flags)
1074 char * res = NULL;
1075 const char * start = *sp;
1076 int len;
1077 int quoted = 0;
1079 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
1080 if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && **sp == '\'' ) {
1081 quoted = 1;
1082 (*sp)++;
1083 start++;
1085 /* Each iteration of this loop gets one decimal string */
1086 while (**sp) {
1087 if ( !LDAP_DIGIT(**sp) ) {
1089 * Initial char is not a digit or char after dot is
1090 * not a digit
1092 *code = LDAP_SCHERR_NODIGIT;
1093 return NULL;
1095 (*sp)++;
1096 while ( LDAP_DIGIT(**sp) )
1097 (*sp)++;
1098 if ( **sp != '.' )
1099 break;
1100 /* Otherwise, gobble the dot and loop again */
1101 (*sp)++;
1103 /* Now *sp points at the char past the numericoid. Perfect. */
1104 len = *sp - start;
1105 if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && quoted ) {
1106 if ( **sp == '\'' ) {
1107 (*sp)++;
1108 } else {
1109 *code = LDAP_SCHERR_UNEXPTOKEN;
1110 return NULL;
1113 if (flags & LDAP_SCHEMA_SKIP) {
1114 res = (char *)start;
1115 } else {
1116 res = LDAP_MALLOC(len+1);
1117 if (!res) {
1118 *code = LDAP_SCHERR_OUTOFMEM;
1119 return(NULL);
1121 strncpy(res,start,len);
1122 res[len] = '\0';
1124 return(res);
1127 /* Parse a sequence of dot-separated decimal strings */
1129 ldap_int_parse_ruleid(const char **sp, int *code, const int flags, int *ruleid)
1131 *ruleid=0;
1133 if ( !LDAP_DIGIT(**sp) ) {
1134 *code = LDAP_SCHERR_NODIGIT;
1135 return -1;
1137 *ruleid = (**sp) - '0';
1138 (*sp)++;
1140 while ( LDAP_DIGIT(**sp) ) {
1141 *ruleid *= 10;
1142 *ruleid += (**sp) - '0';
1143 (*sp)++;
1146 return 0;
1149 /* Parse a qdescr or a list of them enclosed in () */
1150 static char **
1151 parse_qdescrs(const char **sp, int *code)
1153 char ** res;
1154 char ** res1;
1155 tk_t kind;
1156 char * sval;
1157 int size;
1158 int pos;
1160 parse_whsp(sp);
1161 kind = get_token(sp,&sval);
1162 if ( kind == TK_LEFTPAREN ) {
1163 /* Let's presume there will be at least 2 entries */
1164 size = 3;
1165 res = LDAP_CALLOC(3,sizeof(char *));
1166 if ( !res ) {
1167 *code = LDAP_SCHERR_OUTOFMEM;
1168 return NULL;
1170 pos = 0;
1171 while (1) {
1172 parse_whsp(sp);
1173 kind = get_token(sp,&sval);
1174 if ( kind == TK_RIGHTPAREN )
1175 break;
1176 if ( kind == TK_QDESCR ) {
1177 if ( pos == size-2 ) {
1178 size++;
1179 res1 = LDAP_REALLOC(res,size*sizeof(char *));
1180 if ( !res1 ) {
1181 LDAP_VFREE(res);
1182 LDAP_FREE(sval);
1183 *code = LDAP_SCHERR_OUTOFMEM;
1184 return(NULL);
1186 res = res1;
1188 res[pos++] = sval;
1189 res[pos] = NULL;
1190 parse_whsp(sp);
1191 } else {
1192 LDAP_VFREE(res);
1193 LDAP_FREE(sval);
1194 *code = LDAP_SCHERR_UNEXPTOKEN;
1195 return(NULL);
1198 parse_whsp(sp);
1199 return(res);
1200 } else if ( kind == TK_QDESCR ) {
1201 res = LDAP_CALLOC(2,sizeof(char *));
1202 if ( !res ) {
1203 *code = LDAP_SCHERR_OUTOFMEM;
1204 return NULL;
1206 res[0] = sval;
1207 res[1] = NULL;
1208 parse_whsp(sp);
1209 return res;
1210 } else {
1211 LDAP_FREE(sval);
1212 *code = LDAP_SCHERR_BADNAME;
1213 return NULL;
1217 /* Parse a woid */
1218 static char *
1219 parse_woid(const char **sp, int *code)
1221 char * sval;
1222 tk_t kind;
1224 parse_whsp(sp);
1225 kind = get_token(sp, &sval);
1226 if ( kind != TK_BAREWORD ) {
1227 LDAP_FREE(sval);
1228 *code = LDAP_SCHERR_UNEXPTOKEN;
1229 return NULL;
1231 parse_whsp(sp);
1232 return sval;
1235 /* Parse a noidlen */
1236 static char *
1237 parse_noidlen(const char **sp, int *code, int *len, int flags)
1239 char * sval;
1240 const char *savepos;
1241 int quoted = 0;
1242 int allow_quoted = ( flags & LDAP_SCHEMA_ALLOW_QUOTED );
1243 int allow_oidmacro = ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO );
1245 *len = 0;
1246 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
1247 if ( allow_quoted && **sp == '\'' ) {
1248 quoted = 1;
1249 (*sp)++;
1251 savepos = *sp;
1252 sval = ldap_int_parse_numericoid(sp, code, 0);
1253 if ( !sval ) {
1254 if ( allow_oidmacro
1255 && *sp == savepos
1256 && *code == LDAP_SCHERR_NODIGIT )
1258 if ( get_token(sp, &sval) != TK_BAREWORD ) {
1259 if ( sval != NULL ) {
1260 LDAP_FREE(sval);
1262 return NULL;
1264 } else {
1265 return NULL;
1268 if ( **sp == '{' /*}*/ ) {
1269 (*sp)++;
1270 *len = atoi(*sp);
1271 while ( LDAP_DIGIT(**sp) )
1272 (*sp)++;
1273 if ( **sp != /*{*/ '}' ) {
1274 *code = LDAP_SCHERR_UNEXPTOKEN;
1275 LDAP_FREE(sval);
1276 return NULL;
1278 (*sp)++;
1280 if ( allow_quoted && quoted ) {
1281 if ( **sp == '\'' ) {
1282 (*sp)++;
1283 } else {
1284 *code = LDAP_SCHERR_UNEXPTOKEN;
1285 LDAP_FREE(sval);
1286 return NULL;
1289 return sval;
1293 * Next routine will accept a qdstring in place of an oid if
1294 * allow_quoted is set. This is necessary to interoperate with
1295 * Netscape Directory server that will improperly quote each oid (at
1296 * least those of the descr kind) in the SUP clause.
1299 /* Parse a woid or a $-separated list of them enclosed in () */
1300 static char **
1301 parse_oids(const char **sp, int *code, const int allow_quoted)
1303 char ** res;
1304 char ** res1;
1305 tk_t kind;
1306 char * sval;
1307 int size;
1308 int pos;
1311 * Strictly speaking, doing this here accepts whsp before the
1312 * ( at the begining of an oidlist, but this is harmless. Also,
1313 * we are very liberal in what we accept as an OID. Maybe
1314 * refine later.
1316 parse_whsp(sp);
1317 kind = get_token(sp,&sval);
1318 if ( kind == TK_LEFTPAREN ) {
1319 /* Let's presume there will be at least 2 entries */
1320 size = 3;
1321 res = LDAP_CALLOC(3,sizeof(char *));
1322 if ( !res ) {
1323 *code = LDAP_SCHERR_OUTOFMEM;
1324 return NULL;
1326 pos = 0;
1327 parse_whsp(sp);
1328 kind = get_token(sp,&sval);
1329 if ( kind == TK_BAREWORD ||
1330 ( allow_quoted && kind == TK_QDSTRING ) ) {
1331 res[pos++] = sval;
1332 res[pos] = NULL;
1333 } else if ( kind == TK_RIGHTPAREN ) {
1334 /* FIXME: be liberal in what we accept... */
1335 parse_whsp(sp);
1336 LDAP_FREE(res);
1337 return NULL;
1338 } else {
1339 *code = LDAP_SCHERR_UNEXPTOKEN;
1340 LDAP_FREE(sval);
1341 LDAP_VFREE(res);
1342 return NULL;
1344 parse_whsp(sp);
1345 while (1) {
1346 kind = get_token(sp,&sval);
1347 if ( kind == TK_RIGHTPAREN )
1348 break;
1349 if ( kind == TK_DOLLAR ) {
1350 parse_whsp(sp);
1351 kind = get_token(sp,&sval);
1352 if ( kind == TK_BAREWORD ||
1353 ( allow_quoted &&
1354 kind == TK_QDSTRING ) ) {
1355 if ( pos == size-2 ) {
1356 size++;
1357 res1 = LDAP_REALLOC(res,size*sizeof(char *));
1358 if ( !res1 ) {
1359 LDAP_FREE(sval);
1360 LDAP_VFREE(res);
1361 *code = LDAP_SCHERR_OUTOFMEM;
1362 return(NULL);
1364 res = res1;
1366 res[pos++] = sval;
1367 res[pos] = NULL;
1368 } else {
1369 *code = LDAP_SCHERR_UNEXPTOKEN;
1370 LDAP_FREE(sval);
1371 LDAP_VFREE(res);
1372 return NULL;
1374 parse_whsp(sp);
1375 } else {
1376 *code = LDAP_SCHERR_UNEXPTOKEN;
1377 LDAP_FREE(sval);
1378 LDAP_VFREE(res);
1379 return NULL;
1382 parse_whsp(sp);
1383 return(res);
1384 } else if ( kind == TK_BAREWORD ||
1385 ( allow_quoted && kind == TK_QDSTRING ) ) {
1386 res = LDAP_CALLOC(2,sizeof(char *));
1387 if ( !res ) {
1388 LDAP_FREE(sval);
1389 *code = LDAP_SCHERR_OUTOFMEM;
1390 return NULL;
1392 res[0] = sval;
1393 res[1] = NULL;
1394 parse_whsp(sp);
1395 return res;
1396 } else {
1397 LDAP_FREE(sval);
1398 *code = LDAP_SCHERR_BADNAME;
1399 return NULL;
1403 static int
1404 add_extension(LDAPSchemaExtensionItem ***extensions,
1405 char * name, char ** values)
1407 int n;
1408 LDAPSchemaExtensionItem **tmp, *ext;
1410 ext = LDAP_CALLOC(1, sizeof(LDAPSchemaExtensionItem));
1411 if ( !ext )
1412 return 1;
1413 ext->lsei_name = name;
1414 ext->lsei_values = values;
1416 if ( !*extensions ) {
1417 *extensions =
1418 LDAP_CALLOC(2, sizeof(LDAPSchemaExtensionItem *));
1419 if ( !*extensions ) {
1420 LDAP_FREE( ext );
1421 return 1;
1423 n = 0;
1424 } else {
1425 for ( n=0; (*extensions)[n] != NULL; n++ )
1427 tmp = LDAP_REALLOC(*extensions,
1428 (n+2)*sizeof(LDAPSchemaExtensionItem *));
1429 if ( !tmp ) {
1430 LDAP_FREE( ext );
1431 return 1;
1433 *extensions = tmp;
1435 (*extensions)[n] = ext;
1436 (*extensions)[n+1] = NULL;
1437 return 0;
1440 static void
1441 free_extensions(LDAPSchemaExtensionItem **extensions)
1443 LDAPSchemaExtensionItem **ext;
1445 if ( extensions ) {
1446 for ( ext = extensions; *ext != NULL; ext++ ) {
1447 LDAP_FREE((*ext)->lsei_name);
1448 LDAP_VFREE((*ext)->lsei_values);
1449 LDAP_FREE(*ext);
1451 LDAP_FREE(extensions);
1455 void
1456 ldap_syntax_free( LDAPSyntax * syn )
1458 LDAP_FREE(syn->syn_oid);
1459 if (syn->syn_names) LDAP_VFREE(syn->syn_names);
1460 if (syn->syn_desc) LDAP_FREE(syn->syn_desc);
1461 free_extensions(syn->syn_extensions);
1462 LDAP_FREE(syn);
1465 LDAPSyntax *
1466 ldap_str2syntax( LDAP_CONST char * s,
1467 int * code,
1468 LDAP_CONST char ** errp,
1469 LDAP_CONST unsigned flags )
1471 tk_t kind;
1472 const char * ss = s;
1473 char * sval;
1474 int seen_name = 0;
1475 int seen_desc = 0;
1476 LDAPSyntax * syn;
1477 char ** ext_vals;
1479 if ( !s ) {
1480 *code = LDAP_SCHERR_EMPTY;
1481 *errp = "";
1482 return NULL;
1485 *errp = s;
1486 syn = LDAP_CALLOC(1,sizeof(LDAPSyntax));
1488 if ( !syn ) {
1489 *code = LDAP_SCHERR_OUTOFMEM;
1490 return NULL;
1493 kind = get_token(&ss,&sval);
1494 if ( kind != TK_LEFTPAREN ) {
1495 LDAP_FREE(sval);
1496 *code = LDAP_SCHERR_NOLEFTPAREN;
1497 ldap_syntax_free(syn);
1498 return NULL;
1501 parse_whsp(&ss);
1502 syn->syn_oid = ldap_int_parse_numericoid(&ss,code,0);
1503 if ( !syn->syn_oid ) {
1504 *errp = ss;
1505 ldap_syntax_free(syn);
1506 return NULL;
1508 parse_whsp(&ss);
1511 * Beyond this point we will be liberal and accept the items
1512 * in any order.
1514 while (1) {
1515 kind = get_token(&ss,&sval);
1516 switch (kind) {
1517 case TK_EOS:
1518 *code = LDAP_SCHERR_NORIGHTPAREN;
1519 *errp = EndOfInput;
1520 ldap_syntax_free(syn);
1521 return NULL;
1522 case TK_RIGHTPAREN:
1523 return syn;
1524 case TK_BAREWORD:
1525 if ( !strcasecmp(sval,"NAME") ) {
1526 LDAP_FREE(sval);
1527 if ( seen_name ) {
1528 *code = LDAP_SCHERR_DUPOPT;
1529 *errp = ss;
1530 ldap_syntax_free(syn);
1531 return(NULL);
1533 seen_name = 1;
1534 syn->syn_names = parse_qdescrs(&ss,code);
1535 if ( !syn->syn_names ) {
1536 if ( *code != LDAP_SCHERR_OUTOFMEM )
1537 *code = LDAP_SCHERR_BADNAME;
1538 *errp = ss;
1539 ldap_syntax_free(syn);
1540 return NULL;
1542 } else if ( !strcasecmp(sval,"DESC") ) {
1543 LDAP_FREE(sval);
1544 if ( seen_desc ) {
1545 *code = LDAP_SCHERR_DUPOPT;
1546 *errp = ss;
1547 ldap_syntax_free(syn);
1548 return(NULL);
1550 seen_desc = 1;
1551 parse_whsp(&ss);
1552 kind = get_token(&ss,&sval);
1553 if ( kind != TK_QDSTRING ) {
1554 *code = LDAP_SCHERR_UNEXPTOKEN;
1555 *errp = ss;
1556 LDAP_FREE(sval);
1557 ldap_syntax_free(syn);
1558 return NULL;
1560 syn->syn_desc = sval;
1561 parse_whsp(&ss);
1562 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1563 /* Should be parse_qdstrings */
1564 ext_vals = parse_qdescrs(&ss, code);
1565 if ( !ext_vals ) {
1566 *errp = ss;
1567 ldap_syntax_free(syn);
1568 return NULL;
1570 if ( add_extension(&syn->syn_extensions,
1571 sval, ext_vals) ) {
1572 *code = LDAP_SCHERR_OUTOFMEM;
1573 *errp = ss;
1574 LDAP_FREE(sval);
1575 ldap_syntax_free(syn);
1576 return NULL;
1578 } else {
1579 *code = LDAP_SCHERR_UNEXPTOKEN;
1580 *errp = ss;
1581 LDAP_FREE(sval);
1582 ldap_syntax_free(syn);
1583 return NULL;
1585 break;
1586 default:
1587 *code = LDAP_SCHERR_UNEXPTOKEN;
1588 *errp = ss;
1589 LDAP_FREE(sval);
1590 ldap_syntax_free(syn);
1591 return NULL;
1596 void
1597 ldap_matchingrule_free( LDAPMatchingRule * mr )
1599 LDAP_FREE(mr->mr_oid);
1600 if (mr->mr_names) LDAP_VFREE(mr->mr_names);
1601 if (mr->mr_desc) LDAP_FREE(mr->mr_desc);
1602 if (mr->mr_syntax_oid) LDAP_FREE(mr->mr_syntax_oid);
1603 free_extensions(mr->mr_extensions);
1604 LDAP_FREE(mr);
1607 LDAPMatchingRule *
1608 ldap_str2matchingrule( LDAP_CONST char * s,
1609 int * code,
1610 LDAP_CONST char ** errp,
1611 LDAP_CONST unsigned flags )
1613 tk_t kind;
1614 const char * ss = s;
1615 char * sval;
1616 int seen_name = 0;
1617 int seen_desc = 0;
1618 int seen_obsolete = 0;
1619 int seen_syntax = 0;
1620 LDAPMatchingRule * mr;
1621 char ** ext_vals;
1622 const char * savepos;
1624 if ( !s ) {
1625 *code = LDAP_SCHERR_EMPTY;
1626 *errp = "";
1627 return NULL;
1630 *errp = s;
1631 mr = LDAP_CALLOC(1,sizeof(LDAPMatchingRule));
1633 if ( !mr ) {
1634 *code = LDAP_SCHERR_OUTOFMEM;
1635 return NULL;
1638 kind = get_token(&ss,&sval);
1639 if ( kind != TK_LEFTPAREN ) {
1640 *code = LDAP_SCHERR_NOLEFTPAREN;
1641 LDAP_FREE(sval);
1642 ldap_matchingrule_free(mr);
1643 return NULL;
1646 parse_whsp(&ss);
1647 savepos = ss;
1648 mr->mr_oid = ldap_int_parse_numericoid(&ss,code,flags);
1649 if ( !mr->mr_oid ) {
1650 if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
1651 /* Backtracking */
1652 ss = savepos;
1653 kind = get_token(&ss,&sval);
1654 if ( kind == TK_BAREWORD ) {
1655 if ( !strcasecmp(sval, "NAME") ||
1656 !strcasecmp(sval, "DESC") ||
1657 !strcasecmp(sval, "OBSOLETE") ||
1658 !strcasecmp(sval, "SYNTAX") ||
1659 !strncasecmp(sval, "X-", 2) ) {
1660 /* Missing OID, backtrack */
1661 ss = savepos;
1662 } else {
1663 /* Non-numerical OID, ignore */
1666 LDAP_FREE(sval);
1667 } else {
1668 *errp = ss;
1669 ldap_matchingrule_free(mr);
1670 return NULL;
1673 parse_whsp(&ss);
1676 * Beyond this point we will be liberal and accept the items
1677 * in any order.
1679 while (1) {
1680 kind = get_token(&ss,&sval);
1681 switch (kind) {
1682 case TK_EOS:
1683 *code = LDAP_SCHERR_NORIGHTPAREN;
1684 *errp = EndOfInput;
1685 ldap_matchingrule_free(mr);
1686 return NULL;
1687 case TK_RIGHTPAREN:
1688 if( !seen_syntax ) {
1689 *code = LDAP_SCHERR_MISSING;
1690 ldap_matchingrule_free(mr);
1691 return NULL;
1693 return mr;
1694 case TK_BAREWORD:
1695 if ( !strcasecmp(sval,"NAME") ) {
1696 LDAP_FREE(sval);
1697 if ( seen_name ) {
1698 *code = LDAP_SCHERR_DUPOPT;
1699 *errp = ss;
1700 ldap_matchingrule_free(mr);
1701 return(NULL);
1703 seen_name = 1;
1704 mr->mr_names = parse_qdescrs(&ss,code);
1705 if ( !mr->mr_names ) {
1706 if ( *code != LDAP_SCHERR_OUTOFMEM )
1707 *code = LDAP_SCHERR_BADNAME;
1708 *errp = ss;
1709 ldap_matchingrule_free(mr);
1710 return NULL;
1712 } else if ( !strcasecmp(sval,"DESC") ) {
1713 LDAP_FREE(sval);
1714 if ( seen_desc ) {
1715 *code = LDAP_SCHERR_DUPOPT;
1716 *errp = ss;
1717 ldap_matchingrule_free(mr);
1718 return(NULL);
1720 seen_desc = 1;
1721 parse_whsp(&ss);
1722 kind = get_token(&ss,&sval);
1723 if ( kind != TK_QDSTRING ) {
1724 *code = LDAP_SCHERR_UNEXPTOKEN;
1725 *errp = ss;
1726 LDAP_FREE(sval);
1727 ldap_matchingrule_free(mr);
1728 return NULL;
1730 mr->mr_desc = sval;
1731 parse_whsp(&ss);
1732 } else if ( !strcasecmp(sval,"OBSOLETE") ) {
1733 LDAP_FREE(sval);
1734 if ( seen_obsolete ) {
1735 *code = LDAP_SCHERR_DUPOPT;
1736 *errp = ss;
1737 ldap_matchingrule_free(mr);
1738 return(NULL);
1740 seen_obsolete = 1;
1741 mr->mr_obsolete = LDAP_SCHEMA_YES;
1742 parse_whsp(&ss);
1743 } else if ( !strcasecmp(sval,"SYNTAX") ) {
1744 LDAP_FREE(sval);
1745 if ( seen_syntax ) {
1746 *code = LDAP_SCHERR_DUPOPT;
1747 *errp = ss;
1748 ldap_matchingrule_free(mr);
1749 return(NULL);
1751 seen_syntax = 1;
1752 parse_whsp(&ss);
1753 mr->mr_syntax_oid =
1754 ldap_int_parse_numericoid(&ss,code,flags);
1755 if ( !mr->mr_syntax_oid ) {
1756 *errp = ss;
1757 ldap_matchingrule_free(mr);
1758 return NULL;
1760 parse_whsp(&ss);
1761 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1762 /* Should be parse_qdstrings */
1763 ext_vals = parse_qdescrs(&ss, code);
1764 if ( !ext_vals ) {
1765 *errp = ss;
1766 ldap_matchingrule_free(mr);
1767 return NULL;
1769 if ( add_extension(&mr->mr_extensions,
1770 sval, ext_vals) ) {
1771 *code = LDAP_SCHERR_OUTOFMEM;
1772 *errp = ss;
1773 LDAP_FREE(sval);
1774 ldap_matchingrule_free(mr);
1775 return NULL;
1777 } else {
1778 *code = LDAP_SCHERR_UNEXPTOKEN;
1779 *errp = ss;
1780 LDAP_FREE(sval);
1781 ldap_matchingrule_free(mr);
1782 return NULL;
1784 break;
1785 default:
1786 *code = LDAP_SCHERR_UNEXPTOKEN;
1787 *errp = ss;
1788 LDAP_FREE(sval);
1789 ldap_matchingrule_free(mr);
1790 return NULL;
1795 void
1796 ldap_matchingruleuse_free( LDAPMatchingRuleUse * mru )
1798 LDAP_FREE(mru->mru_oid);
1799 if (mru->mru_names) LDAP_VFREE(mru->mru_names);
1800 if (mru->mru_desc) LDAP_FREE(mru->mru_desc);
1801 if (mru->mru_applies_oids) LDAP_VFREE(mru->mru_applies_oids);
1802 free_extensions(mru->mru_extensions);
1803 LDAP_FREE(mru);
1806 LDAPMatchingRuleUse *
1807 ldap_str2matchingruleuse( LDAP_CONST char * s,
1808 int * code,
1809 LDAP_CONST char ** errp,
1810 LDAP_CONST unsigned flags )
1812 tk_t kind;
1813 const char * ss = s;
1814 char * sval;
1815 int seen_name = 0;
1816 int seen_desc = 0;
1817 int seen_obsolete = 0;
1818 int seen_applies = 0;
1819 LDAPMatchingRuleUse * mru;
1820 char ** ext_vals;
1821 const char * savepos;
1823 if ( !s ) {
1824 *code = LDAP_SCHERR_EMPTY;
1825 *errp = "";
1826 return NULL;
1829 *errp = s;
1830 mru = LDAP_CALLOC(1,sizeof(LDAPMatchingRuleUse));
1832 if ( !mru ) {
1833 *code = LDAP_SCHERR_OUTOFMEM;
1834 return NULL;
1837 kind = get_token(&ss,&sval);
1838 if ( kind != TK_LEFTPAREN ) {
1839 *code = LDAP_SCHERR_NOLEFTPAREN;
1840 LDAP_FREE(sval);
1841 ldap_matchingruleuse_free(mru);
1842 return NULL;
1845 parse_whsp(&ss);
1846 savepos = ss;
1847 mru->mru_oid = ldap_int_parse_numericoid(&ss,code,flags);
1848 if ( !mru->mru_oid ) {
1849 if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
1850 /* Backtracking */
1851 ss = savepos;
1852 kind = get_token(&ss,&sval);
1853 if ( kind == TK_BAREWORD ) {
1854 if ( !strcasecmp(sval, "NAME") ||
1855 !strcasecmp(sval, "DESC") ||
1856 !strcasecmp(sval, "OBSOLETE") ||
1857 !strcasecmp(sval, "APPLIES") ||
1858 !strncasecmp(sval, "X-", 2) ) {
1859 /* Missing OID, backtrack */
1860 ss = savepos;
1861 } else {
1862 /* Non-numerical OID, ignore */
1865 LDAP_FREE(sval);
1866 } else {
1867 *errp = ss;
1868 ldap_matchingruleuse_free(mru);
1869 return NULL;
1872 parse_whsp(&ss);
1875 * Beyond this point we will be liberal and accept the items
1876 * in any order.
1878 while (1) {
1879 kind = get_token(&ss,&sval);
1880 switch (kind) {
1881 case TK_EOS:
1882 *code = LDAP_SCHERR_NORIGHTPAREN;
1883 *errp = EndOfInput;
1884 ldap_matchingruleuse_free(mru);
1885 return NULL;
1886 case TK_RIGHTPAREN:
1887 if( !seen_applies ) {
1888 *code = LDAP_SCHERR_MISSING;
1889 ldap_matchingruleuse_free(mru);
1890 return NULL;
1892 return mru;
1893 case TK_BAREWORD:
1894 if ( !strcasecmp(sval,"NAME") ) {
1895 LDAP_FREE(sval);
1896 if ( seen_name ) {
1897 *code = LDAP_SCHERR_DUPOPT;
1898 *errp = ss;
1899 ldap_matchingruleuse_free(mru);
1900 return(NULL);
1902 seen_name = 1;
1903 mru->mru_names = parse_qdescrs(&ss,code);
1904 if ( !mru->mru_names ) {
1905 if ( *code != LDAP_SCHERR_OUTOFMEM )
1906 *code = LDAP_SCHERR_BADNAME;
1907 *errp = ss;
1908 ldap_matchingruleuse_free(mru);
1909 return NULL;
1911 } else if ( !strcasecmp(sval,"DESC") ) {
1912 LDAP_FREE(sval);
1913 if ( seen_desc ) {
1914 *code = LDAP_SCHERR_DUPOPT;
1915 *errp = ss;
1916 ldap_matchingruleuse_free(mru);
1917 return(NULL);
1919 seen_desc = 1;
1920 parse_whsp(&ss);
1921 kind = get_token(&ss,&sval);
1922 if ( kind != TK_QDSTRING ) {
1923 *code = LDAP_SCHERR_UNEXPTOKEN;
1924 *errp = ss;
1925 LDAP_FREE(sval);
1926 ldap_matchingruleuse_free(mru);
1927 return NULL;
1929 mru->mru_desc = sval;
1930 parse_whsp(&ss);
1931 } else if ( !strcasecmp(sval,"OBSOLETE") ) {
1932 LDAP_FREE(sval);
1933 if ( seen_obsolete ) {
1934 *code = LDAP_SCHERR_DUPOPT;
1935 *errp = ss;
1936 ldap_matchingruleuse_free(mru);
1937 return(NULL);
1939 seen_obsolete = 1;
1940 mru->mru_obsolete = LDAP_SCHEMA_YES;
1941 parse_whsp(&ss);
1942 } else if ( !strcasecmp(sval,"APPLIES") ) {
1943 LDAP_FREE(sval);
1944 if ( seen_applies ) {
1945 *code = LDAP_SCHERR_DUPOPT;
1946 *errp = ss;
1947 ldap_matchingruleuse_free(mru);
1948 return(NULL);
1950 seen_applies = 1;
1951 mru->mru_applies_oids = parse_oids(&ss,
1952 code,
1953 flags);
1954 if ( !mru->mru_applies_oids && *code != LDAP_SUCCESS ) {
1955 *errp = ss;
1956 ldap_matchingruleuse_free(mru);
1957 return NULL;
1959 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1960 /* Should be parse_qdstrings */
1961 ext_vals = parse_qdescrs(&ss, code);
1962 if ( !ext_vals ) {
1963 *errp = ss;
1964 ldap_matchingruleuse_free(mru);
1965 return NULL;
1967 if ( add_extension(&mru->mru_extensions,
1968 sval, ext_vals) ) {
1969 *code = LDAP_SCHERR_OUTOFMEM;
1970 *errp = ss;
1971 LDAP_FREE(sval);
1972 ldap_matchingruleuse_free(mru);
1973 return NULL;
1975 } else {
1976 *code = LDAP_SCHERR_UNEXPTOKEN;
1977 *errp = ss;
1978 LDAP_FREE(sval);
1979 ldap_matchingruleuse_free(mru);
1980 return NULL;
1982 break;
1983 default:
1984 *code = LDAP_SCHERR_UNEXPTOKEN;
1985 *errp = ss;
1986 LDAP_FREE(sval);
1987 ldap_matchingruleuse_free(mru);
1988 return NULL;
1993 void
1994 ldap_attributetype_free(LDAPAttributeType * at)
1996 LDAP_FREE(at->at_oid);
1997 if (at->at_names) LDAP_VFREE(at->at_names);
1998 if (at->at_desc) LDAP_FREE(at->at_desc);
1999 if (at->at_sup_oid) LDAP_FREE(at->at_sup_oid);
2000 if (at->at_equality_oid) LDAP_FREE(at->at_equality_oid);
2001 if (at->at_ordering_oid) LDAP_FREE(at->at_ordering_oid);
2002 if (at->at_substr_oid) LDAP_FREE(at->at_substr_oid);
2003 if (at->at_syntax_oid) LDAP_FREE(at->at_syntax_oid);
2004 free_extensions(at->at_extensions);
2005 LDAP_FREE(at);
2008 LDAPAttributeType *
2009 ldap_str2attributetype( LDAP_CONST char * s,
2010 int * code,
2011 LDAP_CONST char ** errp,
2012 LDAP_CONST unsigned flags )
2014 tk_t kind;
2015 const char * ss = s;
2016 char * sval;
2017 int seen_name = 0;
2018 int seen_desc = 0;
2019 int seen_obsolete = 0;
2020 int seen_sup = 0;
2021 int seen_equality = 0;
2022 int seen_ordering = 0;
2023 int seen_substr = 0;
2024 int seen_syntax = 0;
2025 int seen_usage = 0;
2026 LDAPAttributeType * at;
2027 char ** ext_vals;
2028 const char * savepos;
2030 if ( !s ) {
2031 *code = LDAP_SCHERR_EMPTY;
2032 *errp = "";
2033 return NULL;
2036 *errp = s;
2037 at = LDAP_CALLOC(1,sizeof(LDAPAttributeType));
2039 if ( !at ) {
2040 *code = LDAP_SCHERR_OUTOFMEM;
2041 return NULL;
2044 kind = get_token(&ss,&sval);
2045 if ( kind != TK_LEFTPAREN ) {
2046 *code = LDAP_SCHERR_NOLEFTPAREN;
2047 LDAP_FREE(sval);
2048 ldap_attributetype_free(at);
2049 return NULL;
2053 * Definitions MUST begin with an OID in the numericoid format.
2054 * However, this routine is used by clients to parse the response
2055 * from servers and very well known servers will provide an OID
2056 * in the wrong format or even no OID at all. We do our best to
2057 * extract info from those servers.
2059 parse_whsp(&ss);
2060 savepos = ss;
2061 at->at_oid = ldap_int_parse_numericoid(&ss,code,0);
2062 if ( !at->at_oid ) {
2063 if ( ( flags & ( LDAP_SCHEMA_ALLOW_NO_OID
2064 | LDAP_SCHEMA_ALLOW_OID_MACRO ) )
2065 && (ss == savepos) )
2067 /* Backtracking */
2068 ss = savepos;
2069 kind = get_token(&ss,&sval);
2070 if ( kind == TK_BAREWORD ) {
2071 if ( !strcasecmp(sval, "NAME") ||
2072 !strcasecmp(sval, "DESC") ||
2073 !strcasecmp(sval, "OBSOLETE") ||
2074 !strcasecmp(sval, "SUP") ||
2075 !strcasecmp(sval, "EQUALITY") ||
2076 !strcasecmp(sval, "ORDERING") ||
2077 !strcasecmp(sval, "SUBSTR") ||
2078 !strcasecmp(sval, "SYNTAX") ||
2079 !strcasecmp(sval, "SINGLE-VALUE") ||
2080 !strcasecmp(sval, "COLLECTIVE") ||
2081 !strcasecmp(sval, "NO-USER-MODIFICATION") ||
2082 !strcasecmp(sval, "USAGE") ||
2083 !strncasecmp(sval, "X-", 2) )
2085 /* Missing OID, backtrack */
2086 ss = savepos;
2087 } else if ( flags
2088 & LDAP_SCHEMA_ALLOW_OID_MACRO)
2090 /* Non-numerical OID ... */
2091 int len = ss-savepos;
2092 at->at_oid = LDAP_MALLOC(len+1);
2093 strncpy(at->at_oid, savepos, len);
2094 at->at_oid[len] = 0;
2097 LDAP_FREE(sval);
2098 } else {
2099 *errp = ss;
2100 ldap_attributetype_free(at);
2101 return NULL;
2104 parse_whsp(&ss);
2107 * Beyond this point we will be liberal and accept the items
2108 * in any order.
2110 while (1) {
2111 kind = get_token(&ss,&sval);
2112 switch (kind) {
2113 case TK_EOS:
2114 *code = LDAP_SCHERR_NORIGHTPAREN;
2115 *errp = EndOfInput;
2116 ldap_attributetype_free(at);
2117 return NULL;
2118 case TK_RIGHTPAREN:
2119 return at;
2120 case TK_BAREWORD:
2121 if ( !strcasecmp(sval,"NAME") ) {
2122 LDAP_FREE(sval);
2123 if ( seen_name ) {
2124 *code = LDAP_SCHERR_DUPOPT;
2125 *errp = ss;
2126 ldap_attributetype_free(at);
2127 return(NULL);
2129 seen_name = 1;
2130 at->at_names = parse_qdescrs(&ss,code);
2131 if ( !at->at_names ) {
2132 if ( *code != LDAP_SCHERR_OUTOFMEM )
2133 *code = LDAP_SCHERR_BADNAME;
2134 *errp = ss;
2135 ldap_attributetype_free(at);
2136 return NULL;
2138 } else if ( !strcasecmp(sval,"DESC") ) {
2139 LDAP_FREE(sval);
2140 if ( seen_desc ) {
2141 *code = LDAP_SCHERR_DUPOPT;
2142 *errp = ss;
2143 ldap_attributetype_free(at);
2144 return(NULL);
2146 seen_desc = 1;
2147 parse_whsp(&ss);
2148 kind = get_token(&ss,&sval);
2149 if ( kind != TK_QDSTRING ) {
2150 *code = LDAP_SCHERR_UNEXPTOKEN;
2151 *errp = ss;
2152 LDAP_FREE(sval);
2153 ldap_attributetype_free(at);
2154 return NULL;
2156 at->at_desc = sval;
2157 parse_whsp(&ss);
2158 } else if ( !strcasecmp(sval,"OBSOLETE") ) {
2159 LDAP_FREE(sval);
2160 if ( seen_obsolete ) {
2161 *code = LDAP_SCHERR_DUPOPT;
2162 *errp = ss;
2163 ldap_attributetype_free(at);
2164 return(NULL);
2166 seen_obsolete = 1;
2167 at->at_obsolete = LDAP_SCHEMA_YES;
2168 parse_whsp(&ss);
2169 } else if ( !strcasecmp(sval,"SUP") ) {
2170 LDAP_FREE(sval);
2171 if ( seen_sup ) {
2172 *code = LDAP_SCHERR_DUPOPT;
2173 *errp = ss;
2174 ldap_attributetype_free(at);
2175 return(NULL);
2177 seen_sup = 1;
2178 at->at_sup_oid = parse_woid(&ss,code);
2179 if ( !at->at_sup_oid ) {
2180 *errp = ss;
2181 ldap_attributetype_free(at);
2182 return NULL;
2184 } else if ( !strcasecmp(sval,"EQUALITY") ) {
2185 LDAP_FREE(sval);
2186 if ( seen_equality ) {
2187 *code = LDAP_SCHERR_DUPOPT;
2188 *errp = ss;
2189 ldap_attributetype_free(at);
2190 return(NULL);
2192 seen_equality = 1;
2193 at->at_equality_oid = parse_woid(&ss,code);
2194 if ( !at->at_equality_oid ) {
2195 *errp = ss;
2196 ldap_attributetype_free(at);
2197 return NULL;
2199 } else if ( !strcasecmp(sval,"ORDERING") ) {
2200 LDAP_FREE(sval);
2201 if ( seen_ordering ) {
2202 *code = LDAP_SCHERR_DUPOPT;
2203 *errp = ss;
2204 ldap_attributetype_free(at);
2205 return(NULL);
2207 seen_ordering = 1;
2208 at->at_ordering_oid = parse_woid(&ss,code);
2209 if ( !at->at_ordering_oid ) {
2210 *errp = ss;
2211 ldap_attributetype_free(at);
2212 return NULL;
2214 } else if ( !strcasecmp(sval,"SUBSTR") ) {
2215 LDAP_FREE(sval);
2216 if ( seen_substr ) {
2217 *code = LDAP_SCHERR_DUPOPT;
2218 *errp = ss;
2219 ldap_attributetype_free(at);
2220 return(NULL);
2222 seen_substr = 1;
2223 at->at_substr_oid = parse_woid(&ss,code);
2224 if ( !at->at_substr_oid ) {
2225 *errp = ss;
2226 ldap_attributetype_free(at);
2227 return NULL;
2229 } else if ( !strcasecmp(sval,"SYNTAX") ) {
2230 LDAP_FREE(sval);
2231 if ( seen_syntax ) {
2232 *code = LDAP_SCHERR_DUPOPT;
2233 *errp = ss;
2234 ldap_attributetype_free(at);
2235 return(NULL);
2237 seen_syntax = 1;
2238 parse_whsp(&ss);
2239 savepos = ss;
2240 at->at_syntax_oid =
2241 parse_noidlen(&ss,
2242 code,
2243 &at->at_syntax_len,
2244 flags);
2245 if ( !at->at_syntax_oid ) {
2246 if ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO ) {
2247 kind = get_token(&ss,&sval);
2248 if (kind == TK_BAREWORD)
2250 char *sp = strchr(sval, '{');
2251 at->at_syntax_oid = sval;
2252 if (sp)
2254 *sp++ = 0;
2255 at->at_syntax_len = atoi(sp);
2256 while ( LDAP_DIGIT(*sp) )
2257 sp++;
2258 if ( *sp != '}' ) {
2259 *code = LDAP_SCHERR_UNEXPTOKEN;
2260 *errp = ss;
2261 ldap_attributetype_free(at);
2262 return NULL;
2266 } else {
2267 *errp = ss;
2268 ldap_attributetype_free(at);
2269 return NULL;
2272 parse_whsp(&ss);
2273 } else if ( !strcasecmp(sval,"SINGLE-VALUE") ) {
2274 LDAP_FREE(sval);
2275 if ( at->at_single_value ) {
2276 *code = LDAP_SCHERR_DUPOPT;
2277 *errp = ss;
2278 ldap_attributetype_free(at);
2279 return(NULL);
2281 at->at_single_value = LDAP_SCHEMA_YES;
2282 parse_whsp(&ss);
2283 } else if ( !strcasecmp(sval,"COLLECTIVE") ) {
2284 LDAP_FREE(sval);
2285 if ( at->at_collective ) {
2286 *code = LDAP_SCHERR_DUPOPT;
2287 *errp = ss;
2288 ldap_attributetype_free(at);
2289 return(NULL);
2291 at->at_collective = LDAP_SCHEMA_YES;
2292 parse_whsp(&ss);
2293 } else if ( !strcasecmp(sval,"NO-USER-MODIFICATION") ) {
2294 LDAP_FREE(sval);
2295 if ( at->at_no_user_mod ) {
2296 *code = LDAP_SCHERR_DUPOPT;
2297 *errp = ss;
2298 ldap_attributetype_free(at);
2299 return(NULL);
2301 at->at_no_user_mod = LDAP_SCHEMA_YES;
2302 parse_whsp(&ss);
2303 } else if ( !strcasecmp(sval,"USAGE") ) {
2304 LDAP_FREE(sval);
2305 if ( seen_usage ) {
2306 *code = LDAP_SCHERR_DUPOPT;
2307 *errp = ss;
2308 ldap_attributetype_free(at);
2309 return(NULL);
2311 seen_usage = 1;
2312 parse_whsp(&ss);
2313 kind = get_token(&ss,&sval);
2314 if ( kind != TK_BAREWORD ) {
2315 *code = LDAP_SCHERR_UNEXPTOKEN;
2316 *errp = ss;
2317 LDAP_FREE(sval);
2318 ldap_attributetype_free(at);
2319 return NULL;
2321 if ( !strcasecmp(sval,"userApplications") )
2322 at->at_usage =
2323 LDAP_SCHEMA_USER_APPLICATIONS;
2324 else if ( !strcasecmp(sval,"directoryOperation") )
2325 at->at_usage =
2326 LDAP_SCHEMA_DIRECTORY_OPERATION;
2327 else if ( !strcasecmp(sval,"distributedOperation") )
2328 at->at_usage =
2329 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
2330 else if ( !strcasecmp(sval,"dSAOperation") )
2331 at->at_usage =
2332 LDAP_SCHEMA_DSA_OPERATION;
2333 else {
2334 *code = LDAP_SCHERR_UNEXPTOKEN;
2335 *errp = ss;
2336 LDAP_FREE(sval);
2337 ldap_attributetype_free(at);
2338 return NULL;
2340 LDAP_FREE(sval);
2341 parse_whsp(&ss);
2342 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
2343 /* Should be parse_qdstrings */
2344 ext_vals = parse_qdescrs(&ss, code);
2345 if ( !ext_vals ) {
2346 *errp = ss;
2347 ldap_attributetype_free(at);
2348 return NULL;
2350 if ( add_extension(&at->at_extensions,
2351 sval, ext_vals) ) {
2352 *code = LDAP_SCHERR_OUTOFMEM;
2353 *errp = ss;
2354 LDAP_FREE(sval);
2355 ldap_attributetype_free(at);
2356 return NULL;
2358 } else {
2359 *code = LDAP_SCHERR_UNEXPTOKEN;
2360 *errp = ss;
2361 LDAP_FREE(sval);
2362 ldap_attributetype_free(at);
2363 return NULL;
2365 break;
2366 default:
2367 *code = LDAP_SCHERR_UNEXPTOKEN;
2368 *errp = ss;
2369 LDAP_FREE(sval);
2370 ldap_attributetype_free(at);
2371 return NULL;
2376 void
2377 ldap_objectclass_free(LDAPObjectClass * oc)
2379 LDAP_FREE(oc->oc_oid);
2380 if (oc->oc_names) LDAP_VFREE(oc->oc_names);
2381 if (oc->oc_desc) LDAP_FREE(oc->oc_desc);
2382 if (oc->oc_sup_oids) LDAP_VFREE(oc->oc_sup_oids);
2383 if (oc->oc_at_oids_must) LDAP_VFREE(oc->oc_at_oids_must);
2384 if (oc->oc_at_oids_may) LDAP_VFREE(oc->oc_at_oids_may);
2385 free_extensions(oc->oc_extensions);
2386 LDAP_FREE(oc);
2389 LDAPObjectClass *
2390 ldap_str2objectclass( LDAP_CONST char * s,
2391 int * code,
2392 LDAP_CONST char ** errp,
2393 LDAP_CONST unsigned flags )
2395 tk_t kind;
2396 const char * ss = s;
2397 char * sval;
2398 int seen_name = 0;
2399 int seen_desc = 0;
2400 int seen_obsolete = 0;
2401 int seen_sup = 0;
2402 int seen_kind = 0;
2403 int seen_must = 0;
2404 int seen_may = 0;
2405 LDAPObjectClass * oc;
2406 char ** ext_vals;
2407 const char * savepos;
2409 if ( !s ) {
2410 *code = LDAP_SCHERR_EMPTY;
2411 *errp = "";
2412 return NULL;
2415 *errp = s;
2416 oc = LDAP_CALLOC(1,sizeof(LDAPObjectClass));
2418 if ( !oc ) {
2419 *code = LDAP_SCHERR_OUTOFMEM;
2420 return NULL;
2422 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
2424 kind = get_token(&ss,&sval);
2425 if ( kind != TK_LEFTPAREN ) {
2426 *code = LDAP_SCHERR_NOLEFTPAREN;
2427 LDAP_FREE(sval);
2428 ldap_objectclass_free(oc);
2429 return NULL;
2433 * Definitions MUST begin with an OID in the numericoid format.
2434 * However, this routine is used by clients to parse the response
2435 * from servers and very well known servers will provide an OID
2436 * in the wrong format or even no OID at all. We do our best to
2437 * extract info from those servers.
2439 parse_whsp(&ss);
2440 savepos = ss;
2441 oc->oc_oid = ldap_int_parse_numericoid(&ss,code,0);
2442 if ( !oc->oc_oid ) {
2443 if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) {
2444 /* Backtracking */
2445 ss = savepos;
2446 kind = get_token(&ss,&sval);
2447 if ( kind == TK_BAREWORD ) {
2448 if ( !strcasecmp(sval, "NAME") ||
2449 !strcasecmp(sval, "DESC") ||
2450 !strcasecmp(sval, "OBSOLETE") ||
2451 !strcasecmp(sval, "SUP") ||
2452 !strcasecmp(sval, "ABSTRACT") ||
2453 !strcasecmp(sval, "STRUCTURAL") ||
2454 !strcasecmp(sval, "AUXILIARY") ||
2455 !strcasecmp(sval, "MUST") ||
2456 !strcasecmp(sval, "MAY") ||
2457 !strncasecmp(sval, "X-", 2) ) {
2458 /* Missing OID, backtrack */
2459 ss = savepos;
2460 } else if ( flags &
2461 LDAP_SCHEMA_ALLOW_OID_MACRO ) {
2462 /* Non-numerical OID, ignore */
2463 int len = ss-savepos;
2464 oc->oc_oid = LDAP_MALLOC(len+1);
2465 strncpy(oc->oc_oid, savepos, len);
2466 oc->oc_oid[len] = 0;
2469 LDAP_FREE(sval);
2470 *code = 0;
2471 } else {
2472 *errp = ss;
2473 ldap_objectclass_free(oc);
2474 return NULL;
2477 parse_whsp(&ss);
2480 * Beyond this point we will be liberal an accept the items
2481 * in any order.
2483 while (1) {
2484 kind = get_token(&ss,&sval);
2485 switch (kind) {
2486 case TK_EOS:
2487 *code = LDAP_SCHERR_NORIGHTPAREN;
2488 *errp = EndOfInput;
2489 ldap_objectclass_free(oc);
2490 return NULL;
2491 case TK_RIGHTPAREN:
2492 return oc;
2493 case TK_BAREWORD:
2494 if ( !strcasecmp(sval,"NAME") ) {
2495 LDAP_FREE(sval);
2496 if ( seen_name ) {
2497 *code = LDAP_SCHERR_DUPOPT;
2498 *errp = ss;
2499 ldap_objectclass_free(oc);
2500 return(NULL);
2502 seen_name = 1;
2503 oc->oc_names = parse_qdescrs(&ss,code);
2504 if ( !oc->oc_names ) {
2505 if ( *code != LDAP_SCHERR_OUTOFMEM )
2506 *code = LDAP_SCHERR_BADNAME;
2507 *errp = ss;
2508 ldap_objectclass_free(oc);
2509 return NULL;
2511 } else if ( !strcasecmp(sval,"DESC") ) {
2512 LDAP_FREE(sval);
2513 if ( seen_desc ) {
2514 *code = LDAP_SCHERR_DUPOPT;
2515 *errp = ss;
2516 ldap_objectclass_free(oc);
2517 return(NULL);
2519 seen_desc = 1;
2520 parse_whsp(&ss);
2521 kind = get_token(&ss,&sval);
2522 if ( kind != TK_QDSTRING ) {
2523 *code = LDAP_SCHERR_UNEXPTOKEN;
2524 *errp = ss;
2525 LDAP_FREE(sval);
2526 ldap_objectclass_free(oc);
2527 return NULL;
2529 oc->oc_desc = sval;
2530 parse_whsp(&ss);
2531 } else if ( !strcasecmp(sval,"OBSOLETE") ) {
2532 LDAP_FREE(sval);
2533 if ( seen_obsolete ) {
2534 *code = LDAP_SCHERR_DUPOPT;
2535 *errp = ss;
2536 ldap_objectclass_free(oc);
2537 return(NULL);
2539 seen_obsolete = 1;
2540 oc->oc_obsolete = LDAP_SCHEMA_YES;
2541 parse_whsp(&ss);
2542 } else if ( !strcasecmp(sval,"SUP") ) {
2543 LDAP_FREE(sval);
2544 if ( seen_sup ) {
2545 *code = LDAP_SCHERR_DUPOPT;
2546 *errp = ss;
2547 ldap_objectclass_free(oc);
2548 return(NULL);
2550 seen_sup = 1;
2551 oc->oc_sup_oids = parse_oids(&ss,
2552 code,
2553 flags);
2554 if ( !oc->oc_sup_oids && *code != LDAP_SUCCESS ) {
2555 *errp = ss;
2556 ldap_objectclass_free(oc);
2557 return NULL;
2559 *code = 0;
2560 } else if ( !strcasecmp(sval,"ABSTRACT") ) {
2561 LDAP_FREE(sval);
2562 if ( seen_kind ) {
2563 *code = LDAP_SCHERR_DUPOPT;
2564 *errp = ss;
2565 ldap_objectclass_free(oc);
2566 return(NULL);
2568 seen_kind = 1;
2569 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
2570 parse_whsp(&ss);
2571 } else if ( !strcasecmp(sval,"STRUCTURAL") ) {
2572 LDAP_FREE(sval);
2573 if ( seen_kind ) {
2574 *code = LDAP_SCHERR_DUPOPT;
2575 *errp = ss;
2576 ldap_objectclass_free(oc);
2577 return(NULL);
2579 seen_kind = 1;
2580 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
2581 parse_whsp(&ss);
2582 } else if ( !strcasecmp(sval,"AUXILIARY") ) {
2583 LDAP_FREE(sval);
2584 if ( seen_kind ) {
2585 *code = LDAP_SCHERR_DUPOPT;
2586 *errp = ss;
2587 ldap_objectclass_free(oc);
2588 return(NULL);
2590 seen_kind = 1;
2591 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
2592 parse_whsp(&ss);
2593 } else if ( !strcasecmp(sval,"MUST") ) {
2594 LDAP_FREE(sval);
2595 if ( seen_must ) {
2596 *code = LDAP_SCHERR_DUPOPT;
2597 *errp = ss;
2598 ldap_objectclass_free(oc);
2599 return(NULL);
2601 seen_must = 1;
2602 oc->oc_at_oids_must = parse_oids(&ss,code,0);
2603 if ( !oc->oc_at_oids_must && *code != LDAP_SUCCESS ) {
2604 *errp = ss;
2605 ldap_objectclass_free(oc);
2606 return NULL;
2608 *code = 0;
2609 parse_whsp(&ss);
2610 } else if ( !strcasecmp(sval,"MAY") ) {
2611 LDAP_FREE(sval);
2612 if ( seen_may ) {
2613 *code = LDAP_SCHERR_DUPOPT;
2614 *errp = ss;
2615 ldap_objectclass_free(oc);
2616 return(NULL);
2618 seen_may = 1;
2619 oc->oc_at_oids_may = parse_oids(&ss,code,0);
2620 if ( !oc->oc_at_oids_may && *code != LDAP_SUCCESS ) {
2621 *errp = ss;
2622 ldap_objectclass_free(oc);
2623 return NULL;
2625 *code = 0;
2626 parse_whsp(&ss);
2627 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
2628 /* Should be parse_qdstrings */
2629 ext_vals = parse_qdescrs(&ss, code);
2630 *code = 0;
2631 if ( !ext_vals ) {
2632 *errp = ss;
2633 ldap_objectclass_free(oc);
2634 return NULL;
2636 if ( add_extension(&oc->oc_extensions,
2637 sval, ext_vals) ) {
2638 *code = LDAP_SCHERR_OUTOFMEM;
2639 *errp = ss;
2640 LDAP_FREE(sval);
2641 ldap_objectclass_free(oc);
2642 return NULL;
2644 } else {
2645 *code = LDAP_SCHERR_UNEXPTOKEN;
2646 *errp = ss;
2647 LDAP_FREE(sval);
2648 ldap_objectclass_free(oc);
2649 return NULL;
2651 break;
2652 default:
2653 *code = LDAP_SCHERR_UNEXPTOKEN;
2654 *errp = ss;
2655 LDAP_FREE(sval);
2656 ldap_objectclass_free(oc);
2657 return NULL;
2662 void
2663 ldap_contentrule_free(LDAPContentRule * cr)
2665 LDAP_FREE(cr->cr_oid);
2666 if (cr->cr_names) LDAP_VFREE(cr->cr_names);
2667 if (cr->cr_desc) LDAP_FREE(cr->cr_desc);
2668 if (cr->cr_oc_oids_aux) LDAP_VFREE(cr->cr_oc_oids_aux);
2669 if (cr->cr_at_oids_must) LDAP_VFREE(cr->cr_at_oids_must);
2670 if (cr->cr_at_oids_may) LDAP_VFREE(cr->cr_at_oids_may);
2671 if (cr->cr_at_oids_not) LDAP_VFREE(cr->cr_at_oids_not);
2672 free_extensions(cr->cr_extensions);
2673 LDAP_FREE(cr);
2676 LDAPContentRule *
2677 ldap_str2contentrule( LDAP_CONST char * s,
2678 int * code,
2679 LDAP_CONST char ** errp,
2680 LDAP_CONST unsigned flags )
2682 tk_t kind;
2683 const char * ss = s;
2684 char * sval;
2685 int seen_name = 0;
2686 int seen_desc = 0;
2687 int seen_obsolete = 0;
2688 int seen_aux = 0;
2689 int seen_must = 0;
2690 int seen_may = 0;
2691 int seen_not = 0;
2692 LDAPContentRule * cr;
2693 char ** ext_vals;
2694 const char * savepos;
2696 if ( !s ) {
2697 *code = LDAP_SCHERR_EMPTY;
2698 *errp = "";
2699 return NULL;
2702 *errp = s;
2703 cr = LDAP_CALLOC(1,sizeof(LDAPContentRule));
2705 if ( !cr ) {
2706 *code = LDAP_SCHERR_OUTOFMEM;
2707 return NULL;
2710 kind = get_token(&ss,&sval);
2711 if ( kind != TK_LEFTPAREN ) {
2712 *code = LDAP_SCHERR_NOLEFTPAREN;
2713 LDAP_FREE(sval);
2714 ldap_contentrule_free(cr);
2715 return NULL;
2719 * Definitions MUST begin with an OID in the numericoid format.
2721 parse_whsp(&ss);
2722 savepos = ss;
2723 cr->cr_oid = ldap_int_parse_numericoid(&ss,code,0);
2724 if ( !cr->cr_oid ) {
2725 if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) {
2726 /* Backtracking */
2727 ss = savepos;
2728 kind = get_token(&ss,&sval);
2729 if ( kind == TK_BAREWORD ) {
2730 if ( !strcasecmp(sval, "NAME") ||
2731 !strcasecmp(sval, "DESC") ||
2732 !strcasecmp(sval, "OBSOLETE") ||
2733 !strcasecmp(sval, "AUX") ||
2734 !strcasecmp(sval, "MUST") ||
2735 !strcasecmp(sval, "MAY") ||
2736 !strcasecmp(sval, "NOT") ||
2737 !strncasecmp(sval, "X-", 2) ) {
2738 /* Missing OID, backtrack */
2739 ss = savepos;
2740 } else if ( flags &
2741 LDAP_SCHEMA_ALLOW_OID_MACRO ) {
2742 /* Non-numerical OID, ignore */
2743 int len = ss-savepos;
2744 cr->cr_oid = LDAP_MALLOC(len+1);
2745 strncpy(cr->cr_oid, savepos, len);
2746 cr->cr_oid[len] = 0;
2749 LDAP_FREE(sval);
2750 } else {
2751 *errp = ss;
2752 ldap_contentrule_free(cr);
2753 return NULL;
2756 parse_whsp(&ss);
2759 * Beyond this point we will be liberal an accept the items
2760 * in any order.
2762 while (1) {
2763 kind = get_token(&ss,&sval);
2764 switch (kind) {
2765 case TK_EOS:
2766 *code = LDAP_SCHERR_NORIGHTPAREN;
2767 *errp = EndOfInput;
2768 ldap_contentrule_free(cr);
2769 return NULL;
2770 case TK_RIGHTPAREN:
2771 return cr;
2772 case TK_BAREWORD:
2773 if ( !strcasecmp(sval,"NAME") ) {
2774 LDAP_FREE(sval);
2775 if ( seen_name ) {
2776 *code = LDAP_SCHERR_DUPOPT;
2777 *errp = ss;
2778 ldap_contentrule_free(cr);
2779 return(NULL);
2781 seen_name = 1;
2782 cr->cr_names = parse_qdescrs(&ss,code);
2783 if ( !cr->cr_names ) {
2784 if ( *code != LDAP_SCHERR_OUTOFMEM )
2785 *code = LDAP_SCHERR_BADNAME;
2786 *errp = ss;
2787 ldap_contentrule_free(cr);
2788 return NULL;
2790 } else if ( !strcasecmp(sval,"DESC") ) {
2791 LDAP_FREE(sval);
2792 if ( seen_desc ) {
2793 *code = LDAP_SCHERR_DUPOPT;
2794 *errp = ss;
2795 ldap_contentrule_free(cr);
2796 return(NULL);
2798 seen_desc = 1;
2799 parse_whsp(&ss);
2800 kind = get_token(&ss,&sval);
2801 if ( kind != TK_QDSTRING ) {
2802 *code = LDAP_SCHERR_UNEXPTOKEN;
2803 *errp = ss;
2804 LDAP_FREE(sval);
2805 ldap_contentrule_free(cr);
2806 return NULL;
2808 cr->cr_desc = sval;
2809 parse_whsp(&ss);
2810 } else if ( !strcasecmp(sval,"OBSOLETE") ) {
2811 LDAP_FREE(sval);
2812 if ( seen_obsolete ) {
2813 *code = LDAP_SCHERR_DUPOPT;
2814 *errp = ss;
2815 ldap_contentrule_free(cr);
2816 return(NULL);
2818 seen_obsolete = 1;
2819 cr->cr_obsolete = LDAP_SCHEMA_YES;
2820 parse_whsp(&ss);
2821 } else if ( !strcasecmp(sval,"AUX") ) {
2822 LDAP_FREE(sval);
2823 if ( seen_aux ) {
2824 *code = LDAP_SCHERR_DUPOPT;
2825 *errp = ss;
2826 ldap_contentrule_free(cr);
2827 return(NULL);
2829 seen_aux = 1;
2830 cr->cr_oc_oids_aux = parse_oids(&ss,code,0);
2831 if ( !cr->cr_oc_oids_aux ) {
2832 *errp = ss;
2833 ldap_contentrule_free(cr);
2834 return NULL;
2836 parse_whsp(&ss);
2837 } else if ( !strcasecmp(sval,"MUST") ) {
2838 LDAP_FREE(sval);
2839 if ( seen_must ) {
2840 *code = LDAP_SCHERR_DUPOPT;
2841 *errp = ss;
2842 ldap_contentrule_free(cr);
2843 return(NULL);
2845 seen_must = 1;
2846 cr->cr_at_oids_must = parse_oids(&ss,code,0);
2847 if ( !cr->cr_at_oids_must && *code != LDAP_SUCCESS ) {
2848 *errp = ss;
2849 ldap_contentrule_free(cr);
2850 return NULL;
2852 parse_whsp(&ss);
2853 } else if ( !strcasecmp(sval,"MAY") ) {
2854 LDAP_FREE(sval);
2855 if ( seen_may ) {
2856 *code = LDAP_SCHERR_DUPOPT;
2857 *errp = ss;
2858 ldap_contentrule_free(cr);
2859 return(NULL);
2861 seen_may = 1;
2862 cr->cr_at_oids_may = parse_oids(&ss,code,0);
2863 if ( !cr->cr_at_oids_may && *code != LDAP_SUCCESS ) {
2864 *errp = ss;
2865 ldap_contentrule_free(cr);
2866 return NULL;
2868 parse_whsp(&ss);
2869 } else if ( !strcasecmp(sval,"NOT") ) {
2870 LDAP_FREE(sval);
2871 if ( seen_not ) {
2872 *code = LDAP_SCHERR_DUPOPT;
2873 *errp = ss;
2874 ldap_contentrule_free(cr);
2875 return(NULL);
2877 seen_not = 1;
2878 cr->cr_at_oids_not = parse_oids(&ss,code,0);
2879 if ( !cr->cr_at_oids_not && *code != LDAP_SUCCESS ) {
2880 *errp = ss;
2881 ldap_contentrule_free(cr);
2882 return NULL;
2884 parse_whsp(&ss);
2885 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
2886 /* Should be parse_qdstrings */
2887 ext_vals = parse_qdescrs(&ss, code);
2888 if ( !ext_vals ) {
2889 *errp = ss;
2890 ldap_contentrule_free(cr);
2891 return NULL;
2893 if ( add_extension(&cr->cr_extensions,
2894 sval, ext_vals) ) {
2895 *code = LDAP_SCHERR_OUTOFMEM;
2896 *errp = ss;
2897 LDAP_FREE(sval);
2898 ldap_contentrule_free(cr);
2899 return NULL;
2901 } else {
2902 *code = LDAP_SCHERR_UNEXPTOKEN;
2903 *errp = ss;
2904 LDAP_FREE(sval);
2905 ldap_contentrule_free(cr);
2906 return NULL;
2908 break;
2909 default:
2910 *code = LDAP_SCHERR_UNEXPTOKEN;
2911 *errp = ss;
2912 LDAP_FREE(sval);
2913 ldap_contentrule_free(cr);
2914 return NULL;
2919 void
2920 ldap_structurerule_free(LDAPStructureRule * sr)
2922 if (sr->sr_names) LDAP_VFREE(sr->sr_names);
2923 if (sr->sr_desc) LDAP_FREE(sr->sr_desc);
2924 if (sr->sr_nameform) LDAP_FREE(sr->sr_nameform);
2925 if (sr->sr_sup_ruleids) LDAP_FREE(sr->sr_sup_ruleids);
2926 free_extensions(sr->sr_extensions);
2927 LDAP_FREE(sr);
2930 LDAPStructureRule *
2931 ldap_str2structurerule( LDAP_CONST char * s,
2932 int * code,
2933 LDAP_CONST char ** errp,
2934 LDAP_CONST unsigned flags )
2936 tk_t kind;
2937 int ret;
2938 const char * ss = s;
2939 char * sval;
2940 int seen_name = 0;
2941 int seen_desc = 0;
2942 int seen_obsolete = 0;
2943 int seen_nameform = 0;
2944 LDAPStructureRule * sr;
2945 char ** ext_vals;
2946 const char * savepos;
2948 if ( !s ) {
2949 *code = LDAP_SCHERR_EMPTY;
2950 *errp = "";
2951 return NULL;
2954 *errp = s;
2955 sr = LDAP_CALLOC(1,sizeof(LDAPStructureRule));
2957 if ( !sr ) {
2958 *code = LDAP_SCHERR_OUTOFMEM;
2959 return NULL;
2962 kind = get_token(&ss,&sval);
2963 if ( kind != TK_LEFTPAREN ) {
2964 *code = LDAP_SCHERR_NOLEFTPAREN;
2965 LDAP_FREE(sval);
2966 ldap_structurerule_free(sr);
2967 return NULL;
2971 * Definitions MUST begin with a ruleid.
2973 parse_whsp(&ss);
2974 savepos = ss;
2975 ret = ldap_int_parse_ruleid(&ss,code,0,&sr->sr_ruleid);
2976 if ( ret ) {
2977 *errp = ss;
2978 ldap_structurerule_free(sr);
2979 return NULL;
2981 parse_whsp(&ss);
2984 * Beyond this point we will be liberal an accept the items
2985 * in any order.
2987 while (1) {
2988 kind = get_token(&ss,&sval);
2989 switch (kind) {
2990 case TK_EOS:
2991 *code = LDAP_SCHERR_NORIGHTPAREN;
2992 *errp = EndOfInput;
2993 ldap_structurerule_free(sr);
2994 return NULL;
2995 case TK_RIGHTPAREN:
2996 if( !seen_nameform ) {
2997 *code = LDAP_SCHERR_MISSING;
2998 ldap_structurerule_free(sr);
2999 return NULL;
3001 return sr;
3002 case TK_BAREWORD:
3003 if ( !strcasecmp(sval,"NAME") ) {
3004 LDAP_FREE(sval);
3005 if ( seen_name ) {
3006 *code = LDAP_SCHERR_DUPOPT;
3007 *errp = ss;
3008 ldap_structurerule_free(sr);
3009 return(NULL);
3011 seen_name = 1;
3012 sr->sr_names = parse_qdescrs(&ss,code);
3013 if ( !sr->sr_names ) {
3014 if ( *code != LDAP_SCHERR_OUTOFMEM )
3015 *code = LDAP_SCHERR_BADNAME;
3016 *errp = ss;
3017 ldap_structurerule_free(sr);
3018 return NULL;
3020 } else if ( !strcasecmp(sval,"DESC") ) {
3021 LDAP_FREE(sval);
3022 if ( seen_desc ) {
3023 *code = LDAP_SCHERR_DUPOPT;
3024 *errp = ss;
3025 ldap_structurerule_free(sr);
3026 return(NULL);
3028 seen_desc = 1;
3029 parse_whsp(&ss);
3030 kind = get_token(&ss,&sval);
3031 if ( kind != TK_QDSTRING ) {
3032 *code = LDAP_SCHERR_UNEXPTOKEN;
3033 *errp = ss;
3034 LDAP_FREE(sval);
3035 ldap_structurerule_free(sr);
3036 return NULL;
3038 sr->sr_desc = sval;
3039 parse_whsp(&ss);
3040 } else if ( !strcasecmp(sval,"OBSOLETE") ) {
3041 LDAP_FREE(sval);
3042 if ( seen_obsolete ) {
3043 *code = LDAP_SCHERR_DUPOPT;
3044 *errp = ss;
3045 ldap_structurerule_free(sr);
3046 return(NULL);
3048 seen_obsolete = 1;
3049 sr->sr_obsolete = LDAP_SCHEMA_YES;
3050 parse_whsp(&ss);
3051 } else if ( !strcasecmp(sval,"FORM") ) {
3052 LDAP_FREE(sval);
3053 if ( seen_nameform ) {
3054 *code = LDAP_SCHERR_DUPOPT;
3055 *errp = ss;
3056 ldap_structurerule_free(sr);
3057 return(NULL);
3059 seen_nameform = 1;
3060 sr->sr_nameform = parse_woid(&ss,code);
3061 if ( !sr->sr_nameform ) {
3062 *errp = ss;
3063 ldap_structurerule_free(sr);
3064 return NULL;
3066 parse_whsp(&ss);
3067 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
3068 /* Should be parse_qdstrings */
3069 ext_vals = parse_qdescrs(&ss, code);
3070 if ( !ext_vals ) {
3071 *errp = ss;
3072 ldap_structurerule_free(sr);
3073 return NULL;
3075 if ( add_extension(&sr->sr_extensions,
3076 sval, ext_vals) ) {
3077 *code = LDAP_SCHERR_OUTOFMEM;
3078 *errp = ss;
3079 LDAP_FREE(sval);
3080 ldap_structurerule_free(sr);
3081 return NULL;
3083 } else {
3084 *code = LDAP_SCHERR_UNEXPTOKEN;
3085 *errp = ss;
3086 LDAP_FREE(sval);
3087 ldap_structurerule_free(sr);
3088 return NULL;
3090 break;
3091 default:
3092 *code = LDAP_SCHERR_UNEXPTOKEN;
3093 *errp = ss;
3094 LDAP_FREE(sval);
3095 ldap_structurerule_free(sr);
3096 return NULL;
3101 void
3102 ldap_nameform_free(LDAPNameForm * nf)
3104 LDAP_FREE(nf->nf_oid);
3105 if (nf->nf_names) LDAP_VFREE(nf->nf_names);
3106 if (nf->nf_desc) LDAP_FREE(nf->nf_desc);
3107 if (nf->nf_objectclass) LDAP_FREE(nf->nf_objectclass);
3108 if (nf->nf_at_oids_must) LDAP_VFREE(nf->nf_at_oids_must);
3109 if (nf->nf_at_oids_may) LDAP_VFREE(nf->nf_at_oids_may);
3110 free_extensions(nf->nf_extensions);
3111 LDAP_FREE(nf);
3114 LDAPNameForm *
3115 ldap_str2nameform( LDAP_CONST char * s,
3116 int * code,
3117 LDAP_CONST char ** errp,
3118 LDAP_CONST unsigned flags )
3120 tk_t kind;
3121 const char * ss = s;
3122 char * sval;
3123 int seen_name = 0;
3124 int seen_desc = 0;
3125 int seen_obsolete = 0;
3126 int seen_class = 0;
3127 int seen_must = 0;
3128 int seen_may = 0;
3129 LDAPNameForm * nf;
3130 char ** ext_vals;
3131 const char * savepos;
3133 if ( !s ) {
3134 *code = LDAP_SCHERR_EMPTY;
3135 *errp = "";
3136 return NULL;
3139 *errp = s;
3140 nf = LDAP_CALLOC(1,sizeof(LDAPNameForm));
3142 if ( !nf ) {
3143 *code = LDAP_SCHERR_OUTOFMEM;
3144 return NULL;
3147 kind = get_token(&ss,&sval);
3148 if ( kind != TK_LEFTPAREN ) {
3149 *code = LDAP_SCHERR_NOLEFTPAREN;
3150 LDAP_FREE(sval);
3151 ldap_nameform_free(nf);
3152 return NULL;
3156 * Definitions MUST begin with an OID in the numericoid format.
3157 * However, this routine is used by clients to parse the response
3158 * from servers and very well known servers will provide an OID
3159 * in the wrong format or even no OID at all. We do our best to
3160 * extract info from those servers.
3162 parse_whsp(&ss);
3163 savepos = ss;
3164 nf->nf_oid = ldap_int_parse_numericoid(&ss,code,0);
3165 if ( !nf->nf_oid ) {
3166 *errp = ss;
3167 ldap_nameform_free(nf);
3168 return NULL;
3170 parse_whsp(&ss);
3173 * Beyond this point we will be liberal an accept the items
3174 * in any order.
3176 while (1) {
3177 kind = get_token(&ss,&sval);
3178 switch (kind) {
3179 case TK_EOS:
3180 *code = LDAP_SCHERR_NORIGHTPAREN;
3181 *errp = EndOfInput;
3182 ldap_nameform_free(nf);
3183 return NULL;
3184 case TK_RIGHTPAREN:
3185 if( !seen_class || !seen_must ) {
3186 *code = LDAP_SCHERR_MISSING;
3187 ldap_nameform_free(nf);
3188 return NULL;
3190 return nf;
3191 case TK_BAREWORD:
3192 if ( !strcasecmp(sval,"NAME") ) {
3193 LDAP_FREE(sval);
3194 if ( seen_name ) {
3195 *code = LDAP_SCHERR_DUPOPT;
3196 *errp = ss;
3197 ldap_nameform_free(nf);
3198 return(NULL);
3200 seen_name = 1;
3201 nf->nf_names = parse_qdescrs(&ss,code);
3202 if ( !nf->nf_names ) {
3203 if ( *code != LDAP_SCHERR_OUTOFMEM )
3204 *code = LDAP_SCHERR_BADNAME;
3205 *errp = ss;
3206 ldap_nameform_free(nf);
3207 return NULL;
3209 } else if ( !strcasecmp(sval,"DESC") ) {
3210 LDAP_FREE(sval);
3211 if ( seen_desc ) {
3212 *code = LDAP_SCHERR_DUPOPT;
3213 *errp = ss;
3214 ldap_nameform_free(nf);
3215 return(NULL);
3217 seen_desc = 1;
3218 parse_whsp(&ss);
3219 kind = get_token(&ss,&sval);
3220 if ( kind != TK_QDSTRING ) {
3221 *code = LDAP_SCHERR_UNEXPTOKEN;
3222 *errp = ss;
3223 LDAP_FREE(sval);
3224 ldap_nameform_free(nf);
3225 return NULL;
3227 nf->nf_desc = sval;
3228 parse_whsp(&ss);
3229 } else if ( !strcasecmp(sval,"OBSOLETE") ) {
3230 LDAP_FREE(sval);
3231 if ( seen_obsolete ) {
3232 *code = LDAP_SCHERR_DUPOPT;
3233 *errp = ss;
3234 ldap_nameform_free(nf);
3235 return(NULL);
3237 seen_obsolete = 1;
3238 nf->nf_obsolete = LDAP_SCHEMA_YES;
3239 parse_whsp(&ss);
3240 } else if ( !strcasecmp(sval,"OC") ) {
3241 LDAP_FREE(sval);
3242 if ( seen_class ) {
3243 *code = LDAP_SCHERR_DUPOPT;
3244 *errp = ss;
3245 ldap_nameform_free(nf);
3246 return(NULL);
3248 seen_class = 1;
3249 nf->nf_objectclass = parse_woid(&ss,code);
3250 if ( !nf->nf_objectclass ) {
3251 *errp = ss;
3252 ldap_nameform_free(nf);
3253 return NULL;
3255 } else if ( !strcasecmp(sval,"MUST") ) {
3256 LDAP_FREE(sval);
3257 if ( seen_must ) {
3258 *code = LDAP_SCHERR_DUPOPT;
3259 *errp = ss;
3260 ldap_nameform_free(nf);
3261 return(NULL);
3263 seen_must = 1;
3264 nf->nf_at_oids_must = parse_oids(&ss,code,0);
3265 if ( !nf->nf_at_oids_must && *code != LDAP_SUCCESS ) {
3266 *errp = ss;
3267 ldap_nameform_free(nf);
3268 return NULL;
3270 parse_whsp(&ss);
3271 } else if ( !strcasecmp(sval,"MAY") ) {
3272 LDAP_FREE(sval);
3273 if ( seen_may ) {
3274 *code = LDAP_SCHERR_DUPOPT;
3275 *errp = ss;
3276 ldap_nameform_free(nf);
3277 return(NULL);
3279 seen_may = 1;
3280 nf->nf_at_oids_may = parse_oids(&ss,code,0);
3281 if ( !nf->nf_at_oids_may && *code != LDAP_SUCCESS ) {
3282 *errp = ss;
3283 ldap_nameform_free(nf);
3284 return NULL;
3286 parse_whsp(&ss);
3287 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
3288 /* Should be parse_qdstrings */
3289 ext_vals = parse_qdescrs(&ss, code);
3290 if ( !ext_vals ) {
3291 *errp = ss;
3292 ldap_nameform_free(nf);
3293 return NULL;
3295 if ( add_extension(&nf->nf_extensions,
3296 sval, ext_vals) ) {
3297 *code = LDAP_SCHERR_OUTOFMEM;
3298 *errp = ss;
3299 LDAP_FREE(sval);
3300 ldap_nameform_free(nf);
3301 return NULL;
3303 } else {
3304 *code = LDAP_SCHERR_UNEXPTOKEN;
3305 *errp = ss;
3306 LDAP_FREE(sval);
3307 ldap_nameform_free(nf);
3308 return NULL;
3310 break;
3311 default:
3312 *code = LDAP_SCHERR_UNEXPTOKEN;
3313 *errp = ss;
3314 LDAP_FREE(sval);
3315 ldap_nameform_free(nf);
3316 return NULL;
3321 static char *const err2text[] = {
3322 N_("Success"),
3323 N_("Out of memory"),
3324 N_("Unexpected token"),
3325 N_("Missing opening parenthesis"),
3326 N_("Missing closing parenthesis"),
3327 N_("Expecting digit"),
3328 N_("Expecting a name"),
3329 N_("Bad description"),
3330 N_("Bad superiors"),
3331 N_("Duplicate option"),
3332 N_("Unexpected end of data"),
3333 N_("Missing required field"),
3334 N_("Out of order field")
3337 char *
3338 ldap_scherr2str(int code)
3340 if ( code < 0 || code >= (int)(sizeof(err2text)/sizeof(char *)) ) {
3341 return _("Unknown error");
3342 } else {
3343 return _(err2text[code]);