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