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