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