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