Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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