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