GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ldapctl/../ldapd/schema.c Lines: 0 696 0.0 %
Date: 2017-11-07 Branches: 0 1355 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: schema.c,v 1.17 2017/01/20 11:55:08 benno Exp $ */
2
3
/*
4
 * Copyright (c) 2010 Martin Hedenfalk <martinh@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
21
#include <ctype.h>
22
#include <stdlib.h>
23
#include <string.h>
24
#include <syslog.h>
25
26
#include "ldapd.h"
27
#include "log.h"
28
29
#define ERROR	-1
30
#define STRING	 1
31
32
static int
33
attr_oid_cmp(struct attr_type *a, struct attr_type *b)
34
{
35
	return strcasecmp(a->oid, b->oid);
36
}
37
38
static int
39
obj_oid_cmp(struct object *a, struct object *b)
40
{
41
	return strcasecmp(a->oid, b->oid);
42
}
43
44
static int
45
oidname_cmp(struct oidname *a, struct oidname *b)
46
{
47
	return strcasecmp(a->on_name, b->on_name);
48
}
49
50
static int
51
symoid_cmp(struct symoid *a, struct symoid *b)
52
{
53
	return strcasecmp(a->name, b->name);
54
}
55
56
RB_GENERATE(attr_type_tree, attr_type, link, attr_oid_cmp);
57
RB_GENERATE(object_tree, object, link, obj_oid_cmp);
58
RB_GENERATE(oidname_tree, oidname, link, oidname_cmp);
59
RB_GENERATE(symoid_tree, symoid, link, symoid_cmp);
60
61
static struct attr_list	*push_attr(struct attr_list *alist, struct attr_type *a);
62
static struct obj_list	*push_obj(struct obj_list *olist, struct object *obj);
63
static struct name_list *push_name(struct name_list *nl, char *name);
64
int			 is_oidstr(const char *oidstr);
65
66
struct attr_type *
67
lookup_attribute_by_name(struct schema *schema, char *name)
68
{
69
	struct oidname		*on, find;
70
71
	find.on_name = name;
72
	on = RB_FIND(oidname_tree, &schema->attr_names, &find);
73
74
	if (on)
75
		return on->on_attr_type;
76
	return NULL;
77
}
78
79
struct attr_type *
80
lookup_attribute_by_oid(struct schema *schema, char *oid)
81
{
82
	struct attr_type	 find;
83
84
	find.oid = oid;
85
	return RB_FIND(attr_type_tree, &schema->attr_types, &find);
86
}
87
88
struct attr_type *
89
lookup_attribute(struct schema *schema, char *oid_or_name)
90
{
91
	if (is_oidstr(oid_or_name))
92
		return lookup_attribute_by_oid(schema, oid_or_name);
93
	return lookup_attribute_by_name(schema, oid_or_name);
94
}
95
96
struct object *
97
lookup_object_by_oid(struct schema *schema, char *oid)
98
{
99
	struct object	 find;
100
101
	find.oid = oid;
102
	return RB_FIND(object_tree, &schema->objects, &find);
103
}
104
105
struct object *
106
lookup_object_by_name(struct schema *schema, char *name)
107
{
108
	struct oidname		*on, find;
109
110
	find.on_name = name;
111
	on = RB_FIND(oidname_tree, &schema->object_names, &find);
112
113
	if (on)
114
		return on->on_object;
115
	return NULL;
116
}
117
118
struct object *
119
lookup_object(struct schema *schema, char *oid_or_name)
120
{
121
	if (is_oidstr(oid_or_name))
122
		return lookup_object_by_oid(schema, oid_or_name);
123
	return lookup_object_by_name(schema, oid_or_name);
124
}
125
126
/*
127
 * Looks up a symbolic OID, optionally with a suffix OID, so if
128
 *   SYMBOL = 1.2.3.4
129
 * then
130
 *   SYMBOL:5.6 = 1.2.3.4.5.6
131
 *
132
 * Returned string must be freed by the caller.
133
 * Modifies the name argument.
134
 */
135
char *
136
lookup_symbolic_oid(struct schema *schema, char *name)
137
{
138
	struct symoid	*symoid, find;
139
	char		*colon, *oid;
140
	size_t		 sz;
141
142
	colon = strchr(name, ':');
143
	if (colon != NULL) {
144
		if (!is_oidstr(colon + 1)) {
145
			log_warnx("invalid OID after colon: %s", colon + 1);
146
			return NULL;
147
		}
148
		*colon = '\0';
149
	}
150
151
	find.name = name;
152
	symoid = RB_FIND(symoid_tree, &schema->symbolic_oids, &find);
153
	if (symoid == NULL)
154
		return NULL;
155
156
	if (colon == NULL)
157
		return strdup(symoid->oid);
158
159
	/* Expand SYMBOL:OID. */
160
	sz = strlen(symoid->oid) + 1 + strlen(colon + 1) + 1;
161
	if ((oid = malloc(sz)) == NULL) {
162
		log_warnx("malloc");
163
		return NULL;
164
	}
165
166
	strlcpy(oid, symoid->oid, sz);
167
	strlcat(oid, ".", sz);
168
	strlcat(oid, colon + 1, sz);
169
170
	return oid;
171
}
172
173
/*
174
 * Push a symbol-OID pair on the tree. Name and OID must be valid pointers
175
 * during the lifetime of the tree.
176
 */
177
static struct symoid *
178
push_symbolic_oid(struct schema *schema, char *name, char *oid)
179
{
180
	struct symoid	*symoid, find;
181
182
	find.name = name;
183
	symoid = RB_FIND(symoid_tree, &schema->symbolic_oids, &find);
184
185
	if (symoid == NULL) {
186
		symoid = calloc(1, sizeof(*symoid));
187
		if (symoid == NULL) {
188
			log_warnx("calloc");
189
			return NULL;
190
		}
191
192
		symoid->name = name;
193
		RB_INSERT(symoid_tree, &schema->symbolic_oids, symoid);
194
	}
195
196
	free(symoid->oid);
197
	symoid->oid = oid;
198
199
	return symoid;
200
}
201
202
static struct attr_list *
203
push_attr(struct attr_list *alist, struct attr_type *a)
204
{
205
	struct attr_ptr		*aptr;
206
207
	if (alist == NULL) {
208
		if ((alist = calloc(1, sizeof(*alist))) == NULL) {
209
			log_warn("calloc");
210
			return NULL;
211
		}
212
		SLIST_INIT(alist);
213
	}
214
215
	if ((aptr = calloc(1, sizeof(*aptr))) == NULL) {
216
		log_warn("calloc");
217
		free(alist);
218
		return NULL;
219
	}
220
	aptr->attr_type = a;
221
	SLIST_INSERT_HEAD(alist, aptr, next);
222
223
	return alist;
224
}
225
226
static struct obj_list *
227
push_obj(struct obj_list *olist, struct object *obj)
228
{
229
	struct obj_ptr		*optr;
230
231
	if (olist == NULL) {
232
		if ((olist = calloc(1, sizeof(*olist))) == NULL) {
233
			log_warn("calloc");
234
			return NULL;
235
		}
236
		SLIST_INIT(olist);
237
	}
238
239
	if ((optr = calloc(1, sizeof(*optr))) == NULL) {
240
		log_warn("calloc");
241
		free(olist);
242
		return NULL;
243
	}
244
	optr->object = obj;
245
	SLIST_INSERT_HEAD(olist, optr, next);
246
247
	return olist;
248
}
249
250
int
251
is_oidstr(const char *oidstr)
252
{
253
	struct ber_oid	 oid;
254
	return (ber_string2oid(oidstr, &oid) == 0);
255
}
256
257
static struct name_list *
258
push_name(struct name_list *nl, char *name)
259
{
260
	struct name	*n;
261
262
	if (nl == NULL) {
263
		if ((nl = calloc(1, sizeof(*nl))) == NULL) {
264
			log_warn("calloc");
265
			return NULL;
266
		}
267
		SLIST_INIT(nl);
268
	}
269
	if ((n = calloc(1, sizeof(*n))) == NULL) {
270
		log_warn("calloc");
271
		free(nl);
272
		return NULL;
273
	}
274
	n->name = name;
275
	SLIST_INSERT_HEAD(nl, n, next);
276
277
	return nl;
278
}
279
280
static int
281
schema_getc(struct schema *schema, int quotec)
282
{
283
	int		c, next;
284
285
	if (schema->pushback_index)
286
		return (schema->pushback_buffer[--schema->pushback_index]);
287
288
	if (quotec) {
289
		if ((c = getc(schema->fp)) == EOF) {
290
			log_warnx("reached end of file while parsing "
291
			    "quoted string");
292
			return EOF;
293
		}
294
		return (c);
295
	}
296
297
	while ((c = getc(schema->fp)) == '\\') {
298
		next = getc(schema->fp);
299
		if (next != '\n') {
300
			c = next;
301
			break;
302
		}
303
		schema->lineno++;
304
	}
305
306
	return (c);
307
}
308
309
static int
310
schema_ungetc(struct schema *schema, int c)
311
{
312
	if (c == EOF)
313
		return EOF;
314
315
	if (schema->pushback_index < SCHEMA_MAXPUSHBACK-1)
316
		return (schema->pushback_buffer[schema->pushback_index++] = c);
317
	else
318
		return (EOF);
319
}
320
321
static int
322
findeol(struct schema *schema)
323
{
324
	int	c;
325
326
	/* skip to either EOF or the first real EOL */
327
	while (1) {
328
		if (schema->pushback_index)
329
			c = schema->pushback_buffer[--schema->pushback_index];
330
		else
331
			c = schema_getc(schema, 0);
332
		if (c == '\n') {
333
			schema->lineno++;
334
			break;
335
		}
336
		if (c == EOF)
337
			break;
338
	}
339
	return (ERROR);
340
}
341
342
static int
343
schema_lex(struct schema *schema, char **kw)
344
{
345
	char	 buf[8096];
346
	char	*p;
347
	int	 quotec, next, c;
348
349
	if (kw)
350
		*kw = NULL;
351
352
top:
353
	p = buf;
354
	while ((c = schema_getc(schema, 0)) == ' ' || c == '\t')
355
		; /* nothing */
356
357
	if (c == '#')
358
		while ((c = schema_getc(schema, 0)) != '\n' && c != EOF)
359
			; /* nothing */
360
361
	switch (c) {
362
	case '\'':
363
	case '"':
364
		quotec = c;
365
		while (1) {
366
			if ((c = schema_getc(schema, quotec)) == EOF)
367
				return (0);
368
			if (c == '\n') {
369
				schema->lineno++;
370
				continue;
371
			} else if (c == '\\') {
372
				if ((next = schema_getc(schema, quotec)) == EOF)
373
					return (0);
374
				if (next == quotec || c == ' ' || c == '\t')
375
					c = next;
376
				else if (next == '\n')
377
					continue;
378
				else
379
					schema_ungetc(schema, next);
380
			} else if (c == quotec) {
381
				*p = '\0';
382
				break;
383
			}
384
			if (p + 1 >= buf + sizeof(buf) - 1) {
385
				log_warnx("string too long");
386
				return (findeol(schema));
387
			}
388
			*p++ = (char)c;
389
		}
390
		if (kw != NULL && (*kw = strdup(buf)) == NULL)
391
			fatal("schema_lex: strdup");
392
		return (STRING);
393
	}
394
395
#define allowed_in_string(x) \
396
	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
397
	x != '{' && x != '}' && x != '<' && x != '>' && \
398
	x != '!' && x != '=' && x != '/' && x != '#' && \
399
	x != ','))
400
401
	if (isalnum(c) || c == ':' || c == '_' || c == '*') {
402
		do {
403
			*p++ = c;
404
			if ((unsigned)(p-buf) >= sizeof(buf)) {
405
				log_warnx("string too long");
406
				return (findeol(schema));
407
			}
408
		} while ((c = schema_getc(schema, 0)) != EOF && (allowed_in_string(c)));
409
		schema_ungetc(schema, c);
410
		*p = '\0';
411
		if (kw != NULL && (*kw = strdup(buf)) == NULL)
412
			fatal("schema_lex: strdup");
413
		return STRING;
414
	}
415
	if (c == '\n') {
416
		schema->lineno++;
417
		goto top;
418
	}
419
	if (c == EOF)
420
		return (0);
421
	return (c);
422
}
423
424
struct schema *
425
schema_new(void)
426
{
427
	struct schema	*schema;
428
429
	if ((schema = calloc(1, sizeof(*schema))) == NULL)
430
		return NULL;
431
432
	RB_INIT(&schema->attr_types);
433
	RB_INIT(&schema->attr_names);
434
	RB_INIT(&schema->objects);
435
	RB_INIT(&schema->object_names);
436
	RB_INIT(&schema->symbolic_oids);
437
438
	return schema;
439
}
440
441
static void
442
schema_err(struct schema *schema, const char *fmt, ...)
443
{
444
	va_list		 ap;
445
	char		*msg;
446
447
	va_start(ap, fmt);
448
	if (vasprintf(&msg, fmt, ap) == -1)
449
		fatal("vasprintf");
450
	va_end(ap);
451
	logit(LOG_CRIT, "%s:%d: %s", schema->filename, schema->lineno, msg);
452
	free(msg);
453
454
	schema->error++;
455
}
456
457
static int
458
schema_link_attr_name(struct schema *schema, const char *name, struct attr_type *attr)
459
{
460
	struct oidname		*oidname, *prev;
461
462
	if ((oidname = calloc(1, sizeof(*oidname))) == NULL) {
463
		log_warn("calloc");
464
		return -1;
465
	}
466
467
	oidname->on_name = name;
468
	oidname->on_attr_type = attr;
469
	prev = RB_INSERT(oidname_tree, &schema->attr_names, oidname);
470
	if (prev != NULL) {
471
		schema_err(schema, "attribute type name '%s'"
472
		    " already defined for oid %s",
473
		    name, prev->on_attr_type->oid);
474
		free(oidname);
475
		return -1;
476
	}
477
478
	return 0;
479
}
480
481
static int
482
schema_link_attr_names(struct schema *schema, struct attr_type *attr)
483
{
484
	struct name	*name;
485
486
	SLIST_FOREACH(name, attr->names, next) {
487
		if (schema_link_attr_name(schema, name->name, attr) != 0)
488
			return -1;
489
	}
490
	return 0;
491
}
492
493
static int
494
schema_link_obj_name(struct schema *schema, const char *name, struct object *obj)
495
{
496
	struct oidname		*oidname, *prev;
497
498
	if ((oidname = calloc(1, sizeof(*oidname))) == NULL) {
499
		log_warn("calloc");
500
		return -1;
501
	}
502
503
	oidname->on_name = name;
504
	oidname->on_object = obj;
505
	prev = RB_INSERT(oidname_tree, &schema->object_names, oidname);
506
	if (prev != NULL) {
507
		schema_err(schema, "object class name '%s'"
508
		    " already defined for oid %s",
509
		    name, prev->on_object->oid);
510
		free(oidname);
511
		return -1;
512
	}
513
514
	return 0;
515
}
516
517
static int
518
schema_link_obj_names(struct schema *schema, struct object *obj)
519
{
520
	struct name	*name;
521
522
	SLIST_FOREACH(name, obj->names, next) {
523
		if (schema_link_obj_name(schema, name->name, obj) != 0)
524
			return -1;
525
	}
526
	return 0;
527
}
528
529
static struct name_list *
530
schema_parse_names(struct schema *schema)
531
{
532
	struct name_list	*nlist = NULL;
533
	char			*kw;
534
	int			 token;
535
536
	token = schema_lex(schema, &kw);
537
	if (token == STRING)
538
		return push_name(NULL, kw);
539
540
	if (token != '(')
541
		goto fail;
542
543
	for (;;) {
544
		token = schema_lex(schema, &kw);
545
		if (token == ')')
546
			break;
547
		if (token != STRING)
548
			goto fail;
549
		nlist = push_name(nlist, kw);
550
	}
551
552
	return nlist;
553
554
fail:
555
	free(kw);
556
	/* FIXME: leaks nlist here */
557
	return NULL;
558
}
559
560
static void
561
schema_free_name_list(struct name_list *nlist)
562
{
563
	struct name	*name;
564
565
	while ((name = SLIST_FIRST(nlist)) != NULL) {
566
		SLIST_REMOVE_HEAD(nlist, next);
567
		free(name->name);
568
		free(name);
569
	}
570
	free(nlist);
571
}
572
573
static struct attr_list *
574
schema_parse_attrlist(struct schema *schema)
575
{
576
	struct attr_list	*alist = NULL;
577
	struct attr_type	*attr;
578
	char			*kw;
579
	int			 token, want_dollar = 0;
580
581
	token = schema_lex(schema, &kw);
582
	if (token == STRING) {
583
		if ((attr = lookup_attribute(schema, kw)) == NULL) {
584
			schema_err(schema, "undeclared attribute type '%s'", kw);
585
			goto fail;
586
		}
587
		free(kw);
588
		return push_attr(NULL, attr);
589
	}
590
591
	if (token != '(')
592
		goto fail;
593
594
	for (;;) {
595
		token = schema_lex(schema, &kw);
596
		if (token == ')')
597
			break;
598
		if (token == '$') {
599
			if (!want_dollar)
600
				goto fail;
601
			want_dollar = 0;
602
			continue;
603
		}
604
		if (token != STRING)
605
			goto fail;
606
		if ((attr = lookup_attribute(schema, kw)) == NULL) {
607
			schema_err(schema, "%s: no such attribute", kw);
608
			goto fail;
609
		}
610
		alist = push_attr(alist, attr);
611
		free(kw);
612
		want_dollar = 1;
613
	}
614
615
	return alist;
616
617
fail:
618
	free(kw);
619
	/* FIXME: leaks alist here */
620
	return NULL;
621
}
622
623
static struct obj_list *
624
schema_parse_objlist(struct schema *schema)
625
{
626
	struct obj_list	*olist = NULL;
627
	struct object	*obj;
628
	char		*kw;
629
	int		 token, want_dollar = 0;
630
631
	token = schema_lex(schema, &kw);
632
	if (token == STRING) {
633
		if ((obj = lookup_object(schema, kw)) == NULL) {
634
			schema_err(schema, "undeclared object class '%s'", kw);
635
			goto fail;
636
		}
637
		free(kw);
638
		return push_obj(NULL, obj);
639
	}
640
641
	if (token != '(')
642
		goto fail;
643
644
	for (;;) {
645
		token = schema_lex(schema, &kw);
646
		if (token == ')')
647
			break;
648
		if (token == '$') {
649
			if (!want_dollar)
650
				goto fail;
651
			want_dollar = 0;
652
			continue;
653
		}
654
		if (token != STRING)
655
			goto fail;
656
		if ((obj = lookup_object(schema, kw)) == NULL)
657
			goto fail;
658
		olist = push_obj(olist, obj);
659
		want_dollar = 1;
660
	}
661
662
	return olist;
663
664
fail:
665
	free(kw);
666
	/* FIXME: leaks olist here */
667
	return NULL;
668
}
669
670
static int
671
schema_validate_match_rule(struct schema *schema, struct attr_type *at,
672
    const struct match_rule *mrule, enum match_rule_type type)
673
{
674
	int i;
675
676
	if (mrule == NULL)
677
		return 0;
678
679
	if ((mrule->type & type) != type) {
680
		schema_err(schema, "%s: bad matching rule '%s'",
681
		    ATTR_NAME(at), mrule->name);
682
		return -1;
683
	}
684
685
	/* Is this matching rule compatible with the attribute syntax? */
686
	if (strcmp(mrule->syntax_oid, at->syntax->oid) == 0)
687
		return 0;
688
689
	/* Check any alternative syntaxes for compatibility. */
690
	for (i = 0; mrule->alt_syntax_oids && mrule->alt_syntax_oids[i]; i++)
691
		if (strcmp(mrule->alt_syntax_oids[i], at->syntax->oid) == 0)
692
			return 0;
693
694
	schema_err(schema, "%s: inappropriate matching rule '%s' for syntax [%s]",
695
	    ATTR_NAME(at), mrule->name, at->syntax->oid);
696
	return -1;
697
}
698
699
static int
700
schema_parse_attributetype(struct schema *schema)
701
{
702
	struct attr_type	*attr = NULL, *prev, *sup;
703
	struct name_list	*xnames;
704
	char			*kw = NULL, *arg = NULL;
705
	int			 token, ret = 0, c;
706
707
	if (schema_lex(schema, NULL) != '(')
708
		goto fail;
709
710
	if (schema_lex(schema, &kw) != STRING)
711
		goto fail;
712
713
	if ((attr = calloc(1, sizeof(*attr))) == NULL) {
714
		log_warn("calloc");
715
		goto fail;
716
	}
717
	attr->usage = USAGE_USER_APP;
718
719
	if (is_oidstr(kw))
720
		attr->oid = kw;
721
	else {
722
		attr->oid = lookup_symbolic_oid(schema, kw);
723
		if (attr->oid == NULL)
724
			goto fail;
725
		free(kw);
726
	}
727
	kw = NULL;
728
729
	prev = RB_INSERT(attr_type_tree, &schema->attr_types, attr);
730
	if (prev != NULL) {
731
		schema_err(schema, "attribute type %s already defined", attr->oid);
732
		goto fail;
733
	}
734
735
	while (ret == 0) {
736
		token = schema_lex(schema, &kw);
737
		if (token == ')')
738
			break;
739
		else if (token != STRING)
740
			goto fail;
741
		if (strcasecmp(kw, "NAME") == 0) {
742
			attr->names = schema_parse_names(schema);
743
			if (attr->names == NULL)
744
				goto fail;
745
			schema_link_attr_names(schema, attr);
746
		} else if (strcasecmp(kw, "DESC") == 0) {
747
			if (schema_lex(schema, &attr->desc) != STRING)
748
				goto fail;
749
		} else if (strcasecmp(kw, "OBSOLETE") == 0) {
750
			attr->obsolete = 1;
751
		} else if (strcasecmp(kw, "SUP") == 0) {
752
			if (schema_lex(schema, &arg) != STRING)
753
				goto fail;
754
			if ((attr->sup = lookup_attribute(schema, arg)) == NULL) {
755
				schema_err(schema, "%s: no such attribute", arg);
756
				goto fail;
757
			}
758
			free(arg);
759
		} else if (strcasecmp(kw, "EQUALITY") == 0) {
760
			if (schema_lex(schema, &arg) != STRING)
761
				goto fail;
762
			if ((attr->equality = match_rule_lookup(arg)) == NULL) {
763
				schema_err(schema, "%s: unknown matching rule",
764
				    arg);
765
				goto fail;
766
			}
767
			free(arg);
768
		} else if (strcasecmp(kw, "ORDERING") == 0) {
769
			if (schema_lex(schema, &arg) != STRING)
770
				goto fail;
771
			if ((attr->ordering = match_rule_lookup(arg)) == NULL) {
772
				schema_err(schema, "%s: unknown matching rule",
773
				    arg);
774
				goto fail;
775
			}
776
			free(arg);
777
		} else if (strcasecmp(kw, "SUBSTR") == 0) {
778
			if (schema_lex(schema, &arg) != STRING)
779
				goto fail;
780
			if ((attr->substr = match_rule_lookup(arg)) == NULL) {
781
				schema_err(schema, "%s: unknown matching rule",
782
				    arg);
783
				goto fail;
784
			}
785
			free(arg);
786
		} else if (strcasecmp(kw, "SYNTAX") == 0) {
787
			if (schema_lex(schema, &arg) != STRING ||
788
			    !is_oidstr(arg))
789
				goto fail;
790
791
			if ((attr->syntax = syntax_lookup(arg)) == NULL) {
792
				schema_err(schema, "syntax not supported: %s",
793
				    arg);
794
				goto fail;
795
			}
796
797
			if ((c = schema_getc(schema, 0)) == '{') {
798
				if (schema_lex(schema, NULL) != STRING ||
799
				    schema_lex(schema, NULL) != '}')
800
					goto fail;
801
			} else
802
				schema_ungetc(schema, c);
803
			free(arg);
804
		} else if (strcasecmp(kw, "SINGLE-VALUE") == 0) {
805
			attr->single = 1;
806
		} else if (strcasecmp(kw, "COLLECTIVE") == 0) {
807
			attr->collective = 1;
808
		} else if (strcasecmp(kw, "NO-USER-MODIFICATION") == 0) {
809
			attr->immutable = 1;
810
		} else if (strcasecmp(kw, "USAGE") == 0) {
811
			if (schema_lex(schema, &arg) != STRING)
812
				goto fail;
813
			if (strcasecmp(arg, "dSAOperation") == 0)
814
				attr->usage = USAGE_DSA_OP;
815
			else if (strcasecmp(arg, "directoryOperation") == 0)
816
				attr->usage = USAGE_DIR_OP;
817
			else if (strcasecmp(arg, "distributedOperation") == 0)
818
				attr->usage = USAGE_DIST_OP;
819
			else if (strcasecmp(arg, "userApplications") == 0)
820
				attr->usage = USAGE_USER_APP;
821
			else {
822
				schema_err(schema, "invalid usage '%s'", arg);
823
				goto fail;
824
			}
825
			free(arg);
826
		} else if (strncmp(kw, "X-", 2) == 0) {
827
			/* unknown extension, eat argument(s) */
828
			xnames = schema_parse_names(schema);
829
			if (xnames == NULL)
830
				goto fail;
831
			schema_free_name_list(xnames);
832
		} else {
833
			schema_err(schema, "syntax error at token '%s'", kw);
834
			goto fail;
835
		}
836
		free(kw);
837
	}
838
839
	/* Check that a syntax is defined, either directly or
840
	 * indirectly via a superior attribute type.
841
	 */
842
	sup = attr->sup;
843
	while (attr->syntax == NULL && sup != NULL) {
844
		attr->syntax = sup->syntax;
845
		sup = sup->sup;
846
	}
847
	if (attr->syntax == NULL) {
848
		schema_err(schema, "%s: no syntax defined", ATTR_NAME(attr));
849
		goto fail;
850
	}
851
852
	/* If the attribute type doesn't explicitly define equality, check
853
	 * if any superior attribute type does.
854
	 */
855
	sup = attr->sup;
856
	while (attr->equality == NULL && sup != NULL) {
857
		attr->equality = sup->equality;
858
		sup = sup->sup;
859
	}
860
	/* Same thing with ordering matching rule. */
861
	sup = attr->sup;
862
	while (attr->ordering == NULL && sup != NULL) {
863
		attr->ordering = sup->ordering;
864
		sup = sup->sup;
865
	}
866
	/* ...and substring matching rule. */
867
	sup = attr->sup;
868
	while (attr->substr == NULL && sup != NULL) {
869
		attr->substr = sup->substr;
870
		sup = sup->sup;
871
	}
872
873
	if (schema_validate_match_rule(schema, attr, attr->equality, MATCH_EQUALITY) != 0 ||
874
	    schema_validate_match_rule(schema, attr, attr->ordering, MATCH_ORDERING) != 0 ||
875
	    schema_validate_match_rule(schema, attr, attr->substr, MATCH_SUBSTR) != 0)
876
		goto fail;
877
878
	return 0;
879
880
fail:
881
	free(kw);
882
	if (attr != NULL) {
883
		if (attr->oid != NULL) {
884
			RB_REMOVE(attr_type_tree, &schema->attr_types, attr);
885
			free(attr->oid);
886
		}
887
		free(attr->desc);
888
		free(attr);
889
	}
890
	return -1;
891
}
892
893
static int
894
schema_parse_objectclass(struct schema *schema)
895
{
896
	struct object		*obj = NULL, *prev;
897
	struct obj_ptr		*optr;
898
	struct name_list	*xnames;
899
	char			*kw = NULL;
900
	int			 token, ret = 0;
901
902
	if (schema_lex(schema, NULL) != '(')
903
		goto fail;
904
905
	if (schema_lex(schema, &kw) != STRING)
906
		goto fail;
907
908
	if ((obj = calloc(1, sizeof(*obj))) == NULL) {
909
		log_warn("calloc");
910
		goto fail;
911
	}
912
	obj->kind = KIND_STRUCTURAL;
913
914
	if (is_oidstr(kw))
915
		obj->oid = kw;
916
	else {
917
		obj->oid = lookup_symbolic_oid(schema, kw);
918
		if (obj->oid == NULL)
919
			goto fail;
920
		free(kw);
921
	}
922
	kw = NULL;
923
924
	prev = RB_INSERT(object_tree, &schema->objects, obj);
925
	if (prev != NULL) {
926
		schema_err(schema, "object class %s already defined", obj->oid);
927
		goto fail;
928
	}
929
930
	while (ret == 0) {
931
		token = schema_lex(schema, &kw);
932
		if (token == ')')
933
			break;
934
		else if (token != STRING)
935
			goto fail;
936
		if (strcasecmp(kw, "NAME") == 0) {
937
			obj->names = schema_parse_names(schema);
938
			if (obj->names == NULL)
939
				goto fail;
940
			schema_link_obj_names(schema, obj);
941
		} else if (strcasecmp(kw, "DESC") == 0) {
942
			if (schema_lex(schema, &obj->desc) != STRING)
943
				goto fail;
944
		} else if (strcasecmp(kw, "OBSOLETE") == 0) {
945
			obj->obsolete = 1;
946
		} else if (strcasecmp(kw, "SUP") == 0) {
947
			obj->sup = schema_parse_objlist(schema);
948
			if (obj->sup == NULL)
949
				goto fail;
950
		} else if (strcasecmp(kw, "ABSTRACT") == 0) {
951
			obj->kind = KIND_ABSTRACT;
952
		} else if (strcasecmp(kw, "STRUCTURAL") == 0) {
953
			obj->kind = KIND_STRUCTURAL;
954
		} else if (strcasecmp(kw, "AUXILIARY") == 0) {
955
			obj->kind = KIND_AUXILIARY;
956
		} else if (strcasecmp(kw, "MUST") == 0) {
957
			obj->must = schema_parse_attrlist(schema);
958
			if (obj->must == NULL)
959
				goto fail;
960
		} else if (strcasecmp(kw, "MAY") == 0) {
961
			obj->may = schema_parse_attrlist(schema);
962
			if (obj->may == NULL)
963
				goto fail;
964
		} else if (strncasecmp(kw, "X-", 2) == 0) {
965
			/* unknown extension, eat argument(s) */
966
			xnames = schema_parse_names(schema);
967
			if (xnames == NULL)
968
				goto fail;
969
			schema_free_name_list(xnames);
970
		} else {
971
			schema_err(schema, "syntax error at token '%s'", kw);
972
			goto fail;
973
		}
974
		free(kw);
975
	}
976
977
	/* Verify the subclassing is allowed.
978
	 *
979
	 * Structural object classes cannot subclass auxiliary object classes.
980
	 * Auxiliary object classes cannot subclass structural object classes.
981
	 * Abstract object classes cannot derive from structural or auxiliary
982
	 *   object classes.
983
	 */
984
	if (obj->sup != NULL) {
985
		SLIST_FOREACH(optr, obj->sup, next) {
986
			if (obj->kind == KIND_STRUCTURAL &&
987
			    optr->object->kind == KIND_AUXILIARY) {
988
				log_warnx("structural object class '%s' cannot"
989
				    " subclass auxiliary object class '%s'",
990
				    OBJ_NAME(obj), OBJ_NAME(optr->object));
991
				goto fail;
992
			}
993
994
			if (obj->kind == KIND_AUXILIARY &&
995
			    optr->object->kind == KIND_STRUCTURAL) {
996
				log_warnx("auxiliary object class '%s' cannot"
997
				    " subclass structural object class '%s'",
998
				    OBJ_NAME(obj), OBJ_NAME(optr->object));
999
				goto fail;
1000
			}
1001
1002
			if (obj->kind == KIND_ABSTRACT &&
1003
			    optr->object->kind != KIND_ABSTRACT) {
1004
				log_warnx("abstract object class '%s' cannot"
1005
				    " subclass non-abstract object class '%s'",
1006
				    OBJ_NAME(obj), OBJ_NAME(optr->object));
1007
				goto fail;
1008
			}
1009
		}
1010
	}
1011
1012
	return 0;
1013
1014
fail:
1015
	free(kw);
1016
	if (obj != NULL) {
1017
		if (obj->oid != NULL) {
1018
			RB_REMOVE(object_tree, &schema->objects, obj);
1019
			free(obj->oid);
1020
		}
1021
		free(obj->desc);
1022
		free(obj);
1023
	}
1024
	return -1;
1025
}
1026
1027
static int
1028
schema_parse_objectidentifier(struct schema *schema)
1029
{
1030
	char		*symname = NULL, *symoid = NULL;
1031
	char		*oid = NULL;
1032
1033
	if (schema_lex(schema, &symname) != STRING)
1034
		goto fail;
1035
	if (schema_lex(schema, &symoid) != STRING)
1036
		goto fail;
1037
1038
	if (is_oidstr(symoid)) {
1039
		oid = symoid;
1040
		symoid = NULL;
1041
	} else if ((oid = lookup_symbolic_oid(schema, symoid)) == NULL)
1042
		goto fail;
1043
1044
	if (push_symbolic_oid(schema, symname, oid) == NULL)
1045
		goto fail;
1046
1047
	free(symoid);
1048
	return 0;
1049
1050
fail:
1051
	free(symname);
1052
	free(symoid);
1053
	free(oid);
1054
	return -1;
1055
}
1056
1057
int
1058
schema_parse(struct schema *schema, const char *filename)
1059
{
1060
	char	*kw;
1061
	int	 token, ret = 0;
1062
1063
	log_debug("parsing schema file '%s'", filename);
1064
1065
	if ((schema->fp = fopen(filename, "r")) == NULL) {
1066
		log_warn("%s", filename);
1067
		return -1;
1068
	}
1069
	schema->filename = filename;
1070
	schema->lineno = 1;
1071
1072
	while (ret == 0) {
1073
		token = schema_lex(schema, &kw);
1074
		if (token == STRING) {
1075
			if (strcasecmp(kw, "attributetype") == 0)
1076
				ret = schema_parse_attributetype(schema);
1077
			else if (strcasecmp(kw, "objectclass") == 0)
1078
				ret = schema_parse_objectclass(schema);
1079
			else if (strcasecmp(kw, "objectidentifier") == 0)
1080
				ret = schema_parse_objectidentifier(schema);
1081
			else {
1082
				schema_err(schema, "syntax error at '%s'", kw);
1083
				ret = -1;
1084
			}
1085
			if (ret == -1 && schema->error == 0)
1086
				schema_err(schema, "syntax error");
1087
			free(kw);
1088
		} else if (token == 0) {	/* EOF */
1089
			break;
1090
		} else {
1091
			schema_err(schema, "syntax error");
1092
			ret = -1;
1093
		}
1094
	}
1095
1096
	fclose(schema->fp);
1097
	schema->fp = NULL;
1098
	schema->filename = NULL;
1099
1100
	return ret;
1101
}
1102
1103
static int
1104
schema_dump_names(const char *desc, struct name_list *nlist,
1105
    char *buf, size_t size)
1106
{
1107
	struct name	*name;
1108
1109
	if (nlist == NULL || SLIST_EMPTY(nlist))
1110
		return 0;
1111
1112
	if (strlcat(buf, " ", size) >= size ||
1113
	    strlcat(buf, desc, size) >= size)
1114
		return -1;
1115
1116
	name = SLIST_FIRST(nlist);
1117
	if (SLIST_NEXT(name, next) == NULL) {
1118
		/* single name, no parenthesis */
1119
		if (strlcat(buf, " '", size) >= size ||
1120
		    strlcat(buf, name->name, size) >= size ||
1121
		    strlcat(buf, "'", size) >= size)
1122
			return -1;
1123
	} else {
1124
		if (strlcat(buf, " ( ", size) >= size)
1125
			return -1;
1126
		SLIST_FOREACH(name, nlist, next)
1127
			if (strlcat(buf, "'", size) >= size ||
1128
			    strlcat(buf, name->name, size) >= size ||
1129
			    strlcat(buf, "' ", size) >= size)
1130
				return -1;
1131
		if (strlcat(buf, ")", size) >= size)
1132
			return -1;
1133
	}
1134
1135
	return 0;
1136
}
1137
1138
static int
1139
schema_dump_attrlist(const char *desc, struct attr_list *alist,
1140
    char *buf, size_t size)
1141
{
1142
	struct attr_ptr		*aptr;
1143
1144
	if (alist == NULL || SLIST_EMPTY(alist))
1145
		return 0;
1146
1147
	if (strlcat(buf, " ", size) >= size ||
1148
	    strlcat(buf, desc, size) >= size)
1149
		return -1;
1150
1151
	aptr = SLIST_FIRST(alist);
1152
	if (SLIST_NEXT(aptr, next) == NULL) {
1153
		/* single attribute, no parenthesis */
1154
		if (strlcat(buf, " ", size) >= size ||
1155
		    strlcat(buf, ATTR_NAME(aptr->attr_type), size) >= size)
1156
			return -1;
1157
	} else {
1158
		if (strlcat(buf, " ( ", size) >= size)
1159
			return -1;
1160
		SLIST_FOREACH(aptr, alist, next) {
1161
			if (strlcat(buf, ATTR_NAME(aptr->attr_type),
1162
			    size) >= size ||
1163
			    strlcat(buf, " ", size) >= size)
1164
				return -1;
1165
			if (SLIST_NEXT(aptr, next) != NULL &&
1166
			    strlcat(buf, "$ ", size) >= size)
1167
				return -1;
1168
		}
1169
		if (strlcat(buf, ")", size) >= size)
1170
			return -1;
1171
	}
1172
1173
	return 0;
1174
}
1175
1176
static int
1177
schema_dump_objlist(const char *desc, struct obj_list *olist,
1178
    char *buf, size_t size)
1179
{
1180
	struct obj_ptr		*optr;
1181
1182
	if (olist == NULL || SLIST_EMPTY(olist))
1183
		return 0;
1184
1185
	if (strlcat(buf, " ", size) >= size ||
1186
	    strlcat(buf, desc, size) >= size)
1187
		return -1;
1188
1189
	optr = SLIST_FIRST(olist);
1190
	if (SLIST_NEXT(optr, next) == NULL) {
1191
		/* single attribute, no parenthesis */
1192
		if (strlcat(buf, " ", size) >= size ||
1193
		    strlcat(buf, OBJ_NAME(optr->object), size) >= size)
1194
			return -1;
1195
	} else {
1196
		if (strlcat(buf, " ( ", size) >= size)
1197
			return -1;
1198
		SLIST_FOREACH(optr, olist, next) {
1199
			if (strlcat(buf, OBJ_NAME(optr->object), size) >= size ||
1200
			    strlcat(buf, " ", size) >= size)
1201
				return -1;
1202
			if (SLIST_NEXT(optr, next) != NULL &&
1203
			    strlcat(buf, "$ ", size) >= size)
1204
				return -1;
1205
		}
1206
		if (strlcat(buf, ")", size) >= size)
1207
			return -1;
1208
	}
1209
1210
	return 0;
1211
}
1212
1213
int
1214
schema_dump_object(struct object *obj, char *buf, size_t size)
1215
{
1216
	if (strlcpy(buf, "( ", size) >= size ||
1217
	    strlcat(buf, obj->oid, size) >= size)
1218
		return -1;
1219
1220
	if (schema_dump_names("NAME", obj->names, buf, size) != 0)
1221
		return -1;
1222
1223
	if (obj->desc != NULL)
1224
		if (strlcat(buf, " DESC '", size) >= size ||
1225
		    strlcat(buf, obj->desc, size) >= size ||
1226
		    strlcat(buf, "'", size) >= size)
1227
			return -1;
1228
1229
	switch (obj->kind) {
1230
	case KIND_STRUCTURAL:
1231
		if (strlcat(buf, " STRUCTURAL", size) >= size)
1232
			return -1;
1233
		break;
1234
	case KIND_ABSTRACT:
1235
		if (strlcat(buf, " ABSTRACT", size) >= size)
1236
			return -1;
1237
		break;
1238
	case KIND_AUXILIARY:
1239
		if (strlcat(buf, " AUXILIARY", size) >= size)
1240
			return -1;
1241
		break;
1242
	}
1243
1244
	if (schema_dump_objlist("SUP", obj->sup, buf, size) != 0)
1245
		return -1;
1246
1247
	if (obj->obsolete && strlcat(buf, " OBSOLETE", size) >= size)
1248
		return -1;
1249
1250
	if (schema_dump_attrlist("MUST", obj->must, buf, size) != 0)
1251
		return -1;
1252
1253
	if (schema_dump_attrlist("MAY", obj->may, buf, size) != 0)
1254
		return -1;
1255
1256
	if (strlcat(buf, " )", size) >= size)
1257
		return -1;
1258
1259
	return 0;
1260
}
1261
1262
int
1263
schema_dump_attribute(struct attr_type *at, char *buf, size_t size)
1264
{
1265
	if (strlcpy(buf, "( ", size) >= size ||
1266
	    strlcat(buf, at->oid, size) >= size)
1267
		return -1;
1268
1269
	if (schema_dump_names("NAME", at->names, buf, size) != 0)
1270
		return -1;
1271
1272
	if (at->desc != NULL)
1273
		if (strlcat(buf, " DESC '", size) >= size ||
1274
		    strlcat(buf, at->desc, size) >= size ||
1275
		    strlcat(buf, "'", size) >= size)
1276
			return -1;
1277
1278
	if (at->obsolete && strlcat(buf, " OBSOLETE", size) >= size)
1279
		return -1;
1280
1281
	if (at->sup != NULL)
1282
		if (strlcat(buf, " SUP ", size) >= size ||
1283
		    strlcat(buf, ATTR_NAME(at->sup), size) >= size)
1284
			return -1;
1285
1286
	if (at->equality != NULL)
1287
		if (strlcat(buf, " EQUALITY ", size) >= size ||
1288
		    strlcat(buf, at->equality->name, size) >= size)
1289
			return -1;
1290
1291
	if (at->ordering != NULL)
1292
		if (strlcat(buf, " ORDERING ", size) >= size ||
1293
		    strlcat(buf, at->ordering->name, size) >= size)
1294
			return -1;
1295
1296
	if (at->substr != NULL)
1297
		if (strlcat(buf, " SUBSTR ", size) >= size ||
1298
		    strlcat(buf, at->substr->name, size) >= size)
1299
			return -1;
1300
1301
	if (at->syntax != NULL)
1302
		if (strlcat(buf, " SYNTAX ", size) >= size ||
1303
		    strlcat(buf, at->syntax->oid, size) >= size)
1304
			return -1;
1305
1306
	if (at->single && strlcat(buf, " SINGLE-VALUE", size) >= size)
1307
		return -1;
1308
1309
	if (at->collective && strlcat(buf, " COLLECTIVE", size) >= size)
1310
		return -1;
1311
1312
	if (at->immutable && strlcat(buf, " NO-USER-MODIFICATION", size) >= size)
1313
		return -1;
1314
1315
	switch (at->usage) {
1316
	case USAGE_USER_APP:
1317
		/* User application usage is the default. */
1318
		break;
1319
	case USAGE_DIR_OP:
1320
		if (strlcat(buf, " USAGE directoryOperation", size) >= size)
1321
			return -1;
1322
		break;
1323
	case USAGE_DIST_OP:
1324
		if (strlcat(buf, " USAGE distributedOperation", size) >= size)
1325
			return -1;
1326
		break;
1327
	case USAGE_DSA_OP:
1328
		if (strlcat(buf, " USAGE dSAOperation", size) >= size)
1329
			return -1;
1330
		break;
1331
	}
1332
1333
	if (strlcat(buf, " )", size) >= size)
1334
		return -1;
1335
1336
	return 0;
1337
}
1338
1339
int
1340
schema_dump_match_rule(struct match_rule *mr, char *buf, size_t size)
1341
{
1342
	if (strlcpy(buf, "( ", size) >= size ||
1343
	    strlcat(buf, mr->oid, size) >= size ||
1344
	    strlcat(buf, " NAME '", size) >= size ||
1345
	    strlcat(buf, mr->name, size) >= size ||
1346
	    strlcat(buf, "' SYNTAX ", size) >= size ||
1347
	    strlcat(buf, mr->syntax_oid, size) >= size ||
1348
	    strlcat(buf, " )", size) >= size)
1349
		return -1;
1350
1351
	return 0;
1352
}
1353