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