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