GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ldapctl/../ldapd/parse.y Lines: 0 477 0.0 %
Date: 2017-11-07 Branches: 0 360 0.0 %

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