1 /* $OpenBSD: parse.y,v 1.36 2020/06/24 07:20:47 tb Exp $ */ 2 3 /* 4 * Copyright (c) 2009, 2010 Martin Hedenfalk <martinh@openbsd.org> 5 * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> 6 * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> 7 * Copyright (c) 2001 Markus Friedl. All rights reserved. 8 * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. 9 * Copyright (c) 2001 Theo de Raadt. All rights reserved. 10 * 11 * Permission to use, copy, modify, and distribute this software for any 12 * purpose with or without fee is hereby granted, provided that the above 13 * copyright notice and this permission notice appear in all copies. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 21 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 */ 23 24 %{ 25 #include <sys/types.h> 26 #include <sys/queue.h> 27 #include <sys/tree.h> 28 #include <sys/socket.h> 29 #include <sys/stat.h> 30 #include <sys/un.h> 31 #include <netinet/in.h> 32 #include <arpa/inet.h> 33 34 #include <ctype.h> 35 #include <err.h> 36 #include <errno.h> 37 #include <ifaddrs.h> 38 #include <limits.h> 39 #include <netdb.h> 40 #include <stdarg.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <syslog.h> 45 #include <unistd.h> 46 47 #include "ldapd.h" 48 #include "log.h" 49 50 TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); 51 static struct file { 52 TAILQ_ENTRY(file) entry; 53 FILE *stream; 54 char *name; 55 size_t ungetpos; 56 size_t ungetsize; 57 u_char *ungetbuf; 58 int eof_reached; 59 int lineno; 60 int errors; 61 } *file, *topfile; 62 struct file *pushfile(const char *, int); 63 int popfile(void); 64 int check_file_secrecy(int, const char *); 65 int yyparse(void); 66 int yylex(void); 67 int yyerror(const char *, ...) 68 __attribute__((__format__ (printf, 1, 2))) 69 __attribute__((__nonnull__ (1))); 70 int kw_cmp(const void *, const void *); 71 int lookup(char *); 72 int igetc(void); 73 int lgetc(int); 74 void lungetc(int); 75 int findeol(void); 76 77 struct listener *host_unix(const char *path); 78 struct listener *host_v4(const char *, in_port_t); 79 struct listener *host_v6(const char *, in_port_t); 80 int host_dns(const char *, const char *, 81 struct listenerlist *, int, in_port_t, u_int8_t); 82 int host(const char *, const char *, 83 struct listenerlist *, int, in_port_t, u_int8_t); 84 int interface(const char *, const char *, 85 struct listenerlist *, int, in_port_t, u_int8_t); 86 int load_certfile(struct ldapd_config *, const char *, u_int8_t, 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 MAX_LISTEN, $4, $5)) { 209 if (host($3, cert, &conf->listeners, 210 MAX_LISTEN, $4, $5) <= 0) { 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 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 431 kw_cmp(const void *k, const void *e) 432 { 433 return (strcmp(k, ((const struct keywords *)e)->k_name)); 434 } 435 436 int 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 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 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 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 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 599 yylex(void) 600 { 601 u_char buf[4096]; 602 u_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(*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(*--p); 717 c = *--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 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 * 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 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 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 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 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 * 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 * 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 * 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 * 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 1016 host_dns(const char *s, const char *cert, 1017 struct listenerlist *al, int max, in_port_t port, u_int8_t flags) 1018 { 1019 struct addrinfo hints, *res0, *res; 1020 int error, cnt = 0; 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 && cnt < max; 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 cnt++; 1068 } 1069 if (cnt == max && res) { 1070 log_warnx("host_dns: %s resolves to more than %d hosts", 1071 s, max); 1072 } 1073 freeaddrinfo(res0); 1074 return (cnt); 1075 } 1076 1077 int 1078 host(const char *s, const char *cert, struct listenerlist *al, 1079 int max, in_port_t port, u_int8_t flags) 1080 { 1081 struct listener *h; 1082 1083 /* Unix socket path? */ 1084 h = host_unix(s); 1085 1086 /* IPv4 address? */ 1087 if (h == NULL) 1088 h = host_v4(s, port); 1089 1090 /* IPv6 address? */ 1091 if (h == NULL) 1092 h = host_v6(s, port); 1093 1094 if (h != NULL) { 1095 h->port = port; 1096 h->flags |= flags; 1097 h->ssl = NULL; 1098 h->ssl_cert_name[0] = '\0'; 1099 if (cert != NULL) 1100 strlcpy(h->ssl_cert_name, cert, sizeof(h->ssl_cert_name)); 1101 1102 TAILQ_INSERT_HEAD(al, h, entry); 1103 return (1); 1104 } 1105 1106 return (host_dns(s, cert, al, max, port, flags)); 1107 } 1108 1109 int 1110 interface(const char *s, const char *cert, 1111 struct listenerlist *al, int max, in_port_t port, u_int8_t flags) 1112 { 1113 int ret = 0; 1114 struct ifaddrs *ifap, *p; 1115 struct sockaddr_in *sain; 1116 struct sockaddr_in6 *sin6; 1117 struct listener *h; 1118 1119 if (getifaddrs(&ifap) == -1) 1120 fatal("getifaddrs"); 1121 1122 for (p = ifap; p != NULL; p = p->ifa_next) { 1123 if (strcmp(s, p->ifa_name) != 0) 1124 continue; 1125 1126 switch (p->ifa_addr->sa_family) { 1127 case AF_INET: 1128 if ((h = calloc(1, sizeof(*h))) == NULL) 1129 fatal(NULL); 1130 sain = (struct sockaddr_in *)&h->ss; 1131 *sain = *(struct sockaddr_in *)p->ifa_addr; 1132 sain->sin_len = sizeof(struct sockaddr_in); 1133 sain->sin_port = port; 1134 1135 h->fd = -1; 1136 h->port = port; 1137 h->flags = flags; 1138 h->ssl = NULL; 1139 h->ssl_cert_name[0] = '\0'; 1140 if (cert != NULL) 1141 (void)strlcpy(h->ssl_cert_name, cert, sizeof(h->ssl_cert_name)); 1142 1143 ret = 1; 1144 TAILQ_INSERT_HEAD(al, h, entry); 1145 1146 break; 1147 1148 case AF_INET6: 1149 if ((h = calloc(1, sizeof(*h))) == NULL) 1150 fatal(NULL); 1151 sin6 = (struct sockaddr_in6 *)&h->ss; 1152 *sin6 = *(struct sockaddr_in6 *)p->ifa_addr; 1153 sin6->sin6_len = sizeof(struct sockaddr_in6); 1154 sin6->sin6_port = port; 1155 1156 h->fd = -1; 1157 h->port = port; 1158 h->flags = flags; 1159 h->ssl = NULL; 1160 h->ssl_cert_name[0] = '\0'; 1161 if (cert != NULL) 1162 (void)strlcpy(h->ssl_cert_name, cert, sizeof(h->ssl_cert_name)); 1163 1164 ret = 1; 1165 TAILQ_INSERT_HEAD(al, h, entry); 1166 1167 break; 1168 } 1169 } 1170 1171 freeifaddrs(ifap); 1172 1173 return ret; 1174 } 1175 1176 static struct aci * 1177 mk_aci(int type, int rights, enum scope scope, char *target, char *attr, 1178 char *subject) 1179 { 1180 struct aci *aci; 1181 1182 if ((aci = calloc(1, sizeof(*aci))) == NULL) { 1183 yyerror("calloc"); 1184 return NULL; 1185 } 1186 aci->type = type; 1187 aci->rights = rights; 1188 aci->scope = scope; 1189 aci->target = target; 1190 aci->attribute = attr; 1191 aci->subject = subject; 1192 1193 log_debug("%s %02X access to %s%s%s scope %d by %s", 1194 aci->type == ACI_DENY ? "deny" : "allow", 1195 aci->rights, 1196 aci->target ? aci->target : "any", 1197 aci->attribute ? " attribute " : "", 1198 aci->attribute ? aci->attribute : "", 1199 aci->scope, 1200 aci->subject ? aci->subject : "any"); 1201 1202 return aci; 1203 } 1204 1205 struct namespace * 1206 namespace_new(const char *suffix) 1207 { 1208 struct namespace *ns; 1209 1210 if ((ns = calloc(1, sizeof(*ns))) == NULL) 1211 return NULL; 1212 ns->suffix = strdup(suffix); 1213 ns->sync = 1; 1214 ns->cache_size = 1024; 1215 ns->index_cache_size = 512; 1216 if (ns->suffix == NULL) { 1217 free(ns->suffix); 1218 free(ns); 1219 return NULL; 1220 } 1221 TAILQ_INIT(&ns->indices); 1222 TAILQ_INIT(&ns->request_queue); 1223 SIMPLEQ_INIT(&ns->acl); 1224 SLIST_INIT(&ns->referrals); 1225 1226 return ns; 1227 } 1228 1229 int 1230 ssl_cmp(struct ssl *s1, struct ssl *s2) 1231 { 1232 return (strcmp(s1->ssl_name, s2->ssl_name)); 1233 } 1234 1235 int 1236 load_certfile(struct ldapd_config *env, const char *name, u_int8_t flags, 1237 u_int8_t protocol) 1238 { 1239 struct ssl *s; 1240 struct ssl key; 1241 char certfile[PATH_MAX]; 1242 uint32_t tls_protocols = TLS_PROTOCOLS_DEFAULT; 1243 const char *tls_ciphers = "default"; 1244 1245 if (strlcpy(key.ssl_name, name, sizeof(key.ssl_name)) 1246 >= sizeof(key.ssl_name)) { 1247 log_warn("load_certfile: certificate name truncated"); 1248 return -1; 1249 } 1250 1251 s = SPLAY_FIND(ssltree, env->sc_ssl, &key); 1252 if (s != NULL) { 1253 s->flags |= flags; 1254 return 0; 1255 } 1256 1257 if ((s = calloc(1, sizeof(*s))) == NULL) 1258 fatal(NULL); 1259 1260 s->flags = flags; 1261 (void)strlcpy(s->ssl_name, key.ssl_name, sizeof(s->ssl_name)); 1262 1263 s->config = tls_config_new(); 1264 if (s->config == NULL) 1265 goto err; 1266 1267 if (protocol & F_LEGACY) { 1268 tls_protocols = TLS_PROTOCOLS_ALL; 1269 tls_ciphers = "all"; 1270 } 1271 if (tls_config_set_protocols(s->config, tls_protocols) != 0) { 1272 log_warn("load_certfile: failed to set tls protocols: %s", 1273 tls_config_error(s->config)); 1274 goto err; 1275 } 1276 if (tls_config_set_ciphers(s->config, tls_ciphers)) { 1277 log_warn("load_certfile: failed to set tls ciphers: %s", 1278 tls_config_error(s->config)); 1279 goto err; 1280 } 1281 1282 if ((name[0] == '/' && 1283 !bsnprintf(certfile, sizeof(certfile), "%s.crt", name)) || 1284 !bsnprintf(certfile, sizeof(certfile), "/etc/ldap/certs/%s.crt", 1285 name)) { 1286 log_warn("load_certfile: path truncated"); 1287 goto err; 1288 } 1289 1290 log_debug("loading certificate file %s", certfile); 1291 s->ssl_cert = tls_load_file(certfile, &s->ssl_cert_len, NULL); 1292 if (s->ssl_cert == NULL) 1293 goto err; 1294 1295 if (tls_config_set_cert_mem(s->config, s->ssl_cert, s->ssl_cert_len)) { 1296 log_warn("load_certfile: failed to set tls certificate: %s", 1297 tls_config_error(s->config)); 1298 goto err; 1299 } 1300 1301 if ((name[0] == '/' && 1302 !bsnprintf(certfile, sizeof(certfile), "%s.key", name)) || 1303 !bsnprintf(certfile, sizeof(certfile), "/etc/ldap/certs/%s.key", 1304 name)) { 1305 log_warn("load_certfile: path truncated"); 1306 goto err; 1307 } 1308 1309 log_debug("loading key file %s", certfile); 1310 s->ssl_key = tls_load_file(certfile, &s->ssl_key_len, NULL); 1311 if (s->ssl_key == NULL) 1312 goto err; 1313 1314 if (tls_config_set_key_mem(s->config, s->ssl_key, s->ssl_key_len)) { 1315 log_warn("load_certfile: failed to set tls key: %s", 1316 tls_config_error(s->config)); 1317 goto err; 1318 } 1319 1320 SPLAY_INSERT(ssltree, env->sc_ssl, s); 1321 1322 return (0); 1323 err: 1324 free(s->ssl_cert); 1325 free(s->ssl_key); 1326 tls_config_free(s->config); 1327 free(s); 1328 return (-1); 1329 } 1330