Bug Summary

File:src/usr.sbin/bgplgd/slowcgi.c
Warning:line 1222, column 2
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/bgplgd/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/bgplgd/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/bgplgd/slowcgi.c
1/* $OpenBSD: slowcgi.c,v 1.6 2023/03/31 09:55:39 claudio Exp $ */
2/*
3 * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
4 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
5 * Copyright (c) 2013 David Gwynne <dlg@openbsd.org>
6 * Copyright (c) 2013 Florian Obser <florian@openbsd.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21#include <sys/types.h>
22#include <sys/ioctl.h>
23#include <sys/queue.h>
24#include <sys/socket.h>
25#include <sys/stat.h>
26#include <sys/time.h>
27#include <sys/un.h>
28#include <sys/wait.h>
29#include <arpa/inet.h>
30#include <err.h>
31#include <fcntl.h>
32#include <errno(*__errno()).h>
33#include <event.h>
34#include <limits.h>
35#include <pwd.h>
36#include <signal.h>
37#include <stdio.h>
38#include <stdarg.h>
39#include <stdlib.h>
40#include <string.h>
41#include <syslog.h>
42#include <unistd.h>
43
44#include "slowcgi.h"
45#include "bgplgd.h"
46#include "http.h"
47
48#define TIMEOUT_DEFAULT30 30
49#define WWW_USER"www" "www"
50#define BGPLGD_USER"_bgplgd" "_bgplgd"
51
52#define FCGI_CONTENT_SIZE65535 65535
53#define FCGI_PADDING_SIZE255 255
54#define FCGI_RECORD_SIZE(sizeof(struct fcgi_record_header) + 65535 + 255) \
55 (sizeof(struct fcgi_record_header) + FCGI_CONTENT_SIZE65535 + FCGI_PADDING_SIZE255)
56
57#define FCGI_ALIGNMENT8 8
58#define FCGI_ALIGN(n)(((n) + (8 - 1)) & ~(8 - 1)) \
59 (((n) + (FCGI_ALIGNMENT8 - 1)) & ~(FCGI_ALIGNMENT8 - 1))
60
61#define STDOUT_DONE0x1 0x1
62#define STDERR_DONE0x2 0x2
63#define SCRIPT_DONE0x4 0x4
64
65#define FCGI_REQUEST_COMPLETE0 0
66#define FCGI_CANT_MPX_CONN1 1
67#define FCGI_OVERLOADED2 2
68#define FCGI_UNKNOWN_ROLE3 3
69
70#define FD_RESERVE5 5
71#define FD_NEEDED6 6
72int cgi_inflight = 0;
73
74struct listener {
75 struct event ev, pause;
76};
77
78struct env_val {
79 SLIST_ENTRY(env_val)struct { struct env_val *sle_next; } entry;
80 char *key;
81 char *val;
82};
83SLIST_HEAD(env_head, env_val)struct env_head { struct env_val *slh_first; };
84
85struct fcgi_record_header {
86 uint8_t version;
87 uint8_t type;
88 uint16_t id;
89 uint16_t content_len;
90 uint8_t padding_len;
91 uint8_t reserved;
92}__packed__attribute__((__packed__));
93
94struct fcgi_response {
95 TAILQ_ENTRY(fcgi_response)struct { struct fcgi_response *tqe_next; struct fcgi_response
**tqe_prev; }
entry;
96 uint8_t data[FCGI_RECORD_SIZE(sizeof(struct fcgi_record_header) + 65535 + 255)];
97 size_t data_pos;
98 size_t data_len;
99};
100TAILQ_HEAD(fcgi_response_head, fcgi_response)struct fcgi_response_head { struct fcgi_response *tqh_first; struct
fcgi_response **tqh_last; }
;
101
102struct request {
103 LIST_ENTRY(request)struct { struct request *le_next; struct request **le_prev; } entry;
104 struct event ev;
105 struct event resp_ev;
106 struct event tmo;
107 struct event script_ev;
108 struct event script_err_ev;
109 struct fcgi_response_head response_head;
110 struct env_head env;
111 uint8_t buf[FCGI_RECORD_SIZE(sizeof(struct fcgi_record_header) + 65535 + 255)];
112 size_t buf_pos;
113 size_t buf_len;
114 int fd;
115 int env_count;
116 int inflight_fds_accounted;
117 pid_t command_pid;
118 int command_status;
119 int script_flags;
120 uint16_t id;
121 uint8_t request_started;
122 uint8_t request_done;
123 uint8_t timeout_fired;
124};
125
126LIST_HEAD(requests_head, request)struct requests_head { struct request *lh_first; };
127
128struct slowcgi_proc {
129 struct requests_head requests;
130 struct event ev_sigchld;
131};
132
133struct fcgi_begin_request_body {
134 uint16_t role;
135 uint8_t flags;
136 uint8_t reserved[5];
137}__packed__attribute__((__packed__));
138
139struct fcgi_end_request_body {
140 uint32_t app_status;
141 uint8_t protocol_status;
142 uint8_t reserved[3];
143}__packed__attribute__((__packed__));
144
145__dead__attribute__((__noreturn__)) void usage(void);
146int slowcgi_listen(char *, struct passwd *);
147void slowcgi_paused(int, short, void *);
148int accept_reserve(int, struct sockaddr *, socklen_t *, int,
149 volatile int *);
150void slowcgi_accept(int, short, void *);
151void slowcgi_request(int, short, void *);
152void slowcgi_response(int, short, void *);
153void slowcgi_add_response(struct request *, struct fcgi_response *);
154void slowcgi_timeout(int, short, void *);
155void slowcgi_sig_handler(int, short, void *);
156size_t parse_record(uint8_t * , size_t, struct request *);
157void parse_begin_request(uint8_t *, uint16_t, struct request *,
158 uint16_t);
159void parse_params(uint8_t *, uint16_t, struct request *, uint16_t);
160void parse_stdin(uint8_t *, uint16_t, struct request *, uint16_t);
161char *env_get(struct request *, const char *);
162void error_response(struct request *, int);
163void exec_cgi(struct request *);
164void script_std_in(int, short, void *);
165void script_err_in(int, short, void *);
166void create_data_record(struct request *, uint8_t, const void *,
167 size_t);
168void create_end_record(struct request *);
169void cleanup_request(struct request *);
170void dump_fcgi_record(const char *,
171 struct fcgi_record_header *);
172void dump_fcgi_record_header(const char *,
173 struct fcgi_record_header *);
174void dump_fcgi_begin_request_body(const char *,
175 struct fcgi_begin_request_body *);
176void dump_fcgi_end_request_body(const char *,
177 struct fcgi_end_request_body *);
178
179const struct loggers conslogger = {
180 err,
181 errx,
182 warn,
183 warnx,
184 warnx, /* info */
185 warnx /* debug */
186};
187
188__dead__attribute__((__noreturn__)) void syslog_err(int, const char *, ...)
189 __attribute__((__format__ (printf, 2, 3)));
190__dead__attribute__((__noreturn__)) void syslog_errx(int, const char *, ...)
191 __attribute__((__format__ (printf, 2, 3)));
192void syslog_warn(const char *, ...)
193 __attribute__((__format__ (printf, 1, 2)));
194void syslog_warnx(const char *, ...)
195 __attribute__((__format__ (printf, 1, 2)));
196void syslog_info(const char *, ...)
197 __attribute__((__format__ (printf, 1, 2)));
198void syslog_debug(const char *, ...)
199 __attribute__((__format__ (printf, 1, 2)));
200void syslog_vstrerror(int, int, const char *, va_list)
201 __attribute__((__format__ (printf, 3, 0)));
202
203const struct loggers syslogger = {
204 syslog_err,
205 syslog_errx,
206 syslog_warn,
207 syslog_warnx,
208 syslog_info,
209 syslog_debug
210};
211
212const struct loggers *logger = &conslogger;
213
214__dead__attribute__((__noreturn__)) void
215usage(void)
216{
217 extern char *__progname;
218 fprintf(stderr(&__sF[2]),
219 "usage: %s [-d] [-p path] [-S socket] [-s socket] [-U user]\n",
220 __progname);
221 exit(1);
222}
223
224struct timeval timeout = { TIMEOUT_DEFAULT30, 0 };
225struct timeval kill_timeout = { 5, 0 };
226struct slowcgi_proc slowcgi_proc;
227int debug = 0;
228int on = 1;
229char *fcgi_socket = "/var/www/run/bgplgd.sock";
230char *bgpctlpath = "bgpctl";
231char *bgpctlsock = "/var/run/bgpd.rsock";
232
233
234/*
235 * Unveil the command we want to run.
236 * If this has a pathname component in it, interpret as a file
237 * and unveil the file directly.
238 * Otherwise, look up the command in our PATH.
239 */
240static void
241unveil_command(const char *prog)
242{
243 const char *pp;
244 char *save, *cmd, *path;
245 struct stat st;
246
247 if (strchr(prog, '/') != NULL((void *)0)) {
248 if (unveil(prog, "x") == -1)
249 err(1, "%s: unveil", prog);
250 return;
251 }
252
253 if (getenv("PATH") == NULL((void *)0))
254 lerrx(1, "PATH is unset")logger->errx((1), "PATH is unset");
255 if ((path = strdup(getenv("PATH"))) == NULL((void *)0))
256 lerr(1, NULL)logger->err((1), ((void *)0));
257 save = path;
258 while ((pp = strsep(&path, ":")) != NULL((void *)0)) {
259 if (*pp == '\0')
260 continue;
261 if (asprintf(&cmd, "%s/%s", pp, prog) == -1)
262 lerr(1, NULL)logger->err((1), ((void *)0));
263 if (lstat(cmd, &st) == -1) {
264 free(cmd);
265 continue;
266 }
267 if (unveil(cmd, "x") == -1)
268 lerr(1, "%s: unveil", cmd)logger->err((1), "%s: unveil", cmd);
269 free(cmd);
270 break;
271 }
272 free(save);
273}
274
275int
276main(int argc, char *argv[])
277{
278 extern char *__progname;
279 struct listener *l = NULL((void *)0);
280 struct passwd *pw;
281 struct stat sb;
282 int c, fd;
283 const char *sock_user = WWW_USER"www";
284 const char *cgi_user = BGPLGD_USER"_bgplgd";
285
286 /*
287 * Ensure we have fds 0-2 open so that we have no fd overlaps
288 * in exec_cgi() later. Just exit on error, we don't have enough
289 * fds open to output an error message anywhere.
290 */
291 for (c=0; c < 3; c++) {
292 if (fstat(c, &sb) == -1) {
293 if ((fd = open("/dev/null", O_RDWR0x0002)) != -1) {
294 if (dup2(fd, c) == -1)
295 exit(1);
296 if (fd > c)
297 close(fd);
298 } else
299 exit(1);
300 }
301 }
302
303 while ((c = getopt(argc, argv, "dp:S:s:U:u:")) != -1) {
304 switch (c) {
305 case 'd':
306 debug++;
307 break;
308 case 'p':
309 bgpctlpath = optarg;
310 break;
311 case 'S':
312 bgpctlsock = optarg;
313 break;
314 case 's':
315 fcgi_socket = optarg;
316 break;
317 case 'U':
318 sock_user = optarg;
319 break;
320 default:
321 usage();
322 /* NOTREACHED */
323 }
324 }
325
326 if (geteuid() != 0)
327 errx(1, "need root privileges");
328
329 if (!debug && daemon(0, 0) == -1)
330 err(1, "daemon");
331
332 if (!debug) {
333 openlog(__progname, LOG_PID0x01|LOG_NDELAY0x08, LOG_DAEMON(3<<3));
334 logger = &syslogger;
335 }
336
337 ldebug("sock_user: %s", sock_user)logger->debug("sock_user: %s", sock_user);
338 pw = getpwnam(sock_user);
339 if (pw == NULL((void *)0))
340 lerrx(1, "no %s user", sock_user)logger->errx((1), "no %s user", sock_user);
341
342 fd = slowcgi_listen(fcgi_socket, pw);
343
344 ldebug("cgi_user: %s", cgi_user)logger->debug("cgi_user: %s", cgi_user);
345 pw = getpwnam(cgi_user);
346 if (pw == NULL((void *)0))
347 lerrx(1, "no %s user", cgi_user)logger->errx((1), "no %s user", cgi_user);
348
349 if (setgroups(1, &pw->pw_gid) ||
350 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
351 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
352 lerr(1, "unable to revoke privs")logger->err((1), "unable to revoke privs");
353
354 unveil_command(bgpctlpath);
355
356 if (pledge("stdio rpath unix proc exec", NULL((void *)0)) == -1)
357 lerr(1, "pledge")logger->err((1), "pledge");
358
359 LIST_INIT(&slowcgi_proc.requests)do { ((&slowcgi_proc.requests)->lh_first) = ((void *)0
); } while (0)
;
360 event_init();
361
362 l = calloc(1, sizeof(*l));
363 if (l == NULL((void *)0))
364 lerr(1, "listener ev alloc")logger->err((1), "listener ev alloc");
365
366 event_set(&l->ev, fd, EV_READ0x02 | EV_PERSIST0x10, slowcgi_accept, l);
367 event_add(&l->ev, NULL((void *)0));
368 evtimer_set(&l->pause, slowcgi_paused, l)event_set(&l->pause, -1, 0, slowcgi_paused, l);
369
370 signal_set(&slowcgi_proc.ev_sigchld, SIGCHLD, slowcgi_sig_handler,event_set(&slowcgi_proc.ev_sigchld, 20, 0x08|0x10, slowcgi_sig_handler
, &slowcgi_proc)
371 &slowcgi_proc)event_set(&slowcgi_proc.ev_sigchld, 20, 0x08|0x10, slowcgi_sig_handler
, &slowcgi_proc)
;
372 signal_add(&slowcgi_proc.ev_sigchld, NULL)event_add(&slowcgi_proc.ev_sigchld, ((void *)0));
373
374 signal(SIGPIPE13, SIG_IGN(void (*)(int))1);
375
376 event_dispatch();
377 return (0);
378}
379
380int
381slowcgi_listen(char *path, struct passwd *pw)
382{
383 struct sockaddr_un sun;
384 mode_t old_umask;
385 int fd;
386
387 if ((fd = socket(AF_UNIX1, SOCK_STREAM1 | SOCK_NONBLOCK0x4000 | SOCK_CLOEXEC0x8000,
388 0)) == -1)
389 lerr(1, "slowcgi_listen: socket")logger->err((1), "slowcgi_listen: socket");
390
391 memset(&sun, 0, sizeof(sun));
392 sun.sun_family = AF_UNIX1;
393 if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
394 sizeof(sun.sun_path))
395 lerrx(1, "socket path too long")logger->errx((1), "socket path too long");
396
397 if (unlink(path) == -1)
398 if (errno(*__errno()) != ENOENT2)
399 lerr(1, "slowcgi_listen: unlink %s", path)logger->err((1), "slowcgi_listen: unlink %s", path);
400
401 old_umask = umask(S_IXUSR0000100|S_IXGRP0000010|S_IWOTH0000002|S_IROTH0000004|S_IXOTH0000001);
402
403 if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
404 lerr(1,"slowcgi_listen: bind: %s", path)logger->err((1), "slowcgi_listen: bind: %s", path);
405
406 umask(old_umask);
407
408 if (chown(path, pw->pw_uid, pw->pw_gid) == -1)
409 lerr(1, "slowcgi_listen: chown: %s", path)logger->err((1), "slowcgi_listen: chown: %s", path);
410
411 if (listen(fd, 5) == -1)
412 lerr(1, "listen")logger->err((1), "listen");
413
414 ldebug("socket: %s", path)logger->debug("socket: %s", path);
415 return fd;
416}
417
418void
419slowcgi_paused(int fd, short events, void *arg)
420{
421 struct listener *l = arg;
422 event_add(&l->ev, NULL((void *)0));
423}
424
425int
426accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
427 int reserve, volatile int *counter)
428{
429 int ret;
430 if (getdtablecount() + reserve +
431 ((*counter + 1) * FD_NEEDED6) >= getdtablesize()) {
432 ldebug("inflight fds exceeded")logger->debug("inflight fds exceeded");
433 errno(*__errno()) = EMFILE24;
434 return -1;
435 }
436
437 if ((ret = accept4(sockfd, addr, addrlen, SOCK_NONBLOCK0x4000 | SOCK_CLOEXEC0x8000))
438 > -1) {
439 (*counter)++;
440 ldebug("inflight incremented, now %d", *counter)logger->debug("inflight incremented, now %d", *counter);
441 }
442 return ret;
443}
444
445void
446slowcgi_accept(int fd, short events, void *arg)
447{
448 struct listener *l;
449 struct sockaddr_storage ss;
450 struct timeval backoff;
451 struct request *c;
452 socklen_t len;
453 int s;
454
455 l = arg;
456 backoff.tv_sec = 1;
457 backoff.tv_usec = 0;
458 c = NULL((void *)0);
459
460 len = sizeof(ss);
461 if ((s = accept_reserve(fd, (struct sockaddr *)&ss,
462 &len, FD_RESERVE5, &cgi_inflight)) == -1) {
463 switch (errno(*__errno())) {
464 case EINTR4:
465 case EWOULDBLOCK35:
466 case ECONNABORTED53:
467 return;
468 case EMFILE24:
469 case ENFILE23:
470 event_del(&l->ev);
471 evtimer_add(&l->pause, &backoff)event_add(&l->pause, &backoff);
472 return;
473 default:
474 lerr(1, "accept")logger->err((1), "accept");
475 }
476 }
477
478 c = calloc(1, sizeof(*c));
479 if (c == NULL((void *)0)) {
480 lwarn("cannot calloc request")logger->warn("cannot calloc request");
481 close(s);
482 cgi_inflight--;
483 return;
484 }
485 c->fd = s;
486 c->buf_pos = 0;
487 c->buf_len = 0;
488 c->request_started = 0;
489 c->inflight_fds_accounted = 0;
490 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)
;
491
492 event_set(&c->ev, s, EV_READ0x02 | EV_PERSIST0x10, slowcgi_request, c);
493 event_add(&c->ev, NULL((void *)0));
494 event_set(&c->resp_ev, s, EV_WRITE0x04 | EV_PERSIST0x10, slowcgi_response, c);
495 evtimer_set(&c->tmo, slowcgi_timeout, c)event_set(&c->tmo, -1, 0, slowcgi_timeout, c);
496 evtimer_add(&c->tmo, &timeout)event_add(&c->tmo, &timeout);
497 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
)
;
498}
499
500void
501slowcgi_timeout(int fd, short events, void *arg)
502{
503 struct request *c = arg;
504 int sig = SIGTERM15;
505
506 if (c->script_flags & SCRIPT_DONE0x4)
507 return;
508
509 if (c->command_pid == 0) {
510 c->command_status = SIGALRM14;
511 error_response(c, 408);
512 return;
513 }
514
515 ldebug("timeout fired for pid %d", c->command_pid)logger->debug("timeout fired for pid %d", c->command_pid
)
;
516
517 if (c->timeout_fired)
518 sig = SIGKILL9;
519
520 if (kill(c->command_pid, sig) == -1) {
521 lwarn("kill child %d after timeout", c->command_pid)logger->warn("kill child %d after timeout", c->command_pid
)
;
522 if (event_initialized(&c->script_ev)((&c->script_ev)->ev_flags & 0x80)) {
523 close(EVENT_FD(&c->script_ev)(int)(&c->script_ev)->ev_fd);
524 event_del(&c->script_ev);
525 }
526 if (event_initialized(&c->script_err_ev)((&c->script_err_ev)->ev_flags & 0x80)) {
527 close(EVENT_FD(&c->script_err_ev)(int)(&c->script_err_ev)->ev_fd);
528 event_del(&c->script_err_ev);
529 }
530
531 c->command_status = SIGALRM14;
532 c->script_flags = STDOUT_DONE0x1 | STDERR_DONE0x2 | SCRIPT_DONE0x4;
533 create_end_record(c);
534 }
535
536 if (c->timeout_fired++ == 0)
537 evtimer_add(&c->tmo, &kill_timeout)event_add(&c->tmo, &kill_timeout);
538}
539
540void
541slowcgi_sig_handler(int sig, short event, void *arg)
542{
543 struct request *c;
544 struct slowcgi_proc *p;
545 pid_t pid;
546 int status;
547
548 p = arg;
549
550 switch (sig) {
551 case SIGCHLD20:
552 while ((pid = waitpid(WAIT_ANY(-1), &status, WNOHANG0x01)) > 0) {
553 LIST_FOREACH(c, &p->requests, entry)for((c) = ((&p->requests)->lh_first); (c)!= ((void *
)0); (c) = ((c)->entry.le_next))
554 if (c->command_pid == pid)
555 break;
556 if (c == NULL((void *)0)) {
557 lwarnx("caught exit of unknown child %d", pid)logger->warnx("caught exit of unknown child %d", pid);
558 continue;
559 }
560
561 if (WIFSIGNALED(status)(((status) & 0177) != 0177 && ((status) & 0177
) != 0)
)
562 c->command_status = WTERMSIG(status)(((status) & 0177));
563 else
564 c->command_status = WEXITSTATUS(status)(int)(((unsigned)(status) >> 8) & 0xff);
565
566 ldebug("pid %d exit %s%d", pid,logger->debug("pid %d exit %s%d", pid, (((status) & 0177
) != 0177 && ((status) & 0177) != 0) ? "signal " :
"", c->command_status)
567 WIFSIGNALED(status) ? "signal " : "",logger->debug("pid %d exit %s%d", pid, (((status) & 0177
) != 0177 && ((status) & 0177) != 0) ? "signal " :
"", c->command_status)
568 c->command_status)logger->debug("pid %d exit %s%d", pid, (((status) & 0177
) != 0177 && ((status) & 0177) != 0) ? "signal " :
"", c->command_status)
;
569
570 c->script_flags |= SCRIPT_DONE0x4;
571
572 if (c->script_flags == (STDOUT_DONE0x1 | STDERR_DONE0x2 |
573 SCRIPT_DONE0x4))
574 create_end_record(c);
575 }
576 if (pid == -1 && errno(*__errno()) != ECHILD10)
577 lwarn("waitpid")logger->warn("waitpid");
578 break;
579 default:
580 lerr(1, "unexpected signal: %d", sig)logger->err((1), "unexpected signal: %d", sig);
581 break;
582 }
583}
584
585void
586slowcgi_add_response(struct request *c, struct fcgi_response *resp)
587{
588 struct fcgi_record_header *header;
589 size_t padded_len;
590
591 header = (struct fcgi_record_header*)resp->data;
592
593 /* The FastCGI spec suggests to align the output buffer */
594 padded_len = FCGI_ALIGN(resp->data_len)(((resp->data_len) + (8 - 1)) & ~(8 - 1));
595 if (padded_len > resp->data_len) {
596 /* There should always be FCGI_PADDING_SIZE bytes left */
597 if (padded_len > FCGI_RECORD_SIZE(sizeof(struct fcgi_record_header) + 65535 + 255))
598 lerr(1, "response too long")logger->err((1), "response too long");
599 header->padding_len = padded_len - resp->data_len;
600 resp->data_len = padded_len;
601 }
602
603 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)
;
604 event_add(&c->resp_ev, NULL((void *)0));
605}
606
607void
608slowcgi_response(int fd, short events, void *arg)
609{
610 struct request *c;
611 struct fcgi_record_header *header;
612 struct fcgi_response *resp;
613 ssize_t n;
614
615 c = arg;
616
617 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
618 header = (struct fcgi_record_header*) resp->data;
619 if (debug > 1)
2
Assuming 'debug' is > 1
3
Taking true branch
13
Assuming 'debug' is > 1
14
Taking true branch
620 dump_fcgi_record("resp ", header);
15
Calling 'dump_fcgi_record'
621
622 n = write(fd, resp->data + resp->data_pos, resp->data_len);
623 if (n == -1) {
4
Assuming the condition is false
5
Taking false branch
624 if (errno(*__errno()) == EAGAIN35 || errno(*__errno()) == EINTR4)
625 return;
626 cleanup_request(c);
627 return;
628 }
629 resp->data_pos += n;
630 resp->data_len -= n;
631 if (resp->data_len == 0) {
6
Assuming field 'data_len' is equal to 0
7
Taking true branch
632 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
633 free(resp);
11
Memory is released
634 }
635 }
636
637 if (TAILQ_EMPTY(&c->response_head)(((&c->response_head)->tqh_first) == ((void *)0))) {
638 if (c->request_done)
639 cleanup_request(c);
640 else
641 event_del(&c->resp_ev);
642 }
643}
644
645void
646slowcgi_request(int fd, short events, void *arg)
647{
648 struct request *c;
649 ssize_t n;
650 size_t parsed;
651
652 c = arg;
653
654 n = read(fd, c->buf + c->buf_pos + c->buf_len,
655 FCGI_RECORD_SIZE(sizeof(struct fcgi_record_header) + 65535 + 255) - c->buf_pos-c->buf_len);
656
657 switch (n) {
658 case -1:
659 switch (errno(*__errno())) {
660 case EINTR4:
661 case EAGAIN35:
662 return;
663 default:
664 goto fail;
665 }
666 break;
667
668 case 0:
669 ldebug("closed connection")logger->debug("closed connection");
670 goto fail;
671 default:
672 break;
673 }
674
675 c->buf_len += n;
676
677 /*
678 * Parse the records as they are received. Per the FastCGI
679 * specification, the server need only receive the FastCGI
680 * parameter records in full; it is free to begin execution
681 * at that point, which is what happens here.
682 */
683 do {
684 parsed = parse_record(c->buf + c->buf_pos, c->buf_len, c);
685 c->buf_pos += parsed;
686 c->buf_len -= parsed;
687 } while (parsed > 0 && c->buf_len > 0);
688
689 /* Make space for further reads */
690 if (c->buf_len > 0) {
691 memmove(c->buf, c->buf + c->buf_pos, c->buf_len);
692 c->buf_pos = 0;
693 }
694 return;
695fail:
696 cleanup_request(c);
697}
698
699void
700parse_begin_request(uint8_t *buf, uint16_t n, struct request *c, uint16_t id)
701{
702 /* XXX -- FCGI_CANT_MPX_CONN */
703 if (c->request_started) {
704 lwarnx("unexpected FCGI_BEGIN_REQUEST, ignoring")logger->warnx("unexpected FCGI_BEGIN_REQUEST, ignoring");
705 return;
706 }
707
708 if (n != sizeof(struct fcgi_begin_request_body)) {
709 lwarnx("wrong size %d != %lu", n,logger->warnx("wrong size %d != %lu", n, sizeof(struct fcgi_begin_request_body
))
710 sizeof(struct fcgi_begin_request_body))logger->warnx("wrong size %d != %lu", n, sizeof(struct fcgi_begin_request_body
))
;
711 return;
712 }
713
714 c->request_started = 1;
715
716 c->id = id;
717 SLIST_INIT(&c->env){ ((&c->env)->slh_first) = ((void *)0); };
718 c->env_count = 0;
719}
720
721void
722parse_params(uint8_t *buf, uint16_t n, struct request *c, uint16_t id)
723{
724 struct env_val *env_entry;
725 uint32_t name_len, val_len;
726
727 if (!c->request_started) {
728 lwarnx("FCGI_PARAMS without FCGI_BEGIN_REQUEST, ignoring")logger->warnx("FCGI_PARAMS without FCGI_BEGIN_REQUEST, ignoring"
)
;
729 return;
730 }
731
732 if (c->id != id) {
733 lwarnx("unexpected id, ignoring")logger->warnx("unexpected id, ignoring");
734 return;
735 }
736
737 /*
738 * If this is the last FastCGI parameter record,
739 * begin execution of the CGI script.
740 */
741 if (n == 0) {
742 exec_cgi(c);
743 return;
744 }
745
746 while (n > 0) {
747 if (buf[0] >> 7 == 0) {
748 name_len = buf[0];
749 n--;
750 buf++;
751 } else {
752 if (n > 3) {
753 name_len = ((buf[0] & 0x7f) << 24) +
754 (buf[1] << 16) + (buf[2] << 8) + buf[3];
755 n -= 4;
756 buf += 4;
757 } else
758 return;
759 }
760
761 if (n > 0) {
762 if (buf[0] >> 7 == 0) {
763 val_len = buf[0];
764 n--;
765 buf++;
766 } else {
767 if (n > 3) {
768 val_len = ((buf[0] & 0x7f) << 24) +
769 (buf[1] << 16) + (buf[2] << 8) +
770 buf[3];
771 n -= 4;
772 buf += 4;
773 } else
774 return;
775 }
776 } else
777 return;
778
779 if (n < name_len + val_len)
780 return;
781
782 if ((env_entry = malloc(sizeof(struct env_val))) == NULL((void *)0)) {
783 lwarnx("cannot allocate env_entry")logger->warnx("cannot allocate env_entry");
784 return;
785 }
786
787 if ((env_entry->key = malloc(name_len + 1)) == NULL((void *)0)) {
788 lwarnx("cannot allocate env_entry->key")logger->warnx("cannot allocate env_entry->key");
789 free(env_entry);
790 return;
791 }
792 if ((env_entry->val = malloc(val_len + 1)) == NULL((void *)0)) {
793 lwarnx("cannot allocate env_entry->val")logger->warnx("cannot allocate env_entry->val");
794 free(env_entry->key);
795 free(env_entry);
796 return;
797 }
798
799 memcpy(env_entry->key, buf, name_len);
800 buf += name_len;
801 n -= name_len;
802 env_entry->key[name_len] = '\0';
803 memcpy(env_entry->val, buf, val_len);
804 buf += val_len;
805 n -= val_len;
806 env_entry->val[val_len] = '\0';
807
808 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)
;
809 ldebug("env[%d], %s=%s", c->env_count, env_entry->key,logger->debug("env[%d], %s=%s", c->env_count, env_entry
->key, env_entry->val)
810 env_entry->val)logger->debug("env[%d], %s=%s", c->env_count, env_entry
->key, env_entry->val)
;
811 c->env_count++;
812 }
813}
814
815void
816parse_stdin(uint8_t *buf, uint16_t n, struct request *c, uint16_t id)
817{
818 if (c->id != id) {
819 lwarnx("unexpected id, ignoring")logger->warnx("unexpected id, ignoring");
820 return;
821 }
822
823 if (n != 0)
824 lwarnx("unexpected stdin input, ignoring")logger->warnx("unexpected stdin input, ignoring");
825}
826
827size_t
828parse_record(uint8_t *buf, size_t n, struct request *c)
829{
830 struct fcgi_record_header *h;
831
832 if (n < sizeof(struct fcgi_record_header))
833 return (0);
834
835 h = (struct fcgi_record_header*) buf;
836
837 if (debug > 1)
838 dump_fcgi_record("", h);
839
840 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))
841 + h->padding_len)
842 return (0);
843
844 if (h->version != 1)
845 lerrx(1, "wrong version")logger->errx((1), "wrong version");
846
847 switch (h->type) {
848 case FCGI_BEGIN_REQUEST1:
849 parse_begin_request(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_PARAMS4:
853 parse_params(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 case FCGI_STDIN5:
857 parse_stdin(buf + sizeof(struct fcgi_record_header),
858 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))
);
859 break;
860 default:
861 lwarnx("unimplemented type %d", h->type)logger->warnx("unimplemented type %d", h->type);
862 break;
863 }
864
865 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))
866 + h->padding_len);
867}
868
869char *
870env_get(struct request *c, const char *key)
871{
872 struct env_val *env;
873
874 SLIST_FOREACH(env, &c->env, entry)for((env) = ((&c->env)->slh_first); (env) != ((void
*)0); (env) = ((env)->entry.sle_next))
{
875 if (strcmp(env->key, key) == 0)
876 return (env->val);
877 }
878 return (NULL((void *)0));
879}
880
881static const char *
882http_error(int *res)
883{
884 const struct http_error errors[] = HTTP_ERRORS{ { 100, "Continue" }, { 101, "Switching Protocols" }, { 102,
"Processing" }, { 200, "OK" }, { 201, "Created" }, { 202, "Accepted"
}, { 203, "Non-Authoritative Information" }, { 204, "No Content"
}, { 205, "Reset Content" }, { 206, "Partial Content" }, { 207
, "Multi-Status" }, { 208, "Already Reported" }, { 226, "IM Used"
}, { 300, "Multiple Choices" }, { 301, "Moved Permanently" }
, { 302, "Found" }, { 303, "See Other" }, { 304, "Not Modified"
}, { 305, "Use Proxy" }, { 306, "Switch Proxy" }, { 307, "Temporary Redirect"
}, { 308, "Permanent Redirect" }, { 400, "Bad Request" }, { 401
, "Unauthorized" }, { 402, "Payment Required" }, { 403, "Forbidden"
}, { 404, "Not Found" }, { 405, "Method Not Allowed" }, { 406
, "Not Acceptable" }, { 407, "Proxy Authentication Required" }
, { 408, "Request Timeout" }, { 409, "Conflict" }, { 410, "Gone"
}, { 411, "Length Required" }, { 412, "Precondition Failed" }
, { 413, "Payload Too Large" }, { 414, "URI Too Long" }, { 415
, "Unsupported Media Type" }, { 416, "Range Not Satisfiable" }
, { 417, "Expectation Failed" }, { 418, "I'm a teapot" }, { 420
, "Enhance Your Calm" }, { 422, "Unprocessable Entity" }, { 423
, "Locked" }, { 424, "Failed Dependency" }, { 426, "Upgrade Required"
}, { 428, "Precondition Required" }, { 429, "Too Many Requests"
}, { 431, "Request Header Fields Too Large" }, { 451, "Unavailable For Legal Reasons"
}, { 500, "Internal Server Error" }, { 501, "Not Implemented"
}, { 502, "Bad Gateway" }, { 503, "Service Unavailable" }, {
504, "Gateway Timeout" }, { 505, "HTTP Version Not Supported"
}, { 506, "Variant Also Negotiates" }, { 507, "Insufficient Storage"
}, { 508, "Loop Detected" }, { 510, "Not Extended" }, { 511,
"Network Authentication Required" }, { 0, ((void *)0) } }
;
885 size_t i;
886
887 for (i = 0; errors[i].error_code != 0; i++)
888 if (errors[i].error_code == *res)
889 return errors[i].error_name;
890
891 /* unknown error - change to 500 */
892 lwarnx("unknown http error %d", *res)logger->warnx("unknown http error %d", *res);
893 *res = 500;
894 return "Internal Server Error";
895}
896
897void
898error_response(struct request *c, int res)
899{
900 const char *type = "text/html";
901 const char *errstr = http_error(&res);
902 char *buf;
903 int len;
904
905 lwarnx("HTTP status %d: %s", res, errstr)logger->warnx("HTTP status %d: %s", res, errstr);
906
907 len = asprintf(&buf,
908 "Content-Type: %s\n"
909 "Status: %d\n"
910 "Cache-Control: no-cache\n"
911 "\n"
912 "<!DOCTYPE html>\n"
913 "<html>\n"
914 " <head>\n"
915 " <meta http-equiv=\"Content-Type\" "
916 "content=\"%s; charset=utf-8\"/>\n"
917 " <title>%d %s</title>\n"
918 " </head>\n"
919 " <body>\n"
920 " <h1>%d %s</h1>\n"
921 " <hr>\n"
922 " <address>OpenBSD bgplgd</address>\n"
923 " </body>\n"
924 "</html>\n",
925 type, res, type, res, errstr, res, errstr);
926
927 if (len == -1)
928 lerr(1, NULL)logger->err((1), ((void *)0));
929
930 create_data_record(c, FCGI_STDOUT6, buf, len);
931 free(buf);
932 c->script_flags = (STDOUT_DONE0x1 | STDERR_DONE0x2 | SCRIPT_DONE0x4);
933 create_end_record(c);
934}
935
936/*
937 * Fork a new CGI process to handle the request, translating
938 * between FastCGI parameter records and CGI's environment variables,
939 * as well as between the CGI process' stdin/stdout and the
940 * corresponding FastCGI records.
941 */
942void
943exec_cgi(struct request *c)
944{
945 struct lg_ctx ctx = { 0 };
946 int s_in[2], s_out[2], s_err[2], res;
947 pid_t pid;
948
949 res = prep_request(&ctx, env_get(c, "REQUEST_METHOD"),
950 env_get(c, "PATH_INFO"), env_get(c, "QUERY_STRING"));
951 if (res != 0) {
952 error_response(c, res);
953 return;
954 }
955
956 if (pipe(s_in) == -1)
957 lerr(1, "pipe")logger->err((1), "pipe");
958 if (pipe(s_out) == -1)
959 lerr(1, "pipe")logger->err((1), "pipe");
960 if (pipe(s_err) == -1)
961 lerr(1, "pipe")logger->err((1), "pipe");
962 cgi_inflight--;
963 c->inflight_fds_accounted = 1;
964
965 switch (pid = fork()) {
966 case -1:
967 c->command_status = errno(*__errno());
968
969 lwarn("fork")logger->warn("fork");
970
971 close(s_in[0]);
972 close(s_out[0]);
973 close(s_err[0]);
974
975 close(s_in[1]);
976 close(s_out[1]);
977 close(s_err[1]);
978
979 c->script_flags = (STDOUT_DONE0x1 | STDERR_DONE0x2 | SCRIPT_DONE0x4);
980 create_end_record(c);
981 return;
982 case 0:
983 /* Child process */
984 if (pledge("stdio rpath exec", NULL((void *)0)) == -1)
985 lerr(1, "pledge")logger->err((1), "pledge");
986 close(s_in[0]);
987 close(s_out[0]);
988 close(s_err[0]);
989
990 if (dup2(s_in[1], STDIN_FILENO0) == -1)
991 _exit(1);
992 if (dup2(s_out[1], STDOUT_FILENO1) == -1)
993 _exit(1);
994 if (dup2(s_err[1], STDERR_FILENO2) == -1)
995 _exit(1);
996
997 close(s_in[1]);
998 close(s_out[1]);
999 close(s_err[1]);
1000
1001 bgpctl_call(&ctx);
1002
1003 /* should not be reached */
1004 _exit(1);
1005
1006 }
1007
1008 ldebug("fork %d", pid)logger->debug("fork %d", pid);
1009
1010 /* Parent process*/
1011 close(s_in[1]);
1012 close(s_out[1]);
1013 close(s_err[1]);
1014
1015 fcntl(s_in[0], F_SETFD2, FD_CLOEXEC1);
1016 fcntl(s_out[0], F_SETFD2, FD_CLOEXEC1);
1017 fcntl(s_err[0], F_SETFD2, FD_CLOEXEC1);
1018
1019 if (ioctl(s_in[0], FIONBIO((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((126)))
, &on) == -1)
1020 lerr(1, "script ioctl(FIONBIO)")logger->err((1), "script ioctl(FIONBIO)");
1021 if (ioctl(s_out[0], FIONBIO((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((126)))
, &on) == -1)
1022 lerr(1, "script ioctl(FIONBIO)")logger->err((1), "script ioctl(FIONBIO)");
1023 if (ioctl(s_err[0], FIONBIO((unsigned long)0x80000000 | ((sizeof(int) & 0x1fff) <<
16) | ((('f')) << 8) | ((126)))
, &on) == -1)
1024 lerr(1, "script ioctl(FIONBIO)")logger->err((1), "script ioctl(FIONBIO)");
1025
1026 close(s_in[0]); /* close stdin, bgpctl does not expect anything */
1027
1028 c->command_pid = pid;
1029 event_set(&c->script_ev, s_out[0], EV_READ0x02 | EV_PERSIST0x10,
1030 script_std_in, c);
1031 event_add(&c->script_ev, NULL((void *)0));
1032 event_set(&c->script_err_ev, s_err[0], EV_READ0x02 | EV_PERSIST0x10,
1033 script_err_in, c);
1034 event_add(&c->script_err_ev, NULL((void *)0));
1035}
1036
1037static void
1038script_in(int fd, struct event *ev, struct request *c, uint8_t type)
1039{
1040 struct fcgi_response *resp;
1041 struct fcgi_record_header *header;
1042 ssize_t n;
1043
1044 if ((resp = calloc(1, sizeof(struct fcgi_response))) == NULL((void *)0)) {
1045 lwarnx("cannot malloc fcgi_response")logger->warnx("cannot malloc fcgi_response");
1046 return;
1047 }
1048 header = (struct fcgi_record_header*) resp->data;
1049 header->version = 1;
1050 header->type = type;
1051 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))
;
1052 header->padding_len = 0;
1053 header->reserved = 0;
1054
1055 n = read(fd, resp->data + sizeof(struct fcgi_record_header),
1056 FCGI_CONTENT_SIZE65535);
1057
1058 if (n == -1) {
1059 switch (errno(*__errno())) {
1060 case EINTR4:
1061 case EAGAIN35:
1062 free(resp);
1063 return;
1064 default:
1065 n = 0; /* fake empty FCGI_STD{OUT,ERR} response */
1066 }
1067 }
1068 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))
;
1069 resp->data_pos = 0;
1070 resp->data_len = n + sizeof(struct fcgi_record_header);
1071 slowcgi_add_response(c, resp);
1072
1073 if (n == 0) {
1074 if (type == FCGI_STDOUT6)
1075 c->script_flags |= STDOUT_DONE0x1;
1076 else
1077 c->script_flags |= STDERR_DONE0x2;
1078
1079 if (c->script_flags == (STDOUT_DONE0x1 | STDERR_DONE0x2 |
1080 SCRIPT_DONE0x4))
1081 create_end_record(c);
1082 event_del(ev);
1083 close(fd);
1084 }
1085}
1086
1087void
1088script_std_in(int fd, short events, void *arg)
1089{
1090 struct request *c = arg;
1091 script_in(fd, &c->script_ev, c, FCGI_STDOUT6);
1092}
1093
1094void
1095script_err_in(int fd, short events, void *arg)
1096{
1097 struct request *c = arg;
1098 script_in(fd, &c->script_err_ev, c, FCGI_STDERR7);
1099}
1100
1101void
1102create_data_record(struct request *c, uint8_t type, const void *buf, size_t len)
1103{
1104 struct fcgi_response *resp;
1105 struct fcgi_record_header *header;
1106 const char *d = buf;
1107 size_t n;
1108
1109 do {
1110 if ((resp = calloc(1, sizeof(struct fcgi_response))) == NULL((void *)0)) {
1111 lwarnx("cannot malloc fcgi_response")logger->warnx("cannot malloc fcgi_response");
1112 return;
1113 }
1114 header = (struct fcgi_record_header*) resp->data;
1115 header->version = 1;
1116 header->type = type;
1117 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))
;
1118 header->padding_len = 0;
1119 header->reserved = 0;
1120
1121 n = len > FCGI_CONTENT_SIZE65535 ? FCGI_CONTENT_SIZE65535 : len;
1122 memcpy(resp->data + sizeof(struct fcgi_record_header), d, n);
1123
1124 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))
;
1125 resp->data_pos = 0;
1126 resp->data_len = n + sizeof(struct fcgi_record_header);
1127 slowcgi_add_response(c, resp);
1128
1129 len -= n;
1130 d += n;
1131 } while (len > 0);
1132}
1133
1134void
1135create_end_record(struct request *c)
1136{
1137 struct fcgi_response *resp;
1138 struct fcgi_record_header *header;
1139 struct fcgi_end_request_body *end_request;
1140
1141 if ((resp = calloc(1, sizeof(struct fcgi_response))) == NULL((void *)0)) {
1142 lwarnx("cannot malloc fcgi_response")logger->warnx("cannot malloc fcgi_response");
1143 return;
1144 }
1145 header = (struct fcgi_record_header*) resp->data;
1146 header->version = 1;
1147 header->type = FCGI_END_REQUEST3;
1148 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))
;
1149 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
)))
1150 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
)))
;
1151 header->padding_len = 0;
1152 header->reserved = 0;
1153 end_request = (struct fcgi_end_request_body *) (resp->data +
1154 sizeof(struct fcgi_record_header));
1155 end_request->app_status = htonl(c->command_status)(__uint32_t)(__builtin_constant_p(c->command_status) ? (__uint32_t
)(((__uint32_t)(c->command_status) & 0xff) << 24
| ((__uint32_t)(c->command_status) & 0xff00) <<
8 | ((__uint32_t)(c->command_status) & 0xff0000) >>
8 | ((__uint32_t)(c->command_status) & 0xff000000) >>
24) : __swap32md(c->command_status))
;
1156 end_request->protocol_status = FCGI_REQUEST_COMPLETE0;
1157 end_request->reserved[0] = 0;
1158 end_request->reserved[1] = 0;
1159 end_request->reserved[2] = 0;
1160 resp->data_pos = 0;
1161 resp->data_len = sizeof(struct fcgi_end_request_body) +
1162 sizeof(struct fcgi_record_header);
1163 slowcgi_add_response(c, resp);
1164 c->request_done = 1;
1165}
1166
1167void
1168cleanup_request(struct request *c)
1169{
1170 struct fcgi_response *resp;
1171 struct env_val *env_entry;
1172
1173 evtimer_del(&c->tmo)event_del(&c->tmo);
1174 if (event_initialized(&c->ev)((&c->ev)->ev_flags & 0x80))
1175 event_del(&c->ev);
1176 if (event_initialized(&c->resp_ev)((&c->resp_ev)->ev_flags & 0x80))
1177 event_del(&c->resp_ev);
1178 if (event_initialized(&c->script_ev)((&c->script_ev)->ev_flags & 0x80)) {
1179 close(EVENT_FD(&c->script_ev)(int)(&c->script_ev)->ev_fd);
1180 event_del(&c->script_ev);
1181 }
1182 if (event_initialized(&c->script_err_ev)((&c->script_err_ev)->ev_flags & 0x80)) {
1183 close(EVENT_FD(&c->script_err_ev)(int)(&c->script_err_ev)->ev_fd);
1184 event_del(&c->script_err_ev);
1185 }
1186
1187 close(c->fd);
1188 while (!SLIST_EMPTY(&c->env)(((&c->env)->slh_first) == ((void *)0))) {
1189 env_entry = SLIST_FIRST(&c->env)((&c->env)->slh_first);
1190 SLIST_REMOVE_HEAD(&c->env, entry)do { (&c->env)->slh_first = (&c->env)->slh_first
->entry.sle_next; } while (0)
;
1191 free(env_entry->key);
1192 free(env_entry->val);
1193 free(env_entry);
1194 }
1195
1196 while ((resp = TAILQ_FIRST(&c->response_head)((&c->response_head)->tqh_first))) {
1197 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)
;
1198 free(resp);
1199 }
1200 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)
;
1201 if (! c->inflight_fds_accounted)
1202 cgi_inflight--;
1203 free(c);
1204}
1205
1206void
1207dump_fcgi_record(const char *p, struct fcgi_record_header *h)
1208{
1209 dump_fcgi_record_header(p, h);
16
Calling 'dump_fcgi_record_header'
1210
1211 if (h->type == FCGI_BEGIN_REQUEST1)
1212 dump_fcgi_begin_request_body(p,
1213 (struct fcgi_begin_request_body *)(h + 1));
1214 else if (h->type == FCGI_END_REQUEST3)
1215 dump_fcgi_end_request_body(p,
1216 (struct fcgi_end_request_body *)(h + 1));
1217}
1218
1219void
1220dump_fcgi_record_header(const char* p, struct fcgi_record_header *h)
1221{
1222 ldebug("%sversion: %d", p, h->version)logger->debug("%sversion: %d", p, h->version);
17
Use of memory after it is freed
1223 ldebug("%stype: %d", p, h->type)logger->debug("%stype: %d", p, h->type);
1224 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)))
;
1225 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)))
;
1226 ldebug("%spaddingLength: %d", p, h->padding_len)logger->debug("%spaddingLength: %d", p, h->padding_len
)
;
1227 ldebug("%sreserved: %d", p, h->reserved)logger->debug("%sreserved: %d", p, h->reserved);
1228}
1229
1230void
1231dump_fcgi_begin_request_body(const char *p, struct fcgi_begin_request_body *b)
1232{
1233 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)))
;
1234 ldebug("%sflags %d", p, b->flags)logger->debug("%sflags %d", p, b->flags);
1235}
1236
1237void
1238dump_fcgi_end_request_body(const char *p, struct fcgi_end_request_body *b)
1239{
1240 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)))
;
1241 ldebug("%sprotocolStatus: %d", p, b->protocol_status)logger->debug("%sprotocolStatus: %d", p, b->protocol_status
)
;
1242}
1243
1244void
1245syslog_vstrerror(int e, int priority, const char *fmt, va_list ap)
1246{
1247 char *s;
1248
1249 if (vasprintf(&s, fmt, ap) == -1) {
1250 syslog(LOG_EMERG0, "unable to alloc in syslog_vstrerror");
1251 exit(1);
1252 }
1253 syslog(priority, "%s: %s", s, strerror(e));
1254 free(s);
1255}
1256
1257__dead__attribute__((__noreturn__)) void
1258syslog_err(int ecode, const char *fmt, ...)
1259{
1260 va_list ap;
1261
1262 va_start(ap, fmt)__builtin_va_start((ap), fmt);
1263 syslog_vstrerror(errno(*__errno()), LOG_CRIT2, fmt, ap);
1264 va_end(ap)__builtin_va_end((ap));
1265 exit(ecode);
1266}
1267
1268__dead__attribute__((__noreturn__)) void
1269syslog_errx(int ecode, const char *fmt, ...)
1270{
1271 va_list ap;
1272
1273 va_start(ap, fmt)__builtin_va_start((ap), fmt);
1274 vsyslog(LOG_CRIT2, fmt, ap);
1275 va_end(ap)__builtin_va_end((ap));
1276 exit(ecode);
1277}
1278
1279void
1280syslog_warn(const char *fmt, ...)
1281{
1282 va_list ap;
1283
1284 va_start(ap, fmt)__builtin_va_start((ap), fmt);
1285 syslog_vstrerror(errno(*__errno()), LOG_ERR3, fmt, ap);
1286 va_end(ap)__builtin_va_end((ap));
1287}
1288
1289void
1290syslog_warnx(const char *fmt, ...)
1291{
1292 va_list ap;
1293
1294 va_start(ap, fmt)__builtin_va_start((ap), fmt);
1295 vsyslog(LOG_ERR3, fmt, ap);
1296 va_end(ap)__builtin_va_end((ap));
1297}
1298
1299void
1300syslog_info(const char *fmt, ...)
1301{
1302 va_list ap;
1303
1304 va_start(ap, fmt)__builtin_va_start((ap), fmt);
1305 vsyslog(LOG_INFO6, fmt, ap);
1306 va_end(ap)__builtin_va_end((ap));
1307}
1308
1309void
1310syslog_debug(const char *fmt, ...)
1311{
1312 va_list ap;
1313
1314 va_start(ap, fmt)__builtin_va_start((ap), fmt);
1315 vsyslog(LOG_DEBUG7, fmt, ap);
1316 va_end(ap)__builtin_va_end((ap));
1317}