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