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