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