1 /* $OpenBSD: httpd.c,v 1.2 2014/07/13 14:17:37 reyk Exp $ */ 2 3 /* 4 * Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/queue.h> 21 #include <sys/socket.h> 22 #include <sys/wait.h> 23 #include <sys/resource.h> 24 #include <sys/hash.h> 25 26 #include <net/if.h> 27 #include <netinet/in.h> 28 #include <arpa/inet.h> 29 30 #include <string.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <fcntl.h> 34 #include <getopt.h> 35 #include <fnmatch.h> 36 #include <err.h> 37 #include <errno.h> 38 #include <event.h> 39 #include <unistd.h> 40 #include <ctype.h> 41 #include <pwd.h> 42 #include <sha1.h> 43 #include <md5.h> 44 45 #include <openssl/ssl.h> 46 47 #include "httpd.h" 48 49 __dead void usage(void); 50 51 int parent_configure(struct httpd *); 52 void parent_configure_done(struct httpd *); 53 void parent_reload(struct httpd *, u_int, const char *); 54 void parent_sig_handler(int, short, void *); 55 void parent_shutdown(struct httpd *); 56 int parent_dispatch_server(int, struct privsep_proc *, 57 struct imsg *); 58 59 struct httpd *httpd_env; 60 61 static struct privsep_proc procs[] = { 62 { "server", PROC_SERVER, parent_dispatch_server, server } 63 }; 64 65 void 66 parent_sig_handler(int sig, short event, void *arg) 67 { 68 struct privsep *ps = arg; 69 int die = 0, status, fail, id; 70 pid_t pid; 71 char *cause; 72 73 switch (sig) { 74 case SIGTERM: 75 case SIGINT: 76 die = 1; 77 /* FALLTHROUGH */ 78 case SIGCHLD: 79 do { 80 pid = waitpid(WAIT_ANY, &status, WNOHANG); 81 if (pid <= 0) 82 continue; 83 84 fail = 0; 85 if (WIFSIGNALED(status)) { 86 fail = 1; 87 asprintf(&cause, "terminated; signal %d", 88 WTERMSIG(status)); 89 } else if (WIFEXITED(status)) { 90 if (WEXITSTATUS(status) != 0) { 91 fail = 1; 92 asprintf(&cause, "exited abnormally"); 93 } else 94 asprintf(&cause, "exited okay"); 95 } else 96 fatalx("unexpected cause of SIGCHLD"); 97 98 die = 1; 99 100 for (id = 0; id < PROC_MAX; id++) 101 if (pid == ps->ps_pid[id]) { 102 if (fail) 103 log_warnx("lost child: %s %s", 104 ps->ps_title[id], cause); 105 break; 106 } 107 108 free(cause); 109 } while (pid > 0 || (pid == -1 && errno == EINTR)); 110 111 if (die) 112 parent_shutdown(ps->ps_env); 113 break; 114 case SIGHUP: 115 log_info("%s: reload requested with SIGHUP", __func__); 116 117 /* 118 * This is safe because libevent uses async signal handlers 119 * that run in the event loop and not in signal context. 120 */ 121 parent_reload(ps->ps_env, CONFIG_RELOAD, NULL); 122 break; 123 case SIGPIPE: 124 /* ignore */ 125 break; 126 default: 127 fatalx("unexpected signal"); 128 } 129 } 130 131 __dead void 132 usage(void) 133 { 134 extern char *__progname; 135 136 fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n", 137 __progname); 138 exit(1); 139 } 140 141 int 142 main(int argc, char *argv[]) 143 { 144 int c; 145 int debug = 0, verbose = 0; 146 u_int32_t opts = 0; 147 struct httpd *env; 148 struct privsep *ps; 149 const char *conffile = CONF_FILE; 150 151 while ((c = getopt(argc, argv, "dD:nf:v")) != -1) { 152 switch (c) { 153 case 'd': 154 debug = 2; 155 break; 156 case 'D': 157 if (cmdline_symset(optarg) < 0) 158 log_warnx("could not parse macro definition %s", 159 optarg); 160 break; 161 case 'n': 162 debug = 2; 163 opts |= HTTPD_OPT_NOACTION; 164 break; 165 case 'f': 166 conffile = optarg; 167 break; 168 case 'v': 169 verbose++; 170 opts |= HTTPD_OPT_VERBOSE; 171 break; 172 default: 173 usage(); 174 } 175 } 176 177 log_init(debug ? debug : 1); /* log to stderr until daemonized */ 178 179 argc -= optind; 180 if (argc > 0) 181 usage(); 182 183 if ((env = calloc(1, sizeof(*env))) == NULL || 184 (ps = calloc(1, sizeof(*ps))) == NULL) 185 exit(1); 186 187 httpd_env = env; 188 env->sc_ps = ps; 189 ps->ps_env = env; 190 TAILQ_INIT(&ps->ps_rcsocks); 191 env->sc_conffile = conffile; 192 env->sc_opts = opts; 193 194 if (parse_config(env->sc_conffile, env) == -1) 195 exit(1); 196 197 if (debug) 198 env->sc_opts |= HTTPD_OPT_LOGUPDATE; 199 200 if (geteuid()) 201 errx(1, "need root privileges"); 202 203 if ((ps->ps_pw = getpwnam(HTTPD_USER)) == NULL) 204 errx(1, "unknown user %s", HTTPD_USER); 205 206 /* Configure the control socket */ 207 ps->ps_csock.cs_name = HTTPD_SOCKET; 208 209 log_init(debug); 210 log_verbose(verbose); 211 212 if (!debug && daemon(1, 0) == -1) 213 err(1, "failed to daemonize"); 214 215 if (env->sc_opts & HTTPD_OPT_NOACTION) 216 ps->ps_noaction = 1; 217 else 218 log_info("startup"); 219 220 ps->ps_instances[PROC_SERVER] = env->sc_prefork_server; 221 ps->ps_ninstances = env->sc_prefork_server; 222 223 proc_init(ps, procs, nitems(procs)); 224 225 setproctitle("parent"); 226 227 event_init(); 228 229 signal_set(&ps->ps_evsigint, SIGINT, parent_sig_handler, ps); 230 signal_set(&ps->ps_evsigterm, SIGTERM, parent_sig_handler, ps); 231 signal_set(&ps->ps_evsigchld, SIGCHLD, parent_sig_handler, ps); 232 signal_set(&ps->ps_evsighup, SIGHUP, parent_sig_handler, ps); 233 signal_set(&ps->ps_evsigpipe, SIGPIPE, parent_sig_handler, ps); 234 235 signal_add(&ps->ps_evsigint, NULL); 236 signal_add(&ps->ps_evsigterm, NULL); 237 signal_add(&ps->ps_evsigchld, NULL); 238 signal_add(&ps->ps_evsighup, NULL); 239 signal_add(&ps->ps_evsigpipe, NULL); 240 241 proc_listen(ps, procs, nitems(procs)); 242 243 if (load_config(env->sc_conffile, env) == -1) { 244 proc_kill(env->sc_ps); 245 exit(1); 246 } 247 248 if (env->sc_opts & HTTPD_OPT_NOACTION) { 249 fprintf(stderr, "configuration OK\n"); 250 proc_kill(env->sc_ps); 251 exit(0); 252 } 253 254 if (parent_configure(env) == -1) 255 fatalx("configuration failed"); 256 257 event_dispatch(); 258 259 parent_shutdown(env); 260 /* NOTREACHED */ 261 262 return (0); 263 } 264 265 int 266 parent_configure(struct httpd *env) 267 { 268 int id; 269 struct ctl_flags cf; 270 int ret = -1; 271 struct server *srv; 272 struct media_type *media; 273 274 RB_FOREACH(media, mediatypes, env->sc_mediatypes) { 275 if (config_setmedia(env, media) == -1) 276 fatal("send media"); 277 } 278 279 TAILQ_FOREACH(srv, env->sc_servers, srv_entry) { 280 if (config_setserver(env, srv) == -1) 281 fatal("send server"); 282 } 283 284 /* The servers need to reload their config. */ 285 env->sc_reload = env->sc_prefork_server; 286 287 for (id = 0; id < PROC_MAX; id++) { 288 if (id == privsep_process) 289 continue; 290 cf.cf_opts = env->sc_opts; 291 cf.cf_flags = env->sc_flags; 292 293 proc_compose_imsg(env->sc_ps, id, -1, IMSG_CFG_DONE, -1, 294 &cf, sizeof(cf)); 295 } 296 297 ret = 0; 298 299 config_purge(env, CONFIG_ALL); 300 return (ret); 301 } 302 303 void 304 parent_reload(struct httpd *env, u_int reset, const char *filename) 305 { 306 if (env->sc_reload) { 307 log_debug("%s: already in progress: %d pending", 308 __func__, env->sc_reload); 309 return; 310 } 311 312 /* Switch back to the default config file */ 313 if (filename == NULL || *filename == '\0') 314 filename = env->sc_conffile; 315 316 log_debug("%s: level %d config file %s", __func__, reset, filename); 317 318 config_purge(env, CONFIG_ALL); 319 320 if (reset == CONFIG_RELOAD) { 321 if (load_config(filename, env) == -1) { 322 log_debug("%s: failed to load config file %s", 323 __func__, filename); 324 } 325 326 config_setreset(env, CONFIG_ALL); 327 328 if (parent_configure(env) == -1) { 329 log_debug("%s: failed to commit config from %s", 330 __func__, filename); 331 } 332 } else 333 config_setreset(env, reset); 334 } 335 336 void 337 parent_configure_done(struct httpd *env) 338 { 339 int id; 340 341 if (env->sc_reload == 0) { 342 log_warnx("%s: configuration already finished", __func__); 343 return; 344 } 345 346 env->sc_reload--; 347 if (env->sc_reload == 0) { 348 for (id = 0; id < PROC_MAX; id++) { 349 if (id == privsep_process) 350 continue; 351 352 proc_compose_imsg(env->sc_ps, id, -1, IMSG_CTL_START, 353 -1, NULL, 0); 354 } 355 } 356 } 357 358 void 359 parent_shutdown(struct httpd *env) 360 { 361 config_purge(env, CONFIG_ALL); 362 363 proc_kill(env->sc_ps); 364 control_cleanup(&env->sc_ps->ps_csock); 365 366 free(env->sc_ps); 367 free(env); 368 369 log_info("parent terminating, pid %d", getpid()); 370 371 exit(0); 372 } 373 374 int 375 parent_dispatch_server(int fd, struct privsep_proc *p, struct imsg *imsg) 376 { 377 struct httpd *env = p->p_env; 378 379 switch (imsg->hdr.type) { 380 case IMSG_CFG_DONE: 381 parent_configure_done(env); 382 break; 383 default: 384 return (-1); 385 } 386 387 return (0); 388 } 389 390 /* 391 * Utility functions 392 */ 393 394 void 395 event_again(struct event *ev, int fd, short event, 396 void (*fn)(int, short, void *), 397 struct timeval *start, struct timeval *end, void *arg) 398 { 399 struct timeval tv_next, tv_now, tv; 400 401 getmonotime(&tv_now); 402 memcpy(&tv_next, end, sizeof(tv_next)); 403 timersub(&tv_now, start, &tv_now); 404 timersub(&tv_next, &tv_now, &tv_next); 405 406 memset(&tv, 0, sizeof(tv)); 407 if (timercmp(&tv_next, &tv, >)) 408 memcpy(&tv, &tv_next, sizeof(tv)); 409 410 event_del(ev); 411 event_set(ev, fd, event, fn, arg); 412 event_add(ev, &tv); 413 } 414 415 const char * 416 canonicalize_host(const char *host, char *name, size_t len) 417 { 418 struct sockaddr_in sin4; 419 struct sockaddr_in6 sin6; 420 u_int i, j; 421 size_t plen; 422 char c; 423 424 if (len < 2) 425 goto fail; 426 427 /* 428 * Canonicalize an IPv4/6 address 429 */ 430 if (inet_pton(AF_INET, host, &sin4) == 1) 431 return (inet_ntop(AF_INET, &sin4, name, len)); 432 if (inet_pton(AF_INET6, host, &sin6) == 1) 433 return (inet_ntop(AF_INET6, &sin6, name, len)); 434 435 /* 436 * Canonicalize a hostname 437 */ 438 439 /* 1. remove repeated dots and convert upper case to lower case */ 440 plen = strlen(host); 441 memset(name, 0, len); 442 for (i = j = 0; i < plen; i++) { 443 if (j >= (len - 1)) 444 goto fail; 445 c = tolower(host[i]); 446 if ((c == '.') && (j == 0 || name[j - 1] == '.')) 447 continue; 448 name[j++] = c; 449 } 450 451 /* 2. remove trailing dots */ 452 for (i = j; i > 0; i--) { 453 if (name[i - 1] != '.') 454 break; 455 name[i - 1] = '\0'; 456 j--; 457 } 458 if (j <= 0) 459 goto fail; 460 461 return (name); 462 463 fail: 464 errno = EINVAL; 465 return (NULL); 466 } 467 468 void 469 socket_rlimit(int maxfd) 470 { 471 struct rlimit rl; 472 473 if (getrlimit(RLIMIT_NOFILE, &rl) == -1) 474 fatal("socket_rlimit: failed to get resource limit"); 475 log_debug("%s: max open files %llu", __func__, rl.rlim_max); 476 477 /* 478 * Allow the maximum number of open file descriptors for this 479 * login class (which should be the class "daemon" by default). 480 */ 481 if (maxfd == -1) 482 rl.rlim_cur = rl.rlim_max; 483 else 484 rl.rlim_cur = MAX(rl.rlim_max, (rlim_t)maxfd); 485 if (setrlimit(RLIMIT_NOFILE, &rl) == -1) 486 fatal("socket_rlimit: failed to set resource limit"); 487 } 488 489 char * 490 get_string(u_int8_t *ptr, size_t len) 491 { 492 size_t i; 493 char *str; 494 495 for (i = 0; i < len; i++) 496 if (!(isprint(ptr[i]) || isspace(ptr[i]))) 497 break; 498 499 if ((str = calloc(1, i + 1)) == NULL) 500 return (NULL); 501 memcpy(str, ptr, i); 502 503 return (str); 504 } 505 506 void * 507 get_data(u_int8_t *ptr, size_t len) 508 { 509 u_int8_t *data; 510 511 if ((data = calloc(1, len)) == NULL) 512 return (NULL); 513 memcpy(data, ptr, len); 514 515 return (data); 516 } 517 518 int 519 accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen, 520 int reserve, volatile int *counter) 521 { 522 int ret; 523 if (getdtablecount() + reserve + 524 *counter >= getdtablesize()) { 525 errno = EMFILE; 526 return (-1); 527 } 528 529 if ((ret = accept(sockfd, addr, addrlen)) > -1) { 530 (*counter)++; 531 DPRINTF("%s: inflight incremented, now %d",__func__, *counter); 532 } 533 return (ret); 534 } 535 536 struct kv * 537 kv_add(struct kvtree *keys, char *key, char *value) 538 { 539 struct kv *kv, *oldkv; 540 541 if (key == NULL) 542 return (NULL); 543 if ((kv = calloc(1, sizeof(*kv))) == NULL) 544 return (NULL); 545 if ((kv->kv_key = strdup(key)) == NULL) { 546 free(kv); 547 return (NULL); 548 } 549 if (value != NULL && 550 (kv->kv_value = strdup(value)) == NULL) { 551 free(kv->kv_key); 552 free(kv); 553 return (NULL); 554 } 555 TAILQ_INIT(&kv->kv_children); 556 557 if ((oldkv = RB_INSERT(kvtree, keys, kv)) != NULL) { 558 TAILQ_INSERT_TAIL(&oldkv->kv_children, kv, kv_entry); 559 kv->kv_parent = oldkv; 560 } 561 562 return (kv); 563 } 564 565 int 566 kv_set(struct kv *kv, char *fmt, ...) 567 { 568 va_list ap; 569 char *value = NULL; 570 struct kv *ckv; 571 572 va_start(ap, fmt); 573 if (vasprintf(&value, fmt, ap) == -1) 574 return (-1); 575 va_end(ap); 576 577 /* Remove all children */ 578 while ((ckv = TAILQ_FIRST(&kv->kv_children)) != NULL) { 579 TAILQ_REMOVE(&kv->kv_children, ckv, kv_entry); 580 kv_free(ckv); 581 free(ckv); 582 } 583 584 /* Set the new value */ 585 if (kv->kv_value != NULL) 586 free(kv->kv_value); 587 kv->kv_value = value; 588 589 return (0); 590 } 591 592 int 593 kv_setkey(struct kv *kv, char *fmt, ...) 594 { 595 va_list ap; 596 char *key = NULL; 597 598 va_start(ap, fmt); 599 if (vasprintf(&key, fmt, ap) == -1) 600 return (-1); 601 va_end(ap); 602 603 if (kv->kv_key != NULL) 604 free(kv->kv_key); 605 kv->kv_key = key; 606 607 return (0); 608 } 609 610 void 611 kv_delete(struct kvtree *keys, struct kv *kv) 612 { 613 struct kv *ckv; 614 615 RB_REMOVE(kvtree, keys, kv); 616 617 /* Remove all children */ 618 while ((ckv = TAILQ_FIRST(&kv->kv_children)) != NULL) { 619 TAILQ_REMOVE(&kv->kv_children, ckv, kv_entry); 620 kv_free(ckv); 621 free(ckv); 622 } 623 624 kv_free(kv); 625 free(kv); 626 } 627 628 struct kv * 629 kv_extend(struct kvtree *keys, struct kv *kv, char *value) 630 { 631 char *newvalue; 632 633 if (kv == NULL) { 634 return (NULL); 635 } else if (kv->kv_value != NULL) { 636 if (asprintf(&newvalue, "%s%s", kv->kv_value, value) == -1) 637 return (NULL); 638 639 free(kv->kv_value); 640 kv->kv_value = newvalue; 641 } else if ((kv->kv_value = strdup(value)) == NULL) 642 return (NULL); 643 644 return (kv); 645 } 646 647 void 648 kv_purge(struct kvtree *keys) 649 { 650 struct kv *kv; 651 652 while ((kv = RB_MIN(kvtree, keys)) != NULL) 653 kv_delete(keys, kv); 654 } 655 656 void 657 kv_free(struct kv *kv) 658 { 659 if (kv->kv_type == KEY_TYPE_NONE) 660 return; 661 if (kv->kv_key != NULL) { 662 free(kv->kv_key); 663 } 664 kv->kv_key = NULL; 665 if (kv->kv_value != NULL) { 666 free(kv->kv_value); 667 } 668 kv->kv_value = NULL; 669 memset(kv, 0, sizeof(*kv)); 670 } 671 672 struct kv * 673 kv_inherit(struct kv *dst, struct kv *src) 674 { 675 memset(dst, 0, sizeof(*dst)); 676 memcpy(dst, src, sizeof(*dst)); 677 TAILQ_INIT(&dst->kv_children); 678 679 if (src->kv_key != NULL) { 680 if ((dst->kv_key = strdup(src->kv_key)) == NULL) { 681 kv_free(dst); 682 return (NULL); 683 } 684 } 685 if (src->kv_value != NULL) { 686 if ((dst->kv_value = strdup(src->kv_value)) == NULL) { 687 kv_free(dst); 688 return (NULL); 689 } 690 } 691 692 return (dst); 693 } 694 695 int 696 kv_log(struct evbuffer *log, struct kv *kv) 697 { 698 char *msg; 699 700 if (log == NULL) 701 return (0); 702 if (asprintf(&msg, " [%s%s%s]", 703 kv->kv_key == NULL ? "(unknown)" : kv->kv_key, 704 kv->kv_value == NULL ? "" : ": ", 705 kv->kv_value == NULL ? "" : kv->kv_value) == -1) 706 return (-1); 707 if (evbuffer_add(log, msg, strlen(msg)) == -1) { 708 free(msg); 709 return (-1); 710 } 711 free(msg); 712 713 return (0); 714 } 715 716 struct kv * 717 kv_find(struct kvtree *keys, struct kv *kv) 718 { 719 struct kv *match; 720 const char *key; 721 722 if (kv->kv_flags & KV_FLAG_GLOBBING) { 723 /* Test header key using shell globbing rules */ 724 key = kv->kv_key == NULL ? "" : kv->kv_key; 725 RB_FOREACH(match, kvtree, keys) { 726 if (fnmatch(key, match->kv_key, FNM_CASEFOLD) == 0) 727 break; 728 } 729 } else { 730 /* Fast tree-based lookup only works without globbing */ 731 match = RB_FIND(kvtree, keys, kv); 732 } 733 734 return (match); 735 } 736 737 int 738 kv_cmp(struct kv *a, struct kv *b) 739 { 740 return (strcasecmp(a->kv_key, b->kv_key)); 741 } 742 743 RB_GENERATE(kvtree, kv, kv_node, kv_cmp); 744 745 struct media_type * 746 media_add(struct mediatypes *types, struct media_type *media) 747 { 748 struct media_type *entry; 749 750 if ((entry = RB_FIND(mediatypes, types, media)) != NULL) { 751 log_debug("%s: duplicated entry for \"%s\"", __func__, 752 media->media_name); 753 return (NULL); 754 } 755 756 if ((entry = malloc(sizeof(*media))) == NULL) 757 return (NULL); 758 759 memcpy(entry, media, sizeof(*entry)); 760 RB_INSERT(mediatypes, types, entry); 761 762 return (entry); 763 } 764 765 void 766 media_delete(struct mediatypes *types, struct media_type *media) 767 { 768 RB_REMOVE(mediatypes, types, media); 769 if (media->media_encoding != NULL) 770 free(media->media_encoding); 771 free(media); 772 } 773 774 void 775 media_purge(struct mediatypes *types) 776 { 777 struct media_type *media; 778 779 while ((media = RB_MIN(mediatypes, types)) != NULL) 780 media_delete(types, media); 781 } 782 783 struct media_type * 784 media_find(struct mediatypes *types, char *file) 785 { 786 struct media_type *match, media; 787 char *p; 788 789 if ((p = strrchr(file, '.')) == NULL) { 790 p = file; 791 } else if (*p++ == '\0') { 792 return (NULL); 793 } 794 if (strlcpy(media.media_name, p, 795 sizeof(media.media_name)) >= 796 sizeof(media.media_name)) { 797 return (NULL); 798 } 799 800 /* Find media type by extension name */ 801 match = RB_FIND(mediatypes, types, &media); 802 803 return (match); 804 } 805 806 int 807 media_cmp(struct media_type *a, struct media_type *b) 808 { 809 return (strcasecmp(a->media_name, b->media_name)); 810 } 811 812 RB_GENERATE(mediatypes, media_type, media_entry, media_cmp); 813