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