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