1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3 *
4 * Copyright 1998-2021 The OpenLDAP Foundation.
5 * All rights reserved.
6 *
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.
10 *
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>.
14 */
15
16 /*
17 * schema.c: parsing routines used by servers and clients to process
18 * schema definitions
19 */
20
21 #include "portable.h"
22
23 #include <stdio.h>
24 #include <ac/stdlib.h>
25
26 #include <ac/string.h>
27 #include <ac/time.h>
28
29 #include "ldap-int.h"
30
31 #include <ldap_schema.h>
32
33 static const char EndOfInput[] = "end of input";
34
35 static const char *
choose_name(char * names[],const char * fallback)36 choose_name( char *names[], const char *fallback )
37 {
38 return (names != NULL && names[0] != NULL) ? names[0] : fallback;
39 }
40
41 LDAP_CONST char *
ldap_syntax2name(LDAPSyntax * syn)42 ldap_syntax2name( LDAPSyntax * syn )
43 {
44 if (!syn) return NULL;
45 return( syn->syn_oid );
46 }
47
48 LDAP_CONST char *
ldap_matchingrule2name(LDAPMatchingRule * mr)49 ldap_matchingrule2name( LDAPMatchingRule * mr )
50 {
51 if (!mr) return NULL;
52 return( choose_name( mr->mr_names, mr->mr_oid ) );
53 }
54
55 LDAP_CONST char *
ldap_matchingruleuse2name(LDAPMatchingRuleUse * mru)56 ldap_matchingruleuse2name( LDAPMatchingRuleUse * mru )
57 {
58 if (!mru) return NULL;
59 return( choose_name( mru->mru_names, mru->mru_oid ) );
60 }
61
62 LDAP_CONST char *
ldap_attributetype2name(LDAPAttributeType * at)63 ldap_attributetype2name( LDAPAttributeType * at )
64 {
65 if (!at) return NULL;
66 return( choose_name( at->at_names, at->at_oid ) );
67 }
68
69 LDAP_CONST char *
ldap_objectclass2name(LDAPObjectClass * oc)70 ldap_objectclass2name( LDAPObjectClass * oc )
71 {
72 if (!oc) return NULL;
73 return( choose_name( oc->oc_names, oc->oc_oid ) );
74 }
75
76 LDAP_CONST char *
ldap_contentrule2name(LDAPContentRule * cr)77 ldap_contentrule2name( LDAPContentRule * cr )
78 {
79 if (!cr) return NULL;
80 return( choose_name( cr->cr_names, cr->cr_oid ) );
81 }
82
83 LDAP_CONST char *
ldap_nameform2name(LDAPNameForm * nf)84 ldap_nameform2name( LDAPNameForm * nf )
85 {
86 if (!nf) return NULL;
87 return( choose_name( nf->nf_names, nf->nf_oid ) );
88 }
89
90 LDAP_CONST char *
ldap_structurerule2name(LDAPStructureRule * sr)91 ldap_structurerule2name( LDAPStructureRule * sr )
92 {
93 if (!sr) return NULL;
94 return( choose_name( sr->sr_names, NULL ) );
95 }
96
97 /*
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.
103 */
104
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;
111
112 static safe_string *
new_safe_string(int size)113 new_safe_string(int size)
114 {
115 safe_string * ss;
116
117 ss = LDAP_MALLOC(sizeof(safe_string));
118 if ( !ss )
119 return(NULL);
120
121 ss->val = LDAP_MALLOC(size);
122 if ( !ss->val ) {
123 LDAP_FREE(ss);
124 return(NULL);
125 }
126
127 ss->size = size;
128 ss->pos = 0;
129 ss->at_whsp = 0;
130
131 return ss;
132 }
133
134 static void
safe_string_free(safe_string * ss)135 safe_string_free(safe_string * ss)
136 {
137 if ( !ss )
138 return;
139 LDAP_FREE(ss->val);
140 LDAP_FREE(ss);
141 }
142
143 #if 0 /* unused */
144 static char *
145 safe_string_val(safe_string * ss)
146 {
147 ss->val[ss->pos] = '\0';
148 return(ss->val);
149 }
150 #endif
151
152 static char *
safe_strdup(safe_string * ss)153 safe_strdup(safe_string * ss)
154 {
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;
161 }
162
163 static int
append_to_safe_string(safe_string * ss,char * s)164 append_to_safe_string(safe_string * ss, char * s)
165 {
166 int l = strlen(s);
167 char * temp;
168
169 /*
170 * Some runaway process is trying to append to a string that
171 * overflowed and we could not extend.
172 */
173 if ( !ss->val )
174 return -1;
175
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;
181 }
182
183 temp = LDAP_REALLOC(ss->val, ss->size);
184 if ( !temp ) {
185 /* Trouble, out of memory */
186 LDAP_FREE(ss->val);
187 return -1;
188 }
189 ss->val = temp;
190 }
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;
197
198 return 0;
199 }
200
201 static int
print_literal(safe_string * ss,char * s)202 print_literal(safe_string *ss, char *s)
203 {
204 return(append_to_safe_string(ss,s));
205 }
206
207 static int
print_whsp(safe_string * ss)208 print_whsp(safe_string *ss)
209 {
210 if ( ss->at_whsp )
211 return(append_to_safe_string(ss,""));
212 else
213 return(append_to_safe_string(ss," "));
214 }
215
216 static int
print_numericoid(safe_string * ss,char * s)217 print_numericoid(safe_string *ss, char *s)
218 {
219 if ( s )
220 return(append_to_safe_string(ss,s));
221 else
222 return(append_to_safe_string(ss,""));
223 }
224
225 /* This one is identical to print_qdescr */
226 static int
print_qdstring(safe_string * ss,char * s)227 print_qdstring(safe_string *ss, char *s)
228 {
229 print_whsp(ss);
230 print_literal(ss,"'");
231 append_to_safe_string(ss,s);
232 print_literal(ss,"'");
233 return(print_whsp(ss));
234 }
235
236 static int
print_qdescr(safe_string * ss,char * s)237 print_qdescr(safe_string *ss, char *s)
238 {
239 print_whsp(ss);
240 print_literal(ss,"'");
241 append_to_safe_string(ss,s);
242 print_literal(ss,"'");
243 return(print_whsp(ss));
244 }
245
246 static int
print_qdescrlist(safe_string * ss,char ** sa)247 print_qdescrlist(safe_string *ss, char **sa)
248 {
249 char **sp;
250 int ret = 0;
251
252 for (sp=sa; *sp; sp++) {
253 ret = print_qdescr(ss,*sp);
254 }
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.
258 */
259 return(ret);
260 }
261
262 static int
print_qdescrs(safe_string * ss,char ** sa)263 print_qdescrs(safe_string *ss, char **sa)
264 {
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.
270 */
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));
279 }
280 }
281
282 static int
print_woid(safe_string * ss,char * s)283 print_woid(safe_string *ss, char *s)
284 {
285 print_whsp(ss);
286 append_to_safe_string(ss,s);
287 return print_whsp(ss);
288 }
289
290 static int
print_oidlist(safe_string * ss,char ** sa)291 print_oidlist(safe_string *ss, char **sa)
292 {
293 char **sp;
294
295 for (sp=sa; *(sp+1); sp++) {
296 print_woid(ss,*sp);
297 print_literal(ss,"$");
298 }
299 return(print_woid(ss,*sp));
300 }
301
302 static int
print_oids(safe_string * ss,char ** sa)303 print_oids(safe_string *ss, char **sa)
304 {
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));
312 }
313 }
314
315 static int
print_noidlen(safe_string * ss,char * s,int l)316 print_noidlen(safe_string *ss, char *s, int l)
317 {
318 char buf[64];
319 int ret;
320
321 ret = print_numericoid(ss,s);
322 if ( l ) {
323 snprintf(buf, sizeof buf, "{%d}",l);
324 ret = print_literal(ss,buf);
325 }
326 return(ret);
327 }
328
329 static int
print_ruleid(safe_string * ss,int rid)330 print_ruleid(safe_string *ss, int rid)
331 {
332 char buf[64];
333 snprintf(buf, sizeof buf, "%d", rid);
334 return print_literal(ss,buf);
335 }
336
337 static int
print_ruleids(safe_string * ss,int n,int * rids)338 print_ruleids(safe_string *ss, int n, int *rids)
339 {
340 int i;
341
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]);
350 }
351 print_whsp(ss);
352 return print_literal(ss,/*(*/")");
353 }
354 }
355
356
357 static int
print_extensions(safe_string * ss,LDAPSchemaExtensionItem ** extensions)358 print_extensions(safe_string *ss, LDAPSchemaExtensionItem **extensions)
359 {
360 LDAPSchemaExtensionItem **ext;
361
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);
370 }
371 }
372
373 return 0;
374 }
375
376 char *
ldap_syntax2str(LDAPSyntax * syn)377 ldap_syntax2str( LDAPSyntax * syn )
378 {
379 struct berval bv;
380 if (ldap_syntax2bv( syn, &bv ))
381 return(bv.bv_val);
382 else
383 return NULL;
384 }
385
386 struct berval *
ldap_syntax2bv(LDAPSyntax * syn,struct berval * bv)387 ldap_syntax2bv( LDAPSyntax * syn, struct berval *bv )
388 {
389 safe_string * ss;
390
391 if ( !syn || !bv )
392 return NULL;
393
394 ss = new_safe_string(256);
395 if ( !ss )
396 return NULL;
397
398 print_literal(ss,"("/*)*/);
399 print_whsp(ss);
400
401 print_numericoid(ss, syn->syn_oid);
402 print_whsp(ss);
403
404 if ( syn->syn_desc ) {
405 print_literal(ss,"DESC");
406 print_qdstring(ss,syn->syn_desc);
407 }
408
409 print_whsp(ss);
410
411 print_extensions(ss, syn->syn_extensions);
412
413 print_literal(ss,/*(*/ ")");
414
415 bv->bv_val = safe_strdup(ss);
416 bv->bv_len = ss->pos;
417 safe_string_free(ss);
418 return(bv);
419 }
420
421 char *
ldap_matchingrule2str(LDAPMatchingRule * mr)422 ldap_matchingrule2str( LDAPMatchingRule * mr )
423 {
424 struct berval bv;
425 if (ldap_matchingrule2bv( mr, &bv ))
426 return(bv.bv_val);
427 else
428 return NULL;
429 }
430
431 struct berval *
ldap_matchingrule2bv(LDAPMatchingRule * mr,struct berval * bv)432 ldap_matchingrule2bv( LDAPMatchingRule * mr, struct berval *bv )
433 {
434 safe_string * ss;
435
436 if ( !mr || !bv )
437 return NULL;
438
439 ss = new_safe_string(256);
440 if ( !ss )
441 return NULL;
442
443 print_literal(ss,"(" /*)*/);
444 print_whsp(ss);
445
446 print_numericoid(ss, mr->mr_oid);
447 print_whsp(ss);
448
449 if ( mr->mr_names ) {
450 print_literal(ss,"NAME");
451 print_qdescrs(ss,mr->mr_names);
452 }
453
454 if ( mr->mr_desc ) {
455 print_literal(ss,"DESC");
456 print_qdstring(ss,mr->mr_desc);
457 }
458
459 if ( mr->mr_obsolete ) {
460 print_literal(ss, "OBSOLETE");
461 print_whsp(ss);
462 }
463
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);
469 }
470
471 print_whsp(ss);
472
473 print_extensions(ss, mr->mr_extensions);
474
475 print_literal(ss,/*(*/")");
476
477 bv->bv_val = safe_strdup(ss);
478 bv->bv_len = ss->pos;
479 safe_string_free(ss);
480 return(bv);
481 }
482
483 char *
ldap_matchingruleuse2str(LDAPMatchingRuleUse * mru)484 ldap_matchingruleuse2str( LDAPMatchingRuleUse * mru )
485 {
486 struct berval bv;
487 if (ldap_matchingruleuse2bv( mru, &bv ))
488 return(bv.bv_val);
489 else
490 return NULL;
491 }
492
493 struct berval *
ldap_matchingruleuse2bv(LDAPMatchingRuleUse * mru,struct berval * bv)494 ldap_matchingruleuse2bv( LDAPMatchingRuleUse * mru, struct berval *bv )
495 {
496 safe_string * ss;
497
498 if ( !mru || !bv )
499 return NULL;
500
501 ss = new_safe_string(256);
502 if ( !ss )
503 return NULL;
504
505 print_literal(ss,"(" /*)*/);
506 print_whsp(ss);
507
508 print_numericoid(ss, mru->mru_oid);
509 print_whsp(ss);
510
511 if ( mru->mru_names ) {
512 print_literal(ss,"NAME");
513 print_qdescrs(ss,mru->mru_names);
514 }
515
516 if ( mru->mru_desc ) {
517 print_literal(ss,"DESC");
518 print_qdstring(ss,mru->mru_desc);
519 }
520
521 if ( mru->mru_obsolete ) {
522 print_literal(ss, "OBSOLETE");
523 print_whsp(ss);
524 }
525
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);
531 }
532
533 print_whsp(ss);
534
535 print_extensions(ss, mru->mru_extensions);
536
537 print_literal(ss,/*(*/")");
538
539 bv->bv_val = safe_strdup(ss);
540 bv->bv_len = ss->pos;
541 safe_string_free(ss);
542 return(bv);
543 }
544
545 char *
ldap_objectclass2str(LDAPObjectClass * oc)546 ldap_objectclass2str( LDAPObjectClass * oc )
547 {
548 struct berval bv;
549 if (ldap_objectclass2bv( oc, &bv ))
550 return(bv.bv_val);
551 else
552 return NULL;
553 }
554
555 struct berval *
ldap_objectclass2bv(LDAPObjectClass * oc,struct berval * bv)556 ldap_objectclass2bv( LDAPObjectClass * oc, struct berval *bv )
557 {
558 safe_string * ss;
559
560 if ( !oc || !bv )
561 return NULL;
562
563 ss = new_safe_string(256);
564 if ( !ss )
565 return NULL;
566
567 print_literal(ss,"("/*)*/);
568 print_whsp(ss);
569
570 print_numericoid(ss, oc->oc_oid);
571 print_whsp(ss);
572
573 if ( oc->oc_names ) {
574 print_literal(ss,"NAME");
575 print_qdescrs(ss,oc->oc_names);
576 }
577
578 if ( oc->oc_desc ) {
579 print_literal(ss,"DESC");
580 print_qdstring(ss,oc->oc_desc);
581 }
582
583 if ( oc->oc_obsolete ) {
584 print_literal(ss, "OBSOLETE");
585 print_whsp(ss);
586 }
587
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);
593 }
594
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;
608 }
609 print_whsp(ss);
610
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);
616 }
617
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);
623 }
624
625 print_whsp(ss);
626
627 print_extensions(ss, oc->oc_extensions);
628
629 print_literal(ss, /*(*/")");
630
631 bv->bv_val = safe_strdup(ss);
632 bv->bv_len = ss->pos;
633 safe_string_free(ss);
634 return(bv);
635 }
636
637 char *
ldap_contentrule2str(LDAPContentRule * cr)638 ldap_contentrule2str( LDAPContentRule * cr )
639 {
640 struct berval bv;
641 if (ldap_contentrule2bv( cr, &bv ))
642 return(bv.bv_val);
643 else
644 return NULL;
645 }
646
647 struct berval *
ldap_contentrule2bv(LDAPContentRule * cr,struct berval * bv)648 ldap_contentrule2bv( LDAPContentRule * cr, struct berval *bv )
649 {
650 safe_string * ss;
651
652 if ( !cr || !bv )
653 return NULL;
654
655 ss = new_safe_string(256);
656 if ( !ss )
657 return NULL;
658
659 print_literal(ss,"("/*)*/);
660 print_whsp(ss);
661
662 print_numericoid(ss, cr->cr_oid);
663 print_whsp(ss);
664
665 if ( cr->cr_names ) {
666 print_literal(ss,"NAME");
667 print_qdescrs(ss,cr->cr_names);
668 }
669
670 if ( cr->cr_desc ) {
671 print_literal(ss,"DESC");
672 print_qdstring(ss,cr->cr_desc);
673 }
674
675 if ( cr->cr_obsolete ) {
676 print_literal(ss, "OBSOLETE");
677 print_whsp(ss);
678 }
679
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);
685 }
686
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);
692 }
693
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);
699 }
700
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);
706 }
707
708 print_whsp(ss);
709 print_extensions(ss, cr->cr_extensions);
710
711 print_literal(ss, /*(*/")");
712
713 bv->bv_val = safe_strdup(ss);
714 bv->bv_len = ss->pos;
715 safe_string_free(ss);
716 return(bv);
717 }
718
719 char *
ldap_structurerule2str(LDAPStructureRule * sr)720 ldap_structurerule2str( LDAPStructureRule * sr )
721 {
722 struct berval bv;
723 if (ldap_structurerule2bv( sr, &bv ))
724 return(bv.bv_val);
725 else
726 return NULL;
727 }
728
729 struct berval *
ldap_structurerule2bv(LDAPStructureRule * sr,struct berval * bv)730 ldap_structurerule2bv( LDAPStructureRule * sr, struct berval *bv )
731 {
732 safe_string * ss;
733
734 if ( !sr || !bv )
735 return NULL;
736
737 ss = new_safe_string(256);
738 if ( !ss )
739 return NULL;
740
741 print_literal(ss,"("/*)*/);
742 print_whsp(ss);
743
744 print_ruleid(ss, sr->sr_ruleid);
745 print_whsp(ss);
746
747 if ( sr->sr_names ) {
748 print_literal(ss,"NAME");
749 print_qdescrs(ss,sr->sr_names);
750 }
751
752 if ( sr->sr_desc ) {
753 print_literal(ss,"DESC");
754 print_qdstring(ss,sr->sr_desc);
755 }
756
757 if ( sr->sr_obsolete ) {
758 print_literal(ss, "OBSOLETE");
759 print_whsp(ss);
760 }
761
762 print_literal(ss,"FORM");
763 print_whsp(ss);
764 print_woid(ss,sr->sr_nameform);
765 print_whsp(ss);
766
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);
772 }
773
774 print_whsp(ss);
775 print_extensions(ss, sr->sr_extensions);
776
777 print_literal(ss, /*(*/")");
778
779 bv->bv_val = safe_strdup(ss);
780 bv->bv_len = ss->pos;
781 safe_string_free(ss);
782 return(bv);
783 }
784
785
786 char *
ldap_nameform2str(LDAPNameForm * nf)787 ldap_nameform2str( LDAPNameForm * nf )
788 {
789 struct berval bv;
790 if (ldap_nameform2bv( nf, &bv ))
791 return(bv.bv_val);
792 else
793 return NULL;
794 }
795
796 struct berval *
ldap_nameform2bv(LDAPNameForm * nf,struct berval * bv)797 ldap_nameform2bv( LDAPNameForm * nf, struct berval *bv )
798 {
799 safe_string * ss;
800
801 if ( !nf || !bv )
802 return NULL;
803
804 ss = new_safe_string(256);
805 if ( !ss )
806 return NULL;
807
808 print_literal(ss,"("/*)*/);
809 print_whsp(ss);
810
811 print_numericoid(ss, nf->nf_oid);
812 print_whsp(ss);
813
814 if ( nf->nf_names ) {
815 print_literal(ss,"NAME");
816 print_qdescrs(ss,nf->nf_names);
817 }
818
819 if ( nf->nf_desc ) {
820 print_literal(ss,"DESC");
821 print_qdstring(ss,nf->nf_desc);
822 }
823
824 if ( nf->nf_obsolete ) {
825 print_literal(ss, "OBSOLETE");
826 print_whsp(ss);
827 }
828
829 print_literal(ss,"OC");
830 print_whsp(ss);
831 print_woid(ss,nf->nf_objectclass);
832 print_whsp(ss);
833
834 print_literal(ss,"MUST");
835 print_whsp(ss);
836 print_oids(ss,nf->nf_at_oids_must);
837 print_whsp(ss);
838
839
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);
845 }
846
847 print_whsp(ss);
848 print_extensions(ss, nf->nf_extensions);
849
850 print_literal(ss, /*(*/")");
851
852 bv->bv_val = safe_strdup(ss);
853 bv->bv_len = ss->pos;
854 safe_string_free(ss);
855 return(bv);
856 }
857
858 char *
ldap_attributetype2str(LDAPAttributeType * at)859 ldap_attributetype2str( LDAPAttributeType * at )
860 {
861 struct berval bv;
862 if (ldap_attributetype2bv( at, &bv ))
863 return(bv.bv_val);
864 else
865 return NULL;
866 }
867
868 struct berval *
ldap_attributetype2bv(LDAPAttributeType * at,struct berval * bv)869 ldap_attributetype2bv( LDAPAttributeType * at, struct berval *bv )
870 {
871 safe_string * ss;
872
873 if ( !at || !bv )
874 return NULL;
875
876 ss = new_safe_string(256);
877 if ( !ss )
878 return NULL;
879
880 print_literal(ss,"("/*)*/);
881 print_whsp(ss);
882
883 print_numericoid(ss, at->at_oid);
884 print_whsp(ss);
885
886 if ( at->at_names ) {
887 print_literal(ss,"NAME");
888 print_qdescrs(ss,at->at_names);
889 }
890
891 if ( at->at_desc ) {
892 print_literal(ss,"DESC");
893 print_qdstring(ss,at->at_desc);
894 }
895
896 if ( at->at_obsolete ) {
897 print_literal(ss, "OBSOLETE");
898 print_whsp(ss);
899 }
900
901 if ( at->at_sup_oid ) {
902 print_literal(ss,"SUP");
903 print_woid(ss,at->at_sup_oid);
904 }
905
906 if ( at->at_equality_oid ) {
907 print_literal(ss,"EQUALITY");
908 print_woid(ss,at->at_equality_oid);
909 }
910
911 if ( at->at_ordering_oid ) {
912 print_literal(ss,"ORDERING");
913 print_woid(ss,at->at_ordering_oid);
914 }
915
916 if ( at->at_substr_oid ) {
917 print_literal(ss,"SUBSTR");
918 print_woid(ss,at->at_substr_oid);
919 }
920
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);
926 }
927
928 if ( at->at_single_value == LDAP_SCHEMA_YES ) {
929 print_literal(ss,"SINGLE-VALUE");
930 print_whsp(ss);
931 }
932
933 if ( at->at_collective == LDAP_SCHEMA_YES ) {
934 print_literal(ss,"COLLECTIVE");
935 print_whsp(ss);
936 }
937
938 if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
939 print_literal(ss,"NO-USER-MODIFICATION");
940 print_whsp(ss);
941 }
942
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;
959 }
960 }
961
962 print_whsp(ss);
963
964 print_extensions(ss, at->at_extensions);
965
966 print_literal(ss,/*(*/")");
967
968 bv->bv_val = safe_strdup(ss);
969 bv->bv_len = ss->pos;
970 safe_string_free(ss);
971 return(bv);
972 }
973
974 /*
975 * Now come the parsers. There is one parser for each entity type:
976 * objectclasses, attributetypes, etc.
977 *
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.
982 *
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.
991 *
992 * The difference is pretty academic (modulo bugs or incorrect
993 * interpretation of the specs).
994 */
995
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;
1008
1009 static tk_t
get_token(const char ** sp,char ** token_val)1010 get_token( const char ** sp, char ** token_val )
1011 {
1012 tk_t kind;
1013 const char * p;
1014 const char * q;
1015 char * res;
1016
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;
1050 }
1051 (*sp)++;
1052 } else {
1053 kind = TK_NOENDQUOTE;
1054 }
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;
1077 }
1078 break;
1079 /* kind = TK_UNEXPCHAR; */
1080 /* break; */
1081 }
1082
1083 return kind;
1084 }
1085
1086 /* Gobble optional whitespace */
1087 static void
parse_whsp(const char ** sp)1088 parse_whsp(const char **sp)
1089 {
1090 while (LDAP_SPACE(**sp))
1091 (*sp)++;
1092 }
1093
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.
1100 */
1101
1102 /* Parse a sequence of dot-separated decimal strings */
1103 char *
ldap_int_parse_numericoid(const char ** sp,int * code,const int flags)1104 ldap_int_parse_numericoid(const char **sp, int *code, const int flags)
1105 {
1106 char * res = NULL;
1107 const char * start = *sp;
1108 int len;
1109 int quoted = 0;
1110
1111 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
1112 if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && **sp == '\'' ) {
1113 quoted = 1;
1114 (*sp)++;
1115 start++;
1116 }
1117 /* Each iteration of this loop gets one decimal string */
1118 while (**sp) {
1119 if ( !LDAP_DIGIT(**sp) ) {
1120 /*
1121 * Initial char is not a digit or char after dot is
1122 * not a digit
1123 */
1124 *code = LDAP_SCHERR_NODIGIT;
1125 return NULL;
1126 }
1127 (*sp)++;
1128 while ( LDAP_DIGIT(**sp) )
1129 (*sp)++;
1130 if ( **sp != '.' )
1131 break;
1132 /* Otherwise, gobble the dot and loop again */
1133 (*sp)++;
1134 }
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;
1143 }
1144 }
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);
1152 }
1153 strncpy(res,start,len);
1154 res[len] = '\0';
1155 }
1156 return(res);
1157 }
1158
1159 /* Parse a sequence of dot-separated decimal strings */
1160 int
ldap_int_parse_ruleid(const char ** sp,int * code,const int flags,int * ruleid)1161 ldap_int_parse_ruleid(const char **sp, int *code, const int flags, int *ruleid)
1162 {
1163 *ruleid=0;
1164
1165 if ( !LDAP_DIGIT(**sp) ) {
1166 *code = LDAP_SCHERR_NODIGIT;
1167 return -1;
1168 }
1169 *ruleid = (**sp) - '0';
1170 (*sp)++;
1171
1172 while ( LDAP_DIGIT(**sp) ) {
1173 *ruleid *= 10;
1174 *ruleid += (**sp) - '0';
1175 (*sp)++;
1176 }
1177
1178 return 0;
1179 }
1180
1181 /* Parse a qdescr or a list of them enclosed in () */
1182 static char **
parse_qdescrs(const char ** sp,int * code)1183 parse_qdescrs(const char **sp, int *code)
1184 {
1185 char ** res;
1186 char ** res1;
1187 tk_t kind;
1188 char * sval;
1189 int size;
1190 int pos;
1191
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;
1201 }
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);
1217 }
1218 res = res1;
1219 }
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);
1228 }
1229 }
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;
1237 }
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;
1246 }
1247 }
1248
1249 /* Parse a woid */
1250 static char *
parse_woid(const char ** sp,int * code)1251 parse_woid(const char **sp, int *code)
1252 {
1253 char * sval;
1254 tk_t kind;
1255
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;
1262 }
1263 parse_whsp(sp);
1264 return sval;
1265 }
1266
1267 /* Parse a noidlen */
1268 static char *
parse_noidlen(const char ** sp,int * code,int * len,int flags)1269 parse_noidlen(const char **sp, int *code, int *len, int flags)
1270 {
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 );
1276
1277 *len = 0;
1278 /* Netscape puts the SYNTAX value in quotes (incorrectly) */
1279 if ( allow_quoted && **sp == '\'' ) {
1280 quoted = 1;
1281 (*sp)++;
1282 }
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 )
1289 {
1290 if ( get_token(sp, &sval) != TK_BAREWORD ) {
1291 if ( sval != NULL ) {
1292 LDAP_FREE(sval);
1293 }
1294 return NULL;
1295 }
1296 } else {
1297 return NULL;
1298 }
1299 }
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;
1309 }
1310 (*sp)++;
1311 }
1312 if ( allow_quoted && quoted ) {
1313 if ( **sp == '\'' ) {
1314 (*sp)++;
1315 } else {
1316 *code = LDAP_SCHERR_UNEXPTOKEN;
1317 LDAP_FREE(sval);
1318 return NULL;
1319 }
1320 }
1321 return sval;
1322 }
1323
1324 /*
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.
1329 */
1330
1331 /* Parse a woid or a $-separated list of them enclosed in () */
1332 static char **
parse_oids(const char ** sp,int * code,const int allow_quoted)1333 parse_oids(const char **sp, int *code, const int allow_quoted)
1334 {
1335 char ** res;
1336 char ** res1;
1337 tk_t kind;
1338 char * sval;
1339 int size;
1340 int pos;
1341
1342 /*
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.
1347 */
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;
1357 }
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;
1375 }
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);
1395 }
1396 res = res1;
1397 }
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;
1405 }
1406 parse_whsp(sp);
1407 } else {
1408 *code = LDAP_SCHERR_UNEXPTOKEN;
1409 LDAP_FREE(sval);
1410 LDAP_VFREE(res);
1411 return NULL;
1412 }
1413 }
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;
1423 }
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;
1432 }
1433 }
1434
1435 static int
add_extension(LDAPSchemaExtensionItem *** extensions,char * name,char ** values)1436 add_extension(LDAPSchemaExtensionItem ***extensions,
1437 char * name, char ** values)
1438 {
1439 int n;
1440 LDAPSchemaExtensionItem **tmp, *ext;
1441
1442 ext = LDAP_CALLOC(1, sizeof(LDAPSchemaExtensionItem));
1443 if ( !ext )
1444 return 1;
1445 ext->lsei_name = name;
1446 ext->lsei_values = values;
1447
1448 if ( !*extensions ) {
1449 *extensions =
1450 LDAP_CALLOC(2, sizeof(LDAPSchemaExtensionItem *));
1451 if ( !*extensions ) {
1452 LDAP_FREE( ext );
1453 return 1;
1454 }
1455 n = 0;
1456 } else {
1457 for ( n=0; (*extensions)[n] != NULL; n++ )
1458 ;
1459 tmp = LDAP_REALLOC(*extensions,
1460 (n+2)*sizeof(LDAPSchemaExtensionItem *));
1461 if ( !tmp ) {
1462 LDAP_FREE( ext );
1463 return 1;
1464 }
1465 *extensions = tmp;
1466 }
1467 (*extensions)[n] = ext;
1468 (*extensions)[n+1] = NULL;
1469 return 0;
1470 }
1471
1472 static void
free_extensions(LDAPSchemaExtensionItem ** extensions)1473 free_extensions(LDAPSchemaExtensionItem **extensions)
1474 {
1475 LDAPSchemaExtensionItem **ext;
1476
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);
1482 }
1483 LDAP_FREE(extensions);
1484 }
1485 }
1486
1487 void
ldap_syntax_free(LDAPSyntax * syn)1488 ldap_syntax_free( LDAPSyntax * syn )
1489 {
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);
1496 }
1497
1498 LDAPSyntax *
ldap_str2syntax(LDAP_CONST char * s,int * code,LDAP_CONST char ** errp,LDAP_CONST unsigned flags)1499 ldap_str2syntax( LDAP_CONST char * s,
1500 int * code,
1501 LDAP_CONST char ** errp,
1502 LDAP_CONST unsigned flags )
1503 {
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;
1511
1512 if ( !s ) {
1513 *code = LDAP_SCHERR_EMPTY;
1514 *errp = "";
1515 return NULL;
1516 }
1517
1518 *errp = s;
1519 syn = LDAP_CALLOC(1,sizeof(LDAPSyntax));
1520
1521 if ( !syn ) {
1522 *code = LDAP_SCHERR_OUTOFMEM;
1523 return NULL;
1524 }
1525
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;
1532 }
1533
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;
1540 }
1541 parse_whsp(&ss);
1542
1543 /*
1544 * Beyond this point we will be liberal and accept the items
1545 * in any order.
1546 */
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);
1565 }
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;
1574 }
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);
1582 }
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;
1592 }
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;
1602 }
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;
1610 }
1611 } else {
1612 *code = LDAP_SCHERR_UNEXPTOKEN;
1613 *errp = ss;
1614 LDAP_FREE(sval);
1615 ldap_syntax_free(syn);
1616 return NULL;
1617 }
1618 break;
1619 default:
1620 *code = LDAP_SCHERR_UNEXPTOKEN;
1621 *errp = ss;
1622 LDAP_FREE(sval);
1623 ldap_syntax_free(syn);
1624 return NULL;
1625 }
1626 }
1627 }
1628
1629 void
ldap_matchingrule_free(LDAPMatchingRule * mr)1630 ldap_matchingrule_free( LDAPMatchingRule * mr )
1631 {
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);
1639 }
1640
1641 LDAPMatchingRule *
ldap_str2matchingrule(LDAP_CONST char * s,int * code,LDAP_CONST char ** errp,LDAP_CONST unsigned flags)1642 ldap_str2matchingrule( LDAP_CONST char * s,
1643 int * code,
1644 LDAP_CONST char ** errp,
1645 LDAP_CONST unsigned flags )
1646 {
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;
1657
1658 if ( !s ) {
1659 *code = LDAP_SCHERR_EMPTY;
1660 *errp = "";
1661 return NULL;
1662 }
1663
1664 *errp = s;
1665 mr = LDAP_CALLOC(1,sizeof(LDAPMatchingRule));
1666
1667 if ( !mr ) {
1668 *code = LDAP_SCHERR_OUTOFMEM;
1669 return NULL;
1670 }
1671
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;
1678 }
1679
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 */
1698 }
1699 }
1700 LDAP_FREE(sval);
1701 } else {
1702 *errp = ss;
1703 ldap_matchingrule_free(mr);
1704 return NULL;
1705 }
1706 }
1707 parse_whsp(&ss);
1708
1709 /*
1710 * Beyond this point we will be liberal and accept the items
1711 * in any order.
1712 */
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;
1726 }
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);
1736 }
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;
1745 }
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);
1753 }
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;
1763 }
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);
1773 }
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);
1784 }
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;
1793 }
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;
1802 }
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;
1810 }
1811 } else {
1812 *code = LDAP_SCHERR_UNEXPTOKEN;
1813 *errp = ss;
1814 LDAP_FREE(sval);
1815 ldap_matchingrule_free(mr);
1816 return NULL;
1817 }
1818 break;
1819 default:
1820 *code = LDAP_SCHERR_UNEXPTOKEN;
1821 *errp = ss;
1822 LDAP_FREE(sval);
1823 ldap_matchingrule_free(mr);
1824 return NULL;
1825 }
1826 }
1827 }
1828
1829 void
ldap_matchingruleuse_free(LDAPMatchingRuleUse * mru)1830 ldap_matchingruleuse_free( LDAPMatchingRuleUse * mru )
1831 {
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);
1839 }
1840
1841 LDAPMatchingRuleUse *
ldap_str2matchingruleuse(LDAP_CONST char * s,int * code,LDAP_CONST char ** errp,LDAP_CONST unsigned flags)1842 ldap_str2matchingruleuse( LDAP_CONST char * s,
1843 int * code,
1844 LDAP_CONST char ** errp,
1845 LDAP_CONST unsigned flags )
1846 {
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;
1857
1858 if ( !s ) {
1859 *code = LDAP_SCHERR_EMPTY;
1860 *errp = "";
1861 return NULL;
1862 }
1863
1864 *errp = s;
1865 mru = LDAP_CALLOC(1,sizeof(LDAPMatchingRuleUse));
1866
1867 if ( !mru ) {
1868 *code = LDAP_SCHERR_OUTOFMEM;
1869 return NULL;
1870 }
1871
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;
1878 }
1879
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 */
1898 }
1899 }
1900 LDAP_FREE(sval);
1901 } else {
1902 *errp = ss;
1903 ldap_matchingruleuse_free(mru);
1904 return NULL;
1905 }
1906 }
1907 parse_whsp(&ss);
1908
1909 /*
1910 * Beyond this point we will be liberal and accept the items
1911 * in any order.
1912 */
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;
1926 }
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);
1936 }
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;
1945 }
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);
1953 }
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;
1963 }
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);
1973 }
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);
1984 }
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;
1993 }
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;
2001 }
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;
2009 }
2010 } else {
2011 *code = LDAP_SCHERR_UNEXPTOKEN;
2012 *errp = ss;
2013 LDAP_FREE(sval);
2014 ldap_matchingruleuse_free(mru);
2015 return NULL;
2016 }
2017 break;
2018 default:
2019 *code = LDAP_SCHERR_UNEXPTOKEN;
2020 *errp = ss;
2021 LDAP_FREE(sval);
2022 ldap_matchingruleuse_free(mru);
2023 return NULL;
2024 }
2025 }
2026 }
2027
2028 void
ldap_attributetype_free(LDAPAttributeType * at)2029 ldap_attributetype_free(LDAPAttributeType * at)
2030 {
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);
2042 }
2043
2044 LDAPAttributeType *
ldap_str2attributetype(LDAP_CONST char * s,int * code,LDAP_CONST char ** errp,LDAP_CONST unsigned flags)2045 ldap_str2attributetype( LDAP_CONST char * s,
2046 int * code,
2047 LDAP_CONST char ** errp,
2048 LDAP_CONST unsigned flags )
2049 {
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;
2065
2066 if ( !s ) {
2067 *code = LDAP_SCHERR_EMPTY;
2068 *errp = "";
2069 return NULL;
2070 }
2071
2072 *errp = s;
2073 at = LDAP_CALLOC(1,sizeof(LDAPAttributeType));
2074
2075 if ( !at ) {
2076 *code = LDAP_SCHERR_OUTOFMEM;
2077 return NULL;
2078 }
2079
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;
2086 }
2087
2088 /*
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.
2094 */
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) )
2102 {
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) )
2120 {
2121 /* Missing OID, backtrack */
2122 ss = savepos;
2123 } else if ( flags
2124 & LDAP_SCHEMA_ALLOW_OID_MACRO)
2125 {
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;
2132 }
2133
2134 strncpy(at->at_oid, savepos, len);
2135 at->at_oid[len] = 0;
2136 }
2137 }
2138 LDAP_FREE(sval);
2139 } else {
2140 *errp = ss;
2141 ldap_attributetype_free(at);
2142 return NULL;
2143 }
2144 }
2145 parse_whsp(&ss);
2146
2147 /*
2148 * Beyond this point we will be liberal and accept the items
2149 * in any order.
2150 */
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);
2169 }
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;
2178 }
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);
2186 }
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;
2196 }
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);
2206 }
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);
2217 }
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;
2224 }
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);
2232 }
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;
2239 }
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);
2247 }
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;
2254 }
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);
2262 }
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;
2269 }
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);
2277 }
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)
2290 {
2291 char *sp = strchr(sval, '{');
2292 at->at_syntax_oid = sval;
2293 if (sp)
2294 {
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;
2304 }
2305 }
2306 }
2307 } else {
2308 *errp = ss;
2309 ldap_attributetype_free(at);
2310 return NULL;
2311 }
2312 }
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);
2321 }
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);
2331 }
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);
2341 }
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);
2351 }
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;
2361 }
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;
2380 }
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;
2390 }
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;
2398 }
2399 } else {
2400 *code = LDAP_SCHERR_UNEXPTOKEN;
2401 *errp = ss;
2402 LDAP_FREE(sval);
2403 ldap_attributetype_free(at);
2404 return NULL;
2405 }
2406 break;
2407 default:
2408 *code = LDAP_SCHERR_UNEXPTOKEN;
2409 *errp = ss;
2410 LDAP_FREE(sval);
2411 ldap_attributetype_free(at);
2412 return NULL;
2413 }
2414 }
2415 }
2416
2417 void
ldap_objectclass_free(LDAPObjectClass * oc)2418 ldap_objectclass_free(LDAPObjectClass * oc)
2419 {
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);
2429 }
2430
2431 LDAPObjectClass *
ldap_str2objectclass(LDAP_CONST char * s,int * code,LDAP_CONST char ** errp,LDAP_CONST unsigned flags)2432 ldap_str2objectclass( LDAP_CONST char * s,
2433 int * code,
2434 LDAP_CONST char ** errp,
2435 LDAP_CONST unsigned flags )
2436 {
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;
2450
2451 if ( !s ) {
2452 *code = LDAP_SCHERR_EMPTY;
2453 *errp = "";
2454 return NULL;
2455 }
2456
2457 *errp = s;
2458 oc = LDAP_CALLOC(1,sizeof(LDAPObjectClass));
2459
2460 if ( !oc ) {
2461 *code = LDAP_SCHERR_OUTOFMEM;
2462 return NULL;
2463 }
2464 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
2465
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;
2472 }
2473
2474 /*
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.
2480 */
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;
2510 }
2511
2512 strncpy(oc->oc_oid, savepos, len);
2513 oc->oc_oid[len] = 0;
2514 }
2515 }
2516 LDAP_FREE(sval);
2517 *code = 0;
2518 } else {
2519 *errp = ss;
2520 ldap_objectclass_free(oc);
2521 return NULL;
2522 }
2523 }
2524 parse_whsp(&ss);
2525
2526 /*
2527 * Beyond this point we will be liberal an accept the items
2528 * in any order.
2529 */
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);
2548 }
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;
2557 }
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);
2565 }
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;
2575 }
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);
2585 }
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);
2596 }
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;
2605 }
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);
2614 }
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);
2625 }
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);
2636 }
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);
2647 }
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;
2654 }
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);
2664 }
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;
2671 }
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;
2682 }
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;
2690 }
2691 } else {
2692 *code = LDAP_SCHERR_UNEXPTOKEN;
2693 *errp = ss;
2694 LDAP_FREE(sval);
2695 ldap_objectclass_free(oc);
2696 return NULL;
2697 }
2698 break;
2699 default:
2700 *code = LDAP_SCHERR_UNEXPTOKEN;
2701 *errp = ss;
2702 LDAP_FREE(sval);
2703 ldap_objectclass_free(oc);
2704 return NULL;
2705 }
2706 }
2707 }
2708
2709 void
ldap_contentrule_free(LDAPContentRule * cr)2710 ldap_contentrule_free(LDAPContentRule * cr)
2711 {
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);
2722 }
2723
2724 LDAPContentRule *
ldap_str2contentrule(LDAP_CONST char * s,int * code,LDAP_CONST char ** errp,LDAP_CONST unsigned flags)2725 ldap_str2contentrule( LDAP_CONST char * s,
2726 int * code,
2727 LDAP_CONST char ** errp,
2728 LDAP_CONST unsigned flags )
2729 {
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;
2743
2744 if ( !s ) {
2745 *code = LDAP_SCHERR_EMPTY;
2746 *errp = "";
2747 return NULL;
2748 }
2749
2750 *errp = s;
2751 cr = LDAP_CALLOC(1,sizeof(LDAPContentRule));
2752
2753 if ( !cr ) {
2754 *code = LDAP_SCHERR_OUTOFMEM;
2755 return NULL;
2756 }
2757
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;
2764 }
2765
2766 /*
2767 * Definitions MUST begin with an OID in the numericoid format.
2768 */
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;
2796 }
2797
2798 strncpy(cr->cr_oid, savepos, len);
2799 cr->cr_oid[len] = 0;
2800 }
2801 }
2802 LDAP_FREE(sval);
2803 } else {
2804 *errp = ss;
2805 ldap_contentrule_free(cr);
2806 return NULL;
2807 }
2808 }
2809 parse_whsp(&ss);
2810
2811 /*
2812 * Beyond this point we will be liberal an accept the items
2813 * in any order.
2814 */
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);
2833 }
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;
2842 }
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);
2850 }
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;
2860 }
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);
2870 }
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);
2881 }
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;
2888 }
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);
2897 }
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;
2904 }
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);
2913 }
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;
2920 }
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);
2929 }
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;
2936 }
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;
2945 }
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;
2953 }
2954 } else {
2955 *code = LDAP_SCHERR_UNEXPTOKEN;
2956 *errp = ss;
2957 LDAP_FREE(sval);
2958 ldap_contentrule_free(cr);
2959 return NULL;
2960 }
2961 break;
2962 default:
2963 *code = LDAP_SCHERR_UNEXPTOKEN;
2964 *errp = ss;
2965 LDAP_FREE(sval);
2966 ldap_contentrule_free(cr);
2967 return NULL;
2968 }
2969 }
2970 }
2971
2972 void
ldap_structurerule_free(LDAPStructureRule * sr)2973 ldap_structurerule_free(LDAPStructureRule * sr)
2974 {
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);
2982 }
2983
2984 LDAPStructureRule *
ldap_str2structurerule(LDAP_CONST char * s,int * code,LDAP_CONST char ** errp,LDAP_CONST unsigned flags)2985 ldap_str2structurerule( LDAP_CONST char * s,
2986 int * code,
2987 LDAP_CONST char ** errp,
2988 LDAP_CONST unsigned flags )
2989 {
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;
3001
3002 if ( !s ) {
3003 *code = LDAP_SCHERR_EMPTY;
3004 *errp = "";
3005 return NULL;
3006 }
3007
3008 *errp = s;
3009 sr = LDAP_CALLOC(1,sizeof(LDAPStructureRule));
3010
3011 if ( !sr ) {
3012 *code = LDAP_SCHERR_OUTOFMEM;
3013 return NULL;
3014 }
3015
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;
3022 }
3023
3024 /*
3025 * Definitions MUST begin with a ruleid.
3026 */
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;
3034 }
3035 parse_whsp(&ss);
3036
3037 /*
3038 * Beyond this point we will be liberal an accept the items
3039 * in any order.
3040 */
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;
3054 }
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);
3064 }
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;
3073 }
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);
3081 }
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;
3091 }
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);
3101 }
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);
3112 }
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;
3119 }
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;
3128 }
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;
3136 }
3137 } else {
3138 *code = LDAP_SCHERR_UNEXPTOKEN;
3139 *errp = ss;
3140 LDAP_FREE(sval);
3141 ldap_structurerule_free(sr);
3142 return NULL;
3143 }
3144 break;
3145 default:
3146 *code = LDAP_SCHERR_UNEXPTOKEN;
3147 *errp = ss;
3148 LDAP_FREE(sval);
3149 ldap_structurerule_free(sr);
3150 return NULL;
3151 }
3152 }
3153 }
3154
3155 void
ldap_nameform_free(LDAPNameForm * nf)3156 ldap_nameform_free(LDAPNameForm * nf)
3157 {
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);
3167 }
3168
3169 LDAPNameForm *
ldap_str2nameform(LDAP_CONST char * s,int * code,LDAP_CONST char ** errp,LDAP_CONST unsigned flags)3170 ldap_str2nameform( LDAP_CONST char * s,
3171 int * code,
3172 LDAP_CONST char ** errp,
3173 LDAP_CONST unsigned flags )
3174 {
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;
3187
3188 if ( !s ) {
3189 *code = LDAP_SCHERR_EMPTY;
3190 *errp = "";
3191 return NULL;
3192 }
3193
3194 *errp = s;
3195 nf = LDAP_CALLOC(1,sizeof(LDAPNameForm));
3196
3197 if ( !nf ) {
3198 *code = LDAP_SCHERR_OUTOFMEM;
3199 return NULL;
3200 }
3201
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;
3208 }
3209
3210 /*
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.
3216 */
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;
3224 }
3225 parse_whsp(&ss);
3226
3227 /*
3228 * Beyond this point we will be liberal an accept the items
3229 * in any order.
3230 */
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;
3244 }
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);
3254 }
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;
3263 }
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);
3271 }
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;
3281 }
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);
3291 }
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);
3302 }
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;
3309 }
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);
3317 }
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;
3324 }
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);
3333 }
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;
3340 }
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;
3349 }
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;
3357 }
3358 } else {
3359 *code = LDAP_SCHERR_UNEXPTOKEN;
3360 *errp = ss;
3361 LDAP_FREE(sval);
3362 ldap_nameform_free(nf);
3363 return NULL;
3364 }
3365 break;
3366 default:
3367 *code = LDAP_SCHERR_UNEXPTOKEN;
3368 *errp = ss;
3369 LDAP_FREE(sval);
3370 ldap_nameform_free(nf);
3371 return NULL;
3372 }
3373 }
3374 }
3375
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")
3390 };
3391
3392 char *
ldap_scherr2str(int code)3393 ldap_scherr2str(int code)
3394 {
3395 if ( code < 0 || code >= (int)(sizeof(err2text)/sizeof(char *)) ) {
3396 return _("Unknown error");
3397 } else {
3398 return _(err2text[code]);
3399 }
3400 }
3401