Bug Summary

File:src/usr.sbin/slowcgi/slowcgi.c
Warning:line 1099, column 7
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name slowcgi.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/slowcgi/obj -resource-dir /usr/local/llvm16/lib/clang/16 -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/slowcgi/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.sbin/slowcgi/slowcgi.c
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(*__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_DEFAULT120 120
43#define TIMEOUT_MAX(86400 * 365) (86400 * 365)
44#define SLOWCGI_USER"www" "www"
45
46#define FCGI_CONTENT_SIZE65535 65535
47#define FCGI_PADDING_SIZE255 255
48#define FCGI_RECORD_SIZE(sizeof(struct fcgi_record_header) + 65535 + 255) \
49 (sizeof(struct fcgi_record_header) + FCGI_CONTENT_SIZE65535 + FCGI_PADDING_SIZE255)
50
51#define FCGI_ALIGNMENT8 8
52#define FCGI_ALIGN(n)(((n) + (8 - 1)) & ~(8 - 1)) \
53 (((n) + (FCGI_ALIGNMENT8 - 1)) & ~(FCGI_ALIGNMENT8 - 1))
54
55#define STDOUT_DONE1 1
56#define STDERR_DONE2 2
57#define SCRIPT_DONE4 4
58
59#define FCGI_BEGIN_REQUEST1 1
60#define FCGI_ABORT_REQUEST2 2
61#define FCGI_END_REQUEST3 3
62#define FCGI_PARAMS4 4
63#define FCGI_STDIN5 5
64#define FCGI_STDOUT6 6
65#define FCGI_STDERR7 7
66#define FCGI_DATA8 8
67#define FCGI_GET_VALUES9 9
68#define FCGI_GET_VALUES_RESULT10 10
69#define FCGI_UNKNOWN_TYPE11 11
70#define FCGI_MAXTYPE(11) (FCGI_UNKNOWN_TYPE11)
71
72#define FCGI_REQUEST_COMPLETE0 0
73#define FCGI_CANT_MPX_CONN1 1
74#define FCGI_OVERLOADED2 2
75#define FCGI_UNKNOWN_ROLE3 3
76
77#define FD_RESERVE5 5
78#define FD_NEEDED6 6
79int cgi_inflight = 0;
80
81struct listener {
82 struct event ev, pause;
83};
84
85struct env_val {
86 SLIST_ENTRY(env_val)struct { struct env_val *sle_next; } entry;
87 char *val;
88};
89SLIST_HEAD(env_head, env_val)struct env_head { struct env_val *slh_first; };
90
91struct 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__attribute__((__packed__));
99
100struct fcgi_response {
101 TAILQ_ENTRY(fcgi_response)struct { struct fcgi_response *tqe_next; struct fcgi_response
**tqe_prev; }
entry;
102 uint8_t data[FCGI_RECORD_SIZE(sizeof(struct fcgi_record_header) + 65535 + 255)];
103 size_t data_pos;
104 size_t data_len;
105};
106TAILQ_HEAD(fcgi_response_head, fcgi_response)struct fcgi_response_head { struct fcgi_response *tqh_first; struct
fcgi_response **tqh_last; }
;
107
108struct fcgi_stdin {
109 TAILQ_ENTRY(fcgi_stdin)struct { struct fcgi_stdin *tqe_next; struct fcgi_stdin **tqe_prev
; }
entry;
110 uint8_t data[FCGI_RECORD_SIZE(sizeof(struct fcgi_record_header) + 65535 + 255)];
111 size_t data_pos;
112 size_t data_len;
113};
114TAILQ_HEAD(fcgi_stdin_head, fcgi_stdin)struct fcgi_stdin_head { struct fcgi_stdin *tqh_first; struct
fcgi_stdin **tqh_last; }
;
115
116struct request {
117 LIST_ENTRY(request)struct { struct request *le_next; struct request **le_prev; } entry;
118 struct event ev;
119 struct event resp_ev;
120 struct event tmo;
121 int fd;
122 uint8_t buf[FCGI_RECORD_SIZE(sizeof(struct fcgi_record_header) + 65535 + 255)];
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_MAX1024];
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
144LIST_HEAD(requests_head, request)struct requests_head { struct request *lh_first; };
145
146struct slowcgi_proc {
147 struct requests_head requests;
148 struct event ev_sigchld;
149};
150
151struct fcgi_begin_request_body {
152 uint16_t role;
153 uint8_t flags;
154 uint8_t reserved[5];
155}__packed__attribute__((__packed__));
156
157struct fcgi_end_request_body {
158 uint32_t app_status;
159 uint8_t protocol_status;
160 uint8_t reserved[3];
161}__packed__attribute__((__packed__));
162
163__dead__attribute__((__noreturn__)) void usage(void);
164int slowcgi_listen(char *, struct passwd *);
165void slowcgi_paused(int, short, void *);
166int accept_reserve(int, struct sockaddr *, socklen_t *, int, int *);
167void slowcgi_accept(int, short, void *);
168void slowcgi_request(int, short, void *);
169void slowcgi_response(int, short, void *);
170void slowcgi_add_response(struct request *, struct fcgi_response *);
171void slowcgi_timeout(int, short, void *);
172void slowcgi_sig_handler(int, short, void *);
173size_t parse_record(uint8_t * , size_t, struct request *);
174void parse_begin_request(uint8_t *, uint16_t, struct request *,
175 uint16_t);
176void parse_params(uint8_t *, uint16_t, struct request *, uint16_t);
177void parse_stdin(uint8_t *, uint16_t, struct request *, uint16_t);
178void exec_cgi(struct request *);
179void script_in(int, struct event *, struct request *, uint8_t);
180void script_std_in(int, short, void *);
181void script_err_in(int, short, void *);
182void script_out(int, short, void *);
183void create_end_record(struct request *);
184void dump_fcgi_record(const char *,
185 struct fcgi_record_header *);
186void dump_fcgi_record_header(const char *,
187 struct fcgi_record_header *);
188void dump_fcgi_begin_request_body(const char *,
189 struct fcgi_begin_request_body *);
190void dump_fcgi_end_request_body(const char *,
191 struct fcgi_end_request_body *);
192void cleanup_request(struct request *);
193
194struct loggers {
195 __dead__attribute__((__noreturn__)) void (*err)(int, const char *, ...)
196 __attribute__((__format__ (printf, 2, 3)));
197 __dead__attribute__((__noreturn__)) 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
209const struct loggers conslogger = {
210 err,
211 errx,
212 warn,
213 warnx,
214 warnx, /* info */
215 warnx /* debug */
216};
217
218__dead__attribute__((__noreturn__)) void syslog_err(int, const char *, ...)
219 __attribute__((__format__ (printf, 2, 3)));
220__dead__attribute__((__noreturn__)) void syslog_errx(int, const char *, ...)
221 __attribute__((__format__ (printf, 2, 3)));
222void syslog_warn(const char *, ...)
223 __attribute__((__format__ (printf, 1, 2)));
224void syslog_warnx(const char *, ...)
225 __attribute__((__format__ (printf, 1, 2)));
226void syslog_info(const char *, ...)
227 __attribute__((__format__ (printf, 1, 2)));
228void syslog_debug(const char *, ...)
229 __attribute__((__format__ (printf, 1, 2)));
230void syslog_vstrerror(int, int, const char *, va_list)
231 __attribute__((__format__ (printf, 3, 0)));
232
233const struct loggers syslogger = {
234 syslog_err,
235 syslog_errx,
236 syslog_warn,
237 syslog_warnx,
238 syslog_info,
239 syslog_debug
240};
241
242const struct loggers *logger = &conslogger;
243
244#define lerr(_e, _f...)logger->err((_e), _f...) logger->err((_e), _f)
245#define lerrx(_e, _f...)logger->errx((_e), _f...) logger->errx((_e), _f)
246#define lwarn(_f...)logger->warn(_f...) logger->warn(_f)
247#define lwarnx(_f...)logger->warnx(_f...) logger->warnx(_f)
248#define linfo(_f...)logger->info(_f...) logger->info(_f)
249#define ldebug(_f...)logger->debug(_f...) logger->debug(_f)
250
251__dead__attribute__((__noreturn__)) void
252usage(void)
253{
254 extern char *__progname;
255 fprintf(stderr(&__sF[2]),
256 "usage: %s [-dv] [-p path] [-s socket] [-t timeout] [-U user] "
257 "[-u user]\n", __progname);
258 exit(1);
259}
260
261struct timeval timeout = { TIMEOUT_DEFAULT120, 0 };
262struct slowcgi_proc slowcgi_proc;
263int debug = 0;
264int verbose = 0;
265int on = 1;
266char *fcgi_socket = "/var/www/run/slowcgi.sock";
267
268int
269main(int argc, char *argv[])
270{
271 extern char *__progname;
272 struct listener *l = NULL((void *)0);
273 struct passwd *pw;
274 struct stat sb;
275 int c, fd;
276 const char *chrootpath = NULL((void *)0);
277 const char *sock_user = SLOWCGI_USER"www";
278 const char *slowcgi_user = SLOWCGI_USER"www";
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_RDWR0x0002)) != -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(86400 * 365),
311 &errstr);
312 if (errstr != NULL((void *)0))
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_PID0x01|LOG_NDELAY0x08, LOG_DAEMON(3<<3));
338 logger = &syslogger;
339 }
340
341 ldebug("sock_user: %s", sock_user)logger->debug("sock_user: %s", sock_user);
342 pw = getpwnam(sock_user);
343 if (pw == NULL((void *)0))
344 lerrx(1, "no %s user", sock_user)logger->errx((1), "no %s user", sock_user);
345
346 fd = slowcgi_listen(fcgi_socket, pw);
347
348 ldebug("slowcgi_user: %s", slowcgi_user)logger->debug("slowcgi_user: %s", slowcgi_user);
349 pw = getpwnam(slowcgi_user);
350 if (pw == NULL((void *)0))
351 lerrx(1, "no %s user", slowcgi_user)logger->errx((1), "no %s user", slowcgi_user);
352
353 if (chrootpath == NULL((void *)0))
354 chrootpath = pw->pw_dir;
355
356 if (chroot(chrootpath) == -1)
357 lerr(1, "chroot(%s)", chrootpath)logger->err((1), "chroot(%s)", chrootpath);
358
359 ldebug("chroot: %s", chrootpath)logger->debug("chroot: %s", chrootpath);
360
361 if (chdir("/") == -1)
362 lerr(1, "chdir(/)")logger->err((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")logger->err((1), "unable to revoke privs");
368
369 if (pledge("stdio rpath unix proc exec", NULL((void *)0)) == -1)
370 lerr(1, "pledge")logger->err((1), "pledge");
371
372 LIST_INIT(&slowcgi_proc.requests)do { ((&slowcgi_proc.requests)->lh_first) = ((void *)0
); } while (0)
;
373 event_init();
374
375 l = calloc(1, sizeof(*l));
376 if (l == NULL((void *)0))
377 lerr(1, "listener ev alloc")logger->err((1), "listener ev alloc");
378
379 event_set(&l->ev, fd, EV_READ0x02 | EV_PERSIST0x10, slowcgi_accept, l);
380 event_add(&l->ev, NULL((void *)0));
381 evtimer_set(&l->pause, slowcgi_paused, l)event_set(&l->pause, -1, 0, slowcgi_paused, l);
382
383 signal_set(&slowcgi_proc.ev_sigchld, SIGCHLD, slowcgi_sig_handler,event_set(&slowcgi_proc.ev_sigchld, 20, 0x08|0x10, slowcgi_sig_handler
, &slowcgi_proc)
384 &slowcgi_proc)event_set(&slowcgi_proc.ev_sigchld, 20, 0x08|0x10, slowcgi_sig_handler
, &slowcgi_proc)
;
385 signal(SIGPIPE13, SIG_IGN(void (*)(int))1);
386
387 signal_add(&slowcgi_proc.ev_sigchld, NULL)event_add(&slowcgi_proc.ev_sigchld, ((void *)0));
388
389 event_dispatch();
390 return (0);
391}
392
393int
394slowcgi_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_UNIX1, SOCK_STREAM1 | SOCK_NONBLOCK0x4000 | SOCK_CLOEXEC0x8000,
401 0)) == -1)
402 lerr(1, "slowcgi_listen: socket")logger->err((1), "slowcgi_listen: socket");
403
404 bzero(&sun, sizeof(sun));
405 sun.sun_family = AF_UNIX1;
406 if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
407 sizeof(sun.sun_path))
408 lerrx(1, "socket path too long")logger->errx((1), "socket path too long");
409
410 if (unlink(path) == -1)
411 if (errno(*__errno()) != ENOENT2)
412 lerr(1, "slowcgi_listen: unlink %s", path)logger->err((1), "slowcgi_listen: unlink %s", path);
413
414 old_umask = umask(S_IXUSR0000100|S_IXGRP0000010|S_IWOTH0000002|S_IROTH0000004|S_IXOTH0000001);
415
416 if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
417 lerr(1,"slowcgi_listen: bind: %s", path)logger->err((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)logger->err((1), "slowcgi_listen: chown: %s", path);
423
424 if (listen(fd, 5) == -1)
425 lerr(1, "listen")logger->err((1), "listen");
426
427 ldebug("socket: %s", path)logger->debug("socket: %s", path);
428 return fd;
429}
430
431void
432slowcgi_paused(int fd, short events, void *arg)
433{
434 struct listener *l = arg;
435 event_add(&l->ev, NULL((void *)0));
436}
437
438int
439accept_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_NEEDED6) >= getdtablesize()) {
445 ldebug("inflight fds exceeded")logger->debug("inflight fds exceeded");
446 errno(*__errno()) = EMFILE24;
447 return -1;
448 }
449
450 if ((ret = accept4(sockfd, addr, addrlen, SOCK_NONBLOCK0x4000 | SOCK_CLOEXEC0x8000))
451 > -1) {
452 (*counter)++;
453 ldebug("inflight incremented, now %d", *counter)logger->debug("inflight incremented, now %d", *counter);
454 }
455 return ret;
456}
457
458void
459slowcgi_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((void *)0);
472
473 len = sizeof(ss);
474 if ((s = accept_reserve(fd, (struct sockaddr *)&ss,
475 &len, FD_RESERVE5, &cgi_inflight)) == -1) {
476 switch (errno(*__errno())) {
477 case EINTR4:
478 case EWOULDBLOCK35:
479 case ECONNABORTED53:
480 return;
481 case EMFILE24:
482 case ENFILE23:
483 event_del(&l->ev);
484 evtimer_add(&l->pause, &backoff)event_add(&l->pause, &backoff);
485 return;
486 default:
487 lerr(1, "accept")logger->err((1), "accept");
488 }
489 }
490
491 c = calloc(1, sizeof(*c));
492 if (c == NULL((void *)0)) {
493 lwarn("cannot calloc request")logger->warn("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)do { (&c->response_head)->tqh_first = ((void *)0); (
&c->response_head)->tqh_last = &(&c->response_head
)->tqh_first; } while (0)
;
505 TAILQ_INIT(&c->stdin_head)do { (&c->stdin_head)->tqh_first = ((void *)0); (&
c->stdin_head)->tqh_last = &(&c->stdin_head)
->tqh_first; } while (0)
;
506
507 event_set(&c->ev, s, EV_READ0x02 | EV_PERSIST0x10, slowcgi_request, c);
508 event_add(&c->ev, NULL((void *)0));
509 event_set(&c->resp_ev, s, EV_WRITE0x04 | EV_PERSIST0x10, slowcgi_response, c);
510 evtimer_set(&c->tmo, slowcgi_timeout, c)event_set(&c->tmo, -1, 0, slowcgi_timeout, c);
511 evtimer_add(&c->tmo, &timeout)event_add(&c->tmo, &timeout);
512 LIST_INSERT_HEAD(&slowcgi_proc.requests, c, entry)do { if (((c)->entry.le_next = (&slowcgi_proc.requests
)->lh_first) != ((void *)0)) (&slowcgi_proc.requests)->
lh_first->entry.le_prev = &(c)->entry.le_next; (&
slowcgi_proc.requests)->lh_first = (c); (c)->entry.le_prev
= &(&slowcgi_proc.requests)->lh_first; } while (0
)
;
513}
514
515void
516slowcgi_timeout(int fd, short events, void *arg)
517{
518 cleanup_request((struct request*) arg);
519}
520
521void
522slowcgi_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 SIGCHLD20:
533 while ((pid = waitpid(WAIT_ANY(-1), &status, WNOHANG0x01)) > 0) {
534 LIST_FOREACH(c, &p->requests, entry)for((c) = ((&p->requests)->lh_first); (c)!= ((void *
)0); (c) = ((c)->entry.le_next))
535 if (c->script_pid == pid)
536 break;
537 if (c == NULL((void *)0)) {
538 lwarnx("caught exit of unknown child %i", pid)logger->warnx("caught exit of unknown child %i", pid);
539 continue;
540 }
541
542 if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177
) != 0)
)
543 c->script_status = WTERMSIG(status)(((status) & 0177));
544 else
545 c->script_status = WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff);
546
547 if (c->script_flags == (STDOUT_DONE1 | STDERR_DONE2))
548 create_end_record(c);
549 c->script_flags |= SCRIPT_DONE4;
550
551 ldebug("wait: %s", c->script_name)logger->debug("wait: %s", c->script_name);
552 }
553 if (pid == -1 && errno(*__errno()) != ECHILD10)
554 lwarn("waitpid")logger->warn("waitpid");
555 break;
556 default:
557 lerr(1, "unexpected signal: %d", sig)logger->err((1), "unexpected signal: %d", sig);
558 break;
559 }
560}
561
562void
563slowcgi_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)(((resp->data_len) + (8 - 1)) & ~(8 - 1));
572 if (padded_len > resp->data_len) {
573 /* There should always be FCGI_PADDING_SIZE bytes left */
574 if (padded_len > FCGI_RECORD_SIZE(sizeof(struct fcgi_record_header) + 65535 + 255))
575 lerr(1, "response too long")logger->err((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)do { (resp)->entry.tqe_next = ((void *)0); (resp)->entry
.tqe_prev = (&c->response_head)->tqh_last; *(&c
->response_head)->tqh_last = (resp); (&c->response_head
)->tqh_last = &(resp)->entry.tqe_next; } while (0)
;
581 event_add(&c->resp_ev, NULL((void *)0));
582}
583
584void
585slowcgi_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)((&c->response_head)->tqh_first))) {
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(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4)
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)do { if (((resp)->entry.tqe_next) != ((void *)0)) (resp)->
entry.tqe_next->entry.tqe_prev = (resp)->entry.tqe_prev
; else (&c->response_head)->tqh_last = (resp)->entry
.tqe_prev; *(resp)->entry.tqe_prev = (resp)->entry.tqe_next
; ; ; } while (0)
;
610 free(resp);
611 }
612 }
613
614 if (TAILQ_EMPTY(&c->response_head)(((&c->response_head)->tqh_first) == ((void *)0))) {
615 if (c->script_flags == (STDOUT_DONE1 | STDERR_DONE2 |
616 SCRIPT_DONE4))
617 cleanup_request(c);
618 else
619 event_del(&c->resp_ev);
620 }
621}
622
623void
624slowcgi_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(sizeof(struct fcgi_record_header) + 65535 + 255) - c->buf_pos-c->buf_len);
634
635 switch (n) {
636 case -1:
637 switch (errno(*__errno())) {
638 case EINTR4:
639 case EAGAIN35:
640 return;
641 default:
642 goto fail;
643 }
644 break;
645
646 case 0:
647 ldebug("closed connection")logger->debug("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;
673fail:
674 cleanup_request(c);
675}
676
677void
678parse_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")logger->warnx("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,logger->warnx("wrong size %d != %lu", n, sizeof(struct fcgi_begin_request_body
))
688 sizeof(struct fcgi_begin_request_body))logger->warnx("wrong size %d != %lu", n, 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){ ((&c->env)->slh_first) = ((void *)0); };
696 c->env_count = 0;
697}
698
699void
700parse_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")logger->warnx("FCGI_PARAMS without FCGI_BEGIN_REQUEST, ignoring"
)
;
707 return;
708 }
709
710 if (c->id != id) {
711 lwarnx("unexpected id, ignoring")logger->warnx("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((void *)0)) {
761 lwarnx("cannot allocate env_entry")logger->warnx("cannot allocate env_entry");
762 return;
763 }
764
765 if ((env_entry->val = calloc(sizeof(char), name_len + val_len +
766 2)) == NULL((void *)0)) {
767 lwarnx("cannot allocate env_entry->val")logger->warnx("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_MAX1024 && 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_MAX1024 && 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)do { (env_entry)->entry.sle_next = (&c->env)->slh_first
; (&c->env)->slh_first = (env_entry); } while (0)
;
793 ldebug("env[%d], %s", c->env_count, env_entry->val)logger->debug("env[%d], %s", c->env_count, env_entry->
val)
;
794 c->env_count++;
795 }
796}
797
798void
799parse_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")logger->warnx("unexpected id, ignoring");
805 return;
806 }
807
808 if ((node = calloc(1, sizeof(struct fcgi_stdin))) == NULL((void *)0)) {
809 lwarnx("cannot calloc stdin node")logger->warnx("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)do { (node)->entry.tqe_next = ((void *)0); (node)->entry
.tqe_prev = (&c->stdin_head)->tqh_last; *(&c->
stdin_head)->tqh_last = (node); (&c->stdin_head)->
tqh_last = &(node)->entry.tqe_next; } while (0)
;
818
819 if (event_initialized(&c->script_stdin_ev)((&c->script_stdin_ev)->ev_flags & 0x80))
820 event_add(&c->script_stdin_ev, NULL((void *)0));
821}
822
823size_t
824parse_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)(__uint16_t)(__builtin_constant_p(h->content_len) ? (__uint16_t
)(((__uint16_t)(h->content_len) & 0xffU) << 8 | (
(__uint16_t)(h->content_len) & 0xff00U) >> 8) : __swap16md
(h->content_len))
837 + h->padding_len)
838 return (0);
839
840 if (h->version != 1)
841 lerrx(1, "wrong version")logger->errx((1), "wrong version");
842
843 switch (h->type) {
844 case FCGI_BEGIN_REQUEST1:
845 parse_begin_request(buf + sizeof(struct fcgi_record_header),
846 ntohs(h->content_len)(__uint16_t)(__builtin_constant_p(h->content_len) ? (__uint16_t
)(((__uint16_t)(h->content_len) & 0xffU) << 8 | (
(__uint16_t)(h->content_len) & 0xff00U) >> 8) : __swap16md
(h->content_len))
, c, ntohs(h->id)(__uint16_t)(__builtin_constant_p(h->id) ? (__uint16_t)(((
__uint16_t)(h->id) & 0xffU) << 8 | ((__uint16_t)
(h->id) & 0xff00U) >> 8) : __swap16md(h->id))
);
847 break;
848 case FCGI_PARAMS4:
849 parse_params(buf + sizeof(struct fcgi_record_header),
850 ntohs(h->content_len)(__uint16_t)(__builtin_constant_p(h->content_len) ? (__uint16_t
)(((__uint16_t)(h->content_len) & 0xffU) << 8 | (
(__uint16_t)(h->content_len) & 0xff00U) >> 8) : __swap16md
(h->content_len))
, c, ntohs(h->id)(__uint16_t)(__builtin_constant_p(h->id) ? (__uint16_t)(((
__uint16_t)(h->id) & 0xffU) << 8 | ((__uint16_t)
(h->id) & 0xff00U) >> 8) : __swap16md(h->id))
);
851 break;
852 case FCGI_STDIN5:
853 parse_stdin(buf + sizeof(struct fcgi_record_header),
854 ntohs(h->content_len)(__uint16_t)(__builtin_constant_p(h->content_len) ? (__uint16_t
)(((__uint16_t)(h->content_len) & 0xffU) << 8 | (
(__uint16_t)(h->content_len) & 0xff00U) >> 8) : __swap16md
(h->content_len))
, c, ntohs(h->id)(__uint16_t)(__builtin_constant_p(h->id) ? (__uint16_t)(((
__uint16_t)(h->id) & 0xffU) << 8 | ((__uint16_t)
(h->id) & 0xff00U) >> 8) : __swap16md(h->id))
);
855 break;
856 default:
857 lwarnx("unimplemented type %d", h->type)logger->warnx("unimplemented type %d", h->type);
858 break;
859 }
860
861 return (sizeof(struct fcgi_record_header) + ntohs(h->content_len)(__uint16_t)(__builtin_constant_p(h->content_len) ? (__uint16_t
)(((__uint16_t)(h->content_len) & 0xffU) << 8 | (
(__uint16_t)(h->content_len) & 0xff00U) >> 8) : __swap16md
(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 */
871void
872exec_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_UNIX1, SOCK_STREAM1, PF_UNSPEC0, s_in) == -1)
884 lerr(1, "socketpair")logger->err((1), "socketpair");
885 if (socketpair(AF_UNIX1, SOCK_STREAM1, PF_UNSPEC0, s_out) == -1)
886 lerr(1, "socketpair")logger->err((1), "socketpair");
887 if (socketpair(AF_UNIX1, SOCK_STREAM1, PF_UNSPEC0, s_err) == -1)
888 lerr(1, "socketpair")logger->err((1), "socketpair");
889 cgi_inflight--;
890 c->inflight_fds_accounted = 1;
891 ldebug("fork: %s", c->script_name)logger->debug("fork: %s", c->script_name);
892
893 switch (pid = fork()) {
894 case -1:
895 c->script_status = errno(*__errno());
896
897 lwarn("fork")logger->warn("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_DONE1 | STDERR_DONE2 | SCRIPT_DONE4);
910
911 create_end_record(c);
912 return;
913 case 0:
914 /* Child process */
915 if (pledge("stdio rpath exec", NULL((void *)0)) == -1)
916 lerr(1, "pledge")logger->err((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_FILENO0) == -1)
922 _exit(1);
923 if (dup2(s_out[1], STDOUT_FILENO1) == -1)
924 _exit(1);
925 if (dup2(s_err[1], STDERR_FILENO2) == -1)
926 _exit(1);
927
928 close(s_in[1]);
929 close(s_out[1]);
930 close(s_err[1]);
931
932 signal(SIGPIPE13, SIG_DFL(void (*)(int))0);
933
934 path = strrchr(c->script_name, '/');
935 if (path != NULL((void *)0)) {
936 if (path != c->script_name) {
937 *path = '\0';
938 if (chdir(c->script_name) == -1)
939 lwarn("cannot chdir to %s",logger->warn("cannot chdir to %s", c->script_name)
940 c->script_name)logger->warn("cannot chdir to %s", c->script_name);
941 *path = '/';
942 } else
943 if (chdir("/") == -1)
944 lwarn("cannot chdir to /")logger->warn("cannot chdir to /");
945 }
946
947 argv[0] = c->script_name;
948 argv[1] = NULL((void *)0);
949 if ((env = calloc(c->env_count + 1, sizeof(char*))) == NULL((void *)0))
950 _exit(1);
951 SLIST_FOREACH(env_entry, &c->env, entry)for((env_entry) = ((&c->env)->slh_first); (env_entry
) != ((void *)0); (env_entry) = ((env_entry)->entry.sle_next
))
952 env[i++] = env_entry->val;
953 env[i++] = NULL((void *)0);
954 execve(c->script_name, argv, env);
955 lwarn("execve %s", c->script_name)logger->warn("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_SETFD2, FD_CLOEXEC1);
966 fcntl(s_out[0], F_SETFD2, FD_CLOEXEC1);
967 fcntl(s_err[0], F_SETFD2, FD_CLOEXEC1);
968
969 if (ioctl(s_in[0], FIONBIO((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((126)))
, &on) == -1)
970 lerr(1, "script ioctl(FIONBIO)")logger->err((1), "script ioctl(FIONBIO)");
971 if (ioctl(s_out[0], FIONBIO((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((126)))
, &on) == -1)
972 lerr(1, "script ioctl(FIONBIO)")logger->err((1), "script ioctl(FIONBIO)");
973 if (ioctl(s_err[0], FIONBIO((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((126)))
, &on) == -1)
974 lerr(1, "script ioctl(FIONBIO)")logger->err((1), "script ioctl(FIONBIO)");
975
976 c->script_pid = pid;
977 event_set(&c->script_stdin_ev, s_in[0], EV_WRITE0x04 | EV_PERSIST0x10,
978 script_out, c);
979 event_add(&c->script_stdin_ev, NULL((void *)0));
980 event_set(&c->script_ev, s_out[0], EV_READ0x02 | EV_PERSIST0x10,
981 script_std_in, c);
982 event_add(&c->script_ev, NULL((void *)0));
983 event_set(&c->script_err_ev, s_err[0], EV_READ0x02 | EV_PERSIST0x10,
984 script_err_in, c);
985 event_add(&c->script_err_ev, NULL((void *)0));
986}
987
988void
989create_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((void *)0)) {
996 lwarnx("cannot malloc fcgi_response")logger->warnx("cannot malloc fcgi_response");
997 return;
998 }
999 header = (struct fcgi_record_header*) resp->data;
1000 header->version = 1;
1001 header->type = FCGI_END_REQUEST3;
1002 header->id = htons(c->id)(__uint16_t)(__builtin_constant_p(c->id) ? (__uint16_t)(((
__uint16_t)(c->id) & 0xffU) << 8 | ((__uint16_t)
(c->id) & 0xff00U) >> 8) : __swap16md(c->id))
;
1003 header->content_len = htons(sizeof(struct(__uint16_t)(__builtin_constant_p(sizeof(struct fcgi_end_request_body
)) ? (__uint16_t)(((__uint16_t)(sizeof(struct fcgi_end_request_body
)) & 0xffU) << 8 | ((__uint16_t)(sizeof(struct fcgi_end_request_body
)) & 0xff00U) >> 8) : __swap16md(sizeof(struct fcgi_end_request_body
)))
1004 fcgi_end_request_body))(__uint16_t)(__builtin_constant_p(sizeof(struct fcgi_end_request_body
)) ? (__uint16_t)(((__uint16_t)(sizeof(struct fcgi_end_request_body
)) & 0xffU) << 8 | ((__uint16_t)(sizeof(struct fcgi_end_request_body
)) & 0xff00U) >> 8) : __swap16md(sizeof(struct 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)(__uint32_t)(__builtin_constant_p(c->script_status) ? (__uint32_t
)(((__uint32_t)(c->script_status) & 0xff) << 24 |
((__uint32_t)(c->script_status) & 0xff00) << 8 |
((__uint32_t)(c->script_status) & 0xff0000) >> 8
| ((__uint32_t)(c->script_status) & 0xff000000) >>
24) : __swap32md(c->script_status))
;
1010 end_request->protocol_status = FCGI_REQUEST_COMPLETE0;
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
1020void
1021script_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((void *)0)) {
1028 lwarnx("cannot malloc fcgi_response")logger->warnx("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)(__uint16_t)(__builtin_constant_p(c->id) ? (__uint16_t)(((
__uint16_t)(c->id) & 0xffU) << 8 | ((__uint16_t)
(c->id) & 0xff00U) >> 8) : __swap16md(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_SIZE65535);
1040
1041 if (n == -1) {
1042 switch (errno(*__errno())) {
1043 case EINTR4:
1044 case EAGAIN35:
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)(__uint16_t)(__builtin_constant_p(n) ? (__uint16_t)(((__uint16_t
)(n) & 0xffU) << 8 | ((__uint16_t)(n) & 0xff00U
) >> 8) : __swap16md(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_STDOUT6)
1058 c->script_flags |= STDOUT_DONE1;
1059 else
1060 c->script_flags |= STDERR_DONE2;
1061
1062 if (c->script_flags == (STDOUT_DONE1 | STDERR_DONE2 |
1063 SCRIPT_DONE4)) {
1064 create_end_record(c);
1065 }
1066 event_del(ev);
1067 close(fd);
1068 if (type == FCGI_STDOUT6)
1069 c->stdout_fd_closed = 1;
1070 else
1071 c->stderr_fd_closed = 1;
1072 }
1073}
1074
1075void
1076script_std_in(int fd, short events, void *arg)
1077{
1078 struct request *c = arg;
1079 script_in(fd, &c->script_ev, c, FCGI_STDOUT6);
1080}
1081
1082void
1083script_err_in(int fd, short events, void *arg)
1084{
1085 struct request *c = arg;
1086 script_in(fd, &c->script_err_ev, c, FCGI_STDERR7);
1087}
1088
1089void
1090script_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)((&c->stdin_head)->tqh_first))) {
1
Loop condition is true. Entering loop body
12
Loop condition is true. Entering loop body
1099 if (node->data_len == 0) { /* end of stdin marker */
2
Assuming field 'data_len' is not equal to 0
3
Taking false branch
13
Use of memory after it is freed
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) {
4
Assuming the condition is false
5
Taking false branch
1106 if (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4)
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) {
6
Assuming field 'data_len' is equal to 0
7
Taking true branch
1114 TAILQ_REMOVE(&c->stdin_head, node, entry)do { if (((node)->entry.tqe_next) != ((void *)0)) (node)->
entry.tqe_next->entry.tqe_prev = (node)->entry.tqe_prev
; else (&c->stdin_head)->tqh_last = (node)->entry
.tqe_prev; *(node)->entry.tqe_prev = (node)->entry.tqe_next
; ; ; } while (0)
;
8
Assuming field 'tqe_next' is equal to null
9
Taking false branch
10
Loop condition is false. Exiting loop
1115 free(node);
11
Memory is released
1116 }
1117 }
1118 event_del(&c->script_stdin_ev);
1119}
1120
1121void
1122cleanup_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)event_del(&c->tmo);
1129 if (event_initialized(&c->ev)((&c->ev)->ev_flags & 0x80))
1130 event_del(&c->ev);
1131 if (event_initialized(&c->resp_ev)((&c->resp_ev)->ev_flags & 0x80))
1132 event_del(&c->resp_ev);
1133 if (event_initialized(&c->script_ev)((&c->script_ev)->ev_flags & 0x80)) {
1134 if (!c->stdout_fd_closed)
1135 close(EVENT_FD(&c->script_ev)(int)(&c->script_ev)->ev_fd);
1136 event_del(&c->script_ev);
1137 }
1138 if (event_initialized(&c->script_err_ev)((&c->script_err_ev)->ev_flags & 0x80)) {
1139 if (!c->stderr_fd_closed)
1140 close(EVENT_FD(&c->script_err_ev)(int)(&c->script_err_ev)->ev_fd);
1141 event_del(&c->script_err_ev);
1142 }
1143 if (event_initialized(&c->script_stdin_ev)((&c->script_stdin_ev)->ev_flags & 0x80)) {
1144 if (!c->stdin_fd_closed)
1145 close(EVENT_FD(&c->script_stdin_ev)(int)(&c->script_stdin_ev)->ev_fd);
1146 event_del(&c->script_stdin_ev);
1147 }
1148 close(c->fd);
1149 while (!SLIST_EMPTY(&c->env)(((&c->env)->slh_first) == ((void *)0))) {
1150 env_entry = SLIST_FIRST(&c->env)((&c->env)->slh_first);
1151 SLIST_REMOVE_HEAD(&c->env, entry)do { (&c->env)->slh_first = (&c->env)->slh_first
->entry.sle_next; } while (0)
;
1152 free(env_entry->val);
1153 free(env_entry);
1154 }
1155
1156 while ((resp = TAILQ_FIRST(&c->response_head)((&c->response_head)->tqh_first))) {
1157 TAILQ_REMOVE(&c->response_head, resp, entry)do { if (((resp)->entry.tqe_next) != ((void *)0)) (resp)->
entry.tqe_next->entry.tqe_prev = (resp)->entry.tqe_prev
; else (&c->response_head)->tqh_last = (resp)->entry
.tqe_prev; *(resp)->entry.tqe_prev = (resp)->entry.tqe_next
; ; ; } while (0)
;
1158 free(resp);
1159 }
1160 while ((stdin_node = TAILQ_FIRST(&c->stdin_head)((&c->stdin_head)->tqh_first))) {
1161 TAILQ_REMOVE(&c->stdin_head, stdin_node, entry)do { if (((stdin_node)->entry.tqe_next) != ((void *)0)) (stdin_node
)->entry.tqe_next->entry.tqe_prev = (stdin_node)->entry
.tqe_prev; else (&c->stdin_head)->tqh_last = (stdin_node
)->entry.tqe_prev; *(stdin_node)->entry.tqe_prev = (stdin_node
)->entry.tqe_next; ; ; } while (0)
;
1162 free(stdin_node);
1163 }
1164 LIST_REMOVE(c, entry)do { if ((c)->entry.le_next != ((void *)0)) (c)->entry.
le_next->entry.le_prev = (c)->entry.le_prev; *(c)->entry
.le_prev = (c)->entry.le_next; ; ; } while (0)
;
1165 if (! c->inflight_fds_accounted)
1166 cgi_inflight--;
1167 free(c);
1168}
1169
1170void
1171dump_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_REQUEST1)
1176 dump_fcgi_begin_request_body(p,
1177 (struct fcgi_begin_request_body *)(h + 1));
1178 else if (h->type == FCGI_END_REQUEST3)
1179 dump_fcgi_end_request_body(p,
1180 (struct fcgi_end_request_body *)(h + 1));
1181}
1182
1183void
1184dump_fcgi_record_header(const char* p, struct fcgi_record_header *h)
1185{
1186 ldebug("%sversion: %d", p, h->version)logger->debug("%sversion: %d", p, h->version);
1187 ldebug("%stype: %d", p, h->type)logger->debug("%stype: %d", p, h->type);
1188 ldebug("%srequestId: %d", p, ntohs(h->id))logger->debug("%srequestId: %d", p, (__uint16_t)(__builtin_constant_p
(h->id) ? (__uint16_t)(((__uint16_t)(h->id) & 0xffU
) << 8 | ((__uint16_t)(h->id) & 0xff00U) >>
8) : __swap16md(h->id)))
;
1189 ldebug("%scontentLength: %d", p, ntohs(h->content_len))logger->debug("%scontentLength: %d", p, (__uint16_t)(__builtin_constant_p
(h->content_len) ? (__uint16_t)(((__uint16_t)(h->content_len
) & 0xffU) << 8 | ((__uint16_t)(h->content_len) &
0xff00U) >> 8) : __swap16md(h->content_len)))
;
1190 ldebug("%spaddingLength: %d", p, h->padding_len)logger->debug("%spaddingLength: %d", p, h->padding_len
)
;
1191 ldebug("%sreserved: %d", p, h->reserved)logger->debug("%sreserved: %d", p, h->reserved);
1192}
1193
1194void
1195dump_fcgi_begin_request_body(const char *p, struct fcgi_begin_request_body *b)
1196{
1197 ldebug("%srole %d", p, ntohs(b->role))logger->debug("%srole %d", p, (__uint16_t)(__builtin_constant_p
(b->role) ? (__uint16_t)(((__uint16_t)(b->role) & 0xffU
) << 8 | ((__uint16_t)(b->role) & 0xff00U) >>
8) : __swap16md(b->role)))
;
1198 ldebug("%sflags %d", p, b->flags)logger->debug("%sflags %d", p, b->flags);
1199}
1200
1201void
1202dump_fcgi_end_request_body(const char *p, struct fcgi_end_request_body *b)
1203{
1204 ldebug("%sappStatus: %d", p, ntohl(b->app_status))logger->debug("%sappStatus: %d", p, (__uint32_t)(__builtin_constant_p
(b->app_status) ? (__uint32_t)(((__uint32_t)(b->app_status
) & 0xff) << 24 | ((__uint32_t)(b->app_status) &
0xff00) << 8 | ((__uint32_t)(b->app_status) & 0xff0000
) >> 8 | ((__uint32_t)(b->app_status) & 0xff000000
) >> 24) : __swap32md(b->app_status)))
;
1205 ldebug("%sprotocolStatus: %d", p, b->protocol_status)logger->debug("%sprotocolStatus: %d", p, b->protocol_status
)
;
1206}
1207
1208void
1209syslog_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_EMERG0, "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__attribute__((__noreturn__)) void
1222syslog_err(int ecode, const char *fmt, ...)
1223{
1224 va_list ap;
1225
1226 va_start(ap, fmt)__builtin_va_start((ap), fmt);
1227 syslog_vstrerror(errno(*__errno()), LOG_CRIT2, fmt, ap);
1228 va_end(ap)__builtin_va_end((ap));
1229 exit(ecode);
1230}
1231
1232__dead__attribute__((__noreturn__)) void
1233syslog_errx(int ecode, const char *fmt, ...)
1234{
1235 va_list ap;
1236
1237 va_start(ap, fmt)__builtin_va_start((ap), fmt);
1238 vsyslog(LOG_CRIT2, fmt, ap);
1239 va_end(ap)__builtin_va_end((ap));
1240 exit(ecode);
1241}
1242
1243void
1244syslog_warn(const char *fmt, ...)
1245{
1246 va_list ap;
1247
1248 va_start(ap, fmt)__builtin_va_start((ap), fmt);
1249 syslog_vstrerror(errno(*__errno()), LOG_ERR3, fmt, ap);
1250 va_end(ap)__builtin_va_end((ap));
1251}
1252
1253void
1254syslog_warnx(const char *fmt, ...)
1255{
1256 va_list ap;
1257
1258 va_start(ap, fmt)__builtin_va_start((ap), fmt);
1259 vsyslog(LOG_ERR3, fmt, ap);
1260 va_end(ap)__builtin_va_end((ap));
1261}
1262
1263void
1264syslog_info(const char *fmt, ...)
1265{
1266 va_list ap;
1267
1268 va_start(ap, fmt)__builtin_va_start((ap), fmt);
1269 vsyslog(LOG_INFO6, fmt, ap);
1270 va_end(ap)__builtin_va_end((ap));
1271}
1272
1273void
1274syslog_debug(const char *fmt, ...)
1275{
1276 if (verbose > 0) {
1277 va_list ap;
1278 va_start(ap, fmt)__builtin_va_start((ap), fmt);
1279 vsyslog(LOG_DEBUG7, fmt, ap);
1280 va_end(ap)__builtin_va_end((ap));
1281 }
1282}