xref: /openbsd-src/usr.sbin/bgplgd/slowcgi.c (revision 25c4e8bd056e974b28f4a0ffd39d76c190a56013)
1 /*	$OpenBSD: slowcgi.c,v 1.2 2022/07/08 08:48:56 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		 120
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 	int				fd;
110 	uint8_t				buf[FCGI_RECORD_SIZE];
111 	size_t				buf_pos;
112 	size_t				buf_len;
113 	struct fcgi_response_head	response_head;
114 	struct env_head			env;
115 	int				env_count;
116 	pid_t				command_pid;
117 	int				command_status;
118 	int				script_flags;
119 	uint16_t			id;
120 	uint8_t				request_started;
121 	uint8_t				request_done;
122 	int				inflight_fds_accounted;
123 };
124 
125 LIST_HEAD(requests_head, request);
126 
127 struct slowcgi_proc {
128 	struct requests_head	requests;
129 	struct event		ev_sigchld;
130 };
131 
132 struct fcgi_begin_request_body {
133 	uint16_t	role;
134 	uint8_t		flags;
135 	uint8_t		reserved[5];
136 }__packed;
137 
138 struct fcgi_end_request_body {
139 	uint32_t	app_status;
140 	uint8_t		protocol_status;
141 	uint8_t		reserved[3];
142 }__packed;
143 
144 __dead void	usage(void);
145 int		slowcgi_listen(char *, struct passwd *);
146 void		slowcgi_paused(int, short, void *);
147 int		accept_reserve(int, struct sockaddr *, socklen_t *, int,
148 		    volatile int *);
149 void		slowcgi_accept(int, short, void *);
150 void		slowcgi_request(int, short, void *);
151 void		slowcgi_response(int, short, void *);
152 void		slowcgi_add_response(struct request *, struct fcgi_response *);
153 void		slowcgi_timeout(int, short, void *);
154 void		slowcgi_sig_handler(int, short, void *);
155 size_t		parse_record(uint8_t * , size_t, struct request *);
156 void		parse_begin_request(uint8_t *, uint16_t, struct request *,
157 		    uint16_t);
158 void		parse_params(uint8_t *, uint16_t, struct request *, uint16_t);
159 void		parse_stdin(uint8_t *, uint16_t, struct request *, uint16_t);
160 char		*env_get(struct request *, const char *);
161 void		exec_cgi(struct request *);
162 void		script_std_in(int, short, void *);
163 void		script_err_in(int, short, void *);
164 void		create_data_record(struct request *, uint8_t, const void *,
165 		    size_t);
166 void		create_end_record(struct request *);
167 void		cleanup_request(struct request *);
168 void		dump_fcgi_record(const char *,
169 		    struct fcgi_record_header *);
170 void		dump_fcgi_record_header(const char *,
171 		    struct fcgi_record_header *);
172 void		dump_fcgi_begin_request_body(const char *,
173 		    struct fcgi_begin_request_body *);
174 void		dump_fcgi_end_request_body(const char *,
175 		    struct fcgi_end_request_body *);
176 
177 const struct loggers conslogger = {
178 	err,
179 	errx,
180 	warn,
181 	warnx,
182 	warnx, /* info */
183 	warnx /* debug */
184 };
185 
186 __dead void	syslog_err(int, const char *, ...)
187 		    __attribute__((__format__ (printf, 2, 3)));
188 __dead void	syslog_errx(int, const char *, ...)
189 		    __attribute__((__format__ (printf, 2, 3)));
190 void		syslog_warn(const char *, ...)
191 		    __attribute__((__format__ (printf, 1, 2)));
192 void		syslog_warnx(const char *, ...)
193 		    __attribute__((__format__ (printf, 1, 2)));
194 void		syslog_info(const char *, ...)
195 		    __attribute__((__format__ (printf, 1, 2)));
196 void		syslog_debug(const char *, ...)
197 		    __attribute__((__format__ (printf, 1, 2)));
198 void		syslog_vstrerror(int, int, const char *, va_list)
199 		    __attribute__((__format__ (printf, 3, 0)));
200 
201 const struct loggers syslogger = {
202 	syslog_err,
203 	syslog_errx,
204 	syslog_warn,
205 	syslog_warnx,
206 	syslog_info,
207 	syslog_debug
208 };
209 
210 const struct loggers *logger = &conslogger;
211 
212 __dead void
213 usage(void)
214 {
215 	extern char *__progname;
216 	fprintf(stderr,
217 	    "usage: %s [-d] [-p path] [-S socket] [-s socket] [-U user]\n",
218 	    __progname);
219 	exit(1);
220 }
221 
222 struct timeval		timeout = { TIMEOUT_DEFAULT, 0 };
223 struct slowcgi_proc	slowcgi_proc;
224 int			debug = 0;
225 int			on = 1;
226 char			*fcgi_socket = "/var/www/run/bgplgd.sock";
227 char			*bgpctlpath = "bgpctl";
228 char			*bgpctlsock = "/var/run/bgpd.rsock";
229 
230 
231 /*
232  * Unveil the command we want to run.
233  * If this has a pathname component in it, interpret as a file
234  * and unveil the file directly.
235  * Otherwise, look up the command in our PATH.
236  */
237 static void
238 unveil_command(const char *prog)
239 {
240 	const char *pp;
241 	char *save, *cmd, *path;
242 	struct stat st;
243 
244 	if (strchr(prog, '/') != NULL) {
245 		if (unveil(prog, "x") == -1)
246 			err(1, "%s: unveil", prog);
247 		return;
248 	}
249 
250 	if (getenv("PATH") == NULL)
251 		lerrx(1, "PATH is unset");
252 	if ((path = strdup(getenv("PATH"))) == NULL)
253 		lerr(1, NULL);
254 	save = path;
255 	while ((pp = strsep(&path, ":")) != NULL) {
256 		if (*pp == '\0')
257 			continue;
258 		if (asprintf(&cmd, "%s/%s", pp, prog) == -1)
259 			lerr(1, NULL);
260 		if (lstat(cmd, &st) == -1) {
261 			free(cmd);
262 			continue;
263 		}
264 		if (unveil(cmd, "x") == -1)
265 			lerr(1, "%s: unveil", cmd);
266 		free(cmd);
267 		break;
268 	}
269 	free(save);
270 }
271 
272 int
273 main(int argc, char *argv[])
274 {
275 	extern char *__progname;
276 	struct listener	*l = NULL;
277 	struct passwd	*pw;
278 	struct stat	 sb;
279 	int		 c, fd;
280 	const char	*sock_user = WWW_USER;
281 	const char	*cgi_user = BGPLGD_USER;
282 
283 	/*
284 	 * Ensure we have fds 0-2 open so that we have no fd overlaps
285 	 * in exec_cgi() later. Just exit on error, we don't have enough
286 	 * fds open to output an error message anywhere.
287 	 */
288 	for (c=0; c < 3; c++) {
289 		if (fstat(c, &sb) == -1) {
290 			if ((fd = open("/dev/null", O_RDWR)) != -1) {
291 				if (dup2(fd, c) == -1)
292 					exit(1);
293 				if (fd > c)
294 					close(fd);
295 			} else
296 				exit(1);
297 		}
298 	}
299 
300 	while ((c = getopt(argc, argv, "dp:S:s:U:u:")) != -1) {
301 		switch (c) {
302 		case 'd':
303 			debug++;
304 			break;
305 		case 'p':
306 			bgpctlpath = optarg;
307 			break;
308 		case 'S':
309 			bgpctlsock = optarg;
310 			break;
311 		case 's':
312 			fcgi_socket = optarg;
313 			break;
314 		case 'U':
315 			sock_user = optarg;
316 			break;
317 		default:
318 			usage();
319 			/* NOTREACHED */
320 		}
321 	}
322 
323 	if (geteuid() != 0)
324 		errx(1, "need root privileges");
325 
326 	if (!debug && daemon(0, 0) == -1)
327 		err(1, "daemon");
328 
329 	if (!debug) {
330 		openlog(__progname, LOG_PID|LOG_NDELAY, LOG_DAEMON);
331 		logger = &syslogger;
332 	}
333 
334 	ldebug("sock_user: %s", sock_user);
335 	pw = getpwnam(sock_user);
336 	if (pw == NULL)
337 		lerrx(1, "no %s user", sock_user);
338 
339 	fd = slowcgi_listen(fcgi_socket, pw);
340 
341 	ldebug("cgi_user: %s", cgi_user);
342 	pw = getpwnam(cgi_user);
343 	if (pw == NULL)
344 		lerrx(1, "no %s user", cgi_user);
345 
346 	if (setgroups(1, &pw->pw_gid) ||
347 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
348 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
349 		lerr(1, "unable to revoke privs");
350 
351 	unveil_command(bgpctlpath);
352 
353 	if (pledge("stdio rpath unix proc exec", NULL) == -1)
354 		lerr(1, "pledge");
355 
356 	LIST_INIT(&slowcgi_proc.requests);
357 	event_init();
358 
359 	l = calloc(1, sizeof(*l));
360 	if (l == NULL)
361 		lerr(1, "listener ev alloc");
362 
363 	event_set(&l->ev, fd, EV_READ | EV_PERSIST, slowcgi_accept, l);
364 	event_add(&l->ev, NULL);
365 	evtimer_set(&l->pause, slowcgi_paused, l);
366 
367 	signal_set(&slowcgi_proc.ev_sigchld, SIGCHLD, slowcgi_sig_handler,
368 	    &slowcgi_proc);
369 	signal_add(&slowcgi_proc.ev_sigchld, NULL);
370 
371 	signal(SIGPIPE, SIG_IGN);
372 
373 	event_dispatch();
374 	return (0);
375 }
376 
377 int
378 slowcgi_listen(char *path, struct passwd *pw)
379 {
380 	struct sockaddr_un	 sun;
381 	mode_t			 old_umask;
382 	int			 fd;
383 
384 	if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
385 	    0)) == -1)
386 		lerr(1, "slowcgi_listen: socket");
387 
388 	bzero(&sun, sizeof(sun));
389 	sun.sun_family = AF_UNIX;
390 	if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
391 	    sizeof(sun.sun_path))
392 		lerrx(1, "socket path too long");
393 
394 	if (unlink(path) == -1)
395 		if (errno != ENOENT)
396 			lerr(1, "slowcgi_listen: unlink %s", path);
397 
398 	old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
399 
400 	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
401 		lerr(1,"slowcgi_listen: bind: %s", path);
402 
403 	umask(old_umask);
404 
405 	if (chown(path, pw->pw_uid, pw->pw_gid) == -1)
406 		lerr(1, "slowcgi_listen: chown: %s", path);
407 
408 	if (listen(fd, 5) == -1)
409 		lerr(1, "listen");
410 
411 	ldebug("socket: %s", path);
412 	return fd;
413 }
414 
415 void
416 slowcgi_paused(int fd, short events, void *arg)
417 {
418 	struct listener	*l = arg;
419 	event_add(&l->ev, NULL);
420 }
421 
422 int
423 accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
424     int reserve, volatile int *counter)
425 {
426 	int ret;
427 	if (getdtablecount() + reserve +
428 	    ((*counter + 1) * FD_NEEDED) >= getdtablesize()) {
429 		ldebug("inflight fds exceeded");
430 		errno = EMFILE;
431 		return -1;
432 	}
433 
434 	if ((ret = accept4(sockfd, addr, addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC))
435 	    > -1) {
436 		(*counter)++;
437 		ldebug("inflight incremented, now %d", *counter);
438 	}
439 	return ret;
440 }
441 
442 void
443 slowcgi_accept(int fd, short events, void *arg)
444 {
445 	struct listener		*l;
446 	struct sockaddr_storage	 ss;
447 	struct timeval		 backoff;
448 	struct request		*c;
449 	socklen_t		 len;
450 	int			 s;
451 
452 	l = arg;
453 	backoff.tv_sec = 1;
454 	backoff.tv_usec = 0;
455 	c = NULL;
456 
457 	len = sizeof(ss);
458 	if ((s = accept_reserve(fd, (struct sockaddr *)&ss,
459 	    &len, FD_RESERVE, &cgi_inflight)) == -1) {
460 		switch (errno) {
461 		case EINTR:
462 		case EWOULDBLOCK:
463 		case ECONNABORTED:
464 			return;
465 		case EMFILE:
466 		case ENFILE:
467 			event_del(&l->ev);
468 			evtimer_add(&l->pause, &backoff);
469 			return;
470 		default:
471 			lerr(1, "accept");
472 		}
473 	}
474 
475 	c = calloc(1, sizeof(*c));
476 	if (c == NULL) {
477 		lwarn("cannot calloc request");
478 		close(s);
479 		cgi_inflight--;
480 		return;
481 	}
482 	c->fd = s;
483 	c->buf_pos = 0;
484 	c->buf_len = 0;
485 	c->request_started = 0;
486 	c->inflight_fds_accounted = 0;
487 	TAILQ_INIT(&c->response_head);
488 
489 	event_set(&c->ev, s, EV_READ | EV_PERSIST, slowcgi_request, c);
490 	event_add(&c->ev, NULL);
491 	event_set(&c->resp_ev, s, EV_WRITE | EV_PERSIST, slowcgi_response, c);
492 	evtimer_set(&c->tmo, slowcgi_timeout, c);
493 	evtimer_add(&c->tmo, &timeout);
494 	LIST_INSERT_HEAD(&slowcgi_proc.requests, c, entry);
495 }
496 
497 void
498 slowcgi_timeout(int fd, short events, void *arg)
499 {
500 	cleanup_request((struct request*) arg);
501 }
502 
503 void
504 slowcgi_sig_handler(int sig, short event, void *arg)
505 {
506 	struct request		*c;
507 	struct slowcgi_proc	*p;
508 	pid_t			 pid;
509 	int			 status;
510 
511 	p = arg;
512 
513 	switch (sig) {
514 	case SIGCHLD:
515 		while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0) {
516 			LIST_FOREACH(c, &p->requests, entry)
517 				if (c->command_pid == pid)
518 					break;
519 			if (c == NULL) {
520 				lwarnx("caught exit of unknown child %i", pid);
521 				continue;
522 			}
523 
524 			if (WIFSIGNALED(status))
525 				c->command_status = WTERMSIG(status);
526 			else
527 				c->command_status = WEXITSTATUS(status);
528 
529 			ldebug("exit %s%d",
530 			    WIFSIGNALED(status) ? "signal" : "",
531 			    c->command_status);
532 
533 			c->script_flags |= SCRIPT_DONE;
534 
535 			if (c->script_flags == (STDOUT_DONE | STDERR_DONE |
536 			    SCRIPT_DONE))
537 				create_end_record(c);
538 		}
539 		if (pid == -1 && errno != ECHILD)
540 			lwarn("waitpid");
541 		break;
542 	default:
543 		lerr(1, "unexpected signal: %d", sig);
544 		break;
545 	}
546 }
547 
548 void
549 slowcgi_add_response(struct request *c, struct fcgi_response *resp)
550 {
551 	struct fcgi_record_header	*header;
552 	size_t				 padded_len;
553 
554 	header = (struct fcgi_record_header*)resp->data;
555 
556 	/* The FastCGI spec suggests to align the output buffer */
557 	padded_len = FCGI_ALIGN(resp->data_len);
558 	if (padded_len > resp->data_len) {
559 		/* There should always be FCGI_PADDING_SIZE bytes left */
560 		if (padded_len > FCGI_RECORD_SIZE)
561 			lerr(1, "response too long");
562 		header->padding_len = padded_len - resp->data_len;
563 		resp->data_len = padded_len;
564 	}
565 
566 	TAILQ_INSERT_TAIL(&c->response_head, resp, entry);
567 	event_add(&c->resp_ev, NULL);
568 }
569 
570 void
571 slowcgi_response(int fd, short events, void *arg)
572 {
573 	struct request			*c;
574 	struct fcgi_record_header	*header;
575 	struct fcgi_response		*resp;
576 	ssize_t				 n;
577 
578 	c = arg;
579 
580 	while ((resp = TAILQ_FIRST(&c->response_head))) {
581 		header = (struct fcgi_record_header*) resp->data;
582 		if (debug > 1)
583 			dump_fcgi_record("resp ", header);
584 
585 		n = write(fd, resp->data + resp->data_pos, resp->data_len);
586 		if (n == -1) {
587 			if (errno == EAGAIN || errno == EINTR)
588 				return;
589 			cleanup_request(c);
590 			return;
591 		}
592 		resp->data_pos += n;
593 		resp->data_len -= n;
594 		if (resp->data_len == 0) {
595 			TAILQ_REMOVE(&c->response_head, resp, entry);
596 			free(resp);
597 		}
598 	}
599 
600 	if (TAILQ_EMPTY(&c->response_head)) {
601 		if (c->request_done)
602 			cleanup_request(c);
603 		else
604 			event_del(&c->resp_ev);
605 	}
606 }
607 
608 void
609 slowcgi_request(int fd, short events, void *arg)
610 {
611 	struct request	*c;
612 	ssize_t		 n;
613 	size_t		 parsed;
614 
615 	c = arg;
616 
617 	n = read(fd, c->buf + c->buf_pos + c->buf_len,
618 	    FCGI_RECORD_SIZE - c->buf_pos-c->buf_len);
619 
620 	switch (n) {
621 	case -1:
622 		switch (errno) {
623 		case EINTR:
624 		case EAGAIN:
625 			return;
626 		default:
627 			goto fail;
628 		}
629 		break;
630 
631 	case 0:
632 		ldebug("closed connection");
633 		goto fail;
634 	default:
635 		break;
636 	}
637 
638 	c->buf_len += n;
639 
640 	/*
641 	 * Parse the records as they are received. Per the FastCGI
642 	 * specification, the server need only receive the FastCGI
643 	 * parameter records in full; it is free to begin execution
644 	 * at that point, which is what happens here.
645 	 */
646 	do {
647 		parsed = parse_record(c->buf + c->buf_pos, c->buf_len, c);
648 		c->buf_pos += parsed;
649 		c->buf_len -= parsed;
650 	} while (parsed > 0 && c->buf_len > 0);
651 
652 	/* Make space for further reads */
653 	if (c->buf_len > 0) {
654 		bcopy(c->buf + c->buf_pos, c->buf, c->buf_len);
655 		c->buf_pos = 0;
656 	}
657 	return;
658 fail:
659 	cleanup_request(c);
660 }
661 
662 void
663 parse_begin_request(uint8_t *buf, uint16_t n, struct request *c, uint16_t id)
664 {
665 	/* XXX -- FCGI_CANT_MPX_CONN */
666 	if (c->request_started) {
667 		lwarnx("unexpected FCGI_BEGIN_REQUEST, ignoring");
668 		return;
669 	}
670 
671 	if (n != sizeof(struct fcgi_begin_request_body)) {
672 		lwarnx("wrong size %d != %lu", n,
673 		    sizeof(struct fcgi_begin_request_body));
674 		return;
675 	}
676 
677 	c->request_started = 1;
678 
679 	c->id = id;
680 	SLIST_INIT(&c->env);
681 	c->env_count = 0;
682 }
683 
684 void
685 parse_params(uint8_t *buf, uint16_t n, struct request *c, uint16_t id)
686 {
687 	struct env_val			*env_entry;
688 	uint32_t			 name_len, val_len;
689 
690 	if (!c->request_started) {
691 		lwarnx("FCGI_PARAMS without FCGI_BEGIN_REQUEST, ignoring");
692 		return;
693 	}
694 
695 	if (c->id != id) {
696 		lwarnx("unexpected id, ignoring");
697 		return;
698 	}
699 
700 	/*
701 	 * If this is the last FastCGI parameter record,
702 	 * begin execution of the CGI script.
703 	 */
704 	if (n == 0) {
705 		exec_cgi(c);
706 		return;
707 	}
708 
709 	while (n > 0) {
710 		if (buf[0] >> 7 == 0) {
711 			name_len = buf[0];
712 			n--;
713 			buf++;
714 		} else {
715 			if (n > 3) {
716 				name_len = ((buf[0] & 0x7f) << 24) +
717 				    (buf[1] << 16) + (buf[2] << 8) + buf[3];
718 				n -= 4;
719 				buf += 4;
720 			} else
721 				return;
722 		}
723 
724 		if (n > 0) {
725 			if (buf[0] >> 7 == 0) {
726 				val_len = buf[0];
727 				n--;
728 				buf++;
729 			} else {
730 				if (n > 3) {
731 					val_len = ((buf[0] & 0x7f) << 24) +
732 					    (buf[1] << 16) + (buf[2] << 8) +
733 					     buf[3];
734 					n -= 4;
735 					buf += 4;
736 				} else
737 					return;
738 			}
739 		} else
740 			return;
741 
742 		if (n < name_len + val_len)
743 			return;
744 
745 		if ((env_entry = malloc(sizeof(struct env_val))) == NULL) {
746 			lwarnx("cannot allocate env_entry");
747 			return;
748 		}
749 
750 		if ((env_entry->key = malloc(name_len + 1)) == NULL) {
751 			lwarnx("cannot allocate env_entry->key");
752 			free(env_entry);
753 			return;
754 		}
755 		if ((env_entry->val = malloc(val_len + 1)) == NULL) {
756 			lwarnx("cannot allocate env_entry->val");
757 			free(env_entry->key);
758 			free(env_entry);
759 			return;
760 		}
761 
762 		bcopy(buf, env_entry->key, name_len);
763 		buf += name_len;
764 		n -= name_len;
765 		env_entry->key[name_len] = '\0';
766 		bcopy(buf, env_entry->val, val_len);
767 		buf += val_len;
768 		n -= val_len;
769 		env_entry->val[val_len] = '\0';
770 
771 		SLIST_INSERT_HEAD(&c->env, env_entry, entry);
772 		ldebug("env[%d], %s=%s", c->env_count, env_entry->key,
773 		    env_entry->val);
774 		c->env_count++;
775 	}
776 }
777 
778 void
779 parse_stdin(uint8_t *buf, uint16_t n, struct request *c, uint16_t id)
780 {
781 	if (c->id != id) {
782 		lwarnx("unexpected id, ignoring");
783 		return;
784 	}
785 
786 	if (n != 0)
787 		lwarnx("unexpected stdin input, ignoring");
788 }
789 
790 size_t
791 parse_record(uint8_t *buf, size_t n, struct request *c)
792 {
793 	struct fcgi_record_header	*h;
794 
795 	if (n < sizeof(struct fcgi_record_header))
796 		return (0);
797 
798 	h = (struct fcgi_record_header*) buf;
799 
800 	if (debug > 1)
801 		dump_fcgi_record("", h);
802 
803 	if (n < sizeof(struct fcgi_record_header) + ntohs(h->content_len)
804 	    + h->padding_len)
805 		return (0);
806 
807 	if (h->version != 1)
808 		lerrx(1, "wrong version");
809 
810 	switch (h->type) {
811 	case FCGI_BEGIN_REQUEST:
812 		parse_begin_request(buf + sizeof(struct fcgi_record_header),
813 		    ntohs(h->content_len), c, ntohs(h->id));
814 		break;
815 	case FCGI_PARAMS:
816 		parse_params(buf + sizeof(struct fcgi_record_header),
817 		    ntohs(h->content_len), c, ntohs(h->id));
818 		break;
819 	case FCGI_STDIN:
820 		parse_stdin(buf + sizeof(struct fcgi_record_header),
821 		    ntohs(h->content_len), c, ntohs(h->id));
822 		break;
823 	default:
824 		lwarnx("unimplemented type %d", h->type);
825 		break;
826 	}
827 
828 	return (sizeof(struct fcgi_record_header) + ntohs(h->content_len)
829 	    + h->padding_len);
830 }
831 
832 char *
833 env_get(struct request *c, const char *key)
834 {
835 	struct env_val	*env;
836 
837 	SLIST_FOREACH(env, &c->env, entry) {
838 		if (strcmp(env->key, key) == 0)
839 			return (env->val);
840 	}
841 	return (NULL);
842 }
843 
844 static const char *
845 http_error(int *res)
846 {
847 	const struct http_error errors[] = HTTP_ERRORS;
848 	size_t i;
849 
850 	for (i = 0; errors[i].error_code != 0; i++)
851 		if (errors[i].error_code == *res)
852 			return errors[i].error_name;
853 
854 	/* unknown error - change to 500 */
855 	lwarnx("unknown http error %d", *res);
856 	*res = 500;
857 	return "Internal Server Error";
858 }
859 
860 static void
861 error_response(struct request *c, int res)
862 {
863 	const char *type = "text/html";
864 	const char *errstr = http_error(&res);
865 	char *buf;
866 	int len;
867 
868 	lwarnx("HTTP status %d: %s", res, errstr);
869 
870 	len = asprintf(&buf,
871 	    "Content-Type: %s\n"
872 	    "Status: %d\n"
873 	    "Cache-Control: no-cache\n"
874 	    "\n"
875 	    "<!DOCTYPE html>\n"
876 	    "<html>\n"
877 	    " <head>\n"
878 	    "  <meta http-equiv=\"Content-Type\" "
879 	    "content=\"%s; charset=utf-8\"/>\n"
880 	    "  <title>%d %s</title>\n"
881 	    " </head>\n"
882 	    " <body>\n"
883 	    "  <h1>%d %s</h1>\n"
884 	    "  <hr>\n"
885 	    "  <address>OpenBSD bgplgd</address>\n"
886 	    " </body>\n"
887 	    "</html>\n",
888 	    type, res, type, res, errstr, res, errstr);
889 
890 	if (len == -1)
891 		lerr(1, NULL);
892 
893 	create_data_record(c, FCGI_STDOUT, buf, len);
894 	free(buf);
895 	c->script_flags = (STDOUT_DONE | STDERR_DONE | SCRIPT_DONE);
896 	create_end_record(c);
897 }
898 
899 /*
900  * Fork a new CGI process to handle the request, translating
901  * between FastCGI parameter records and CGI's environment variables,
902  * as well as between the CGI process' stdin/stdout and the
903  * corresponding FastCGI records.
904  */
905 void
906 exec_cgi(struct request *c)
907 {
908 	struct lg_ctx	 ctx = { 0 };
909 	int		 s_in[2], s_out[2], s_err[2], res;
910 	pid_t		 pid;
911 
912 	res = prep_request(&ctx, env_get(c, "REQUEST_METHOD"),
913 	    env_get(c, "PATH_INFO"), env_get(c, "QUERY_STRING"));
914 	if (res != 0) {
915 		error_response(c, res);
916 		return;
917 	}
918 
919 	if (pipe(s_in) == -1)
920 		lerr(1, "pipe");
921 	if (pipe(s_out) == -1)
922 		lerr(1, "pipe");
923 	if (pipe(s_err) == -1)
924 		lerr(1, "pipe");
925 	cgi_inflight--;
926 	c->inflight_fds_accounted = 1;
927 
928 	switch (pid = fork()) {
929 	case -1:
930 		c->command_status = errno;
931 
932 		lwarn("fork");
933 
934 		close(s_in[0]);
935 		close(s_out[0]);
936 		close(s_err[0]);
937 
938 		close(s_in[1]);
939 		close(s_out[1]);
940 		close(s_err[1]);
941 
942 		c->script_flags = (STDOUT_DONE | STDERR_DONE | SCRIPT_DONE);
943 		create_end_record(c);
944 		return;
945 	case 0:
946 		/* Child process */
947 		if (pledge("stdio rpath exec", NULL) == -1)
948 			lerr(1, "pledge");
949 		close(s_in[0]);
950 		close(s_out[0]);
951 		close(s_err[0]);
952 
953 		if (dup2(s_in[1], STDIN_FILENO) == -1)
954 			_exit(1);
955 		if (dup2(s_out[1], STDOUT_FILENO) == -1)
956 			_exit(1);
957 		if (dup2(s_err[1], STDERR_FILENO) == -1)
958 			_exit(1);
959 
960 		close(s_in[1]);
961 		close(s_out[1]);
962 		close(s_err[1]);
963 
964 		bgpctl_call(&ctx);
965 
966 		/* should not be reached */
967 		_exit(1);
968 
969 	}
970 
971 	ldebug("fork %d", pid);
972 
973 	/* Parent process*/
974 	close(s_in[1]);
975 	close(s_out[1]);
976 	close(s_err[1]);
977 
978 	fcntl(s_in[0], F_SETFD, FD_CLOEXEC);
979 	fcntl(s_out[0], F_SETFD, FD_CLOEXEC);
980 	fcntl(s_err[0], F_SETFD, FD_CLOEXEC);
981 
982 	if (ioctl(s_in[0], FIONBIO, &on) == -1)
983 		lerr(1, "script ioctl(FIONBIO)");
984 	if (ioctl(s_out[0], FIONBIO, &on) == -1)
985 		lerr(1, "script ioctl(FIONBIO)");
986 	if (ioctl(s_err[0], FIONBIO, &on) == -1)
987 		lerr(1, "script ioctl(FIONBIO)");
988 
989 	close(s_in[0]);	/* close stdin, bgpctl does not expect anything */
990 
991 	c->command_pid = pid;
992 	event_set(&c->script_ev, s_out[0], EV_READ | EV_PERSIST,
993 	    script_std_in, c);
994 	event_add(&c->script_ev, NULL);
995 	event_set(&c->script_err_ev, s_err[0], EV_READ | EV_PERSIST,
996 	    script_err_in, c);
997 	event_add(&c->script_err_ev, NULL);
998 }
999 
1000 static void
1001 script_in(int fd, struct event *ev, struct request *c, uint8_t type)
1002 {
1003 	struct fcgi_response		*resp;
1004 	struct fcgi_record_header	*header;
1005 	ssize_t				 n;
1006 
1007 	if ((resp = calloc(1, sizeof(struct fcgi_response))) == NULL) {
1008 		lwarnx("cannot malloc fcgi_response");
1009 		return;
1010 	}
1011 	header = (struct fcgi_record_header*) resp->data;
1012 	header->version = 1;
1013 	header->type = type;
1014 	header->id = htons(c->id);
1015 	header->padding_len = 0;
1016 	header->reserved = 0;
1017 
1018 	n = read(fd, resp->data + sizeof(struct fcgi_record_header),
1019 	    FCGI_CONTENT_SIZE);
1020 
1021 	if (n == -1) {
1022 		switch (errno) {
1023 		case EINTR:
1024 		case EAGAIN:
1025 			free(resp);
1026 			return;
1027 		default:
1028 			n = 0; /* fake empty FCGI_STD{OUT,ERR} response */
1029 		}
1030 	}
1031 	header->content_len = htons(n);
1032 	resp->data_pos = 0;
1033 	resp->data_len = n + sizeof(struct fcgi_record_header);
1034 	slowcgi_add_response(c, resp);
1035 
1036 	if (n == 0) {
1037 		if (type == FCGI_STDOUT)
1038 			c->script_flags |= STDOUT_DONE;
1039 		else
1040 			c->script_flags |= STDERR_DONE;
1041 
1042 		if (c->script_flags == (STDOUT_DONE | STDERR_DONE |
1043 		    SCRIPT_DONE))
1044 			create_end_record(c);
1045 		event_del(ev);
1046 		close(fd);
1047 	}
1048 }
1049 
1050 void
1051 script_std_in(int fd, short events, void *arg)
1052 {
1053 	struct request *c = arg;
1054 	script_in(fd, &c->script_ev, c, FCGI_STDOUT);
1055 }
1056 
1057 void
1058 script_err_in(int fd, short events, void *arg)
1059 {
1060 	struct request *c = arg;
1061 	script_in(fd, &c->script_err_ev, c, FCGI_STDERR);
1062 }
1063 
1064 void
1065 create_data_record(struct request *c, uint8_t type, const void *buf, size_t len)
1066 {
1067 	struct fcgi_response		*resp;
1068 	struct fcgi_record_header	*header;
1069 	const char			*d = buf;
1070 	size_t				 n;
1071 
1072 	do {
1073 		if ((resp = calloc(1, sizeof(struct fcgi_response))) == NULL) {
1074 			lwarnx("cannot malloc fcgi_response");
1075 			return;
1076 		}
1077 		header = (struct fcgi_record_header*) resp->data;
1078 		header->version = 1;
1079 		header->type = type;
1080 		header->id = htons(c->id);
1081 		header->padding_len = 0;
1082 		header->reserved = 0;
1083 
1084 		n = len > FCGI_CONTENT_SIZE ? FCGI_CONTENT_SIZE : len;
1085 		memcpy(resp->data + sizeof(struct fcgi_record_header), d, n);
1086 
1087 		header->content_len = htons(n);
1088 		resp->data_pos = 0;
1089 		resp->data_len = n + sizeof(struct fcgi_record_header);
1090 		slowcgi_add_response(c, resp);
1091 
1092 		len -= n;
1093 		d += n;
1094 	} while (len > 0);
1095 }
1096 
1097 void
1098 create_end_record(struct request *c)
1099 {
1100 	struct fcgi_response		*resp;
1101 	struct fcgi_record_header	*header;
1102 	struct fcgi_end_request_body	*end_request;
1103 
1104 	if ((resp = calloc(1, sizeof(struct fcgi_response))) == NULL) {
1105 		lwarnx("cannot malloc fcgi_response");
1106 		return;
1107 	}
1108 	header = (struct fcgi_record_header*) resp->data;
1109 	header->version = 1;
1110 	header->type = FCGI_END_REQUEST;
1111 	header->id = htons(c->id);
1112 	header->content_len = htons(sizeof(struct
1113 	    fcgi_end_request_body));
1114 	header->padding_len = 0;
1115 	header->reserved = 0;
1116 	end_request = (struct fcgi_end_request_body *) (resp->data +
1117 	    sizeof(struct fcgi_record_header));
1118 	end_request->app_status = htonl(c->command_status);
1119 	end_request->protocol_status = FCGI_REQUEST_COMPLETE;
1120 	end_request->reserved[0] = 0;
1121 	end_request->reserved[1] = 0;
1122 	end_request->reserved[2] = 0;
1123 	resp->data_pos = 0;
1124 	resp->data_len = sizeof(struct fcgi_end_request_body) +
1125 	    sizeof(struct fcgi_record_header);
1126 	slowcgi_add_response(c, resp);
1127 	c->request_done = 1;
1128 }
1129 
1130 void
1131 cleanup_request(struct request *c)
1132 {
1133 	struct fcgi_response	*resp;
1134 	struct env_val		*env_entry;
1135 
1136 	evtimer_del(&c->tmo);
1137 	if (event_initialized(&c->ev))
1138 		event_del(&c->ev);
1139 	if (event_initialized(&c->resp_ev))
1140 		event_del(&c->resp_ev);
1141 	if (event_initialized(&c->script_ev)) {
1142 		close(EVENT_FD(&c->script_ev));
1143 		event_del(&c->script_ev);
1144 	}
1145 	if (event_initialized(&c->script_err_ev)) {
1146 		close(EVENT_FD(&c->script_err_ev));
1147 		event_del(&c->script_err_ev);
1148 	}
1149 
1150 	close(c->fd);
1151 	while (!SLIST_EMPTY(&c->env)) {
1152 		env_entry = SLIST_FIRST(&c->env);
1153 		SLIST_REMOVE_HEAD(&c->env, entry);
1154 		free(env_entry->key);
1155 		free(env_entry->val);
1156 		free(env_entry);
1157 	}
1158 
1159 	while ((resp = TAILQ_FIRST(&c->response_head))) {
1160 		TAILQ_REMOVE(&c->response_head, resp, entry);
1161 		free(resp);
1162 	}
1163 	LIST_REMOVE(c, entry);
1164 	if (! c->inflight_fds_accounted)
1165 		cgi_inflight--;
1166 	free(c);
1167 }
1168 
1169 void
1170 dump_fcgi_record(const char *p, struct fcgi_record_header *h)
1171 {
1172 	dump_fcgi_record_header(p, h);
1173 
1174 	if (h->type == FCGI_BEGIN_REQUEST)
1175 		dump_fcgi_begin_request_body(p,
1176 		    (struct fcgi_begin_request_body *)(h + 1));
1177 	else if (h->type == FCGI_END_REQUEST)
1178 		dump_fcgi_end_request_body(p,
1179 		    (struct fcgi_end_request_body *)(h + 1));
1180 }
1181 
1182 void
1183 dump_fcgi_record_header(const char* p, struct fcgi_record_header *h)
1184 {
1185 	ldebug("%sversion:         %d", p, h->version);
1186 	ldebug("%stype:            %d", p, h->type);
1187 	ldebug("%srequestId:       %d", p, ntohs(h->id));
1188 	ldebug("%scontentLength:   %d", p, ntohs(h->content_len));
1189 	ldebug("%spaddingLength:   %d", p, h->padding_len);
1190 	ldebug("%sreserved:        %d", p, h->reserved);
1191 }
1192 
1193 void
1194 dump_fcgi_begin_request_body(const char *p, struct fcgi_begin_request_body *b)
1195 {
1196 	ldebug("%srole             %d", p, ntohs(b->role));
1197 	ldebug("%sflags            %d", p, b->flags);
1198 }
1199 
1200 void
1201 dump_fcgi_end_request_body(const char *p, struct fcgi_end_request_body *b)
1202 {
1203 	ldebug("%sappStatus:       %d", p, ntohl(b->app_status));
1204 	ldebug("%sprotocolStatus:  %d", p, b->protocol_status);
1205 }
1206 
1207 void
1208 syslog_vstrerror(int e, int priority, const char *fmt, va_list ap)
1209 {
1210 	char *s;
1211 
1212 	if (vasprintf(&s, fmt, ap) == -1) {
1213 		syslog(LOG_EMERG, "unable to alloc in syslog_vstrerror");
1214 		exit(1);
1215 	}
1216 	syslog(priority, "%s: %s", s, strerror(e));
1217 	free(s);
1218 }
1219 
1220 __dead void
1221 syslog_err(int ecode, const char *fmt, ...)
1222 {
1223 	va_list ap;
1224 
1225 	va_start(ap, fmt);
1226 	syslog_vstrerror(errno, LOG_CRIT, fmt, ap);
1227 	va_end(ap);
1228 	exit(ecode);
1229 }
1230 
1231 __dead void
1232 syslog_errx(int ecode, const char *fmt, ...)
1233 {
1234 	va_list ap;
1235 
1236 	va_start(ap, fmt);
1237 	vsyslog(LOG_CRIT, fmt, ap);
1238 	va_end(ap);
1239 	exit(ecode);
1240 }
1241 
1242 void
1243 syslog_warn(const char *fmt, ...)
1244 {
1245 	va_list ap;
1246 
1247 	va_start(ap, fmt);
1248 	syslog_vstrerror(errno, LOG_ERR, fmt, ap);
1249 	va_end(ap);
1250 }
1251 
1252 void
1253 syslog_warnx(const char *fmt, ...)
1254 {
1255 	va_list ap;
1256 
1257 	va_start(ap, fmt);
1258 	vsyslog(LOG_ERR, fmt, ap);
1259 	va_end(ap);
1260 }
1261 
1262 void
1263 syslog_info(const char *fmt, ...)
1264 {
1265 	va_list ap;
1266 
1267 	va_start(ap, fmt);
1268 	vsyslog(LOG_INFO, fmt, ap);
1269 	va_end(ap);
1270 }
1271 
1272 void
1273 syslog_debug(const char *fmt, ...)
1274 {
1275 	va_list ap;
1276 
1277 	va_start(ap, fmt);
1278 	vsyslog(LOG_DEBUG, fmt, ap);
1279 	va_end(ap);
1280 }
1281