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