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