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