1 /* $OpenBSD: server_http.c,v 1.142 2020/10/29 12:30:52 denis Exp $ */ 2 3 /* 4 * Copyright (c) 2020 Matthias Pressfreund <mpfr@fn.de> 5 * Copyright (c) 2006 - 2018 Reyk Floeter <reyk@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/queue.h> 22 #include <sys/socket.h> 23 #include <sys/tree.h> 24 #include <sys/stat.h> 25 26 #include <netinet/in.h> 27 #include <arpa/inet.h> 28 29 #include <errno.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <unistd.h> 33 #include <limits.h> 34 #include <fnmatch.h> 35 #include <stdio.h> 36 #include <time.h> 37 #include <resolv.h> 38 #include <event.h> 39 #include <ctype.h> 40 #include <vis.h> 41 #include <fcntl.h> 42 43 #include "httpd.h" 44 #include "http.h" 45 #include "patterns.h" 46 47 static int server_httpmethod_cmp(const void *, const void *); 48 static int server_httperror_cmp(const void *, const void *); 49 void server_httpdesc_free(struct http_descriptor *); 50 int server_http_authenticate(struct server_config *, 51 struct client *); 52 char *server_expand_http(struct client *, const char *, 53 char *, size_t); 54 55 static struct http_method http_methods[] = HTTP_METHODS; 56 static struct http_error http_errors[] = HTTP_ERRORS; 57 58 void 59 server_http(void) 60 { 61 DPRINTF("%s: sorting lookup tables, pid %d", __func__, getpid()); 62 63 /* Sort the HTTP lookup arrays */ 64 qsort(http_methods, sizeof(http_methods) / 65 sizeof(http_methods[0]) - 1, 66 sizeof(http_methods[0]), server_httpmethod_cmp); 67 qsort(http_errors, sizeof(http_errors) / 68 sizeof(http_errors[0]) - 1, 69 sizeof(http_errors[0]), server_httperror_cmp); 70 } 71 72 void 73 server_http_init(struct server *srv) 74 { 75 /* nothing */ 76 } 77 78 int 79 server_httpdesc_init(struct client *clt) 80 { 81 struct http_descriptor *desc; 82 83 if ((desc = calloc(1, sizeof(*desc))) == NULL) 84 return (-1); 85 RB_INIT(&desc->http_headers); 86 clt->clt_descreq = desc; 87 88 if ((desc = calloc(1, sizeof(*desc))) == NULL) { 89 /* req will be cleaned up later */ 90 return (-1); 91 } 92 RB_INIT(&desc->http_headers); 93 clt->clt_descresp = desc; 94 95 return (0); 96 } 97 98 void 99 server_httpdesc_free(struct http_descriptor *desc) 100 { 101 if (desc == NULL) 102 return; 103 104 free(desc->http_path); 105 desc->http_path = NULL; 106 free(desc->http_path_orig); 107 desc->http_path_orig = NULL; 108 free(desc->http_path_alias); 109 desc->http_path_alias = NULL; 110 free(desc->http_query); 111 desc->http_query = NULL; 112 free(desc->http_query_alias); 113 desc->http_query_alias = NULL; 114 free(desc->http_version); 115 desc->http_version = NULL; 116 free(desc->http_host); 117 desc->http_host = NULL; 118 119 kv_purge(&desc->http_headers); 120 desc->http_lastheader = NULL; 121 desc->http_method = 0; 122 desc->http_chunked = 0; 123 } 124 125 int 126 server_http_authenticate(struct server_config *srv_conf, struct client *clt) 127 { 128 char decoded[1024]; 129 FILE *fp = NULL; 130 struct http_descriptor *desc = clt->clt_descreq; 131 const struct auth *auth = srv_conf->auth; 132 struct kv *ba, key; 133 size_t linesize = 0; 134 ssize_t linelen; 135 int ret = -1; 136 char *line = NULL, *user = NULL, *pass = NULL; 137 char *clt_user = NULL, *clt_pass = NULL; 138 139 memset(decoded, 0, sizeof(decoded)); 140 key.kv_key = "Authorization"; 141 142 if ((ba = kv_find(&desc->http_headers, &key)) == NULL || 143 ba->kv_value == NULL) 144 goto done; 145 146 if (strncmp(ba->kv_value, "Basic ", strlen("Basic ")) != 0) 147 goto done; 148 149 if (b64_pton(strchr(ba->kv_value, ' ') + 1, (uint8_t *)decoded, 150 sizeof(decoded)) <= 0) 151 goto done; 152 153 if ((clt_pass = strchr(decoded, ':')) == NULL) 154 goto done; 155 156 clt_user = decoded; 157 *clt_pass++ = '\0'; 158 if ((clt->clt_remote_user = strdup(clt_user)) == NULL) 159 goto done; 160 161 if ((fp = fopen(auth->auth_htpasswd, "r")) == NULL) 162 goto done; 163 164 while ((linelen = getline(&line, &linesize, fp)) != -1) { 165 if (line[linelen - 1] == '\n') 166 line[linelen - 1] = '\0'; 167 user = line; 168 pass = strchr(line, ':'); 169 170 if (pass == NULL) { 171 explicit_bzero(line, linelen); 172 continue; 173 } 174 175 *pass++ = '\0'; 176 177 if (strcmp(clt_user, user) != 0) { 178 explicit_bzero(line, linelen); 179 continue; 180 } 181 182 if (crypt_checkpass(clt_pass, pass) == 0) { 183 explicit_bzero(line, linelen); 184 ret = 0; 185 break; 186 } 187 } 188 done: 189 free(line); 190 if (fp != NULL) 191 fclose(fp); 192 193 if (ba != NULL && ba->kv_value != NULL) { 194 explicit_bzero(ba->kv_value, strlen(ba->kv_value)); 195 explicit_bzero(decoded, sizeof(decoded)); 196 } 197 198 return (ret); 199 } 200 201 void 202 server_read_http(struct bufferevent *bev, void *arg) 203 { 204 struct client *clt = arg; 205 struct http_descriptor *desc = clt->clt_descreq; 206 struct evbuffer *src = EVBUFFER_INPUT(bev); 207 char *line = NULL, *key, *value; 208 const char *errstr; 209 size_t size, linelen; 210 struct kv *hdr = NULL; 211 212 getmonotime(&clt->clt_tv_last); 213 214 size = EVBUFFER_LENGTH(src); 215 DPRINTF("%s: session %d: size %lu, to read %lld", 216 __func__, clt->clt_id, size, clt->clt_toread); 217 if (!size) { 218 clt->clt_toread = TOREAD_HTTP_HEADER; 219 goto done; 220 } 221 222 while (!clt->clt_headersdone) { 223 if (!clt->clt_line) { 224 /* Peek into the buffer to see if it looks like HTTP */ 225 key = EVBUFFER_DATA(src); 226 if (!isalpha((unsigned char)*key)) { 227 server_abort_http(clt, 400, 228 "invalid request line"); 229 goto abort; 230 } 231 } 232 233 if ((line = evbuffer_readln(src, 234 &linelen, EVBUFFER_EOL_CRLF_STRICT)) == NULL) { 235 /* No newline found after too many bytes */ 236 if (size > SERVER_MAXHEADERLENGTH) { 237 server_abort_http(clt, 413, 238 "request line too long"); 239 goto abort; 240 } 241 break; 242 } 243 244 /* 245 * An empty line indicates the end of the request. 246 * libevent already stripped the \r\n for us. 247 */ 248 if (!linelen) { 249 clt->clt_headersdone = 1; 250 free(line); 251 break; 252 } 253 key = line; 254 255 /* Limit the total header length minus \r\n */ 256 clt->clt_headerlen += linelen; 257 if (clt->clt_headerlen > SERVER_MAXHEADERLENGTH) { 258 server_abort_http(clt, 413, "request too large"); 259 goto abort; 260 } 261 262 /* 263 * The first line is the GET/POST/PUT/... request, 264 * subsequent lines are HTTP headers. 265 */ 266 if (++clt->clt_line == 1) 267 value = strchr(key, ' '); 268 else if (*key == ' ' || *key == '\t') 269 /* Multiline headers wrap with a space or tab */ 270 value = NULL; 271 else 272 value = strchr(key, ':'); 273 if (value == NULL) { 274 if (clt->clt_line == 1) { 275 server_abort_http(clt, 400, "malformed"); 276 goto abort; 277 } 278 279 /* Append line to the last header, if present */ 280 if (kv_extend(&desc->http_headers, 281 desc->http_lastheader, line) == NULL) 282 goto fail; 283 284 free(line); 285 continue; 286 } 287 if (*value == ':') { 288 *value++ = '\0'; 289 value += strspn(value, " \t\r\n"); 290 } else { 291 *value++ = '\0'; 292 } 293 294 DPRINTF("%s: session %d: header '%s: %s'", __func__, 295 clt->clt_id, key, value); 296 297 /* 298 * Identify and handle specific HTTP request methods 299 */ 300 if (clt->clt_line == 1) { 301 if ((desc->http_method = server_httpmethod_byname(key)) 302 == HTTP_METHOD_NONE) { 303 server_abort_http(clt, 400, "malformed"); 304 goto abort; 305 } 306 307 /* 308 * Decode request path and query 309 */ 310 desc->http_path = strdup(value); 311 if (desc->http_path == NULL) 312 goto fail; 313 314 desc->http_version = strchr(desc->http_path, ' '); 315 if (desc->http_version == NULL) { 316 server_abort_http(clt, 400, "malformed"); 317 goto abort; 318 } 319 320 *desc->http_version++ = '\0'; 321 desc->http_query = strchr(desc->http_path, '?'); 322 if (desc->http_query != NULL) 323 *desc->http_query++ = '\0'; 324 325 /* 326 * Have to allocate the strings because they could 327 * be changed independently by the filters later. 328 */ 329 if ((desc->http_version = 330 strdup(desc->http_version)) == NULL) 331 goto fail; 332 333 if (desc->http_query != NULL && 334 (desc->http_query = 335 strdup(desc->http_query)) == NULL) 336 goto fail; 337 338 } else if (desc->http_method != HTTP_METHOD_NONE && 339 strcasecmp("Content-Length", key) == 0) { 340 if (desc->http_method == HTTP_METHOD_TRACE || 341 desc->http_method == HTTP_METHOD_CONNECT) { 342 /* 343 * These method should not have a body 344 * and thus no Content-Length header. 345 */ 346 server_abort_http(clt, 400, "malformed"); 347 goto abort; 348 } 349 350 /* 351 * Need to read data from the client after the 352 * HTTP header. 353 * XXX What about non-standard clients not using 354 * the carriage return? And some browsers seem to 355 * include the line length in the content-length. 356 */ 357 clt->clt_toread = strtonum(value, 0, LLONG_MAX, 358 &errstr); 359 if (errstr) { 360 server_abort_http(clt, 500, errstr); 361 goto abort; 362 } 363 } 364 365 if (strcasecmp("Transfer-Encoding", key) == 0 && 366 strcasecmp("chunked", value) == 0) 367 desc->http_chunked = 1; 368 369 if (clt->clt_line != 1) { 370 if ((hdr = kv_add(&desc->http_headers, key, 371 value)) == NULL) 372 goto fail; 373 374 desc->http_lastheader = hdr; 375 } 376 377 free(line); 378 } 379 if (clt->clt_headersdone) { 380 if (desc->http_method == HTTP_METHOD_NONE) { 381 server_abort_http(clt, 406, "no method"); 382 return; 383 } 384 385 switch (desc->http_method) { 386 case HTTP_METHOD_CONNECT: 387 /* Data stream */ 388 clt->clt_toread = TOREAD_UNLIMITED; 389 bev->readcb = server_read; 390 break; 391 case HTTP_METHOD_GET: 392 case HTTP_METHOD_HEAD: 393 /* WebDAV methods */ 394 case HTTP_METHOD_COPY: 395 case HTTP_METHOD_MOVE: 396 clt->clt_toread = 0; 397 break; 398 case HTTP_METHOD_DELETE: 399 case HTTP_METHOD_OPTIONS: 400 case HTTP_METHOD_POST: 401 case HTTP_METHOD_PUT: 402 case HTTP_METHOD_RESPONSE: 403 /* WebDAV methods */ 404 case HTTP_METHOD_PROPFIND: 405 case HTTP_METHOD_PROPPATCH: 406 case HTTP_METHOD_MKCOL: 407 case HTTP_METHOD_LOCK: 408 case HTTP_METHOD_UNLOCK: 409 case HTTP_METHOD_VERSION_CONTROL: 410 case HTTP_METHOD_REPORT: 411 case HTTP_METHOD_CHECKOUT: 412 case HTTP_METHOD_CHECKIN: 413 case HTTP_METHOD_UNCHECKOUT: 414 case HTTP_METHOD_MKWORKSPACE: 415 case HTTP_METHOD_UPDATE: 416 case HTTP_METHOD_LABEL: 417 case HTTP_METHOD_MERGE: 418 case HTTP_METHOD_BASELINE_CONTROL: 419 case HTTP_METHOD_MKACTIVITY: 420 case HTTP_METHOD_ORDERPATCH: 421 case HTTP_METHOD_ACL: 422 case HTTP_METHOD_MKREDIRECTREF: 423 case HTTP_METHOD_UPDATEREDIRECTREF: 424 case HTTP_METHOD_SEARCH: 425 case HTTP_METHOD_PATCH: 426 /* HTTP request payload */ 427 if (clt->clt_toread > 0) 428 bev->readcb = server_read_httpcontent; 429 430 /* Single-pass HTTP body */ 431 if (clt->clt_toread < 0) { 432 clt->clt_toread = TOREAD_UNLIMITED; 433 bev->readcb = server_read; 434 } 435 break; 436 default: 437 server_abort_http(clt, 405, "method not allowed"); 438 return; 439 } 440 if (desc->http_chunked) { 441 /* Chunked transfer encoding */ 442 clt->clt_toread = TOREAD_HTTP_CHUNK_LENGTH; 443 bev->readcb = server_read_httpchunks; 444 } 445 446 done: 447 if (clt->clt_toread != 0) 448 bufferevent_disable(bev, EV_READ); 449 server_response(httpd_env, clt); 450 return; 451 } 452 if (clt->clt_done) { 453 server_close(clt, "done"); 454 return; 455 } 456 if (EVBUFFER_LENGTH(src) && bev->readcb != server_read_http) 457 bev->readcb(bev, arg); 458 bufferevent_enable(bev, EV_READ); 459 return; 460 fail: 461 server_abort_http(clt, 500, strerror(errno)); 462 abort: 463 free(line); 464 } 465 466 void 467 server_read_httpcontent(struct bufferevent *bev, void *arg) 468 { 469 struct client *clt = arg; 470 struct evbuffer *src = EVBUFFER_INPUT(bev); 471 size_t size; 472 473 getmonotime(&clt->clt_tv_last); 474 475 size = EVBUFFER_LENGTH(src); 476 DPRINTF("%s: session %d: size %lu, to read %lld", __func__, 477 clt->clt_id, size, clt->clt_toread); 478 if (!size) 479 return; 480 481 if (clt->clt_toread > 0) { 482 /* Read content data */ 483 if ((off_t)size > clt->clt_toread) { 484 size = clt->clt_toread; 485 if (fcgi_add_stdin(clt, src) == -1) 486 goto fail; 487 clt->clt_toread = 0; 488 } else { 489 if (fcgi_add_stdin(clt, src) == -1) 490 goto fail; 491 clt->clt_toread -= size; 492 } 493 DPRINTF("%s: done, size %lu, to read %lld", __func__, 494 size, clt->clt_toread); 495 } 496 if (clt->clt_toread == 0) { 497 fcgi_add_stdin(clt, NULL); 498 clt->clt_toread = TOREAD_HTTP_HEADER; 499 bufferevent_disable(bev, EV_READ); 500 bev->readcb = server_read_http; 501 return; 502 } 503 if (clt->clt_done) 504 goto done; 505 if (bev->readcb != server_read_httpcontent) 506 bev->readcb(bev, arg); 507 508 return; 509 done: 510 return; 511 fail: 512 server_close(clt, strerror(errno)); 513 } 514 515 void 516 server_read_httpchunks(struct bufferevent *bev, void *arg) 517 { 518 struct client *clt = arg; 519 struct evbuffer *src = EVBUFFER_INPUT(bev); 520 char *line; 521 long long llval; 522 size_t size; 523 524 getmonotime(&clt->clt_tv_last); 525 526 size = EVBUFFER_LENGTH(src); 527 DPRINTF("%s: session %d: size %lu, to read %lld", __func__, 528 clt->clt_id, size, clt->clt_toread); 529 if (!size) 530 return; 531 532 if (clt->clt_toread > 0) { 533 /* Read chunk data */ 534 if ((off_t)size > clt->clt_toread) { 535 size = clt->clt_toread; 536 if (server_bufferevent_write_chunk(clt, src, size) 537 == -1) 538 goto fail; 539 clt->clt_toread = 0; 540 } else { 541 if (server_bufferevent_write_buffer(clt, src) == -1) 542 goto fail; 543 clt->clt_toread -= size; 544 } 545 DPRINTF("%s: done, size %lu, to read %lld", __func__, 546 size, clt->clt_toread); 547 } 548 switch (clt->clt_toread) { 549 case TOREAD_HTTP_CHUNK_LENGTH: 550 line = evbuffer_readln(src, NULL, EVBUFFER_EOL_CRLF_STRICT); 551 if (line == NULL) { 552 /* Ignore empty line, continue */ 553 bufferevent_enable(bev, EV_READ); 554 return; 555 } 556 if (strlen(line) == 0) { 557 free(line); 558 goto next; 559 } 560 561 /* 562 * Read prepended chunk size in hex, ignore the trailer. 563 * The returned signed value must not be negative. 564 */ 565 if (sscanf(line, "%llx", &llval) != 1 || llval < 0) { 566 free(line); 567 server_close(clt, "invalid chunk size"); 568 return; 569 } 570 571 if (server_bufferevent_print(clt, line) == -1 || 572 server_bufferevent_print(clt, "\r\n") == -1) { 573 free(line); 574 goto fail; 575 } 576 free(line); 577 578 if ((clt->clt_toread = llval) == 0) { 579 DPRINTF("%s: last chunk", __func__); 580 clt->clt_toread = TOREAD_HTTP_CHUNK_TRAILER; 581 } 582 break; 583 case TOREAD_HTTP_CHUNK_TRAILER: 584 /* Last chunk is 0 bytes followed by trailer and empty line */ 585 line = evbuffer_readln(src, NULL, EVBUFFER_EOL_CRLF_STRICT); 586 if (line == NULL) { 587 /* Ignore empty line, continue */ 588 bufferevent_enable(bev, EV_READ); 589 return; 590 } 591 if (server_bufferevent_print(clt, line) == -1 || 592 server_bufferevent_print(clt, "\r\n") == -1) { 593 free(line); 594 goto fail; 595 } 596 if (strlen(line) == 0) { 597 /* Switch to HTTP header mode */ 598 clt->clt_toread = TOREAD_HTTP_HEADER; 599 bev->readcb = server_read_http; 600 } 601 free(line); 602 break; 603 case 0: 604 /* Chunk is terminated by an empty newline */ 605 line = evbuffer_readln(src, NULL, EVBUFFER_EOL_CRLF_STRICT); 606 free(line); 607 if (server_bufferevent_print(clt, "\r\n") == -1) 608 goto fail; 609 clt->clt_toread = TOREAD_HTTP_CHUNK_LENGTH; 610 break; 611 } 612 613 next: 614 if (clt->clt_done) 615 goto done; 616 if (EVBUFFER_LENGTH(src)) 617 bev->readcb(bev, arg); 618 bufferevent_enable(bev, EV_READ); 619 return; 620 621 done: 622 server_close(clt, "last http chunk read (done)"); 623 return; 624 fail: 625 server_close(clt, strerror(errno)); 626 } 627 628 void 629 server_read_httprange(struct bufferevent *bev, void *arg) 630 { 631 struct client *clt = arg; 632 struct evbuffer *src = EVBUFFER_INPUT(bev); 633 size_t size; 634 struct media_type *media; 635 struct range_data *r = &clt->clt_ranges; 636 struct range *range; 637 638 getmonotime(&clt->clt_tv_last); 639 640 if (r->range_toread > 0) { 641 size = EVBUFFER_LENGTH(src); 642 if (!size) 643 return; 644 645 /* Read chunk data */ 646 if ((off_t)size > r->range_toread) { 647 size = r->range_toread; 648 if (server_bufferevent_write_chunk(clt, src, size) 649 == -1) 650 goto fail; 651 r->range_toread = 0; 652 } else { 653 if (server_bufferevent_write_buffer(clt, src) == -1) 654 goto fail; 655 r->range_toread -= size; 656 } 657 if (r->range_toread < 1) 658 r->range_toread = TOREAD_HTTP_RANGE; 659 DPRINTF("%s: done, size %lu, to read %lld", __func__, 660 size, r->range_toread); 661 } 662 663 switch (r->range_toread) { 664 case TOREAD_HTTP_RANGE: 665 if (r->range_index >= r->range_count) { 666 if (r->range_count > 1) { 667 /* Add end marker */ 668 if (server_bufferevent_printf(clt, 669 "\r\n--%llu--\r\n", 670 clt->clt_boundary) == -1) 671 goto fail; 672 } 673 r->range_toread = TOREAD_HTTP_NONE; 674 break; 675 } 676 677 range = &r->range[r->range_index]; 678 679 if (r->range_count > 1) { 680 media = r->range_media; 681 if (server_bufferevent_printf(clt, 682 "\r\n--%llu\r\n" 683 "Content-Type: %s/%s\r\n" 684 "Content-Range: bytes %lld-%lld/%zu\r\n\r\n", 685 clt->clt_boundary, 686 media->media_type, media->media_subtype, 687 range->start, range->end, r->range_total) == -1) 688 goto fail; 689 } 690 r->range_toread = range->end - range->start + 1; 691 692 if (lseek(clt->clt_fd, range->start, SEEK_SET) == -1) 693 goto fail; 694 695 /* Throw away bytes that are already in the input buffer */ 696 evbuffer_drain(src, EVBUFFER_LENGTH(src)); 697 698 /* Increment for the next part */ 699 r->range_index++; 700 break; 701 case TOREAD_HTTP_NONE: 702 goto done; 703 case 0: 704 break; 705 } 706 707 if (clt->clt_done) 708 goto done; 709 710 if (EVBUFFER_LENGTH(EVBUFFER_OUTPUT(clt->clt_bev)) > (size_t) 711 SERVER_MAX_PREFETCH * clt->clt_sndbufsiz) { 712 bufferevent_disable(clt->clt_srvbev, EV_READ); 713 clt->clt_srvbev_throttled = 1; 714 } 715 716 return; 717 done: 718 (*bev->errorcb)(bev, EVBUFFER_READ, bev->cbarg); 719 return; 720 fail: 721 server_close(clt, strerror(errno)); 722 } 723 724 void 725 server_reset_http(struct client *clt) 726 { 727 struct server *srv = clt->clt_srv; 728 729 server_log(clt, NULL); 730 731 server_httpdesc_free(clt->clt_descreq); 732 server_httpdesc_free(clt->clt_descresp); 733 clt->clt_headerlen = 0; 734 clt->clt_headersdone = 0; 735 clt->clt_done = 0; 736 clt->clt_line = 0; 737 clt->clt_chunk = 0; 738 free(clt->clt_remote_user); 739 clt->clt_remote_user = NULL; 740 clt->clt_bev->readcb = server_read_http; 741 clt->clt_srv_conf = &srv->srv_conf; 742 str_match_free(&clt->clt_srv_match); 743 } 744 745 ssize_t 746 server_http_time(time_t t, char *tmbuf, size_t len) 747 { 748 struct tm tm; 749 750 /* New HTTP/1.1 RFC 7231 prefers IMF-fixdate from RFC 5322 */ 751 if (t == -1 || gmtime_r(&t, &tm) == NULL) 752 return (-1); 753 else 754 return (strftime(tmbuf, len, "%a, %d %h %Y %T %Z", &tm)); 755 } 756 757 const char * 758 server_http_host(struct sockaddr_storage *ss, char *buf, size_t len) 759 { 760 char hbuf[HOST_NAME_MAX+1]; 761 in_port_t port; 762 763 if (print_host(ss, buf, len) == NULL) 764 return (NULL); 765 766 port = ntohs(server_socket_getport(ss)); 767 if (port == HTTP_PORT) 768 return (buf); 769 770 switch (ss->ss_family) { 771 case AF_INET: 772 if ((size_t)snprintf(hbuf, sizeof(hbuf), 773 "%s:%u", buf, port) >= sizeof(hbuf)) 774 return (NULL); 775 break; 776 case AF_INET6: 777 if ((size_t)snprintf(hbuf, sizeof(hbuf), 778 "[%s]:%u", buf, port) >= sizeof(hbuf)) 779 return (NULL); 780 break; 781 } 782 783 if (strlcpy(buf, hbuf, len) >= len) 784 return (NULL); 785 786 return (buf); 787 } 788 789 char * 790 server_http_parsehost(char *host, char *buf, size_t len, int *portval) 791 { 792 char *start, *end, *port; 793 const char *errstr = NULL; 794 795 if (strlcpy(buf, host, len) >= len) { 796 log_debug("%s: host name too long", __func__); 797 return (NULL); 798 } 799 800 start = buf; 801 end = port = NULL; 802 803 if (*start == '[' && (end = strchr(start, ']')) != NULL) { 804 /* Address enclosed in [] with port, eg. [2001:db8::1]:80 */ 805 start++; 806 *end++ = '\0'; 807 if ((port = strchr(end, ':')) == NULL || *port == '\0') 808 port = NULL; 809 else 810 port++; 811 memmove(buf, start, strlen(start) + 1); 812 } else if ((end = strchr(start, ':')) != NULL) { 813 /* Name or address with port, eg. www.example.com:80 */ 814 *end++ = '\0'; 815 port = end; 816 } else { 817 /* Name or address with default port, eg. www.example.com */ 818 port = NULL; 819 } 820 821 if (port != NULL) { 822 /* Save the requested port */ 823 *portval = strtonum(port, 0, 0xffff, &errstr); 824 if (errstr != NULL) { 825 log_debug("%s: invalid port: %s", __func__, 826 strerror(errno)); 827 return (NULL); 828 } 829 *portval = htons(*portval); 830 } else { 831 /* Port not given, indicate the default port */ 832 *portval = -1; 833 } 834 835 return (start); 836 } 837 838 void 839 server_abort_http(struct client *clt, unsigned int code, const char *msg) 840 { 841 struct server_config *srv_conf = clt->clt_srv_conf; 842 struct bufferevent *bev = clt->clt_bev; 843 struct http_descriptor *desc = clt->clt_descreq; 844 const char *httperr = NULL, *style; 845 char *httpmsg, *body = NULL, *extraheader = NULL; 846 char tmbuf[32], hbuf[128], *hstsheader = NULL; 847 char *clenheader = NULL; 848 char buf[IBUF_READ_SIZE]; 849 char *escapedmsg = NULL; 850 int bodylen; 851 852 if (code == 0) { 853 server_close(clt, "dropped"); 854 return; 855 } 856 857 if ((httperr = server_httperror_byid(code)) == NULL) 858 httperr = "Unknown Error"; 859 860 if (bev == NULL) 861 goto done; 862 863 if (server_log_http(clt, code, 0) == -1) 864 goto done; 865 866 /* Some system information */ 867 if (print_host(&srv_conf->ss, hbuf, sizeof(hbuf)) == NULL) 868 goto done; 869 870 if (server_http_time(time(NULL), tmbuf, sizeof(tmbuf)) <= 0) 871 goto done; 872 873 /* Do not send details of the Internal Server Error */ 874 switch (code) { 875 case 301: 876 case 302: 877 case 303: 878 case 307: 879 case 308: 880 if (msg == NULL) 881 break; 882 memset(buf, 0, sizeof(buf)); 883 if (server_expand_http(clt, msg, buf, sizeof(buf)) == NULL) 884 goto done; 885 if (asprintf(&extraheader, "Location: %s\r\n", buf) == -1) { 886 code = 500; 887 extraheader = NULL; 888 } 889 msg = buf; 890 break; 891 case 401: 892 if (msg == NULL) 893 break; 894 if (stravis(&escapedmsg, msg, VIS_DQ) == -1) { 895 code = 500; 896 extraheader = NULL; 897 } else if (asprintf(&extraheader, 898 "WWW-Authenticate: Basic realm=\"%s\"\r\n", escapedmsg) 899 == -1) { 900 code = 500; 901 extraheader = NULL; 902 } 903 break; 904 case 416: 905 if (msg == NULL) 906 break; 907 if (asprintf(&extraheader, 908 "Content-Range: %s\r\n", msg) == -1) { 909 code = 500; 910 extraheader = NULL; 911 } 912 break; 913 default: 914 /* 915 * Do not send details of the error. Traditionally, 916 * web servers responsed with the request path on 40x 917 * errors which could be abused to inject JavaScript etc. 918 * Instead of sanitizing the path here, we just don't 919 * reprint it. 920 */ 921 break; 922 } 923 924 free(escapedmsg); 925 926 /* A CSS stylesheet allows minimal customization by the user */ 927 style = "body { background-color: white; color: black; font-family: " 928 "'Comic Sans MS', 'Chalkboard SE', 'Comic Neue', sans-serif; }\n" 929 "hr { border: 0; border-bottom: 1px dashed; }\n" 930 "@media (prefers-color-scheme: dark) {\n" 931 "body { background-color: #1E1F21; color: #EEEFF1; }\n" 932 "a { color: #BAD7FF; }\n}"; 933 934 /* Generate simple HTML error document */ 935 if ((bodylen = asprintf(&body, 936 "<!DOCTYPE html>\n" 937 "<html>\n" 938 "<head>\n" 939 "<meta charset=\"utf-8\">\n" 940 "<title>%03d %s</title>\n" 941 "<style type=\"text/css\"><!--\n%s\n--></style>\n" 942 "</head>\n" 943 "<body>\n" 944 "<h1>%03d %s</h1>\n" 945 "<hr>\n<address>%s</address>\n" 946 "</body>\n" 947 "</html>\n", 948 code, httperr, style, code, httperr, HTTPD_SERVERNAME)) == -1) { 949 body = NULL; 950 goto done; 951 } 952 953 if (srv_conf->flags & SRVFLAG_SERVER_HSTS && 954 srv_conf->flags & SRVFLAG_TLS) { 955 if (asprintf(&hstsheader, "Strict-Transport-Security: " 956 "max-age=%d%s%s\r\n", srv_conf->hsts_max_age, 957 srv_conf->hsts_flags & HSTSFLAG_SUBDOMAINS ? 958 "; includeSubDomains" : "", 959 srv_conf->hsts_flags & HSTSFLAG_PRELOAD ? 960 "; preload" : "") == -1) { 961 hstsheader = NULL; 962 goto done; 963 } 964 } 965 966 if ((code >= 100 && code < 200) || code == 204) 967 clenheader = NULL; 968 else { 969 if (asprintf(&clenheader, 970 "Content-Length: %d\r\n", bodylen) == -1) { 971 clenheader = NULL; 972 goto done; 973 } 974 } 975 976 /* Add basic HTTP headers */ 977 if (asprintf(&httpmsg, 978 "HTTP/1.0 %03d %s\r\n" 979 "Date: %s\r\n" 980 "Server: %s\r\n" 981 "Connection: close\r\n" 982 "Content-Type: text/html\r\n" 983 "%s" 984 "%s" 985 "%s" 986 "\r\n" 987 "%s", 988 code, httperr, tmbuf, HTTPD_SERVERNAME, 989 clenheader == NULL ? "" : clenheader, 990 extraheader == NULL ? "" : extraheader, 991 hstsheader == NULL ? "" : hstsheader, 992 desc->http_method == HTTP_METHOD_HEAD || clenheader == NULL ? 993 "" : body) == -1) 994 goto done; 995 996 /* Dump the message without checking for success */ 997 server_dump(clt, httpmsg, strlen(httpmsg)); 998 free(httpmsg); 999 1000 done: 1001 free(body); 1002 free(extraheader); 1003 free(hstsheader); 1004 free(clenheader); 1005 if (msg == NULL) 1006 msg = "\"\""; 1007 if (asprintf(&httpmsg, "%s (%03d %s)", msg, code, httperr) == -1) { 1008 server_close(clt, msg); 1009 } else { 1010 server_close(clt, httpmsg); 1011 free(httpmsg); 1012 } 1013 } 1014 1015 void 1016 server_close_http(struct client *clt) 1017 { 1018 struct http_descriptor *desc; 1019 1020 desc = clt->clt_descreq; 1021 server_httpdesc_free(desc); 1022 free(desc); 1023 clt->clt_descreq = NULL; 1024 1025 desc = clt->clt_descresp; 1026 server_httpdesc_free(desc); 1027 free(desc); 1028 clt->clt_descresp = NULL; 1029 free(clt->clt_remote_user); 1030 clt->clt_remote_user = NULL; 1031 1032 str_match_free(&clt->clt_srv_match); 1033 } 1034 1035 char * 1036 server_expand_http(struct client *clt, const char *val, char *buf, 1037 size_t len) 1038 { 1039 struct http_descriptor *desc = clt->clt_descreq; 1040 struct server_config *srv_conf = clt->clt_srv_conf; 1041 char ibuf[128], *str, *path, *query; 1042 const char *errstr = NULL, *p; 1043 size_t size; 1044 int n, ret; 1045 1046 if (strlcpy(buf, val, len) >= len) 1047 return (NULL); 1048 1049 /* Find previously matched substrings by index */ 1050 for (p = val; clt->clt_srv_match.sm_nmatch && 1051 (p = strstr(p, "%")) != NULL; p++) { 1052 if (!isdigit((unsigned char)*(p + 1))) 1053 continue; 1054 1055 /* Copy number, leading '%' char and add trailing \0 */ 1056 size = strspn(p + 1, "0123456789") + 2; 1057 if (size >= sizeof(ibuf)) 1058 return (NULL); 1059 (void)strlcpy(ibuf, p, size); 1060 n = strtonum(ibuf + 1, 0, 1061 clt->clt_srv_match.sm_nmatch - 1, &errstr); 1062 if (errstr != NULL) 1063 return (NULL); 1064 1065 /* Expand variable with matched value */ 1066 if ((str = url_encode(clt->clt_srv_match.sm_match[n])) == NULL) 1067 return (NULL); 1068 ret = expand_string(buf, len, ibuf, str); 1069 free(str); 1070 if (ret != 0) 1071 return (NULL); 1072 } 1073 if (strstr(val, "$DOCUMENT_URI") != NULL) { 1074 if ((path = url_encode(desc->http_path)) == NULL) 1075 return (NULL); 1076 ret = expand_string(buf, len, "$DOCUMENT_URI", path); 1077 free(path); 1078 if (ret != 0) 1079 return (NULL); 1080 } 1081 if (strstr(val, "$QUERY_STRING_ENC") != NULL) { 1082 if (desc->http_query == NULL) { 1083 ret = expand_string(buf, len, "$QUERY_STRING_ENC", ""); 1084 } else { 1085 if ((query = url_encode(desc->http_query)) == NULL) 1086 return (NULL); 1087 ret = expand_string(buf, len, "$QUERY_STRING_ENC", query); 1088 free(query); 1089 } 1090 if (ret != 0) 1091 return (NULL); 1092 } 1093 if (strstr(val, "$QUERY_STRING") != NULL) { 1094 if (desc->http_query == NULL) { 1095 ret = expand_string(buf, len, "$QUERY_STRING", ""); 1096 } else { 1097 ret = expand_string(buf, len, "$QUERY_STRING", 1098 desc->http_query); 1099 } 1100 if (ret != 0) 1101 return (NULL); 1102 } 1103 if (strstr(val, "$HTTP_HOST") != NULL) { 1104 if (desc->http_host == NULL) 1105 return (NULL); 1106 if ((str = url_encode(desc->http_host)) == NULL) 1107 return (NULL); 1108 expand_string(buf, len, "$HTTP_HOST", str); 1109 free(str); 1110 } 1111 if (strstr(val, "$REMOTE_") != NULL) { 1112 if (strstr(val, "$REMOTE_ADDR") != NULL) { 1113 if (print_host(&clt->clt_ss, 1114 ibuf, sizeof(ibuf)) == NULL) 1115 return (NULL); 1116 if (expand_string(buf, len, 1117 "$REMOTE_ADDR", ibuf) != 0) 1118 return (NULL); 1119 } 1120 if (strstr(val, "$REMOTE_PORT") != NULL) { 1121 snprintf(ibuf, sizeof(ibuf), 1122 "%u", ntohs(clt->clt_port)); 1123 if (expand_string(buf, len, 1124 "$REMOTE_PORT", ibuf) != 0) 1125 return (NULL); 1126 } 1127 if (strstr(val, "$REMOTE_USER") != NULL) { 1128 if ((srv_conf->flags & SRVFLAG_AUTH) && 1129 clt->clt_remote_user != NULL) { 1130 if ((str = url_encode(clt->clt_remote_user)) 1131 == NULL) 1132 return (NULL); 1133 } else 1134 str = strdup(""); 1135 ret = expand_string(buf, len, "$REMOTE_USER", str); 1136 free(str); 1137 if (ret != 0) 1138 return (NULL); 1139 } 1140 } 1141 if (strstr(val, "$REQUEST_URI") != NULL) { 1142 if ((path = url_encode(desc->http_path)) == NULL) 1143 return (NULL); 1144 if (desc->http_query == NULL) { 1145 str = path; 1146 } else { 1147 ret = asprintf(&str, "%s?%s", path, desc->http_query); 1148 free(path); 1149 if (ret == -1) 1150 return (NULL); 1151 } 1152 1153 ret = expand_string(buf, len, "$REQUEST_URI", str); 1154 free(str); 1155 if (ret != 0) 1156 return (NULL); 1157 } 1158 if (strstr(val, "$REQUEST_SCHEME") != NULL) { 1159 if (srv_conf->flags & SRVFLAG_TLS) { 1160 ret = expand_string(buf, len, "$REQUEST_SCHEME", "https"); 1161 } else { 1162 ret = expand_string(buf, len, "$REQUEST_SCHEME", "http"); 1163 } 1164 if (ret != 0) 1165 return (NULL); 1166 } 1167 if (strstr(val, "$SERVER_") != NULL) { 1168 if (strstr(val, "$SERVER_ADDR") != NULL) { 1169 if (print_host(&srv_conf->ss, 1170 ibuf, sizeof(ibuf)) == NULL) 1171 return (NULL); 1172 if (expand_string(buf, len, 1173 "$SERVER_ADDR", ibuf) != 0) 1174 return (NULL); 1175 } 1176 if (strstr(val, "$SERVER_PORT") != NULL) { 1177 snprintf(ibuf, sizeof(ibuf), "%u", 1178 ntohs(srv_conf->port)); 1179 if (expand_string(buf, len, 1180 "$SERVER_PORT", ibuf) != 0) 1181 return (NULL); 1182 } 1183 if (strstr(val, "$SERVER_NAME") != NULL) { 1184 if ((str = url_encode(srv_conf->name)) 1185 == NULL) 1186 return (NULL); 1187 ret = expand_string(buf, len, "$SERVER_NAME", str); 1188 free(str); 1189 if (ret != 0) 1190 return (NULL); 1191 } 1192 } 1193 1194 return (buf); 1195 } 1196 1197 int 1198 server_response(struct httpd *httpd, struct client *clt) 1199 { 1200 char path[PATH_MAX]; 1201 char hostname[HOST_NAME_MAX+1]; 1202 struct http_descriptor *desc = clt->clt_descreq; 1203 struct http_descriptor *resp = clt->clt_descresp; 1204 struct server *srv = clt->clt_srv; 1205 struct server_config *srv_conf = &srv->srv_conf; 1206 struct kv *kv, key, *host; 1207 struct str_find sm; 1208 int portval = -1, ret; 1209 char *hostval, *query; 1210 const char *errstr = NULL; 1211 1212 /* Preserve original path */ 1213 if (desc->http_path == NULL || 1214 (desc->http_path_orig = strdup(desc->http_path)) == NULL) 1215 goto fail; 1216 1217 /* Decode the URL */ 1218 if (url_decode(desc->http_path) == NULL) 1219 goto fail; 1220 1221 /* Canonicalize the request path */ 1222 if (canonicalize_path(desc->http_path, path, sizeof(path)) == NULL) 1223 goto fail; 1224 free(desc->http_path); 1225 if ((desc->http_path = strdup(path)) == NULL) 1226 goto fail; 1227 1228 key.kv_key = "Host"; 1229 if ((host = kv_find(&desc->http_headers, &key)) != NULL && 1230 host->kv_value == NULL) 1231 host = NULL; 1232 1233 if (strcmp(desc->http_version, "HTTP/1.1") == 0) { 1234 /* Host header is mandatory */ 1235 if (host == NULL) 1236 goto fail; 1237 1238 /* Is the connection persistent? */ 1239 key.kv_key = "Connection"; 1240 if ((kv = kv_find(&desc->http_headers, &key)) != NULL && 1241 strcasecmp("close", kv->kv_value) == 0) 1242 clt->clt_persist = 0; 1243 else 1244 clt->clt_persist++; 1245 } else { 1246 /* Is the connection persistent? */ 1247 key.kv_key = "Connection"; 1248 if ((kv = kv_find(&desc->http_headers, &key)) != NULL && 1249 strcasecmp("keep-alive", kv->kv_value) == 0) 1250 clt->clt_persist++; 1251 else 1252 clt->clt_persist = 0; 1253 } 1254 1255 /* 1256 * Do we have a Host header and matching configuration? 1257 * XXX the Host can also appear in the URL path. 1258 */ 1259 if (host != NULL) { 1260 if ((hostval = server_http_parsehost(host->kv_value, 1261 hostname, sizeof(hostname), &portval)) == NULL) 1262 goto fail; 1263 1264 TAILQ_FOREACH(srv_conf, &srv->srv_hosts, entry) { 1265 #ifdef DEBUG 1266 if ((srv_conf->flags & SRVFLAG_LOCATION) == 0) { 1267 DPRINTF("%s: virtual host \"%s:%u\"" 1268 " host \"%s\" (\"%s\")", 1269 __func__, srv_conf->name, 1270 ntohs(srv_conf->port), host->kv_value, 1271 hostname); 1272 } 1273 #endif 1274 if (srv_conf->flags & SRVFLAG_LOCATION) 1275 continue; 1276 else if (srv_conf->flags & SRVFLAG_SERVER_MATCH) { 1277 str_find(hostname, srv_conf->name, 1278 &sm, 1, &errstr); 1279 ret = errstr == NULL ? 0 : -1; 1280 } else { 1281 ret = fnmatch(srv_conf->name, 1282 hostname, FNM_CASEFOLD); 1283 } 1284 if (ret == 0 && 1285 (portval == -1 || portval == srv_conf->port)) { 1286 /* Replace host configuration */ 1287 clt->clt_srv_conf = srv_conf; 1288 srv_conf = NULL; 1289 break; 1290 } 1291 } 1292 } 1293 1294 if (srv_conf != NULL) { 1295 /* Use the actual server IP address */ 1296 if (server_http_host(&clt->clt_srv_ss, hostname, 1297 sizeof(hostname)) == NULL) 1298 goto fail; 1299 } else { 1300 /* Host header was valid and found */ 1301 if (strlcpy(hostname, host->kv_value, sizeof(hostname)) >= 1302 sizeof(hostname)) 1303 goto fail; 1304 srv_conf = clt->clt_srv_conf; 1305 } 1306 1307 if (clt->clt_persist >= srv_conf->maxrequests) 1308 clt->clt_persist = 0; 1309 1310 /* pipelining should end after the first "idempotent" method */ 1311 if (clt->clt_pipelining && clt->clt_toread > 0) 1312 clt->clt_persist = 0; 1313 1314 if ((desc->http_host = strdup(hostname)) == NULL) 1315 goto fail; 1316 1317 /* Now fill in the mandatory parts of the response descriptor */ 1318 resp->http_method = desc->http_method; 1319 if ((resp->http_version = strdup(desc->http_version)) == NULL) 1320 goto fail; 1321 1322 /* Now search for the location */ 1323 if ((srv_conf = server_getlocation(clt, 1324 desc->http_path)) == NULL) { 1325 server_abort_http(clt, 500, desc->http_path); 1326 return (-1); 1327 } 1328 1329 /* Optional rewrite */ 1330 if (srv_conf->flags & SRVFLAG_PATH_REWRITE) { 1331 /* Expand macros */ 1332 if (server_expand_http(clt, srv_conf->path, 1333 path, sizeof(path)) == NULL) 1334 goto fail; 1335 1336 /* 1337 * Reset and update the query. The updated query must already 1338 * be URL encoded - either specified by the user or by using the 1339 * original $QUERY_STRING. 1340 */ 1341 free(desc->http_query_alias); 1342 desc->http_query_alias = NULL; 1343 if ((query = strchr(path, '?')) != NULL) { 1344 *query++ = '\0'; 1345 if ((desc->http_query_alias = strdup(query)) == NULL) 1346 goto fail; 1347 } 1348 1349 /* Canonicalize the updated request path */ 1350 if (canonicalize_path(path, 1351 path, sizeof(path)) == NULL) 1352 goto fail; 1353 1354 log_debug("%s: rewrote %s?%s -> %s?%s", __func__, 1355 desc->http_path, desc->http_query ? desc->http_query : "", 1356 path, query ? query : ""); 1357 1358 free(desc->http_path_alias); 1359 if ((desc->http_path_alias = strdup(path)) == NULL) 1360 goto fail; 1361 1362 /* Now search for the updated location */ 1363 if ((srv_conf = server_getlocation(clt, 1364 desc->http_path_alias)) == NULL) { 1365 server_abort_http(clt, 500, desc->http_path_alias); 1366 return (-1); 1367 } 1368 } 1369 1370 if (clt->clt_toread > 0 && (size_t)clt->clt_toread > 1371 srv_conf->maxrequestbody) { 1372 server_abort_http(clt, 413, NULL); 1373 return (-1); 1374 } 1375 1376 if (srv_conf->flags & SRVFLAG_BLOCK) { 1377 server_abort_http(clt, srv_conf->return_code, 1378 srv_conf->return_uri); 1379 return (-1); 1380 } else if (srv_conf->flags & SRVFLAG_AUTH && 1381 server_http_authenticate(srv_conf, clt) == -1) { 1382 server_abort_http(clt, 401, srv_conf->auth_realm); 1383 return (-1); 1384 } else 1385 return (server_file(httpd, clt)); 1386 fail: 1387 server_abort_http(clt, 400, "bad request"); 1388 return (-1); 1389 } 1390 1391 const char * 1392 server_root_strip(const char *path, int n) 1393 { 1394 const char *p; 1395 1396 /* Strip strip leading directories. Leading '/' is ignored. */ 1397 for (; n > 0 && *path != '\0'; n--) 1398 if ((p = strchr(++path, '/')) == NULL) 1399 path = strchr(path, '\0'); 1400 else 1401 path = p; 1402 1403 return (path); 1404 } 1405 1406 struct server_config * 1407 server_getlocation(struct client *clt, const char *path) 1408 { 1409 struct server *srv = clt->clt_srv; 1410 struct server_config *srv_conf = clt->clt_srv_conf, *location; 1411 const char *errstr = NULL; 1412 int ret; 1413 1414 /* Now search for the location */ 1415 TAILQ_FOREACH(location, &srv->srv_hosts, entry) { 1416 #ifdef DEBUG 1417 if (location->flags & SRVFLAG_LOCATION) { 1418 DPRINTF("%s: location \"%s\" path \"%s\"", 1419 __func__, location->location, path); 1420 } 1421 #endif 1422 if ((location->flags & SRVFLAG_LOCATION) && 1423 location->parent_id == srv_conf->parent_id) { 1424 errstr = NULL; 1425 if (location->flags & SRVFLAG_LOCATION_MATCH) { 1426 ret = str_match(path, location->location, 1427 &clt->clt_srv_match, &errstr); 1428 } else { 1429 ret = fnmatch(location->location, 1430 path, FNM_CASEFOLD); 1431 } 1432 if (ret == 0 && errstr == NULL) { 1433 if ((ret = server_locationaccesstest(location, 1434 path)) == -1) 1435 return (NULL); 1436 1437 if (ret) 1438 continue; 1439 /* Replace host configuration */ 1440 clt->clt_srv_conf = srv_conf = location; 1441 break; 1442 } 1443 } 1444 } 1445 1446 return (srv_conf); 1447 } 1448 1449 int 1450 server_locationaccesstest(struct server_config *srv_conf, const char *path) 1451 { 1452 int rootfd, ret; 1453 struct stat sb; 1454 1455 if (((SRVFLAG_LOCATION_FOUND | SRVFLAG_LOCATION_NOT_FOUND) & 1456 srv_conf->flags) == 0) 1457 return (0); 1458 1459 if ((rootfd = open(srv_conf->root, O_RDONLY)) == -1) 1460 return (-1); 1461 1462 path = server_root_strip(path, srv_conf->strip) + 1; 1463 if ((ret = faccessat(rootfd, path, R_OK, 0)) != -1) 1464 ret = fstatat(rootfd, path, &sb, 0); 1465 close(rootfd); 1466 return ((ret == -1 && SRVFLAG_LOCATION_FOUND & srv_conf->flags) || 1467 (ret == 0 && SRVFLAG_LOCATION_NOT_FOUND & srv_conf->flags)); 1468 } 1469 1470 int 1471 server_response_http(struct client *clt, unsigned int code, 1472 struct media_type *media, off_t size, time_t mtime) 1473 { 1474 struct server_config *srv_conf = clt->clt_srv_conf; 1475 struct http_descriptor *desc = clt->clt_descreq; 1476 struct http_descriptor *resp = clt->clt_descresp; 1477 const char *error; 1478 struct kv *ct, *cl; 1479 char tmbuf[32]; 1480 1481 if (desc == NULL || media == NULL || 1482 (error = server_httperror_byid(code)) == NULL) 1483 return (-1); 1484 1485 if (server_log_http(clt, code, size >= 0 ? size : 0) == -1) 1486 return (-1); 1487 1488 /* Add error codes */ 1489 if (kv_setkey(&resp->http_pathquery, "%u", code) == -1 || 1490 kv_set(&resp->http_pathquery, "%s", error) == -1) 1491 return (-1); 1492 1493 /* Add headers */ 1494 if (kv_add(&resp->http_headers, "Server", HTTPD_SERVERNAME) == NULL) 1495 return (-1); 1496 1497 /* Is it a persistent connection? */ 1498 if (clt->clt_persist) { 1499 if (kv_add(&resp->http_headers, 1500 "Connection", "keep-alive") == NULL) 1501 return (-1); 1502 } else if (kv_add(&resp->http_headers, "Connection", "close") == NULL) 1503 return (-1); 1504 1505 /* Set media type */ 1506 if ((ct = kv_add(&resp->http_headers, "Content-Type", NULL)) == NULL || 1507 kv_set(ct, "%s/%s", media->media_type, media->media_subtype) == -1) 1508 return (-1); 1509 1510 /* Set content length, if specified */ 1511 if (size >= 0 && ((cl = 1512 kv_add(&resp->http_headers, "Content-Length", NULL)) == NULL || 1513 kv_set(cl, "%lld", (long long)size) == -1)) 1514 return (-1); 1515 1516 /* Set last modification time */ 1517 if (server_http_time(mtime, tmbuf, sizeof(tmbuf)) <= 0 || 1518 kv_add(&resp->http_headers, "Last-Modified", tmbuf) == NULL) 1519 return (-1); 1520 1521 /* HSTS header */ 1522 if (srv_conf->flags & SRVFLAG_SERVER_HSTS && 1523 srv_conf->flags & SRVFLAG_TLS) { 1524 if ((cl = 1525 kv_add(&resp->http_headers, "Strict-Transport-Security", 1526 NULL)) == NULL || 1527 kv_set(cl, "max-age=%d%s%s", srv_conf->hsts_max_age, 1528 srv_conf->hsts_flags & HSTSFLAG_SUBDOMAINS ? 1529 "; includeSubDomains" : "", 1530 srv_conf->hsts_flags & HSTSFLAG_PRELOAD ? 1531 "; preload" : "") == -1) 1532 return (-1); 1533 } 1534 1535 /* Date header is mandatory and should be added as late as possible */ 1536 if (server_http_time(time(NULL), tmbuf, sizeof(tmbuf)) <= 0 || 1537 kv_add(&resp->http_headers, "Date", tmbuf) == NULL) 1538 return (-1); 1539 1540 /* Write completed header */ 1541 if (server_writeresponse_http(clt) == -1 || 1542 server_bufferevent_print(clt, "\r\n") == -1 || 1543 server_headers(clt, resp, server_writeheader_http, NULL) == -1 || 1544 server_bufferevent_print(clt, "\r\n") == -1) 1545 return (-1); 1546 1547 if (size <= 0 || resp->http_method == HTTP_METHOD_HEAD) { 1548 bufferevent_enable(clt->clt_bev, EV_READ|EV_WRITE); 1549 if (clt->clt_persist) 1550 clt->clt_toread = TOREAD_HTTP_HEADER; 1551 else 1552 clt->clt_toread = TOREAD_HTTP_NONE; 1553 clt->clt_done = 0; 1554 return (0); 1555 } 1556 1557 return (1); 1558 } 1559 1560 int 1561 server_writeresponse_http(struct client *clt) 1562 { 1563 struct http_descriptor *desc = clt->clt_descresp; 1564 1565 DPRINTF("version: %s rescode: %s resmsg: %s", desc->http_version, 1566 desc->http_rescode, desc->http_resmesg); 1567 1568 if (server_bufferevent_print(clt, desc->http_version) == -1 || 1569 server_bufferevent_print(clt, " ") == -1 || 1570 server_bufferevent_print(clt, desc->http_rescode) == -1 || 1571 server_bufferevent_print(clt, " ") == -1 || 1572 server_bufferevent_print(clt, desc->http_resmesg) == -1) 1573 return (-1); 1574 1575 return (0); 1576 } 1577 1578 int 1579 server_writeheader_http(struct client *clt, struct kv *hdr, void *arg) 1580 { 1581 char *ptr; 1582 const char *key; 1583 1584 if (hdr->kv_flags & KV_FLAG_INVALID) 1585 return (0); 1586 1587 /* The key might have been updated in the parent */ 1588 if (hdr->kv_parent != NULL && hdr->kv_parent->kv_key != NULL) 1589 key = hdr->kv_parent->kv_key; 1590 else 1591 key = hdr->kv_key; 1592 1593 ptr = hdr->kv_value; 1594 if (server_bufferevent_print(clt, key) == -1 || 1595 (ptr != NULL && 1596 (server_bufferevent_print(clt, ": ") == -1 || 1597 server_bufferevent_print(clt, ptr) == -1 || 1598 server_bufferevent_print(clt, "\r\n") == -1))) 1599 return (-1); 1600 DPRINTF("%s: %s: %s", __func__, key, 1601 hdr->kv_value == NULL ? "" : hdr->kv_value); 1602 1603 return (0); 1604 } 1605 1606 int 1607 server_headers(struct client *clt, void *descp, 1608 int (*hdr_cb)(struct client *, struct kv *, void *), void *arg) 1609 { 1610 struct kv *hdr, *kv; 1611 struct http_descriptor *desc = descp; 1612 1613 RB_FOREACH(hdr, kvtree, &desc->http_headers) { 1614 if ((hdr_cb)(clt, hdr, arg) == -1) 1615 return (-1); 1616 TAILQ_FOREACH(kv, &hdr->kv_children, kv_entry) { 1617 if ((hdr_cb)(clt, kv, arg) == -1) 1618 return (-1); 1619 } 1620 } 1621 1622 return (0); 1623 } 1624 1625 enum httpmethod 1626 server_httpmethod_byname(const char *name) 1627 { 1628 enum httpmethod id = HTTP_METHOD_NONE; 1629 struct http_method method, *res = NULL; 1630 1631 /* Set up key */ 1632 method.method_name = name; 1633 1634 if ((res = bsearch(&method, http_methods, 1635 sizeof(http_methods) / sizeof(http_methods[0]) - 1, 1636 sizeof(http_methods[0]), server_httpmethod_cmp)) != NULL) 1637 id = res->method_id; 1638 1639 return (id); 1640 } 1641 1642 const char * 1643 server_httpmethod_byid(unsigned int id) 1644 { 1645 const char *name = "<UNKNOWN>"; 1646 int i; 1647 1648 for (i = 0; http_methods[i].method_name != NULL; i++) { 1649 if (http_methods[i].method_id == id) { 1650 name = http_methods[i].method_name; 1651 break; 1652 } 1653 } 1654 1655 return (name); 1656 } 1657 1658 static int 1659 server_httpmethod_cmp(const void *a, const void *b) 1660 { 1661 const struct http_method *ma = a; 1662 const struct http_method *mb = b; 1663 1664 /* 1665 * RFC 2616 section 5.1.1 says that the method is case 1666 * sensitive so we don't do a strcasecmp here. 1667 */ 1668 return (strcmp(ma->method_name, mb->method_name)); 1669 } 1670 1671 const char * 1672 server_httperror_byid(unsigned int id) 1673 { 1674 struct http_error error, *res; 1675 1676 /* Set up key */ 1677 error.error_code = (int)id; 1678 1679 if ((res = bsearch(&error, http_errors, 1680 sizeof(http_errors) / sizeof(http_errors[0]) - 1, 1681 sizeof(http_errors[0]), server_httperror_cmp)) != NULL) 1682 return (res->error_name); 1683 1684 return (NULL); 1685 } 1686 1687 static int 1688 server_httperror_cmp(const void *a, const void *b) 1689 { 1690 const struct http_error *ea = a; 1691 const struct http_error *eb = b; 1692 return (ea->error_code - eb->error_code); 1693 } 1694 1695 int 1696 server_log_http(struct client *clt, unsigned int code, size_t len) 1697 { 1698 static char tstamp[64]; 1699 static char ip[INET6_ADDRSTRLEN]; 1700 time_t t; 1701 struct kv key, *agent, *referrer, *xff, *xfp; 1702 struct tm *tm; 1703 struct server_config *srv_conf; 1704 struct http_descriptor *desc; 1705 int ret = -1; 1706 char *user = NULL; 1707 char *path = NULL; 1708 char *version = NULL; 1709 char *referrer_v = NULL; 1710 char *agent_v = NULL; 1711 char *xff_v = NULL; 1712 char *xfp_v = NULL; 1713 1714 if ((srv_conf = clt->clt_srv_conf) == NULL) 1715 return (-1); 1716 if ((srv_conf->flags & SRVFLAG_LOG) == 0) 1717 return (0); 1718 if ((desc = clt->clt_descreq) == NULL) 1719 return (-1); 1720 1721 if ((t = time(NULL)) == -1) 1722 return (-1); 1723 if ((tm = localtime(&t)) == NULL) 1724 return (-1); 1725 if (strftime(tstamp, sizeof(tstamp), "%d/%b/%Y:%H:%M:%S %z", tm) == 0) 1726 return (-1); 1727 1728 if (print_host(&clt->clt_ss, ip, sizeof(ip)) == NULL) 1729 return (-1); 1730 1731 /* 1732 * For details on common log format, see: 1733 * https://httpd.apache.org/docs/current/mod/mod_log_config.html 1734 * 1735 * httpd's format is similar to these Apache LogFormats: 1736 * "%v %h %l %u %t \"%r\" %>s %B" 1737 * "%v %h %l %u %t \"%r\" %>s %B \"%{Referer}i\" \"%{User-agent}i\"" 1738 */ 1739 switch (srv_conf->logformat) { 1740 case LOG_FORMAT_COMMON: 1741 /* Use vis to encode input values from the header */ 1742 if (clt->clt_remote_user && 1743 stravis(&user, clt->clt_remote_user, HTTPD_LOGVIS) == -1) 1744 goto done; 1745 if (desc->http_version && 1746 stravis(&version, desc->http_version, HTTPD_LOGVIS) == -1) 1747 goto done; 1748 1749 /* The following should be URL-encoded */ 1750 if (desc->http_path && 1751 (path = url_encode(desc->http_path)) == NULL) 1752 goto done; 1753 1754 ret = evbuffer_add_printf(clt->clt_log, 1755 "%s %s - %s [%s] \"%s %s%s%s%s%s\" %03d %zu\n", 1756 srv_conf->name, ip, clt->clt_remote_user == NULL ? "-" : 1757 user, tstamp, 1758 server_httpmethod_byid(desc->http_method), 1759 desc->http_path == NULL ? "" : path, 1760 desc->http_query == NULL ? "" : "?", 1761 desc->http_query == NULL ? "" : desc->http_query, 1762 desc->http_version == NULL ? "" : " ", 1763 desc->http_version == NULL ? "" : version, 1764 code, len); 1765 1766 break; 1767 1768 case LOG_FORMAT_COMBINED: 1769 case LOG_FORMAT_FORWARDED: 1770 key.kv_key = "Referer"; /* sic */ 1771 if ((referrer = kv_find(&desc->http_headers, &key)) != NULL && 1772 referrer->kv_value == NULL) 1773 referrer = NULL; 1774 1775 key.kv_key = "User-Agent"; 1776 if ((agent = kv_find(&desc->http_headers, &key)) != NULL && 1777 agent->kv_value == NULL) 1778 agent = NULL; 1779 1780 /* Use vis to encode input values from the header */ 1781 if (clt->clt_remote_user && 1782 stravis(&user, clt->clt_remote_user, HTTPD_LOGVIS) == -1) 1783 goto done; 1784 if (clt->clt_remote_user == NULL && 1785 clt->clt_tls_ctx != NULL && 1786 (srv_conf->tls_flags & TLSFLAG_CA) && 1787 tls_peer_cert_subject(clt->clt_tls_ctx) != NULL && 1788 stravis(&user, tls_peer_cert_subject(clt->clt_tls_ctx), 1789 HTTPD_LOGVIS) == -1) 1790 goto done; 1791 if (desc->http_version && 1792 stravis(&version, desc->http_version, HTTPD_LOGVIS) == -1) 1793 goto done; 1794 if (agent && 1795 stravis(&agent_v, agent->kv_value, HTTPD_LOGVIS) == -1) 1796 goto done; 1797 1798 /* The following should be URL-encoded */ 1799 if (desc->http_path && 1800 (path = url_encode(desc->http_path)) == NULL) 1801 goto done; 1802 if (referrer && 1803 (referrer_v = url_encode(referrer->kv_value)) == NULL) 1804 goto done; 1805 1806 if ((ret = evbuffer_add_printf(clt->clt_log, 1807 "%s %s - %s [%s] \"%s %s%s%s%s%s\"" 1808 " %03d %zu \"%s\" \"%s\"", 1809 srv_conf->name, ip, user == NULL ? "-" : 1810 user, tstamp, 1811 server_httpmethod_byid(desc->http_method), 1812 desc->http_path == NULL ? "" : path, 1813 desc->http_query == NULL ? "" : "?", 1814 desc->http_query == NULL ? "" : desc->http_query, 1815 desc->http_version == NULL ? "" : " ", 1816 desc->http_version == NULL ? "" : version, 1817 code, len, 1818 referrer == NULL ? "" : referrer_v, 1819 agent == NULL ? "" : agent_v)) == -1) 1820 break; 1821 1822 if (srv_conf->logformat == LOG_FORMAT_COMBINED) 1823 goto finish; 1824 1825 xff = xfp = NULL; 1826 1827 key.kv_key = "X-Forwarded-For"; 1828 if ((xff = kv_find(&desc->http_headers, &key)) != NULL 1829 && xff->kv_value == NULL) 1830 xff = NULL; 1831 1832 if (xff && 1833 stravis(&xff_v, xff->kv_value, HTTPD_LOGVIS) == -1) 1834 goto finish; 1835 1836 key.kv_key = "X-Forwarded-Port"; 1837 if ((xfp = kv_find(&desc->http_headers, &key)) != NULL && 1838 (xfp->kv_value == NULL)) 1839 xfp = NULL; 1840 1841 if (xfp && 1842 stravis(&xfp_v, xfp->kv_value, HTTPD_LOGVIS) == -1) 1843 goto finish; 1844 1845 if ((ret = evbuffer_add_printf(clt->clt_log, " %s %s", 1846 xff == NULL ? "-" : xff_v, 1847 xfp == NULL ? "-" : xfp_v)) == -1) 1848 break; 1849 finish: 1850 ret = evbuffer_add_printf(clt->clt_log, "\n"); 1851 1852 break; 1853 1854 case LOG_FORMAT_CONNECTION: 1855 /* URL-encode the path */ 1856 if (desc->http_path && 1857 (path = url_encode(desc->http_path)) == NULL) 1858 goto done; 1859 1860 ret = evbuffer_add_printf(clt->clt_log, " [%s]", 1861 desc->http_path == NULL ? "" : path); 1862 1863 break; 1864 } 1865 1866 done: 1867 free(user); 1868 free(path); 1869 free(version); 1870 free(referrer_v); 1871 free(agent_v); 1872 free(xff_v); 1873 free(xfp_v); 1874 1875 return (ret); 1876 } 1877