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