1 /* $OpenBSD: slowcgi.c,v 1.6 2023/03/31 09:55:39 claudio Exp $ */ 2 /* 3 * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org> 4 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> 5 * Copyright (c) 2013 David Gwynne <dlg@openbsd.org> 6 * Copyright (c) 2013 Florian Obser <florian@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21 #include <sys/types.h> 22 #include <sys/ioctl.h> 23 #include <sys/queue.h> 24 #include <sys/socket.h> 25 #include <sys/stat.h> 26 #include <sys/time.h> 27 #include <sys/un.h> 28 #include <sys/wait.h> 29 #include <arpa/inet.h> 30 #include <err.h> 31 #include <fcntl.h> 32 #include <errno.h> 33 #include <event.h> 34 #include <limits.h> 35 #include <pwd.h> 36 #include <signal.h> 37 #include <stdio.h> 38 #include <stdarg.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <syslog.h> 42 #include <unistd.h> 43 44 #include "slowcgi.h" 45 #include "bgplgd.h" 46 #include "http.h" 47 48 #define TIMEOUT_DEFAULT 30 49 #define WWW_USER "www" 50 #define BGPLGD_USER "_bgplgd" 51 52 #define FCGI_CONTENT_SIZE 65535 53 #define FCGI_PADDING_SIZE 255 54 #define FCGI_RECORD_SIZE \ 55 (sizeof(struct fcgi_record_header) + FCGI_CONTENT_SIZE + FCGI_PADDING_SIZE) 56 57 #define FCGI_ALIGNMENT 8 58 #define FCGI_ALIGN(n) \ 59 (((n) + (FCGI_ALIGNMENT - 1)) & ~(FCGI_ALIGNMENT - 1)) 60 61 #define STDOUT_DONE 0x1 62 #define STDERR_DONE 0x2 63 #define SCRIPT_DONE 0x4 64 65 #define FCGI_REQUEST_COMPLETE 0 66 #define FCGI_CANT_MPX_CONN 1 67 #define FCGI_OVERLOADED 2 68 #define FCGI_UNKNOWN_ROLE 3 69 70 #define FD_RESERVE 5 71 #define FD_NEEDED 6 72 int cgi_inflight = 0; 73 74 struct listener { 75 struct event ev, pause; 76 }; 77 78 struct env_val { 79 SLIST_ENTRY(env_val) entry; 80 char *key; 81 char *val; 82 }; 83 SLIST_HEAD(env_head, env_val); 84 85 struct fcgi_record_header { 86 uint8_t version; 87 uint8_t type; 88 uint16_t id; 89 uint16_t content_len; 90 uint8_t padding_len; 91 uint8_t reserved; 92 }__packed; 93 94 struct fcgi_response { 95 TAILQ_ENTRY(fcgi_response) entry; 96 uint8_t data[FCGI_RECORD_SIZE]; 97 size_t data_pos; 98 size_t data_len; 99 }; 100 TAILQ_HEAD(fcgi_response_head, fcgi_response); 101 102 struct request { 103 LIST_ENTRY(request) entry; 104 struct event ev; 105 struct event resp_ev; 106 struct event tmo; 107 struct event script_ev; 108 struct event script_err_ev; 109 struct fcgi_response_head response_head; 110 struct env_head env; 111 uint8_t buf[FCGI_RECORD_SIZE]; 112 size_t buf_pos; 113 size_t buf_len; 114 int fd; 115 int env_count; 116 int inflight_fds_accounted; 117 pid_t command_pid; 118 int command_status; 119 int script_flags; 120 uint16_t id; 121 uint8_t request_started; 122 uint8_t request_done; 123 uint8_t timeout_fired; 124 }; 125 126 LIST_HEAD(requests_head, request); 127 128 struct slowcgi_proc { 129 struct requests_head requests; 130 struct event ev_sigchld; 131 }; 132 133 struct fcgi_begin_request_body { 134 uint16_t role; 135 uint8_t flags; 136 uint8_t reserved[5]; 137 }__packed; 138 139 struct fcgi_end_request_body { 140 uint32_t app_status; 141 uint8_t protocol_status; 142 uint8_t reserved[3]; 143 }__packed; 144 145 __dead void usage(void); 146 int slowcgi_listen(char *, struct passwd *); 147 void slowcgi_paused(int, short, void *); 148 int accept_reserve(int, struct sockaddr *, socklen_t *, int, 149 volatile int *); 150 void slowcgi_accept(int, short, void *); 151 void slowcgi_request(int, short, void *); 152 void slowcgi_response(int, short, void *); 153 void slowcgi_add_response(struct request *, struct fcgi_response *); 154 void slowcgi_timeout(int, short, void *); 155 void slowcgi_sig_handler(int, short, void *); 156 size_t parse_record(uint8_t * , size_t, struct request *); 157 void parse_begin_request(uint8_t *, uint16_t, struct request *, 158 uint16_t); 159 void parse_params(uint8_t *, uint16_t, struct request *, uint16_t); 160 void parse_stdin(uint8_t *, uint16_t, struct request *, uint16_t); 161 char *env_get(struct request *, const char *); 162 void error_response(struct request *, int); 163 void exec_cgi(struct request *); 164 void script_std_in(int, short, void *); 165 void script_err_in(int, short, void *); 166 void create_data_record(struct request *, uint8_t, const void *, 167 size_t); 168 void create_end_record(struct request *); 169 void cleanup_request(struct request *); 170 void dump_fcgi_record(const char *, 171 struct fcgi_record_header *); 172 void dump_fcgi_record_header(const char *, 173 struct fcgi_record_header *); 174 void dump_fcgi_begin_request_body(const char *, 175 struct fcgi_begin_request_body *); 176 void dump_fcgi_end_request_body(const char *, 177 struct fcgi_end_request_body *); 178 179 const struct loggers conslogger = { 180 err, 181 errx, 182 warn, 183 warnx, 184 warnx, /* info */ 185 warnx /* debug */ 186 }; 187 188 __dead void syslog_err(int, const char *, ...) 189 __attribute__((__format__ (printf, 2, 3))); 190 __dead void syslog_errx(int, const char *, ...) 191 __attribute__((__format__ (printf, 2, 3))); 192 void syslog_warn(const char *, ...) 193 __attribute__((__format__ (printf, 1, 2))); 194 void syslog_warnx(const char *, ...) 195 __attribute__((__format__ (printf, 1, 2))); 196 void syslog_info(const char *, ...) 197 __attribute__((__format__ (printf, 1, 2))); 198 void syslog_debug(const char *, ...) 199 __attribute__((__format__ (printf, 1, 2))); 200 void syslog_vstrerror(int, int, const char *, va_list) 201 __attribute__((__format__ (printf, 3, 0))); 202 203 const struct loggers syslogger = { 204 syslog_err, 205 syslog_errx, 206 syslog_warn, 207 syslog_warnx, 208 syslog_info, 209 syslog_debug 210 }; 211 212 const struct loggers *logger = &conslogger; 213 214 __dead void 215 usage(void) 216 { 217 extern char *__progname; 218 fprintf(stderr, 219 "usage: %s [-d] [-p path] [-S socket] [-s socket] [-U user]\n", 220 __progname); 221 exit(1); 222 } 223 224 struct timeval timeout = { TIMEOUT_DEFAULT, 0 }; 225 struct timeval kill_timeout = { 5, 0 }; 226 struct slowcgi_proc slowcgi_proc; 227 int debug = 0; 228 int on = 1; 229 char *fcgi_socket = "/var/www/run/bgplgd.sock"; 230 char *bgpctlpath = "bgpctl"; 231 char *bgpctlsock = "/var/run/bgpd.rsock"; 232 233 234 /* 235 * Unveil the command we want to run. 236 * If this has a pathname component in it, interpret as a file 237 * and unveil the file directly. 238 * Otherwise, look up the command in our PATH. 239 */ 240 static void 241 unveil_command(const char *prog) 242 { 243 const char *pp; 244 char *save, *cmd, *path; 245 struct stat st; 246 247 if (strchr(prog, '/') != NULL) { 248 if (unveil(prog, "x") == -1) 249 err(1, "%s: unveil", prog); 250 return; 251 } 252 253 if (getenv("PATH") == NULL) 254 lerrx(1, "PATH is unset"); 255 if ((path = strdup(getenv("PATH"))) == NULL) 256 lerr(1, NULL); 257 save = path; 258 while ((pp = strsep(&path, ":")) != NULL) { 259 if (*pp == '\0') 260 continue; 261 if (asprintf(&cmd, "%s/%s", pp, prog) == -1) 262 lerr(1, NULL); 263 if (lstat(cmd, &st) == -1) { 264 free(cmd); 265 continue; 266 } 267 if (unveil(cmd, "x") == -1) 268 lerr(1, "%s: unveil", cmd); 269 free(cmd); 270 break; 271 } 272 free(save); 273 } 274 275 int 276 main(int argc, char *argv[]) 277 { 278 extern char *__progname; 279 struct listener *l = NULL; 280 struct passwd *pw; 281 struct stat sb; 282 int c, fd; 283 const char *sock_user = WWW_USER; 284 const char *cgi_user = BGPLGD_USER; 285 286 /* 287 * Ensure we have fds 0-2 open so that we have no fd overlaps 288 * in exec_cgi() later. Just exit on error, we don't have enough 289 * fds open to output an error message anywhere. 290 */ 291 for (c=0; c < 3; c++) { 292 if (fstat(c, &sb) == -1) { 293 if ((fd = open("/dev/null", O_RDWR)) != -1) { 294 if (dup2(fd, c) == -1) 295 exit(1); 296 if (fd > c) 297 close(fd); 298 } else 299 exit(1); 300 } 301 } 302 303 while ((c = getopt(argc, argv, "dp:S:s:U:u:")) != -1) { 304 switch (c) { 305 case 'd': 306 debug++; 307 break; 308 case 'p': 309 bgpctlpath = optarg; 310 break; 311 case 'S': 312 bgpctlsock = optarg; 313 break; 314 case 's': 315 fcgi_socket = optarg; 316 break; 317 case 'U': 318 sock_user = optarg; 319 break; 320 default: 321 usage(); 322 /* NOTREACHED */ 323 } 324 } 325 326 if (geteuid() != 0) 327 errx(1, "need root privileges"); 328 329 if (!debug && daemon(0, 0) == -1) 330 err(1, "daemon"); 331 332 if (!debug) { 333 openlog(__progname, LOG_PID|LOG_NDELAY, LOG_DAEMON); 334 logger = &syslogger; 335 } 336 337 ldebug("sock_user: %s", sock_user); 338 pw = getpwnam(sock_user); 339 if (pw == NULL) 340 lerrx(1, "no %s user", sock_user); 341 342 fd = slowcgi_listen(fcgi_socket, pw); 343 344 ldebug("cgi_user: %s", cgi_user); 345 pw = getpwnam(cgi_user); 346 if (pw == NULL) 347 lerrx(1, "no %s user", cgi_user); 348 349 if (setgroups(1, &pw->pw_gid) || 350 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 351 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 352 lerr(1, "unable to revoke privs"); 353 354 unveil_command(bgpctlpath); 355 356 if (pledge("stdio rpath unix proc exec", NULL) == -1) 357 lerr(1, "pledge"); 358 359 LIST_INIT(&slowcgi_proc.requests); 360 event_init(); 361 362 l = calloc(1, sizeof(*l)); 363 if (l == NULL) 364 lerr(1, "listener ev alloc"); 365 366 event_set(&l->ev, fd, EV_READ | EV_PERSIST, slowcgi_accept, l); 367 event_add(&l->ev, NULL); 368 evtimer_set(&l->pause, slowcgi_paused, l); 369 370 signal_set(&slowcgi_proc.ev_sigchld, SIGCHLD, slowcgi_sig_handler, 371 &slowcgi_proc); 372 signal_add(&slowcgi_proc.ev_sigchld, NULL); 373 374 signal(SIGPIPE, SIG_IGN); 375 376 event_dispatch(); 377 return (0); 378 } 379 380 int 381 slowcgi_listen(char *path, struct passwd *pw) 382 { 383 struct sockaddr_un sun; 384 mode_t old_umask; 385 int fd; 386 387 if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 388 0)) == -1) 389 lerr(1, "slowcgi_listen: socket"); 390 391 memset(&sun, 0, sizeof(sun)); 392 sun.sun_family = AF_UNIX; 393 if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >= 394 sizeof(sun.sun_path)) 395 lerrx(1, "socket path too long"); 396 397 if (unlink(path) == -1) 398 if (errno != ENOENT) 399 lerr(1, "slowcgi_listen: unlink %s", path); 400 401 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); 402 403 if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) 404 lerr(1,"slowcgi_listen: bind: %s", path); 405 406 umask(old_umask); 407 408 if (chown(path, pw->pw_uid, pw->pw_gid) == -1) 409 lerr(1, "slowcgi_listen: chown: %s", path); 410 411 if (listen(fd, 5) == -1) 412 lerr(1, "listen"); 413 414 ldebug("socket: %s", path); 415 return fd; 416 } 417 418 void 419 slowcgi_paused(int fd, short events, void *arg) 420 { 421 struct listener *l = arg; 422 event_add(&l->ev, NULL); 423 } 424 425 int 426 accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen, 427 int reserve, volatile int *counter) 428 { 429 int ret; 430 if (getdtablecount() + reserve + 431 ((*counter + 1) * FD_NEEDED) >= getdtablesize()) { 432 ldebug("inflight fds exceeded"); 433 errno = EMFILE; 434 return -1; 435 } 436 437 if ((ret = accept4(sockfd, addr, addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC)) 438 > -1) { 439 (*counter)++; 440 ldebug("inflight incremented, now %d", *counter); 441 } 442 return ret; 443 } 444 445 void 446 slowcgi_accept(int fd, short events, void *arg) 447 { 448 struct listener *l; 449 struct sockaddr_storage ss; 450 struct timeval backoff; 451 struct request *c; 452 socklen_t len; 453 int s; 454 455 l = arg; 456 backoff.tv_sec = 1; 457 backoff.tv_usec = 0; 458 c = NULL; 459 460 len = sizeof(ss); 461 if ((s = accept_reserve(fd, (struct sockaddr *)&ss, 462 &len, FD_RESERVE, &cgi_inflight)) == -1) { 463 switch (errno) { 464 case EINTR: 465 case EWOULDBLOCK: 466 case ECONNABORTED: 467 return; 468 case EMFILE: 469 case ENFILE: 470 event_del(&l->ev); 471 evtimer_add(&l->pause, &backoff); 472 return; 473 default: 474 lerr(1, "accept"); 475 } 476 } 477 478 c = calloc(1, sizeof(*c)); 479 if (c == NULL) { 480 lwarn("cannot calloc request"); 481 close(s); 482 cgi_inflight--; 483 return; 484 } 485 c->fd = s; 486 c->buf_pos = 0; 487 c->buf_len = 0; 488 c->request_started = 0; 489 c->inflight_fds_accounted = 0; 490 TAILQ_INIT(&c->response_head); 491 492 event_set(&c->ev, s, EV_READ | EV_PERSIST, slowcgi_request, c); 493 event_add(&c->ev, NULL); 494 event_set(&c->resp_ev, s, EV_WRITE | EV_PERSIST, slowcgi_response, c); 495 evtimer_set(&c->tmo, slowcgi_timeout, c); 496 evtimer_add(&c->tmo, &timeout); 497 LIST_INSERT_HEAD(&slowcgi_proc.requests, c, entry); 498 } 499 500 void 501 slowcgi_timeout(int fd, short events, void *arg) 502 { 503 struct request *c = arg; 504 int sig = SIGTERM; 505 506 if (c->script_flags & SCRIPT_DONE) 507 return; 508 509 if (c->command_pid == 0) { 510 c->command_status = SIGALRM; 511 error_response(c, 408); 512 return; 513 } 514 515 ldebug("timeout fired for pid %d", c->command_pid); 516 517 if (c->timeout_fired) 518 sig = SIGKILL; 519 520 if (kill(c->command_pid, sig) == -1) { 521 lwarn("kill child %d after timeout", c->command_pid); 522 if (event_initialized(&c->script_ev)) { 523 close(EVENT_FD(&c->script_ev)); 524 event_del(&c->script_ev); 525 } 526 if (event_initialized(&c->script_err_ev)) { 527 close(EVENT_FD(&c->script_err_ev)); 528 event_del(&c->script_err_ev); 529 } 530 531 c->command_status = SIGALRM; 532 c->script_flags = STDOUT_DONE | STDERR_DONE | SCRIPT_DONE; 533 create_end_record(c); 534 } 535 536 if (c->timeout_fired++ == 0) 537 evtimer_add(&c->tmo, &kill_timeout); 538 } 539 540 void 541 slowcgi_sig_handler(int sig, short event, void *arg) 542 { 543 struct request *c; 544 struct slowcgi_proc *p; 545 pid_t pid; 546 int status; 547 548 p = arg; 549 550 switch (sig) { 551 case SIGCHLD: 552 while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0) { 553 LIST_FOREACH(c, &p->requests, entry) 554 if (c->command_pid == pid) 555 break; 556 if (c == NULL) { 557 lwarnx("caught exit of unknown child %d", pid); 558 continue; 559 } 560 561 if (WIFSIGNALED(status)) 562 c->command_status = WTERMSIG(status); 563 else 564 c->command_status = WEXITSTATUS(status); 565 566 ldebug("pid %d exit %s%d", pid, 567 WIFSIGNALED(status) ? "signal " : "", 568 c->command_status); 569 570 c->script_flags |= SCRIPT_DONE; 571 572 if (c->script_flags == (STDOUT_DONE | STDERR_DONE | 573 SCRIPT_DONE)) 574 create_end_record(c); 575 } 576 if (pid == -1 && errno != ECHILD) 577 lwarn("waitpid"); 578 break; 579 default: 580 lerr(1, "unexpected signal: %d", sig); 581 break; 582 } 583 } 584 585 void 586 slowcgi_add_response(struct request *c, struct fcgi_response *resp) 587 { 588 struct fcgi_record_header *header; 589 size_t padded_len; 590 591 header = (struct fcgi_record_header*)resp->data; 592 593 /* The FastCGI spec suggests to align the output buffer */ 594 padded_len = FCGI_ALIGN(resp->data_len); 595 if (padded_len > resp->data_len) { 596 /* There should always be FCGI_PADDING_SIZE bytes left */ 597 if (padded_len > FCGI_RECORD_SIZE) 598 lerr(1, "response too long"); 599 header->padding_len = padded_len - resp->data_len; 600 resp->data_len = padded_len; 601 } 602 603 TAILQ_INSERT_TAIL(&c->response_head, resp, entry); 604 event_add(&c->resp_ev, NULL); 605 } 606 607 void 608 slowcgi_response(int fd, short events, void *arg) 609 { 610 struct request *c; 611 struct fcgi_record_header *header; 612 struct fcgi_response *resp; 613 ssize_t n; 614 615 c = arg; 616 617 while ((resp = TAILQ_FIRST(&c->response_head))) { 618 header = (struct fcgi_record_header*) resp->data; 619 if (debug > 1) 620 dump_fcgi_record("resp ", header); 621 622 n = write(fd, resp->data + resp->data_pos, resp->data_len); 623 if (n == -1) { 624 if (errno == EAGAIN || errno == EINTR) 625 return; 626 cleanup_request(c); 627 return; 628 } 629 resp->data_pos += n; 630 resp->data_len -= n; 631 if (resp->data_len == 0) { 632 TAILQ_REMOVE(&c->response_head, resp, entry); 633 free(resp); 634 } 635 } 636 637 if (TAILQ_EMPTY(&c->response_head)) { 638 if (c->request_done) 639 cleanup_request(c); 640 else 641 event_del(&c->resp_ev); 642 } 643 } 644 645 void 646 slowcgi_request(int fd, short events, void *arg) 647 { 648 struct request *c; 649 ssize_t n; 650 size_t parsed; 651 652 c = arg; 653 654 n = read(fd, c->buf + c->buf_pos + c->buf_len, 655 FCGI_RECORD_SIZE - c->buf_pos-c->buf_len); 656 657 switch (n) { 658 case -1: 659 switch (errno) { 660 case EINTR: 661 case EAGAIN: 662 return; 663 default: 664 goto fail; 665 } 666 break; 667 668 case 0: 669 ldebug("closed connection"); 670 goto fail; 671 default: 672 break; 673 } 674 675 c->buf_len += n; 676 677 /* 678 * Parse the records as they are received. Per the FastCGI 679 * specification, the server need only receive the FastCGI 680 * parameter records in full; it is free to begin execution 681 * at that point, which is what happens here. 682 */ 683 do { 684 parsed = parse_record(c->buf + c->buf_pos, c->buf_len, c); 685 c->buf_pos += parsed; 686 c->buf_len -= parsed; 687 } while (parsed > 0 && c->buf_len > 0); 688 689 /* Make space for further reads */ 690 if (c->buf_len > 0) { 691 memmove(c->buf, c->buf + c->buf_pos, c->buf_len); 692 c->buf_pos = 0; 693 } 694 return; 695 fail: 696 cleanup_request(c); 697 } 698 699 void 700 parse_begin_request(uint8_t *buf, uint16_t n, struct request *c, uint16_t id) 701 { 702 /* XXX -- FCGI_CANT_MPX_CONN */ 703 if (c->request_started) { 704 lwarnx("unexpected FCGI_BEGIN_REQUEST, ignoring"); 705 return; 706 } 707 708 if (n != sizeof(struct fcgi_begin_request_body)) { 709 lwarnx("wrong size %d != %lu", n, 710 sizeof(struct fcgi_begin_request_body)); 711 return; 712 } 713 714 c->request_started = 1; 715 716 c->id = id; 717 SLIST_INIT(&c->env); 718 c->env_count = 0; 719 } 720 721 void 722 parse_params(uint8_t *buf, uint16_t n, struct request *c, uint16_t id) 723 { 724 struct env_val *env_entry; 725 uint32_t name_len, val_len; 726 727 if (!c->request_started) { 728 lwarnx("FCGI_PARAMS without FCGI_BEGIN_REQUEST, ignoring"); 729 return; 730 } 731 732 if (c->id != id) { 733 lwarnx("unexpected id, ignoring"); 734 return; 735 } 736 737 /* 738 * If this is the last FastCGI parameter record, 739 * begin execution of the CGI script. 740 */ 741 if (n == 0) { 742 exec_cgi(c); 743 return; 744 } 745 746 while (n > 0) { 747 if (buf[0] >> 7 == 0) { 748 name_len = buf[0]; 749 n--; 750 buf++; 751 } else { 752 if (n > 3) { 753 name_len = ((buf[0] & 0x7f) << 24) + 754 (buf[1] << 16) + (buf[2] << 8) + buf[3]; 755 n -= 4; 756 buf += 4; 757 } else 758 return; 759 } 760 761 if (n > 0) { 762 if (buf[0] >> 7 == 0) { 763 val_len = buf[0]; 764 n--; 765 buf++; 766 } else { 767 if (n > 3) { 768 val_len = ((buf[0] & 0x7f) << 24) + 769 (buf[1] << 16) + (buf[2] << 8) + 770 buf[3]; 771 n -= 4; 772 buf += 4; 773 } else 774 return; 775 } 776 } else 777 return; 778 779 if (n < name_len + val_len) 780 return; 781 782 if ((env_entry = malloc(sizeof(struct env_val))) == NULL) { 783 lwarnx("cannot allocate env_entry"); 784 return; 785 } 786 787 if ((env_entry->key = malloc(name_len + 1)) == NULL) { 788 lwarnx("cannot allocate env_entry->key"); 789 free(env_entry); 790 return; 791 } 792 if ((env_entry->val = malloc(val_len + 1)) == NULL) { 793 lwarnx("cannot allocate env_entry->val"); 794 free(env_entry->key); 795 free(env_entry); 796 return; 797 } 798 799 memcpy(env_entry->key, buf, name_len); 800 buf += name_len; 801 n -= name_len; 802 env_entry->key[name_len] = '\0'; 803 memcpy(env_entry->val, buf, val_len); 804 buf += val_len; 805 n -= val_len; 806 env_entry->val[val_len] = '\0'; 807 808 SLIST_INSERT_HEAD(&c->env, env_entry, entry); 809 ldebug("env[%d], %s=%s", c->env_count, env_entry->key, 810 env_entry->val); 811 c->env_count++; 812 } 813 } 814 815 void 816 parse_stdin(uint8_t *buf, uint16_t n, struct request *c, uint16_t id) 817 { 818 if (c->id != id) { 819 lwarnx("unexpected id, ignoring"); 820 return; 821 } 822 823 if (n != 0) 824 lwarnx("unexpected stdin input, ignoring"); 825 } 826 827 size_t 828 parse_record(uint8_t *buf, size_t n, struct request *c) 829 { 830 struct fcgi_record_header *h; 831 832 if (n < sizeof(struct fcgi_record_header)) 833 return (0); 834 835 h = (struct fcgi_record_header*) buf; 836 837 if (debug > 1) 838 dump_fcgi_record("", h); 839 840 if (n < sizeof(struct fcgi_record_header) + ntohs(h->content_len) 841 + h->padding_len) 842 return (0); 843 844 if (h->version != 1) 845 lerrx(1, "wrong version"); 846 847 switch (h->type) { 848 case FCGI_BEGIN_REQUEST: 849 parse_begin_request(buf + sizeof(struct fcgi_record_header), 850 ntohs(h->content_len), c, ntohs(h->id)); 851 break; 852 case FCGI_PARAMS: 853 parse_params(buf + sizeof(struct fcgi_record_header), 854 ntohs(h->content_len), c, ntohs(h->id)); 855 break; 856 case FCGI_STDIN: 857 parse_stdin(buf + sizeof(struct fcgi_record_header), 858 ntohs(h->content_len), c, ntohs(h->id)); 859 break; 860 default: 861 lwarnx("unimplemented type %d", h->type); 862 break; 863 } 864 865 return (sizeof(struct fcgi_record_header) + ntohs(h->content_len) 866 + h->padding_len); 867 } 868 869 char * 870 env_get(struct request *c, const char *key) 871 { 872 struct env_val *env; 873 874 SLIST_FOREACH(env, &c->env, entry) { 875 if (strcmp(env->key, key) == 0) 876 return (env->val); 877 } 878 return (NULL); 879 } 880 881 static const char * 882 http_error(int *res) 883 { 884 const struct http_error errors[] = HTTP_ERRORS; 885 size_t i; 886 887 for (i = 0; errors[i].error_code != 0; i++) 888 if (errors[i].error_code == *res) 889 return errors[i].error_name; 890 891 /* unknown error - change to 500 */ 892 lwarnx("unknown http error %d", *res); 893 *res = 500; 894 return "Internal Server Error"; 895 } 896 897 void 898 error_response(struct request *c, int res) 899 { 900 const char *type = "text/html"; 901 const char *errstr = http_error(&res); 902 char *buf; 903 int len; 904 905 lwarnx("HTTP status %d: %s", res, errstr); 906 907 len = asprintf(&buf, 908 "Content-Type: %s\n" 909 "Status: %d\n" 910 "Cache-Control: no-cache\n" 911 "\n" 912 "<!DOCTYPE html>\n" 913 "<html>\n" 914 " <head>\n" 915 " <meta http-equiv=\"Content-Type\" " 916 "content=\"%s; charset=utf-8\"/>\n" 917 " <title>%d %s</title>\n" 918 " </head>\n" 919 " <body>\n" 920 " <h1>%d %s</h1>\n" 921 " <hr>\n" 922 " <address>OpenBSD bgplgd</address>\n" 923 " </body>\n" 924 "</html>\n", 925 type, res, type, res, errstr, res, errstr); 926 927 if (len == -1) 928 lerr(1, NULL); 929 930 create_data_record(c, FCGI_STDOUT, buf, len); 931 free(buf); 932 c->script_flags = (STDOUT_DONE | STDERR_DONE | SCRIPT_DONE); 933 create_end_record(c); 934 } 935 936 /* 937 * Fork a new CGI process to handle the request, translating 938 * between FastCGI parameter records and CGI's environment variables, 939 * as well as between the CGI process' stdin/stdout and the 940 * corresponding FastCGI records. 941 */ 942 void 943 exec_cgi(struct request *c) 944 { 945 struct lg_ctx ctx = { 0 }; 946 int s_in[2], s_out[2], s_err[2], res; 947 pid_t pid; 948 949 res = prep_request(&ctx, env_get(c, "REQUEST_METHOD"), 950 env_get(c, "PATH_INFO"), env_get(c, "QUERY_STRING")); 951 if (res != 0) { 952 error_response(c, res); 953 return; 954 } 955 956 if (pipe(s_in) == -1) 957 lerr(1, "pipe"); 958 if (pipe(s_out) == -1) 959 lerr(1, "pipe"); 960 if (pipe(s_err) == -1) 961 lerr(1, "pipe"); 962 cgi_inflight--; 963 c->inflight_fds_accounted = 1; 964 965 switch (pid = fork()) { 966 case -1: 967 c->command_status = errno; 968 969 lwarn("fork"); 970 971 close(s_in[0]); 972 close(s_out[0]); 973 close(s_err[0]); 974 975 close(s_in[1]); 976 close(s_out[1]); 977 close(s_err[1]); 978 979 c->script_flags = (STDOUT_DONE | STDERR_DONE | SCRIPT_DONE); 980 create_end_record(c); 981 return; 982 case 0: 983 /* Child process */ 984 if (pledge("stdio rpath exec", NULL) == -1) 985 lerr(1, "pledge"); 986 close(s_in[0]); 987 close(s_out[0]); 988 close(s_err[0]); 989 990 if (dup2(s_in[1], STDIN_FILENO) == -1) 991 _exit(1); 992 if (dup2(s_out[1], STDOUT_FILENO) == -1) 993 _exit(1); 994 if (dup2(s_err[1], STDERR_FILENO) == -1) 995 _exit(1); 996 997 close(s_in[1]); 998 close(s_out[1]); 999 close(s_err[1]); 1000 1001 bgpctl_call(&ctx); 1002 1003 /* should not be reached */ 1004 _exit(1); 1005 1006 } 1007 1008 ldebug("fork %d", pid); 1009 1010 /* Parent process*/ 1011 close(s_in[1]); 1012 close(s_out[1]); 1013 close(s_err[1]); 1014 1015 fcntl(s_in[0], F_SETFD, FD_CLOEXEC); 1016 fcntl(s_out[0], F_SETFD, FD_CLOEXEC); 1017 fcntl(s_err[0], F_SETFD, FD_CLOEXEC); 1018 1019 if (ioctl(s_in[0], FIONBIO, &on) == -1) 1020 lerr(1, "script ioctl(FIONBIO)"); 1021 if (ioctl(s_out[0], FIONBIO, &on) == -1) 1022 lerr(1, "script ioctl(FIONBIO)"); 1023 if (ioctl(s_err[0], FIONBIO, &on) == -1) 1024 lerr(1, "script ioctl(FIONBIO)"); 1025 1026 close(s_in[0]); /* close stdin, bgpctl does not expect anything */ 1027 1028 c->command_pid = pid; 1029 event_set(&c->script_ev, s_out[0], EV_READ | EV_PERSIST, 1030 script_std_in, c); 1031 event_add(&c->script_ev, NULL); 1032 event_set(&c->script_err_ev, s_err[0], EV_READ | EV_PERSIST, 1033 script_err_in, c); 1034 event_add(&c->script_err_ev, NULL); 1035 } 1036 1037 static void 1038 script_in(int fd, struct event *ev, struct request *c, uint8_t type) 1039 { 1040 struct fcgi_response *resp; 1041 struct fcgi_record_header *header; 1042 ssize_t n; 1043 1044 if ((resp = calloc(1, sizeof(struct fcgi_response))) == NULL) { 1045 lwarnx("cannot malloc fcgi_response"); 1046 return; 1047 } 1048 header = (struct fcgi_record_header*) resp->data; 1049 header->version = 1; 1050 header->type = type; 1051 header->id = htons(c->id); 1052 header->padding_len = 0; 1053 header->reserved = 0; 1054 1055 n = read(fd, resp->data + sizeof(struct fcgi_record_header), 1056 FCGI_CONTENT_SIZE); 1057 1058 if (n == -1) { 1059 switch (errno) { 1060 case EINTR: 1061 case EAGAIN: 1062 free(resp); 1063 return; 1064 default: 1065 n = 0; /* fake empty FCGI_STD{OUT,ERR} response */ 1066 } 1067 } 1068 header->content_len = htons(n); 1069 resp->data_pos = 0; 1070 resp->data_len = n + sizeof(struct fcgi_record_header); 1071 slowcgi_add_response(c, resp); 1072 1073 if (n == 0) { 1074 if (type == FCGI_STDOUT) 1075 c->script_flags |= STDOUT_DONE; 1076 else 1077 c->script_flags |= STDERR_DONE; 1078 1079 if (c->script_flags == (STDOUT_DONE | STDERR_DONE | 1080 SCRIPT_DONE)) 1081 create_end_record(c); 1082 event_del(ev); 1083 close(fd); 1084 } 1085 } 1086 1087 void 1088 script_std_in(int fd, short events, void *arg) 1089 { 1090 struct request *c = arg; 1091 script_in(fd, &c->script_ev, c, FCGI_STDOUT); 1092 } 1093 1094 void 1095 script_err_in(int fd, short events, void *arg) 1096 { 1097 struct request *c = arg; 1098 script_in(fd, &c->script_err_ev, c, FCGI_STDERR); 1099 } 1100 1101 void 1102 create_data_record(struct request *c, uint8_t type, const void *buf, size_t len) 1103 { 1104 struct fcgi_response *resp; 1105 struct fcgi_record_header *header; 1106 const char *d = buf; 1107 size_t n; 1108 1109 do { 1110 if ((resp = calloc(1, sizeof(struct fcgi_response))) == NULL) { 1111 lwarnx("cannot malloc fcgi_response"); 1112 return; 1113 } 1114 header = (struct fcgi_record_header*) resp->data; 1115 header->version = 1; 1116 header->type = type; 1117 header->id = htons(c->id); 1118 header->padding_len = 0; 1119 header->reserved = 0; 1120 1121 n = len > FCGI_CONTENT_SIZE ? FCGI_CONTENT_SIZE : len; 1122 memcpy(resp->data + sizeof(struct fcgi_record_header), d, n); 1123 1124 header->content_len = htons(n); 1125 resp->data_pos = 0; 1126 resp->data_len = n + sizeof(struct fcgi_record_header); 1127 slowcgi_add_response(c, resp); 1128 1129 len -= n; 1130 d += n; 1131 } while (len > 0); 1132 } 1133 1134 void 1135 create_end_record(struct request *c) 1136 { 1137 struct fcgi_response *resp; 1138 struct fcgi_record_header *header; 1139 struct fcgi_end_request_body *end_request; 1140 1141 if ((resp = calloc(1, sizeof(struct fcgi_response))) == NULL) { 1142 lwarnx("cannot malloc fcgi_response"); 1143 return; 1144 } 1145 header = (struct fcgi_record_header*) resp->data; 1146 header->version = 1; 1147 header->type = FCGI_END_REQUEST; 1148 header->id = htons(c->id); 1149 header->content_len = htons(sizeof(struct 1150 fcgi_end_request_body)); 1151 header->padding_len = 0; 1152 header->reserved = 0; 1153 end_request = (struct fcgi_end_request_body *) (resp->data + 1154 sizeof(struct fcgi_record_header)); 1155 end_request->app_status = htonl(c->command_status); 1156 end_request->protocol_status = FCGI_REQUEST_COMPLETE; 1157 end_request->reserved[0] = 0; 1158 end_request->reserved[1] = 0; 1159 end_request->reserved[2] = 0; 1160 resp->data_pos = 0; 1161 resp->data_len = sizeof(struct fcgi_end_request_body) + 1162 sizeof(struct fcgi_record_header); 1163 slowcgi_add_response(c, resp); 1164 c->request_done = 1; 1165 } 1166 1167 void 1168 cleanup_request(struct request *c) 1169 { 1170 struct fcgi_response *resp; 1171 struct env_val *env_entry; 1172 1173 evtimer_del(&c->tmo); 1174 if (event_initialized(&c->ev)) 1175 event_del(&c->ev); 1176 if (event_initialized(&c->resp_ev)) 1177 event_del(&c->resp_ev); 1178 if (event_initialized(&c->script_ev)) { 1179 close(EVENT_FD(&c->script_ev)); 1180 event_del(&c->script_ev); 1181 } 1182 if (event_initialized(&c->script_err_ev)) { 1183 close(EVENT_FD(&c->script_err_ev)); 1184 event_del(&c->script_err_ev); 1185 } 1186 1187 close(c->fd); 1188 while (!SLIST_EMPTY(&c->env)) { 1189 env_entry = SLIST_FIRST(&c->env); 1190 SLIST_REMOVE_HEAD(&c->env, entry); 1191 free(env_entry->key); 1192 free(env_entry->val); 1193 free(env_entry); 1194 } 1195 1196 while ((resp = TAILQ_FIRST(&c->response_head))) { 1197 TAILQ_REMOVE(&c->response_head, resp, entry); 1198 free(resp); 1199 } 1200 LIST_REMOVE(c, entry); 1201 if (! c->inflight_fds_accounted) 1202 cgi_inflight--; 1203 free(c); 1204 } 1205 1206 void 1207 dump_fcgi_record(const char *p, struct fcgi_record_header *h) 1208 { 1209 dump_fcgi_record_header(p, h); 1210 1211 if (h->type == FCGI_BEGIN_REQUEST) 1212 dump_fcgi_begin_request_body(p, 1213 (struct fcgi_begin_request_body *)(h + 1)); 1214 else if (h->type == FCGI_END_REQUEST) 1215 dump_fcgi_end_request_body(p, 1216 (struct fcgi_end_request_body *)(h + 1)); 1217 } 1218 1219 void 1220 dump_fcgi_record_header(const char* p, struct fcgi_record_header *h) 1221 { 1222 ldebug("%sversion: %d", p, h->version); 1223 ldebug("%stype: %d", p, h->type); 1224 ldebug("%srequestId: %d", p, ntohs(h->id)); 1225 ldebug("%scontentLength: %d", p, ntohs(h->content_len)); 1226 ldebug("%spaddingLength: %d", p, h->padding_len); 1227 ldebug("%sreserved: %d", p, h->reserved); 1228 } 1229 1230 void 1231 dump_fcgi_begin_request_body(const char *p, struct fcgi_begin_request_body *b) 1232 { 1233 ldebug("%srole %d", p, ntohs(b->role)); 1234 ldebug("%sflags %d", p, b->flags); 1235 } 1236 1237 void 1238 dump_fcgi_end_request_body(const char *p, struct fcgi_end_request_body *b) 1239 { 1240 ldebug("%sappStatus: %d", p, ntohl(b->app_status)); 1241 ldebug("%sprotocolStatus: %d", p, b->protocol_status); 1242 } 1243 1244 void 1245 syslog_vstrerror(int e, int priority, const char *fmt, va_list ap) 1246 { 1247 char *s; 1248 1249 if (vasprintf(&s, fmt, ap) == -1) { 1250 syslog(LOG_EMERG, "unable to alloc in syslog_vstrerror"); 1251 exit(1); 1252 } 1253 syslog(priority, "%s: %s", s, strerror(e)); 1254 free(s); 1255 } 1256 1257 __dead void 1258 syslog_err(int ecode, const char *fmt, ...) 1259 { 1260 va_list ap; 1261 1262 va_start(ap, fmt); 1263 syslog_vstrerror(errno, LOG_CRIT, fmt, ap); 1264 va_end(ap); 1265 exit(ecode); 1266 } 1267 1268 __dead void 1269 syslog_errx(int ecode, const char *fmt, ...) 1270 { 1271 va_list ap; 1272 1273 va_start(ap, fmt); 1274 vsyslog(LOG_CRIT, fmt, ap); 1275 va_end(ap); 1276 exit(ecode); 1277 } 1278 1279 void 1280 syslog_warn(const char *fmt, ...) 1281 { 1282 va_list ap; 1283 1284 va_start(ap, fmt); 1285 syslog_vstrerror(errno, LOG_ERR, fmt, ap); 1286 va_end(ap); 1287 } 1288 1289 void 1290 syslog_warnx(const char *fmt, ...) 1291 { 1292 va_list ap; 1293 1294 va_start(ap, fmt); 1295 vsyslog(LOG_ERR, fmt, ap); 1296 va_end(ap); 1297 } 1298 1299 void 1300 syslog_info(const char *fmt, ...) 1301 { 1302 va_list ap; 1303 1304 va_start(ap, fmt); 1305 vsyslog(LOG_INFO, fmt, ap); 1306 va_end(ap); 1307 } 1308 1309 void 1310 syslog_debug(const char *fmt, ...) 1311 { 1312 va_list ap; 1313 1314 va_start(ap, fmt); 1315 vsyslog(LOG_DEBUG, fmt, ap); 1316 va_end(ap); 1317 } 1318