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