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