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