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