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