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