main.c revision 1.139
1/*	$OpenBSD: main.c,v 1.139 2021/04/19 17:04:35 deraadt Exp $ */
2/*
3 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <sys/queue.h>
19#include <sys/socket.h>
20#include <sys/resource.h>
21#include <sys/tree.h>
22#include <sys/types.h>
23#include <sys/wait.h>
24
25#include <assert.h>
26#include <err.h>
27#include <errno.h>
28#include <dirent.h>
29#include <fcntl.h>
30#include <fnmatch.h>
31#include <poll.h>
32#include <pwd.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <signal.h>
36#include <string.h>
37#include <limits.h>
38#include <syslog.h>
39#include <unistd.h>
40#include <imsg.h>
41
42#include "extern.h"
43#include "version.h"
44
45/*
46 * Maximum number of TAL files we'll load.
47 */
48#define	TALSZ_MAX	8
49
50size_t	entity_queue;
51int	timeout = 60*60;
52volatile sig_atomic_t killme;
53void	suicide(int sig);
54
55static struct filepath_tree	fpt = RB_INITIALIZER(&fpt);
56static struct msgbuf		procq, rsyncq, httpq, rrdpq;
57static int			cachefd, outdirfd;
58
59const char	*bird_tablename = "ROAS";
60
61int	verbose;
62int	noop;
63int	rrdpon;
64
65struct stats	 stats;
66
67/*
68 * Log a message to stderr if and only if "verbose" is non-zero.
69 * This uses the err(3) functionality.
70 */
71void
72logx(const char *fmt, ...)
73{
74	va_list		 ap;
75
76	if (verbose && fmt != NULL) {
77		va_start(ap, fmt);
78		vwarnx(fmt, ap);
79		va_end(ap);
80	}
81}
82
83void
84entity_free(struct entity *ent)
85{
86
87	if (ent == NULL)
88		return;
89
90	free(ent->pkey);
91	free(ent->file);
92	free(ent->descr);
93	free(ent);
94}
95
96/*
97 * Read a queue entity from the descriptor.
98 * Matched by entity_buffer_req().
99 * The pointer must be passed entity_free().
100 */
101void
102entity_read_req(int fd, struct entity *ent)
103{
104
105	io_simple_read(fd, &ent->type, sizeof(enum rtype));
106	io_str_read(fd, &ent->file);
107	io_simple_read(fd, &ent->has_pkey, sizeof(int));
108	if (ent->has_pkey)
109		io_buf_read_alloc(fd, (void **)&ent->pkey, &ent->pkeysz);
110	io_str_read(fd, &ent->descr);
111}
112
113/*
114 * Write the queue entity.
115 * Matched by entity_read_req().
116 */
117static void
118entity_write_req(const struct entity *ent)
119{
120	struct ibuf *b;
121
122	if (filepath_add(&fpt, ent->file) == 0) {
123		warnx("%s: File already visited", ent->file);
124		return;
125	}
126
127	if ((b = ibuf_dynamic(sizeof(*ent), UINT_MAX)) == NULL)
128		err(1, NULL);
129	io_simple_buffer(b, &ent->type, sizeof(ent->type));
130	io_str_buffer(b, ent->file);
131	io_simple_buffer(b, &ent->has_pkey, sizeof(int));
132	if (ent->has_pkey)
133		io_buf_buffer(b, ent->pkey, ent->pkeysz);
134	io_str_buffer(b, ent->descr);
135	ibuf_close(&procq, b);
136}
137
138/*
139 * Scan through all queued requests and see which ones are in the given
140 * repo, then flush those into the parser process.
141 */
142void
143entityq_flush(struct entityq *q, struct repo *rp)
144{
145	struct entity	*p, *np;
146
147	TAILQ_FOREACH_SAFE(p, q, entries, np) {
148		char *file = p->file;
149
150		/*
151		 * XXX fixup path here since the repo may change
152		 * during load because of fallback. In that case
153		 * the file path changes as well since RRDP and RSYNC
154		 * can not share a common repo.
155		 */
156		p->file = repo_filename(rp, file);
157		if (p->file == NULL)
158			err(1, "can't construct repo filename");
159		free(file);
160
161		entity_write_req(p);
162		TAILQ_REMOVE(q, p, entries);
163		entity_free(p);
164	}
165}
166
167/*
168 * Add the heap-allocated file to the queue for processing.
169 */
170static void
171entityq_add(char *file, enum rtype type, struct repo *rp,
172    const unsigned char *pkey, size_t pkeysz, char *descr)
173{
174	struct entity	*p;
175
176	if ((p = calloc(1, sizeof(struct entity))) == NULL)
177		err(1, NULL);
178
179	p->type = type;
180	p->file = file;
181	p->has_pkey = pkey != NULL;
182	if (p->has_pkey) {
183		p->pkeysz = pkeysz;
184		if ((p->pkey = malloc(pkeysz)) == NULL)
185			err(1, NULL);
186		memcpy(p->pkey, pkey, pkeysz);
187	}
188	if (descr != NULL)
189		if ((p->descr = strdup(descr)) == NULL)
190			err(1, NULL);
191
192	entity_queue++;
193
194	/*
195	 * Write to the queue if there's no repo or the repo has already
196	 * been loaded else enqueue it for later.
197	 */
198
199	if (rp == NULL || !repo_queued(rp, p)) {
200		/*
201		 * XXX fixup path here since for repo path the
202		 * file path has not yet been fixed here.
203		 * This is a quick way to make this work but in
204		 * the long run repos need to be passed to the parser.
205		 */
206		if (rp != NULL) {
207			file = p->file;
208			p->file = repo_filename(rp, file);
209			if (p->file == NULL)
210				err(1, "can't construct repo filename from %s",
211				    file);
212			free(file);
213		}
214		entity_write_req(p);
215		entity_free(p);
216	}
217}
218
219static void
220rrdp_file_resp(size_t id, int ok)
221{
222	enum rrdp_msg type = RRDP_FILE;
223	struct ibuf *b;
224
225	if ((b = ibuf_open(sizeof(type) + sizeof(id) + sizeof(ok))) == NULL)
226		err(1, NULL);
227	io_simple_buffer(b, &type, sizeof(type));
228	io_simple_buffer(b, &id, sizeof(id));
229	io_simple_buffer(b, &ok, sizeof(ok));
230	ibuf_close(&rrdpq, b);
231}
232
233void
234rrdp_fetch(size_t id, const char *uri, const char *local,
235    struct rrdp_session *s)
236{
237	enum rrdp_msg type = RRDP_START;
238	struct ibuf *b;
239
240	if ((b = ibuf_dynamic(256, UINT_MAX)) == NULL)
241		err(1, NULL);
242	io_simple_buffer(b, &type, sizeof(type));
243	io_simple_buffer(b, &id, sizeof(id));
244	io_str_buffer(b, local);
245	io_str_buffer(b, uri);
246	io_str_buffer(b, s->session_id);
247	io_simple_buffer(b, &s->serial, sizeof(s->serial));
248	io_str_buffer(b, s->last_mod);
249	ibuf_close(&rrdpq, b);
250}
251
252/*
253 * Request a repository sync via rsync URI to directory local.
254 */
255void
256rsync_fetch(size_t id, const char *uri, const char *local)
257{
258	struct ibuf	*b;
259
260	if ((b = ibuf_dynamic(256, UINT_MAX)) == NULL)
261		err(1, NULL);
262	io_simple_buffer(b, &id, sizeof(id));
263	io_str_buffer(b, local);
264	io_str_buffer(b, uri);
265	ibuf_close(&rsyncq, b);
266}
267
268/*
269 * Request a file from a https uri, data is written to the file descriptor fd.
270 */
271void
272http_fetch(size_t id, const char *uri, const char *last_mod, int fd)
273{
274	struct ibuf	*b;
275
276	if ((b = ibuf_dynamic(256, UINT_MAX)) == NULL)
277		err(1, NULL);
278	io_simple_buffer(b, &id, sizeof(id));
279	io_str_buffer(b, uri);
280	io_str_buffer(b, last_mod);
281	/* pass file as fd */
282	b->fd = fd;
283	ibuf_close(&httpq, b);
284}
285
286/*
287 * Request some XML file on behalf of the rrdp parser.
288 * Create a pipe and pass the pipe endpoints to the http and rrdp process.
289 */
290static void
291rrdp_http_fetch(size_t id, const char *uri, const char *last_mod)
292{
293	enum rrdp_msg type = RRDP_HTTP_INI;
294	struct ibuf *b;
295	int pi[2];
296
297	if (pipe2(pi, O_CLOEXEC | O_NONBLOCK) == -1)
298		err(1, "pipe");
299
300	if ((b = ibuf_open(sizeof(type) + sizeof(id))) == NULL)
301		err(1, NULL);
302	io_simple_buffer(b, &type, sizeof(type));
303	io_simple_buffer(b, &id, sizeof(id));
304	b->fd = pi[0];
305	ibuf_close(&rrdpq, b);
306
307	http_fetch(id, uri, last_mod, pi[1]);
308}
309
310void
311rrdp_http_done(size_t id, enum http_result res, const char *last_mod)
312{
313	enum rrdp_msg type = RRDP_HTTP_FIN;
314	struct ibuf *b;
315
316	/* RRDP request, relay response over to the rrdp process */
317	if ((b = ibuf_dynamic(256, UINT_MAX)) == NULL)
318		err(1, NULL);
319	io_simple_buffer(b, &type, sizeof(type));
320	io_simple_buffer(b, &id, sizeof(id));
321	io_simple_buffer(b, &res, sizeof(res));
322	io_str_buffer(b, last_mod);
323	ibuf_close(&rrdpq, b);
324}
325
326/*
327 * Add a file (CER, ROA, CRL) from an MFT file, RFC 6486.
328 * These are always relative to the directory in which "mft" sits.
329 */
330static void
331queue_add_from_mft(const char *mft, const struct mftfile *file, enum rtype type)
332{
333	char		*cp, *nfile;
334
335	/* Construct local path from filename. */
336	cp = strrchr(mft, '/');
337	assert(cp != NULL);
338	assert(cp - mft < INT_MAX);
339	if (asprintf(&nfile, "%.*s/%s", (int)(cp - mft), mft, file->file) == -1)
340		err(1, NULL);
341
342	/*
343	 * Since we're from the same directory as the MFT file, we know
344	 * that the repository has already been loaded.
345	 */
346
347	entityq_add(nfile, type, NULL, NULL, 0, NULL);
348}
349
350/*
351 * Loops over queue_add_from_mft() for all files.
352 * The order here is important: we want to parse the revocation
353 * list *before* we parse anything else.
354 * FIXME: set the type of file in the mftfile so that we don't need to
355 * keep doing the check (this should be done in the parser, where we
356 * check the suffix anyway).
357 */
358static void
359queue_add_from_mft_set(const struct mft *mft)
360{
361	size_t			 i, sz;
362	const struct mftfile	*f;
363
364	for (i = 0; i < mft->filesz; i++) {
365		f = &mft->files[i];
366		sz = strlen(f->file);
367		assert(sz > 4);
368		if (strcasecmp(f->file + sz - 4, ".crl") != 0)
369			continue;
370		queue_add_from_mft(mft->file, f, RTYPE_CRL);
371	}
372
373	for (i = 0; i < mft->filesz; i++) {
374		f = &mft->files[i];
375		sz = strlen(f->file);
376		assert(sz > 4);
377		if (strcasecmp(f->file + sz - 4, ".crl") == 0)
378			continue;
379		else if (strcasecmp(f->file + sz - 4, ".cer") == 0)
380			queue_add_from_mft(mft->file, f, RTYPE_CER);
381		else if (strcasecmp(f->file + sz - 4, ".roa") == 0)
382			queue_add_from_mft(mft->file, f, RTYPE_ROA);
383		else if (strcasecmp(f->file + sz - 4, ".gbr") == 0)
384			queue_add_from_mft(mft->file, f, RTYPE_GBR);
385		else
386			logx("%s: unsupported file type: %s", mft->file,
387			    f->file);
388	}
389}
390
391/*
392 * Add a local TAL file (RFC 7730) to the queue of files to fetch.
393 */
394static void
395queue_add_tal(const char *file)
396{
397	char	*nfile, *buf;
398
399	if ((nfile = strdup(file)) == NULL)
400		err(1, NULL);
401	buf = tal_read_file(file);
402
403	/* Record tal for later reporting */
404	if (stats.talnames == NULL) {
405		if ((stats.talnames = strdup(file)) == NULL)
406			err(1, NULL);
407	} else {
408		char *tmp;
409
410		if (asprintf(&tmp, "%s %s", stats.talnames, file) == -1)
411			err(1, NULL);
412		free(stats.talnames);
413		stats.talnames = tmp;
414	}
415
416	/* Not in a repository, so directly add to queue. */
417	entityq_add(nfile, RTYPE_TAL, NULL, NULL, 0, buf);
418	/* entityq_add makes a copy of buf */
419	free(buf);
420}
421
422/*
423 * Add URIs (CER) from a TAL file, RFC 8630.
424 */
425static void
426queue_add_from_tal(struct tal *tal)
427{
428	struct repo	*repo;
429
430	assert(tal->urisz);
431
432	/* Look up the repository. */
433	repo = ta_lookup(tal);
434
435	entityq_add(NULL, RTYPE_CER, repo, tal->pkey,
436	    tal->pkeysz, tal->descr);
437}
438
439/*
440 * Add a manifest (MFT) found in an X509 certificate, RFC 6487.
441 */
442static void
443queue_add_from_cert(const struct cert *cert)
444{
445	struct repo	*repo;
446	char		*nfile;
447
448	repo = repo_lookup(cert->repo, rrdpon ? cert->notify : NULL);
449	if (repo == NULL) {
450		warnx("%s: repository lookup failed", cert->repo);
451		return;
452	}
453
454	if ((nfile = strdup(cert->mft)) == NULL)
455		err(1, NULL);
456	entityq_add(nfile, RTYPE_MFT, repo, NULL, 0, NULL);
457}
458
459/*
460 * Process parsed content.
461 * For non-ROAs, we grok for more data.
462 * For ROAs, we want to extract the valid info.
463 * In all cases, we gather statistics.
464 */
465static void
466entity_process(int proc, struct stats *st, struct vrp_tree *tree)
467{
468	enum rtype	type;
469	struct tal	*tal;
470	struct cert	*cert;
471	struct mft	*mft;
472	struct roa	*roa;
473	int		 c;
474
475	/*
476	 * For most of these, we first read whether there's any content
477	 * at all---this means that the syntactic parse failed (X509
478	 * certificate, for example).
479	 * We follow that up with whether the resources didn't parse.
480	 */
481	io_simple_read(proc, &type, sizeof(type));
482
483	switch (type) {
484	case RTYPE_TAL:
485		st->tals++;
486		tal = tal_read(proc);
487		queue_add_from_tal(tal);
488		tal_free(tal);
489		break;
490	case RTYPE_CER:
491		st->certs++;
492		io_simple_read(proc, &c, sizeof(int));
493		if (c == 0) {
494			st->certs_fail++;
495			break;
496		}
497		cert = cert_read(proc);
498		if (cert->valid) {
499			/*
500			 * Process the revocation list from the
501			 * certificate *first*, since it might mark that
502			 * we're revoked and then we don't want to
503			 * process the MFT.
504			 */
505			queue_add_from_cert(cert);
506		} else
507			st->certs_invalid++;
508		cert_free(cert);
509		break;
510	case RTYPE_MFT:
511		st->mfts++;
512		io_simple_read(proc, &c, sizeof(int));
513		if (c == 0) {
514			st->mfts_fail++;
515			break;
516		}
517		mft = mft_read(proc);
518		if (mft->stale)
519			st->mfts_stale++;
520		queue_add_from_mft_set(mft);
521		mft_free(mft);
522		break;
523	case RTYPE_CRL:
524		st->crls++;
525		break;
526	case RTYPE_ROA:
527		st->roas++;
528		io_simple_read(proc, &c, sizeof(int));
529		if (c == 0) {
530			st->roas_fail++;
531			break;
532		}
533		roa = roa_read(proc);
534		if (roa->valid)
535			roa_insert_vrps(tree, roa, &st->vrps, &st->uniqs);
536		else
537			st->roas_invalid++;
538		roa_free(roa);
539		break;
540	case RTYPE_GBR:
541		st->gbrs++;
542		break;
543	default:
544		errx(1, "unknown entity type");
545	}
546
547	entity_queue--;
548}
549
550/*
551 * Assign filenames ending in ".tal" in "/etc/rpki" into "tals",
552 * returning the number of files found and filled-in.
553 * This may be zero.
554 * Don't exceded "max" filenames.
555 */
556static size_t
557tal_load_default(const char *tals[], size_t max)
558{
559	static const char *confdir = "/etc/rpki";
560	size_t s = 0;
561	char *path;
562	DIR *dirp;
563	struct dirent *dp;
564
565	dirp = opendir(confdir);
566	if (dirp == NULL)
567		err(1, "open %s", confdir);
568	while ((dp = readdir(dirp)) != NULL) {
569		if (fnmatch("*.tal", dp->d_name, FNM_PERIOD) == FNM_NOMATCH)
570			continue;
571		if (s >= max)
572			err(1, "too many tal files found in %s",
573			    confdir);
574		if (asprintf(&path, "%s/%s", confdir, dp->d_name) == -1)
575			err(1, NULL);
576		tals[s++] = path;
577	}
578	closedir(dirp);
579	return s;
580}
581
582void
583suicide(int sig __attribute__((unused)))
584{
585	killme = 1;
586}
587
588#define NPFD	4
589
590int
591main(int argc, char *argv[])
592{
593	int		 rc, c, st, proc, rsync, http, rrdp, ok,
594			 hangup = 0, fl = SOCK_STREAM | SOCK_CLOEXEC;
595	size_t		 i, id, outsz = 0, talsz = 0;
596	pid_t		 pid, procpid, rsyncpid, httppid, rrdppid;
597	int		 fd[2];
598	struct pollfd	 pfd[NPFD];
599	struct msgbuf	*queues[NPFD];
600	struct roa	**out = NULL;
601	char		*rsync_prog = "openrsync";
602	char		*bind_addr = NULL;
603	const char	*cachedir = NULL, *outputdir = NULL;
604	const char	*tals[TALSZ_MAX], *errs, *name;
605	struct vrp_tree	 v = RB_INITIALIZER(&v);
606	struct rusage	ru;
607	struct timeval	start_time, now_time;
608
609	gettimeofday(&start_time, NULL);
610
611	/* If started as root, priv-drop to _rpki-client */
612	if (getuid() == 0) {
613		struct passwd *pw;
614
615		pw = getpwnam("_rpki-client");
616		if (!pw)
617			errx(1, "no _rpki-client user to revoke to");
618		if (setgroups(1, &pw->pw_gid) == -1 ||
619		    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 ||
620		    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
621			err(1, "unable to revoke privs");
622	}
623	cachedir = RPKI_PATH_BASE_DIR;
624	outputdir = RPKI_PATH_OUT_DIR;
625
626	if (pledge("stdio rpath wpath cpath inet fattr dns sendfd recvfd "
627	    "proc exec unveil", NULL) == -1)
628		err(1, "pledge");
629
630	while ((c = getopt(argc, argv, "b:Bcd:e:jnorRs:t:T:vV")) != -1)
631		switch (c) {
632		case 'b':
633			bind_addr = optarg;
634			break;
635		case 'B':
636			outformats |= FORMAT_BIRD;
637			break;
638		case 'c':
639			outformats |= FORMAT_CSV;
640			break;
641		case 'd':
642			cachedir = optarg;
643			break;
644		case 'e':
645			rsync_prog = optarg;
646			break;
647		case 'j':
648			outformats |= FORMAT_JSON;
649			break;
650		case 'n':
651			noop = 1;
652			break;
653		case 'o':
654			outformats |= FORMAT_OPENBGPD;
655			break;
656		case 'R':
657			rrdpon = 0;
658			break;
659		case 'r':
660			rrdpon = 1;
661			break;
662		case 's':
663			timeout = strtonum(optarg, 0, 24*60*60, &errs);
664			if (errs)
665				errx(1, "-s: %s", errs);
666			break;
667		case 't':
668			if (talsz >= TALSZ_MAX)
669				err(1,
670				    "too many tal files specified");
671			tals[talsz++] = optarg;
672			break;
673		case 'T':
674			bird_tablename = optarg;
675			break;
676		case 'v':
677			verbose++;
678			break;
679		case 'V':
680			fprintf(stderr, "rpki-client %s\n", RPKI_VERSION);
681			return 0;
682		default:
683			goto usage;
684		}
685
686	argv += optind;
687	argc -= optind;
688	if (argc == 1)
689		outputdir = argv[0];
690	else if (argc > 1)
691		goto usage;
692
693	signal(SIGPIPE, SIG_IGN);
694
695	if (timeout) {
696		signal(SIGALRM, suicide);
697		/* Commit suicide eventually - cron will normally start a new one */
698		alarm(timeout);
699	}
700
701	if (cachedir == NULL) {
702		warnx("cache directory required");
703		goto usage;
704	}
705	if (outputdir == NULL) {
706		warnx("output directory required");
707		goto usage;
708	}
709
710	if ((cachefd = open(cachedir, O_RDONLY, 0)) == -1)
711		err(1, "cache directory %s", cachedir);
712	if ((outdirfd = open(outputdir, O_RDONLY, 0)) == -1)
713		err(1, "output directory %s", outputdir);
714
715	if (outformats == 0)
716		outformats = FORMAT_OPENBGPD;
717
718	if (talsz == 0)
719		talsz = tal_load_default(tals, TALSZ_MAX);
720	if (talsz == 0)
721		err(1, "no TAL files found in %s", "/etc/rpki");
722
723	/*
724	 * Create the file reader as a jailed child process.
725	 * It will be responsible for reading all of the files (ROAs,
726	 * manifests, certificates, etc.) and returning contents.
727	 */
728
729	if (socketpair(AF_UNIX, fl, 0, fd) == -1)
730		err(1, "socketpair");
731	if ((procpid = fork()) == -1)
732		err(1, "fork");
733
734	if (procpid == 0) {
735		close(fd[1]);
736
737		setproctitle("parser");
738		/* change working directory to the cache directory */
739		if (fchdir(cachefd) == -1)
740			err(1, "fchdir");
741
742		/* Only allow access to the cache directory. */
743		if (unveil(".", "r") == -1)
744			err(1, "%s: unveil", cachedir);
745		if (pledge("stdio rpath", NULL) == -1)
746			err(1, "pledge");
747		proc_parser(fd[0]);
748		errx(1, "parser process returned");
749	}
750
751	close(fd[0]);
752	proc = fd[1];
753
754	/*
755	 * Create a process that will do the rsync'ing.
756	 * This process is responsible for making sure that all the
757	 * repositories referenced by a certificate manifest (or the
758	 * TAL) exists and has been downloaded.
759	 */
760
761	if (!noop) {
762		if (socketpair(AF_UNIX, fl, 0, fd) == -1)
763			err(1, "socketpair");
764		if ((rsyncpid = fork()) == -1)
765			err(1, "fork");
766
767		if (rsyncpid == 0) {
768			close(proc);
769			close(fd[1]);
770
771			setproctitle("rsync");
772			/* change working directory to the cache directory */
773			if (fchdir(cachefd) == -1)
774				err(1, "fchdir");
775
776			if (pledge("stdio rpath proc exec unveil", NULL) == -1)
777				err(1, "pledge");
778
779			proc_rsync(rsync_prog, bind_addr, fd[0]);
780			errx(1, "rsync process returned");
781		}
782
783		close(fd[0]);
784		rsync = fd[1];
785	} else {
786		rsync = -1;
787		rsyncpid = -1;
788	}
789
790	/*
791	 * Create a process that will fetch data via https.
792	 * With every request the http process receives a file descriptor
793	 * where the data should be written to.
794	 */
795
796	if (!noop) {
797		if (socketpair(AF_UNIX, fl, 0, fd) == -1)
798			err(1, "socketpair");
799		if ((httppid = fork()) == -1)
800			err(1, "fork");
801
802		if (httppid == 0) {
803			close(proc);
804			close(rsync);
805			close(fd[1]);
806
807			setproctitle("http");
808			/* change working directory to the cache directory */
809			if (fchdir(cachefd) == -1)
810				err(1, "fchdir");
811
812			if (pledge("stdio rpath inet dns recvfd", NULL) == -1)
813				err(1, "pledge");
814
815			proc_http(bind_addr, fd[0]);
816			errx(1, "http process returned");
817		}
818
819		close(fd[0]);
820		http = fd[1];
821	} else {
822		http = -1;
823		httppid = -1;
824	}
825
826	/*
827	 * Create a process that will process RRDP.
828	 * The rrdp process requires the http process to fetch the various
829	 * XML files and does this via the main process.
830	 */
831
832	if (!noop && rrdpon) {
833		if (socketpair(AF_UNIX, fl, 0, fd) == -1)
834			err(1, "socketpair");
835		if ((rrdppid = fork()) == -1)
836			err(1, "fork");
837
838		if (rrdppid == 0) {
839			close(proc);
840			close(rsync);
841			close(http);
842			close(fd[1]);
843
844			setproctitle("rrdp");
845			/* change working directory to the cache directory */
846			if (fchdir(cachefd) == -1)
847				err(1, "fchdir");
848
849			if (pledge("stdio recvfd", NULL) == -1)
850				err(1, "pledge");
851
852			proc_rrdp(fd[0]);
853			/* NOTREACHED */
854		}
855
856		close(fd[0]);
857		rrdp = fd[1];
858	} else
859		rrdp = -1;
860
861	/* TODO unveil cachedir and outputdir, no other access allowed */
862	if (pledge("stdio rpath wpath cpath fattr sendfd", NULL) == -1)
863		err(1, "pledge");
864
865	msgbuf_init(&procq);
866	msgbuf_init(&rsyncq);
867	msgbuf_init(&httpq);
868	msgbuf_init(&rrdpq);
869	procq.fd = proc;
870	rsyncq.fd = rsync;
871	httpq.fd = http;
872	rrdpq.fd = rrdp;
873
874	/*
875	 * The main process drives the top-down scan to leaf ROAs using
876	 * data downloaded by the rsync process and parsed by the
877	 * parsing process.
878	 */
879
880	pfd[0].fd = proc;
881	queues[0] = &procq;
882	pfd[1].fd = rsync;
883	queues[1] = &rsyncq;
884	pfd[2].fd = http;
885	queues[2] = &httpq;
886	pfd[3].fd = rrdp;
887	queues[3] = &rrdpq;
888
889	/*
890	 * Prime the process with our TAL file.
891	 * This will contain (hopefully) links to our manifest and we
892	 * can get the ball rolling.
893	 */
894
895	for (i = 0; i < talsz; i++)
896		queue_add_tal(tals[i]);
897
898	/* change working directory to the cache directory */
899	if (fchdir(cachefd) == -1)
900		err(1, "fchdir");
901
902	while (entity_queue > 0 && !killme) {
903		for (i = 0; i < NPFD; i++) {
904			pfd[i].events = POLLIN;
905			if (queues[i]->queued)
906				pfd[i].events |= POLLOUT;
907		}
908
909		if ((c = poll(pfd, NPFD, INFTIM)) == -1) {
910			if (errno == EINTR)
911				continue;
912			err(1, "poll");
913		}
914
915		for (i = 0; i < NPFD; i++) {
916			if (pfd[i].revents & (POLLERR|POLLNVAL))
917				errx(1, "poll[%zu]: bad fd", i);
918			if (pfd[i].revents & POLLHUP) {
919				warnx("poll[%zu]: hangup", i);
920				hangup = 1;
921			}
922			if (pfd[i].revents & POLLOUT) {
923				/*
924				 * XXX work around deadlocks because of
925				 * blocking read vs non-blocking writes.
926				 */
927				if (i > 1)
928					io_socket_nonblocking(pfd[i].fd);
929				switch (msgbuf_write(queues[i])) {
930				case 0:
931					errx(1, "write[%zu]: "
932					    "connection closed", i);
933				case -1:
934					err(1, "write[%zu]", i);
935				}
936				if (i > 1)
937					io_socket_blocking(pfd[i].fd);
938			}
939		}
940		if (hangup)
941			break;
942
943		/*
944		 * Check the rsync and http process.
945		 * This means that one of our modules has completed
946		 * downloading and we can flush the module requests into
947		 * the parser process.
948		 */
949
950		if ((pfd[1].revents & POLLIN)) {
951			io_simple_read(rsync, &id, sizeof(id));
952			io_simple_read(rsync, &ok, sizeof(ok));
953			rsync_finish(id, ok);
954		}
955
956		if ((pfd[2].revents & POLLIN)) {
957			enum http_result res;
958			char *last_mod;
959
960			io_simple_read(http, &id, sizeof(id));
961			io_simple_read(http, &res, sizeof(res));
962			io_str_read(http, &last_mod);
963			http_finish(id, res, last_mod);
964			free(last_mod);
965		}
966
967		/*
968		 * Handle RRDP requests here.
969		 */
970		if ((pfd[3].revents & POLLIN)) {
971			enum rrdp_msg type;
972			enum publish_type pt;
973			struct rrdp_session s;
974			char *uri, *last_mod, *data;
975			char hash[SHA256_DIGEST_LENGTH];
976			size_t dsz;
977
978			io_simple_read(rrdp, &type, sizeof(type));
979			io_simple_read(rrdp, &id, sizeof(id));
980
981			switch (type) {
982			case RRDP_END:
983				io_simple_read(rrdp, &ok, sizeof(ok));
984				rrdp_finish(id, ok);
985				break;
986			case RRDP_HTTP_REQ:
987				io_str_read(rrdp, &uri);
988				io_str_read(rrdp, &last_mod);
989				rrdp_http_fetch(id, uri, last_mod);
990				break;
991			case RRDP_SESSION:
992				io_str_read(rrdp, &s.session_id);
993				io_simple_read(rrdp, &s.serial,
994				    sizeof(s.serial));
995				io_str_read(rrdp, &s.last_mod);
996				rrdp_save_state(id, &s);
997				free(s.session_id);
998				free(s.last_mod);
999				break;
1000			case RRDP_FILE:
1001				io_simple_read(rrdp, &pt, sizeof(pt));
1002				if (pt != PUB_ADD)
1003					io_simple_read(rrdp, &hash,
1004					    sizeof(hash));
1005				io_str_read(rrdp, &uri);
1006				io_buf_read_alloc(rrdp, (void **)&data, &dsz);
1007
1008				ok = rrdp_handle_file(id, pt, uri,
1009				    hash, sizeof(hash), data, dsz);
1010				rrdp_file_resp(id, ok);
1011
1012				free(uri);
1013				free(data);
1014				break;
1015			default:
1016				errx(1, "unexpected rrdp response");
1017			}
1018		}
1019
1020		/*
1021		 * The parser has finished something for us.
1022		 * Dequeue these one by one.
1023		 */
1024
1025		if ((pfd[0].revents & POLLIN)) {
1026			entity_process(proc, &stats, &v);
1027		}
1028	}
1029
1030	if (killme) {
1031		syslog(LOG_CRIT|LOG_DAEMON,
1032		    "excessive runtime (%d seconds), giving up", timeout);
1033		errx(1, "excessive runtime (%d seconds), giving up", timeout);
1034	}
1035
1036	/*
1037	 * For clean-up, close the input for the parser and rsync
1038	 * process.
1039	 * This will cause them to exit, then we reap them.
1040	 */
1041
1042	close(proc);
1043	close(rsync);
1044	close(http);
1045	close(rrdp);
1046
1047	rc = 0;
1048	for (;;) {
1049		pid = waitpid(WAIT_ANY, &st, 0);
1050		if (pid == -1) {
1051			if (errno == EINTR)
1052				continue;
1053			if (errno == ECHILD)
1054				break;
1055			err(1, "wait");
1056		}
1057
1058		if (pid == procpid)
1059			name = "parser";
1060		else if (pid == rsyncpid)
1061			name = "rsync";
1062		else if (pid == httppid)
1063			name = "http";
1064		else if (pid == rrdppid)
1065			name = "rrdp";
1066		else
1067			name = "unknown";
1068
1069		if (WIFSIGNALED(st)) {
1070			warnx("%s terminated signal %d", name, WTERMSIG(st));
1071			rc = 1;
1072		} else if (!WIFEXITED(st) || WEXITSTATUS(st) != 0) {
1073			warnx("%s process exited abnormally", name);
1074			rc = 1;
1075		}
1076	}
1077
1078	/* processing did not finish because of error */
1079	if (entity_queue != 0)
1080		return 1;
1081
1082	logx("all files parsed: generating output");
1083
1084	repo_cleanup(&fpt);
1085
1086	gettimeofday(&now_time, NULL);
1087	timersub(&now_time, &start_time, &stats.elapsed_time);
1088	if (getrusage(RUSAGE_SELF, &ru) == 0) {
1089		stats.user_time = ru.ru_utime;
1090		stats.system_time = ru.ru_stime;
1091	}
1092	if (getrusage(RUSAGE_CHILDREN, &ru) == 0) {
1093		timeradd(&stats.user_time, &ru.ru_utime, &stats.user_time);
1094		timeradd(&stats.system_time, &ru.ru_stime, &stats.system_time);
1095	}
1096
1097	/* change working directory to the output directory */
1098	if (fchdir(outdirfd) == -1)
1099		err(1, "fchdir output dir");
1100
1101	if (outputfiles(&v, &stats))
1102		rc = 1;
1103
1104
1105	logx("Route Origin Authorizations: %zu (%zu failed parse, %zu invalid)",
1106	    stats.roas, stats.roas_fail, stats.roas_invalid);
1107	logx("Certificates: %zu (%zu failed parse, %zu invalid)",
1108	    stats.certs, stats.certs_fail, stats.certs_invalid);
1109	logx("Trust Anchor Locators: %zu", stats.tals);
1110	logx("Manifests: %zu (%zu failed parse, %zu stale)",
1111	    stats.mfts, stats.mfts_fail, stats.mfts_stale);
1112	logx("Certificate revocation lists: %zu", stats.crls);
1113	logx("Ghostbuster records: %zu", stats.gbrs);
1114	logx("Repositories: %zu", stats.repos);
1115	logx("Cleanup: removed %zu files, %zu directories",
1116	    stats.del_files, stats.del_dirs);
1117	logx("VRP Entries: %zu (%zu unique)", stats.vrps, stats.uniqs);
1118
1119	/* Memory cleanup. */
1120	repo_free();
1121
1122	for (i = 0; i < outsz; i++)
1123		roa_free(out[i]);
1124	free(out);
1125
1126	return rc;
1127
1128usage:
1129	fprintf(stderr,
1130	    "usage: rpki-client [-BcjnoRrVv] [-b sourceaddr] [-d cachedir]"
1131	    " [-e rsync_prog]\n"
1132	    "                   [-s timeout] [-T table] [-t tal]"
1133	    " [outputdir]\n");
1134	return 1;
1135}
1136