1 /* $Id: http.c,v 1.31 2021/09/14 16:37:20 tb Exp $ */ 2 /* 3 * Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/types.h> 19 #include <sys/socket.h> 20 21 #include <arpa/inet.h> 22 #include <netinet/in.h> 23 24 #include <ctype.h> 25 #include <err.h> 26 #include <limits.h> 27 #include <netdb.h> 28 #include <stdio.h> 29 #include <stdint.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <tls.h> 33 #include <unistd.h> 34 35 #include "http.h" 36 #include "extern.h" 37 38 /* 39 * A buffer for transferring HTTP/S data. 40 */ 41 struct httpxfer { 42 char *hbuf; /* header transfer buffer */ 43 size_t hbufsz; /* header buffer size */ 44 int headok; /* header has been parsed */ 45 char *bbuf; /* body transfer buffer */ 46 size_t bbufsz; /* body buffer size */ 47 int bodyok; /* body has been parsed */ 48 char *headbuf; /* lookaside buffer for headers */ 49 struct httphead *head; /* parsed headers */ 50 size_t headsz; /* number of headers */ 51 }; 52 53 /* 54 * An HTTP/S connection object. 55 */ 56 struct http { 57 int fd; /* connected socket */ 58 short port; /* port number */ 59 struct source src; /* endpoint (raw) host */ 60 char *path; /* path to request */ 61 char *host; /* name of endpoint host */ 62 struct tls *ctx; /* if TLS */ 63 writefp writer; /* write function */ 64 readfp reader; /* read function */ 65 }; 66 67 struct tls_config *tlscfg; 68 69 static ssize_t 70 dosysread(char *buf, size_t sz, const struct http *http) 71 { 72 ssize_t rc; 73 74 rc = read(http->fd, buf, sz); 75 if (rc == -1) 76 warn("%s: read", http->src.ip); 77 return rc; 78 } 79 80 static ssize_t 81 dosyswrite(const void *buf, size_t sz, const struct http *http) 82 { 83 ssize_t rc; 84 85 rc = write(http->fd, buf, sz); 86 if (rc == -1) 87 warn("%s: write", http->src.ip); 88 return rc; 89 } 90 91 static ssize_t 92 dotlsread(char *buf, size_t sz, const struct http *http) 93 { 94 ssize_t rc; 95 96 do { 97 rc = tls_read(http->ctx, buf, sz); 98 } while (rc == TLS_WANT_POLLIN || rc == TLS_WANT_POLLOUT); 99 100 if (rc == -1) 101 warnx("%s: tls_read: %s", http->src.ip, 102 tls_error(http->ctx)); 103 return rc; 104 } 105 106 static ssize_t 107 dotlswrite(const void *buf, size_t sz, const struct http *http) 108 { 109 ssize_t rc; 110 111 do { 112 rc = tls_write(http->ctx, buf, sz); 113 } while (rc == TLS_WANT_POLLIN || rc == TLS_WANT_POLLOUT); 114 115 if (rc == -1) 116 warnx("%s: tls_write: %s", http->src.ip, 117 tls_error(http->ctx)); 118 return rc; 119 } 120 121 int 122 http_init(void) 123 { 124 if (tlscfg != NULL) 125 return 0; 126 127 tlscfg = tls_config_new(); 128 if (tlscfg == NULL) { 129 warn("tls_config_new"); 130 goto err; 131 } 132 133 if (tls_config_set_ca_file(tlscfg, tls_default_ca_cert_file()) == -1) { 134 warn("tls_config_set_ca_file: %s", tls_config_error(tlscfg)); 135 goto err; 136 } 137 138 return 0; 139 140 err: 141 tls_config_free(tlscfg); 142 tlscfg = NULL; 143 144 return -1; 145 } 146 147 static ssize_t 148 http_read(char *buf, size_t sz, const struct http *http) 149 { 150 ssize_t ssz, xfer; 151 152 xfer = 0; 153 do { 154 if ((ssz = http->reader(buf, sz, http)) < 0) 155 return -1; 156 if (ssz == 0) 157 break; 158 xfer += ssz; 159 sz -= ssz; 160 buf += ssz; 161 } while (ssz > 0 && sz > 0); 162 163 return xfer; 164 } 165 166 static int 167 http_write(const char *buf, size_t sz, const struct http *http) 168 { 169 ssize_t ssz, xfer; 170 171 xfer = sz; 172 while (sz > 0) { 173 if ((ssz = http->writer(buf, sz, http)) < 0) 174 return -1; 175 sz -= ssz; 176 buf += (size_t)ssz; 177 } 178 return xfer; 179 } 180 181 void 182 http_disconnect(struct http *http) 183 { 184 int rc; 185 186 if (http->ctx != NULL) { 187 /* TLS connection. */ 188 do { 189 rc = tls_close(http->ctx); 190 } while (rc == TLS_WANT_POLLIN || rc == TLS_WANT_POLLOUT); 191 192 tls_free(http->ctx); 193 } 194 if (http->fd != -1) { 195 if (close(http->fd) == -1) 196 warn("%s: close", http->src.ip); 197 } 198 199 http->fd = -1; 200 http->ctx = NULL; 201 } 202 203 void 204 http_free(struct http *http) 205 { 206 207 if (http == NULL) 208 return; 209 http_disconnect(http); 210 free(http->host); 211 free(http->path); 212 free(http->src.ip); 213 free(http); 214 } 215 216 struct http * 217 http_alloc(const struct source *addrs, size_t addrsz, 218 const char *host, short port, const char *path) 219 { 220 struct sockaddr_storage ss; 221 int family, fd, c; 222 socklen_t len; 223 size_t cur, i = 0; 224 struct http *http; 225 226 /* Do this while we still have addresses to connect. */ 227 again: 228 if (i == addrsz) 229 return NULL; 230 cur = i++; 231 232 /* Convert to PF_INET or PF_INET6 address from string. */ 233 234 memset(&ss, 0, sizeof(struct sockaddr_storage)); 235 236 if (addrs[cur].family == 4) { 237 family = PF_INET; 238 ((struct sockaddr_in *)&ss)->sin_family = AF_INET; 239 ((struct sockaddr_in *)&ss)->sin_port = htons(port); 240 c = inet_pton(AF_INET, addrs[cur].ip, 241 &((struct sockaddr_in *)&ss)->sin_addr); 242 len = sizeof(struct sockaddr_in); 243 } else if (addrs[cur].family == 6) { 244 family = PF_INET6; 245 ((struct sockaddr_in6 *)&ss)->sin6_family = AF_INET6; 246 ((struct sockaddr_in6 *)&ss)->sin6_port = htons(port); 247 c = inet_pton(AF_INET6, addrs[cur].ip, 248 &((struct sockaddr_in6 *)&ss)->sin6_addr); 249 len = sizeof(struct sockaddr_in6); 250 } else { 251 warnx("%s: unknown family", addrs[cur].ip); 252 goto again; 253 } 254 255 if (c < 0) { 256 warn("%s: inet_ntop", addrs[cur].ip); 257 goto again; 258 } else if (c == 0) { 259 warnx("%s: inet_ntop", addrs[cur].ip); 260 goto again; 261 } 262 263 /* Create socket and connect. */ 264 265 fd = socket(family, SOCK_STREAM, 0); 266 if (fd == -1) { 267 warn("%s: socket", addrs[cur].ip); 268 goto again; 269 } else if (connect(fd, (struct sockaddr *)&ss, len) == -1) { 270 warn("%s: connect", addrs[cur].ip); 271 close(fd); 272 goto again; 273 } 274 275 /* Allocate the communicator. */ 276 277 http = calloc(1, sizeof(struct http)); 278 if (http == NULL) { 279 warn("calloc"); 280 close(fd); 281 return NULL; 282 } 283 http->fd = fd; 284 http->port = port; 285 http->src.family = addrs[cur].family; 286 http->src.ip = strdup(addrs[cur].ip); 287 http->host = strdup(host); 288 http->path = strdup(path); 289 if (http->src.ip == NULL || http->host == NULL || http->path == NULL) { 290 warn("strdup"); 291 goto err; 292 } 293 294 /* If necessary, do our TLS setup. */ 295 296 if (port != 443) { 297 http->writer = dosyswrite; 298 http->reader = dosysread; 299 return http; 300 } 301 302 http->writer = dotlswrite; 303 http->reader = dotlsread; 304 305 if ((http->ctx = tls_client()) == NULL) { 306 warn("tls_client"); 307 goto err; 308 } else if (tls_configure(http->ctx, tlscfg) == -1) { 309 warnx("%s: tls_configure: %s", 310 http->src.ip, tls_error(http->ctx)); 311 goto err; 312 } 313 314 if (tls_connect_socket(http->ctx, http->fd, http->host) != 0) { 315 warnx("%s: tls_connect_socket: %s, %s", http->src.ip, 316 http->host, tls_error(http->ctx)); 317 goto err; 318 } 319 320 return http; 321 err: 322 http_free(http); 323 return NULL; 324 } 325 326 struct httpxfer * 327 http_open(const struct http *http, int headreq, const void *p, size_t psz) 328 { 329 char *req; 330 int c; 331 struct httpxfer *trans; 332 333 if (p == NULL) { 334 if (headreq) 335 c = asprintf(&req, 336 "HEAD %s HTTP/1.0\r\n" 337 "Host: %s\r\n" 338 "User-Agent: OpenBSD-acme-client\r\n" 339 "\r\n", 340 http->path, http->host); 341 else 342 c = asprintf(&req, 343 "GET %s HTTP/1.0\r\n" 344 "Host: %s\r\n" 345 "User-Agent: OpenBSD-acme-client\r\n" 346 "\r\n", 347 http->path, http->host); 348 } else { 349 c = asprintf(&req, 350 "POST %s HTTP/1.0\r\n" 351 "Host: %s\r\n" 352 "Content-Length: %zu\r\n" 353 "Content-Type: application/jose+json\r\n" 354 "User-Agent: OpenBSD-acme-client\r\n" 355 "\r\n", 356 http->path, http->host, psz); 357 } 358 359 if (c == -1) { 360 warn("asprintf"); 361 return NULL; 362 } else if (!http_write(req, c, http)) { 363 free(req); 364 return NULL; 365 } else if (p != NULL && !http_write(p, psz, http)) { 366 free(req); 367 return NULL; 368 } 369 370 free(req); 371 372 trans = calloc(1, sizeof(struct httpxfer)); 373 if (trans == NULL) 374 warn("calloc"); 375 return trans; 376 } 377 378 void 379 http_close(struct httpxfer *x) 380 { 381 382 if (x == NULL) 383 return; 384 free(x->hbuf); 385 free(x->bbuf); 386 free(x->headbuf); 387 free(x->head); 388 free(x); 389 } 390 391 /* 392 * Read the HTTP body from the wire. 393 * If invoked multiple times, this will return the same pointer with the 394 * same data (or NULL, if the original invocation returned NULL). 395 * Returns NULL if read or allocation errors occur. 396 * You must not free the returned pointer. 397 */ 398 char * 399 http_body_read(const struct http *http, struct httpxfer *trans, size_t *sz) 400 { 401 char buf[BUFSIZ]; 402 ssize_t ssz; 403 void *pp; 404 size_t szp; 405 406 if (sz == NULL) 407 sz = &szp; 408 409 /* Have we already parsed this? */ 410 411 if (trans->bodyok > 0) { 412 *sz = trans->bbufsz; 413 return trans->bbuf; 414 } else if (trans->bodyok < 0) 415 return NULL; 416 417 *sz = 0; 418 trans->bodyok = -1; 419 420 do { 421 /* If less than sizeof(buf), at EOF. */ 422 if ((ssz = http_read(buf, sizeof(buf), http)) < 0) 423 return NULL; 424 else if (ssz == 0) 425 break; 426 pp = recallocarray(trans->bbuf, 427 trans->bbufsz, trans->bbufsz + ssz, 1); 428 if (pp == NULL) { 429 warn("recallocarray"); 430 return NULL; 431 } 432 trans->bbuf = pp; 433 memcpy(trans->bbuf + trans->bbufsz, buf, ssz); 434 trans->bbufsz += ssz; 435 } while (ssz == sizeof(buf)); 436 437 trans->bodyok = 1; 438 *sz = trans->bbufsz; 439 return trans->bbuf; 440 } 441 442 struct httphead * 443 http_head_get(const char *v, struct httphead *h, size_t hsz) 444 { 445 size_t i; 446 447 for (i = 0; i < hsz; i++) { 448 if (strcasecmp(h[i].key, v) == 0) 449 return &h[i]; 450 } 451 return NULL; 452 } 453 454 /* 455 * Look through the headers and determine our HTTP code. 456 * This will return -1 on failure, otherwise the code. 457 */ 458 int 459 http_head_status(const struct http *http, struct httphead *h, size_t sz) 460 { 461 int rc; 462 unsigned int code; 463 struct httphead *st; 464 465 if ((st = http_head_get("Status", h, sz)) == NULL) { 466 warnx("%s: no status header", http->src.ip); 467 return -1; 468 } 469 470 rc = sscanf(st->val, "%*s %u %*s", &code); 471 if (rc < 0) { 472 warn("sscanf"); 473 return -1; 474 } else if (rc != 1) { 475 warnx("%s: cannot convert status header", http->src.ip); 476 return -1; 477 } 478 return code; 479 } 480 481 /* 482 * Parse headers from the transfer. 483 * Malformed headers are skipped. 484 * A special "Status" header is added for the HTTP status line. 485 * This can only happen once http_head_read has been called with 486 * success. 487 * This can be invoked multiple times: it will only parse the headers 488 * once and after that it will just return the cache. 489 * You must not free the returned pointer. 490 * If the original header parse failed, or if memory allocation fails 491 * internally, this returns NULL. 492 */ 493 struct httphead * 494 http_head_parse(const struct http *http, struct httpxfer *trans, size_t *sz) 495 { 496 size_t hsz, szp; 497 struct httphead *h; 498 char *cp, *ep, *ccp, *buf; 499 500 if (sz == NULL) 501 sz = &szp; 502 503 /* 504 * If we've already parsed the headers, return the 505 * previously-parsed buffer now. 506 * If we have errors on the stream, return NULL now. 507 */ 508 509 if (trans->head != NULL) { 510 *sz = trans->headsz; 511 return trans->head; 512 } else if (trans->headok <= 0) 513 return NULL; 514 515 if ((buf = strdup(trans->hbuf)) == NULL) { 516 warn("strdup"); 517 return NULL; 518 } 519 hsz = 0; 520 cp = buf; 521 522 do { 523 if ((cp = strstr(cp, "\r\n")) != NULL) 524 cp += 2; 525 hsz++; 526 } while (cp != NULL); 527 528 /* 529 * Allocate headers, then step through the data buffer, parsing 530 * out headers as we have them. 531 * We know at this point that the buffer is NUL-terminated in 532 * the usual way. 533 */ 534 535 h = calloc(hsz, sizeof(struct httphead)); 536 if (h == NULL) { 537 warn("calloc"); 538 free(buf); 539 return NULL; 540 } 541 542 *sz = hsz; 543 hsz = 0; 544 cp = buf; 545 546 do { 547 if ((ep = strstr(cp, "\r\n")) != NULL) { 548 *ep = '\0'; 549 ep += 2; 550 } 551 if (hsz == 0) { 552 h[hsz].key = "Status"; 553 h[hsz++].val = cp; 554 continue; 555 } 556 557 /* Skip bad headers. */ 558 if ((ccp = strchr(cp, ':')) == NULL) { 559 warnx("%s: header without separator", http->src.ip); 560 continue; 561 } 562 563 *ccp++ = '\0'; 564 while (isspace((int)*ccp)) 565 ccp++; 566 h[hsz].key = cp; 567 h[hsz++].val = ccp; 568 } while ((cp = ep) != NULL); 569 570 trans->headbuf = buf; 571 trans->head = h; 572 trans->headsz = hsz; 573 return h; 574 } 575 576 /* 577 * Read the HTTP headers from the wire. 578 * If invoked multiple times, this will return the same pointer with the 579 * same data (or NULL, if the original invocation returned NULL). 580 * Returns NULL if read or allocation errors occur. 581 * You must not free the returned pointer. 582 */ 583 char * 584 http_head_read(const struct http *http, struct httpxfer *trans, size_t *sz) 585 { 586 char buf[BUFSIZ]; 587 ssize_t ssz; 588 char *ep; 589 void *pp; 590 size_t szp; 591 592 if (sz == NULL) 593 sz = &szp; 594 595 /* Have we already parsed this? */ 596 597 if (trans->headok > 0) { 598 *sz = trans->hbufsz; 599 return trans->hbuf; 600 } else if (trans->headok < 0) 601 return NULL; 602 603 *sz = 0; 604 ep = NULL; 605 trans->headok = -1; 606 607 /* 608 * Begin by reading by BUFSIZ blocks until we reach the header 609 * termination marker (two CRLFs). 610 * We might read into our body, but that's ok: we'll copy out 611 * the body parts into our body buffer afterward. 612 */ 613 614 do { 615 /* If less than sizeof(buf), at EOF. */ 616 if ((ssz = http_read(buf, sizeof(buf), http)) < 0) 617 return NULL; 618 else if (ssz == 0) 619 break; 620 pp = recallocarray(trans->hbuf, 621 trans->hbufsz, trans->hbufsz + ssz, 1); 622 if (pp == NULL) { 623 warn("recallocarray"); 624 return NULL; 625 } 626 trans->hbuf = pp; 627 memcpy(trans->hbuf + trans->hbufsz, buf, ssz); 628 trans->hbufsz += ssz; 629 /* Search for end of headers marker. */ 630 ep = memmem(trans->hbuf, trans->hbufsz, "\r\n\r\n", 4); 631 } while (ep == NULL && ssz == sizeof(buf)); 632 633 if (ep == NULL) { 634 warnx("%s: partial transfer", http->src.ip); 635 return NULL; 636 } 637 *ep = '\0'; 638 639 /* 640 * The header data is invalid if it has any binary characters in 641 * it: check that now. 642 * This is important because we want to guarantee that all 643 * header keys and pairs are properly NUL-terminated. 644 */ 645 646 if (strlen(trans->hbuf) != (uintptr_t)(ep - trans->hbuf)) { 647 warnx("%s: binary data in header", http->src.ip); 648 return NULL; 649 } 650 651 /* 652 * Copy remaining buffer into body buffer. 653 */ 654 655 ep += 4; 656 trans->bbufsz = (trans->hbuf + trans->hbufsz) - ep; 657 trans->bbuf = malloc(trans->bbufsz); 658 if (trans->bbuf == NULL) { 659 warn("malloc"); 660 return NULL; 661 } 662 memcpy(trans->bbuf, ep, trans->bbufsz); 663 664 trans->headok = 1; 665 *sz = trans->hbufsz; 666 return trans->hbuf; 667 } 668 669 void 670 http_get_free(struct httpget *g) 671 { 672 673 if (g == NULL) 674 return; 675 http_close(g->xfer); 676 http_free(g->http); 677 free(g); 678 } 679 680 struct httpget * 681 http_get(const struct source *addrs, size_t addrsz, const char *domain, 682 short port, const char *path, int headreq, const void *post, size_t postsz) 683 { 684 struct http *h; 685 struct httpxfer *x; 686 struct httpget *g; 687 struct httphead *head; 688 size_t headsz, bodsz, headrsz; 689 int code; 690 char *bod, *headr; 691 692 h = http_alloc(addrs, addrsz, domain, port, path); 693 if (h == NULL) 694 return NULL; 695 696 if ((x = http_open(h, headreq, post, postsz)) == NULL) { 697 http_free(h); 698 return NULL; 699 } else if ((headr = http_head_read(h, x, &headrsz)) == NULL) { 700 http_close(x); 701 http_free(h); 702 return NULL; 703 } else if ((bod = http_body_read(h, x, &bodsz)) == NULL) { 704 http_close(x); 705 http_free(h); 706 return NULL; 707 } 708 709 http_disconnect(h); 710 711 if ((head = http_head_parse(h, x, &headsz)) == NULL) { 712 http_close(x); 713 http_free(h); 714 return NULL; 715 } else if ((code = http_head_status(h, head, headsz)) < 0) { 716 http_close(x); 717 http_free(h); 718 return NULL; 719 } 720 721 if ((g = calloc(1, sizeof(struct httpget))) == NULL) { 722 warn("calloc"); 723 http_close(x); 724 http_free(h); 725 return NULL; 726 } 727 728 g->headpart = headr; 729 g->headpartsz = headrsz; 730 g->bodypart = bod; 731 g->bodypartsz = bodsz; 732 g->head = head; 733 g->headsz = headsz; 734 g->code = code; 735 g->xfer = x; 736 g->http = h; 737 return g; 738 } 739