libs: Import code from upstream openldap 2.5.13.
[wine.git] / libs / ldap / libldap / schema.c
blob2c477bde73423204933ee4bcad571a4ca7fe3d6b
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 * Copyright 1998-2022 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 if (!syn) return NULL;
45 return( syn->syn_oid );
48 LDAP_CONST char *
49 ldap_matchingrule2name( LDAPMatchingRule * mr )
51 if (!mr) return NULL;
52 return( choose_name( mr->mr_names, mr->mr_oid ) );
55 LDAP_CONST char *
56 ldap_matchingruleuse2name( LDAPMatchingRuleUse * mru )
58 if (!mru) return NULL;
59 return( choose_name( mru->mru_names, mru->mru_oid ) );
62 LDAP_CONST char *
63 ldap_attributetype2name( LDAPAttributeType * at )
65 if (!at) return NULL;
66 return( choose_name( at->at_names, at->at_oid ) );
69 LDAP_CONST char *
70 ldap_objectclass2name( LDAPObjectClass * oc )
72 if (!oc) return NULL;
73 return( choose_name( oc->oc_names, oc->oc_oid ) );
76 LDAP_CONST char *
77 ldap_contentrule2name( LDAPContentRule * cr )
79 if (!cr) return NULL;
80 return( choose_name( cr->cr_names, cr->cr_oid ) );
83 LDAP_CONST char *
84 ldap_nameform2name( LDAPNameForm * nf )
86 if (!nf) return NULL;
87 return( choose_name( nf->nf_names, nf->nf_oid ) );
90 LDAP_CONST char *
91 ldap_structurerule2name( LDAPStructureRule * sr )
93 if (!sr) return NULL;
94 return( choose_name( sr->sr_names, NULL ) );
98 * When pretty printing the entities we will be appending to a buffer.
99 * Since checking for overflow, realloc'ing and checking if no error
100 * is extremely boring, we will use a protection layer that will let
101 * us blissfully ignore the error until the end. This layer is
102 * implemented with the help of the next type.
105 typedef struct safe_string {
106 char * val;
107 ber_len_t size;
108 ber_len_t pos;
109 int at_whsp;
110 } safe_string;
112 static safe_string *
113 new_safe_string(int size)
115 safe_string * ss;
117 ss = LDAP_MALLOC(sizeof(safe_string));
118 if ( !ss )
119 return(NULL);
121 ss->val = LDAP_MALLOC(size);
122 if ( !ss->val ) {
123 LDAP_FREE(ss);
124 return(NULL);
127 ss->size = size;
128 ss->pos = 0;
129 ss->at_whsp = 0;
131 return ss;
134 static void
135 safe_string_free(safe_string * ss)
137 if ( !ss )
138 return;
139 LDAP_FREE(ss->val);
140 LDAP_FREE(ss);
143 #if 0 /* unused */
144 static char *
145 safe_string_val(safe_string * ss)
147 ss->val[ss->pos] = '\0';
148 return(ss->val);
150 #endif
152 static char *
153 safe_strdup(safe_string * ss)
155 char *ret = LDAP_MALLOC(ss->pos+1);
156 if (!ret)
157 return NULL;
158 AC_MEMCPY(ret, ss->val, ss->pos);
159 ret[ss->pos] = '\0';
160 return ret;
163 static int
164 append_to_safe_string(safe_string * ss, char * s)
166 int l = strlen(s);
167 char * temp;
170 * Some runaway process is trying to append to a string that
171 * overflowed and we could not extend.
173 if ( !ss->val )
174 return -1;
176 /* We always make sure there is at least one position available */
177 if ( ss->pos + l >= ss->size-1 ) {
178 ss->size *= 2;
179 if ( ss->pos + l >= ss->size-1 ) {
180 ss->size = ss->pos + l + 1;
183 temp = LDAP_REALLOC(ss->val, ss->size);
184 if ( !temp ) {
185 /* Trouble, out of memory */
186 LDAP_FREE(ss->val);
187 return -1;
189 ss->val = temp;
191 strncpy(&ss->val[ss->pos], s, l);
192 ss->pos += l;
193 if ( ss->pos > 0 && LDAP_SPACE(ss->val[ss->pos-1]) )
194 ss->at_whsp = 1;
195 else
196 ss->at_whsp = 0;
198 return 0;
201 static int
202 print_literal(safe_string *ss, char *s)
204 return(append_to_safe_string(ss,s));
207 static int
208 print_whsp(safe_string *ss)
210 if ( ss->at_whsp )
211 return(append_to_safe_string(ss,""));
212 else
213 return(append_to_safe_string(ss," "));
216 static int
217 print_numericoid(safe_string *ss, char *s)
219 if ( s )
220 return(append_to_safe_string(ss,s));
221 else
222 return(append_to_safe_string(ss,""));
225 /* This one is identical to print_qdescr */
226 static int
227 print_qdstring(safe_string *ss, char *s)
229 print_whsp(ss);
230 print_literal(ss,"'");
231 append_to_safe_string(ss,s);
232 print_literal(ss,"'");
233 return(print_whsp(ss));
236 static int
237 print_qdescr(safe_string *ss, char *s)
239 print_whsp(ss);
240 print_literal(ss,"'");
241 append_to_safe_string(ss,s);
242 print_literal(ss,"'");
243 return(print_whsp(ss));
246 static int
247 print_qdescrlist(safe_string *ss, char **sa)
249 char **sp;
250 int ret = 0;
252 for (sp=sa; *sp; sp++) {
253 ret = print_qdescr(ss,*sp);
255 /* If the list was empty, we return zero that is potentially
256 * incorrect, but since we will be still appending things, the
257 * overflow will be detected later. Maybe FIX.
259 return(ret);
262 static int
263 print_qdescrs(safe_string *ss, char **sa)
265 /* The only way to represent an empty list is as a qdescrlist
266 * so, if the list is empty we treat it as a long list.
267 * Really, this is what the syntax mandates. We should not
268 * be here if the list was empty, but if it happens, a label
269 * has already been output and we cannot undo it.
271 if ( !sa[0] || ( sa[0] && sa[1] ) ) {
272 print_whsp(ss);
273 print_literal(ss,"("/*)*/);
274 print_qdescrlist(ss,sa);
275 print_literal(ss,/*(*/")");
276 return(print_whsp(ss));
277 } else {
278 return(print_qdescr(ss,*sa));
282 static int
283 print_woid(safe_string *ss, char *s)
285 print_whsp(ss);
286 append_to_safe_string(ss,s);
287 return print_whsp(ss);
290 static int
291 print_oidlist(safe_string *ss, char **sa)
293 char **sp;
295 for (sp=sa; *(sp+1); sp++) {
296 print_woid(ss,*sp);
297 print_literal(ss,"$");
299 return(print_woid(ss,*sp));
302 static int
303 print_oids(safe_string *ss, char **sa)
305 if ( sa[0] && sa[1] ) {
306 print_literal(ss,"("/*)*/);
307 print_oidlist(ss,sa);
308 print_whsp(ss);
309 return(print_literal(ss,/*(*/")"));
310 } else {
311 return(print_woid(ss,*sa));
315 static int
316 print_noidlen(safe_string *ss, char *s, int l)
318 char buf[64];
319 int ret;
321 ret = print_numericoid(ss,s);
322 if ( l ) {
323 snprintf(buf, sizeof buf, "{%d}",l);
324 ret = print_literal(ss,buf);
326 return(ret);
329 static int
330 print_ruleid(safe_string *ss, int rid)
332 char buf[64];
333 snprintf(buf, sizeof buf, "%d", rid);
334 return print_literal(ss,buf);
337 static int
338 print_ruleids(safe_string *ss, int n, int *rids)
340 int i;
342 if( n == 1 ) {
343 print_ruleid(ss,rids[0]);
344 return print_whsp(ss);
345 } else {
346 print_literal(ss,"("/*)*/);
347 for( i=0; i<n; i++ ) {
348 print_whsp(ss);
349 print_ruleid(ss,rids[i]);
351 print_whsp(ss);
352 return print_literal(ss,/*(*/")");
357 static int
358 print_extensions(safe_string *ss, LDAPSchemaExtensionItem **extensions)
360 LDAPSchemaExtensionItem **ext;
362 if ( extensions ) {
363 print_whsp(ss);
364 for ( ext = extensions; *ext != NULL; ext++ ) {
365 print_literal(ss, (*ext)->lsei_name);
366 print_whsp(ss);
367 /* Should be print_qdstrings */
368 print_qdescrs(ss, (*ext)->lsei_values);
369 print_whsp(ss);
373 return 0;
376 char *
377 ldap_syntax2str( LDAPSyntax * syn )
379 struct berval bv;
380 if (ldap_syntax2bv( syn, &bv ))
381 return(bv.bv_val);
382 else
383 return NULL;
386 struct berval *
387 ldap_syntax2bv( LDAPSyntax * syn, struct berval *bv )
389 safe_string * ss;
391 if ( !syn || !bv )
392 return NULL;
394 ss = new_safe_string(256);
395 if ( !ss )
396 return NULL;
398 print_literal(ss,"("/*)*/);
399 print_whsp(ss);
401 print_numericoid(ss, syn->syn_oid);
402 print_whsp(ss);
404 if ( syn->syn_desc ) {
405 print_literal(ss,"DESC");
406 print_qdstring(ss,syn->syn_desc);
409 print_whsp(ss);
411 print_extensions(ss, syn->syn_extensions);
413 print_literal(ss,/*(*/ ")");
415 bv->bv_val = safe_strdup(ss);
416 bv->bv_len = ss->pos;
417 safe_string_free(ss);
418 return(bv);
421 char *
422 ldap_matchingrule2str( LDAPMatchingRule * mr )
424 struct berval bv;
425 if (ldap_matchingrule2bv( mr, &bv ))
426 return(bv.bv_val);
427 else
428 return NULL;
431 struct berval *
432 ldap_matchingrule2bv( LDAPMatchingRule * mr, struct berval *bv )
434 safe_string * ss;
436 if ( !mr || !bv )
437 return NULL;
439 ss = new_safe_string(256);
440 if ( !ss )
441 return NULL;
443 print_literal(ss,"(" /*)*/);
444 print_whsp(ss);
446 print_numericoid(ss, mr->mr_oid);
447 print_whsp(ss);
449 if ( mr->mr_names ) {
450 print_literal(ss,"NAME");
451 print_qdescrs(ss,mr->mr_names);
454 if ( mr->mr_desc ) {
455 print_literal(ss,"DESC");
456 print_qdstring(ss,mr->mr_desc);
459 if ( mr->mr_obsolete ) {
460 print_literal(ss, "OBSOLETE");
461 print_whsp(ss);
464 if ( mr->mr_syntax_oid ) {
465 print_literal(ss,"SYNTAX");
466 print_whsp(ss);
467 print_literal(ss, mr->mr_syntax_oid);
468 print_whsp(ss);
471 print_whsp(ss);
473 print_extensions(ss, mr->mr_extensions);
475 print_literal(ss,/*(*/")");
477 bv->bv_val = safe_strdup(ss);
478 bv->bv_len = ss->pos;
479 safe_string_free(ss);
480 return(bv);
483 char *
484 ldap_matchingruleuse2str( LDAPMatchingRuleUse * mru )
486 struct berval bv;
487 if (ldap_matchingruleuse2bv( mru, &bv ))
488 return(bv.bv_val);
489 else
490 return NULL;
493 struct berval *
494 ldap_matchingruleuse2bv( LDAPMatchingRuleUse * mru, struct berval *bv )
496 safe_string * ss;
498 if ( !mru || !bv )
499 return NULL;
501 ss = new_safe_string(256);
502 if ( !ss )
503 return NULL;
505 print_literal(ss,"(" /*)*/);
506 print_whsp(ss);
508 print_numericoid(ss, mru->mru_oid);
509 print_whsp(ss);
511 if ( mru->mru_names ) {
512 print_literal(ss,"NAME");
513 print_qdescrs(ss,mru->mru_names);
516 if ( mru->mru_desc ) {
517 print_literal(ss,"DESC");
518 print_qdstring(ss,mru->mru_desc);
521 if ( mru->mru_obsolete ) {
522 print_literal(ss, "OBSOLETE");
523 print_whsp(ss);
526 if ( mru->mru_applies_oids ) {
527 print_literal(ss,"APPLIES");
528 print_whsp(ss);
529 print_oids(ss, mru->mru_applies_oids);
530 print_whsp(ss);
533 print_whsp(ss);
535 print_extensions(ss, mru->mru_extensions);
537 print_literal(ss,/*(*/")");
539 bv->bv_val = safe_strdup(ss);
540 bv->bv_len = ss->pos;
541 safe_string_free(ss);
542 return(bv);
545 char *
546 ldap_objectclass2str( LDAPObjectClass * oc )
548 struct berval bv;
549 if (ldap_objectclass2bv( oc, &bv ))
550 return(bv.bv_val);
551 else
552 return NULL;
555 struct berval *
556 ldap_objectclass2bv( LDAPObjectClass * oc, struct berval *bv )
558 safe_string * ss;
560 if ( !oc || !bv )
561 return NULL;
563 ss = new_safe_string(256);
564 if ( !ss )
565 return NULL;
567 print_literal(ss,"("/*)*/);
568 print_whsp(ss);
570 print_numericoid(ss, oc->oc_oid);
571 print_whsp(ss);
573 if ( oc->oc_names ) {
574 print_literal(ss,"NAME");
575 print_qdescrs(ss,oc->oc_names);
578 if ( oc->oc_desc ) {
579 print_literal(ss,"DESC");
580 print_qdstring(ss,oc->oc_desc);
583 if ( oc->oc_obsolete ) {
584 print_literal(ss, "OBSOLETE");
585 print_whsp(ss);
588 if ( oc->oc_sup_oids ) {
589 print_literal(ss,"SUP");
590 print_whsp(ss);
591 print_oids(ss,oc->oc_sup_oids);
592 print_whsp(ss);
595 switch (oc->oc_kind) {
596 case LDAP_SCHEMA_ABSTRACT:
597 print_literal(ss,"ABSTRACT");
598 break;
599 case LDAP_SCHEMA_STRUCTURAL:
600 print_literal(ss,"STRUCTURAL");
601 break;
602 case LDAP_SCHEMA_AUXILIARY:
603 print_literal(ss,"AUXILIARY");
604 break;
605 default:
606 print_literal(ss,"KIND-UNKNOWN");
607 break;
609 print_whsp(ss);
611 if ( oc->oc_at_oids_must ) {
612 print_literal(ss,"MUST");
613 print_whsp(ss);
614 print_oids(ss,oc->oc_at_oids_must);
615 print_whsp(ss);
618 if ( oc->oc_at_oids_may ) {
619 print_literal(ss,"MAY");
620 print_whsp(ss);
621 print_oids(ss,oc->oc_at_oids_may);
622 print_whsp(ss);
625 print_whsp(ss);
627 print_extensions(ss, oc->oc_extensions);
629 print_literal(ss, /*(*/")");
631 bv->bv_val = safe_strdup(ss);
632 bv->bv_len = ss->pos;
633 safe_string_free(ss);
634 return(bv);
637 char *
638 ldap_contentrule2str( LDAPContentRule * cr )
640 struct berval bv;
641 if (ldap_contentrule2bv( cr, &bv ))
642 return(bv.bv_val);
643 else
644 return NULL;
647 struct berval *
648 ldap_contentrule2bv( LDAPContentRule * cr, struct berval *bv )
650 safe_string * ss;
652 if ( !cr || !bv )
653 return NULL;
655 ss = new_safe_string(256);
656 if ( !ss )
657 return NULL;
659 print_literal(ss,"("/*)*/);
660 print_whsp(ss);
662 print_numericoid(ss, cr->cr_oid);
663 print_whsp(ss);
665 if ( cr->cr_names ) {
666 print_literal(ss,"NAME");
667 print_qdescrs(ss,cr->cr_names);
670 if ( cr->cr_desc ) {
671 print_literal(ss,"DESC");
672 print_qdstring(ss,cr->cr_desc);
675 if ( cr->cr_obsolete ) {
676 print_literal(ss, "OBSOLETE");
677 print_whsp(ss);
680 if ( cr->cr_oc_oids_aux ) {
681 print_literal(ss,"AUX");
682 print_whsp(ss);
683 print_oids(ss,cr->cr_oc_oids_aux);
684 print_whsp(ss);
687 if ( cr->cr_at_oids_must ) {
688 print_literal(ss,"MUST");
689 print_whsp(ss);
690 print_oids(ss,cr->cr_at_oids_must);
691 print_whsp(ss);
694 if ( cr->cr_at_oids_may ) {
695 print_literal(ss,"MAY");
696 print_whsp(ss);
697 print_oids(ss,cr->cr_at_oids_may);
698 print_whsp(ss);
701 if ( cr->cr_at_oids_not ) {
702 print_literal(ss,"NOT");
703 print_whsp(ss);
704 print_oids(ss,cr->cr_at_oids_not);
705 print_whsp(ss);
708 print_whsp(ss);
709 print_extensions(ss, cr->cr_extensions);
711 print_literal(ss, /*(*/")");
713 bv->bv_val = safe_strdup(ss);
714 bv->bv_len = ss->pos;
715 safe_string_free(ss);
716 return(bv);
719 char *
720 ldap_structurerule2str( LDAPStructureRule * sr )
722 struct berval bv;
723 if (ldap_structurerule2bv( sr, &bv ))
724 return(bv.bv_val);
725 else
726 return NULL;
729 struct berval *
730 ldap_structurerule2bv( LDAPStructureRule * sr, struct berval *bv )
732 safe_string * ss;
734 if ( !sr || !bv )
735 return NULL;
737 ss = new_safe_string(256);
738 if ( !ss )
739 return NULL;
741 print_literal(ss,"("/*)*/);
742 print_whsp(ss);
744 print_ruleid(ss, sr->sr_ruleid);
745 print_whsp(ss);
747 if ( sr->sr_names ) {
748 print_literal(ss,"NAME");
749 print_qdescrs(ss,sr->sr_names);
752 if ( sr->sr_desc ) {
753 print_literal(ss,"DESC");
754 print_qdstring(ss,sr->sr_desc);
757 if ( sr->sr_obsolete ) {
758 print_literal(ss, "OBSOLETE");
759 print_whsp(ss);
762 print_literal(ss,"FORM");
763 print_whsp(ss);
764 print_woid(ss,sr->sr_nameform);
765 print_whsp(ss);
767 if ( sr->sr_nsup_ruleids ) {
768 print_literal(ss,"SUP");
769 print_whsp(ss);
770 print_ruleids(ss,sr->sr_nsup_ruleids,sr->sr_sup_ruleids);
771 print_whsp(ss);
774 print_whsp(ss);
775 print_extensions(ss, sr->sr_extensions);
777 print_literal(ss, /*(*/")");
779 bv->bv_val = safe_strdup(ss);
780 bv->bv_len = ss->pos;
781 safe_string_free(ss);
782 return(bv);
786 char *
787 ldap_nameform2str( LDAPNameForm * nf )
789 struct berval bv;
790 if (ldap_nameform2bv( nf, &bv ))
791 return(bv.bv_val);
792 else
793 return NULL;
796 struct berval *
797 ldap_nameform2bv( LDAPNameForm * nf, struct berval *bv )
799 safe_string * ss;
801 if ( !nf || !bv )
802 return NULL;
804 ss = new_safe_string(256);
805 if ( !ss )
806 return NULL;
808 print_literal(ss,"("/*)*/);
809 print_whsp(ss);
811 print_numericoid(ss, nf->nf_oid);
812 print_whsp(ss);
814 if ( nf->nf_names ) {
815 print_literal(ss,"NAME");
816 print_qdescrs(ss,nf->nf_names);
819 if ( nf->nf_desc ) {
820 print_literal(ss,"DESC");
821 print_qdstring(ss,nf->nf_desc);
824 if ( nf->nf_obsolete ) {
825 print_literal(ss, "OBSOLETE");
826 print_whsp(ss);
829 print_literal(ss,"OC");
830 print_whsp(ss);
831 print_woid(ss,nf->nf_objectclass);
832 print_whsp(ss);
834 print_literal(ss,"MUST");
835 print_whsp(ss);
836 print_oids(ss,nf->nf_at_oids_must);
837 print_whsp(ss);
840 if ( nf->nf_at_oids_may ) {
841 print_literal(ss,"MAY");
842 print_whsp(ss);
843 print_oids(ss,nf->nf_at_oids_may);
844 print_whsp(ss);
847 print_whsp(ss);
848 print_extensions(ss, nf->nf_extensions);
850 print_literal(ss, /*(*/")");
852 bv->bv_val = safe_strdup(ss);
853 bv->bv_len = ss->pos;
854 safe_string_free(ss);
855 return(bv);
858 char *
859 ldap_attributetype2str( LDAPAttributeType * at )
861 struct berval bv;
862 if (ldap_attributetype2bv( at, &bv ))
863 return(bv.bv_val);
864 else
865 return NULL;
868 struct berval *
869 ldap_attributetype2bv( LDAPAttributeType * at, struct berval *bv )
871 safe_string * ss;
873 if ( !at || !bv )
874 return NULL;
876 ss = new_safe_string(256);
877 if ( !ss )
878 return NULL;
880 print_literal(ss,"("/*)*/);
881 print_whsp(ss);
883 print_numericoid(ss, at->at_oid);
884 print_whsp(ss);
886 if ( at->at_names ) {
887 print_literal(ss,"NAME");
888 print_qdescrs(ss,at->at_names);
891 if ( at->at_desc ) {
892 print_literal(ss,"DESC");
893 print_qdstring(ss,at->at_desc);
896 if ( at->at_obsolete ) {
897 print_literal(ss, "OBSOLETE");
898 print_whsp(ss);
901 if ( at->at_sup_oid ) {
902 print_literal(ss,"SUP");
903 print_woid(ss,at->at_sup_oid);
906 if ( at->at_equality_oid ) {
907 print_literal(ss,"EQUALITY");
908 print_woid(ss,at->at_equality_oid);
911 if ( at->at_ordering_oid ) {
912 print_literal(ss,"ORDERING");
913 print_woid(ss,at->at_ordering_oid);
916 if ( at->at_substr_oid ) {
917 print_literal(ss,"SUBSTR");
918 print_woid(ss,at->at_substr_oid);
921 if ( at->at_syntax_oid ) {
922 print_literal(ss,"SYNTAX");
923 print_whsp(ss);
924 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
925 print_whsp(ss);
928 if ( at->at_single_value == LDAP_SCHEMA_YES ) {
929 print_literal(ss,"SINGLE-VALUE");
930 print_whsp(ss);
933 if ( at->at_collective == LDAP_SCHEMA_YES ) {
934 print_literal(ss,"COLLECTIVE");
935 print_whsp(ss);
938 if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
939 print_literal(ss,"NO-USER-MODIFICATION");
940 print_whsp(ss);
943 if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
944 print_literal(ss,"USAGE");
945 print_whsp(ss);
946 switch (at->at_usage) {
947 case LDAP_SCHEMA_DIRECTORY_OPERATION:
948 print_literal(ss,"directoryOperation");
949 break;
950 case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
951 print_literal(ss,"distributedOperation");
952 break;
953 case LDAP_SCHEMA_DSA_OPERATION:
954 print_literal(ss,"dSAOperation");
955 break;
956 default:
957 print_literal(ss,"UNKNOWN");
958 break;
962 print_whsp(ss);
964 print_extensions(ss, at->at_extensions);
966 print_literal(ss,/*(*/")");
968 bv->bv_val = safe_strdup(ss);
969 bv->bv_len = ss->pos;
970 safe_string_free(ss);
971 return(bv);
975 * Now come the parsers. There is one parser for each entity type:
976 * objectclasses, attributetypes, etc.
978 * Each of them is written as a recursive-descent parser, except that
979 * none of them is really recursive. But the idea is kept: there
980 * is one routine per non-terminal that either gobbles lexical tokens
981 * or calls lower-level routines, etc.
983 * The scanner is implemented in the routine get_token. Actually,
984 * get_token is more than a scanner and will return tokens that are
985 * in fact non-terminals in the grammar. So you can see the whole
986 * approach as the combination of a low-level bottom-up recognizer
987 * combined with a scanner and a number of top-down parsers. Or just
988 * consider that the real grammars recognized by the parsers are not
989 * those of the standards. As a matter of fact, our parsers are more
990 * liberal than the spec when there is no ambiguity.
992 * The difference is pretty academic (modulo bugs or incorrect
993 * interpretation of the specs).
996 typedef enum tk_t {
997 TK_NOENDQUOTE = -2,
998 TK_OUTOFMEM = -1,
999 TK_EOS = 0,
1000 TK_UNEXPCHAR = 1,
1001 TK_BAREWORD = 2,
1002 TK_QDSTRING = 3,
1003 TK_LEFTPAREN = 4,
1004 TK_RIGHTPAREN = 5,
1005 TK_DOLLAR = 6,
1006 TK_QDESCR = TK_QDSTRING
1007 } tk_t;
1009 static tk_t
1010 get_token( const char ** sp, char ** token_val )
1012 tk_t kind;
1013 const char * p;
1014 const char * q;
1015 char * res;
1017 *token_val = NULL;
1018 switch (**sp) {
1019 case '\0':
1020 kind = TK_EOS;
1021 (*sp)++;
1022 break;
1023 case '(':
1024 kind = TK_LEFTPAREN;
1025 (*sp)++;
1026 break;
1027 case ')':
1028 kind = TK_RIGHTPAREN;
1029 (*sp)++;
1030 break;
1031 case '$':
1032 kind = TK_DOLLAR;
1033 (*sp)++;
1034 break;
1035 case '\'':
1036 kind = TK_QDSTRING;
1037 (*sp)++;
1038 p = *sp;
1039 while ( **sp != '\'' && **sp != '\0' )
1040 (*sp)++;
1041 if ( **sp == '\'' ) {
1042 q = *sp;
1043 res = LDAP_MALLOC(q-p+1);
1044 if ( !res ) {
1045 kind = TK_OUTOFMEM;
1046 } else {
1047 strncpy(res,p,q-p);
1048 res[q-p] = '\0';
1049 *token_val = res;
1051 (*sp)++;
1052 } else {
1053 kind = TK_NOENDQUOTE;
1055 break;
1056 default:
1057 kind = TK_BAREWORD;
1058 p = *sp;
1059 while ( !LDAP_SPACE(**sp) &&
1060 **sp != '(' &&
1061 **sp != ')' &&
1062 **sp != '$' &&
1063 **sp != '\'' &&
1064 /* for suggested minimum upper bound on the number
1065 * of characters (RFC 4517) */
1066 **sp != '{' &&
1067 **sp != '\0' )
1068 (*sp)++;
1069 q = *sp;
1070 res = LDAP_MALLOC(q-p+1);
1071 if ( !res ) {
1072 kind = TK_OUTOFMEM;
1073 } else {
1074 strncpy(res,p,q-p);
1075 res[q-p] = '\0';
1076 *token_val = res;
1078 break;
1079 /* kind = TK_UNEXPCHAR; */
1080 /* break; */
1083 return kind;
1086 /* Gobble optional whitespace */
1087 static void
1088 parse_whsp(const char **sp)
1090 while (LDAP_SPACE(**sp))
1091 (*sp)++;
1094 /* TBC:!!
1095 * General note for all parsers: to guarantee the algorithm halts they
1096 * must always advance the pointer even when an error is found. For
1097 * this one is not that important since an error here is fatal at the
1098 * upper layers, but it is a simple strategy that will not get in
1099 * endless loops.
1102 /* Parse a sequence of dot-separated decimal strings */
1103 char *
1104 ldap_int_parse_numericoid(const char **sp, int *code, const int flags)
1106 char * res = NULL;
1107 const char * start = *sp;
1108 int len;
1109 int quoted = 0;
1111 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
1112 if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && **sp == '\'' ) {
1113 quoted = 1;
1114 (*sp)++;
1115 start++;
1117 /* Each iteration of this loop gets one decimal string */
1118 while (**sp) {
1119 if ( !LDAP_DIGIT(**sp) ) {
1121 * Initial char is not a digit or char after dot is
1122 * not a digit
1124 *code = LDAP_SCHERR_NODIGIT;
1125 return NULL;
1127 (*sp)++;
1128 while ( LDAP_DIGIT(**sp) )
1129 (*sp)++;
1130 if ( **sp != '.' )
1131 break;
1132 /* Otherwise, gobble the dot and loop again */
1133 (*sp)++;
1135 /* Now *sp points at the char past the numericoid. Perfect. */
1136 len = *sp - start;
1137 if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && quoted ) {
1138 if ( **sp == '\'' ) {
1139 (*sp)++;
1140 } else {
1141 *code = LDAP_SCHERR_UNEXPTOKEN;
1142 return NULL;
1145 if (flags & LDAP_SCHEMA_SKIP) {
1146 res = (char *)start;
1147 } else {
1148 res = LDAP_MALLOC(len+1);
1149 if (!res) {
1150 *code = LDAP_SCHERR_OUTOFMEM;
1151 return(NULL);
1153 strncpy(res,start,len);
1154 res[len] = '\0';
1156 return(res);
1159 /* Parse a sequence of dot-separated decimal strings */
1161 ldap_int_parse_ruleid(const char **sp, int *code, const int flags, int *ruleid)
1163 *ruleid=0;
1165 if ( !LDAP_DIGIT(**sp) ) {
1166 *code = LDAP_SCHERR_NODIGIT;
1167 return -1;
1169 *ruleid = (**sp) - '0';
1170 (*sp)++;
1172 while ( LDAP_DIGIT(**sp) ) {
1173 *ruleid *= 10;
1174 *ruleid += (**sp) - '0';
1175 (*sp)++;
1178 return 0;
1181 /* Parse a qdescr or a list of them enclosed in () */
1182 static char **
1183 parse_qdescrs(const char **sp, int *code)
1185 char ** res;
1186 char ** res1;
1187 tk_t kind;
1188 char * sval;
1189 int size;
1190 int pos;
1192 parse_whsp(sp);
1193 kind = get_token(sp,&sval);
1194 if ( kind == TK_LEFTPAREN ) {
1195 /* Let's presume there will be at least 2 entries */
1196 size = 3;
1197 res = LDAP_CALLOC(3,sizeof(char *));
1198 if ( !res ) {
1199 *code = LDAP_SCHERR_OUTOFMEM;
1200 return NULL;
1202 pos = 0;
1203 while (1) {
1204 parse_whsp(sp);
1205 kind = get_token(sp,&sval);
1206 if ( kind == TK_RIGHTPAREN )
1207 break;
1208 if ( kind == TK_QDESCR ) {
1209 if ( pos == size-2 ) {
1210 size++;
1211 res1 = LDAP_REALLOC(res,size*sizeof(char *));
1212 if ( !res1 ) {
1213 LDAP_VFREE(res);
1214 LDAP_FREE(sval);
1215 *code = LDAP_SCHERR_OUTOFMEM;
1216 return(NULL);
1218 res = res1;
1220 res[pos++] = sval;
1221 res[pos] = NULL;
1222 parse_whsp(sp);
1223 } else {
1224 LDAP_VFREE(res);
1225 LDAP_FREE(sval);
1226 *code = LDAP_SCHERR_UNEXPTOKEN;
1227 return(NULL);
1230 parse_whsp(sp);
1231 return(res);
1232 } else if ( kind == TK_QDESCR ) {
1233 res = LDAP_CALLOC(2,sizeof(char *));
1234 if ( !res ) {
1235 *code = LDAP_SCHERR_OUTOFMEM;
1236 return NULL;
1238 res[0] = sval;
1239 res[1] = NULL;
1240 parse_whsp(sp);
1241 return res;
1242 } else {
1243 LDAP_FREE(sval);
1244 *code = LDAP_SCHERR_BADNAME;
1245 return NULL;
1249 /* Parse a woid */
1250 static char *
1251 parse_woid(const char **sp, int *code)
1253 char * sval;
1254 tk_t kind;
1256 parse_whsp(sp);
1257 kind = get_token(sp, &sval);
1258 if ( kind != TK_BAREWORD ) {
1259 LDAP_FREE(sval);
1260 *code = LDAP_SCHERR_UNEXPTOKEN;
1261 return NULL;
1263 parse_whsp(sp);
1264 return sval;
1267 /* Parse a noidlen */
1268 static char *
1269 parse_noidlen(const char **sp, int *code, int *len, int flags)
1271 char * sval;
1272 const char *savepos;
1273 int quoted = 0;
1274 int allow_quoted = ( flags & LDAP_SCHEMA_ALLOW_QUOTED );
1275 int allow_oidmacro = ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO );
1277 *len = 0;
1278 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
1279 if ( allow_quoted && **sp == '\'' ) {
1280 quoted = 1;
1281 (*sp)++;
1283 savepos = *sp;
1284 sval = ldap_int_parse_numericoid(sp, code, 0);
1285 if ( !sval ) {
1286 if ( allow_oidmacro
1287 && *sp == savepos
1288 && *code == LDAP_SCHERR_NODIGIT )
1290 if ( get_token(sp, &sval) != TK_BAREWORD ) {
1291 if ( sval != NULL ) {
1292 LDAP_FREE(sval);
1294 return NULL;
1296 } else {
1297 return NULL;
1300 if ( **sp == '{' /*}*/ ) {
1301 (*sp)++;
1302 *len = atoi(*sp);
1303 while ( LDAP_DIGIT(**sp) )
1304 (*sp)++;
1305 if ( **sp != /*{*/ '}' ) {
1306 *code = LDAP_SCHERR_UNEXPTOKEN;
1307 LDAP_FREE(sval);
1308 return NULL;
1310 (*sp)++;
1312 if ( allow_quoted && quoted ) {
1313 if ( **sp == '\'' ) {
1314 (*sp)++;
1315 } else {
1316 *code = LDAP_SCHERR_UNEXPTOKEN;
1317 LDAP_FREE(sval);
1318 return NULL;
1321 return sval;
1325 * Next routine will accept a qdstring in place of an oid if
1326 * allow_quoted is set. This is necessary to interoperate with
1327 * Netscape Directory server that will improperly quote each oid (at
1328 * least those of the descr kind) in the SUP clause.
1331 /* Parse a woid or a $-separated list of them enclosed in () */
1332 static char **
1333 parse_oids(const char **sp, int *code, const int allow_quoted)
1335 char ** res;
1336 char ** res1;
1337 tk_t kind;
1338 char * sval;
1339 int size;
1340 int pos;
1343 * Strictly speaking, doing this here accepts whsp before the
1344 * ( at the beginning of an oidlist, but this is harmless. Also,
1345 * we are very liberal in what we accept as an OID. Maybe
1346 * refine later.
1348 parse_whsp(sp);
1349 kind = get_token(sp,&sval);
1350 if ( kind == TK_LEFTPAREN ) {
1351 /* Let's presume there will be at least 2 entries */
1352 size = 3;
1353 res = LDAP_CALLOC(3,sizeof(char *));
1354 if ( !res ) {
1355 *code = LDAP_SCHERR_OUTOFMEM;
1356 return NULL;
1358 pos = 0;
1359 parse_whsp(sp);
1360 kind = get_token(sp,&sval);
1361 if ( kind == TK_BAREWORD ||
1362 ( allow_quoted && kind == TK_QDSTRING ) ) {
1363 res[pos++] = sval;
1364 res[pos] = NULL;
1365 } else if ( kind == TK_RIGHTPAREN ) {
1366 /* FIXME: be liberal in what we accept... */
1367 parse_whsp(sp);
1368 LDAP_FREE(res);
1369 return NULL;
1370 } else {
1371 *code = LDAP_SCHERR_UNEXPTOKEN;
1372 LDAP_FREE(sval);
1373 LDAP_VFREE(res);
1374 return NULL;
1376 parse_whsp(sp);
1377 while (1) {
1378 kind = get_token(sp,&sval);
1379 if ( kind == TK_RIGHTPAREN )
1380 break;
1381 if ( kind == TK_DOLLAR ) {
1382 parse_whsp(sp);
1383 kind = get_token(sp,&sval);
1384 if ( kind == TK_BAREWORD ||
1385 ( allow_quoted &&
1386 kind == TK_QDSTRING ) ) {
1387 if ( pos == size-2 ) {
1388 size++;
1389 res1 = LDAP_REALLOC(res,size*sizeof(char *));
1390 if ( !res1 ) {
1391 LDAP_FREE(sval);
1392 LDAP_VFREE(res);
1393 *code = LDAP_SCHERR_OUTOFMEM;
1394 return(NULL);
1396 res = res1;
1398 res[pos++] = sval;
1399 res[pos] = NULL;
1400 } else {
1401 *code = LDAP_SCHERR_UNEXPTOKEN;
1402 LDAP_FREE(sval);
1403 LDAP_VFREE(res);
1404 return NULL;
1406 parse_whsp(sp);
1407 } else {
1408 *code = LDAP_SCHERR_UNEXPTOKEN;
1409 LDAP_FREE(sval);
1410 LDAP_VFREE(res);
1411 return NULL;
1414 parse_whsp(sp);
1415 return(res);
1416 } else if ( kind == TK_BAREWORD ||
1417 ( allow_quoted && kind == TK_QDSTRING ) ) {
1418 res = LDAP_CALLOC(2,sizeof(char *));
1419 if ( !res ) {
1420 LDAP_FREE(sval);
1421 *code = LDAP_SCHERR_OUTOFMEM;
1422 return NULL;
1424 res[0] = sval;
1425 res[1] = NULL;
1426 parse_whsp(sp);
1427 return res;
1428 } else {
1429 LDAP_FREE(sval);
1430 *code = LDAP_SCHERR_BADNAME;
1431 return NULL;
1435 static int
1436 add_extension(LDAPSchemaExtensionItem ***extensions,
1437 char * name, char ** values)
1439 int n;
1440 LDAPSchemaExtensionItem **tmp, *ext;
1442 ext = LDAP_CALLOC(1, sizeof(LDAPSchemaExtensionItem));
1443 if ( !ext )
1444 return 1;
1445 ext->lsei_name = name;
1446 ext->lsei_values = values;
1448 if ( !*extensions ) {
1449 *extensions =
1450 LDAP_CALLOC(2, sizeof(LDAPSchemaExtensionItem *));
1451 if ( !*extensions ) {
1452 LDAP_FREE( ext );
1453 return 1;
1455 n = 0;
1456 } else {
1457 for ( n=0; (*extensions)[n] != NULL; n++ )
1459 tmp = LDAP_REALLOC(*extensions,
1460 (n+2)*sizeof(LDAPSchemaExtensionItem *));
1461 if ( !tmp ) {
1462 LDAP_FREE( ext );
1463 return 1;
1465 *extensions = tmp;
1467 (*extensions)[n] = ext;
1468 (*extensions)[n+1] = NULL;
1469 return 0;
1472 static void
1473 free_extensions(LDAPSchemaExtensionItem **extensions)
1475 LDAPSchemaExtensionItem **ext;
1477 if ( extensions ) {
1478 for ( ext = extensions; *ext != NULL; ext++ ) {
1479 LDAP_FREE((*ext)->lsei_name);
1480 LDAP_VFREE((*ext)->lsei_values);
1481 LDAP_FREE(*ext);
1483 LDAP_FREE(extensions);
1487 void
1488 ldap_syntax_free( LDAPSyntax * syn )
1490 if ( !syn ) return;
1491 LDAP_FREE(syn->syn_oid);
1492 if (syn->syn_names) LDAP_VFREE(syn->syn_names);
1493 if (syn->syn_desc) LDAP_FREE(syn->syn_desc);
1494 free_extensions(syn->syn_extensions);
1495 LDAP_FREE(syn);
1498 LDAPSyntax *
1499 ldap_str2syntax( LDAP_CONST char * s,
1500 int * code,
1501 LDAP_CONST char ** errp,
1502 LDAP_CONST unsigned flags )
1504 tk_t kind;
1505 const char * ss = s;
1506 char * sval;
1507 int seen_name = 0;
1508 int seen_desc = 0;
1509 LDAPSyntax * syn;
1510 char ** ext_vals;
1512 if ( !s ) {
1513 *code = LDAP_SCHERR_EMPTY;
1514 *errp = "";
1515 return NULL;
1518 *errp = s;
1519 syn = LDAP_CALLOC(1,sizeof(LDAPSyntax));
1521 if ( !syn ) {
1522 *code = LDAP_SCHERR_OUTOFMEM;
1523 return NULL;
1526 kind = get_token(&ss,&sval);
1527 if ( kind != TK_LEFTPAREN ) {
1528 LDAP_FREE(sval);
1529 *code = LDAP_SCHERR_NOLEFTPAREN;
1530 ldap_syntax_free(syn);
1531 return NULL;
1534 parse_whsp(&ss);
1535 syn->syn_oid = ldap_int_parse_numericoid(&ss,code,0);
1536 if ( !syn->syn_oid ) {
1537 *errp = ss;
1538 ldap_syntax_free(syn);
1539 return NULL;
1541 parse_whsp(&ss);
1544 * Beyond this point we will be liberal and accept the items
1545 * in any order.
1547 while (1) {
1548 kind = get_token(&ss,&sval);
1549 switch (kind) {
1550 case TK_EOS:
1551 *code = LDAP_SCHERR_NORIGHTPAREN;
1552 *errp = EndOfInput;
1553 ldap_syntax_free(syn);
1554 return NULL;
1555 case TK_RIGHTPAREN:
1556 return syn;
1557 case TK_BAREWORD:
1558 if ( !strcasecmp(sval,"NAME") ) {
1559 LDAP_FREE(sval);
1560 if ( seen_name ) {
1561 *code = LDAP_SCHERR_DUPOPT;
1562 *errp = ss;
1563 ldap_syntax_free(syn);
1564 return(NULL);
1566 seen_name = 1;
1567 syn->syn_names = parse_qdescrs(&ss,code);
1568 if ( !syn->syn_names ) {
1569 if ( *code != LDAP_SCHERR_OUTOFMEM )
1570 *code = LDAP_SCHERR_BADNAME;
1571 *errp = ss;
1572 ldap_syntax_free(syn);
1573 return NULL;
1575 } else if ( !strcasecmp(sval,"DESC") ) {
1576 LDAP_FREE(sval);
1577 if ( seen_desc ) {
1578 *code = LDAP_SCHERR_DUPOPT;
1579 *errp = ss;
1580 ldap_syntax_free(syn);
1581 return(NULL);
1583 seen_desc = 1;
1584 parse_whsp(&ss);
1585 kind = get_token(&ss,&sval);
1586 if ( kind != TK_QDSTRING ) {
1587 *code = LDAP_SCHERR_UNEXPTOKEN;
1588 *errp = ss;
1589 LDAP_FREE(sval);
1590 ldap_syntax_free(syn);
1591 return NULL;
1593 syn->syn_desc = sval;
1594 parse_whsp(&ss);
1595 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1596 /* Should be parse_qdstrings */
1597 ext_vals = parse_qdescrs(&ss, code);
1598 if ( !ext_vals ) {
1599 *errp = ss;
1600 ldap_syntax_free(syn);
1601 return NULL;
1603 if ( add_extension(&syn->syn_extensions,
1604 sval, ext_vals) ) {
1605 *code = LDAP_SCHERR_OUTOFMEM;
1606 *errp = ss;
1607 LDAP_FREE(sval);
1608 ldap_syntax_free(syn);
1609 return NULL;
1611 } else {
1612 *code = LDAP_SCHERR_UNEXPTOKEN;
1613 *errp = ss;
1614 LDAP_FREE(sval);
1615 ldap_syntax_free(syn);
1616 return NULL;
1618 break;
1619 default:
1620 *code = LDAP_SCHERR_UNEXPTOKEN;
1621 *errp = ss;
1622 LDAP_FREE(sval);
1623 ldap_syntax_free(syn);
1624 return NULL;
1629 void
1630 ldap_matchingrule_free( LDAPMatchingRule * mr )
1632 if (!mr) return;
1633 LDAP_FREE(mr->mr_oid);
1634 if (mr->mr_names) LDAP_VFREE(mr->mr_names);
1635 if (mr->mr_desc) LDAP_FREE(mr->mr_desc);
1636 if (mr->mr_syntax_oid) LDAP_FREE(mr->mr_syntax_oid);
1637 free_extensions(mr->mr_extensions);
1638 LDAP_FREE(mr);
1641 LDAPMatchingRule *
1642 ldap_str2matchingrule( LDAP_CONST char * s,
1643 int * code,
1644 LDAP_CONST char ** errp,
1645 LDAP_CONST unsigned flags )
1647 tk_t kind;
1648 const char * ss = s;
1649 char * sval;
1650 int seen_name = 0;
1651 int seen_desc = 0;
1652 int seen_obsolete = 0;
1653 int seen_syntax = 0;
1654 LDAPMatchingRule * mr;
1655 char ** ext_vals;
1656 const char * savepos;
1658 if ( !s ) {
1659 *code = LDAP_SCHERR_EMPTY;
1660 *errp = "";
1661 return NULL;
1664 *errp = s;
1665 mr = LDAP_CALLOC(1,sizeof(LDAPMatchingRule));
1667 if ( !mr ) {
1668 *code = LDAP_SCHERR_OUTOFMEM;
1669 return NULL;
1672 kind = get_token(&ss,&sval);
1673 if ( kind != TK_LEFTPAREN ) {
1674 *code = LDAP_SCHERR_NOLEFTPAREN;
1675 LDAP_FREE(sval);
1676 ldap_matchingrule_free(mr);
1677 return NULL;
1680 parse_whsp(&ss);
1681 savepos = ss;
1682 mr->mr_oid = ldap_int_parse_numericoid(&ss,code,flags);
1683 if ( !mr->mr_oid ) {
1684 if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
1685 /* Backtracking */
1686 ss = savepos;
1687 kind = get_token(&ss,&sval);
1688 if ( kind == TK_BAREWORD ) {
1689 if ( !strcasecmp(sval, "NAME") ||
1690 !strcasecmp(sval, "DESC") ||
1691 !strcasecmp(sval, "OBSOLETE") ||
1692 !strcasecmp(sval, "SYNTAX") ||
1693 !strncasecmp(sval, "X-", 2) ) {
1694 /* Missing OID, backtrack */
1695 ss = savepos;
1696 } else {
1697 /* Non-numerical OID, ignore */
1700 LDAP_FREE(sval);
1701 } else {
1702 *errp = ss;
1703 ldap_matchingrule_free(mr);
1704 return NULL;
1707 parse_whsp(&ss);
1710 * Beyond this point we will be liberal and accept the items
1711 * in any order.
1713 while (1) {
1714 kind = get_token(&ss,&sval);
1715 switch (kind) {
1716 case TK_EOS:
1717 *code = LDAP_SCHERR_NORIGHTPAREN;
1718 *errp = EndOfInput;
1719 ldap_matchingrule_free(mr);
1720 return NULL;
1721 case TK_RIGHTPAREN:
1722 if( !seen_syntax ) {
1723 *code = LDAP_SCHERR_MISSING;
1724 ldap_matchingrule_free(mr);
1725 return NULL;
1727 return mr;
1728 case TK_BAREWORD:
1729 if ( !strcasecmp(sval,"NAME") ) {
1730 LDAP_FREE(sval);
1731 if ( seen_name ) {
1732 *code = LDAP_SCHERR_DUPOPT;
1733 *errp = ss;
1734 ldap_matchingrule_free(mr);
1735 return(NULL);
1737 seen_name = 1;
1738 mr->mr_names = parse_qdescrs(&ss,code);
1739 if ( !mr->mr_names ) {
1740 if ( *code != LDAP_SCHERR_OUTOFMEM )
1741 *code = LDAP_SCHERR_BADNAME;
1742 *errp = ss;
1743 ldap_matchingrule_free(mr);
1744 return NULL;
1746 } else if ( !strcasecmp(sval,"DESC") ) {
1747 LDAP_FREE(sval);
1748 if ( seen_desc ) {
1749 *code = LDAP_SCHERR_DUPOPT;
1750 *errp = ss;
1751 ldap_matchingrule_free(mr);
1752 return(NULL);
1754 seen_desc = 1;
1755 parse_whsp(&ss);
1756 kind = get_token(&ss,&sval);
1757 if ( kind != TK_QDSTRING ) {
1758 *code = LDAP_SCHERR_UNEXPTOKEN;
1759 *errp = ss;
1760 LDAP_FREE(sval);
1761 ldap_matchingrule_free(mr);
1762 return NULL;
1764 mr->mr_desc = sval;
1765 parse_whsp(&ss);
1766 } else if ( !strcasecmp(sval,"OBSOLETE") ) {
1767 LDAP_FREE(sval);
1768 if ( seen_obsolete ) {
1769 *code = LDAP_SCHERR_DUPOPT;
1770 *errp = ss;
1771 ldap_matchingrule_free(mr);
1772 return(NULL);
1774 seen_obsolete = 1;
1775 mr->mr_obsolete = LDAP_SCHEMA_YES;
1776 parse_whsp(&ss);
1777 } else if ( !strcasecmp(sval,"SYNTAX") ) {
1778 LDAP_FREE(sval);
1779 if ( seen_syntax ) {
1780 *code = LDAP_SCHERR_DUPOPT;
1781 *errp = ss;
1782 ldap_matchingrule_free(mr);
1783 return(NULL);
1785 seen_syntax = 1;
1786 parse_whsp(&ss);
1787 mr->mr_syntax_oid =
1788 ldap_int_parse_numericoid(&ss,code,flags);
1789 if ( !mr->mr_syntax_oid ) {
1790 *errp = ss;
1791 ldap_matchingrule_free(mr);
1792 return NULL;
1794 parse_whsp(&ss);
1795 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1796 /* Should be parse_qdstrings */
1797 ext_vals = parse_qdescrs(&ss, code);
1798 if ( !ext_vals ) {
1799 *errp = ss;
1800 ldap_matchingrule_free(mr);
1801 return NULL;
1803 if ( add_extension(&mr->mr_extensions,
1804 sval, ext_vals) ) {
1805 *code = LDAP_SCHERR_OUTOFMEM;
1806 *errp = ss;
1807 LDAP_FREE(sval);
1808 ldap_matchingrule_free(mr);
1809 return NULL;
1811 } else {
1812 *code = LDAP_SCHERR_UNEXPTOKEN;
1813 *errp = ss;
1814 LDAP_FREE(sval);
1815 ldap_matchingrule_free(mr);
1816 return NULL;
1818 break;
1819 default:
1820 *code = LDAP_SCHERR_UNEXPTOKEN;
1821 *errp = ss;
1822 LDAP_FREE(sval);
1823 ldap_matchingrule_free(mr);
1824 return NULL;
1829 void
1830 ldap_matchingruleuse_free( LDAPMatchingRuleUse * mru )
1832 if (!mru) return;
1833 LDAP_FREE(mru->mru_oid);
1834 if (mru->mru_names) LDAP_VFREE(mru->mru_names);
1835 if (mru->mru_desc) LDAP_FREE(mru->mru_desc);
1836 if (mru->mru_applies_oids) LDAP_VFREE(mru->mru_applies_oids);
1837 free_extensions(mru->mru_extensions);
1838 LDAP_FREE(mru);
1841 LDAPMatchingRuleUse *
1842 ldap_str2matchingruleuse( LDAP_CONST char * s,
1843 int * code,
1844 LDAP_CONST char ** errp,
1845 LDAP_CONST unsigned flags )
1847 tk_t kind;
1848 const char * ss = s;
1849 char * sval;
1850 int seen_name = 0;
1851 int seen_desc = 0;
1852 int seen_obsolete = 0;
1853 int seen_applies = 0;
1854 LDAPMatchingRuleUse * mru;
1855 char ** ext_vals;
1856 const char * savepos;
1858 if ( !s ) {
1859 *code = LDAP_SCHERR_EMPTY;
1860 *errp = "";
1861 return NULL;
1864 *errp = s;
1865 mru = LDAP_CALLOC(1,sizeof(LDAPMatchingRuleUse));
1867 if ( !mru ) {
1868 *code = LDAP_SCHERR_OUTOFMEM;
1869 return NULL;
1872 kind = get_token(&ss,&sval);
1873 if ( kind != TK_LEFTPAREN ) {
1874 *code = LDAP_SCHERR_NOLEFTPAREN;
1875 LDAP_FREE(sval);
1876 ldap_matchingruleuse_free(mru);
1877 return NULL;
1880 parse_whsp(&ss);
1881 savepos = ss;
1882 mru->mru_oid = ldap_int_parse_numericoid(&ss,code,flags);
1883 if ( !mru->mru_oid ) {
1884 if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
1885 /* Backtracking */
1886 ss = savepos;
1887 kind = get_token(&ss,&sval);
1888 if ( kind == TK_BAREWORD ) {
1889 if ( !strcasecmp(sval, "NAME") ||
1890 !strcasecmp(sval, "DESC") ||
1891 !strcasecmp(sval, "OBSOLETE") ||
1892 !strcasecmp(sval, "APPLIES") ||
1893 !strncasecmp(sval, "X-", 2) ) {
1894 /* Missing OID, backtrack */
1895 ss = savepos;
1896 } else {
1897 /* Non-numerical OID, ignore */
1900 LDAP_FREE(sval);
1901 } else {
1902 *errp = ss;
1903 ldap_matchingruleuse_free(mru);
1904 return NULL;
1907 parse_whsp(&ss);
1910 * Beyond this point we will be liberal and accept the items
1911 * in any order.
1913 while (1) {
1914 kind = get_token(&ss,&sval);
1915 switch (kind) {
1916 case TK_EOS:
1917 *code = LDAP_SCHERR_NORIGHTPAREN;
1918 *errp = EndOfInput;
1919 ldap_matchingruleuse_free(mru);
1920 return NULL;
1921 case TK_RIGHTPAREN:
1922 if( !seen_applies ) {
1923 *code = LDAP_SCHERR_MISSING;
1924 ldap_matchingruleuse_free(mru);
1925 return NULL;
1927 return mru;
1928 case TK_BAREWORD:
1929 if ( !strcasecmp(sval,"NAME") ) {
1930 LDAP_FREE(sval);
1931 if ( seen_name ) {
1932 *code = LDAP_SCHERR_DUPOPT;
1933 *errp = ss;
1934 ldap_matchingruleuse_free(mru);
1935 return(NULL);
1937 seen_name = 1;
1938 mru->mru_names = parse_qdescrs(&ss,code);
1939 if ( !mru->mru_names ) {
1940 if ( *code != LDAP_SCHERR_OUTOFMEM )
1941 *code = LDAP_SCHERR_BADNAME;
1942 *errp = ss;
1943 ldap_matchingruleuse_free(mru);
1944 return NULL;
1946 } else if ( !strcasecmp(sval,"DESC") ) {
1947 LDAP_FREE(sval);
1948 if ( seen_desc ) {
1949 *code = LDAP_SCHERR_DUPOPT;
1950 *errp = ss;
1951 ldap_matchingruleuse_free(mru);
1952 return(NULL);
1954 seen_desc = 1;
1955 parse_whsp(&ss);
1956 kind = get_token(&ss,&sval);
1957 if ( kind != TK_QDSTRING ) {
1958 *code = LDAP_SCHERR_UNEXPTOKEN;
1959 *errp = ss;
1960 LDAP_FREE(sval);
1961 ldap_matchingruleuse_free(mru);
1962 return NULL;
1964 mru->mru_desc = sval;
1965 parse_whsp(&ss);
1966 } else if ( !strcasecmp(sval,"OBSOLETE") ) {
1967 LDAP_FREE(sval);
1968 if ( seen_obsolete ) {
1969 *code = LDAP_SCHERR_DUPOPT;
1970 *errp = ss;
1971 ldap_matchingruleuse_free(mru);
1972 return(NULL);
1974 seen_obsolete = 1;
1975 mru->mru_obsolete = LDAP_SCHEMA_YES;
1976 parse_whsp(&ss);
1977 } else if ( !strcasecmp(sval,"APPLIES") ) {
1978 LDAP_FREE(sval);
1979 if ( seen_applies ) {
1980 *code = LDAP_SCHERR_DUPOPT;
1981 *errp = ss;
1982 ldap_matchingruleuse_free(mru);
1983 return(NULL);
1985 seen_applies = 1;
1986 mru->mru_applies_oids = parse_oids(&ss,
1987 code,
1988 flags);
1989 if ( !mru->mru_applies_oids && *code != LDAP_SUCCESS ) {
1990 *errp = ss;
1991 ldap_matchingruleuse_free(mru);
1992 return NULL;
1994 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1995 /* Should be parse_qdstrings */
1996 ext_vals = parse_qdescrs(&ss, code);
1997 if ( !ext_vals ) {
1998 *errp = ss;
1999 ldap_matchingruleuse_free(mru);
2000 return NULL;
2002 if ( add_extension(&mru->mru_extensions,
2003 sval, ext_vals) ) {
2004 *code = LDAP_SCHERR_OUTOFMEM;
2005 *errp = ss;
2006 LDAP_FREE(sval);
2007 ldap_matchingruleuse_free(mru);
2008 return NULL;
2010 } else {
2011 *code = LDAP_SCHERR_UNEXPTOKEN;
2012 *errp = ss;
2013 LDAP_FREE(sval);
2014 ldap_matchingruleuse_free(mru);
2015 return NULL;
2017 break;
2018 default:
2019 *code = LDAP_SCHERR_UNEXPTOKEN;
2020 *errp = ss;
2021 LDAP_FREE(sval);
2022 ldap_matchingruleuse_free(mru);
2023 return NULL;
2028 void
2029 ldap_attributetype_free(LDAPAttributeType * at)
2031 if (!at) return;
2032 LDAP_FREE(at->at_oid);
2033 if (at->at_names) LDAP_VFREE(at->at_names);
2034 if (at->at_desc) LDAP_FREE(at->at_desc);
2035 if (at->at_sup_oid) LDAP_FREE(at->at_sup_oid);
2036 if (at->at_equality_oid) LDAP_FREE(at->at_equality_oid);
2037 if (at->at_ordering_oid) LDAP_FREE(at->at_ordering_oid);
2038 if (at->at_substr_oid) LDAP_FREE(at->at_substr_oid);
2039 if (at->at_syntax_oid) LDAP_FREE(at->at_syntax_oid);
2040 free_extensions(at->at_extensions);
2041 LDAP_FREE(at);
2044 LDAPAttributeType *
2045 ldap_str2attributetype( LDAP_CONST char * s,
2046 int * code,
2047 LDAP_CONST char ** errp,
2048 LDAP_CONST unsigned flags )
2050 tk_t kind;
2051 const char * ss = s;
2052 char * sval;
2053 int seen_name = 0;
2054 int seen_desc = 0;
2055 int seen_obsolete = 0;
2056 int seen_sup = 0;
2057 int seen_equality = 0;
2058 int seen_ordering = 0;
2059 int seen_substr = 0;
2060 int seen_syntax = 0;
2061 int seen_usage = 0;
2062 LDAPAttributeType * at;
2063 char ** ext_vals;
2064 const char * savepos;
2066 if ( !s ) {
2067 *code = LDAP_SCHERR_EMPTY;
2068 *errp = "";
2069 return NULL;
2072 *errp = s;
2073 at = LDAP_CALLOC(1,sizeof(LDAPAttributeType));
2075 if ( !at ) {
2076 *code = LDAP_SCHERR_OUTOFMEM;
2077 return NULL;
2080 kind = get_token(&ss,&sval);
2081 if ( kind != TK_LEFTPAREN ) {
2082 *code = LDAP_SCHERR_NOLEFTPAREN;
2083 LDAP_FREE(sval);
2084 ldap_attributetype_free(at);
2085 return NULL;
2089 * Definitions MUST begin with an OID in the numericoid format.
2090 * However, this routine is used by clients to parse the response
2091 * from servers and very well known servers will provide an OID
2092 * in the wrong format or even no OID at all. We do our best to
2093 * extract info from those servers.
2095 parse_whsp(&ss);
2096 savepos = ss;
2097 at->at_oid = ldap_int_parse_numericoid(&ss,code,0);
2098 if ( !at->at_oid ) {
2099 if ( ( flags & ( LDAP_SCHEMA_ALLOW_NO_OID
2100 | LDAP_SCHEMA_ALLOW_OID_MACRO ) )
2101 && (ss == savepos) )
2103 /* Backtracking */
2104 ss = savepos;
2105 kind = get_token(&ss,&sval);
2106 if ( kind == TK_BAREWORD ) {
2107 if ( !strcasecmp(sval, "NAME") ||
2108 !strcasecmp(sval, "DESC") ||
2109 !strcasecmp(sval, "OBSOLETE") ||
2110 !strcasecmp(sval, "SUP") ||
2111 !strcasecmp(sval, "EQUALITY") ||
2112 !strcasecmp(sval, "ORDERING") ||
2113 !strcasecmp(sval, "SUBSTR") ||
2114 !strcasecmp(sval, "SYNTAX") ||
2115 !strcasecmp(sval, "SINGLE-VALUE") ||
2116 !strcasecmp(sval, "COLLECTIVE") ||
2117 !strcasecmp(sval, "NO-USER-MODIFICATION") ||
2118 !strcasecmp(sval, "USAGE") ||
2119 !strncasecmp(sval, "X-", 2) )
2121 /* Missing OID, backtrack */
2122 ss = savepos;
2123 } else if ( flags
2124 & LDAP_SCHEMA_ALLOW_OID_MACRO)
2126 /* Non-numerical OID ... */
2127 int len = ss-savepos;
2128 at->at_oid = LDAP_MALLOC(len+1);
2129 if ( !at->at_oid ) {
2130 ldap_attributetype_free(at);
2131 return NULL;
2134 strncpy(at->at_oid, savepos, len);
2135 at->at_oid[len] = 0;
2138 LDAP_FREE(sval);
2139 } else {
2140 *errp = ss;
2141 ldap_attributetype_free(at);
2142 return NULL;
2145 parse_whsp(&ss);
2148 * Beyond this point we will be liberal and accept the items
2149 * in any order.
2151 while (1) {
2152 kind = get_token(&ss,&sval);
2153 switch (kind) {
2154 case TK_EOS:
2155 *code = LDAP_SCHERR_NORIGHTPAREN;
2156 *errp = EndOfInput;
2157 ldap_attributetype_free(at);
2158 return NULL;
2159 case TK_RIGHTPAREN:
2160 return at;
2161 case TK_BAREWORD:
2162 if ( !strcasecmp(sval,"NAME") ) {
2163 LDAP_FREE(sval);
2164 if ( seen_name ) {
2165 *code = LDAP_SCHERR_DUPOPT;
2166 *errp = ss;
2167 ldap_attributetype_free(at);
2168 return(NULL);
2170 seen_name = 1;
2171 at->at_names = parse_qdescrs(&ss,code);
2172 if ( !at->at_names ) {
2173 if ( *code != LDAP_SCHERR_OUTOFMEM )
2174 *code = LDAP_SCHERR_BADNAME;
2175 *errp = ss;
2176 ldap_attributetype_free(at);
2177 return NULL;
2179 } else if ( !strcasecmp(sval,"DESC") ) {
2180 LDAP_FREE(sval);
2181 if ( seen_desc ) {
2182 *code = LDAP_SCHERR_DUPOPT;
2183 *errp = ss;
2184 ldap_attributetype_free(at);
2185 return(NULL);
2187 seen_desc = 1;
2188 parse_whsp(&ss);
2189 kind = get_token(&ss,&sval);
2190 if ( kind != TK_QDSTRING ) {
2191 *code = LDAP_SCHERR_UNEXPTOKEN;
2192 *errp = ss;
2193 LDAP_FREE(sval);
2194 ldap_attributetype_free(at);
2195 return NULL;
2197 at->at_desc = sval;
2198 parse_whsp(&ss);
2199 } else if ( !strcasecmp(sval,"OBSOLETE") ) {
2200 LDAP_FREE(sval);
2201 if ( seen_obsolete ) {
2202 *code = LDAP_SCHERR_DUPOPT;
2203 *errp = ss;
2204 ldap_attributetype_free(at);
2205 return(NULL);
2207 seen_obsolete = 1;
2208 at->at_obsolete = LDAP_SCHEMA_YES;
2209 parse_whsp(&ss);
2210 } else if ( !strcasecmp(sval,"SUP") ) {
2211 LDAP_FREE(sval);
2212 if ( seen_sup ) {
2213 *code = LDAP_SCHERR_DUPOPT;
2214 *errp = ss;
2215 ldap_attributetype_free(at);
2216 return(NULL);
2218 seen_sup = 1;
2219 at->at_sup_oid = parse_woid(&ss,code);
2220 if ( !at->at_sup_oid ) {
2221 *errp = ss;
2222 ldap_attributetype_free(at);
2223 return NULL;
2225 } else if ( !strcasecmp(sval,"EQUALITY") ) {
2226 LDAP_FREE(sval);
2227 if ( seen_equality ) {
2228 *code = LDAP_SCHERR_DUPOPT;
2229 *errp = ss;
2230 ldap_attributetype_free(at);
2231 return(NULL);
2233 seen_equality = 1;
2234 at->at_equality_oid = parse_woid(&ss,code);
2235 if ( !at->at_equality_oid ) {
2236 *errp = ss;
2237 ldap_attributetype_free(at);
2238 return NULL;
2240 } else if ( !strcasecmp(sval,"ORDERING") ) {
2241 LDAP_FREE(sval);
2242 if ( seen_ordering ) {
2243 *code = LDAP_SCHERR_DUPOPT;
2244 *errp = ss;
2245 ldap_attributetype_free(at);
2246 return(NULL);
2248 seen_ordering = 1;
2249 at->at_ordering_oid = parse_woid(&ss,code);
2250 if ( !at->at_ordering_oid ) {
2251 *errp = ss;
2252 ldap_attributetype_free(at);
2253 return NULL;
2255 } else if ( !strcasecmp(sval,"SUBSTR") ) {
2256 LDAP_FREE(sval);
2257 if ( seen_substr ) {
2258 *code = LDAP_SCHERR_DUPOPT;
2259 *errp = ss;
2260 ldap_attributetype_free(at);
2261 return(NULL);
2263 seen_substr = 1;
2264 at->at_substr_oid = parse_woid(&ss,code);
2265 if ( !at->at_substr_oid ) {
2266 *errp = ss;
2267 ldap_attributetype_free(at);
2268 return NULL;
2270 } else if ( !strcasecmp(sval,"SYNTAX") ) {
2271 LDAP_FREE(sval);
2272 if ( seen_syntax ) {
2273 *code = LDAP_SCHERR_DUPOPT;
2274 *errp = ss;
2275 ldap_attributetype_free(at);
2276 return(NULL);
2278 seen_syntax = 1;
2279 parse_whsp(&ss);
2280 savepos = ss;
2281 at->at_syntax_oid =
2282 parse_noidlen(&ss,
2283 code,
2284 &at->at_syntax_len,
2285 flags);
2286 if ( !at->at_syntax_oid ) {
2287 if ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO ) {
2288 kind = get_token(&ss,&sval);
2289 if (kind == TK_BAREWORD)
2291 char *sp = strchr(sval, '{');
2292 at->at_syntax_oid = sval;
2293 if (sp)
2295 *sp++ = 0;
2296 at->at_syntax_len = atoi(sp);
2297 while ( LDAP_DIGIT(*sp) )
2298 sp++;
2299 if ( *sp != '}' ) {
2300 *code = LDAP_SCHERR_UNEXPTOKEN;
2301 *errp = ss;
2302 ldap_attributetype_free(at);
2303 return NULL;
2307 } else {
2308 *errp = ss;
2309 ldap_attributetype_free(at);
2310 return NULL;
2313 parse_whsp(&ss);
2314 } else if ( !strcasecmp(sval,"SINGLE-VALUE") ) {
2315 LDAP_FREE(sval);
2316 if ( at->at_single_value ) {
2317 *code = LDAP_SCHERR_DUPOPT;
2318 *errp = ss;
2319 ldap_attributetype_free(at);
2320 return(NULL);
2322 at->at_single_value = LDAP_SCHEMA_YES;
2323 parse_whsp(&ss);
2324 } else if ( !strcasecmp(sval,"COLLECTIVE") ) {
2325 LDAP_FREE(sval);
2326 if ( at->at_collective ) {
2327 *code = LDAP_SCHERR_DUPOPT;
2328 *errp = ss;
2329 ldap_attributetype_free(at);
2330 return(NULL);
2332 at->at_collective = LDAP_SCHEMA_YES;
2333 parse_whsp(&ss);
2334 } else if ( !strcasecmp(sval,"NO-USER-MODIFICATION") ) {
2335 LDAP_FREE(sval);
2336 if ( at->at_no_user_mod ) {
2337 *code = LDAP_SCHERR_DUPOPT;
2338 *errp = ss;
2339 ldap_attributetype_free(at);
2340 return(NULL);
2342 at->at_no_user_mod = LDAP_SCHEMA_YES;
2343 parse_whsp(&ss);
2344 } else if ( !strcasecmp(sval,"USAGE") ) {
2345 LDAP_FREE(sval);
2346 if ( seen_usage ) {
2347 *code = LDAP_SCHERR_DUPOPT;
2348 *errp = ss;
2349 ldap_attributetype_free(at);
2350 return(NULL);
2352 seen_usage = 1;
2353 parse_whsp(&ss);
2354 kind = get_token(&ss,&sval);
2355 if ( kind != TK_BAREWORD ) {
2356 *code = LDAP_SCHERR_UNEXPTOKEN;
2357 *errp = ss;
2358 LDAP_FREE(sval);
2359 ldap_attributetype_free(at);
2360 return NULL;
2362 if ( !strcasecmp(sval,"userApplications") )
2363 at->at_usage =
2364 LDAP_SCHEMA_USER_APPLICATIONS;
2365 else if ( !strcasecmp(sval,"directoryOperation") )
2366 at->at_usage =
2367 LDAP_SCHEMA_DIRECTORY_OPERATION;
2368 else if ( !strcasecmp(sval,"distributedOperation") )
2369 at->at_usage =
2370 LDAP_SCHEMA_DISTRIBUTED_OPERATION;
2371 else if ( !strcasecmp(sval,"dSAOperation") )
2372 at->at_usage =
2373 LDAP_SCHEMA_DSA_OPERATION;
2374 else {
2375 *code = LDAP_SCHERR_UNEXPTOKEN;
2376 *errp = ss;
2377 LDAP_FREE(sval);
2378 ldap_attributetype_free(at);
2379 return NULL;
2381 LDAP_FREE(sval);
2382 parse_whsp(&ss);
2383 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
2384 /* Should be parse_qdstrings */
2385 ext_vals = parse_qdescrs(&ss, code);
2386 if ( !ext_vals ) {
2387 *errp = ss;
2388 ldap_attributetype_free(at);
2389 return NULL;
2391 if ( add_extension(&at->at_extensions,
2392 sval, ext_vals) ) {
2393 *code = LDAP_SCHERR_OUTOFMEM;
2394 *errp = ss;
2395 LDAP_FREE(sval);
2396 ldap_attributetype_free(at);
2397 return NULL;
2399 } else {
2400 *code = LDAP_SCHERR_UNEXPTOKEN;
2401 *errp = ss;
2402 LDAP_FREE(sval);
2403 ldap_attributetype_free(at);
2404 return NULL;
2406 break;
2407 default:
2408 *code = LDAP_SCHERR_UNEXPTOKEN;
2409 *errp = ss;
2410 LDAP_FREE(sval);
2411 ldap_attributetype_free(at);
2412 return NULL;
2417 void
2418 ldap_objectclass_free(LDAPObjectClass * oc)
2420 if (!oc) return;
2421 LDAP_FREE(oc->oc_oid);
2422 if (oc->oc_names) LDAP_VFREE(oc->oc_names);
2423 if (oc->oc_desc) LDAP_FREE(oc->oc_desc);
2424 if (oc->oc_sup_oids) LDAP_VFREE(oc->oc_sup_oids);
2425 if (oc->oc_at_oids_must) LDAP_VFREE(oc->oc_at_oids_must);
2426 if (oc->oc_at_oids_may) LDAP_VFREE(oc->oc_at_oids_may);
2427 free_extensions(oc->oc_extensions);
2428 LDAP_FREE(oc);
2431 LDAPObjectClass *
2432 ldap_str2objectclass( LDAP_CONST char * s,
2433 int * code,
2434 LDAP_CONST char ** errp,
2435 LDAP_CONST unsigned flags )
2437 tk_t kind;
2438 const char * ss = s;
2439 char * sval;
2440 int seen_name = 0;
2441 int seen_desc = 0;
2442 int seen_obsolete = 0;
2443 int seen_sup = 0;
2444 int seen_kind = 0;
2445 int seen_must = 0;
2446 int seen_may = 0;
2447 LDAPObjectClass * oc;
2448 char ** ext_vals;
2449 const char * savepos;
2451 if ( !s ) {
2452 *code = LDAP_SCHERR_EMPTY;
2453 *errp = "";
2454 return NULL;
2457 *errp = s;
2458 oc = LDAP_CALLOC(1,sizeof(LDAPObjectClass));
2460 if ( !oc ) {
2461 *code = LDAP_SCHERR_OUTOFMEM;
2462 return NULL;
2464 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
2466 kind = get_token(&ss,&sval);
2467 if ( kind != TK_LEFTPAREN ) {
2468 *code = LDAP_SCHERR_NOLEFTPAREN;
2469 LDAP_FREE(sval);
2470 ldap_objectclass_free(oc);
2471 return NULL;
2475 * Definitions MUST begin with an OID in the numericoid format.
2476 * However, this routine is used by clients to parse the response
2477 * from servers and very well known servers will provide an OID
2478 * in the wrong format or even no OID at all. We do our best to
2479 * extract info from those servers.
2481 parse_whsp(&ss);
2482 savepos = ss;
2483 oc->oc_oid = ldap_int_parse_numericoid(&ss,code,0);
2484 if ( !oc->oc_oid ) {
2485 if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) {
2486 /* Backtracking */
2487 ss = savepos;
2488 kind = get_token(&ss,&sval);
2489 if ( kind == TK_BAREWORD ) {
2490 if ( !strcasecmp(sval, "NAME") ||
2491 !strcasecmp(sval, "DESC") ||
2492 !strcasecmp(sval, "OBSOLETE") ||
2493 !strcasecmp(sval, "SUP") ||
2494 !strcasecmp(sval, "ABSTRACT") ||
2495 !strcasecmp(sval, "STRUCTURAL") ||
2496 !strcasecmp(sval, "AUXILIARY") ||
2497 !strcasecmp(sval, "MUST") ||
2498 !strcasecmp(sval, "MAY") ||
2499 !strncasecmp(sval, "X-", 2) ) {
2500 /* Missing OID, backtrack */
2501 ss = savepos;
2502 } else if ( flags &
2503 LDAP_SCHEMA_ALLOW_OID_MACRO ) {
2504 /* Non-numerical OID, ignore */
2505 int len = ss-savepos;
2506 oc->oc_oid = LDAP_MALLOC(len+1);
2507 if ( !oc->oc_oid ) {
2508 ldap_objectclass_free(oc);
2509 return NULL;
2512 strncpy(oc->oc_oid, savepos, len);
2513 oc->oc_oid[len] = 0;
2516 LDAP_FREE(sval);
2517 *code = 0;
2518 } else {
2519 *errp = ss;
2520 ldap_objectclass_free(oc);
2521 return NULL;
2524 parse_whsp(&ss);
2527 * Beyond this point we will be liberal an accept the items
2528 * in any order.
2530 while (1) {
2531 kind = get_token(&ss,&sval);
2532 switch (kind) {
2533 case TK_EOS:
2534 *code = LDAP_SCHERR_NORIGHTPAREN;
2535 *errp = EndOfInput;
2536 ldap_objectclass_free(oc);
2537 return NULL;
2538 case TK_RIGHTPAREN:
2539 return oc;
2540 case TK_BAREWORD:
2541 if ( !strcasecmp(sval,"NAME") ) {
2542 LDAP_FREE(sval);
2543 if ( seen_name ) {
2544 *code = LDAP_SCHERR_DUPOPT;
2545 *errp = ss;
2546 ldap_objectclass_free(oc);
2547 return(NULL);
2549 seen_name = 1;
2550 oc->oc_names = parse_qdescrs(&ss,code);
2551 if ( !oc->oc_names ) {
2552 if ( *code != LDAP_SCHERR_OUTOFMEM )
2553 *code = LDAP_SCHERR_BADNAME;
2554 *errp = ss;
2555 ldap_objectclass_free(oc);
2556 return NULL;
2558 } else if ( !strcasecmp(sval,"DESC") ) {
2559 LDAP_FREE(sval);
2560 if ( seen_desc ) {
2561 *code = LDAP_SCHERR_DUPOPT;
2562 *errp = ss;
2563 ldap_objectclass_free(oc);
2564 return(NULL);
2566 seen_desc = 1;
2567 parse_whsp(&ss);
2568 kind = get_token(&ss,&sval);
2569 if ( kind != TK_QDSTRING ) {
2570 *code = LDAP_SCHERR_UNEXPTOKEN;
2571 *errp = ss;
2572 LDAP_FREE(sval);
2573 ldap_objectclass_free(oc);
2574 return NULL;
2576 oc->oc_desc = sval;
2577 parse_whsp(&ss);
2578 } else if ( !strcasecmp(sval,"OBSOLETE") ) {
2579 LDAP_FREE(sval);
2580 if ( seen_obsolete ) {
2581 *code = LDAP_SCHERR_DUPOPT;
2582 *errp = ss;
2583 ldap_objectclass_free(oc);
2584 return(NULL);
2586 seen_obsolete = 1;
2587 oc->oc_obsolete = LDAP_SCHEMA_YES;
2588 parse_whsp(&ss);
2589 } else if ( !strcasecmp(sval,"SUP") ) {
2590 LDAP_FREE(sval);
2591 if ( seen_sup ) {
2592 *code = LDAP_SCHERR_DUPOPT;
2593 *errp = ss;
2594 ldap_objectclass_free(oc);
2595 return(NULL);
2597 seen_sup = 1;
2598 oc->oc_sup_oids = parse_oids(&ss,
2599 code,
2600 flags);
2601 if ( !oc->oc_sup_oids && *code != LDAP_SUCCESS ) {
2602 *errp = ss;
2603 ldap_objectclass_free(oc);
2604 return NULL;
2606 *code = 0;
2607 } else if ( !strcasecmp(sval,"ABSTRACT") ) {
2608 LDAP_FREE(sval);
2609 if ( seen_kind ) {
2610 *code = LDAP_SCHERR_DUPOPT;
2611 *errp = ss;
2612 ldap_objectclass_free(oc);
2613 return(NULL);
2615 seen_kind = 1;
2616 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
2617 parse_whsp(&ss);
2618 } else if ( !strcasecmp(sval,"STRUCTURAL") ) {
2619 LDAP_FREE(sval);
2620 if ( seen_kind ) {
2621 *code = LDAP_SCHERR_DUPOPT;
2622 *errp = ss;
2623 ldap_objectclass_free(oc);
2624 return(NULL);
2626 seen_kind = 1;
2627 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
2628 parse_whsp(&ss);
2629 } else if ( !strcasecmp(sval,"AUXILIARY") ) {
2630 LDAP_FREE(sval);
2631 if ( seen_kind ) {
2632 *code = LDAP_SCHERR_DUPOPT;
2633 *errp = ss;
2634 ldap_objectclass_free(oc);
2635 return(NULL);
2637 seen_kind = 1;
2638 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
2639 parse_whsp(&ss);
2640 } else if ( !strcasecmp(sval,"MUST") ) {
2641 LDAP_FREE(sval);
2642 if ( seen_must ) {
2643 *code = LDAP_SCHERR_DUPOPT;
2644 *errp = ss;
2645 ldap_objectclass_free(oc);
2646 return(NULL);
2648 seen_must = 1;
2649 oc->oc_at_oids_must = parse_oids(&ss,code,0);
2650 if ( !oc->oc_at_oids_must && *code != LDAP_SUCCESS ) {
2651 *errp = ss;
2652 ldap_objectclass_free(oc);
2653 return NULL;
2655 *code = 0;
2656 parse_whsp(&ss);
2657 } else if ( !strcasecmp(sval,"MAY") ) {
2658 LDAP_FREE(sval);
2659 if ( seen_may ) {
2660 *code = LDAP_SCHERR_DUPOPT;
2661 *errp = ss;
2662 ldap_objectclass_free(oc);
2663 return(NULL);
2665 seen_may = 1;
2666 oc->oc_at_oids_may = parse_oids(&ss,code,0);
2667 if ( !oc->oc_at_oids_may && *code != LDAP_SUCCESS ) {
2668 *errp = ss;
2669 ldap_objectclass_free(oc);
2670 return NULL;
2672 *code = 0;
2673 parse_whsp(&ss);
2674 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
2675 /* Should be parse_qdstrings */
2676 ext_vals = parse_qdescrs(&ss, code);
2677 *code = 0;
2678 if ( !ext_vals ) {
2679 *errp = ss;
2680 ldap_objectclass_free(oc);
2681 return NULL;
2683 if ( add_extension(&oc->oc_extensions,
2684 sval, ext_vals) ) {
2685 *code = LDAP_SCHERR_OUTOFMEM;
2686 *errp = ss;
2687 LDAP_FREE(sval);
2688 ldap_objectclass_free(oc);
2689 return NULL;
2691 } else {
2692 *code = LDAP_SCHERR_UNEXPTOKEN;
2693 *errp = ss;
2694 LDAP_FREE(sval);
2695 ldap_objectclass_free(oc);
2696 return NULL;
2698 break;
2699 default:
2700 *code = LDAP_SCHERR_UNEXPTOKEN;
2701 *errp = ss;
2702 LDAP_FREE(sval);
2703 ldap_objectclass_free(oc);
2704 return NULL;
2709 void
2710 ldap_contentrule_free(LDAPContentRule * cr)
2712 if (!cr) return;
2713 LDAP_FREE(cr->cr_oid);
2714 if (cr->cr_names) LDAP_VFREE(cr->cr_names);
2715 if (cr->cr_desc) LDAP_FREE(cr->cr_desc);
2716 if (cr->cr_oc_oids_aux) LDAP_VFREE(cr->cr_oc_oids_aux);
2717 if (cr->cr_at_oids_must) LDAP_VFREE(cr->cr_at_oids_must);
2718 if (cr->cr_at_oids_may) LDAP_VFREE(cr->cr_at_oids_may);
2719 if (cr->cr_at_oids_not) LDAP_VFREE(cr->cr_at_oids_not);
2720 free_extensions(cr->cr_extensions);
2721 LDAP_FREE(cr);
2724 LDAPContentRule *
2725 ldap_str2contentrule( LDAP_CONST char * s,
2726 int * code,
2727 LDAP_CONST char ** errp,
2728 LDAP_CONST unsigned flags )
2730 tk_t kind;
2731 const char * ss = s;
2732 char * sval;
2733 int seen_name = 0;
2734 int seen_desc = 0;
2735 int seen_obsolete = 0;
2736 int seen_aux = 0;
2737 int seen_must = 0;
2738 int seen_may = 0;
2739 int seen_not = 0;
2740 LDAPContentRule * cr;
2741 char ** ext_vals;
2742 const char * savepos;
2744 if ( !s ) {
2745 *code = LDAP_SCHERR_EMPTY;
2746 *errp = "";
2747 return NULL;
2750 *errp = s;
2751 cr = LDAP_CALLOC(1,sizeof(LDAPContentRule));
2753 if ( !cr ) {
2754 *code = LDAP_SCHERR_OUTOFMEM;
2755 return NULL;
2758 kind = get_token(&ss,&sval);
2759 if ( kind != TK_LEFTPAREN ) {
2760 *code = LDAP_SCHERR_NOLEFTPAREN;
2761 LDAP_FREE(sval);
2762 ldap_contentrule_free(cr);
2763 return NULL;
2767 * Definitions MUST begin with an OID in the numericoid format.
2769 parse_whsp(&ss);
2770 savepos = ss;
2771 cr->cr_oid = ldap_int_parse_numericoid(&ss,code,0);
2772 if ( !cr->cr_oid ) {
2773 if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) {
2774 /* Backtracking */
2775 ss = savepos;
2776 kind = get_token(&ss,&sval);
2777 if ( kind == TK_BAREWORD ) {
2778 if ( !strcasecmp(sval, "NAME") ||
2779 !strcasecmp(sval, "DESC") ||
2780 !strcasecmp(sval, "OBSOLETE") ||
2781 !strcasecmp(sval, "AUX") ||
2782 !strcasecmp(sval, "MUST") ||
2783 !strcasecmp(sval, "MAY") ||
2784 !strcasecmp(sval, "NOT") ||
2785 !strncasecmp(sval, "X-", 2) ) {
2786 /* Missing OID, backtrack */
2787 ss = savepos;
2788 } else if ( flags &
2789 LDAP_SCHEMA_ALLOW_OID_MACRO ) {
2790 /* Non-numerical OID, ignore */
2791 int len = ss-savepos;
2792 cr->cr_oid = LDAP_MALLOC(len+1);
2793 if ( !cr->cr_oid ) {
2794 ldap_contentrule_free(cr);
2795 return NULL;
2798 strncpy(cr->cr_oid, savepos, len);
2799 cr->cr_oid[len] = 0;
2802 LDAP_FREE(sval);
2803 } else {
2804 *errp = ss;
2805 ldap_contentrule_free(cr);
2806 return NULL;
2809 parse_whsp(&ss);
2812 * Beyond this point we will be liberal an accept the items
2813 * in any order.
2815 while (1) {
2816 kind = get_token(&ss,&sval);
2817 switch (kind) {
2818 case TK_EOS:
2819 *code = LDAP_SCHERR_NORIGHTPAREN;
2820 *errp = EndOfInput;
2821 ldap_contentrule_free(cr);
2822 return NULL;
2823 case TK_RIGHTPAREN:
2824 return cr;
2825 case TK_BAREWORD:
2826 if ( !strcasecmp(sval,"NAME") ) {
2827 LDAP_FREE(sval);
2828 if ( seen_name ) {
2829 *code = LDAP_SCHERR_DUPOPT;
2830 *errp = ss;
2831 ldap_contentrule_free(cr);
2832 return(NULL);
2834 seen_name = 1;
2835 cr->cr_names = parse_qdescrs(&ss,code);
2836 if ( !cr->cr_names ) {
2837 if ( *code != LDAP_SCHERR_OUTOFMEM )
2838 *code = LDAP_SCHERR_BADNAME;
2839 *errp = ss;
2840 ldap_contentrule_free(cr);
2841 return NULL;
2843 } else if ( !strcasecmp(sval,"DESC") ) {
2844 LDAP_FREE(sval);
2845 if ( seen_desc ) {
2846 *code = LDAP_SCHERR_DUPOPT;
2847 *errp = ss;
2848 ldap_contentrule_free(cr);
2849 return(NULL);
2851 seen_desc = 1;
2852 parse_whsp(&ss);
2853 kind = get_token(&ss,&sval);
2854 if ( kind != TK_QDSTRING ) {
2855 *code = LDAP_SCHERR_UNEXPTOKEN;
2856 *errp = ss;
2857 LDAP_FREE(sval);
2858 ldap_contentrule_free(cr);
2859 return NULL;
2861 cr->cr_desc = sval;
2862 parse_whsp(&ss);
2863 } else if ( !strcasecmp(sval,"OBSOLETE") ) {
2864 LDAP_FREE(sval);
2865 if ( seen_obsolete ) {
2866 *code = LDAP_SCHERR_DUPOPT;
2867 *errp = ss;
2868 ldap_contentrule_free(cr);
2869 return(NULL);
2871 seen_obsolete = 1;
2872 cr->cr_obsolete = LDAP_SCHEMA_YES;
2873 parse_whsp(&ss);
2874 } else if ( !strcasecmp(sval,"AUX") ) {
2875 LDAP_FREE(sval);
2876 if ( seen_aux ) {
2877 *code = LDAP_SCHERR_DUPOPT;
2878 *errp = ss;
2879 ldap_contentrule_free(cr);
2880 return(NULL);
2882 seen_aux = 1;
2883 cr->cr_oc_oids_aux = parse_oids(&ss,code,0);
2884 if ( !cr->cr_oc_oids_aux ) {
2885 *errp = ss;
2886 ldap_contentrule_free(cr);
2887 return NULL;
2889 parse_whsp(&ss);
2890 } else if ( !strcasecmp(sval,"MUST") ) {
2891 LDAP_FREE(sval);
2892 if ( seen_must ) {
2893 *code = LDAP_SCHERR_DUPOPT;
2894 *errp = ss;
2895 ldap_contentrule_free(cr);
2896 return(NULL);
2898 seen_must = 1;
2899 cr->cr_at_oids_must = parse_oids(&ss,code,0);
2900 if ( !cr->cr_at_oids_must && *code != LDAP_SUCCESS ) {
2901 *errp = ss;
2902 ldap_contentrule_free(cr);
2903 return NULL;
2905 parse_whsp(&ss);
2906 } else if ( !strcasecmp(sval,"MAY") ) {
2907 LDAP_FREE(sval);
2908 if ( seen_may ) {
2909 *code = LDAP_SCHERR_DUPOPT;
2910 *errp = ss;
2911 ldap_contentrule_free(cr);
2912 return(NULL);
2914 seen_may = 1;
2915 cr->cr_at_oids_may = parse_oids(&ss,code,0);
2916 if ( !cr->cr_at_oids_may && *code != LDAP_SUCCESS ) {
2917 *errp = ss;
2918 ldap_contentrule_free(cr);
2919 return NULL;
2921 parse_whsp(&ss);
2922 } else if ( !strcasecmp(sval,"NOT") ) {
2923 LDAP_FREE(sval);
2924 if ( seen_not ) {
2925 *code = LDAP_SCHERR_DUPOPT;
2926 *errp = ss;
2927 ldap_contentrule_free(cr);
2928 return(NULL);
2930 seen_not = 1;
2931 cr->cr_at_oids_not = parse_oids(&ss,code,0);
2932 if ( !cr->cr_at_oids_not && *code != LDAP_SUCCESS ) {
2933 *errp = ss;
2934 ldap_contentrule_free(cr);
2935 return NULL;
2937 parse_whsp(&ss);
2938 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
2939 /* Should be parse_qdstrings */
2940 ext_vals = parse_qdescrs(&ss, code);
2941 if ( !ext_vals ) {
2942 *errp = ss;
2943 ldap_contentrule_free(cr);
2944 return NULL;
2946 if ( add_extension(&cr->cr_extensions,
2947 sval, ext_vals) ) {
2948 *code = LDAP_SCHERR_OUTOFMEM;
2949 *errp = ss;
2950 LDAP_FREE(sval);
2951 ldap_contentrule_free(cr);
2952 return NULL;
2954 } else {
2955 *code = LDAP_SCHERR_UNEXPTOKEN;
2956 *errp = ss;
2957 LDAP_FREE(sval);
2958 ldap_contentrule_free(cr);
2959 return NULL;
2961 break;
2962 default:
2963 *code = LDAP_SCHERR_UNEXPTOKEN;
2964 *errp = ss;
2965 LDAP_FREE(sval);
2966 ldap_contentrule_free(cr);
2967 return NULL;
2972 void
2973 ldap_structurerule_free(LDAPStructureRule * sr)
2975 if (!sr) return;
2976 if (sr->sr_names) LDAP_VFREE(sr->sr_names);
2977 if (sr->sr_desc) LDAP_FREE(sr->sr_desc);
2978 if (sr->sr_nameform) LDAP_FREE(sr->sr_nameform);
2979 if (sr->sr_sup_ruleids) LDAP_FREE(sr->sr_sup_ruleids);
2980 free_extensions(sr->sr_extensions);
2981 LDAP_FREE(sr);
2984 LDAPStructureRule *
2985 ldap_str2structurerule( LDAP_CONST char * s,
2986 int * code,
2987 LDAP_CONST char ** errp,
2988 LDAP_CONST unsigned flags )
2990 tk_t kind;
2991 int ret;
2992 const char * ss = s;
2993 char * sval;
2994 int seen_name = 0;
2995 int seen_desc = 0;
2996 int seen_obsolete = 0;
2997 int seen_nameform = 0;
2998 LDAPStructureRule * sr;
2999 char ** ext_vals;
3000 const char * savepos;
3002 if ( !s ) {
3003 *code = LDAP_SCHERR_EMPTY;
3004 *errp = "";
3005 return NULL;
3008 *errp = s;
3009 sr = LDAP_CALLOC(1,sizeof(LDAPStructureRule));
3011 if ( !sr ) {
3012 *code = LDAP_SCHERR_OUTOFMEM;
3013 return NULL;
3016 kind = get_token(&ss,&sval);
3017 if ( kind != TK_LEFTPAREN ) {
3018 *code = LDAP_SCHERR_NOLEFTPAREN;
3019 LDAP_FREE(sval);
3020 ldap_structurerule_free(sr);
3021 return NULL;
3025 * Definitions MUST begin with a ruleid.
3027 parse_whsp(&ss);
3028 savepos = ss;
3029 ret = ldap_int_parse_ruleid(&ss,code,0,&sr->sr_ruleid);
3030 if ( ret ) {
3031 *errp = ss;
3032 ldap_structurerule_free(sr);
3033 return NULL;
3035 parse_whsp(&ss);
3038 * Beyond this point we will be liberal an accept the items
3039 * in any order.
3041 while (1) {
3042 kind = get_token(&ss,&sval);
3043 switch (kind) {
3044 case TK_EOS:
3045 *code = LDAP_SCHERR_NORIGHTPAREN;
3046 *errp = EndOfInput;
3047 ldap_structurerule_free(sr);
3048 return NULL;
3049 case TK_RIGHTPAREN:
3050 if( !seen_nameform ) {
3051 *code = LDAP_SCHERR_MISSING;
3052 ldap_structurerule_free(sr);
3053 return NULL;
3055 return sr;
3056 case TK_BAREWORD:
3057 if ( !strcasecmp(sval,"NAME") ) {
3058 LDAP_FREE(sval);
3059 if ( seen_name ) {
3060 *code = LDAP_SCHERR_DUPOPT;
3061 *errp = ss;
3062 ldap_structurerule_free(sr);
3063 return(NULL);
3065 seen_name = 1;
3066 sr->sr_names = parse_qdescrs(&ss,code);
3067 if ( !sr->sr_names ) {
3068 if ( *code != LDAP_SCHERR_OUTOFMEM )
3069 *code = LDAP_SCHERR_BADNAME;
3070 *errp = ss;
3071 ldap_structurerule_free(sr);
3072 return NULL;
3074 } else if ( !strcasecmp(sval,"DESC") ) {
3075 LDAP_FREE(sval);
3076 if ( seen_desc ) {
3077 *code = LDAP_SCHERR_DUPOPT;
3078 *errp = ss;
3079 ldap_structurerule_free(sr);
3080 return(NULL);
3082 seen_desc = 1;
3083 parse_whsp(&ss);
3084 kind = get_token(&ss,&sval);
3085 if ( kind != TK_QDSTRING ) {
3086 *code = LDAP_SCHERR_UNEXPTOKEN;
3087 *errp = ss;
3088 LDAP_FREE(sval);
3089 ldap_structurerule_free(sr);
3090 return NULL;
3092 sr->sr_desc = sval;
3093 parse_whsp(&ss);
3094 } else if ( !strcasecmp(sval,"OBSOLETE") ) {
3095 LDAP_FREE(sval);
3096 if ( seen_obsolete ) {
3097 *code = LDAP_SCHERR_DUPOPT;
3098 *errp = ss;
3099 ldap_structurerule_free(sr);
3100 return(NULL);
3102 seen_obsolete = 1;
3103 sr->sr_obsolete = LDAP_SCHEMA_YES;
3104 parse_whsp(&ss);
3105 } else if ( !strcasecmp(sval,"FORM") ) {
3106 LDAP_FREE(sval);
3107 if ( seen_nameform ) {
3108 *code = LDAP_SCHERR_DUPOPT;
3109 *errp = ss;
3110 ldap_structurerule_free(sr);
3111 return(NULL);
3113 seen_nameform = 1;
3114 sr->sr_nameform = parse_woid(&ss,code);
3115 if ( !sr->sr_nameform ) {
3116 *errp = ss;
3117 ldap_structurerule_free(sr);
3118 return NULL;
3120 parse_whsp(&ss);
3121 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
3122 /* Should be parse_qdstrings */
3123 ext_vals = parse_qdescrs(&ss, code);
3124 if ( !ext_vals ) {
3125 *errp = ss;
3126 ldap_structurerule_free(sr);
3127 return NULL;
3129 if ( add_extension(&sr->sr_extensions,
3130 sval, ext_vals) ) {
3131 *code = LDAP_SCHERR_OUTOFMEM;
3132 *errp = ss;
3133 LDAP_FREE(sval);
3134 ldap_structurerule_free(sr);
3135 return NULL;
3137 } else {
3138 *code = LDAP_SCHERR_UNEXPTOKEN;
3139 *errp = ss;
3140 LDAP_FREE(sval);
3141 ldap_structurerule_free(sr);
3142 return NULL;
3144 break;
3145 default:
3146 *code = LDAP_SCHERR_UNEXPTOKEN;
3147 *errp = ss;
3148 LDAP_FREE(sval);
3149 ldap_structurerule_free(sr);
3150 return NULL;
3155 void
3156 ldap_nameform_free(LDAPNameForm * nf)
3158 if (!nf) return;
3159 LDAP_FREE(nf->nf_oid);
3160 if (nf->nf_names) LDAP_VFREE(nf->nf_names);
3161 if (nf->nf_desc) LDAP_FREE(nf->nf_desc);
3162 if (nf->nf_objectclass) LDAP_FREE(nf->nf_objectclass);
3163 if (nf->nf_at_oids_must) LDAP_VFREE(nf->nf_at_oids_must);
3164 if (nf->nf_at_oids_may) LDAP_VFREE(nf->nf_at_oids_may);
3165 free_extensions(nf->nf_extensions);
3166 LDAP_FREE(nf);
3169 LDAPNameForm *
3170 ldap_str2nameform( LDAP_CONST char * s,
3171 int * code,
3172 LDAP_CONST char ** errp,
3173 LDAP_CONST unsigned flags )
3175 tk_t kind;
3176 const char * ss = s;
3177 char * sval;
3178 int seen_name = 0;
3179 int seen_desc = 0;
3180 int seen_obsolete = 0;
3181 int seen_class = 0;
3182 int seen_must = 0;
3183 int seen_may = 0;
3184 LDAPNameForm * nf;
3185 char ** ext_vals;
3186 const char * savepos;
3188 if ( !s ) {
3189 *code = LDAP_SCHERR_EMPTY;
3190 *errp = "";
3191 return NULL;
3194 *errp = s;
3195 nf = LDAP_CALLOC(1,sizeof(LDAPNameForm));
3197 if ( !nf ) {
3198 *code = LDAP_SCHERR_OUTOFMEM;
3199 return NULL;
3202 kind = get_token(&ss,&sval);
3203 if ( kind != TK_LEFTPAREN ) {
3204 *code = LDAP_SCHERR_NOLEFTPAREN;
3205 LDAP_FREE(sval);
3206 ldap_nameform_free(nf);
3207 return NULL;
3211 * Definitions MUST begin with an OID in the numericoid format.
3212 * However, this routine is used by clients to parse the response
3213 * from servers and very well known servers will provide an OID
3214 * in the wrong format or even no OID at all. We do our best to
3215 * extract info from those servers.
3217 parse_whsp(&ss);
3218 savepos = ss;
3219 nf->nf_oid = ldap_int_parse_numericoid(&ss,code,0);
3220 if ( !nf->nf_oid ) {
3221 *errp = ss;
3222 ldap_nameform_free(nf);
3223 return NULL;
3225 parse_whsp(&ss);
3228 * Beyond this point we will be liberal an accept the items
3229 * in any order.
3231 while (1) {
3232 kind = get_token(&ss,&sval);
3233 switch (kind) {
3234 case TK_EOS:
3235 *code = LDAP_SCHERR_NORIGHTPAREN;
3236 *errp = EndOfInput;
3237 ldap_nameform_free(nf);
3238 return NULL;
3239 case TK_RIGHTPAREN:
3240 if( !seen_class || !seen_must ) {
3241 *code = LDAP_SCHERR_MISSING;
3242 ldap_nameform_free(nf);
3243 return NULL;
3245 return nf;
3246 case TK_BAREWORD:
3247 if ( !strcasecmp(sval,"NAME") ) {
3248 LDAP_FREE(sval);
3249 if ( seen_name ) {
3250 *code = LDAP_SCHERR_DUPOPT;
3251 *errp = ss;
3252 ldap_nameform_free(nf);
3253 return(NULL);
3255 seen_name = 1;
3256 nf->nf_names = parse_qdescrs(&ss,code);
3257 if ( !nf->nf_names ) {
3258 if ( *code != LDAP_SCHERR_OUTOFMEM )
3259 *code = LDAP_SCHERR_BADNAME;
3260 *errp = ss;
3261 ldap_nameform_free(nf);
3262 return NULL;
3264 } else if ( !strcasecmp(sval,"DESC") ) {
3265 LDAP_FREE(sval);
3266 if ( seen_desc ) {
3267 *code = LDAP_SCHERR_DUPOPT;
3268 *errp = ss;
3269 ldap_nameform_free(nf);
3270 return(NULL);
3272 seen_desc = 1;
3273 parse_whsp(&ss);
3274 kind = get_token(&ss,&sval);
3275 if ( kind != TK_QDSTRING ) {
3276 *code = LDAP_SCHERR_UNEXPTOKEN;
3277 *errp = ss;
3278 LDAP_FREE(sval);
3279 ldap_nameform_free(nf);
3280 return NULL;
3282 nf->nf_desc = sval;
3283 parse_whsp(&ss);
3284 } else if ( !strcasecmp(sval,"OBSOLETE") ) {
3285 LDAP_FREE(sval);
3286 if ( seen_obsolete ) {
3287 *code = LDAP_SCHERR_DUPOPT;
3288 *errp = ss;
3289 ldap_nameform_free(nf);
3290 return(NULL);
3292 seen_obsolete = 1;
3293 nf->nf_obsolete = LDAP_SCHEMA_YES;
3294 parse_whsp(&ss);
3295 } else if ( !strcasecmp(sval,"OC") ) {
3296 LDAP_FREE(sval);
3297 if ( seen_class ) {
3298 *code = LDAP_SCHERR_DUPOPT;
3299 *errp = ss;
3300 ldap_nameform_free(nf);
3301 return(NULL);
3303 seen_class = 1;
3304 nf->nf_objectclass = parse_woid(&ss,code);
3305 if ( !nf->nf_objectclass ) {
3306 *errp = ss;
3307 ldap_nameform_free(nf);
3308 return NULL;
3310 } else if ( !strcasecmp(sval,"MUST") ) {
3311 LDAP_FREE(sval);
3312 if ( seen_must ) {
3313 *code = LDAP_SCHERR_DUPOPT;
3314 *errp = ss;
3315 ldap_nameform_free(nf);
3316 return(NULL);
3318 seen_must = 1;
3319 nf->nf_at_oids_must = parse_oids(&ss,code,0);
3320 if ( !nf->nf_at_oids_must && *code != LDAP_SUCCESS ) {
3321 *errp = ss;
3322 ldap_nameform_free(nf);
3323 return NULL;
3325 parse_whsp(&ss);
3326 } else if ( !strcasecmp(sval,"MAY") ) {
3327 LDAP_FREE(sval);
3328 if ( seen_may ) {
3329 *code = LDAP_SCHERR_DUPOPT;
3330 *errp = ss;
3331 ldap_nameform_free(nf);
3332 return(NULL);
3334 seen_may = 1;
3335 nf->nf_at_oids_may = parse_oids(&ss,code,0);
3336 if ( !nf->nf_at_oids_may && *code != LDAP_SUCCESS ) {
3337 *errp = ss;
3338 ldap_nameform_free(nf);
3339 return NULL;
3341 parse_whsp(&ss);
3342 } else if ( sval[0] == 'X' && sval[1] == '-' ) {
3343 /* Should be parse_qdstrings */
3344 ext_vals = parse_qdescrs(&ss, code);
3345 if ( !ext_vals ) {
3346 *errp = ss;
3347 ldap_nameform_free(nf);
3348 return NULL;
3350 if ( add_extension(&nf->nf_extensions,
3351 sval, ext_vals) ) {
3352 *code = LDAP_SCHERR_OUTOFMEM;
3353 *errp = ss;
3354 LDAP_FREE(sval);
3355 ldap_nameform_free(nf);
3356 return NULL;
3358 } else {
3359 *code = LDAP_SCHERR_UNEXPTOKEN;
3360 *errp = ss;
3361 LDAP_FREE(sval);
3362 ldap_nameform_free(nf);
3363 return NULL;
3365 break;
3366 default:
3367 *code = LDAP_SCHERR_UNEXPTOKEN;
3368 *errp = ss;
3369 LDAP_FREE(sval);
3370 ldap_nameform_free(nf);
3371 return NULL;
3376 static char *const err2text[] = {
3377 N_("Success"),
3378 N_("Out of memory"),
3379 N_("Unexpected token"),
3380 N_("Missing opening parenthesis"),
3381 N_("Missing closing parenthesis"),
3382 N_("Expecting digit"),
3383 N_("Expecting a name"),
3384 N_("Bad description"),
3385 N_("Bad superiors"),
3386 N_("Duplicate option"),
3387 N_("Unexpected end of data"),
3388 N_("Missing required field"),
3389 N_("Out of order field")
3392 char *
3393 ldap_scherr2str(int code)
3395 if ( code < 0 || code >= (int)(sizeof(err2text)/sizeof(char *)) ) {
3396 return _("Unknown error");
3397 } else {
3398 return _(err2text[code]);