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