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