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