1 /* $OpenBSD: parse.y,v 1.41 2009/10/19 20:00:46 gilles Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> 5 * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@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/time.h> 27 #include <sys/queue.h> 28 #include <sys/tree.h> 29 #include <sys/param.h> 30 #include <sys/socket.h> 31 #include <sys/stat.h> 32 33 #include <netinet/in.h> 34 #include <arpa/inet.h> 35 36 #include <ctype.h> 37 #include <err.h> 38 #include <errno.h> 39 #include <event.h> 40 #include <ifaddrs.h> 41 #include <limits.h> 42 #include <paths.h> 43 #include <pwd.h> 44 #include <netdb.h> 45 #include <stdarg.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <unistd.h> 50 51 #include "smtpd.h" 52 53 TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); 54 static struct file { 55 TAILQ_ENTRY(file) entry; 56 FILE *stream; 57 char *name; 58 int lineno; 59 int errors; 60 } *file, *topfile; 61 struct file *pushfile(const char *, int); 62 int popfile(void); 63 int check_file_secrecy(int, const char *); 64 int yyparse(void); 65 int yylex(void); 66 int kw_cmp(const void *, const void *); 67 int lookup(char *); 68 int lgetc(int); 69 int lungetc(int); 70 int findeol(void); 71 int yyerror(const char *, ...) 72 __attribute__ ((format (printf, 1, 2))); 73 74 TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); 75 struct sym { 76 TAILQ_ENTRY(sym) entry; 77 int used; 78 int persist; 79 char *nam; 80 char *val; 81 }; 82 int symset(const char *, const char *, int); 83 char *symget(const char *); 84 85 struct smtpd *conf = NULL; 86 static int errors = 0; 87 88 objid_t last_map_id = 0; 89 struct map *map = NULL; 90 struct rule *rule = NULL; 91 struct mapel_list *contents = NULL; 92 93 struct listener *host_v4(const char *, in_port_t); 94 struct listener *host_v6(const char *, in_port_t); 95 int host_dns(const char *, const char *, struct listenerlist *, 96 int, in_port_t, u_int8_t); 97 int host(const char *, const char *, struct listenerlist *, 98 int, in_port_t, u_int8_t); 99 int interface(const char *, const char *, struct listenerlist *, 100 int, in_port_t, u_int8_t); 101 void set_localaddrs(void); 102 103 typedef struct { 104 union { 105 int64_t number; 106 objid_t object; 107 struct timeval tv; 108 struct cond *cond; 109 char *string; 110 struct host *host; 111 } v; 112 int lineno; 113 } YYSTYPE; 114 115 %} 116 117 %token QUEUE INTERVAL LISTEN ON ALL PORT 118 %token MAP TYPE HASH LIST SINGLE SSL SMTPS CERTIFICATE 119 %token DNS DB TFILE EXTERNAL DOMAIN CONFIG SOURCE 120 %token RELAY VIA DELIVER TO MAILDIR MBOX HOSTNAME 121 %token ACCEPT REJECT INCLUDE NETWORK ERROR MDA FROM FOR 122 %token ARROW ENABLE AUTH TLS LOCAL VIRTUAL USER 123 %token <v.string> STRING 124 %token <v.number> NUMBER 125 %type <v.map> map 126 %type <v.number> quantifier decision port from auth ssl 127 %type <v.cond> condition 128 %type <v.tv> interval 129 %type <v.object> mapref 130 %type <v.string> certname user 131 132 %% 133 134 grammar : /* empty */ 135 | grammar '\n' 136 | grammar include '\n' 137 | grammar varset '\n' 138 | grammar main '\n' 139 | grammar map '\n' 140 | grammar rule '\n' 141 | grammar error '\n' { file->errors++; } 142 ; 143 144 include : INCLUDE STRING { 145 struct file *nfile; 146 147 if ((nfile = pushfile($2, 0)) == NULL) { 148 yyerror("failed to include file %s", $2); 149 free($2); 150 YYERROR; 151 } 152 free($2); 153 154 file = nfile; 155 lungetc('\n'); 156 } 157 ; 158 159 varset : STRING '=' STRING { 160 if (symset($1, $3, 0) == -1) 161 fatal("cannot store variable"); 162 free($1); 163 free($3); 164 } 165 ; 166 167 comma : ',' 168 | nl 169 | /* empty */ 170 ; 171 172 optnl : '\n' optnl 173 | 174 ; 175 176 nl : '\n' optnl 177 ; 178 179 quantifier : /* empty */ { $$ = 1; } 180 | 'm' { $$ = 60; } 181 | 'h' { $$ = 3600; } 182 | 'd' { $$ = 86400; } 183 ; 184 185 interval : NUMBER quantifier { 186 if ($1 < 0) { 187 yyerror("invalid interval: %lld", $1); 188 YYERROR; 189 } 190 $$.tv_usec = 0; 191 $$.tv_sec = $1 * $2; 192 } 193 194 port : PORT STRING { 195 struct servent *servent; 196 197 servent = getservbyname($2, "tcp"); 198 if (servent == NULL) { 199 yyerror("port %s is invalid", $2); 200 free($2); 201 YYERROR; 202 } 203 $$ = servent->s_port; 204 free($2); 205 } 206 | PORT NUMBER { 207 if ($2 <= 0 || $2 >= (int)USHRT_MAX) { 208 yyerror("invalid port: %lld", $2); 209 YYERROR; 210 } 211 $$ = htons($2); 212 } 213 | /* empty */ { 214 $$ = 0; 215 } 216 ; 217 218 certname : CERTIFICATE STRING { 219 if (($$ = strdup($2)) == NULL) 220 fatal(NULL); 221 free($2); 222 } 223 | /* empty */ { $$ = NULL; } 224 ; 225 226 ssl : SMTPS { $$ = F_SMTPS; } 227 | TLS { $$ = F_STARTTLS; } 228 | SSL { $$ = F_SSL; } 229 | /* empty */ { $$ = 0; } 230 231 auth : ENABLE AUTH { $$ = 1; } 232 | /* empty */ { $$ = 0; } 233 ; 234 235 main : QUEUE INTERVAL interval { 236 conf->sc_qintval = $3; 237 } 238 | LISTEN ON STRING port ssl certname auth { 239 char *cert; 240 u_int8_t flags; 241 242 if ($5 == F_SSL) { 243 yyerror("syntax error"); 244 free($6); 245 free($3); 246 YYERROR; 247 } 248 249 if ($5 == 0 && ($6 != NULL || $7)) { 250 yyerror("error: must specify tls or smtps"); 251 free($6); 252 free($3); 253 YYERROR; 254 } 255 256 if ($4 == 0) { 257 if ($5 == F_SMTPS) 258 $4 = htons(465); 259 else 260 $4 = htons(25); 261 } 262 263 cert = ($6 != NULL) ? $6 : $3; 264 flags = $5; 265 266 if ($7) 267 flags |= F_AUTH; 268 269 if ($5 && ssl_load_certfile(conf, cert, F_SCERT) < 0) { 270 yyerror("cannot load certificate: %s", cert); 271 free($6); 272 free($3); 273 YYERROR; 274 } 275 276 if (! interface($3, cert, conf->sc_listeners, 277 MAX_LISTEN, $4, flags)) { 278 if (host($3, cert, conf->sc_listeners, 279 MAX_LISTEN, $4, flags) <= 0) { 280 yyerror("invalid virtual ip or interface: %s", $3); 281 free($6); 282 free($3); 283 YYERROR; 284 } 285 } 286 free($6); 287 free($3); 288 } 289 | HOSTNAME STRING { 290 if (strlcpy(conf->sc_hostname, $2, 291 sizeof(conf->sc_hostname)) >= 292 sizeof(conf->sc_hostname)) { 293 yyerror("hostname truncated"); 294 free($2); 295 YYERROR; 296 } 297 free($2); 298 } 299 ; 300 301 maptype : SINGLE { map->m_type = T_SINGLE; } 302 | LIST { map->m_type = T_LIST; } 303 | HASH { map->m_type = T_HASH; } 304 ; 305 306 mapsource : DNS { map->m_src = S_DNS; } 307 | TFILE { map->m_src = S_FILE; } 308 | DB STRING { 309 map->m_src = S_DB; 310 if (strlcpy(map->m_config, $2, sizeof(map->m_config)) 311 >= sizeof(map->m_config)) 312 err(1, "pathname too long"); 313 } 314 | EXTERNAL { map->m_src = S_EXT; } 315 ; 316 317 mapopt : TYPE maptype 318 | SOURCE mapsource 319 | CONFIG STRING { 320 } 321 ; 322 323 mapopts_l : mapopts_l mapopt nl 324 | mapopt optnl 325 ; 326 327 map : MAP STRING { 328 struct map *m; 329 330 TAILQ_FOREACH(m, conf->sc_maps, m_entry) 331 if (strcmp(m->m_name, $2) == 0) 332 break; 333 334 if (m != NULL) { 335 yyerror("map %s defined twice", $2); 336 free($2); 337 YYERROR; 338 } 339 if ((m = calloc(1, sizeof(*m))) == NULL) 340 fatal("out of memory"); 341 if (strlcpy(m->m_name, $2, sizeof(m->m_name)) >= 342 sizeof(m->m_name)) { 343 yyerror("map name truncated"); 344 free(m); 345 free($2); 346 YYERROR; 347 } 348 349 m->m_id = last_map_id++; 350 m->m_type = T_SINGLE; 351 352 if (m->m_id == INT_MAX) { 353 yyerror("too many maps defined"); 354 free($2); 355 free(m); 356 YYERROR; 357 } 358 map = m; 359 } '{' optnl mapopts_l '}' { 360 if (map->m_src == S_NONE) { 361 yyerror("map %s has no source defined", $2); 362 free(map); 363 map = NULL; 364 YYERROR; 365 } 366 if (strcmp(map->m_name, "aliases") == 0 || 367 strcmp(map->m_name, "virtual") == 0) { 368 if (map->m_src != S_DB) { 369 yyerror("map source must be db"); 370 free(map); 371 map = NULL; 372 YYERROR; 373 } 374 } 375 TAILQ_INSERT_TAIL(conf->sc_maps, map, m_entry); 376 map = NULL; 377 } 378 ; 379 380 keyval : STRING ARROW STRING { 381 struct mapel *me; 382 383 if ((me = calloc(1, sizeof(*me))) == NULL) 384 fatal("out of memory"); 385 386 if (strlcpy(me->me_key.med_string, $1, 387 sizeof(me->me_key.med_string)) >= 388 sizeof(me->me_key.med_string) || 389 strlcpy(me->me_val.med_string, $3, 390 sizeof(me->me_val.med_string)) >= 391 sizeof(me->me_val.med_string)) { 392 yyerror("map elements too long: %s, %s", 393 $1, $3); 394 free(me); 395 free($1); 396 free($3); 397 YYERROR; 398 } 399 free($1); 400 free($3); 401 402 TAILQ_INSERT_TAIL(contents, me, me_entry); 403 } 404 405 keyval_list : keyval 406 | keyval comma keyval_list 407 ; 408 409 stringel : STRING { 410 struct mapel *me; 411 int bits; 412 struct sockaddr_in ssin; 413 struct sockaddr_in6 ssin6; 414 415 if ((me = calloc(1, sizeof(*me))) == NULL) 416 fatal("out of memory"); 417 418 /* Attempt detection of $1 format */ 419 if (strchr($1, '/') != NULL) { 420 /* Dealing with a netmask */ 421 bzero(&ssin, sizeof(struct sockaddr_in)); 422 bits = inet_net_pton(AF_INET, $1, &ssin.sin_addr, sizeof(struct in_addr)); 423 if (bits != -1) { 424 ssin.sin_family = AF_INET; 425 me->me_key.med_addr.bits = bits; 426 me->me_key.med_addr.ss = *(struct sockaddr_storage *)&ssin; 427 me->me_key.med_addr.ss.ss_len = sizeof(struct sockaddr_in); 428 } 429 else { 430 bzero(&ssin6, sizeof(struct sockaddr_in6)); 431 bits = inet_net_pton(AF_INET6, $1, &ssin6.sin6_addr, sizeof(struct in6_addr)); 432 if (bits == -1) 433 err(1, "inet_net_pton"); 434 ssin6.sin6_family = AF_INET6; 435 me->me_key.med_addr.bits = bits; 436 me->me_key.med_addr.ss = *(struct sockaddr_storage *)&ssin6; 437 me->me_key.med_addr.ss.ss_len = sizeof(struct sockaddr_in6); 438 } 439 } 440 else { 441 /* IP address ? */ 442 if (inet_pton(AF_INET, $1, &ssin.sin_addr) == 1) { 443 ssin.sin_family = AF_INET; 444 me->me_key.med_addr.bits = 0; 445 me->me_key.med_addr.ss = *(struct sockaddr_storage *)&ssin; 446 me->me_key.med_addr.ss.ss_len = sizeof(struct sockaddr_in); 447 } 448 else if (inet_pton(AF_INET6, $1, &ssin6.sin6_addr) == 1) { 449 ssin6.sin6_family = AF_INET6; 450 me->me_key.med_addr.bits = 0; 451 me->me_key.med_addr.ss = *(struct sockaddr_storage *)&ssin6; 452 me->me_key.med_addr.ss.ss_len = sizeof(struct sockaddr_in6); 453 } 454 else { 455 /* either a hostname or a value unrelated to network */ 456 if (strlcpy(me->me_key.med_string, $1, 457 sizeof(me->me_key.med_string)) >= 458 sizeof(me->me_key.med_string)) { 459 yyerror("map element too long: %s", $1); 460 free(me); 461 free($1); 462 YYERROR; 463 } 464 } 465 } 466 free($1); 467 TAILQ_INSERT_TAIL(contents, me, me_entry); 468 } 469 ; 470 471 string_list : stringel 472 | stringel comma string_list 473 ; 474 475 mapref : STRING { 476 struct map *m; 477 struct mapel *me; 478 int bits; 479 struct sockaddr_in ssin; 480 struct sockaddr_in6 ssin6; 481 482 if ((m = calloc(1, sizeof(*m))) == NULL) 483 fatal("out of memory"); 484 m->m_id = last_map_id++; 485 if (m->m_id == INT_MAX) { 486 yyerror("too many maps defined"); 487 free(m); 488 YYERROR; 489 } 490 if (! bsnprintf(m->m_name, sizeof(m->m_name), 491 "<dynamic(%u)>", m->m_id)) 492 fatal("snprintf"); 493 m->m_flags |= F_DYNAMIC|F_USED; 494 m->m_type = T_SINGLE; 495 496 TAILQ_INIT(&m->m_contents); 497 498 if ((me = calloc(1, sizeof(*me))) == NULL) 499 fatal("out of memory"); 500 501 /* Attempt detection of $1 format */ 502 if (strchr($1, '/') != NULL) { 503 /* Dealing with a netmask */ 504 bzero(&ssin, sizeof(struct sockaddr_in)); 505 bits = inet_net_pton(AF_INET, $1, &ssin.sin_addr, sizeof(struct in_addr)); 506 if (bits != -1) { 507 ssin.sin_family = AF_INET; 508 me->me_key.med_addr.bits = bits; 509 me->me_key.med_addr.ss = *(struct sockaddr_storage *)&ssin; 510 me->me_key.med_addr.ss.ss_len = sizeof(struct sockaddr_in); 511 } 512 else { 513 bzero(&ssin6, sizeof(struct sockaddr_in6)); 514 bits = inet_net_pton(AF_INET6, $1, &ssin6.sin6_addr, sizeof(struct in6_addr)); 515 if (bits == -1) 516 err(1, "inet_net_pton"); 517 ssin6.sin6_family = AF_INET6; 518 me->me_key.med_addr.bits = bits; 519 me->me_key.med_addr.ss = *(struct sockaddr_storage *)&ssin6; 520 me->me_key.med_addr.ss.ss_len = sizeof(struct sockaddr_in6); 521 } 522 } 523 else { 524 /* IP address ? */ 525 if (inet_pton(AF_INET, $1, &ssin.sin_addr) == 1) { 526 ssin.sin_family = AF_INET; 527 me->me_key.med_addr.bits = 0; 528 me->me_key.med_addr.ss = *(struct sockaddr_storage *)&ssin; 529 me->me_key.med_addr.ss.ss_len = sizeof(struct sockaddr_in); 530 } 531 else if (inet_pton(AF_INET6, $1, &ssin6.sin6_addr) == 1) { 532 ssin6.sin6_family = AF_INET6; 533 me->me_key.med_addr.bits = 0; 534 me->me_key.med_addr.ss = *(struct sockaddr_storage *)&ssin6; 535 me->me_key.med_addr.ss.ss_len = sizeof(struct sockaddr_in6); 536 } 537 else { 538 /* either a hostname or a value unrelated to network */ 539 if (strlcpy(me->me_key.med_string, $1, 540 sizeof(me->me_key.med_string)) >= 541 sizeof(me->me_key.med_string)) { 542 yyerror("map element too long: %s", $1); 543 free(me); 544 free(m); 545 free($1); 546 YYERROR; 547 } 548 } 549 } 550 free($1); 551 552 TAILQ_INSERT_TAIL(&m->m_contents, me, me_entry); 553 TAILQ_INSERT_TAIL(conf->sc_maps, m, m_entry); 554 $$ = m->m_id; 555 } 556 | '(' { 557 struct map *m; 558 559 if ((m = calloc(1, sizeof(*m))) == NULL) 560 fatal("out of memory"); 561 562 m->m_id = last_map_id++; 563 if (m->m_id == INT_MAX) { 564 yyerror("too many maps defined"); 565 free(m); 566 YYERROR; 567 } 568 if (! bsnprintf(m->m_name, sizeof(m->m_name), 569 "<dynamic(%u)>", m->m_id)) 570 fatal("snprintf"); 571 m->m_flags |= F_DYNAMIC|F_USED; 572 m->m_type = T_LIST; 573 574 TAILQ_INIT(&m->m_contents); 575 contents = &m->m_contents; 576 map = m; 577 578 } string_list ')' { 579 TAILQ_INSERT_TAIL(conf->sc_maps, map, m_entry); 580 $$ = map->m_id; 581 } 582 | '{' { 583 struct map *m; 584 585 if ((m = calloc(1, sizeof(*m))) == NULL) 586 fatal("out of memory"); 587 588 m->m_id = last_map_id++; 589 if (m->m_id == INT_MAX) { 590 yyerror("too many maps defined"); 591 free(m); 592 YYERROR; 593 } 594 if (! bsnprintf(m->m_name, sizeof(m->m_name), 595 "<dynamic(%u)>", m->m_id)) 596 fatal("snprintf"); 597 m->m_flags |= F_DYNAMIC|F_USED; 598 m->m_type = T_HASH; 599 600 TAILQ_INIT(&m->m_contents); 601 contents = &m->m_contents; 602 map = m; 603 604 } keyval_list '}' { 605 TAILQ_INSERT_TAIL(conf->sc_maps, map, m_entry); 606 $$ = map->m_id; 607 } 608 | MAP STRING { 609 struct map *m; 610 611 if ((m = map_findbyname(conf, $2)) == NULL) { 612 yyerror("no such map: %s", $2); 613 free($2); 614 YYERROR; 615 } 616 free($2); 617 m->m_flags |= F_USED; 618 $$ = m->m_id; 619 } 620 ; 621 622 decision : ACCEPT { $$ = 1; } 623 | REJECT { $$ = 0; } 624 ; 625 626 condition : NETWORK mapref { 627 struct cond *c; 628 629 if ((c = calloc(1, sizeof *c)) == NULL) 630 fatal("out of memory"); 631 c->c_type = C_NET; 632 c->c_map = $2; 633 $$ = c; 634 } 635 | DOMAIN mapref { 636 struct cond *c; 637 638 if ((c = calloc(1, sizeof *c)) == NULL) 639 fatal("out of memory"); 640 c->c_type = C_DOM; 641 c->c_map = $2; 642 $$ = c; 643 } 644 | VIRTUAL MAP STRING { 645 struct cond *c; 646 struct map *m; 647 648 if ((m = map_findbyname(conf, $3)) == NULL) { 649 yyerror("no such map: %s", $3); 650 free($3); 651 YYERROR; 652 } 653 free($3); 654 m->m_flags |= F_USED; 655 656 657 if ((c = calloc(1, sizeof *c)) == NULL) 658 fatal("out of memory"); 659 c->c_type = C_VDOM; 660 c->c_map = m->m_id; 661 $$ = c; 662 } 663 | LOCAL { 664 struct cond *c; 665 struct map *m; 666 struct mapel *me; 667 668 if ((m = calloc(1, sizeof(*m))) == NULL) 669 fatal("out of memory"); 670 m->m_id = last_map_id++; 671 if (m->m_id == INT_MAX) { 672 yyerror("too many maps defined"); 673 free(m); 674 YYERROR; 675 } 676 if (! bsnprintf(m->m_name, sizeof(m->m_name), 677 "<dynamic(%u)>", m->m_id)) 678 fatal("snprintf"); 679 m->m_flags |= F_DYNAMIC|F_USED; 680 m->m_type = T_SINGLE; 681 682 TAILQ_INIT(&m->m_contents); 683 684 if ((me = calloc(1, sizeof(*me))) == NULL) 685 fatal("out of memory"); 686 687 (void)strlcpy(me->me_key.med_string, "localhost", 688 sizeof(me->me_key.med_string)); 689 TAILQ_INSERT_TAIL(&m->m_contents, me, me_entry); 690 691 if ((me = calloc(1, sizeof(*me))) == NULL) 692 fatal("out of memory"); 693 694 if (gethostname(me->me_key.med_string, 695 sizeof(me->me_key.med_string)) == -1) { 696 yyerror("gethostname() failed"); 697 free(me); 698 free(m); 699 YYERROR; 700 } 701 TAILQ_INSERT_TAIL(&m->m_contents, me, me_entry); 702 703 TAILQ_INSERT_TAIL(conf->sc_maps, m, m_entry); 704 705 if ((c = calloc(1, sizeof *c)) == NULL) 706 fatal("out of memory"); 707 c->c_type = C_DOM; 708 c->c_map = m->m_id; 709 710 $$ = c; 711 } 712 | ALL { 713 struct cond *c; 714 715 if ((c = calloc(1, sizeof *c)) == NULL) 716 fatal("out of memory"); 717 c->c_type = C_ALL; 718 $$ = c; 719 } 720 ; 721 722 condition_list : condition comma condition_list { 723 TAILQ_INSERT_TAIL(&rule->r_conditions, $1, c_entry); 724 } 725 | condition { 726 TAILQ_INSERT_TAIL(&rule->r_conditions, $1, c_entry); 727 } 728 ; 729 730 conditions : condition { 731 TAILQ_INSERT_TAIL(&rule->r_conditions, $1, c_entry); 732 } 733 | '{' condition_list '}' 734 ; 735 736 user : USER STRING { 737 struct passwd *pw; 738 739 pw = getpwnam($2); 740 if (pw == NULL) { 741 yyerror("user '%s' does not exist.", $2); 742 free($2); 743 YYERROR; 744 } 745 $$ = $2; 746 } 747 | /* empty */ { $$ = NULL; } 748 ; 749 750 action : DELIVER TO MAILDIR user { 751 rule->r_user = $4; 752 rule->r_action = A_MAILDIR; 753 if (strlcpy(rule->r_value.path, "~/Maildir", 754 sizeof(rule->r_value.path)) >= 755 sizeof(rule->r_value.path)) 756 fatal("pathname too long"); 757 } 758 | DELIVER TO MAILDIR STRING user { 759 rule->r_user = $5; 760 rule->r_action = A_MAILDIR; 761 if (strlcpy(rule->r_value.path, $4, 762 sizeof(rule->r_value.path)) >= 763 sizeof(rule->r_value.path)) 764 fatal("pathname too long"); 765 free($4); 766 } 767 | DELIVER TO MBOX { 768 rule->r_action = A_MBOX; 769 if (strlcpy(rule->r_value.path, _PATH_MAILDIR "/%u", 770 sizeof(rule->r_value.path)) 771 >= sizeof(rule->r_value.path)) 772 fatal("pathname too long"); 773 } 774 | DELIVER TO MDA STRING user { 775 rule->r_user = $5; 776 rule->r_action = A_EXT; 777 if (strlcpy(rule->r_value.command, $4, 778 sizeof(rule->r_value.command)) 779 >= sizeof(rule->r_value.command)) 780 fatal("command too long"); 781 free($4); 782 } 783 | RELAY { 784 rule->r_action = A_RELAY; 785 } 786 | RELAY VIA STRING port ssl certname auth { 787 rule->r_action = A_RELAYVIA; 788 789 if ($5 == 0 && ($6 != NULL || $7)) { 790 yyerror("error: must specify tls, smtps, or ssl"); 791 free($6); 792 free($3); 793 YYERROR; 794 } 795 796 if (strlcpy(rule->r_value.relayhost.hostname, $3, 797 sizeof(rule->r_value.relayhost.hostname)) 798 >= sizeof(rule->r_value.relayhost.hostname)) 799 fatal("hostname too long"); 800 801 rule->r_value.relayhost.port = $4; 802 rule->r_value.relayhost.flags |= $5; 803 804 if ($7) 805 rule->r_value.relayhost.flags |= F_AUTH; 806 807 if ($6 != NULL) { 808 if (ssl_load_certfile(conf, $6, F_CCERT) < 0) { 809 yyerror("cannot load certificate: %s", 810 $6); 811 free($6); 812 free($3); 813 YYERROR; 814 } 815 if (strlcpy(rule->r_value.relayhost.cert, $6, 816 sizeof(rule->r_value.relayhost.cert)) 817 >= sizeof(rule->r_value.relayhost.cert)) 818 fatal("certificate path too long"); 819 } 820 821 free($3); 822 free($6); 823 } 824 ; 825 826 from : FROM mapref { 827 $$ = $2; 828 } 829 | FROM ALL { 830 struct map *m; 831 struct mapel *me; 832 struct sockaddr_in *ssin; 833 struct sockaddr_in6 *ssin6; 834 835 if ((m = calloc(1, sizeof(*m))) == NULL) 836 fatal("out of memory"); 837 m->m_id = last_map_id++; 838 if (m->m_id == INT_MAX) { 839 yyerror("too many maps defined"); 840 free(m); 841 YYERROR; 842 } 843 if (! bsnprintf(m->m_name, sizeof(m->m_name), 844 "<dynamic(%u)>", m->m_id)) 845 fatal("snprintf"); 846 m->m_flags |= F_DYNAMIC|F_USED; 847 m->m_type = T_SINGLE; 848 849 TAILQ_INIT(&m->m_contents); 850 851 if ((me = calloc(1, sizeof(*me))) == NULL) 852 fatal("out of memory"); 853 me->me_key.med_addr.bits = 32; 854 me->me_key.med_addr.ss.ss_len = sizeof(struct sockaddr_in); 855 ssin = (struct sockaddr_in *)&me->me_key.med_addr.ss; 856 ssin->sin_family = AF_INET; 857 if (inet_pton(AF_INET, "0.0.0.0", &ssin->sin_addr) != 1) { 858 free(me); 859 free(m); 860 YYERROR; 861 } 862 TAILQ_INSERT_TAIL(&m->m_contents, me, me_entry); 863 864 if ((me = calloc(1, sizeof(*me))) == NULL) 865 fatal("out of memory"); 866 me->me_key.med_addr.bits = 128; 867 me->me_key.med_addr.ss.ss_len = sizeof(struct sockaddr_in6); 868 ssin6 = (struct sockaddr_in6 *)&me->me_key.med_addr.ss; 869 ssin6->sin6_family = AF_INET6; 870 if (inet_pton(AF_INET6, "::", &ssin6->sin6_addr) != 1) { 871 free(me); 872 free(m); 873 YYERROR; 874 } 875 TAILQ_INSERT_TAIL(&m->m_contents, me, me_entry); 876 877 TAILQ_INSERT_TAIL(conf->sc_maps, m, m_entry); 878 $$ = m->m_id; 879 } 880 | /* empty */ { 881 struct map *m; 882 883 m = map_findbyname(conf, "localhost"); 884 $$ = m->m_id; 885 } 886 ; 887 888 rule : decision from { 889 struct rule *r; 890 891 if ((r = calloc(1, sizeof(*r))) == NULL) 892 fatal("out of memory"); 893 rule = r; 894 rule->r_sources = map_find(conf, $2); 895 TAILQ_INIT(&rule->r_conditions); 896 TAILQ_INIT(&rule->r_options); 897 898 } FOR conditions action { 899 TAILQ_INSERT_TAIL(conf->sc_rules, rule, r_entry); 900 } 901 ; 902 %% 903 904 struct keywords { 905 const char *k_name; 906 int k_val; 907 }; 908 909 int 910 yyerror(const char *fmt, ...) 911 { 912 va_list ap; 913 914 file->errors++; 915 va_start(ap, fmt); 916 fprintf(stderr, "%s:%d: ", file->name, yylval.lineno); 917 vfprintf(stderr, fmt, ap); 918 fprintf(stderr, "\n"); 919 va_end(ap); 920 return (0); 921 } 922 923 int 924 kw_cmp(const void *k, const void *e) 925 { 926 return (strcmp(k, ((const struct keywords *)e)->k_name)); 927 } 928 929 int 930 lookup(char *s) 931 { 932 /* this has to be sorted always */ 933 static const struct keywords keywords[] = { 934 { "accept", ACCEPT }, 935 { "all", ALL }, 936 { "auth", AUTH }, 937 { "certificate", CERTIFICATE }, 938 { "config", CONFIG }, 939 { "db", DB }, 940 { "deliver", DELIVER }, 941 { "dns", DNS }, 942 { "domain", DOMAIN }, 943 { "enable", ENABLE }, 944 { "external", EXTERNAL }, 945 { "file", TFILE }, 946 { "for", FOR }, 947 { "from", FROM }, 948 { "hash", HASH }, 949 { "hostname", HOSTNAME }, 950 { "include", INCLUDE }, 951 { "interval", INTERVAL }, 952 { "list", LIST }, 953 { "listen", LISTEN }, 954 { "local", LOCAL }, 955 { "maildir", MAILDIR }, 956 { "map", MAP }, 957 { "mbox", MBOX }, 958 { "mda", MDA }, 959 { "network", NETWORK }, 960 { "on", ON }, 961 { "port", PORT }, 962 { "queue", QUEUE }, 963 { "reject", REJECT }, 964 { "relay", RELAY }, 965 { "single", SINGLE }, 966 { "smtps", SMTPS }, 967 { "source", SOURCE }, 968 { "ssl", SSL }, 969 { "tls", TLS }, 970 { "to", TO }, 971 { "type", TYPE }, 972 { "user", USER }, 973 { "via", VIA }, 974 { "virtual", VIRTUAL }, 975 }; 976 const struct keywords *p; 977 978 p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), 979 sizeof(keywords[0]), kw_cmp); 980 981 if (p) 982 return (p->k_val); 983 else 984 return (STRING); 985 } 986 987 #define MAXPUSHBACK 128 988 989 char *parsebuf; 990 int parseindex; 991 char pushback_buffer[MAXPUSHBACK]; 992 int pushback_index = 0; 993 994 int 995 lgetc(int quotec) 996 { 997 int c, next; 998 999 if (parsebuf) { 1000 /* Read character from the parsebuffer instead of input. */ 1001 if (parseindex >= 0) { 1002 c = parsebuf[parseindex++]; 1003 if (c != '\0') 1004 return (c); 1005 parsebuf = NULL; 1006 } else 1007 parseindex++; 1008 } 1009 1010 if (pushback_index) 1011 return (pushback_buffer[--pushback_index]); 1012 1013 if (quotec) { 1014 if ((c = getc(file->stream)) == EOF) { 1015 yyerror("reached end of file while parsing " 1016 "quoted string"); 1017 if (file == topfile || popfile() == EOF) 1018 return (EOF); 1019 return (quotec); 1020 } 1021 return (c); 1022 } 1023 1024 while ((c = getc(file->stream)) == '\\') { 1025 next = getc(file->stream); 1026 if (next != '\n') { 1027 c = next; 1028 break; 1029 } 1030 yylval.lineno = file->lineno; 1031 file->lineno++; 1032 } 1033 1034 while (c == EOF) { 1035 if (file == topfile || popfile() == EOF) 1036 return (EOF); 1037 c = getc(file->stream); 1038 } 1039 return (c); 1040 } 1041 1042 int 1043 lungetc(int c) 1044 { 1045 if (c == EOF) 1046 return (EOF); 1047 if (parsebuf) { 1048 parseindex--; 1049 if (parseindex >= 0) 1050 return (c); 1051 } 1052 if (pushback_index < MAXPUSHBACK-1) 1053 return (pushback_buffer[pushback_index++] = c); 1054 else 1055 return (EOF); 1056 } 1057 1058 int 1059 findeol(void) 1060 { 1061 int c; 1062 1063 parsebuf = NULL; 1064 pushback_index = 0; 1065 1066 /* skip to either EOF or the first real EOL */ 1067 while (1) { 1068 c = lgetc(0); 1069 if (c == '\n') { 1070 file->lineno++; 1071 break; 1072 } 1073 if (c == EOF) 1074 break; 1075 } 1076 return (ERROR); 1077 } 1078 1079 int 1080 yylex(void) 1081 { 1082 char buf[8096]; 1083 char *p, *val; 1084 int quotec, next, c; 1085 int token; 1086 1087 top: 1088 p = buf; 1089 while ((c = lgetc(0)) == ' ' || c == '\t') 1090 ; /* nothing */ 1091 1092 yylval.lineno = file->lineno; 1093 if (c == '#') 1094 while ((c = lgetc(0)) != '\n' && c != EOF) 1095 ; /* nothing */ 1096 if (c == '$' && parsebuf == NULL) { 1097 while (1) { 1098 if ((c = lgetc(0)) == EOF) 1099 return (0); 1100 1101 if (p + 1 >= buf + sizeof(buf) - 1) { 1102 yyerror("string too long"); 1103 return (findeol()); 1104 } 1105 if (isalnum(c) || c == '_') { 1106 *p++ = (char)c; 1107 continue; 1108 } 1109 *p = '\0'; 1110 lungetc(c); 1111 break; 1112 } 1113 val = symget(buf); 1114 if (val == NULL) { 1115 yyerror("macro '%s' not defined", buf); 1116 return (findeol()); 1117 } 1118 parsebuf = val; 1119 parseindex = 0; 1120 goto top; 1121 } 1122 1123 switch (c) { 1124 case '\'': 1125 case '"': 1126 quotec = c; 1127 while (1) { 1128 if ((c = lgetc(quotec)) == EOF) 1129 return (0); 1130 if (c == '\n') { 1131 file->lineno++; 1132 continue; 1133 } else if (c == '\\') { 1134 if ((next = lgetc(quotec)) == EOF) 1135 return (0); 1136 if (next == quotec || c == ' ' || c == '\t') 1137 c = next; 1138 else if (next == '\n') 1139 continue; 1140 else 1141 lungetc(next); 1142 } else if (c == quotec) { 1143 *p = '\0'; 1144 break; 1145 } 1146 if (p + 1 >= buf + sizeof(buf) - 1) { 1147 yyerror("string too long"); 1148 return (findeol()); 1149 } 1150 *p++ = (char)c; 1151 } 1152 yylval.v.string = strdup(buf); 1153 if (yylval.v.string == NULL) 1154 err(1, "yylex: strdup"); 1155 return (STRING); 1156 } 1157 1158 #define allowed_to_end_number(x) \ 1159 (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') 1160 1161 if (c == '-' || isdigit(c)) { 1162 do { 1163 *p++ = c; 1164 if ((unsigned)(p-buf) >= sizeof(buf)) { 1165 yyerror("string too long"); 1166 return (findeol()); 1167 } 1168 } while ((c = lgetc(0)) != EOF && isdigit(c)); 1169 lungetc(c); 1170 if (p == buf + 1 && buf[0] == '-') 1171 goto nodigits; 1172 if (c == EOF || allowed_to_end_number(c)) { 1173 const char *errstr = NULL; 1174 1175 *p = '\0'; 1176 yylval.v.number = strtonum(buf, LLONG_MIN, 1177 LLONG_MAX, &errstr); 1178 if (errstr) { 1179 yyerror("\"%s\" invalid number: %s", 1180 buf, errstr); 1181 return (findeol()); 1182 } 1183 return (NUMBER); 1184 } else { 1185 nodigits: 1186 while (p > buf + 1) 1187 lungetc(*--p); 1188 c = *--p; 1189 if (c == '-') 1190 return (c); 1191 } 1192 } 1193 1194 if (c == '=') { 1195 if ((c = lgetc(0)) != EOF && c == '>') 1196 return (ARROW); 1197 lungetc(c); 1198 c = '='; 1199 } 1200 1201 #define allowed_in_string(x) \ 1202 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 1203 x != '{' && x != '}' && x != '<' && x != '>' && \ 1204 x != '!' && x != '=' && x != '#' && \ 1205 x != ',')) 1206 1207 if (isalnum(c) || c == ':' || c == '_') { 1208 do { 1209 *p++ = c; 1210 if ((unsigned)(p-buf) >= sizeof(buf)) { 1211 yyerror("string too long"); 1212 return (findeol()); 1213 } 1214 } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); 1215 lungetc(c); 1216 *p = '\0'; 1217 if ((token = lookup(buf)) == STRING) 1218 if ((yylval.v.string = strdup(buf)) == NULL) 1219 err(1, "yylex: strdup"); 1220 return (token); 1221 } 1222 if (c == '\n') { 1223 yylval.lineno = file->lineno; 1224 file->lineno++; 1225 } 1226 if (c == EOF) 1227 return (0); 1228 return (c); 1229 } 1230 1231 int 1232 check_file_secrecy(int fd, const char *fname) 1233 { 1234 struct stat st; 1235 1236 if (fstat(fd, &st)) { 1237 log_warn("cannot stat %s", fname); 1238 return (-1); 1239 } 1240 if (st.st_uid != 0 && st.st_uid != getuid()) { 1241 log_warnx("%s: owner not root or current user", fname); 1242 return (-1); 1243 } 1244 if (st.st_mode & (S_IRWXG | S_IRWXO)) { 1245 log_warnx("%s: group/world readable/writeable", fname); 1246 return (-1); 1247 } 1248 return (0); 1249 } 1250 1251 struct file * 1252 pushfile(const char *name, int secret) 1253 { 1254 struct file *nfile; 1255 1256 if ((nfile = calloc(1, sizeof(struct file))) == NULL) { 1257 log_warn("malloc"); 1258 return (NULL); 1259 } 1260 if ((nfile->name = strdup(name)) == NULL) { 1261 log_warn("malloc"); 1262 free(nfile); 1263 return (NULL); 1264 } 1265 if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { 1266 log_warn("%s", nfile->name); 1267 free(nfile->name); 1268 free(nfile); 1269 return (NULL); 1270 } else if (secret && 1271 check_file_secrecy(fileno(nfile->stream), nfile->name)) { 1272 fclose(nfile->stream); 1273 free(nfile->name); 1274 free(nfile); 1275 return (NULL); 1276 } 1277 nfile->lineno = 1; 1278 TAILQ_INSERT_TAIL(&files, nfile, entry); 1279 return (nfile); 1280 } 1281 1282 int 1283 popfile(void) 1284 { 1285 struct file *prev; 1286 1287 if ((prev = TAILQ_PREV(file, files, entry)) != NULL) 1288 prev->errors += file->errors; 1289 1290 TAILQ_REMOVE(&files, file, entry); 1291 fclose(file->stream); 1292 free(file->name); 1293 free(file); 1294 file = prev; 1295 return (file ? 0 : EOF); 1296 } 1297 1298 int 1299 parse_config(struct smtpd *x_conf, const char *filename, int opts) 1300 { 1301 struct sym *sym, *next; 1302 struct map *m; 1303 1304 conf = x_conf; 1305 bzero(conf, sizeof(*conf)); 1306 if ((conf->sc_maps = calloc(1, sizeof(*conf->sc_maps))) == NULL) { 1307 log_warn("cannot allocate memory"); 1308 return 0; 1309 } 1310 if ((conf->sc_rules = calloc(1, sizeof(*conf->sc_rules))) == NULL) { 1311 log_warn("cannot allocate memory"); 1312 free(conf->sc_maps); 1313 return 0; 1314 } 1315 if ((conf->sc_listeners = calloc(1, sizeof(*conf->sc_listeners))) == NULL) { 1316 log_warn("cannot allocate memory"); 1317 free(conf->sc_maps); 1318 free(conf->sc_rules); 1319 return 0; 1320 } 1321 if ((conf->sc_ssl = calloc(1, sizeof(*conf->sc_ssl))) == NULL) { 1322 log_warn("cannot allocate memory"); 1323 free(conf->sc_maps); 1324 free(conf->sc_rules); 1325 free(conf->sc_listeners); 1326 return 0; 1327 } 1328 if ((m = calloc(1, sizeof(*m))) == NULL) { 1329 log_warn("cannot allocate memory"); 1330 free(conf->sc_maps); 1331 free(conf->sc_rules); 1332 free(conf->sc_listeners); 1333 free(conf->sc_ssl); 1334 return 0; 1335 } 1336 1337 errors = 0; 1338 last_map_id = 0; 1339 1340 map = NULL; 1341 rule = NULL; 1342 1343 TAILQ_INIT(conf->sc_listeners); 1344 TAILQ_INIT(conf->sc_maps); 1345 TAILQ_INIT(conf->sc_rules); 1346 SPLAY_INIT(conf->sc_ssl); 1347 SPLAY_INIT(&conf->sc_sessions); 1348 1349 conf->sc_qintval.tv_sec = SMTPD_QUEUE_INTERVAL; 1350 conf->sc_qintval.tv_usec = 0; 1351 conf->sc_opts = opts; 1352 1353 if ((file = pushfile(filename, 0)) == NULL) { 1354 purge_config(conf, PURGE_EVERYTHING); 1355 return (-1); 1356 } 1357 topfile = file; 1358 1359 /* 1360 * declare special "local" map 1361 */ 1362 m->m_id = last_map_id++; 1363 if (strlcpy(m->m_name, "localhost", sizeof(m->m_name)) 1364 >= sizeof(m->m_name)) 1365 fatal("strlcpy"); 1366 m->m_type = T_LIST; 1367 TAILQ_INIT(&m->m_contents); 1368 TAILQ_INSERT_TAIL(conf->sc_maps, m, m_entry); 1369 set_localaddrs(); 1370 1371 /* 1372 * parse configuration 1373 */ 1374 setservent(1); 1375 yyparse(); 1376 errors = file->errors; 1377 popfile(); 1378 endservent(); 1379 1380 /* Free macros and check which have not been used. */ 1381 for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) { 1382 next = TAILQ_NEXT(sym, entry); 1383 if ((conf->sc_opts & SMTPD_OPT_VERBOSE) && !sym->used) 1384 fprintf(stderr, "warning: macro '%s' not " 1385 "used\n", sym->nam); 1386 if (!sym->persist) { 1387 free(sym->nam); 1388 free(sym->val); 1389 TAILQ_REMOVE(&symhead, sym, entry); 1390 free(sym); 1391 } 1392 } 1393 1394 if (TAILQ_EMPTY(conf->sc_rules)) { 1395 log_warnx("no rules, nothing to do"); 1396 errors++; 1397 } 1398 1399 if (strlen(conf->sc_hostname) == 0) 1400 if (gethostname(conf->sc_hostname, 1401 sizeof(conf->sc_hostname)) == -1) { 1402 log_warn("could not determine host name"); 1403 bzero(conf->sc_hostname, sizeof(conf->sc_hostname)); 1404 errors++; 1405 } 1406 1407 if (errors) { 1408 purge_config(conf, PURGE_EVERYTHING); 1409 return (-1); 1410 } 1411 1412 return (0); 1413 } 1414 1415 int 1416 symset(const char *nam, const char *val, int persist) 1417 { 1418 struct sym *sym; 1419 1420 for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); 1421 sym = TAILQ_NEXT(sym, entry)) 1422 ; /* nothing */ 1423 1424 if (sym != NULL) { 1425 if (sym->persist == 1) 1426 return (0); 1427 else { 1428 free(sym->nam); 1429 free(sym->val); 1430 TAILQ_REMOVE(&symhead, sym, entry); 1431 free(sym); 1432 } 1433 } 1434 if ((sym = calloc(1, sizeof(*sym))) == NULL) 1435 return (-1); 1436 1437 sym->nam = strdup(nam); 1438 if (sym->nam == NULL) { 1439 free(sym); 1440 return (-1); 1441 } 1442 sym->val = strdup(val); 1443 if (sym->val == NULL) { 1444 free(sym->nam); 1445 free(sym); 1446 return (-1); 1447 } 1448 sym->used = 0; 1449 sym->persist = persist; 1450 TAILQ_INSERT_TAIL(&symhead, sym, entry); 1451 return (0); 1452 } 1453 1454 int 1455 cmdline_symset(char *s) 1456 { 1457 char *sym, *val; 1458 int ret; 1459 size_t len; 1460 1461 if ((val = strrchr(s, '=')) == NULL) 1462 return (-1); 1463 1464 len = strlen(s) - strlen(val) + 1; 1465 if ((sym = malloc(len)) == NULL) 1466 errx(1, "cmdline_symset: malloc"); 1467 1468 (void)strlcpy(sym, s, len); 1469 1470 ret = symset(sym, val + 1, 1); 1471 free(sym); 1472 1473 return (ret); 1474 } 1475 1476 char * 1477 symget(const char *nam) 1478 { 1479 struct sym *sym; 1480 1481 TAILQ_FOREACH(sym, &symhead, entry) 1482 if (strcmp(nam, sym->nam) == 0) { 1483 sym->used = 1; 1484 return (sym->val); 1485 } 1486 return (NULL); 1487 } 1488 1489 struct listener * 1490 host_v4(const char *s, in_port_t port) 1491 { 1492 struct in_addr ina; 1493 struct sockaddr_in *sain; 1494 struct listener *h; 1495 1496 bzero(&ina, sizeof(ina)); 1497 if (inet_pton(AF_INET, s, &ina) != 1) 1498 return (NULL); 1499 1500 if ((h = calloc(1, sizeof(*h))) == NULL) 1501 fatal(NULL); 1502 sain = (struct sockaddr_in *)&h->ss; 1503 sain->sin_len = sizeof(struct sockaddr_in); 1504 sain->sin_family = AF_INET; 1505 sain->sin_addr.s_addr = ina.s_addr; 1506 sain->sin_port = port; 1507 1508 return (h); 1509 } 1510 1511 struct listener * 1512 host_v6(const char *s, in_port_t port) 1513 { 1514 struct in6_addr ina6; 1515 struct sockaddr_in6 *sin6; 1516 struct listener *h; 1517 1518 bzero(&ina6, sizeof(ina6)); 1519 if (inet_pton(AF_INET6, s, &ina6) != 1) 1520 return (NULL); 1521 1522 if ((h = calloc(1, sizeof(*h))) == NULL) 1523 fatal(NULL); 1524 sin6 = (struct sockaddr_in6 *)&h->ss; 1525 sin6->sin6_len = sizeof(struct sockaddr_in6); 1526 sin6->sin6_family = AF_INET6; 1527 sin6->sin6_port = port; 1528 memcpy(&sin6->sin6_addr, &ina6, sizeof(ina6)); 1529 1530 return (h); 1531 } 1532 1533 int 1534 host_dns(const char *s, const char *cert, struct listenerlist *al, int max, in_port_t port, 1535 u_int8_t flags) 1536 { 1537 struct addrinfo hints, *res0, *res; 1538 int error, cnt = 0; 1539 struct sockaddr_in *sain; 1540 struct sockaddr_in6 *sin6; 1541 struct listener *h; 1542 1543 bzero(&hints, sizeof(hints)); 1544 hints.ai_family = PF_UNSPEC; 1545 hints.ai_socktype = SOCK_DGRAM; /* DUMMY */ 1546 error = getaddrinfo(s, NULL, &hints, &res0); 1547 if (error == EAI_AGAIN || error == EAI_NODATA || error == EAI_NONAME) 1548 return (0); 1549 if (error) { 1550 log_warnx("host_dns: could not parse \"%s\": %s", s, 1551 gai_strerror(error)); 1552 return (-1); 1553 } 1554 1555 for (res = res0; res && cnt < max; res = res->ai_next) { 1556 if (res->ai_family != AF_INET && 1557 res->ai_family != AF_INET6) 1558 continue; 1559 if ((h = calloc(1, sizeof(*h))) == NULL) 1560 fatal(NULL); 1561 1562 h->port = port; 1563 h->flags = flags; 1564 h->ss.ss_family = res->ai_family; 1565 h->ssl = NULL; 1566 h->ssl_cert_name[0] = '\0'; 1567 if (cert != NULL) 1568 (void)strlcpy(h->ssl_cert_name, cert, sizeof(h->ssl_cert_name)); 1569 1570 if (res->ai_family == AF_INET) { 1571 sain = (struct sockaddr_in *)&h->ss; 1572 sain->sin_len = sizeof(struct sockaddr_in); 1573 sain->sin_addr.s_addr = ((struct sockaddr_in *) 1574 res->ai_addr)->sin_addr.s_addr; 1575 sain->sin_port = port; 1576 } else { 1577 sin6 = (struct sockaddr_in6 *)&h->ss; 1578 sin6->sin6_len = sizeof(struct sockaddr_in6); 1579 memcpy(&sin6->sin6_addr, &((struct sockaddr_in6 *) 1580 res->ai_addr)->sin6_addr, sizeof(struct in6_addr)); 1581 sin6->sin6_port = port; 1582 } 1583 1584 TAILQ_INSERT_HEAD(al, h, entry); 1585 cnt++; 1586 } 1587 if (cnt == max && res) { 1588 log_warnx("host_dns: %s resolves to more than %d hosts", 1589 s, max); 1590 } 1591 freeaddrinfo(res0); 1592 return (cnt); 1593 } 1594 1595 int 1596 host(const char *s, const char *cert, struct listenerlist *al, int max, in_port_t port, 1597 u_int8_t flags) 1598 { 1599 struct listener *h; 1600 1601 h = host_v4(s, port); 1602 1603 /* IPv6 address? */ 1604 if (h == NULL) 1605 h = host_v6(s, port); 1606 1607 if (h != NULL) { 1608 h->port = port; 1609 h->flags = flags; 1610 h->ssl = NULL; 1611 h->ssl_cert_name[0] = '\0'; 1612 if (cert != NULL) 1613 (void)strlcpy(h->ssl_cert_name, cert, sizeof(h->ssl_cert_name)); 1614 1615 1616 TAILQ_INSERT_HEAD(al, h, entry); 1617 return (1); 1618 } 1619 1620 return (host_dns(s, cert, al, max, port, flags)); 1621 } 1622 1623 int 1624 interface(const char *s, const char *cert, struct listenerlist *al, int max, in_port_t port, 1625 u_int8_t flags) 1626 { 1627 struct ifaddrs *ifap, *p; 1628 struct sockaddr_in *sain; 1629 struct sockaddr_in6 *sin6; 1630 struct listener *h; 1631 int ret = 0; 1632 1633 if (getifaddrs(&ifap) == -1) 1634 fatal("getifaddrs"); 1635 1636 for (p = ifap; p != NULL; p = p->ifa_next) { 1637 if (strcmp(s, p->ifa_name) != 0) 1638 continue; 1639 1640 switch (p->ifa_addr->sa_family) { 1641 case AF_INET: 1642 if ((h = calloc(1, sizeof(*h))) == NULL) 1643 fatal(NULL); 1644 sain = (struct sockaddr_in *)&h->ss; 1645 *sain = *(struct sockaddr_in *)p->ifa_addr; 1646 sain->sin_len = sizeof(struct sockaddr_in); 1647 sain->sin_port = port; 1648 1649 h->fd = -1; 1650 h->port = port; 1651 h->flags = flags; 1652 h->ssl = NULL; 1653 h->ssl_cert_name[0] = '\0'; 1654 if (cert != NULL) 1655 (void)strlcpy(h->ssl_cert_name, cert, sizeof(h->ssl_cert_name)); 1656 1657 ret = 1; 1658 TAILQ_INSERT_HEAD(al, h, entry); 1659 1660 break; 1661 1662 case AF_INET6: 1663 if ((h = calloc(1, sizeof(*h))) == NULL) 1664 fatal(NULL); 1665 sin6 = (struct sockaddr_in6 *)&h->ss; 1666 *sin6 = *(struct sockaddr_in6 *)p->ifa_addr; 1667 sin6->sin6_len = sizeof(struct sockaddr_in6); 1668 sin6->sin6_port = port; 1669 1670 h->fd = -1; 1671 h->port = port; 1672 h->flags = flags; 1673 h->ssl = NULL; 1674 h->ssl_cert_name[0] = '\0'; 1675 if (cert != NULL) 1676 (void)strlcpy(h->ssl_cert_name, cert, sizeof(h->ssl_cert_name)); 1677 1678 ret = 1; 1679 TAILQ_INSERT_HEAD(al, h, entry); 1680 1681 break; 1682 } 1683 } 1684 1685 freeifaddrs(ifap); 1686 1687 return ret; 1688 } 1689 1690 void 1691 set_localaddrs(void) 1692 { 1693 struct ifaddrs *ifap, *p; 1694 struct sockaddr_storage ss; 1695 struct sockaddr_in *sain; 1696 struct sockaddr_in6 *sin6; 1697 struct map *m; 1698 struct mapel *me; 1699 1700 if (getifaddrs(&ifap) == -1) 1701 fatal("getifaddrs"); 1702 1703 m = map_findbyname(conf, "localhost"); 1704 1705 for (p = ifap; p != NULL; p = p->ifa_next) { 1706 switch (p->ifa_addr->sa_family) { 1707 case AF_INET: 1708 sain = (struct sockaddr_in *)&ss; 1709 *sain = *(struct sockaddr_in *)p->ifa_addr; 1710 sain->sin_len = sizeof(struct sockaddr_in); 1711 1712 if ((me = calloc(1, sizeof(*me))) == NULL) 1713 fatal("out of memory"); 1714 me->me_key.med_addr.bits = 0; 1715 me->me_key.med_addr.ss = *(struct sockaddr_storage *)sain; 1716 TAILQ_INSERT_TAIL(&m->m_contents, me, me_entry); 1717 1718 break; 1719 1720 case AF_INET6: 1721 sin6 = (struct sockaddr_in6 *)&ss; 1722 *sin6 = *(struct sockaddr_in6 *)p->ifa_addr; 1723 sin6->sin6_len = sizeof(struct sockaddr_in6); 1724 1725 if ((me = calloc(1, sizeof(*me))) == NULL) 1726 fatal("out of memory"); 1727 me->me_key.med_addr.bits = 0; 1728 me->me_key.med_addr.ss = *(struct sockaddr_storage *)sin6; 1729 TAILQ_INSERT_TAIL(&m->m_contents, me, me_entry); 1730 1731 break; 1732 } 1733 } 1734 1735 freeifaddrs(ifap); 1736 } 1737