1 /* $OpenBSD: main.c,v 1.141 2021/05/11 11:48:02 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/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 50 size_t entity_queue; 51 int timeout = 60*60; 52 volatile sig_atomic_t killme; 53 void suicide(int sig); 54 55 static struct filepath_tree fpt = RB_INITIALIZER(&fpt); 56 static struct msgbuf procq, rsyncq, httpq, rrdpq; 57 static int cachefd, outdirfd; 58 59 const char *bird_tablename = "ROAS"; 60 61 int verbose; 62 int noop; 63 int rrdpon; 64 65 struct 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 */ 71 void 72 logx(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 83 void 84 entity_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 */ 101 void 102 entity_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 */ 117 static void 118 entity_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 */ 142 void 143 entityq_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 */ 170 static void 171 entityq_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 219 static void 220 rrdp_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 233 void 234 rrdp_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 */ 255 void 256 rsync_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 */ 271 void 272 http_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 */ 290 static void 291 rrdp_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 310 void 311 rrdp_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 */ 330 static void 331 queue_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 */ 358 static void 359 queue_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 */ 394 static void 395 queue_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 */ 425 static void 426 queue_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 */ 442 static void 443 queue_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 */ 465 static void 466 entity_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 */ 556 static size_t 557 tal_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 582 void 583 suicide(int sig __attribute__((unused))) 584 { 585 killme = 1; 586 } 587 588 #define NPFD 4 589 590 int 591 main(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 (cachedir == NULL) { 696 warnx("cache directory required"); 697 goto usage; 698 } 699 if (outputdir == NULL) { 700 warnx("output directory required"); 701 goto usage; 702 } 703 704 if ((cachefd = open(cachedir, O_RDONLY, 0)) == -1) 705 err(1, "cache directory %s", cachedir); 706 if ((outdirfd = open(outputdir, O_RDONLY, 0)) == -1) 707 err(1, "output directory %s", outputdir); 708 709 if (outformats == 0) 710 outformats = FORMAT_OPENBGPD; 711 712 if (talsz == 0) 713 talsz = tal_load_default(tals, TALSZ_MAX); 714 if (talsz == 0) 715 err(1, "no TAL files found in %s", "/etc/rpki"); 716 717 /* 718 * Create the file reader as a jailed child process. 719 * It will be responsible for reading all of the files (ROAs, 720 * manifests, certificates, etc.) and returning contents. 721 */ 722 723 if (socketpair(AF_UNIX, fl, 0, fd) == -1) 724 err(1, "socketpair"); 725 if ((procpid = fork()) == -1) 726 err(1, "fork"); 727 728 if (procpid == 0) { 729 close(fd[1]); 730 731 setproctitle("parser"); 732 /* change working directory to the cache directory */ 733 if (fchdir(cachefd) == -1) 734 err(1, "fchdir"); 735 736 if (timeout) 737 alarm(timeout); 738 739 /* Only allow access to the cache directory. */ 740 if (unveil(".", "r") == -1) 741 err(1, "%s: unveil", cachedir); 742 if (pledge("stdio rpath", NULL) == -1) 743 err(1, "pledge"); 744 proc_parser(fd[0]); 745 errx(1, "parser process returned"); 746 } 747 748 close(fd[0]); 749 proc = fd[1]; 750 751 /* 752 * Create a process that will do the rsync'ing. 753 * This process is responsible for making sure that all the 754 * repositories referenced by a certificate manifest (or the 755 * TAL) exists and has been downloaded. 756 */ 757 758 if (!noop) { 759 if (socketpair(AF_UNIX, fl, 0, fd) == -1) 760 err(1, "socketpair"); 761 if ((rsyncpid = fork()) == -1) 762 err(1, "fork"); 763 764 if (rsyncpid == 0) { 765 close(proc); 766 close(fd[1]); 767 768 setproctitle("rsync"); 769 /* change working directory to the cache directory */ 770 if (fchdir(cachefd) == -1) 771 err(1, "fchdir"); 772 773 if (timeout) 774 alarm(timeout); 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 (timeout) 813 alarm(timeout); 814 815 if (pledge("stdio rpath inet dns recvfd", NULL) == -1) 816 err(1, "pledge"); 817 818 proc_http(bind_addr, fd[0]); 819 errx(1, "http process returned"); 820 } 821 822 close(fd[0]); 823 http = fd[1]; 824 } else { 825 http = -1; 826 httppid = -1; 827 } 828 829 /* 830 * Create a process that will process RRDP. 831 * The rrdp process requires the http process to fetch the various 832 * XML files and does this via the main process. 833 */ 834 835 if (!noop && rrdpon) { 836 if (socketpair(AF_UNIX, fl, 0, fd) == -1) 837 err(1, "socketpair"); 838 if ((rrdppid = fork()) == -1) 839 err(1, "fork"); 840 841 if (rrdppid == 0) { 842 close(proc); 843 close(rsync); 844 close(http); 845 close(fd[1]); 846 847 setproctitle("rrdp"); 848 /* change working directory to the cache directory */ 849 if (fchdir(cachefd) == -1) 850 err(1, "fchdir"); 851 852 if (timeout) 853 alarm(timeout); 854 855 if (pledge("stdio recvfd", NULL) == -1) 856 err(1, "pledge"); 857 858 proc_rrdp(fd[0]); 859 /* NOTREACHED */ 860 } 861 862 close(fd[0]); 863 rrdp = fd[1]; 864 } else { 865 rrdp = -1; 866 rrdppid = -1; 867 } 868 869 if (timeout) { 870 /* 871 * Commit suicide eventually 872 * cron will normally start a new one 873 */ 874 alarm(timeout); 875 signal(SIGALRM, suicide); 876 } 877 878 /* TODO unveil cachedir and outputdir, no other access allowed */ 879 if (pledge("stdio rpath wpath cpath fattr sendfd", NULL) == -1) 880 err(1, "pledge"); 881 882 msgbuf_init(&procq); 883 msgbuf_init(&rsyncq); 884 msgbuf_init(&httpq); 885 msgbuf_init(&rrdpq); 886 procq.fd = proc; 887 rsyncq.fd = rsync; 888 httpq.fd = http; 889 rrdpq.fd = rrdp; 890 891 /* 892 * The main process drives the top-down scan to leaf ROAs using 893 * data downloaded by the rsync process and parsed by the 894 * parsing process. 895 */ 896 897 pfd[0].fd = proc; 898 queues[0] = &procq; 899 pfd[1].fd = rsync; 900 queues[1] = &rsyncq; 901 pfd[2].fd = http; 902 queues[2] = &httpq; 903 pfd[3].fd = rrdp; 904 queues[3] = &rrdpq; 905 906 /* 907 * Prime the process with our TAL file. 908 * This will contain (hopefully) links to our manifest and we 909 * can get the ball rolling. 910 */ 911 912 for (i = 0; i < talsz; i++) 913 queue_add_tal(tals[i]); 914 915 /* change working directory to the cache directory */ 916 if (fchdir(cachefd) == -1) 917 err(1, "fchdir"); 918 919 while (entity_queue > 0 && !killme) { 920 for (i = 0; i < NPFD; i++) { 921 pfd[i].events = POLLIN; 922 if (queues[i]->queued) 923 pfd[i].events |= POLLOUT; 924 } 925 926 if ((c = poll(pfd, NPFD, INFTIM)) == -1) { 927 if (errno == EINTR) 928 continue; 929 err(1, "poll"); 930 } 931 932 for (i = 0; i < NPFD; i++) { 933 if (pfd[i].revents & (POLLERR|POLLNVAL)) 934 errx(1, "poll[%zu]: bad fd", i); 935 if (pfd[i].revents & POLLHUP) { 936 warnx("poll[%zu]: hangup", i); 937 hangup = 1; 938 } 939 if (pfd[i].revents & POLLOUT) { 940 /* 941 * XXX work around deadlocks because of 942 * blocking read vs non-blocking writes. 943 */ 944 if (i > 1) 945 io_socket_nonblocking(pfd[i].fd); 946 switch (msgbuf_write(queues[i])) { 947 case 0: 948 errx(1, "write[%zu]: " 949 "connection closed", i); 950 case -1: 951 err(1, "write[%zu]", i); 952 } 953 if (i > 1) 954 io_socket_blocking(pfd[i].fd); 955 } 956 } 957 if (hangup) 958 break; 959 960 /* 961 * Check the rsync and http process. 962 * This means that one of our modules has completed 963 * downloading and we can flush the module requests into 964 * the parser process. 965 */ 966 967 if ((pfd[1].revents & POLLIN)) { 968 io_simple_read(rsync, &id, sizeof(id)); 969 io_simple_read(rsync, &ok, sizeof(ok)); 970 rsync_finish(id, ok); 971 } 972 973 if ((pfd[2].revents & POLLIN)) { 974 enum http_result res; 975 char *last_mod; 976 977 io_simple_read(http, &id, sizeof(id)); 978 io_simple_read(http, &res, sizeof(res)); 979 io_str_read(http, &last_mod); 980 http_finish(id, res, last_mod); 981 free(last_mod); 982 } 983 984 /* 985 * Handle RRDP requests here. 986 */ 987 if ((pfd[3].revents & POLLIN)) { 988 enum rrdp_msg type; 989 enum publish_type pt; 990 struct rrdp_session s; 991 char *uri, *last_mod, *data; 992 char hash[SHA256_DIGEST_LENGTH]; 993 size_t dsz; 994 995 io_simple_read(rrdp, &type, sizeof(type)); 996 io_simple_read(rrdp, &id, sizeof(id)); 997 998 switch (type) { 999 case RRDP_END: 1000 io_simple_read(rrdp, &ok, sizeof(ok)); 1001 rrdp_finish(id, ok); 1002 break; 1003 case RRDP_HTTP_REQ: 1004 io_str_read(rrdp, &uri); 1005 io_str_read(rrdp, &last_mod); 1006 rrdp_http_fetch(id, uri, last_mod); 1007 break; 1008 case RRDP_SESSION: 1009 io_str_read(rrdp, &s.session_id); 1010 io_simple_read(rrdp, &s.serial, 1011 sizeof(s.serial)); 1012 io_str_read(rrdp, &s.last_mod); 1013 rrdp_save_state(id, &s); 1014 free(s.session_id); 1015 free(s.last_mod); 1016 break; 1017 case RRDP_FILE: 1018 io_simple_read(rrdp, &pt, sizeof(pt)); 1019 if (pt != PUB_ADD) 1020 io_simple_read(rrdp, &hash, 1021 sizeof(hash)); 1022 io_str_read(rrdp, &uri); 1023 io_buf_read_alloc(rrdp, (void **)&data, &dsz); 1024 1025 ok = rrdp_handle_file(id, pt, uri, 1026 hash, sizeof(hash), data, dsz); 1027 rrdp_file_resp(id, ok); 1028 1029 free(uri); 1030 free(data); 1031 break; 1032 default: 1033 errx(1, "unexpected rrdp response"); 1034 } 1035 } 1036 1037 /* 1038 * The parser has finished something for us. 1039 * Dequeue these one by one. 1040 */ 1041 1042 if ((pfd[0].revents & POLLIN)) { 1043 entity_process(proc, &stats, &v); 1044 } 1045 } 1046 1047 signal(SIGALRM, SIG_DFL); 1048 if (killme) { 1049 syslog(LOG_CRIT|LOG_DAEMON, 1050 "excessive runtime (%d seconds), giving up", timeout); 1051 errx(1, "excessive runtime (%d seconds), giving up", timeout); 1052 } 1053 1054 /* 1055 * For clean-up, close the input for the parser and rsync 1056 * process. 1057 * This will cause them to exit, then we reap them. 1058 */ 1059 1060 close(proc); 1061 close(rsync); 1062 close(http); 1063 close(rrdp); 1064 1065 rc = 0; 1066 for (;;) { 1067 pid = waitpid(WAIT_ANY, &st, 0); 1068 if (pid == -1) { 1069 if (errno == EINTR) 1070 continue; 1071 if (errno == ECHILD) 1072 break; 1073 err(1, "wait"); 1074 } 1075 1076 if (pid == procpid) 1077 name = "parser"; 1078 else if (pid == rsyncpid) 1079 name = "rsync"; 1080 else if (pid == httppid) 1081 name = "http"; 1082 else if (pid == rrdppid) 1083 name = "rrdp"; 1084 else 1085 name = "unknown"; 1086 1087 if (WIFSIGNALED(st)) { 1088 warnx("%s terminated signal %d", name, WTERMSIG(st)); 1089 rc = 1; 1090 } else if (!WIFEXITED(st) || WEXITSTATUS(st) != 0) { 1091 warnx("%s process exited abnormally", name); 1092 rc = 1; 1093 } 1094 } 1095 1096 /* processing did not finish because of error */ 1097 if (entity_queue != 0) 1098 return 1; 1099 1100 logx("all files parsed: generating output"); 1101 1102 repo_cleanup(&fpt); 1103 1104 gettimeofday(&now_time, NULL); 1105 timersub(&now_time, &start_time, &stats.elapsed_time); 1106 if (getrusage(RUSAGE_SELF, &ru) == 0) { 1107 stats.user_time = ru.ru_utime; 1108 stats.system_time = ru.ru_stime; 1109 } 1110 if (getrusage(RUSAGE_CHILDREN, &ru) == 0) { 1111 timeradd(&stats.user_time, &ru.ru_utime, &stats.user_time); 1112 timeradd(&stats.system_time, &ru.ru_stime, &stats.system_time); 1113 } 1114 1115 /* change working directory to the output directory */ 1116 if (fchdir(outdirfd) == -1) 1117 err(1, "fchdir output dir"); 1118 1119 if (outputfiles(&v, &stats)) 1120 rc = 1; 1121 1122 1123 logx("Route Origin Authorizations: %zu (%zu failed parse, %zu invalid)", 1124 stats.roas, stats.roas_fail, stats.roas_invalid); 1125 logx("Certificates: %zu (%zu failed parse, %zu invalid)", 1126 stats.certs, stats.certs_fail, stats.certs_invalid); 1127 logx("Trust Anchor Locators: %zu", stats.tals); 1128 logx("Manifests: %zu (%zu failed parse, %zu stale)", 1129 stats.mfts, stats.mfts_fail, stats.mfts_stale); 1130 logx("Certificate revocation lists: %zu", stats.crls); 1131 logx("Ghostbuster records: %zu", stats.gbrs); 1132 logx("Repositories: %zu", stats.repos); 1133 logx("Cleanup: removed %zu files, %zu directories", 1134 stats.del_files, stats.del_dirs); 1135 logx("VRP Entries: %zu (%zu unique)", stats.vrps, stats.uniqs); 1136 1137 /* Memory cleanup. */ 1138 repo_free(); 1139 1140 for (i = 0; i < outsz; i++) 1141 roa_free(out[i]); 1142 free(out); 1143 1144 return rc; 1145 1146 usage: 1147 fprintf(stderr, 1148 "usage: rpki-client [-BcjnoRrVv] [-b sourceaddr] [-d cachedir]" 1149 " [-e rsync_prog]\n" 1150 " [-s timeout] [-T table] [-t tal]" 1151 " [outputdir]\n"); 1152 return 1; 1153 } 1154