xref: /openbsd/usr.sbin/ldapd/parse.y (revision 8529ddd3)
1 /*	$OpenBSD: parse.y,v 1.16 2014/11/20 05:51:20 jsg Exp $ */
2 
3 /*
4  * Copyright (c) 2009, 2010 Martin Hedenfalk <martinh@openbsd.org>
5  * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
6  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
7  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
8  * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
9  * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
10  *
11  * Permission to use, copy, modify, and distribute this software for any
12  * purpose with or without fee is hereby granted, provided that the above
13  * copyright notice and this permission notice appear in all copies.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
16  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
18  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  */
23 
24 %{
25 #include <sys/types.h>
26 #include <sys/queue.h>
27 #include <sys/tree.h>
28 #include <sys/socket.h>
29 #include <sys/stat.h>
30 #include <sys/un.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 
34 #include <ctype.h>
35 #include <err.h>
36 #include <errno.h>
37 #include <ifaddrs.h>
38 #include <limits.h>
39 #include <netdb.h>
40 #include <stdarg.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <syslog.h>
45 #include <unistd.h>
46 
47 #include "ldapd.h"
48 
49 TAILQ_HEAD(files, file)		 files = TAILQ_HEAD_INITIALIZER(files);
50 static struct file {
51 	TAILQ_ENTRY(file)	 entry;
52 	FILE			*stream;
53 	char			*name;
54 	int			 lineno;
55 	int			 errors;
56 } *file, *topfile;
57 struct file	*pushfile(const char *, int);
58 int		 popfile(void);
59 int		 check_file_secrecy(int, const char *);
60 int		 yyparse(void);
61 int		 yylex(void);
62 int		 yyerror(const char *, ...)
63     __attribute__((__format__ (printf, 1, 2)))
64     __attribute__((__nonnull__ (1)));
65 int		 kw_cmp(const void *, const void *);
66 int		 lookup(char *);
67 int		 lgetc(int);
68 int		 lungetc(int);
69 int		 findeol(void);
70 
71 struct listener *host_unix(const char *path);
72 struct listener	*host_v4(const char *, in_port_t);
73 struct listener	*host_v6(const char *, in_port_t);
74 int		 host_dns(const char *, const char *,
75 		    struct listenerlist *, int, in_port_t, u_int8_t);
76 int		 host(const char *, const char *,
77 		    struct listenerlist *, int, in_port_t, u_int8_t);
78 int		 interface(const char *, const char *,
79 		    struct listenerlist *, int, in_port_t, u_int8_t);
80 
81 TAILQ_HEAD(symhead, sym)	 symhead = TAILQ_HEAD_INITIALIZER(symhead);
82 struct sym {
83 	TAILQ_ENTRY(sym)	 entry;
84 	int			 used;
85 	int			 persist;
86 	char			*nam;
87 	char			*val;
88 };
89 int		 symset(const char *, const char *, int);
90 char		*symget(const char *);
91 
92 struct ldapd_config	*conf;
93 
94 static struct aci	*mk_aci(int type, int rights, enum scope scope,
95 				char *target, char *subject);
96 
97 typedef struct {
98 	union {
99 		int64_t		 number;
100 		char		*string;
101 		struct aci	*aci;
102 	} v;
103 	int lineno;
104 } YYSTYPE;
105 
106 static struct namespace *current_ns = NULL;
107 
108 %}
109 
110 %token	ERROR LISTEN ON TLS LDAPS PORT NAMESPACE ROOTDN ROOTPW INDEX
111 %token	SECURE RELAX STRICT SCHEMA USE COMPRESSION LEVEL
112 %token	INCLUDE CERTIFICATE FSYNC CACHE_SIZE INDEX_CACHE_SIZE
113 %token	DENY ALLOW READ WRITE BIND ACCESS TO ROOT REFERRAL
114 %token	ANY CHILDREN OF ATTRIBUTE IN SUBTREE BY SELF
115 %token	<v.string>	STRING
116 %token  <v.number>	NUMBER
117 %type	<v.number>	port ssl boolean comp_level
118 %type	<v.number>	aci_type aci_access aci_rights aci_right aci_scope
119 %type	<v.string>	aci_target aci_subject certname
120 %type	<v.aci>		aci
121 
122 %%
123 
124 grammar		: /* empty */
125 		| grammar '\n'
126 		| grammar include '\n'
127 		| grammar varset '\n'
128 		| grammar conf_main '\n'
129 		| grammar error '\n'		{ file->errors++; }
130 		| grammar namespace '\n'
131 		| grammar aci '\n'		{
132 			SIMPLEQ_INSERT_TAIL(&conf->acl, $2, entry);
133 		}
134 		| grammar schema '\n'
135 		;
136 
137 ssl		: /* empty */			{ $$ = 0; }
138 		| TLS				{ $$ = F_STARTTLS; }
139 		| LDAPS				{ $$ = F_LDAPS; }
140 		| SECURE			{ $$ = F_SECURE; }
141 		;
142 
143 certname	: /* empty */			{ $$ = NULL; }
144 		| CERTIFICATE STRING		{ $$ = $2; }
145 		;
146 
147 port		: PORT STRING			{
148 			struct servent	*servent;
149 
150 			servent = getservbyname($2, "tcp");
151 			if (servent == NULL) {
152 				yyerror("port %s is invalid", $2);
153 				free($2);
154 				YYERROR;
155 			}
156 			$$ = servent->s_port;
157 			free($2);
158 		}
159 		| PORT NUMBER			{
160 			if ($2 <= 0 || $2 >= (int)USHRT_MAX) {
161 				yyerror("invalid port: %lld", $2);
162 				YYERROR;
163 			}
164 			$$ = htons($2);
165 		}
166 		| /* empty */			{
167 			$$ = 0;
168 		}
169 		;
170 
171 conf_main	: LISTEN ON STRING port ssl certname	{
172 			char			*cert;
173 
174 			if ($4 == 0) {
175 				if ($5 == F_LDAPS)
176 					$4 = htons(LDAPS_PORT);
177 				else
178 					$4 = htons(LDAP_PORT);
179 			}
180 
181 			cert = ($6 != NULL) ? $6 : $3;
182 
183 			if (($5 == F_STARTTLS || $5 == F_LDAPS) &&
184 			    ssl_load_certfile(conf, cert, F_SCERT) < 0) {
185 				yyerror("cannot load certificate: %s", cert);
186 				free($6);
187 				free($3);
188 				YYERROR;
189 			}
190 
191 			if (! interface($3, cert, &conf->listeners,
192 				MAX_LISTEN, $4, $5)) {
193 				if (host($3, cert, &conf->listeners,
194 					MAX_LISTEN, $4, $5) <= 0) {
195 					yyerror("invalid virtual ip or interface: %s", $3);
196 					free($6);
197 					free($3);
198 					YYERROR;
199 				}
200 			}
201 			free($6);
202 			free($3);
203 		}
204 		| REFERRAL STRING		{
205 			struct referral	*ref;
206 			if ((ref = calloc(1, sizeof(*ref))) == NULL) {
207 				yyerror("calloc");
208 				free($2);
209 				YYERROR;
210 			}
211 			ref->url = $2;
212 			SLIST_INSERT_HEAD(&conf->referrals, ref, next);
213 		}
214 		| ROOTDN STRING			{
215 			conf->rootdn = $2;
216 			normalize_dn(conf->rootdn);
217 		}
218 		| ROOTPW STRING			{ conf->rootpw = $2; }
219 		;
220 
221 namespace	: NAMESPACE STRING '{' '\n'		{
222 			log_debug("parsing namespace %s", $2);
223 			current_ns = namespace_new($2);
224 			free($2);
225 			TAILQ_INSERT_TAIL(&conf->namespaces, current_ns, next);
226 		} ns_opts '}'			{ current_ns = NULL; }
227 		;
228 
229 boolean		: STRING			{
230 			if (strcasecmp($1, "true") == 0 ||
231 			    strcasecmp($1, "yes") == 0)
232 				$$ = 1;
233 			else if (strcasecmp($1, "false") == 0 ||
234 			    strcasecmp($1, "off") == 0 ||
235 			    strcasecmp($1, "no") == 0)
236 				$$ = 0;
237 			else {
238 				yyerror("invalid boolean value '%s'", $1);
239 				free($1);
240 				YYERROR;
241 			}
242 			free($1);
243 		}
244 		| ON				{ $$ = 1; }
245 		;
246 
247 ns_opts		: /* empty */
248 		| ns_opts '\n'
249 		| ns_opts ns_opt '\n'
250 		;
251 
252 ns_opt		: ROOTDN STRING			{
253 			current_ns->rootdn = $2;
254 			normalize_dn(current_ns->rootdn);
255 		}
256 		| ROOTPW STRING			{ current_ns->rootpw = $2; }
257 		| INDEX STRING			{
258 			struct attr_index	*ai;
259 			if ((ai = calloc(1, sizeof(*ai))) == NULL) {
260 				yyerror("calloc");
261                                 free($2);
262 				YYERROR;
263 			}
264 			ai->attr = $2;
265 			ai->type = INDEX_EQUAL;
266 			TAILQ_INSERT_TAIL(&current_ns->indices, ai, next);
267 		}
268 		| CACHE_SIZE NUMBER		{ current_ns->cache_size = $2; }
269 		| INDEX_CACHE_SIZE NUMBER	{ current_ns->index_cache_size = $2; }
270 		| FSYNC boolean			{ current_ns->sync = $2; }
271 		| aci				{
272 			SIMPLEQ_INSERT_TAIL(&current_ns->acl, $1, entry);
273 		}
274 		| RELAX SCHEMA			{ current_ns->relax = 1; }
275 		| STRICT SCHEMA			{ current_ns->relax = 0; }
276 		| USE COMPRESSION comp_level	{ current_ns->compression_level = $3; }
277 		| REFERRAL STRING		{
278 			struct referral	*ref;
279 			if ((ref = calloc(1, sizeof(*ref))) == NULL) {
280 				yyerror("calloc");
281 				free($2);
282 				YYERROR;
283 			}
284 			ref->url = $2;
285 			SLIST_INSERT_HEAD(&current_ns->referrals, ref, next);
286 		}
287 		;
288 
289 comp_level	: /* empty */			{ $$ = 6; }
290 		| LEVEL NUMBER			{ $$ = $2; }
291 		;
292 
293 aci		: aci_type aci_access TO aci_scope aci_target aci_subject {
294 			if (($$ = mk_aci($1, $2, $4, $5, $6)) == NULL) {
295 				free($5);
296 				free($6);
297 				YYERROR;
298 			}
299 		}
300 		| aci_type aci_access {
301 			if (($$ = mk_aci($1, $2, LDAP_SCOPE_SUBTREE, NULL,
302 			    NULL)) == NULL) {
303 				YYERROR;
304 			}
305 		}
306 		;
307 
308 aci_type	: DENY				{ $$ = ACI_DENY; }
309 		| ALLOW				{ $$ = ACI_ALLOW; }
310 		;
311 
312 aci_access	: /* empty */			{ $$ = ACI_ALL; }
313 		| ACCESS			{ $$ = ACI_ALL; }
314 		| aci_rights ACCESS		{ $$ = $1; }
315 		;
316 
317 aci_rights	: aci_right			{ $$ = $1; }
318 		| aci_rights ',' aci_right	{ $$ = $1 | $3; }
319 		;
320 
321 aci_right	: READ				{ $$ = ACI_READ; }
322 		| WRITE				{ $$ = ACI_WRITE; }
323 		| BIND				{ $$ = ACI_BIND; }
324 		;
325 
326 
327 aci_scope	: /* empty */			{ $$ = LDAP_SCOPE_BASE; }
328 		| SUBTREE			{ $$ = LDAP_SCOPE_SUBTREE; }
329 		| CHILDREN OF			{ $$ = LDAP_SCOPE_ONELEVEL; }
330 		;
331 
332 aci_target	: ANY				{ $$ = NULL; }
333 		| ROOT				{ $$ = strdup(""); }
334 		| STRING			{ $$ = $1; normalize_dn($$); }
335 		;
336 
337 aci_subject	: /* empty */			{ $$ = NULL; }
338 		| BY ANY			{ $$ = NULL; }
339 		| BY STRING			{ $$ = $2; normalize_dn($$); }
340 		| BY SELF			{ $$ = strdup("@"); }
341 		;
342 
343 include		: INCLUDE STRING		{
344 			struct file	*nfile;
345 
346 			if ((nfile = pushfile($2, 1)) == NULL) {
347 				yyerror("failed to include file %s", $2);
348 				free($2);
349 				YYERROR;
350 			}
351 			free($2);
352 
353 			file = nfile;
354 			lungetc('\n');
355 		}
356 		;
357 
358 varset		: STRING '=' STRING		{
359 			if (symset($1, $3, 0) == -1)
360 				fatal("cannot store variable");
361 			free($1);
362 			free($3);
363 		}
364 		;
365 
366 schema		: SCHEMA STRING			{
367 			int	 ret;
368 
369 			ret = schema_parse(conf->schema, $2);
370 			free($2);
371 			if (ret != 0) {
372 				YYERROR;
373 			}
374 		}
375 		;
376 
377 %%
378 
379 struct keywords {
380 	const char	*k_name;
381 	int		 k_val;
382 };
383 
384 int
385 yyerror(const char *fmt, ...)
386 {
387 	va_list		 ap;
388 	char		*msg;
389 
390 	file->errors++;
391 	va_start(ap, fmt);
392 	if (vasprintf(&msg, fmt, ap) == -1)
393 		fatalx("yyerror vasprintf");
394 	va_end(ap);
395 	logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
396 	free(msg);
397 	return (0);
398 }
399 
400 int
401 kw_cmp(const void *k, const void *e)
402 {
403 	return (strcmp(k, ((const struct keywords *)e)->k_name));
404 }
405 
406 int
407 lookup(char *s)
408 {
409 	/* this has to be sorted always */
410 	static const struct keywords keywords[] = {
411 		{ "access",		ACCESS },
412 		{ "allow",		ALLOW },
413 		{ "any",		ANY },
414 		{ "bind",		BIND },
415 		{ "by",			BY },
416 		{ "cache-size",		CACHE_SIZE },
417 		{ "certificate",	CERTIFICATE },
418 		{ "children",		CHILDREN },
419 		{ "compression",	COMPRESSION },
420 		{ "deny",		DENY },
421 		{ "fsync",		FSYNC },
422 		{ "in",			IN },
423 		{ "include",		INCLUDE },
424 		{ "index",		INDEX },
425 		{ "index-cache-size",	INDEX_CACHE_SIZE },
426 		{ "ldaps",		LDAPS },
427 		{ "level",		LEVEL },
428 		{ "listen",		LISTEN },
429 		{ "namespace",		NAMESPACE },
430 		{ "of",			OF },
431 		{ "on",			ON },
432 		{ "port",		PORT },
433 		{ "read",		READ },
434 		{ "referral",		REFERRAL },
435 		{ "relax",		RELAX },
436 		{ "root",		ROOT },
437 		{ "rootdn",		ROOTDN },
438 		{ "rootpw",		ROOTPW },
439 		{ "schema",		SCHEMA },
440 		{ "secure",		SECURE },
441 		{ "self",		SELF },
442 		{ "strict",		STRICT },
443 		{ "subtree",		SUBTREE },
444 		{ "tls",		TLS },
445 		{ "to",			TO },
446 		{ "use",		USE },
447 		{ "write",		WRITE },
448 
449 	};
450 	const struct keywords	*p;
451 
452 	p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
453 	    sizeof(keywords[0]), kw_cmp);
454 
455 	if (p)
456 		return (p->k_val);
457 	else
458 		return (STRING);
459 }
460 
461 #define MAXPUSHBACK	128
462 
463 u_char	*parsebuf;
464 int	 parseindex;
465 u_char	 pushback_buffer[MAXPUSHBACK];
466 int	 pushback_index = 0;
467 
468 int
469 lgetc(int quotec)
470 {
471 	int		c, next;
472 
473 	if (parsebuf) {
474 		/* Read character from the parsebuffer instead of input. */
475 		if (parseindex >= 0) {
476 			c = parsebuf[parseindex++];
477 			if (c != '\0')
478 				return (c);
479 			parsebuf = NULL;
480 		} else
481 			parseindex++;
482 	}
483 
484 	if (pushback_index)
485 		return (pushback_buffer[--pushback_index]);
486 
487 	if (quotec) {
488 		if ((c = getc(file->stream)) == EOF) {
489 			yyerror("reached end of file while parsing "
490 			    "quoted string");
491 			if (file == topfile || popfile() == EOF)
492 				return (EOF);
493 			return (quotec);
494 		}
495 		return (c);
496 	}
497 
498 	while ((c = getc(file->stream)) == '\\') {
499 		next = getc(file->stream);
500 		if (next != '\n') {
501 			c = next;
502 			break;
503 		}
504 		yylval.lineno = file->lineno;
505 		file->lineno++;
506 	}
507 
508 	while (c == EOF) {
509 		if (file == topfile || popfile() == EOF)
510 			return (EOF);
511 		c = getc(file->stream);
512 	}
513 	return (c);
514 }
515 
516 int
517 lungetc(int c)
518 {
519 	if (c == EOF)
520 		return (EOF);
521 	if (parsebuf) {
522 		parseindex--;
523 		if (parseindex >= 0)
524 			return (c);
525 	}
526 	if (pushback_index < MAXPUSHBACK-1)
527 		return (pushback_buffer[pushback_index++] = c);
528 	else
529 		return (EOF);
530 }
531 
532 int
533 findeol(void)
534 {
535 	int	c;
536 
537 	parsebuf = NULL;
538 
539 	/* skip to either EOF or the first real EOL */
540 	while (1) {
541 		if (pushback_index)
542 			c = pushback_buffer[--pushback_index];
543 		else
544 			c = lgetc(0);
545 		if (c == '\n') {
546 			file->lineno++;
547 			break;
548 		}
549 		if (c == EOF)
550 			break;
551 	}
552 	return (ERROR);
553 }
554 
555 int
556 yylex(void)
557 {
558 	u_char	 buf[4096];
559 	u_char	*p, *val;
560 	int	 quotec, next, c;
561 	int	 token;
562 
563 top:
564 	p = buf;
565 	while ((c = lgetc(0)) == ' ' || c == '\t')
566 		; /* nothing */
567 
568 	yylval.lineno = file->lineno;
569 	if (c == '#')
570 		while ((c = lgetc(0)) != '\n' && c != EOF)
571 			; /* nothing */
572 	if (c == '$' && parsebuf == NULL) {
573 		while (1) {
574 			if ((c = lgetc(0)) == EOF)
575 				return (0);
576 
577 			if (p + 1 >= buf + sizeof(buf) - 1) {
578 				yyerror("string too long");
579 				return (findeol());
580 			}
581 			if (isalnum(c) || c == '_') {
582 				*p++ = c;
583 				continue;
584 			}
585 			*p = '\0';
586 			lungetc(c);
587 			break;
588 		}
589 		val = symget(buf);
590 		if (val == NULL) {
591 			yyerror("macro '%s' not defined", buf);
592 			return (findeol());
593 		}
594 		parsebuf = val;
595 		parseindex = 0;
596 		goto top;
597 	}
598 
599 	switch (c) {
600 	case '\'':
601 	case '"':
602 		quotec = c;
603 		while (1) {
604 			if ((c = lgetc(quotec)) == EOF)
605 				return (0);
606 			if (c == '\n') {
607 				file->lineno++;
608 				continue;
609 			} else if (c == '\\') {
610 				if ((next = lgetc(quotec)) == EOF)
611 					return (0);
612 				if (next == quotec || c == ' ' || c == '\t')
613 					c = next;
614 				else if (next == '\n') {
615 					file->lineno++;
616 					continue;
617 				} else
618 					lungetc(next);
619 			} else if (c == quotec) {
620 				*p = '\0';
621 				break;
622 			} else if (c == '\0') {
623 				yyerror("syntax error");
624 				return (findeol());
625 			}
626 			if (p + 1 >= buf + sizeof(buf) - 1) {
627 				log_warnx("string too long");
628 				return (findeol());
629 			}
630 			*p++ = c;
631 		}
632 		yylval.v.string = strdup(buf);
633 		if (yylval.v.string == NULL)
634 			fatal("yylex: strdup");
635 		return (STRING);
636 	}
637 
638 #define allowed_to_end_number(x) \
639 	(isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
640 
641 	if (c == '-' || isdigit(c)) {
642 		do {
643 			*p++ = c;
644 			if ((unsigned)(p-buf) >= sizeof(buf)) {
645 				yyerror("string too long");
646 				return (findeol());
647 			}
648 		} while ((c = lgetc(0)) != EOF && isdigit(c));
649 		lungetc(c);
650 		if (p == buf + 1 && buf[0] == '-')
651 			goto nodigits;
652 		if (c == EOF || allowed_to_end_number(c)) {
653 			const char *errstr = NULL;
654 
655 			*p = '\0';
656 			yylval.v.number = strtonum(buf, LLONG_MIN,
657 			    LLONG_MAX, &errstr);
658 			if (errstr) {
659 				yyerror("\"%s\" invalid number: %s",
660 				    buf, errstr);
661 				return (findeol());
662 			}
663 			return (NUMBER);
664 		} else {
665 nodigits:
666 			while (p > buf + 1)
667 				lungetc(*--p);
668 			c = *--p;
669 			if (c == '-')
670 				return (c);
671 		}
672 	}
673 
674 #define allowed_in_string(x) \
675 	(isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
676 	x != '{' && x != '}' && x != '<' && x != '>' && \
677 	x != '!' && x != '=' && x != '/' && x != '#' && \
678 	x != ','))
679 
680 	if (isalnum(c) || c == ':' || c == '_' || c == '*') {
681 		do {
682 			*p++ = c;
683 			if ((unsigned)(p-buf) >= sizeof(buf)) {
684 				yyerror("string too long");
685 				return (findeol());
686 			}
687 		} while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
688 		lungetc(c);
689 		*p = '\0';
690 		if ((token = lookup(buf)) == STRING)
691 			if ((yylval.v.string = strdup(buf)) == NULL)
692 				fatal("yylex: strdup");
693 		return (token);
694 	}
695 	if (c == '\n') {
696 		yylval.lineno = file->lineno;
697 		file->lineno++;
698 	}
699 	if (c == EOF)
700 		return (0);
701 	return (c);
702 }
703 
704 int
705 check_file_secrecy(int fd, const char *fname)
706 {
707 	struct stat	st;
708 
709 	if (fstat(fd, &st)) {
710 		log_warn("cannot stat %s", fname);
711 		return (-1);
712 	}
713 	if (st.st_uid != 0 && st.st_uid != getuid()) {
714 		log_warnx("%s: owner not root or current user", fname);
715 		return (-1);
716 	}
717 	if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
718 		log_warnx("%s: group writable or world read/writable", fname);
719 		return (-1);
720 	}
721 	return (0);
722 }
723 
724 struct file *
725 pushfile(const char *name, int secret)
726 {
727 	struct file	*nfile;
728 
729 	log_debug("parsing config %s", name);
730 
731 	if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
732 		log_warn("malloc");
733 		return (NULL);
734 	}
735 	if ((nfile->name = strdup(name)) == NULL) {
736 		log_warn("malloc");
737 		free(nfile);
738 		return (NULL);
739 	}
740 	if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
741 		log_warn("%s", nfile->name);
742 		free(nfile->name);
743 		free(nfile);
744 		return (NULL);
745 	}
746 	if (secret &&
747 	    check_file_secrecy(fileno(nfile->stream), nfile->name)) {
748 		fclose(nfile->stream);
749 		free(nfile->name);
750 		free(nfile);
751 		return (NULL);
752 	}
753 	nfile->lineno = 1;
754 	TAILQ_INSERT_TAIL(&files, nfile, entry);
755 	return (nfile);
756 }
757 
758 int
759 popfile(void)
760 {
761 	struct file	*prev;
762 
763 	if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
764 		prev->errors += file->errors;
765 
766 	TAILQ_REMOVE(&files, file, entry);
767 	fclose(file->stream);
768 	free(file->name);
769 	free(file);
770 	file = prev;
771 	return (file ? 0 : EOF);
772 }
773 
774 int
775 parse_config(char *filename)
776 {
777 	struct sym		*sym, *next;
778 	int			 errors = 0;
779 
780 	if ((conf = calloc(1, sizeof(struct ldapd_config))) == NULL)
781 		fatal(NULL);
782 
783 	conf->schema = schema_new();
784 	if (conf->schema == NULL)
785 		fatal("schema_new");
786 
787 	TAILQ_INIT(&conf->namespaces);
788 	TAILQ_INIT(&conf->listeners);
789 	if ((conf->sc_ssl = calloc(1, sizeof(*conf->sc_ssl))) == NULL)
790 		fatal(NULL);
791 	SPLAY_INIT(conf->sc_ssl);
792 	SIMPLEQ_INIT(&conf->acl);
793 	SLIST_INIT(&conf->referrals);
794 
795 	if ((file = pushfile(filename, 1)) == NULL) {
796 		free(conf);
797 		return (-1);
798 	}
799 	topfile = file;
800 
801 	yyparse();
802 	errors = file->errors;
803 	popfile();
804 
805 	/* Free macros and check which have not been used. */
806 	for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
807 		next = TAILQ_NEXT(sym, entry);
808 		log_debug("warning: macro \"%s\" not used", sym->nam);
809 		if (!sym->persist) {
810 			free(sym->nam);
811 			free(sym->val);
812 			TAILQ_REMOVE(&symhead, sym, entry);
813 			free(sym);
814 		}
815 	}
816 
817 	return (errors ? -1 : 0);
818 }
819 
820 int
821 symset(const char *nam, const char *val, int persist)
822 {
823 	struct sym	*sym;
824 
825 	for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
826 	    sym = TAILQ_NEXT(sym, entry))
827 		;	/* nothing */
828 
829 	if (sym != NULL) {
830 		if (sym->persist == 1)
831 			return (0);
832 		else {
833 			free(sym->nam);
834 			free(sym->val);
835 			TAILQ_REMOVE(&symhead, sym, entry);
836 			free(sym);
837 		}
838 	}
839 	if ((sym = calloc(1, sizeof(*sym))) == NULL)
840 		return (-1);
841 
842 	sym->nam = strdup(nam);
843 	if (sym->nam == NULL) {
844 		free(sym);
845 		return (-1);
846 	}
847 	sym->val = strdup(val);
848 	if (sym->val == NULL) {
849 		free(sym->nam);
850 		free(sym);
851 		return (-1);
852 	}
853 	sym->used = 0;
854 	sym->persist = persist;
855 	TAILQ_INSERT_TAIL(&symhead, sym, entry);
856 	return (0);
857 }
858 
859 int
860 cmdline_symset(char *s)
861 {
862 	char	*sym, *val;
863 	int	ret;
864 	size_t	len;
865 
866 	if ((val = strrchr(s, '=')) == NULL)
867 		return (-1);
868 
869 	len = strlen(s) - strlen(val) + 1;
870 	if ((sym = malloc(len)) == NULL)
871 		fatal("cmdline_symset: malloc");
872 
873 	strlcpy(sym, s, len);
874 
875 	ret = symset(sym, val + 1, 1);
876 	free(sym);
877 
878 	return (ret);
879 }
880 
881 char *
882 symget(const char *nam)
883 {
884 	struct sym	*sym;
885 
886 	TAILQ_FOREACH(sym, &symhead, entry)
887 		if (strcmp(nam, sym->nam) == 0) {
888 			sym->used = 1;
889 			return (sym->val);
890 		}
891 	return (NULL);
892 }
893 
894 struct listener *
895 host_unix(const char *path)
896 {
897 	struct sockaddr_un	*saun;
898 	struct listener		*h;
899 
900 	if (*path != '/')
901 		return (NULL);
902 
903 	if ((h = calloc(1, sizeof(*h))) == NULL)
904 		fatal(NULL);
905 	saun = (struct sockaddr_un *)&h->ss;
906 	saun->sun_len = sizeof(struct sockaddr_un);
907 	saun->sun_family = AF_UNIX;
908 	if (strlcpy(saun->sun_path, path, sizeof(saun->sun_path)) >=
909 	    sizeof(saun->sun_path))
910 		fatal("socket path too long");
911 	h->flags = F_SECURE;
912 
913 	return (h);
914 }
915 
916 struct listener *
917 host_v4(const char *s, in_port_t port)
918 {
919 	struct in_addr		 ina;
920 	struct sockaddr_in	*sain;
921 	struct listener		*h;
922 
923 	bzero(&ina, sizeof(ina));
924 	if (inet_pton(AF_INET, s, &ina) != 1)
925 		return (NULL);
926 
927 	if ((h = calloc(1, sizeof(*h))) == NULL)
928 		fatal(NULL);
929 	sain = (struct sockaddr_in *)&h->ss;
930 	sain->sin_len = sizeof(struct sockaddr_in);
931 	sain->sin_family = AF_INET;
932 	sain->sin_addr.s_addr = ina.s_addr;
933 	sain->sin_port = port;
934 
935 	return (h);
936 }
937 
938 struct listener *
939 host_v6(const char *s, in_port_t port)
940 {
941 	struct in6_addr		 ina6;
942 	struct sockaddr_in6	*sin6;
943 	struct listener		*h;
944 
945 	bzero(&ina6, sizeof(ina6));
946 	if (inet_pton(AF_INET6, s, &ina6) != 1)
947 		return (NULL);
948 
949 	if ((h = calloc(1, sizeof(*h))) == NULL)
950 		fatal(NULL);
951 	sin6 = (struct sockaddr_in6 *)&h->ss;
952 	sin6->sin6_len = sizeof(struct sockaddr_in6);
953 	sin6->sin6_family = AF_INET6;
954 	sin6->sin6_port = port;
955 	memcpy(&sin6->sin6_addr, &ina6, sizeof(ina6));
956 
957 	return (h);
958 }
959 
960 int
961 host_dns(const char *s, const char *cert,
962     struct listenerlist *al, int max, in_port_t port, u_int8_t flags)
963 {
964 	struct addrinfo		 hints, *res0, *res;
965 	int			 error, cnt = 0;
966 	struct sockaddr_in	*sain;
967 	struct sockaddr_in6	*sin6;
968 	struct listener		*h;
969 
970 	bzero(&hints, sizeof(hints));
971 	hints.ai_family = PF_UNSPEC;
972 	hints.ai_socktype = SOCK_DGRAM; /* DUMMY */
973 	error = getaddrinfo(s, NULL, &hints, &res0);
974 	if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME)
975 		return (0);
976 	if (error) {
977 		log_warnx("host_dns: could not parse \"%s\": %s", s,
978 		    gai_strerror(error));
979 		return (-1);
980 	}
981 
982 	for (res = res0; res && cnt < max; res = res->ai_next) {
983 		if (res->ai_family != AF_INET &&
984 		    res->ai_family != AF_INET6)
985 			continue;
986 		if ((h = calloc(1, sizeof(*h))) == NULL)
987 			fatal(NULL);
988 
989 		h->port = port;
990 		h->flags = flags;
991 		h->ss.ss_family = res->ai_family;
992 		h->ssl = NULL;
993 		h->ssl_cert_name[0] = '\0';
994 		if (cert != NULL)
995 			(void)strlcpy(h->ssl_cert_name, cert, sizeof(h->ssl_cert_name));
996 
997 		if (res->ai_family == AF_INET) {
998 			sain = (struct sockaddr_in *)&h->ss;
999 			sain->sin_len = sizeof(struct sockaddr_in);
1000 			sain->sin_addr.s_addr = ((struct sockaddr_in *)
1001 			    res->ai_addr)->sin_addr.s_addr;
1002 			sain->sin_port = port;
1003 		} else {
1004 			sin6 = (struct sockaddr_in6 *)&h->ss;
1005 			sin6->sin6_len = sizeof(struct sockaddr_in6);
1006 			memcpy(&sin6->sin6_addr, &((struct sockaddr_in6 *)
1007 			    res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
1008 			sin6->sin6_port = port;
1009 		}
1010 
1011 		TAILQ_INSERT_HEAD(al, h, entry);
1012 		cnt++;
1013 	}
1014 	if (cnt == max && res) {
1015 		log_warnx("host_dns: %s resolves to more than %d hosts",
1016 		    s, max);
1017 	}
1018 	freeaddrinfo(res0);
1019 	return (cnt);
1020 }
1021 
1022 int
1023 host(const char *s, const char *cert, struct listenerlist *al,
1024     int max, in_port_t port, u_int8_t flags)
1025 {
1026 	struct listener *h;
1027 
1028 	/* Unix socket path? */
1029 	h = host_unix(s);
1030 
1031 	/* IPv4 address? */
1032 	if (h == NULL)
1033 		h = host_v4(s, port);
1034 
1035 	/* IPv6 address? */
1036 	if (h == NULL)
1037 		h = host_v6(s, port);
1038 
1039 	if (h != NULL) {
1040 		h->port = port;
1041 		h->flags |= flags;
1042 		h->ssl = NULL;
1043 		h->ssl_cert_name[0] = '\0';
1044 		if (cert != NULL)
1045 			strlcpy(h->ssl_cert_name, cert, sizeof(h->ssl_cert_name));
1046 
1047 		TAILQ_INSERT_HEAD(al, h, entry);
1048 		return (1);
1049 	}
1050 
1051 	return (host_dns(s, cert, al, max, port, flags));
1052 }
1053 
1054 int
1055 interface(const char *s, const char *cert,
1056     struct listenerlist *al, int max, in_port_t port, u_int8_t flags)
1057 {
1058 	int			 ret = 0;
1059 	struct ifaddrs		*ifap, *p;
1060 	struct sockaddr_in	*sain;
1061 	struct sockaddr_in6	*sin6;
1062 	struct listener		*h;
1063 
1064 	if (getifaddrs(&ifap) == -1)
1065 		fatal("getifaddrs");
1066 
1067 	for (p = ifap; p != NULL; p = p->ifa_next) {
1068 		if (strcmp(s, p->ifa_name) != 0)
1069 			continue;
1070 
1071 		switch (p->ifa_addr->sa_family) {
1072 		case AF_INET:
1073 			if ((h = calloc(1, sizeof(*h))) == NULL)
1074 				fatal(NULL);
1075 			sain = (struct sockaddr_in *)&h->ss;
1076 			*sain = *(struct sockaddr_in *)p->ifa_addr;
1077 			sain->sin_len = sizeof(struct sockaddr_in);
1078 			sain->sin_port = port;
1079 
1080 			h->fd = -1;
1081 			h->port = port;
1082 			h->flags = flags;
1083 			h->ssl = NULL;
1084 			h->ssl_cert_name[0] = '\0';
1085 			if (cert != NULL)
1086 				(void)strlcpy(h->ssl_cert_name, cert, sizeof(h->ssl_cert_name));
1087 
1088 			ret = 1;
1089 			TAILQ_INSERT_HEAD(al, h, entry);
1090 
1091 			break;
1092 
1093 		case AF_INET6:
1094 			if ((h = calloc(1, sizeof(*h))) == NULL)
1095 				fatal(NULL);
1096 			sin6 = (struct sockaddr_in6 *)&h->ss;
1097 			*sin6 = *(struct sockaddr_in6 *)p->ifa_addr;
1098 			sin6->sin6_len = sizeof(struct sockaddr_in6);
1099 			sin6->sin6_port = port;
1100 
1101 			h->fd = -1;
1102 			h->port = port;
1103 			h->flags = flags;
1104 			h->ssl = NULL;
1105 			h->ssl_cert_name[0] = '\0';
1106 			if (cert != NULL)
1107 				(void)strlcpy(h->ssl_cert_name, cert, sizeof(h->ssl_cert_name));
1108 
1109 			ret = 1;
1110 			TAILQ_INSERT_HEAD(al, h, entry);
1111 
1112 			break;
1113 		}
1114 	}
1115 
1116 	freeifaddrs(ifap);
1117 
1118 	return ret;
1119 }
1120 
1121 static struct aci *
1122 mk_aci(int type, int rights, enum scope scope, char *target, char *subject)
1123 {
1124 	struct aci	*aci;
1125 
1126 	if ((aci = calloc(1, sizeof(*aci))) == NULL) {
1127 		yyerror("calloc");
1128 		return NULL;
1129 	}
1130 	aci->type = type;
1131 	aci->rights = rights;
1132 	aci->scope = scope;
1133 	aci->target = target;
1134 	aci->subject = subject;
1135 
1136 	log_debug("%s %02X access to %s scope %d by %s",
1137 	    aci->type == ACI_DENY ? "deny" : "allow",
1138 	    aci->rights,
1139 	    aci->target ? aci->target : "any",
1140 	    aci->scope,
1141 	    aci->subject ? aci->subject : "any");
1142 
1143 	return aci;
1144 }
1145 
1146 struct namespace *
1147 namespace_new(const char *suffix)
1148 {
1149 	struct namespace		*ns;
1150 
1151 	if ((ns = calloc(1, sizeof(*ns))) == NULL)
1152 		return NULL;
1153 	ns->suffix = strdup(suffix);
1154 	ns->sync = 1;
1155 	ns->cache_size = 1024;
1156 	ns->index_cache_size = 512;
1157 	if (ns->suffix == NULL) {
1158 		free(ns->suffix);
1159 		free(ns);
1160 		return NULL;
1161 	}
1162 	TAILQ_INIT(&ns->indices);
1163 	TAILQ_INIT(&ns->request_queue);
1164 	SIMPLEQ_INIT(&ns->acl);
1165 	SLIST_INIT(&ns->referrals);
1166 
1167 	return ns;
1168 }
1169 
1170