xref: /openbsd-src/usr.sbin/bgplgd/slowcgi.c (revision fc405d53b73a2d73393cb97f684863d17b583e38)
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.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_DEFAULT		 30
49 #define WWW_USER		 "www"
50 #define BGPLGD_USER		 "_bgplgd"
51 
52 #define FCGI_CONTENT_SIZE	 65535
53 #define FCGI_PADDING_SIZE	 255
54 #define FCGI_RECORD_SIZE	 \
55     (sizeof(struct fcgi_record_header) + FCGI_CONTENT_SIZE + FCGI_PADDING_SIZE)
56 
57 #define FCGI_ALIGNMENT		 8
58 #define FCGI_ALIGN(n)		 \
59     (((n) + (FCGI_ALIGNMENT - 1)) & ~(FCGI_ALIGNMENT - 1))
60 
61 #define STDOUT_DONE		0x1
62 #define STDERR_DONE		0x2
63 #define SCRIPT_DONE		0x4
64 
65 #define FCGI_REQUEST_COMPLETE	0
66 #define FCGI_CANT_MPX_CONN	1
67 #define FCGI_OVERLOADED		2
68 #define FCGI_UNKNOWN_ROLE	3
69 
70 #define FD_RESERVE		5
71 #define FD_NEEDED		6
72 int cgi_inflight = 0;
73 
74 struct listener {
75 	struct event	ev, pause;
76 };
77 
78 struct env_val {
79 	SLIST_ENTRY(env_val)	 entry;
80 	char			*key;
81 	char			*val;
82 };
83 SLIST_HEAD(env_head, env_val);
84 
85 struct 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;
93 
94 struct fcgi_response {
95 	TAILQ_ENTRY(fcgi_response)	entry;
96 	uint8_t				data[FCGI_RECORD_SIZE];
97 	size_t				data_pos;
98 	size_t				data_len;
99 };
100 TAILQ_HEAD(fcgi_response_head, fcgi_response);
101 
102 struct request {
103 	LIST_ENTRY(request)		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];
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 
126 LIST_HEAD(requests_head, request);
127 
128 struct slowcgi_proc {
129 	struct requests_head	requests;
130 	struct event		ev_sigchld;
131 };
132 
133 struct fcgi_begin_request_body {
134 	uint16_t	role;
135 	uint8_t		flags;
136 	uint8_t		reserved[5];
137 }__packed;
138 
139 struct fcgi_end_request_body {
140 	uint32_t	app_status;
141 	uint8_t		protocol_status;
142 	uint8_t		reserved[3];
143 }__packed;
144 
145 __dead void	usage(void);
146 int		slowcgi_listen(char *, struct passwd *);
147 void		slowcgi_paused(int, short, void *);
148 int		accept_reserve(int, struct sockaddr *, socklen_t *, int,
149 		    volatile int *);
150 void		slowcgi_accept(int, short, void *);
151 void		slowcgi_request(int, short, void *);
152 void		slowcgi_response(int, short, void *);
153 void		slowcgi_add_response(struct request *, struct fcgi_response *);
154 void		slowcgi_timeout(int, short, void *);
155 void		slowcgi_sig_handler(int, short, void *);
156 size_t		parse_record(uint8_t * , size_t, struct request *);
157 void		parse_begin_request(uint8_t *, uint16_t, struct request *,
158 		    uint16_t);
159 void		parse_params(uint8_t *, uint16_t, struct request *, uint16_t);
160 void		parse_stdin(uint8_t *, uint16_t, struct request *, uint16_t);
161 char		*env_get(struct request *, const char *);
162 void		error_response(struct request *, int);
163 void		exec_cgi(struct request *);
164 void		script_std_in(int, short, void *);
165 void		script_err_in(int, short, void *);
166 void		create_data_record(struct request *, uint8_t, const void *,
167 		    size_t);
168 void		create_end_record(struct request *);
169 void		cleanup_request(struct request *);
170 void		dump_fcgi_record(const char *,
171 		    struct fcgi_record_header *);
172 void		dump_fcgi_record_header(const char *,
173 		    struct fcgi_record_header *);
174 void		dump_fcgi_begin_request_body(const char *,
175 		    struct fcgi_begin_request_body *);
176 void		dump_fcgi_end_request_body(const char *,
177 		    struct fcgi_end_request_body *);
178 
179 const struct loggers conslogger = {
180 	err,
181 	errx,
182 	warn,
183 	warnx,
184 	warnx, /* info */
185 	warnx /* debug */
186 };
187 
188 __dead void	syslog_err(int, const char *, ...)
189 		    __attribute__((__format__ (printf, 2, 3)));
190 __dead void	syslog_errx(int, const char *, ...)
191 		    __attribute__((__format__ (printf, 2, 3)));
192 void		syslog_warn(const char *, ...)
193 		    __attribute__((__format__ (printf, 1, 2)));
194 void		syslog_warnx(const char *, ...)
195 		    __attribute__((__format__ (printf, 1, 2)));
196 void		syslog_info(const char *, ...)
197 		    __attribute__((__format__ (printf, 1, 2)));
198 void		syslog_debug(const char *, ...)
199 		    __attribute__((__format__ (printf, 1, 2)));
200 void		syslog_vstrerror(int, int, const char *, va_list)
201 		    __attribute__((__format__ (printf, 3, 0)));
202 
203 const struct loggers syslogger = {
204 	syslog_err,
205 	syslog_errx,
206 	syslog_warn,
207 	syslog_warnx,
208 	syslog_info,
209 	syslog_debug
210 };
211 
212 const struct loggers *logger = &conslogger;
213 
214 __dead void
215 usage(void)
216 {
217 	extern char *__progname;
218 	fprintf(stderr,
219 	    "usage: %s [-d] [-p path] [-S socket] [-s socket] [-U user]\n",
220 	    __progname);
221 	exit(1);
222 }
223 
224 struct timeval		timeout = { TIMEOUT_DEFAULT, 0 };
225 struct timeval		kill_timeout = { 5, 0 };
226 struct slowcgi_proc	slowcgi_proc;
227 int			debug = 0;
228 int			on = 1;
229 char			*fcgi_socket = "/var/www/run/bgplgd.sock";
230 char			*bgpctlpath = "bgpctl";
231 char			*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  */
240 static void
241 unveil_command(const char *prog)
242 {
243 	const char *pp;
244 	char *save, *cmd, *path;
245 	struct stat st;
246 
247 	if (strchr(prog, '/') != NULL) {
248 		if (unveil(prog, "x") == -1)
249 			err(1, "%s: unveil", prog);
250 		return;
251 	}
252 
253 	if (getenv("PATH") == NULL)
254 		lerrx(1, "PATH is unset");
255 	if ((path = strdup(getenv("PATH"))) == NULL)
256 		lerr(1, NULL);
257 	save = path;
258 	while ((pp = strsep(&path, ":")) != NULL) {
259 		if (*pp == '\0')
260 			continue;
261 		if (asprintf(&cmd, "%s/%s", pp, prog) == -1)
262 			lerr(1, NULL);
263 		if (lstat(cmd, &st) == -1) {
264 			free(cmd);
265 			continue;
266 		}
267 		if (unveil(cmd, "x") == -1)
268 			lerr(1, "%s: unveil", cmd);
269 		free(cmd);
270 		break;
271 	}
272 	free(save);
273 }
274 
275 int
276 main(int argc, char *argv[])
277 {
278 	extern char *__progname;
279 	struct listener	*l = NULL;
280 	struct passwd	*pw;
281 	struct stat	 sb;
282 	int		 c, fd;
283 	const char	*sock_user = WWW_USER;
284 	const char	*cgi_user = BGPLGD_USER;
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_RDWR)) != -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_PID|LOG_NDELAY, LOG_DAEMON);
334 		logger = &syslogger;
335 	}
336 
337 	ldebug("sock_user: %s", sock_user);
338 	pw = getpwnam(sock_user);
339 	if (pw == NULL)
340 		lerrx(1, "no %s user", sock_user);
341 
342 	fd = slowcgi_listen(fcgi_socket, pw);
343 
344 	ldebug("cgi_user: %s", cgi_user);
345 	pw = getpwnam(cgi_user);
346 	if (pw == NULL)
347 		lerrx(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");
353 
354 	unveil_command(bgpctlpath);
355 
356 	if (pledge("stdio rpath unix proc exec", NULL) == -1)
357 		lerr(1, "pledge");
358 
359 	LIST_INIT(&slowcgi_proc.requests);
360 	event_init();
361 
362 	l = calloc(1, sizeof(*l));
363 	if (l == NULL)
364 		lerr(1, "listener ev alloc");
365 
366 	event_set(&l->ev, fd, EV_READ | EV_PERSIST, slowcgi_accept, l);
367 	event_add(&l->ev, NULL);
368 	evtimer_set(&l->pause, slowcgi_paused, l);
369 
370 	signal_set(&slowcgi_proc.ev_sigchld, SIGCHLD, slowcgi_sig_handler,
371 	    &slowcgi_proc);
372 	signal_add(&slowcgi_proc.ev_sigchld, NULL);
373 
374 	signal(SIGPIPE, SIG_IGN);
375 
376 	event_dispatch();
377 	return (0);
378 }
379 
380 int
381 slowcgi_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_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
388 	    0)) == -1)
389 		lerr(1, "slowcgi_listen: socket");
390 
391 	memset(&sun, 0, sizeof(sun));
392 	sun.sun_family = AF_UNIX;
393 	if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
394 	    sizeof(sun.sun_path))
395 		lerrx(1, "socket path too long");
396 
397 	if (unlink(path) == -1)
398 		if (errno != ENOENT)
399 			lerr(1, "slowcgi_listen: unlink %s", path);
400 
401 	old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
402 
403 	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
404 		lerr(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);
410 
411 	if (listen(fd, 5) == -1)
412 		lerr(1, "listen");
413 
414 	ldebug("socket: %s", path);
415 	return fd;
416 }
417 
418 void
419 slowcgi_paused(int fd, short events, void *arg)
420 {
421 	struct listener	*l = arg;
422 	event_add(&l->ev, NULL);
423 }
424 
425 int
426 accept_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_NEEDED) >= getdtablesize()) {
432 		ldebug("inflight fds exceeded");
433 		errno = EMFILE;
434 		return -1;
435 	}
436 
437 	if ((ret = accept4(sockfd, addr, addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC))
438 	    > -1) {
439 		(*counter)++;
440 		ldebug("inflight incremented, now %d", *counter);
441 	}
442 	return ret;
443 }
444 
445 void
446 slowcgi_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;
459 
460 	len = sizeof(ss);
461 	if ((s = accept_reserve(fd, (struct sockaddr *)&ss,
462 	    &len, FD_RESERVE, &cgi_inflight)) == -1) {
463 		switch (errno) {
464 		case EINTR:
465 		case EWOULDBLOCK:
466 		case ECONNABORTED:
467 			return;
468 		case EMFILE:
469 		case ENFILE:
470 			event_del(&l->ev);
471 			evtimer_add(&l->pause, &backoff);
472 			return;
473 		default:
474 			lerr(1, "accept");
475 		}
476 	}
477 
478 	c = calloc(1, sizeof(*c));
479 	if (c == NULL) {
480 		lwarn("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);
491 
492 	event_set(&c->ev, s, EV_READ | EV_PERSIST, slowcgi_request, c);
493 	event_add(&c->ev, NULL);
494 	event_set(&c->resp_ev, s, EV_WRITE | EV_PERSIST, slowcgi_response, c);
495 	evtimer_set(&c->tmo, slowcgi_timeout, c);
496 	evtimer_add(&c->tmo, &timeout);
497 	LIST_INSERT_HEAD(&slowcgi_proc.requests, c, entry);
498 }
499 
500 void
501 slowcgi_timeout(int fd, short events, void *arg)
502 {
503 	struct request	*c = arg;
504 	int sig = SIGTERM;
505 
506 	if (c->script_flags & SCRIPT_DONE)
507 		return;
508 
509 	if (c->command_pid == 0) {
510 		c->command_status = SIGALRM;
511 		error_response(c, 408);
512 		return;
513 	}
514 
515 	ldebug("timeout fired for pid %d", c->command_pid);
516 
517 	if (c->timeout_fired)
518 		sig = SIGKILL;
519 
520 	if (kill(c->command_pid, sig) == -1) {
521 		lwarn("kill child %d after timeout", c->command_pid);
522 		if (event_initialized(&c->script_ev)) {
523 			close(EVENT_FD(&c->script_ev));
524 			event_del(&c->script_ev);
525 		}
526 		if (event_initialized(&c->script_err_ev)) {
527 			close(EVENT_FD(&c->script_err_ev));
528 			event_del(&c->script_err_ev);
529 		}
530 
531 		c->command_status = SIGALRM;
532 		c->script_flags = STDOUT_DONE | STDERR_DONE | SCRIPT_DONE;
533 		create_end_record(c);
534 	}
535 
536 	if (c->timeout_fired++ == 0)
537 		evtimer_add(&c->tmo, &kill_timeout);
538 }
539 
540 void
541 slowcgi_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 SIGCHLD:
552 		while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0) {
553 			LIST_FOREACH(c, &p->requests, entry)
554 				if (c->command_pid == pid)
555 					break;
556 			if (c == NULL) {
557 				lwarnx("caught exit of unknown child %d", pid);
558 				continue;
559 			}
560 
561 			if (WIFSIGNALED(status))
562 				c->command_status = WTERMSIG(status);
563 			else
564 				c->command_status = WEXITSTATUS(status);
565 
566 			ldebug("pid %d exit %s%d", pid,
567 			    WIFSIGNALED(status) ? "signal " : "",
568 			    c->command_status);
569 
570 			c->script_flags |= SCRIPT_DONE;
571 
572 			if (c->script_flags == (STDOUT_DONE | STDERR_DONE |
573 			    SCRIPT_DONE))
574 				create_end_record(c);
575 		}
576 		if (pid == -1 && errno != ECHILD)
577 			lwarn("waitpid");
578 		break;
579 	default:
580 		lerr(1, "unexpected signal: %d", sig);
581 		break;
582 	}
583 }
584 
585 void
586 slowcgi_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);
595 	if (padded_len > resp->data_len) {
596 		/* There should always be FCGI_PADDING_SIZE bytes left */
597 		if (padded_len > FCGI_RECORD_SIZE)
598 			lerr(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);
604 	event_add(&c->resp_ev, NULL);
605 }
606 
607 void
608 slowcgi_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))) {
618 		header = (struct fcgi_record_header*) resp->data;
619 		if (debug > 1)
620 			dump_fcgi_record("resp ", header);
621 
622 		n = write(fd, resp->data + resp->data_pos, resp->data_len);
623 		if (n == -1) {
624 			if (errno == EAGAIN || errno == EINTR)
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) {
632 			TAILQ_REMOVE(&c->response_head, resp, entry);
633 			free(resp);
634 		}
635 	}
636 
637 	if (TAILQ_EMPTY(&c->response_head)) {
638 		if (c->request_done)
639 			cleanup_request(c);
640 		else
641 			event_del(&c->resp_ev);
642 	}
643 }
644 
645 void
646 slowcgi_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 - c->buf_pos-c->buf_len);
656 
657 	switch (n) {
658 	case -1:
659 		switch (errno) {
660 		case EINTR:
661 		case EAGAIN:
662 			return;
663 		default:
664 			goto fail;
665 		}
666 		break;
667 
668 	case 0:
669 		ldebug("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;
695 fail:
696 	cleanup_request(c);
697 }
698 
699 void
700 parse_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");
705 		return;
706 	}
707 
708 	if (n != sizeof(struct fcgi_begin_request_body)) {
709 		lwarnx("wrong size %d != %lu", n,
710 		    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);
718 	c->env_count = 0;
719 }
720 
721 void
722 parse_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");
729 		return;
730 	}
731 
732 	if (c->id != id) {
733 		lwarnx("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) {
783 			lwarnx("cannot allocate env_entry");
784 			return;
785 		}
786 
787 		if ((env_entry->key = malloc(name_len + 1)) == NULL) {
788 			lwarnx("cannot allocate env_entry->key");
789 			free(env_entry);
790 			return;
791 		}
792 		if ((env_entry->val = malloc(val_len + 1)) == NULL) {
793 			lwarnx("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);
809 		ldebug("env[%d], %s=%s", c->env_count, env_entry->key,
810 		    env_entry->val);
811 		c->env_count++;
812 	}
813 }
814 
815 void
816 parse_stdin(uint8_t *buf, uint16_t n, struct request *c, uint16_t id)
817 {
818 	if (c->id != id) {
819 		lwarnx("unexpected id, ignoring");
820 		return;
821 	}
822 
823 	if (n != 0)
824 		lwarnx("unexpected stdin input, ignoring");
825 }
826 
827 size_t
828 parse_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)
841 	    + h->padding_len)
842 		return (0);
843 
844 	if (h->version != 1)
845 		lerrx(1, "wrong version");
846 
847 	switch (h->type) {
848 	case FCGI_BEGIN_REQUEST:
849 		parse_begin_request(buf + sizeof(struct fcgi_record_header),
850 		    ntohs(h->content_len), c, ntohs(h->id));
851 		break;
852 	case FCGI_PARAMS:
853 		parse_params(buf + sizeof(struct fcgi_record_header),
854 		    ntohs(h->content_len), c, ntohs(h->id));
855 		break;
856 	case FCGI_STDIN:
857 		parse_stdin(buf + sizeof(struct fcgi_record_header),
858 		    ntohs(h->content_len), c, ntohs(h->id));
859 		break;
860 	default:
861 		lwarnx("unimplemented type %d", h->type);
862 		break;
863 	}
864 
865 	return (sizeof(struct fcgi_record_header) + ntohs(h->content_len)
866 	    + h->padding_len);
867 }
868 
869 char *
870 env_get(struct request *c, const char *key)
871 {
872 	struct env_val	*env;
873 
874 	SLIST_FOREACH(env, &c->env, entry) {
875 		if (strcmp(env->key, key) == 0)
876 			return (env->val);
877 	}
878 	return (NULL);
879 }
880 
881 static const char *
882 http_error(int *res)
883 {
884 	const struct http_error errors[] = HTTP_ERRORS;
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);
893 	*res = 500;
894 	return "Internal Server Error";
895 }
896 
897 void
898 error_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);
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);
929 
930 	create_data_record(c, FCGI_STDOUT, buf, len);
931 	free(buf);
932 	c->script_flags = (STDOUT_DONE | STDERR_DONE | SCRIPT_DONE);
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  */
942 void
943 exec_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");
958 	if (pipe(s_out) == -1)
959 		lerr(1, "pipe");
960 	if (pipe(s_err) == -1)
961 		lerr(1, "pipe");
962 	cgi_inflight--;
963 	c->inflight_fds_accounted = 1;
964 
965 	switch (pid = fork()) {
966 	case -1:
967 		c->command_status = errno;
968 
969 		lwarn("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_DONE | STDERR_DONE | SCRIPT_DONE);
980 		create_end_record(c);
981 		return;
982 	case 0:
983 		/* Child process */
984 		if (pledge("stdio rpath exec", NULL) == -1)
985 			lerr(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_FILENO) == -1)
991 			_exit(1);
992 		if (dup2(s_out[1], STDOUT_FILENO) == -1)
993 			_exit(1);
994 		if (dup2(s_err[1], STDERR_FILENO) == -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);
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_SETFD, FD_CLOEXEC);
1016 	fcntl(s_out[0], F_SETFD, FD_CLOEXEC);
1017 	fcntl(s_err[0], F_SETFD, FD_CLOEXEC);
1018 
1019 	if (ioctl(s_in[0], FIONBIO, &on) == -1)
1020 		lerr(1, "script ioctl(FIONBIO)");
1021 	if (ioctl(s_out[0], FIONBIO, &on) == -1)
1022 		lerr(1, "script ioctl(FIONBIO)");
1023 	if (ioctl(s_err[0], FIONBIO, &on) == -1)
1024 		lerr(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_READ | EV_PERSIST,
1030 	    script_std_in, c);
1031 	event_add(&c->script_ev, NULL);
1032 	event_set(&c->script_err_ev, s_err[0], EV_READ | EV_PERSIST,
1033 	    script_err_in, c);
1034 	event_add(&c->script_err_ev, NULL);
1035 }
1036 
1037 static void
1038 script_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) {
1045 		lwarnx("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);
1052 	header->padding_len = 0;
1053 	header->reserved = 0;
1054 
1055 	n = read(fd, resp->data + sizeof(struct fcgi_record_header),
1056 	    FCGI_CONTENT_SIZE);
1057 
1058 	if (n == -1) {
1059 		switch (errno) {
1060 		case EINTR:
1061 		case EAGAIN:
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);
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_STDOUT)
1075 			c->script_flags |= STDOUT_DONE;
1076 		else
1077 			c->script_flags |= STDERR_DONE;
1078 
1079 		if (c->script_flags == (STDOUT_DONE | STDERR_DONE |
1080 		    SCRIPT_DONE))
1081 			create_end_record(c);
1082 		event_del(ev);
1083 		close(fd);
1084 	}
1085 }
1086 
1087 void
1088 script_std_in(int fd, short events, void *arg)
1089 {
1090 	struct request *c = arg;
1091 	script_in(fd, &c->script_ev, c, FCGI_STDOUT);
1092 }
1093 
1094 void
1095 script_err_in(int fd, short events, void *arg)
1096 {
1097 	struct request *c = arg;
1098 	script_in(fd, &c->script_err_ev, c, FCGI_STDERR);
1099 }
1100 
1101 void
1102 create_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) {
1111 			lwarnx("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);
1118 		header->padding_len = 0;
1119 		header->reserved = 0;
1120 
1121 		n = len > FCGI_CONTENT_SIZE ? FCGI_CONTENT_SIZE : len;
1122 		memcpy(resp->data + sizeof(struct fcgi_record_header), d, n);
1123 
1124 		header->content_len = htons(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 
1134 void
1135 create_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) {
1142 		lwarnx("cannot malloc fcgi_response");
1143 		return;
1144 	}
1145 	header = (struct fcgi_record_header*) resp->data;
1146 	header->version = 1;
1147 	header->type = FCGI_END_REQUEST;
1148 	header->id = htons(c->id);
1149 	header->content_len = htons(sizeof(struct
1150 	    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);
1156 	end_request->protocol_status = FCGI_REQUEST_COMPLETE;
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 
1167 void
1168 cleanup_request(struct request *c)
1169 {
1170 	struct fcgi_response	*resp;
1171 	struct env_val		*env_entry;
1172 
1173 	evtimer_del(&c->tmo);
1174 	if (event_initialized(&c->ev))
1175 		event_del(&c->ev);
1176 	if (event_initialized(&c->resp_ev))
1177 		event_del(&c->resp_ev);
1178 	if (event_initialized(&c->script_ev)) {
1179 		close(EVENT_FD(&c->script_ev));
1180 		event_del(&c->script_ev);
1181 	}
1182 	if (event_initialized(&c->script_err_ev)) {
1183 		close(EVENT_FD(&c->script_err_ev));
1184 		event_del(&c->script_err_ev);
1185 	}
1186 
1187 	close(c->fd);
1188 	while (!SLIST_EMPTY(&c->env)) {
1189 		env_entry = SLIST_FIRST(&c->env);
1190 		SLIST_REMOVE_HEAD(&c->env, entry);
1191 		free(env_entry->key);
1192 		free(env_entry->val);
1193 		free(env_entry);
1194 	}
1195 
1196 	while ((resp = TAILQ_FIRST(&c->response_head))) {
1197 		TAILQ_REMOVE(&c->response_head, resp, entry);
1198 		free(resp);
1199 	}
1200 	LIST_REMOVE(c, entry);
1201 	if (! c->inflight_fds_accounted)
1202 		cgi_inflight--;
1203 	free(c);
1204 }
1205 
1206 void
1207 dump_fcgi_record(const char *p, struct fcgi_record_header *h)
1208 {
1209 	dump_fcgi_record_header(p, h);
1210 
1211 	if (h->type == FCGI_BEGIN_REQUEST)
1212 		dump_fcgi_begin_request_body(p,
1213 		    (struct fcgi_begin_request_body *)(h + 1));
1214 	else if (h->type == FCGI_END_REQUEST)
1215 		dump_fcgi_end_request_body(p,
1216 		    (struct fcgi_end_request_body *)(h + 1));
1217 }
1218 
1219 void
1220 dump_fcgi_record_header(const char* p, struct fcgi_record_header *h)
1221 {
1222 	ldebug("%sversion:         %d", p, h->version);
1223 	ldebug("%stype:            %d", p, h->type);
1224 	ldebug("%srequestId:       %d", p, ntohs(h->id));
1225 	ldebug("%scontentLength:   %d", p, ntohs(h->content_len));
1226 	ldebug("%spaddingLength:   %d", p, h->padding_len);
1227 	ldebug("%sreserved:        %d", p, h->reserved);
1228 }
1229 
1230 void
1231 dump_fcgi_begin_request_body(const char *p, struct fcgi_begin_request_body *b)
1232 {
1233 	ldebug("%srole             %d", p, ntohs(b->role));
1234 	ldebug("%sflags            %d", p, b->flags);
1235 }
1236 
1237 void
1238 dump_fcgi_end_request_body(const char *p, struct fcgi_end_request_body *b)
1239 {
1240 	ldebug("%sappStatus:       %d", p, ntohl(b->app_status));
1241 	ldebug("%sprotocolStatus:  %d", p, b->protocol_status);
1242 }
1243 
1244 void
1245 syslog_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_EMERG, "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 void
1258 syslog_err(int ecode, const char *fmt, ...)
1259 {
1260 	va_list ap;
1261 
1262 	va_start(ap, fmt);
1263 	syslog_vstrerror(errno, LOG_CRIT, fmt, ap);
1264 	va_end(ap);
1265 	exit(ecode);
1266 }
1267 
1268 __dead void
1269 syslog_errx(int ecode, const char *fmt, ...)
1270 {
1271 	va_list ap;
1272 
1273 	va_start(ap, fmt);
1274 	vsyslog(LOG_CRIT, fmt, ap);
1275 	va_end(ap);
1276 	exit(ecode);
1277 }
1278 
1279 void
1280 syslog_warn(const char *fmt, ...)
1281 {
1282 	va_list ap;
1283 
1284 	va_start(ap, fmt);
1285 	syslog_vstrerror(errno, LOG_ERR, fmt, ap);
1286 	va_end(ap);
1287 }
1288 
1289 void
1290 syslog_warnx(const char *fmt, ...)
1291 {
1292 	va_list ap;
1293 
1294 	va_start(ap, fmt);
1295 	vsyslog(LOG_ERR, fmt, ap);
1296 	va_end(ap);
1297 }
1298 
1299 void
1300 syslog_info(const char *fmt, ...)
1301 {
1302 	va_list ap;
1303 
1304 	va_start(ap, fmt);
1305 	vsyslog(LOG_INFO, fmt, ap);
1306 	va_end(ap);
1307 }
1308 
1309 void
1310 syslog_debug(const char *fmt, ...)
1311 {
1312 	va_list ap;
1313 
1314 	va_start(ap, fmt);
1315 	vsyslog(LOG_DEBUG, fmt, ap);
1316 	va_end(ap);
1317 }
1318