xref: /openbsd-src/usr.sbin/rpki-client/main.c (revision d5abdd01d7a5f24fb6f9b0aab446ef59a9e9067a)
1 /*	$OpenBSD: main.c,v 1.241 2023/05/30 16:02:28 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_buffer_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(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 	io_str_buffer(b, s->session_id);
284 	io_simple_buffer(b, &s->serial, sizeof(s->serial));
285 	io_str_buffer(b, s->last_mod);
286 	io_close_buffer(&rrdpq, b);
287 }
288 
289 void
290 rrdp_abort(unsigned int id)
291 {
292 	enum rrdp_msg type = RRDP_ABORT;
293 	struct ibuf *b;
294 
295 	b = io_new_buffer();
296 	io_simple_buffer(b, &type, sizeof(type));
297 	io_simple_buffer(b, &id, sizeof(id));
298 	io_close_buffer(&rrdpq, b);
299 }
300 
301 /*
302  * Request a repository sync via rsync URI to directory local.
303  */
304 void
305 rsync_fetch(unsigned int id, const char *uri, const char *local,
306     const char *base)
307 {
308 	struct ibuf	*b;
309 
310 	b = io_new_buffer();
311 	io_simple_buffer(b, &id, sizeof(id));
312 	io_str_buffer(b, local);
313 	io_str_buffer(b, base);
314 	io_str_buffer(b, uri);
315 	io_close_buffer(&rsyncq, b);
316 }
317 
318 void
319 rsync_abort(unsigned int id)
320 {
321 	struct ibuf	*b;
322 
323 	b = io_new_buffer();
324 	io_simple_buffer(b, &id, sizeof(id));
325 	io_str_buffer(b, NULL);
326 	io_str_buffer(b, NULL);
327 	io_str_buffer(b, NULL);
328 	io_close_buffer(&rsyncq, b);
329 }
330 
331 /*
332  * Request a file from a https uri, data is written to the file descriptor fd.
333  */
334 void
335 http_fetch(unsigned int id, const char *uri, const char *last_mod, int fd)
336 {
337 	struct ibuf	*b;
338 
339 	b = io_new_buffer();
340 	io_simple_buffer(b, &id, sizeof(id));
341 	io_str_buffer(b, uri);
342 	io_str_buffer(b, last_mod);
343 	/* pass file as fd */
344 	b->fd = fd;
345 	io_close_buffer(&httpq, b);
346 }
347 
348 /*
349  * Request some XML file on behalf of the rrdp parser.
350  * Create a pipe and pass the pipe endpoints to the http and rrdp process.
351  */
352 static void
353 rrdp_http_fetch(unsigned int id, const char *uri, const char *last_mod)
354 {
355 	enum rrdp_msg type = RRDP_HTTP_INI;
356 	struct ibuf *b;
357 	int pi[2];
358 
359 	if (pipe2(pi, O_CLOEXEC | O_NONBLOCK) == -1)
360 		err(1, "pipe");
361 
362 	b = io_new_buffer();
363 	io_simple_buffer(b, &type, sizeof(type));
364 	io_simple_buffer(b, &id, sizeof(id));
365 	b->fd = pi[0];
366 	io_close_buffer(&rrdpq, b);
367 
368 	http_fetch(id, uri, last_mod, pi[1]);
369 }
370 
371 void
372 rrdp_http_done(unsigned int id, enum http_result res, const char *last_mod)
373 {
374 	enum rrdp_msg type = RRDP_HTTP_FIN;
375 	struct ibuf *b;
376 
377 	/* RRDP request, relay response over to the rrdp process */
378 	b = io_new_buffer();
379 	io_simple_buffer(b, &type, sizeof(type));
380 	io_simple_buffer(b, &id, sizeof(id));
381 	io_simple_buffer(b, &res, sizeof(res));
382 	io_str_buffer(b, last_mod);
383 	io_close_buffer(&rrdpq, b);
384 }
385 
386 /*
387  * Add a file (CER, ROA, CRL) from an MFT file, RFC 6486.
388  * These are always relative to the directory in which "mft" sits.
389  */
390 static void
391 queue_add_from_mft(const struct mft *mft)
392 {
393 	size_t			 i;
394 	struct repo		*rp;
395 	const struct mftfile	*f;
396 	char			*mftaki, *nfile, *npath = NULL;
397 
398 	rp = repo_byid(mft->repoid);
399 	for (i = 0; i < mft->filesz; i++) {
400 		f = &mft->files[i];
401 
402 		if (f->type == RTYPE_INVALID || f->type == RTYPE_CRL)
403 			continue;
404 
405 		if (mft->path != NULL)
406 			if ((npath = strdup(mft->path)) == NULL)
407 				err(1, NULL);
408 		if ((nfile = strdup(f->file)) == NULL)
409 			err(1, NULL);
410 		if ((mftaki = strdup(mft->aki)) == NULL)
411 			err(1, NULL);
412 		entityq_add(npath, nfile, f->type, f->location, rp, NULL, 0,
413 		    mft->talid, mftaki);
414 	}
415 }
416 
417 /*
418  * Add a local file to the queue of files to fetch.
419  */
420 static void
421 queue_add_file(const char *file, enum rtype type, int talid)
422 {
423 	unsigned char	*buf = NULL;
424 	char		*nfile;
425 	size_t		 len = 0;
426 
427 	if (!filemode || strncmp(file, "rsync://", strlen("rsync://")) != 0) {
428 		buf = load_file(file, &len);
429 		if (buf == NULL)
430 			err(1, "%s", file);
431 	}
432 
433 	if ((nfile = strdup(file)) == NULL)
434 		err(1, NULL);
435 	/* Not in a repository, so directly add to queue. */
436 	entityq_add(NULL, nfile, type, DIR_UNKNOWN, NULL, buf, len, talid,
437 	    NULL);
438 }
439 
440 /*
441  * Add URIs (CER) from a TAL file, RFC 8630.
442  */
443 static void
444 queue_add_from_tal(struct tal *tal)
445 {
446 	struct repo	*repo;
447 	unsigned char	*data;
448 	char		*nfile;
449 
450 	assert(tal->urisz);
451 
452 	if ((taldescs[tal->id] = strdup(tal->descr)) == NULL)
453 		err(1, NULL);
454 
455 	/* figure out the TA filename, must be done before repo lookup */
456 	nfile = strrchr(tal->uri[0], '/');
457 	assert(nfile != NULL);
458 	if ((nfile = strdup(nfile + 1)) == NULL)
459 		err(1, NULL);
460 
461 	/* Look up the repository. */
462 	repo = ta_lookup(tal->id, tal);
463 	if (repo == NULL) {
464 		free(nfile);
465 		return;
466 	}
467 
468 	/* steal the pkey from the tal structure */
469 	data = tal->pkey;
470 	tal->pkey = NULL;
471 	entityq_add(NULL, nfile, RTYPE_CER, DIR_VALID, repo, data,
472 	    tal->pkeysz, tal->id, NULL);
473 }
474 
475 /*
476  * Add a manifest (MFT) found in an X509 certificate, RFC 6487.
477  */
478 static void
479 queue_add_from_cert(const struct cert *cert)
480 {
481 	struct repo		*repo;
482 	struct fqdnlistentry	*le;
483 	char			*nfile, *npath, *host;
484 	const char		*uri, *repouri, *file;
485 	size_t			 repourisz;
486 	int			 shortlisted = 0;
487 
488 	if (strncmp(cert->repo, "rsync://", 8) != 0)
489 		errx(1, "unexpected protocol");
490 	host = cert->repo + 8;
491 
492 	LIST_FOREACH(le, &skiplist, entry) {
493 		if (strncasecmp(host, le->fqdn, strcspn(host, "/")) == 0) {
494 			warnx("skipping %s (listed in skiplist)", cert->repo);
495 			return;
496 		}
497 	}
498 
499 	LIST_FOREACH(le, &shortlist, entry) {
500 		if (strncasecmp(host, le->fqdn, strcspn(host, "/")) == 0) {
501 			shortlisted = 1;
502 			break;
503 		}
504 	}
505 	if (shortlistmode && shortlisted == 0) {
506 		if (verbose)
507 			warnx("skipping %s (not shortlisted)", cert->repo);
508 		return;
509 	}
510 
511 	repo = repo_lookup(cert->talid, cert->repo,
512 	    rrdpon ? cert->notify : NULL);
513 	if (repo == NULL)
514 		return;
515 
516 	/*
517 	 * Figure out the cert filename and path by chopping up the
518 	 * MFT URI in the cert based on the repo base URI.
519 	 */
520 	uri = cert->mft;
521 	repouri = repo_uri(repo);
522 	repourisz = strlen(repouri);
523 	if (strncmp(repouri, cert->mft, repourisz) != 0) {
524 		warnx("%s: URI %s outside of repository", repouri, uri);
525 		return;
526 	}
527 	uri += repourisz + 1;	/* skip base and '/' */
528 	file = strrchr(uri, '/');
529 	if (file == NULL) {
530 		npath = NULL;
531 		if ((nfile = strdup(uri)) == NULL)
532 			err(1, NULL);
533 	} else {
534 		if ((npath = strndup(uri, file - uri)) == NULL)
535 			err(1, NULL);
536 		if ((nfile = strdup(file + 1)) == NULL)
537 			err(1, NULL);
538 	}
539 
540 	entityq_add(npath, nfile, RTYPE_MFT, DIR_UNKNOWN, repo, NULL, 0,
541 	    cert->talid, NULL);
542 }
543 
544 /*
545  * Process parsed content.
546  * For non-ROAs, we grok for more data.
547  * For ROAs, we want to extract the valid info.
548  * In all cases, we gather statistics.
549  */
550 static void
551 entity_process(struct ibuf *b, struct stats *st, struct vrp_tree *tree,
552     struct brk_tree *brktree, struct vap_tree *vaptree)
553 {
554 	enum rtype	 type;
555 	struct tal	*tal;
556 	struct cert	*cert;
557 	struct mft	*mft;
558 	struct roa	*roa;
559 	struct aspa	*aspa;
560 	struct repo	*rp;
561 	char		*file;
562 	time_t		 mtime;
563 	unsigned int	 id;
564 	int		 talid;
565 	int		 c;
566 
567 	/*
568 	 * For most of these, we first read whether there's any content
569 	 * at all---this means that the syntactic parse failed (X509
570 	 * certificate, for example).
571 	 * We follow that up with whether the resources didn't parse.
572 	 */
573 	io_read_buf(b, &type, sizeof(type));
574 	io_read_buf(b, &id, sizeof(id));
575 	io_read_buf(b, &talid, sizeof(talid));
576 	io_read_str(b, &file);
577 	io_read_buf(b, &mtime, sizeof(mtime));
578 
579 	/* in filemode messages can be ignored, only the accounting matters */
580 	if (filemode)
581 		goto done;
582 
583 	if (filepath_add(&fpt, file, mtime) == 0) {
584 		warnx("%s: File already visited", file);
585 		goto done;
586 	}
587 
588 	rp = repo_byid(id);
589 	repo_stat_inc(rp, talid, type, STYPE_OK);
590 	switch (type) {
591 	case RTYPE_TAL:
592 		st->tals++;
593 		tal = tal_read(b);
594 		queue_add_from_tal(tal);
595 		tal_free(tal);
596 		break;
597 	case RTYPE_CER:
598 		io_read_buf(b, &c, sizeof(c));
599 		if (c == 0) {
600 			repo_stat_inc(rp, talid, type, STYPE_FAIL);
601 			break;
602 		}
603 		cert = cert_read(b);
604 		switch (cert->purpose) {
605 		case CERT_PURPOSE_CA:
606 			queue_add_from_cert(cert);
607 			break;
608 		case CERT_PURPOSE_BGPSEC_ROUTER:
609 			cert_insert_brks(brktree, cert);
610 			repo_stat_inc(rp, talid, type, STYPE_BGPSEC);
611 			break;
612 		default:
613 			errx(1, "unexpected cert purpose received");
614 			break;
615 		}
616 		cert_free(cert);
617 		break;
618 	case RTYPE_MFT:
619 		io_read_buf(b, &c, sizeof(c));
620 		if (c == 0) {
621 			repo_stat_inc(rp, talid, type, STYPE_FAIL);
622 			break;
623 		}
624 		mft = mft_read(b);
625 		if (!mft->stale)
626 			queue_add_from_mft(mft);
627 		else
628 			repo_stat_inc(rp, talid, type, STYPE_STALE);
629 		mft_free(mft);
630 		break;
631 	case RTYPE_CRL:
632 		/* CRLs are sent together with MFT and not accounted for */
633 		entity_queue++;
634 		break;
635 	case RTYPE_ROA:
636 		io_read_buf(b, &c, sizeof(c));
637 		if (c == 0) {
638 			repo_stat_inc(rp, talid, type, STYPE_FAIL);
639 			break;
640 		}
641 		roa = roa_read(b);
642 		if (roa->valid)
643 			roa_insert_vrps(tree, roa, rp);
644 		else
645 			repo_stat_inc(rp, talid, type, STYPE_INVALID);
646 		roa_free(roa);
647 		break;
648 	case RTYPE_GBR:
649 		break;
650 	case RTYPE_ASPA:
651 		io_read_buf(b, &c, sizeof(c));
652 		if (c == 0) {
653 			repo_stat_inc(rp, talid, type, STYPE_FAIL);
654 			break;
655 		}
656 		aspa = aspa_read(b);
657 		if (aspa->valid)
658 			aspa_insert_vaps(vaptree, aspa, rp);
659 		else
660 			repo_stat_inc(rp, talid, type, STYPE_INVALID);
661 		aspa_free(aspa);
662 		break;
663 	case RTYPE_TAK:
664 		break;
665 	case RTYPE_FILE:
666 		break;
667 	default:
668 		warnx("%s: unknown entity type %d", file, type);
669 		break;
670 	}
671 
672 done:
673 	free(file);
674 	entity_queue--;
675 }
676 
677 static void
678 rrdp_process(struct ibuf *b)
679 {
680 	enum rrdp_msg type;
681 	enum publish_type pt;
682 	struct rrdp_session s;
683 	char *uri, *last_mod, *data;
684 	char hash[SHA256_DIGEST_LENGTH];
685 	size_t dsz;
686 	unsigned int id;
687 	int ok;
688 
689 	io_read_buf(b, &type, sizeof(type));
690 	io_read_buf(b, &id, sizeof(id));
691 
692 	switch (type) {
693 	case RRDP_END:
694 		io_read_buf(b, &ok, sizeof(ok));
695 		rrdp_finish(id, ok);
696 		break;
697 	case RRDP_HTTP_REQ:
698 		io_read_str(b, &uri);
699 		io_read_str(b, &last_mod);
700 		rrdp_http_fetch(id, uri, last_mod);
701 		break;
702 	case RRDP_SESSION:
703 		io_read_str(b, &s.session_id);
704 		io_read_buf(b, &s.serial, sizeof(s.serial));
705 		io_read_str(b, &s.last_mod);
706 		rrdp_save_state(id, &s);
707 		free(s.session_id);
708 		free(s.last_mod);
709 		break;
710 	case RRDP_FILE:
711 		io_read_buf(b, &pt, sizeof(pt));
712 		if (pt != PUB_ADD)
713 			io_read_buf(b, &hash, sizeof(hash));
714 		io_read_str(b, &uri);
715 		io_read_buf_alloc(b, (void **)&data, &dsz);
716 
717 		ok = rrdp_handle_file(id, pt, uri, hash, sizeof(hash),
718 		    data, dsz);
719 		rrdp_file_resp(id, ok);
720 
721 		free(uri);
722 		free(data);
723 		break;
724 	case RRDP_CLEAR:
725 		rrdp_clear(id);
726 		break;
727 	default:
728 		errx(1, "unexpected rrdp response");
729 	}
730 }
731 
732 static void
733 sum_stats(const struct repo *rp, const struct repotalstats *in, void *arg)
734 {
735 	struct repotalstats *out = arg;
736 
737 	out->mfts += in->mfts;
738 	out->mfts_fail += in->mfts_fail;
739 	out->mfts_stale += in->mfts_stale;
740 	out->certs += in->certs;
741 	out->certs_fail += in->certs_fail;
742 	out->roas += in->roas;
743 	out->roas_fail += in->roas_fail;
744 	out->roas_invalid += in->roas_invalid;
745 	out->aspas += in->aspas;
746 	out->aspas_fail += in->aspas_fail;
747 	out->aspas_invalid += in->aspas_invalid;
748 	out->brks += in->brks;
749 	out->crls += in->crls;
750 	out->gbrs += in->gbrs;
751 	out->taks += in->taks;
752 	out->vrps += in->vrps;
753 	out->vrps_uniqs += in->vrps_uniqs;
754 	out->vaps += in->vaps;
755 	out->vaps_uniqs += in->vaps_uniqs;
756 	out->vaps_pas += in->vaps_pas;
757 	out->vaps_pas4 += in->vaps_pas4;
758 	out->vaps_pas6 += in->vaps_pas6;
759 }
760 
761 static void
762 sum_repostats(const struct repo *rp, const struct repostats *in, void *arg)
763 {
764 	struct repostats *out = arg;
765 
766 	out->del_files += in->del_files;
767 	out->extra_files += in->extra_files;
768 	out->del_extra_files += in->del_extra_files;
769 	out->del_dirs += in->del_dirs;
770 	timespecadd(&in->sync_time, &out->sync_time, &out->sync_time);
771 }
772 
773 /*
774  * Assign filenames ending in ".tal" in "/etc/rpki" into "tals",
775  * returning the number of files found and filled-in.
776  * This may be zero.
777  * Don't exceed "max" filenames.
778  */
779 static int
780 tal_load_default(void)
781 {
782 	static const char *confdir = "/etc/rpki";
783 	int s = 0;
784 	char *path;
785 	DIR *dirp;
786 	struct dirent *dp;
787 
788 	dirp = opendir(confdir);
789 	if (dirp == NULL)
790 		err(1, "open %s", confdir);
791 	while ((dp = readdir(dirp)) != NULL) {
792 		if (fnmatch("*.tal", dp->d_name, FNM_PERIOD) == FNM_NOMATCH)
793 			continue;
794 		if (s >= TALSZ_MAX)
795 			err(1, "too many tal files found in %s",
796 			    confdir);
797 		if (asprintf(&path, "%s/%s", confdir, dp->d_name) == -1)
798 			err(1, NULL);
799 		tals[s++] = path;
800 	}
801 	closedir(dirp);
802 	return s;
803 }
804 
805 /*
806  * Load the list of FQDNs from the skiplist which are to be distrusted.
807  * Return 0 on success.
808  */
809 static void
810 load_skiplist(const char *slf)
811 {
812 	struct fqdnlistentry	*le;
813 	FILE			*fp;
814 	char			*line = NULL;
815 	size_t			 linesize = 0, linelen;
816 
817 	if ((fp = fopen(slf, "r")) == NULL) {
818 		if (errno == ENOENT && strcmp(slf, DEFAULT_SKIPLIST_FILE) == 0)
819 			return;
820 		err(1, "failed to open %s", slf);
821 	}
822 
823 	while (getline(&line, &linesize, fp) != -1) {
824 		/* just eat comment lines or empty lines*/
825 		if (line[0] == '#' || line[0] == '\n')
826 			continue;
827 
828 		if (line[0] == ' ' || line[0] == '\t')
829 			errx(1, "invalid entry in skiplist: %s", line);
830 
831 		/*
832 		 * Ignore anything after comment sign, whitespaces,
833 		 * also chop off LF or CR.
834 		 */
835 		linelen = strcspn(line, " #\r\n\t");
836 		line[linelen] = '\0';
837 
838 		if (!valid_uri(line, linelen, NULL))
839 			errx(1, "invalid entry in skiplist: %s", line);
840 
841 		if ((le = malloc(sizeof(struct fqdnlistentry))) == NULL)
842 			err(1, NULL);
843 		if ((le->fqdn = strdup(line)) == NULL)
844 			err(1, NULL);
845 
846 		LIST_INSERT_HEAD(&skiplist, le, entry);
847 		stats.skiplistentries++;
848 	}
849 
850 	fclose(fp);
851 	free(line);
852 }
853 
854 /*
855  * Load shortlist entries.
856  */
857 static void
858 load_shortlist(const char *fqdn)
859 {
860 	struct fqdnlistentry	*le;
861 
862 	if (!valid_uri(fqdn, strlen(fqdn), NULL))
863 		errx(1, "invalid fqdn passed to -q: %s", fqdn);
864 
865 	if ((le = malloc(sizeof(struct fqdnlistentry))) == NULL)
866 		err(1, NULL);
867 
868 	if ((le->fqdn = strdup(fqdn)) == NULL)
869 		err(1, NULL);
870 
871 	LIST_INSERT_HEAD(&shortlist, le, entry);
872 }
873 
874 static void
875 check_fs_size(int fd, const char *cachedir)
876 {
877 	struct statvfs	fs;
878 	const long long minsize = 500 * 1024 * 1024;
879 	const long long minnode = 300 * 1000;
880 
881 	if (fstatvfs(fd, &fs) == -1)
882 		err(1, "statfs %s", cachedir);
883 
884 	if (fs.f_bavail < minsize / fs.f_frsize ||
885 	    (fs.f_ffree > 0 && fs.f_favail < minnode)) {
886 		fprintf(stderr, "WARNING: rpki-client may need more than "
887 		    "the available disk space\n"
888 		    "on the file-system holding %s.\n", cachedir);
889 		fprintf(stderr, "available space: %lldkB, "
890 		    "suggested minimum %lldkB\n",
891 		    (long long)fs.f_bavail * fs.f_frsize / 1024,
892 		    minsize / 1024);
893 		fprintf(stderr, "available inodes %lld, "
894 		    "suggested minimum %lld\n\n",
895 		    (long long)fs.f_favail, minnode);
896 		fflush(stderr);
897 	}
898 }
899 
900 static pid_t
901 process_start(const char *title, int *fd)
902 {
903 	int		 fl = SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK;
904 	pid_t		 pid;
905 	int		 pair[2];
906 
907 	if (socketpair(AF_UNIX, fl, 0, pair) == -1)
908 		err(1, "socketpair");
909 	if ((pid = fork()) == -1)
910 		err(1, "fork");
911 
912 	if (pid == 0) {
913 		setproctitle("%s", title);
914 		/* change working directory to the cache directory */
915 		if (fchdir(cachefd) == -1)
916 			err(1, "fchdir");
917 		if (!filemode && timeout > 0)
918 			alarm(timeout);
919 		close(pair[1]);
920 		*fd = pair[0];
921 	} else {
922 		close(pair[0]);
923 		*fd = pair[1];
924 	}
925 	return pid;
926 }
927 
928 void
929 suicide(int sig __attribute__((unused)))
930 {
931 	killme = 1;
932 }
933 
934 #define NPFD	4
935 
936 int
937 main(int argc, char *argv[])
938 {
939 	int		 rc, c, i, st, proc, rsync, http, rrdp, hangup = 0;
940 	pid_t		 pid, procpid, rsyncpid, httppid, rrdppid;
941 	struct pollfd	 pfd[NPFD];
942 	struct msgbuf	*queues[NPFD];
943 	struct ibuf	*b, *httpbuf = NULL, *procbuf = NULL;
944 	struct ibuf	*rrdpbuf = NULL, *rsyncbuf = NULL;
945 	char		*rsync_prog = "openrsync";
946 	char		*bind_addr = NULL;
947 	const char	*cachedir = NULL, *outputdir = NULL;
948 	const char	*errs, *name;
949 	const char	*skiplistfile = NULL;
950 	struct vrp_tree	 vrps = RB_INITIALIZER(&vrps);
951 	struct brk_tree	 brks = RB_INITIALIZER(&brks);
952 	struct vap_tree	 vaps = RB_INITIALIZER(&vaps);
953 	struct rusage	 ru;
954 	struct timespec	 start_time, now_time;
955 
956 	clock_gettime(CLOCK_MONOTONIC, &start_time);
957 
958 	/* If started as root, priv-drop to _rpki-client */
959 	if (getuid() == 0) {
960 		struct passwd *pw;
961 
962 		pw = getpwnam("_rpki-client");
963 		if (!pw)
964 			errx(1, "no _rpki-client user to revoke to");
965 		if (setgroups(1, &pw->pw_gid) == -1 ||
966 		    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 ||
967 		    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
968 			err(1, "unable to revoke privs");
969 	}
970 	cachedir = RPKI_PATH_BASE_DIR;
971 	outputdir = RPKI_PATH_OUT_DIR;
972 	repo_timeout = timeout / 4;
973 	skiplistfile = DEFAULT_SKIPLIST_FILE;
974 
975 	if (pledge("stdio rpath wpath cpath inet fattr dns sendfd recvfd "
976 	    "proc exec unveil", NULL) == -1)
977 		err(1, "pledge");
978 
979 	while ((c = getopt(argc, argv, "Ab:Bcd:e:fH:jmnoP:rRs:S:t:T:vV")) != -1)
980 		switch (c) {
981 		case 'A':
982 			excludeaspa = 1;
983 			break;
984 		case 'b':
985 			bind_addr = optarg;
986 			break;
987 		case 'B':
988 			outformats |= FORMAT_BIRD;
989 			break;
990 		case 'c':
991 			outformats |= FORMAT_CSV;
992 			break;
993 		case 'd':
994 			cachedir = optarg;
995 			break;
996 		case 'e':
997 			rsync_prog = optarg;
998 			break;
999 		case 'f':
1000 			filemode = 1;
1001 			noop = 1;
1002 			break;
1003 		case 'H':
1004 			shortlistmode = 1;
1005 			load_shortlist(optarg);
1006 			break;
1007 		case 'j':
1008 			outformats |= FORMAT_JSON;
1009 			break;
1010 		case 'm':
1011 			outformats |= FORMAT_OMETRIC;
1012 			break;
1013 		case 'n':
1014 			noop = 1;
1015 			break;
1016 		case 'o':
1017 			outformats |= FORMAT_OPENBGPD;
1018 			break;
1019 		case 'P':
1020 			evaluation_time = strtonum(optarg, X509_TIME_MIN + 1,
1021 			    X509_TIME_MAX, &errs);
1022 			if (errs)
1023 				errx(1, "-P: time in seconds %s", errs);
1024 			break;
1025 		case 'R':
1026 			rrdpon = 0;
1027 			break;
1028 		case 'r': /* Remove after OpenBSD 7.3 */
1029 			rrdpon = 1;
1030 			break;
1031 		case 's':
1032 			timeout = strtonum(optarg, 0, 24*60*60, &errs);
1033 			if (errs)
1034 				errx(1, "-s: %s", errs);
1035 			if (timeout == 0)
1036 				repo_timeout = 24*60*60;
1037 			else
1038 				repo_timeout = timeout / 4;
1039 			break;
1040 		case 'S':
1041 			skiplistfile = optarg;
1042 			break;
1043 		case 't':
1044 			if (talsz >= TALSZ_MAX)
1045 				err(1, "too many tal files specified");
1046 			tals[talsz++] = optarg;
1047 			break;
1048 		case 'T':
1049 			bird_tablename = optarg;
1050 			break;
1051 		case 'v':
1052 			verbose++;
1053 			break;
1054 		case 'V':
1055 			fprintf(stderr, "rpki-client %s\n", RPKI_VERSION);
1056 			return 0;
1057 		default:
1058 			goto usage;
1059 		}
1060 
1061 	argv += optind;
1062 	argc -= optind;
1063 
1064 	if (!filemode) {
1065 		if (argc == 1)
1066 			outputdir = argv[0];
1067 		else if (argc > 1)
1068 			goto usage;
1069 
1070 		if (outputdir == NULL) {
1071 			warnx("output directory required");
1072 			goto usage;
1073 		}
1074 	} else {
1075 		if (argc == 0)
1076 			goto usage;
1077 		outputdir = NULL;
1078 	}
1079 
1080 	if (cachedir == NULL) {
1081 		warnx("cache directory required");
1082 		goto usage;
1083 	}
1084 
1085 	signal(SIGPIPE, SIG_IGN);
1086 
1087 	if ((cachefd = open(cachedir, O_RDONLY | O_DIRECTORY)) == -1)
1088 		err(1, "cache directory %s", cachedir);
1089 	if (outputdir != NULL) {
1090 		if ((outdirfd = open(outputdir, O_RDONLY | O_DIRECTORY)) == -1)
1091 			err(1, "output directory %s", outputdir);
1092 		if (outformats == 0)
1093 			outformats = FORMAT_OPENBGPD;
1094 	}
1095 
1096 	check_fs_size(cachefd, cachedir);
1097 
1098 	if (talsz == 0)
1099 		talsz = tal_load_default();
1100 	if (talsz == 0)
1101 		err(1, "no TAL files found in %s", "/etc/rpki");
1102 
1103 	/*
1104 	 * Create the file reader as a jailed child process.
1105 	 * It will be responsible for reading all of the files (ROAs,
1106 	 * manifests, certificates, etc.) and returning contents.
1107 	 */
1108 
1109 	procpid = process_start("parser", &proc);
1110 	if (procpid == 0) {
1111 		if (!filemode)
1112 			proc_parser(proc);
1113 		else
1114 			proc_filemode(proc);
1115 	}
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