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