Blob


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 */
19 #include "config.h"
21 #include <sys/types.h>
22 #include <sys/ioctl.h>
23 #include <sys/socket.h>
24 #include <sys/stat.h>
25 #include <sys/time.h>
26 #include <sys/un.h>
27 #include <sys/wait.h>
28 #include <arpa/inet.h>
29 #include <fcntl.h>
30 #include <errno.h>
31 #include <limits.h>
32 #include <pwd.h>
33 #include <signal.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <syslog.h>
39 #include <unistd.h>
41 #define TIMEOUT_DEFAULT 120
42 #define TIMEOUT_MAX (86400 * 365)
43 #define SLOWCGI_USER "www"
45 #define FCGI_CONTENT_SIZE 65535
46 #define FCGI_PADDING_SIZE 255
47 #define FCGI_RECORD_SIZE \
48 (sizeof(struct fcgi_record_header) + FCGI_CONTENT_SIZE + FCGI_PADDING_SIZE)
50 #define FCGI_ALIGNMENT 8
51 #define FCGI_ALIGN(n) \
52 (((n) + (FCGI_ALIGNMENT - 1)) & ~(FCGI_ALIGNMENT - 1))
54 #define STDOUT_DONE 1
55 #define STDERR_DONE 2
56 #define SCRIPT_DONE 4
58 #define FCGI_BEGIN_REQUEST 1
59 #define FCGI_ABORT_REQUEST 2
60 #define FCGI_END_REQUEST 3
61 #define FCGI_PARAMS 4
62 #define FCGI_STDIN 5
63 #define FCGI_STDOUT 6
64 #define FCGI_STDERR 7
65 #define FCGI_DATA 8
66 #define FCGI_GET_VALUES 9
67 #define FCGI_GET_VALUES_RESULT 10
68 #define FCGI_UNKNOWN_TYPE 11
69 #define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE)
71 #define FCGI_REQUEST_COMPLETE 0
72 #define FCGI_CANT_MPX_CONN 1
73 #define FCGI_OVERLOADED 2
74 #define FCGI_UNKNOWN_ROLE 3
76 #define FD_RESERVE 5
77 #define FD_NEEDED 6
78 int cgi_inflight = 0;
80 struct listener {
81 struct event ev, pause;
82 };
84 struct env_val {
85 SLIST_ENTRY(env_val) entry;
86 char *val;
87 };
88 SLIST_HEAD(env_head, env_val);
90 struct fcgi_record_header {
91 uint8_t version;
92 uint8_t type;
93 uint16_t id;
94 uint16_t content_len;
95 uint8_t padding_len;
96 uint8_t reserved;
97 }__packed;
99 struct fcgi_response {
100 TAILQ_ENTRY(fcgi_response) entry;
101 uint8_t data[FCGI_RECORD_SIZE];
102 size_t data_pos;
103 size_t data_len;
104 };
105 TAILQ_HEAD(fcgi_response_head, fcgi_response);
107 struct fcgi_stdin {
108 TAILQ_ENTRY(fcgi_stdin) entry;
109 uint8_t data[FCGI_RECORD_SIZE];
110 size_t data_pos;
111 size_t data_len;
112 };
113 TAILQ_HEAD(fcgi_stdin_head, fcgi_stdin);
115 struct request {
116 LIST_ENTRY(request) entry;
117 struct event ev;
118 struct event resp_ev;
119 struct event tmo;
120 int fd;
121 uint8_t buf[FCGI_RECORD_SIZE];
122 size_t buf_pos;
123 size_t buf_len;
124 struct fcgi_response_head response_head;
125 struct fcgi_stdin_head stdin_head;
126 uint16_t id;
127 char script_name[PATH_MAX];
128 struct env_head env;
129 int env_count;
130 pid_t script_pid;
131 int script_status;
132 struct event script_ev;
133 struct event script_err_ev;
134 struct event script_stdin_ev;
135 int stdin_fd_closed;
136 int stdout_fd_closed;
137 int stderr_fd_closed;
138 uint8_t script_flags;
139 uint8_t request_started;
140 int inflight_fds_accounted;
141 };
143 LIST_HEAD(requests_head, request);
145 struct slowcgi_proc {
146 struct requests_head requests;
147 struct event ev_sigchld;
148 };
150 struct fcgi_begin_request_body {
151 uint16_t role;
152 uint8_t flags;
153 uint8_t reserved[5];
154 }__packed;
156 struct fcgi_end_request_body {
157 uint32_t app_status;
158 uint8_t protocol_status;
159 uint8_t reserved[3];
160 }__packed;
162 __dead void usage(void);
163 int slowcgi_listen(char *, struct passwd *);
164 void slowcgi_paused(int, short, void *);
165 int accept_reserve(int, struct sockaddr *, socklen_t *, int, int *);
166 void slowcgi_accept(int, short, void *);
167 void slowcgi_request(int, short, void *);
168 void slowcgi_response(int, short, void *);
169 void slowcgi_add_response(struct request *, struct fcgi_response *);
170 void slowcgi_timeout(int, short, void *);
171 void slowcgi_sig_handler(int, short, void *);
172 size_t parse_record(uint8_t * , size_t, struct request *);
173 void parse_begin_request(uint8_t *, uint16_t, struct request *,
174 uint16_t);
175 void parse_params(uint8_t *, uint16_t, struct request *, uint16_t);
176 void parse_stdin(uint8_t *, uint16_t, struct request *, uint16_t);
177 void exec_cgi(struct request *);
178 void script_in(int, struct event *, struct request *, uint8_t);
179 void script_std_in(int, short, void *);
180 void script_err_in(int, short, void *);
181 void script_out(int, short, void *);
182 void create_end_record(struct request *);
183 void dump_fcgi_record(const char *,
184 struct fcgi_record_header *);
185 void dump_fcgi_record_header(const char *,
186 struct fcgi_record_header *);
187 void dump_fcgi_begin_request_body(const char *,
188 struct fcgi_begin_request_body *);
189 void dump_fcgi_end_request_body(const char *,
190 struct fcgi_end_request_body *);
191 void cleanup_request(struct request *);
193 struct loggers {
194 __dead void (*err)(int, const char *, ...)
195 __attribute__((__format__ (printf, 2, 3)));
196 __dead void (*errx)(int, const char *, ...)
197 __attribute__((__format__ (printf, 2, 3)));
198 void (*warn)(const char *, ...)
199 __attribute__((__format__ (printf, 1, 2)));
200 void (*warnx)(const char *, ...)
201 __attribute__((__format__ (printf, 1, 2)));
202 void (*info)(const char *, ...)
203 __attribute__((__format__ (printf, 1, 2)));
204 void (*debug)(const char *, ...)
205 __attribute__((__format__ (printf, 1, 2)));
206 };
208 const struct loggers conslogger = {
209 err,
210 errx,
211 warn,
212 warnx,
213 warnx, /* info */
214 warnx /* debug */
215 };
217 __dead void syslog_err(int, const char *, ...)
218 __attribute__((__format__ (printf, 2, 3)));
219 __dead void syslog_errx(int, const char *, ...)
220 __attribute__((__format__ (printf, 2, 3)));
221 void syslog_warn(const char *, ...)
222 __attribute__((__format__ (printf, 1, 2)));
223 void syslog_warnx(const char *, ...)
224 __attribute__((__format__ (printf, 1, 2)));
225 void syslog_info(const char *, ...)
226 __attribute__((__format__ (printf, 1, 2)));
227 void syslog_debug(const char *, ...)
228 __attribute__((__format__ (printf, 1, 2)));
229 void syslog_vstrerror(int, int, const char *, va_list)
230 __attribute__((__format__ (printf, 3, 0)));
232 const struct loggers syslogger = {
233 syslog_err,
234 syslog_errx,
235 syslog_warn,
236 syslog_warnx,
237 syslog_info,
238 syslog_debug
239 };
241 const struct loggers *logger = &conslogger;
243 #define lerr(_e, _f...) logger->err((_e), _f)
244 #define lerrx(_e, _f...) logger->errx((_e), _f)
245 #define lwarn(_f...) logger->warn(_f)
246 #define lwarnx(_f...) logger->warnx(_f)
247 #define linfo(_f...) logger->info(_f)
248 #define ldebug(_f...) logger->debug(_f)
250 __dead void
251 usage(void)
253 extern char *__progname;
254 fprintf(stderr,
255 "usage: %s [-dv] [-p path] [-s socket] [-t timeout] [-U user] "
256 "[-u user]\n", __progname);
257 exit(1);
260 struct timeval timeout = { TIMEOUT_DEFAULT, 0 };
261 struct slowcgi_proc slowcgi_proc;
262 int debug = 0;
263 int verbose = 0;
264 int on = 1;
265 char *fcgi_socket = "/var/www/run/slowcgi.sock";
267 int
268 main(int argc, char *argv[])
270 extern char *__progname;
271 struct listener *l = NULL;
272 struct passwd *pw;
273 struct stat sb;
274 int c, fd;
275 const char *chrootpath = NULL;
276 const char *sock_user = SLOWCGI_USER;
277 const char *slowcgi_user = SLOWCGI_USER;
278 const char *errstr;
280 /*
281 * Ensure we have fds 0-2 open so that we have no fd overlaps
282 * in exec_cgi() later. Just exit on error, we don't have enough
283 * fds open to output an error message anywhere.
284 */
285 for (c=0; c < 3; c++) {
286 if (fstat(c, &sb) == -1) {
287 if ((fd = open("/dev/null", O_RDWR)) != -1) {
288 if (dup2(fd, c) == -1)
289 exit(1);
290 if (fd > c)
291 close(fd);
292 } else
293 exit(1);
297 while ((c = getopt(argc, argv, "dp:s:t:U:u:v")) != -1) {
298 switch (c) {
299 case 'd':
300 debug++;
301 break;
302 case 'p':
303 chrootpath = optarg;
304 break;
305 case 's':
306 fcgi_socket = optarg;
307 break;
308 case 't':
309 timeout.tv_sec = strtonum(optarg, 1, TIMEOUT_MAX,
310 &errstr);
311 if (errstr != NULL)
312 errx(1, "timeout is %s: %s", errstr, optarg);
313 break;
314 case 'U':
315 sock_user = optarg;
316 break;
317 case 'u':
318 slowcgi_user = optarg;
319 break;
320 case 'v':
321 verbose++;
322 break;
323 default:
324 usage();
325 /* NOTREACHED */
329 if (geteuid() != 0)
330 errx(1, "need root privileges");
332 if (!debug && daemon(0, 0) == -1)
333 err(1, "daemon");
335 if (!debug) {
336 openlog(__progname, LOG_PID|LOG_NDELAY, LOG_DAEMON);
337 logger = &syslogger;
340 ldebug("sock_user: %s", sock_user);
341 pw = getpwnam(sock_user);
342 if (pw == NULL)
343 lerrx(1, "no %s user", sock_user);
345 fd = slowcgi_listen(fcgi_socket, pw);
347 ldebug("slowcgi_user: %s", slowcgi_user);
348 pw = getpwnam(slowcgi_user);
349 if (pw == NULL)
350 lerrx(1, "no %s user", slowcgi_user);
352 if (chrootpath == NULL)
353 chrootpath = pw->pw_dir;
355 if (chroot(chrootpath) == -1)
356 lerr(1, "chroot(%s)", chrootpath);
358 ldebug("chroot: %s", chrootpath);
360 if (chdir("/") == -1)
361 lerr(1, "chdir(/)");
363 if (setgroups(1, &pw->pw_gid) ||
364 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
365 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
366 lerr(1, "unable to revoke privs");
368 if (pledge("stdio rpath unix proc exec", NULL) == -1)
369 lerr(1, "pledge");
371 LIST_INIT(&slowcgi_proc.requests);
372 event_init();
374 l = calloc(1, sizeof(*l));
375 if (l == NULL)
376 lerr(1, "listener ev alloc");
378 event_set(&l->ev, fd, EV_READ | EV_PERSIST, slowcgi_accept, l);
379 event_add(&l->ev, NULL);
380 evtimer_set(&l->pause, slowcgi_paused, l);
382 signal_set(&slowcgi_proc.ev_sigchld, SIGCHLD, slowcgi_sig_handler,
383 &slowcgi_proc);
384 signal(SIGPIPE, SIG_IGN);
386 signal_add(&slowcgi_proc.ev_sigchld, NULL);
388 event_dispatch();
389 return (0);
392 int
393 slowcgi_listen(char *path, struct passwd *pw)
395 struct sockaddr_un sun;
396 mode_t old_umask;
397 int fd;
399 if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
400 0)) == -1)
401 lerr(1, "slowcgi_listen: socket");
403 bzero(&sun, sizeof(sun));
404 sun.sun_family = AF_UNIX;
405 if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
406 sizeof(sun.sun_path))
407 lerrx(1, "socket path too long");
409 if (unlink(path) == -1)
410 if (errno != ENOENT)
411 lerr(1, "slowcgi_listen: unlink %s", path);
413 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
415 if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
416 lerr(1,"slowcgi_listen: bind: %s", path);
418 umask(old_umask);
420 if (chown(path, pw->pw_uid, pw->pw_gid) == -1)
421 lerr(1, "slowcgi_listen: chown: %s", path);
423 if (listen(fd, 5) == -1)
424 lerr(1, "listen");
426 ldebug("socket: %s", path);
427 return fd;
430 void
431 slowcgi_paused(int fd, short events, void *arg)
433 struct listener *l = arg;
434 event_add(&l->ev, NULL);
437 int
438 accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
439 int reserve, int *counter)
441 int ret;
442 if (getdtablecount() + reserve +
443 ((*counter + 1) * FD_NEEDED) >= getdtablesize()) {
444 ldebug("inflight fds exceeded");
445 errno = EMFILE;
446 return -1;
449 if ((ret = accept4(sockfd, addr, addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC))
450 > -1) {
451 (*counter)++;
452 ldebug("inflight incremented, now %d", *counter);
454 return ret;
457 void
458 slowcgi_accept(int fd, short events, void *arg)
460 struct listener *l;
461 struct sockaddr_storage ss;
462 struct timeval backoff;
463 struct request *c;
464 socklen_t len;
465 int s;
467 l = arg;
468 backoff.tv_sec = 1;
469 backoff.tv_usec = 0;
470 c = NULL;
472 len = sizeof(ss);
473 if ((s = accept_reserve(fd, (struct sockaddr *)&ss,
474 &len, FD_RESERVE, &cgi_inflight)) == -1) {
475 switch (errno) {
476 case EINTR:
477 case EWOULDBLOCK:
478 case ECONNABORTED:
479 return;
480 case EMFILE:
481 case ENFILE:
482 event_del(&l->ev);
483 evtimer_add(&l->pause, &backoff);
484 return;
485 default:
486 lerr(1, "accept");
490 c = calloc(1, sizeof(*c));
491 if (c == NULL) {
492 lwarn("cannot calloc request");
493 close(s);
494 cgi_inflight--;
495 return;
497 c->fd = s;
498 c->buf_pos = 0;
499 c->buf_len = 0;
500 c->request_started = 0;
501 c->stdin_fd_closed = c->stdout_fd_closed = c->stderr_fd_closed = 0;
502 c->inflight_fds_accounted = 0;
503 TAILQ_INIT(&c->response_head);
504 TAILQ_INIT(&c->stdin_head);
506 event_set(&c->ev, s, EV_READ | EV_PERSIST, slowcgi_request, c);
507 event_add(&c->ev, NULL);
508 event_set(&c->resp_ev, s, EV_WRITE | EV_PERSIST, slowcgi_response, c);
509 evtimer_set(&c->tmo, slowcgi_timeout, c);
510 evtimer_add(&c->tmo, &timeout);
511 LIST_INSERT_HEAD(&slowcgi_proc.requests, c, entry);
514 void
515 slowcgi_timeout(int fd, short events, void *arg)
517 cleanup_request((struct request*) arg);
520 void
521 slowcgi_sig_handler(int sig, short event, void *arg)
523 struct request *c;
524 struct slowcgi_proc *p;
525 pid_t pid;
526 int status;
528 p = arg;
530 switch (sig) {
531 case SIGCHLD:
532 while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0) {
533 LIST_FOREACH(c, &p->requests, entry)
534 if (c->script_pid == pid)
535 break;
536 if (c == NULL) {
537 lwarnx("caught exit of unknown child %i", pid);
538 continue;
541 if (WIFSIGNALED(status))
542 c->script_status = WTERMSIG(status);
543 else
544 c->script_status = WEXITSTATUS(status);
546 if (c->script_flags == (STDOUT_DONE | STDERR_DONE))
547 create_end_record(c);
548 c->script_flags |= SCRIPT_DONE;
550 ldebug("wait: %s", c->script_name);
552 if (pid == -1 && errno != ECHILD)
553 lwarn("waitpid");
554 break;
555 default:
556 lerr(1, "unexpected signal: %d", sig);
557 break;
561 void
562 slowcgi_add_response(struct request *c, struct fcgi_response *resp)
564 struct fcgi_record_header *header;
565 size_t padded_len;
567 header = (struct fcgi_record_header*)resp->data;
569 /* The FastCGI spec suggests to align the output buffer */
570 padded_len = FCGI_ALIGN(resp->data_len);
571 if (padded_len > resp->data_len) {
572 /* There should always be FCGI_PADDING_SIZE bytes left */
573 if (padded_len > FCGI_RECORD_SIZE)
574 lerr(1, "response too long");
575 header->padding_len = padded_len - resp->data_len;
576 resp->data_len = padded_len;
579 TAILQ_INSERT_TAIL(&c->response_head, resp, entry);
580 event_add(&c->resp_ev, NULL);
583 void
584 slowcgi_response(int fd, short events, void *arg)
586 struct request *c;
587 struct fcgi_record_header *header;
588 struct fcgi_response *resp;
589 ssize_t n;
591 c = arg;
593 while ((resp = TAILQ_FIRST(&c->response_head))) {
594 header = (struct fcgi_record_header*) resp->data;
595 if (debug > 1)
596 dump_fcgi_record("resp ", header);
598 n = write(fd, resp->data + resp->data_pos, resp->data_len);
599 if (n == -1) {
600 if (errno == EAGAIN || errno == EINTR)
601 return;
602 cleanup_request(c);
603 return;
605 resp->data_pos += n;
606 resp->data_len -= n;
607 if (resp->data_len == 0) {
608 TAILQ_REMOVE(&c->response_head, resp, entry);
609 free(resp);
613 if (TAILQ_EMPTY(&c->response_head)) {
614 if (c->script_flags == (STDOUT_DONE | STDERR_DONE |
615 SCRIPT_DONE))
616 cleanup_request(c);
617 else
618 event_del(&c->resp_ev);
622 void
623 slowcgi_request(int fd, short events, void *arg)
625 struct request *c;
626 ssize_t n;
627 size_t parsed;
629 c = arg;
631 n = read(fd, c->buf + c->buf_pos + c->buf_len,
632 FCGI_RECORD_SIZE - c->buf_pos-c->buf_len);
634 switch (n) {
635 case -1:
636 switch (errno) {
637 case EINTR:
638 case EAGAIN:
639 return;
640 default:
641 goto fail;
643 break;
645 case 0:
646 ldebug("closed connection");
647 goto fail;
648 default:
649 break;
652 c->buf_len += n;
654 /*
655 * Parse the records as they are received. Per the FastCGI
656 * specification, the server need only receive the FastCGI
657 * parameter records in full; it is free to begin execution
658 * at that point, which is what happens here.
659 */
660 do {
661 parsed = parse_record(c->buf + c->buf_pos, c->buf_len, c);
662 c->buf_pos += parsed;
663 c->buf_len -= parsed;
664 } while (parsed > 0 && c->buf_len > 0);
666 /* Make space for further reads */
667 if (c->buf_len > 0) {
668 bcopy(c->buf + c->buf_pos, c->buf, c->buf_len);
669 c->buf_pos = 0;
671 return;
672 fail:
673 cleanup_request(c);
676 void
677 parse_begin_request(uint8_t *buf, uint16_t n, struct request *c, uint16_t id)
679 /* XXX -- FCGI_CANT_MPX_CONN */
680 if (c->request_started) {
681 lwarnx("unexpected FCGI_BEGIN_REQUEST, ignoring");
682 return;
685 if (n != sizeof(struct fcgi_begin_request_body)) {
686 lwarnx("wrong size %d != %lu", n,
687 sizeof(struct fcgi_begin_request_body));
688 return;
691 c->request_started = 1;
693 c->id = id;
694 SLIST_INIT(&c->env);
695 c->env_count = 0;
698 void
699 parse_params(uint8_t *buf, uint16_t n, struct request *c, uint16_t id)
701 struct env_val *env_entry;
702 uint32_t name_len, val_len;
704 if (!c->request_started) {
705 lwarnx("FCGI_PARAMS without FCGI_BEGIN_REQUEST, ignoring");
706 return;
709 if (c->id != id) {
710 lwarnx("unexpected id, ignoring");
711 return;
714 /*
715 * If this is the last FastCGI parameter record,
716 * begin execution of the CGI script.
717 */
718 if (n == 0) {
719 exec_cgi(c);
720 return;
723 while (n > 0) {
724 if (buf[0] >> 7 == 0) {
725 name_len = buf[0];
726 n--;
727 buf++;
728 } else {
729 if (n > 3) {
730 name_len = ((buf[0] & 0x7f) << 24) +
731 (buf[1] << 16) + (buf[2] << 8) + buf[3];
732 n -= 4;
733 buf += 4;
734 } else
735 return;
738 if (n > 0) {
739 if (buf[0] >> 7 == 0) {
740 val_len = buf[0];
741 n--;
742 buf++;
743 } else {
744 if (n > 3) {
745 val_len = ((buf[0] & 0x7f) << 24) +
746 (buf[1] << 16) + (buf[2] << 8) +
747 buf[3];
748 n -= 4;
749 buf += 4;
750 } else
751 return;
753 } else
754 return;
756 if (n < name_len + val_len)
757 return;
759 if ((env_entry = malloc(sizeof(struct env_val))) == NULL) {
760 lwarnx("cannot allocate env_entry");
761 return;
764 if ((env_entry->val = calloc(sizeof(char), name_len + val_len +
765 2)) == NULL) {
766 lwarnx("cannot allocate env_entry->val");
767 free(env_entry);
768 return;
771 bcopy(buf, env_entry->val, name_len);
772 buf += name_len;
773 n -= name_len;
775 env_entry->val[name_len] = '\0';
776 if (val_len < PATH_MAX && strcmp(env_entry->val,
777 "SCRIPT_NAME") == 0 && c->script_name[0] == '\0') {
778 bcopy(buf, c->script_name, val_len);
779 c->script_name[val_len] = '\0';
780 } else if (val_len < PATH_MAX && strcmp(env_entry->val,
781 "SCRIPT_FILENAME") == 0) {
782 bcopy(buf, c->script_name, val_len);
783 c->script_name[val_len] = '\0';
785 env_entry->val[name_len] = '=';
787 bcopy(buf, (env_entry->val) + name_len + 1, val_len);
788 buf += val_len;
789 n -= val_len;
791 SLIST_INSERT_HEAD(&c->env, env_entry, entry);
792 ldebug("env[%d], %s", c->env_count, env_entry->val);
793 c->env_count++;
797 void
798 parse_stdin(uint8_t *buf, uint16_t n, struct request *c, uint16_t id)
800 struct fcgi_stdin *node;
802 if (c->id != id) {
803 lwarnx("unexpected id, ignoring");
804 return;
807 if ((node = calloc(1, sizeof(struct fcgi_stdin))) == NULL) {
808 lwarnx("cannot calloc stdin node");
809 return;
812 bcopy(buf, node->data, n);
813 node->data_pos = 0;
814 node->data_len = n;
816 TAILQ_INSERT_TAIL(&c->stdin_head, node, entry);
818 if (event_initialized(&c->script_stdin_ev))
819 event_add(&c->script_stdin_ev, NULL);
822 size_t
823 parse_record(uint8_t *buf, size_t n, struct request *c)
825 struct fcgi_record_header *h;
827 if (n < sizeof(struct fcgi_record_header))
828 return (0);
830 h = (struct fcgi_record_header*) buf;
832 if (debug > 1)
833 dump_fcgi_record("", h);
835 if (n < sizeof(struct fcgi_record_header) + ntohs(h->content_len)
836 + h->padding_len)
837 return (0);
839 if (h->version != 1)
840 lerrx(1, "wrong version");
842 switch (h->type) {
843 case FCGI_BEGIN_REQUEST:
844 parse_begin_request(buf + sizeof(struct fcgi_record_header),
845 ntohs(h->content_len), c, ntohs(h->id));
846 break;
847 case FCGI_PARAMS:
848 parse_params(buf + sizeof(struct fcgi_record_header),
849 ntohs(h->content_len), c, ntohs(h->id));
850 break;
851 case FCGI_STDIN:
852 parse_stdin(buf + sizeof(struct fcgi_record_header),
853 ntohs(h->content_len), c, ntohs(h->id));
854 break;
855 default:
856 lwarnx("unimplemented type %d", h->type);
857 break;
860 return (sizeof(struct fcgi_record_header) + ntohs(h->content_len)
861 + h->padding_len);
864 /*
865 * Fork a new CGI process to handle the request, translating
866 * between FastCGI parameter records and CGI's environment variables,
867 * as well as between the CGI process' stdin/stdout and the
868 * corresponding FastCGI records.
869 */
870 void
871 exec_cgi(struct request *c)
873 struct env_val *env_entry;
874 int s_in[2], s_out[2], s_err[2], i;
875 pid_t pid;
876 char *argv[2];
877 char **env;
878 char *path;
880 i = 0;
882 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s_in) == -1)
883 lerr(1, "socketpair");
884 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s_out) == -1)
885 lerr(1, "socketpair");
886 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s_err) == -1)
887 lerr(1, "socketpair");
888 cgi_inflight--;
889 c->inflight_fds_accounted = 1;
890 ldebug("fork: %s", c->script_name);
892 switch (pid = fork()) {
893 case -1:
894 c->script_status = errno;
896 lwarn("fork");
898 close(s_in[0]);
899 close(s_out[0]);
900 close(s_err[0]);
902 close(s_in[1]);
903 close(s_out[1]);
904 close(s_err[1]);
906 c->stdin_fd_closed = c->stdout_fd_closed =
907 c->stderr_fd_closed = 1;
908 c->script_flags = (STDOUT_DONE | STDERR_DONE | SCRIPT_DONE);
910 create_end_record(c);
911 return;
912 case 0:
913 /* Child process */
914 if (pledge("stdio rpath exec", NULL) == -1)
915 lerr(1, "pledge");
916 close(s_in[0]);
917 close(s_out[0]);
918 close(s_err[0]);
920 if (dup2(s_in[1], STDIN_FILENO) == -1)
921 _exit(1);
922 if (dup2(s_out[1], STDOUT_FILENO) == -1)
923 _exit(1);
924 if (dup2(s_err[1], STDERR_FILENO) == -1)
925 _exit(1);
927 close(s_in[1]);
928 close(s_out[1]);
929 close(s_err[1]);
931 signal(SIGPIPE, SIG_DFL);
933 path = strrchr(c->script_name, '/');
934 if (path != NULL) {
935 if (path != c->script_name) {
936 *path = '\0';
937 if (chdir(c->script_name) == -1)
938 lwarn("cannot chdir to %s",
939 c->script_name);
940 *path = '/';
941 } else
942 if (chdir("/") == -1)
943 lwarn("cannot chdir to /");
946 argv[0] = c->script_name;
947 argv[1] = NULL;
948 if ((env = calloc(c->env_count + 1, sizeof(char*))) == NULL)
949 _exit(1);
950 SLIST_FOREACH(env_entry, &c->env, entry)
951 env[i++] = env_entry->val;
952 env[i++] = NULL;
953 execve(c->script_name, argv, env);
954 lwarn("execve %s", c->script_name);
955 _exit(1);
959 /* Parent process*/
960 close(s_in[1]);
961 close(s_out[1]);
962 close(s_err[1]);
964 fcntl(s_in[0], F_SETFD, FD_CLOEXEC);
965 fcntl(s_out[0], F_SETFD, FD_CLOEXEC);
966 fcntl(s_err[0], F_SETFD, FD_CLOEXEC);
968 if (ioctl(s_in[0], FIONBIO, &on) == -1)
969 lerr(1, "script ioctl(FIONBIO)");
970 if (ioctl(s_out[0], FIONBIO, &on) == -1)
971 lerr(1, "script ioctl(FIONBIO)");
972 if (ioctl(s_err[0], FIONBIO, &on) == -1)
973 lerr(1, "script ioctl(FIONBIO)");
975 c->script_pid = pid;
976 event_set(&c->script_stdin_ev, s_in[0], EV_WRITE | EV_PERSIST,
977 script_out, c);
978 event_add(&c->script_stdin_ev, NULL);
979 event_set(&c->script_ev, s_out[0], EV_READ | EV_PERSIST,
980 script_std_in, c);
981 event_add(&c->script_ev, NULL);
982 event_set(&c->script_err_ev, s_err[0], EV_READ | EV_PERSIST,
983 script_err_in, c);
984 event_add(&c->script_err_ev, NULL);
987 void
988 create_end_record(struct request *c)
990 struct fcgi_response *resp;
991 struct fcgi_record_header *header;
992 struct fcgi_end_request_body *end_request;
994 if ((resp = calloc(1, sizeof(struct fcgi_response))) == NULL) {
995 lwarnx("cannot malloc fcgi_response");
996 return;
998 header = (struct fcgi_record_header*) resp->data;
999 header->version = 1;
1000 header->type = FCGI_END_REQUEST;
1001 header->id = htons(c->id);
1002 header->content_len = htons(sizeof(struct
1003 fcgi_end_request_body));
1004 header->padding_len = 0;
1005 header->reserved = 0;
1006 end_request = (struct fcgi_end_request_body *) (resp->data +
1007 sizeof(struct fcgi_record_header));
1008 end_request->app_status = htonl(c->script_status);
1009 end_request->protocol_status = FCGI_REQUEST_COMPLETE;
1010 end_request->reserved[0] = 0;
1011 end_request->reserved[1] = 0;
1012 end_request->reserved[2] = 0;
1013 resp->data_pos = 0;
1014 resp->data_len = sizeof(struct fcgi_end_request_body) +
1015 sizeof(struct fcgi_record_header);
1016 slowcgi_add_response(c, resp);
1019 void
1020 script_in(int fd, struct event *ev, struct request *c, uint8_t type)
1022 struct fcgi_response *resp;
1023 struct fcgi_record_header *header;
1024 ssize_t n;
1026 if ((resp = calloc(1, sizeof(struct fcgi_response))) == NULL) {
1027 lwarnx("cannot malloc fcgi_response");
1028 return;
1030 header = (struct fcgi_record_header*) resp->data;
1031 header->version = 1;
1032 header->type = type;
1033 header->id = htons(c->id);
1034 header->padding_len = 0;
1035 header->reserved = 0;
1037 n = read(fd, resp->data + sizeof(struct fcgi_record_header),
1038 FCGI_CONTENT_SIZE);
1040 if (n == -1) {
1041 switch (errno) {
1042 case EINTR:
1043 case EAGAIN:
1044 free(resp);
1045 return;
1046 default:
1047 n = 0; /* fake empty FCGI_STD{OUT,ERR} response */
1050 header->content_len = htons(n);
1051 resp->data_pos = 0;
1052 resp->data_len = n + sizeof(struct fcgi_record_header);
1053 slowcgi_add_response(c, resp);
1055 if (n == 0) {
1056 if (type == FCGI_STDOUT)
1057 c->script_flags |= STDOUT_DONE;
1058 else
1059 c->script_flags |= STDERR_DONE;
1061 if (c->script_flags == (STDOUT_DONE | STDERR_DONE |
1062 SCRIPT_DONE)) {
1063 create_end_record(c);
1065 event_del(ev);
1066 close(fd);
1067 if (type == FCGI_STDOUT)
1068 c->stdout_fd_closed = 1;
1069 else
1070 c->stderr_fd_closed = 1;
1074 void
1075 script_std_in(int fd, short events, void *arg)
1077 struct request *c = arg;
1078 script_in(fd, &c->script_ev, c, FCGI_STDOUT);
1081 void
1082 script_err_in(int fd, short events, void *arg)
1084 struct request *c = arg;
1085 script_in(fd, &c->script_err_ev, c, FCGI_STDERR);
1088 void
1089 script_out(int fd, short events, void *arg)
1091 struct request *c;
1092 struct fcgi_stdin *node;
1093 ssize_t n;
1095 c = arg;
1097 while ((node = TAILQ_FIRST(&c->stdin_head))) {
1098 if (node->data_len == 0) { /* end of stdin marker */
1099 close(fd);
1100 c->stdin_fd_closed = 1;
1101 break;
1103 n = write(fd, node->data + node->data_pos, node->data_len);
1104 if (n == -1) {
1105 if (errno == EAGAIN || errno == EINTR)
1106 return;
1107 event_del(&c->script_stdin_ev);
1108 return;
1110 node->data_pos += n;
1111 node->data_len -= n;
1112 if (node->data_len == 0) {
1113 TAILQ_REMOVE(&c->stdin_head, node, entry);
1114 free(node);
1117 event_del(&c->script_stdin_ev);
1120 void
1121 cleanup_request(struct request *c)
1123 struct fcgi_response *resp;
1124 struct fcgi_stdin *stdin_node;
1125 struct env_val *env_entry;
1127 evtimer_del(&c->tmo);
1128 if (event_initialized(&c->ev))
1129 event_del(&c->ev);
1130 if (event_initialized(&c->resp_ev))
1131 event_del(&c->resp_ev);
1132 if (event_initialized(&c->script_ev)) {
1133 if (!c->stdout_fd_closed)
1134 close(EVENT_FD(&c->script_ev));
1135 event_del(&c->script_ev);
1137 if (event_initialized(&c->script_err_ev)) {
1138 if (!c->stderr_fd_closed)
1139 close(EVENT_FD(&c->script_err_ev));
1140 event_del(&c->script_err_ev);
1142 if (event_initialized(&c->script_stdin_ev)) {
1143 if (!c->stdin_fd_closed)
1144 close(EVENT_FD(&c->script_stdin_ev));
1145 event_del(&c->script_stdin_ev);
1147 close(c->fd);
1148 while (!SLIST_EMPTY(&c->env)) {
1149 env_entry = SLIST_FIRST(&c->env);
1150 SLIST_REMOVE_HEAD(&c->env, entry);
1151 free(env_entry->val);
1152 free(env_entry);
1155 while ((resp = TAILQ_FIRST(&c->response_head))) {
1156 TAILQ_REMOVE(&c->response_head, resp, entry);
1157 free(resp);
1159 while ((stdin_node = TAILQ_FIRST(&c->stdin_head))) {
1160 TAILQ_REMOVE(&c->stdin_head, stdin_node, entry);
1161 free(stdin_node);
1163 LIST_REMOVE(c, entry);
1164 if (! c->inflight_fds_accounted)
1165 cgi_inflight--;
1166 free(c);
1169 void
1170 dump_fcgi_record(const char *p, struct fcgi_record_header *h)
1172 dump_fcgi_record_header(p, h);
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));
1182 void
1183 dump_fcgi_record_header(const char* p, struct fcgi_record_header *h)
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);
1193 void
1194 dump_fcgi_begin_request_body(const char *p, struct fcgi_begin_request_body *b)
1196 ldebug("%srole %d", p, ntohs(b->role));
1197 ldebug("%sflags %d", p, b->flags);
1200 void
1201 dump_fcgi_end_request_body(const char *p, struct fcgi_end_request_body *b)
1203 ldebug("%sappStatus: %d", p, ntohl(b->app_status));
1204 ldebug("%sprotocolStatus: %d", p, b->protocol_status);
1207 void
1208 syslog_vstrerror(int e, int priority, const char *fmt, va_list ap)
1210 char *s;
1212 if (vasprintf(&s, fmt, ap) == -1) {
1213 syslog(LOG_EMERG, "unable to alloc in syslog_vstrerror");
1214 exit(1);
1216 syslog(priority, "%s: %s", s, strerror(e));
1217 free(s);
1220 __dead void
1221 syslog_err(int ecode, const char *fmt, ...)
1223 va_list ap;
1225 va_start(ap, fmt);
1226 syslog_vstrerror(errno, LOG_CRIT, fmt, ap);
1227 va_end(ap);
1228 exit(ecode);
1231 __dead void
1232 syslog_errx(int ecode, const char *fmt, ...)
1234 va_list ap;
1236 va_start(ap, fmt);
1237 vsyslog(LOG_CRIT, fmt, ap);
1238 va_end(ap);
1239 exit(ecode);
1242 void
1243 syslog_warn(const char *fmt, ...)
1245 va_list ap;
1247 va_start(ap, fmt);
1248 syslog_vstrerror(errno, LOG_ERR, fmt, ap);
1249 va_end(ap);
1252 void
1253 syslog_warnx(const char *fmt, ...)
1255 va_list ap;
1257 va_start(ap, fmt);
1258 vsyslog(LOG_ERR, fmt, ap);
1259 va_end(ap);
1262 void
1263 syslog_info(const char *fmt, ...)
1265 va_list ap;
1267 va_start(ap, fmt);
1268 vsyslog(LOG_INFO, fmt, ap);
1269 va_end(ap);
1272 void
1273 syslog_debug(const char *fmt, ...)
1275 if (verbose > 0) {
1276 va_list ap;
1277 va_start(ap, fmt);
1278 vsyslog(LOG_DEBUG, fmt, ap);
1279 va_end(ap);