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