main.c revision 1.17
1/* $OpenBSD: main.c,v 1.17 2019/09/26 17:07:30 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/stat.h> 21#include <sys/types.h> 22#include <sys/wait.h> 23 24#include <assert.h> 25#include <err.h> 26#include <dirent.h> 27#include <fcntl.h> 28#include <fnmatch.h> 29#include <fts.h> 30#include <inttypes.h> 31#include <poll.h> 32#include <signal.h> 33#include <stdio.h> 34#include <stdlib.h> 35#include <string.h> 36#include <unistd.h> 37 38#include <openssl/err.h> 39#include <openssl/evp.h> 40#include <openssl/x509v3.h> 41 42#include "extern.h" 43 44/* 45 * Base directory for where we'll look for all media. 46 */ 47#define BASE_DIR "/var/cache/rpki-client" 48 49/* 50 * Statistics collected during run-time. 51 */ 52struct stats { 53 size_t tals; /* total number of locators */ 54 size_t mfts; /* total number of manifests */ 55 size_t mfts_fail; /* failing syntactic parse */ 56 size_t mfts_stale; /* stale manifests */ 57 size_t certs; /* certificates */ 58 size_t certs_fail; /* failing syntactic parse */ 59 size_t certs_invalid; /* invalid resources */ 60 size_t roas; /* route origin authorizations */ 61 size_t roas_fail; /* failing syntactic parse */ 62 size_t roas_invalid; /* invalid resources */ 63 size_t repos; /* repositories */ 64 size_t crls; /* revocation lists */ 65}; 66 67/* 68 * An rsync repository. 69 */ 70struct repo { 71 char *host; /* hostname */ 72 char *module; /* module name */ 73 int loaded; /* whether loaded or not */ 74 size_t id; /* identifier (array index) */ 75}; 76 77/* 78 * A running rsync process. 79 * We can have multiple of these simultaneously and need to keep track 80 * of which process maps to which request. 81 */ 82struct rsyncproc { 83 char *uri; /* uri of this rsync proc */ 84 size_t id; /* identity of request */ 85 pid_t pid; /* pid of process or 0 if unassociated */ 86}; 87 88/* 89 * Table of all known repositories. 90 */ 91struct repotab { 92 struct repo *repos; /* repositories */ 93 size_t reposz; /* number of repos */ 94}; 95 96/* 97 * An entity (MFT, ROA, certificate, etc.) that needs to be downloaded 98 * and parsed. 99 */ 100struct entity { 101 size_t id; /* unique identifier */ 102 enum rtype type; /* type of entity (not RTYPE_EOF) */ 103 char *uri; /* file or rsync:// URI */ 104 int has_dgst; /* whether dgst is specified */ 105 unsigned char dgst[SHA256_DIGEST_LENGTH]; /* optional */ 106 ssize_t repo; /* repo index or <0 if w/o repo */ 107 int has_pkey; /* whether pkey/sz is specified */ 108 unsigned char *pkey; /* public key (optional) */ 109 size_t pkeysz; /* public key length (optional) */ 110 TAILQ_ENTRY(entity) entries; 111}; 112 113TAILQ_HEAD(entityq, entity); 114 115/* 116 * Mark that our subprocesses will never return. 117 */ 118static void proc_parser(int, int, int) 119 __attribute__((noreturn)); 120static void proc_rsync(const char *, const char *, int, int) 121 __attribute__((noreturn)); 122static void logx(const char *fmt, ...) 123 __attribute__((format(printf, 1, 2))); 124 125int verbose; 126 127/* 128 * Log a message to stderr if and only if "verbose" is non-zero. 129 * This uses the err(3) functionality. 130 */ 131static void 132logx(const char *fmt, ...) 133{ 134 va_list ap; 135 136 if (verbose && fmt != NULL) { 137 va_start(ap, fmt); 138 vwarnx(fmt, ap); 139 va_end(ap); 140 } 141} 142 143/* 144 * Resolve the media type of a resource by looking at its suffice. 145 * Returns the type of RTYPE_EOF if not found. 146 */ 147static enum rtype 148rtype_resolve(const char *uri) 149{ 150 enum rtype rp; 151 152 rsync_uri_parse(NULL, NULL, NULL, NULL, NULL, NULL, &rp, uri); 153 return rp; 154} 155 156static void 157entity_free(struct entity *ent) 158{ 159 160 if (ent == NULL) 161 return; 162 163 free(ent->pkey); 164 free(ent->uri); 165 free(ent); 166} 167 168/* 169 * Read a queue entity from the descriptor. 170 * Matched by entity_buffer_req(). 171 * The pointer must be passed entity_free(). 172 */ 173static void 174entity_read_req(int fd, struct entity *ent) 175{ 176 177 io_simple_read(fd, &ent->id, sizeof(size_t)); 178 io_simple_read(fd, &ent->type, sizeof(enum rtype)); 179 io_str_read(fd, &ent->uri); 180 io_simple_read(fd, &ent->has_dgst, sizeof(int)); 181 if (ent->has_dgst) 182 io_simple_read(fd, ent->dgst, sizeof(ent->dgst)); 183 io_simple_read(fd, &ent->has_pkey, sizeof(int)); 184 if (ent->has_pkey) 185 io_buf_read_alloc(fd, (void **)&ent->pkey, &ent->pkeysz); 186} 187 188/* 189 * Look up a repository, queueing it for discovery if not found. 190 */ 191static const struct repo * 192repo_lookup(int fd, struct repotab *rt, const char *uri) 193{ 194 const char *host, *mod; 195 size_t hostsz, modsz, i; 196 struct repo *rp; 197 198 if (!rsync_uri_parse(&host, &hostsz, 199 &mod, &modsz, NULL, NULL, NULL, uri)) 200 errx(EXIT_FAILURE, "%s: malformed", uri); 201 202 /* Look up in repository table. */ 203 204 for (i = 0; i < rt->reposz; i++) { 205 if (strlen(rt->repos[i].host) != hostsz) 206 continue; 207 if (strlen(rt->repos[i].module) != modsz) 208 continue; 209 if (strncasecmp(rt->repos[i].host, host, hostsz)) 210 continue; 211 if (strncasecmp(rt->repos[i].module, mod, modsz)) 212 continue; 213 return &rt->repos[i]; 214 } 215 216 rt->repos = reallocarray(rt->repos, 217 rt->reposz + 1, sizeof(struct repo)); 218 if (rt->repos == NULL) 219 err(EXIT_FAILURE, "reallocarray"); 220 221 rp = &rt->repos[rt->reposz++]; 222 memset(rp, 0, sizeof(struct repo)); 223 rp->id = rt->reposz - 1; 224 225 if ((rp->host = strndup(host, hostsz)) == NULL || 226 (rp->module = strndup(mod, modsz)) == NULL) 227 err(EXIT_FAILURE, "strndup"); 228 229 i = rt->reposz - 1; 230 231 logx("%s/%s: loading", rp->host, rp->module); 232 io_simple_write(fd, &i, sizeof(size_t)); 233 io_str_write(fd, rp->host); 234 io_str_write(fd, rp->module); 235 return rp; 236} 237 238/* 239 * Read the next entity from the parser process, removing it from the 240 * queue of pending requests in the process. 241 * This always returns a valid entity. 242 */ 243static struct entity * 244entityq_next(int fd, struct entityq *q) 245{ 246 size_t id; 247 struct entity *entp; 248 249 io_simple_read(fd, &id, sizeof(size_t)); 250 251 TAILQ_FOREACH(entp, q, entries) 252 if (entp->id == id) 253 break; 254 255 assert(entp != NULL); 256 TAILQ_REMOVE(q, entp, entries); 257 return entp; 258} 259 260static void 261entity_buffer_resp(char **b, size_t *bsz, size_t *bmax, 262 const struct entity *ent) 263{ 264 265 io_simple_buffer(b, bsz, bmax, &ent->id, sizeof(size_t)); 266} 267 268/* 269 * Like entity_write_req() but into a buffer. 270 * Matched by entity_read_req(). 271 */ 272static void 273entity_buffer_req(char **b, size_t *bsz, size_t *bmax, 274 const struct entity *ent) 275{ 276 277 io_simple_buffer(b, bsz, bmax, &ent->id, sizeof(size_t)); 278 io_simple_buffer(b, bsz, bmax, &ent->type, sizeof(enum rtype)); 279 io_str_buffer(b, bsz, bmax, ent->uri); 280 io_simple_buffer(b, bsz, bmax, &ent->has_dgst, sizeof(int)); 281 if (ent->has_dgst) 282 io_simple_buffer(b, bsz, bmax, ent->dgst, sizeof(ent->dgst)); 283 io_simple_buffer(b, bsz, bmax, &ent->has_pkey, sizeof(int)); 284 if (ent->has_pkey) 285 io_buf_buffer(b, bsz, bmax, ent->pkey, ent->pkeysz); 286} 287 288/* 289 * Write the queue entity. 290 * Simply a wrapper around entity_buffer_req(). 291 */ 292static void 293entity_write_req(int fd, const struct entity *ent) 294{ 295 char *b = NULL; 296 size_t bsz = 0, bmax = 0; 297 298 entity_buffer_req(&b, &bsz, &bmax, ent); 299 io_simple_write(fd, b, bsz); 300 free(b); 301} 302 303/* 304 * Scan through all queued requests and see which ones are in the given 305 * repo, then flush those into the parser process. 306 */ 307static void 308entityq_flush(int fd, struct entityq *q, const struct repo *repo) 309{ 310 struct entity *p; 311 312 TAILQ_FOREACH(p, q, entries) { 313 if (p->repo < 0 || repo->id != (size_t)p->repo) 314 continue; 315 entity_write_req(fd, p); 316 } 317} 318 319/* 320 * Add the heap-allocated file to the queue for processing. 321 */ 322static void 323entityq_add(int fd, struct entityq *q, char *file, enum rtype type, 324 const struct repo *rp, const unsigned char *dgst, 325 const unsigned char *pkey, size_t pkeysz, size_t *eid) 326{ 327 struct entity *p; 328 329 if ((p = calloc(1, sizeof(struct entity))) == NULL) 330 err(EXIT_FAILURE, "calloc"); 331 332 p->id = (*eid)++; 333 p->type = type; 334 p->uri = file; 335 p->repo = (rp != NULL) ? (ssize_t)rp->id : -1; 336 p->has_dgst = dgst != NULL; 337 p->has_pkey = pkey != NULL; 338 if (p->has_dgst) 339 memcpy(p->dgst, dgst, sizeof(p->dgst)); 340 if (p->has_pkey) { 341 p->pkeysz = pkeysz; 342 if ((p->pkey = malloc(pkeysz)) == NULL) 343 err(EXIT_FAILURE, "malloc"); 344 memcpy(p->pkey, pkey, pkeysz); 345 } 346 TAILQ_INSERT_TAIL(q, p, entries); 347 348 /* 349 * Write to the queue if there's no repo or the repo has already 350 * been loaded. 351 */ 352 353 if (rp == NULL || rp->loaded) 354 entity_write_req(fd, p); 355} 356 357/* 358 * Add a file (CER, ROA, CRL) from an MFT file, RFC 6486. 359 * These are always relative to the directory in which "mft" sits. 360 */ 361static void 362queue_add_from_mft(int fd, struct entityq *q, const char *mft, 363 const struct mftfile *file, enum rtype type, size_t *eid) 364{ 365 size_t sz; 366 char *cp, *nfile; 367 368 assert(strncmp(mft, BASE_DIR, strlen(BASE_DIR)) == 0); 369 370 /* Construct local path from filename. */ 371 372 sz = strlen(file->file) + strlen(mft); 373 if ((nfile = calloc(sz + 1, 1)) == NULL) 374 err(EXIT_FAILURE, "calloc"); 375 376 /* We know this is BASE_DIR/host/module/... */ 377 378 strlcpy(nfile, mft, sz + 1); 379 cp = strrchr(nfile, '/'); 380 assert(cp != NULL); 381 cp++; 382 *cp = '\0'; 383 strlcat(nfile, file->file, sz + 1); 384 385 /* 386 * Since we're from the same directory as the MFT file, we know 387 * that the repository has already been loaded. 388 */ 389 390 entityq_add(fd, q, nfile, type, NULL, file->hash, NULL, 0, eid); 391} 392 393/* 394 * Loops over queue_add_from_mft() for all files. 395 * The order here is important: we want to parse the revocation 396 * list *before* we parse anything else. 397 * FIXME: set the type of file in the mftfile so that we don't need to 398 * keep doing the check (this should be done in the parser, where we 399 * check the suffix anyway). 400 */ 401static void 402queue_add_from_mft_set(int fd, struct entityq *q, const struct mft *mft, 403 size_t *eid) 404{ 405 size_t i, sz; 406 const struct mftfile *f; 407 408 for (i = 0; i < mft->filesz; i++) { 409 f = &mft->files[i]; 410 sz = strlen(f->file); 411 assert(sz > 4); 412 if (strcasecmp(f->file + sz - 4, ".crl")) 413 continue; 414 queue_add_from_mft(fd, q, mft->file, f, RTYPE_CRL, eid); 415 } 416 417 for (i = 0; i < mft->filesz; i++) { 418 f = &mft->files[i]; 419 sz = strlen(f->file); 420 assert(sz > 4); 421 if (strcasecmp(f->file + sz - 4, ".cer")) 422 continue; 423 queue_add_from_mft(fd, q, mft->file, f, RTYPE_CER, eid); 424 } 425 426 for (i = 0; i < mft->filesz; i++) { 427 f = &mft->files[i]; 428 sz = strlen(f->file); 429 assert(sz > 4); 430 if (strcasecmp(f->file + sz - 4, ".roa")) 431 continue; 432 queue_add_from_mft(fd, q, mft->file, f, RTYPE_ROA, eid); 433 } 434} 435 436/* 437 * Add a local TAL file (RFC 7730) to the queue of files to fetch. 438 */ 439static void 440queue_add_tal(int fd, struct entityq *q, const char *file, size_t *eid) 441{ 442 char *nfile; 443 444 if ((nfile = strdup(file)) == NULL) 445 err(EXIT_FAILURE, "strdup"); 446 447 /* Not in a repository, so directly add to queue. */ 448 449 entityq_add(fd, q, nfile, RTYPE_TAL, NULL, NULL, NULL, 0, eid); 450} 451 452/* 453 * Add rsync URIs (CER) from a TAL file, RFC 7730. 454 * Only use the first URI of the set. 455 */ 456static void 457queue_add_from_tal(int proc, int rsync, struct entityq *q, 458 const struct tal *tal, struct repotab *rt, size_t *eid) 459{ 460 char *nfile; 461 const struct repo *repo; 462 const char *uri; 463 464 assert(tal->urisz); 465 uri = tal->uri[0]; 466 467 /* Look up the repository. */ 468 469 assert(rtype_resolve(uri) == RTYPE_CER); 470 repo = repo_lookup(rsync, rt, uri); 471 uri += 8 + strlen(repo->host) + 1 + strlen(repo->module) + 1; 472 473 if (asprintf(&nfile, "%s/%s/%s/%s", 474 BASE_DIR, repo->host, repo->module, uri) == -1) 475 err(EXIT_FAILURE, "asprintf"); 476 477 entityq_add(proc, q, nfile, RTYPE_CER, repo, NULL, tal->pkey, 478 tal->pkeysz, eid); 479} 480 481/* 482 * Add a manifest (MFT) or CRL found in an X509 certificate, RFC 6487. 483 */ 484static void 485queue_add_from_cert(int proc, int rsync, struct entityq *q, 486 const char *uri, struct repotab *rt, size_t *eid) 487{ 488 char *nfile; 489 enum rtype type; 490 const struct repo *repo; 491 492 if ((type = rtype_resolve(uri)) == RTYPE_EOF) 493 errx(EXIT_FAILURE, "%s: unknown file type", uri); 494 if (type != RTYPE_MFT && type != RTYPE_CRL) 495 errx(EXIT_FAILURE, "%s: invalid file type", uri); 496 497 /* Look up the repository. */ 498 499 repo = repo_lookup(rsync, rt, uri); 500 uri += 8 + strlen(repo->host) + 1 + strlen(repo->module) + 1; 501 502 if (asprintf(&nfile, "%s/%s/%s/%s", 503 BASE_DIR, repo->host, repo->module, uri) == -1) 504 err(EXIT_FAILURE, "asprintf"); 505 506 entityq_add(proc, q, nfile, type, repo, NULL, NULL, 0, eid); 507} 508 509static void 510proc_child(int signal) 511{ 512 513 /* Nothing: just discard. */ 514} 515 516/* 517 * Process used for synchronising repositories. 518 * This simply waits to be told which repository to synchronise, then 519 * does so. 520 * It then responds with the identifier of the repo that it updated. 521 * It only exits cleanly when fd is closed. 522 * FIXME: this should use buffered output to prevent deadlocks, but it's 523 * very unlikely that we're going to fill our buffer, so whatever. 524 * FIXME: limit the number of simultaneous process. 525 * Currently, an attacker can trivially specify thousands of different 526 * repositories and saturate our system. 527 */ 528static void 529proc_rsync(const char *prog, const char *bind_addr, int fd, int noop) 530{ 531 size_t id, i, idsz = 0; 532 ssize_t ssz; 533 char *host = NULL, *mod = NULL, *uri = NULL, 534 *dst = NULL, *path, *save, *cmd; 535 const char *pp; 536 pid_t pid; 537 char *args[32]; 538 int st, rc = 0; 539 struct stat stt; 540 struct pollfd pfd; 541 sigset_t mask, oldmask; 542 struct rsyncproc *ids = NULL; 543 544 pfd.fd = fd; 545 pfd.events = POLLIN; 546 547 /* 548 * Unveil the command we want to run. 549 * If this has a pathname component in it, interpret as a file 550 * and unveil the file directly. 551 * Otherwise, look up the command in our PATH. 552 */ 553 554 if (!noop) { 555 if (strchr(prog, '/') == NULL) { 556 if (getenv("PATH") == NULL) 557 errx(EXIT_FAILURE, "PATH is unset"); 558 if ((path = strdup(getenv("PATH"))) == NULL) 559 err(EXIT_FAILURE, "strdup"); 560 save = path; 561 while ((pp = strsep(&path, ":")) != NULL) { 562 if (*pp == '\0') 563 continue; 564 if (asprintf(&cmd, "%s/%s", pp, prog) == -1) 565 err(EXIT_FAILURE, "asprintf"); 566 if (lstat(cmd, &stt) == -1) { 567 free(cmd); 568 continue; 569 } else if (unveil(cmd, "x") == -1) 570 err(EXIT_FAILURE, "%s: unveil", cmd); 571 free(cmd); 572 break; 573 } 574 free(save); 575 } else if (unveil(prog, "x") == -1) 576 err(EXIT_FAILURE, "%s: unveil", prog); 577 578 /* Unveil the repository directory and terminate unveiling. */ 579 580 if (unveil(BASE_DIR, "c") == -1) 581 err(EXIT_FAILURE, "%s: unveil", BASE_DIR); 582 if (unveil(NULL, NULL) == -1) 583 err(EXIT_FAILURE, "unveil"); 584 } 585 586 /* Initialise retriever for children exiting. */ 587 588 if (sigemptyset(&mask) == -1) 589 err(EXIT_FAILURE, NULL); 590 if (signal(SIGCHLD, proc_child) == SIG_ERR) 591 err(EXIT_FAILURE, NULL); 592 if (sigaddset(&mask, SIGCHLD) == -1) 593 err(EXIT_FAILURE, NULL); 594 if (sigprocmask(SIG_BLOCK, &mask, &oldmask) == -1) 595 err(EXIT_FAILURE, NULL); 596 597 for (;;) { 598 if (ppoll(&pfd, 1, NULL, &oldmask) == -1) { 599 if (errno != EINTR) 600 err(EXIT_FAILURE, "ppoll"); 601 602 /* 603 * If we've received an EINTR, it means that one 604 * of our children has exited and we can reap it 605 * and look up its identifier. 606 * Then we respond to the parent. 607 */ 608 609 if ((pid = waitpid(WAIT_ANY, &st, 0)) == -1) 610 err(EXIT_FAILURE, "waitpid"); 611 612 for (i = 0; i < idsz; i++) 613 if (ids[i].pid == pid) 614 break; 615 assert(i < idsz); 616 617 if (!WIFEXITED(st)) { 618 warnx("rsync %s did not exit", ids[i].uri); 619 goto out; 620 } else if (WEXITSTATUS(st) != EXIT_SUCCESS) { 621 warnx("rsync %s failed", ids[i].uri); 622 goto out; 623 } 624 625 io_simple_write(fd, &ids[i].id, sizeof(size_t)); 626 free(ids[i].uri); 627 ids[i].uri = NULL; 628 ids[i].pid = 0; 629 ids[i].id = 0; 630 continue; 631 } 632 633 /* 634 * Read til the parent exits. 635 * That will mean that we can safely exit. 636 */ 637 638 if ((ssz = read(fd, &id, sizeof(size_t))) == -1) 639 err(EXIT_FAILURE, "read"); 640 if (ssz == 0) 641 break; 642 643 /* Read host and module. */ 644 645 io_str_read(fd, &host); 646 io_str_read(fd, &mod); 647 648 if (noop) { 649 io_simple_write(fd, &id, sizeof(size_t)); 650 free(host); 651 free(mod); 652 continue; 653 } 654 655 /* 656 * Create source and destination locations. 657 * Build up the tree to this point because GPL rsync(1) 658 * will not build the destination for us. 659 */ 660 661 if (asprintf(&dst, "%s/%s", BASE_DIR, host) == -1) 662 err(EXIT_FAILURE, NULL); 663 if (mkdir(dst, 0700) == -1 && EEXIST != errno) 664 err(EXIT_FAILURE, "%s", dst); 665 free(dst); 666 667 if (asprintf(&dst, "%s/%s/%s", BASE_DIR, host, mod) == -1) 668 err(EXIT_FAILURE, NULL); 669 if (mkdir(dst, 0700) == -1 && EEXIST != errno) 670 err(EXIT_FAILURE, "%s", dst); 671 672 if (asprintf(&uri, "rsync://%s/%s", host, mod) == -1) 673 err(EXIT_FAILURE, NULL); 674 675 /* Run process itself, wait for exit, check error. */ 676 677 if ((pid = fork()) == -1) 678 err(EXIT_FAILURE, "fork"); 679 680 if (pid == 0) { 681 if (pledge("stdio exec", NULL) == -1) 682 err(EXIT_FAILURE, "pledge"); 683 i = 0; 684 args[i++] = (char *)prog; 685 args[i++] = "-rlt"; 686 args[i++] = "--delete"; 687 if (bind_addr != NULL) { 688 args[i++] = "--address"; 689 args[i++] = (char *)bind_addr; 690 } 691 args[i++] = uri; 692 args[i++] = dst; 693 args[i] = NULL; 694 execvp(args[0], args); 695 err(EXIT_FAILURE, "%s: execvp", prog); 696 } 697 698 /* Augment the list of running processes. */ 699 700 for (i = 0; i < idsz; i++) 701 if (ids[i].pid == 0) 702 break; 703 if (i == idsz) { 704 ids = reallocarray(ids, idsz + 1, sizeof(*ids)); 705 if (ids == NULL) 706 err(EXIT_FAILURE, NULL); 707 idsz++; 708 } 709 710 ids[i].id = id; 711 ids[i].pid = pid; 712 ids[i].uri = uri; 713 714 /* Clean up temporary values. */ 715 716 free(mod); 717 free(dst); 718 free(host); 719 } 720 rc = 1; 721out: 722 723 /* No need for these to be hanging around. */ 724 725 for (i = 0; i < idsz; i++) 726 if (ids[i].pid > 0) { 727 kill(ids[i].pid, SIGTERM); 728 free(ids[i].uri); 729 } 730 731 free(ids); 732 exit(rc ? EXIT_SUCCESS : EXIT_FAILURE); 733 /* NOTREACHED */ 734} 735 736/* 737 * Parse and validate a ROA, not parsing the CRL bits of "norev" has 738 * been set. 739 * This is standard stuff. 740 * Returns the roa on success, NULL on failure. 741 */ 742static struct roa * 743proc_parser_roa(struct entity *entp, int norev, 744 X509_STORE *store, X509_STORE_CTX *ctx, 745 const struct auth *auths, size_t authsz) 746{ 747 struct roa *roa; 748 X509 *x509; 749 int c; 750 X509_VERIFY_PARAM *param; 751 unsigned int fl, nfl; 752 753 assert(entp->has_dgst); 754 if ((roa = roa_parse(&x509, entp->uri, entp->dgst)) == NULL) 755 return NULL; 756 757 assert(x509 != NULL); 758 if (!X509_STORE_CTX_init(ctx, store, x509, NULL)) 759 cryptoerrx("X509_STORE_CTX_init"); 760 761 if ((param = X509_STORE_CTX_get0_param(ctx)) == NULL) 762 cryptoerrx("X509_STORE_CTX_get0_param"); 763 fl = X509_VERIFY_PARAM_get_flags(param); 764 nfl = X509_V_FLAG_IGNORE_CRITICAL; 765 if (!norev) 766 nfl |= X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL; 767 if (!X509_VERIFY_PARAM_set_flags(param, fl | nfl)) 768 cryptoerrx("X509_VERIFY_PARAM_set_flags"); 769 770 if (X509_verify_cert(ctx) <= 0) { 771 c = X509_STORE_CTX_get_error(ctx); 772 X509_STORE_CTX_cleanup(ctx); 773 if (verbose > 0 || c != X509_V_ERR_UNABLE_TO_GET_CRL) 774 warnx("%s: %s", entp->uri, 775 X509_verify_cert_error_string(c)); 776 X509_free(x509); 777 roa_free(roa); 778 return NULL; 779 } 780 X509_STORE_CTX_cleanup(ctx); 781 X509_free(x509); 782 783 /* 784 * If the ROA isn't valid, we accept it anyway and depend upon 785 * the code around roa_read() to check the "valid" field itself. 786 */ 787 788 roa->valid = valid_roa(entp->uri, auths, authsz, roa); 789 return roa; 790} 791 792/* 793 * Parse and validate a manifest file. 794 * Here we *don't* validate against the list of CRLs, because the 795 * certificate used to sign the manifest may specify a CRL that the root 796 * certificate didn't, and we haven't scanned for it yet. 797 * This chicken-and-egg isn't important, however, because we'll catch 798 * the revocation list by the time we scan for any contained resources 799 * (ROA, CER) and will see it then. 800 * Return the mft on success or NULL on failure. 801 */ 802static struct mft * 803proc_parser_mft(struct entity *entp, int force, X509_STORE *store, 804 X509_STORE_CTX *ctx, const struct auth *auths, size_t authsz) 805{ 806 struct mft *mft; 807 X509 *x509; 808 int c; 809 unsigned int fl, nfl; 810 X509_VERIFY_PARAM *param; 811 812 assert(!entp->has_dgst); 813 if ((mft = mft_parse(&x509, entp->uri, force)) == NULL) 814 return NULL; 815 816 if (!X509_STORE_CTX_init(ctx, store, x509, NULL)) 817 cryptoerrx("X509_STORE_CTX_init"); 818 819 if ((param = X509_STORE_CTX_get0_param(ctx)) == NULL) 820 cryptoerrx("X509_STORE_CTX_get0_param"); 821 fl = X509_VERIFY_PARAM_get_flags(param); 822 nfl = X509_V_FLAG_IGNORE_CRITICAL; 823 if (!X509_VERIFY_PARAM_set_flags(param, fl | nfl)) 824 cryptoerrx("X509_VERIFY_PARAM_set_flags"); 825 826 if (X509_verify_cert(ctx) <= 0) { 827 c = X509_STORE_CTX_get_error(ctx); 828 X509_STORE_CTX_cleanup(ctx); 829 warnx("%s: %s", entp->uri, X509_verify_cert_error_string(c)); 830 mft_free(mft); 831 X509_free(x509); 832 return NULL; 833 } 834 835 X509_STORE_CTX_cleanup(ctx); 836 X509_free(x509); 837 return mft; 838} 839 840/* 841 * Certificates are from manifests (has a digest and is signed with 842 * another certificate) or TALs (has a pkey and is self-signed). 843 * Parse the certificate, make sure its signatures are valid (with CRLs 844 * unless "norev" has been specified), then validate the RPKI content. 845 * This returns a certificate (which must not be freed) or NULL on parse 846 * failure. 847 */ 848static struct cert * 849proc_parser_cert(const struct entity *entp, int norev, 850 X509_STORE *store, X509_STORE_CTX *ctx, 851 struct auth **auths, size_t *authsz) 852{ 853 struct cert *cert; 854 X509 *x509; 855 int c; 856 X509_VERIFY_PARAM *param; 857 unsigned int fl, nfl; 858 ssize_t id; 859 860 assert(!entp->has_dgst != !entp->has_pkey); 861 862 /* Extract certificate data and X509. */ 863 864 cert = entp->has_dgst ? cert_parse(&x509, entp->uri, entp->dgst) : 865 ta_parse(&x509, entp->uri, entp->pkey, entp->pkeysz); 866 if (cert == NULL) 867 return NULL; 868 869 /* 870 * Validate certificate chain w/CRLs. 871 * Only check the CRLs if specifically asked. 872 */ 873 874 assert(x509 != NULL); 875 if (!X509_STORE_CTX_init(ctx, store, x509, NULL)) 876 cryptoerrx("X509_STORE_CTX_init"); 877 if ((param = X509_STORE_CTX_get0_param(ctx)) == NULL) 878 cryptoerrx("X509_STORE_CTX_get0_param"); 879 fl = X509_VERIFY_PARAM_get_flags(param); 880 nfl = X509_V_FLAG_IGNORE_CRITICAL; 881 if (!norev) 882 nfl |= X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL; 883 if (!X509_VERIFY_PARAM_set_flags(param, fl | nfl)) 884 cryptoerrx("X509_VERIFY_PARAM_set_flags"); 885 886 /* 887 * FIXME: can we pass any options to the verification that make 888 * the depth-zero self-signed bits verify properly? 889 */ 890 891 if (X509_verify_cert(ctx) <= 0) { 892 c = X509_STORE_CTX_get_error(ctx); 893 if (c != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || 894 !entp->has_pkey) { 895 warnx("%s: %s", entp->uri, 896 X509_verify_cert_error_string(c)); 897 X509_STORE_CTX_cleanup(ctx); 898 X509_free(x509); 899 cert_free(cert); 900 return NULL; 901 } 902 } 903 X509_STORE_CTX_cleanup(ctx); 904 905 /* Semantic validation of RPKI content. */ 906 907 id = entp->has_pkey ? 908 valid_ta(entp->uri, *auths, *authsz, cert) : 909 valid_cert(entp->uri, *auths, *authsz, cert); 910 911 if (id < 0) { 912 X509_free(x509); 913 return cert; 914 } 915 916 /* 917 * Only on success of all do we add the certificate to the store 918 * of trusted certificates, both X509 and RPKI semantic. 919 */ 920 921 cert->valid = 1; 922 *auths = reallocarray(*auths, *authsz + 1, sizeof(struct auth)); 923 if (*auths == NULL) 924 err(EXIT_FAILURE, NULL); 925 926 (*auths)[*authsz].id = *authsz; 927 (*auths)[*authsz].parent = id; 928 (*auths)[*authsz].cert = cert; 929 (*auths)[*authsz].fn = strdup(entp->uri); 930 if ((*auths)[*authsz].fn == NULL) 931 err(EXIT_FAILURE, NULL); 932 (*authsz)++; 933 934 X509_STORE_add_cert(store, x509); 935 X509_free(x509); 936 return cert; 937} 938 939/* 940 * Parse a certificate revocation list (unless "norev", in which case 941 * this is a noop that returns success). 942 * This simply parses the CRL content itself, optionally validating it 943 * within the digest if it comes from a manifest, then adds it to the 944 * store of CRLs. 945 */ 946static void 947proc_parser_crl(struct entity *entp, int norev, X509_STORE *store, 948 X509_STORE_CTX *ctx, const struct auth *auths, size_t authsz) 949{ 950 X509_CRL *x509; 951 const unsigned char *dgst; 952 953 if (norev) 954 return; 955 956 dgst = entp->has_dgst ? entp->dgst : NULL; 957 if ((x509 = crl_parse(entp->uri, dgst)) != NULL) { 958 X509_STORE_add_crl(store, x509); 959 X509_CRL_free(x509); 960 } 961} 962 963/* 964 * Process responsible for parsing and validating content. 965 * All this process does is wait to be told about a file to parse, then 966 * it parses it and makes sure that the data being returned is fully 967 * validated and verified. 968 * The process will exit cleanly only when fd is closed. 969 */ 970static void 971proc_parser(int fd, int force, int norev) 972{ 973 struct tal *tal; 974 struct cert *cert; 975 struct mft *mft; 976 struct roa *roa; 977 struct entity *entp; 978 struct entityq q; 979 int c, rc = 0; 980 struct pollfd pfd; 981 char *b = NULL; 982 size_t i, bsz = 0, bmax = 0, bpos = 0, authsz = 0; 983 ssize_t ssz; 984 X509_STORE *store; 985 X509_STORE_CTX *ctx; 986 struct auth *auths = NULL; 987 int first_tals = 1; 988 989 ERR_load_crypto_strings(); 990 OpenSSL_add_all_ciphers(); 991 OpenSSL_add_all_digests(); 992 993 if ((store = X509_STORE_new()) == NULL) 994 cryptoerrx("X509_STORE_new"); 995 if ((ctx = X509_STORE_CTX_new()) == NULL) 996 cryptoerrx("X509_STORE_CTX_new"); 997 998 TAILQ_INIT(&q); 999 1000 pfd.fd = fd; 1001 pfd.events = POLLIN; 1002 1003 io_socket_nonblocking(pfd.fd); 1004 1005 for (;;) { 1006 if (poll(&pfd, 1, INFTIM) == -1) 1007 err(EXIT_FAILURE, "poll"); 1008 if ((pfd.revents & (POLLERR|POLLNVAL))) 1009 errx(EXIT_FAILURE, "poll: bad descriptor"); 1010 1011 /* If the parent closes, return immediately. */ 1012 1013 if ((pfd.revents & POLLHUP)) 1014 break; 1015 1016 /* 1017 * Start with read events. 1018 * This means that the parent process is sending us 1019 * something we need to parse. 1020 * We don't actually parse it til we have space in our 1021 * outgoing buffer for responding, though. 1022 */ 1023 1024 if ((pfd.revents & POLLIN)) { 1025 io_socket_blocking(fd); 1026 entp = calloc(1, sizeof(struct entity)); 1027 if (entp == NULL) 1028 err(EXIT_FAILURE, NULL); 1029 entity_read_req(fd, entp); 1030 TAILQ_INSERT_TAIL(&q, entp, entries); 1031 pfd.events |= POLLOUT; 1032 io_socket_nonblocking(fd); 1033 } 1034 1035 if (!(pfd.revents & POLLOUT)) 1036 continue; 1037 1038 /* 1039 * If we have a write buffer, then continue trying to 1040 * push it all out. 1041 * When it's all pushed out, reset it and get ready to 1042 * continue sucking down more data. 1043 */ 1044 1045 if (bsz) { 1046 assert(bpos < bmax); 1047 if ((ssz = write(fd, b + bpos, bsz)) == -1) 1048 err(EXIT_FAILURE, "write"); 1049 bpos += ssz; 1050 bsz -= ssz; 1051 if (bsz) 1052 continue; 1053 bpos = bsz = 0; 1054 } 1055 1056 /* 1057 * If there's nothing to parse, then stop waiting for 1058 * the write signal. 1059 */ 1060 1061 if (TAILQ_EMPTY(&q)) { 1062 pfd.events &= ~POLLOUT; 1063 continue; 1064 } 1065 1066 entp = TAILQ_FIRST(&q); 1067 assert(entp != NULL); 1068 1069 /* 1070 * Extra security. 1071 * Our TAL files may be anywhere, but the repository 1072 * resources may only be in BASE_DIR. 1073 * When we've finished processing TAL files, make sure 1074 * that we can only see what's under that. 1075 */ 1076 1077 if (entp->type != RTYPE_TAL && first_tals) { 1078 if (unveil(BASE_DIR, "r") == -1) 1079 err(EXIT_FAILURE, "%s: unveil", BASE_DIR); 1080 if (unveil(NULL, NULL) == -1) 1081 err(EXIT_FAILURE, "unveil"); 1082 first_tals = 0; 1083 } else if (entp->type != RTYPE_TAL) { 1084 assert(!first_tals); 1085 } else if (entp->type == RTYPE_TAL) 1086 assert(first_tals); 1087 1088 entity_buffer_resp(&b, &bsz, &bmax, entp); 1089 1090 switch (entp->type) { 1091 case RTYPE_TAL: 1092 assert(!entp->has_dgst); 1093 if ((tal = tal_parse(entp->uri)) == NULL) 1094 goto out; 1095 tal_buffer(&b, &bsz, &bmax, tal); 1096 tal_free(tal); 1097 break; 1098 case RTYPE_CER: 1099 cert = proc_parser_cert(entp, norev, 1100 store, ctx, &auths, &authsz); 1101 c = (cert != NULL); 1102 io_simple_buffer(&b, &bsz, &bmax, &c, sizeof(int)); 1103 if (cert != NULL) 1104 cert_buffer(&b, &bsz, &bmax, cert); 1105 /* 1106 * The parsed certificate data "cert" is now 1107 * managed in the "auths" table, so don't free 1108 * it here (see the loop after "out"). 1109 */ 1110 break; 1111 case RTYPE_MFT: 1112 mft = proc_parser_mft(entp, force, 1113 store, ctx, auths, authsz); 1114 c = (mft != NULL); 1115 io_simple_buffer(&b, &bsz, &bmax, &c, sizeof(int)); 1116 if (mft != NULL) 1117 mft_buffer(&b, &bsz, &bmax, mft); 1118 mft_free(mft); 1119 break; 1120 case RTYPE_CRL: 1121 proc_parser_crl(entp, norev, 1122 store, ctx, auths, authsz); 1123 break; 1124 case RTYPE_ROA: 1125 assert(entp->has_dgst); 1126 roa = proc_parser_roa(entp, norev, 1127 store, ctx, auths, authsz); 1128 c = (roa != NULL); 1129 io_simple_buffer(&b, &bsz, &bmax, &c, sizeof(int)); 1130 if (roa != NULL) 1131 roa_buffer(&b, &bsz, &bmax, roa); 1132 roa_free(roa); 1133 break; 1134 default: 1135 abort(); 1136 } 1137 1138 TAILQ_REMOVE(&q, entp, entries); 1139 entity_free(entp); 1140 } 1141 1142 rc = 1; 1143out: 1144 while ((entp = TAILQ_FIRST(&q)) != NULL) { 1145 TAILQ_REMOVE(&q, entp, entries); 1146 entity_free(entp); 1147 } 1148 1149 for (i = 0; i < authsz; i++) { 1150 free(auths[i].fn); 1151 cert_free(auths[i].cert); 1152 } 1153 1154 X509_STORE_CTX_free(ctx); 1155 X509_STORE_free(store); 1156 free(auths); 1157 1158 free(b); 1159 1160 EVP_cleanup(); 1161 CRYPTO_cleanup_all_ex_data(); 1162 ERR_remove_state(0); 1163 ERR_free_strings(); 1164 1165 exit(rc ? EXIT_SUCCESS : EXIT_FAILURE); 1166} 1167 1168/* 1169 * Process parsed content. 1170 * For non-ROAs, we grok for more data. 1171 * For ROAs, we want to extract the valid info. 1172 * In all cases, we gather statistics. 1173 */ 1174static void 1175entity_process(int proc, int rsync, struct stats *st, 1176 struct entityq *q, const struct entity *ent, struct repotab *rt, 1177 size_t *eid, struct roa ***out, size_t *outsz) 1178{ 1179 struct tal *tal; 1180 struct cert *cert; 1181 struct mft *mft; 1182 struct roa *roa; 1183 int c; 1184 1185 /* 1186 * For most of these, we first read whether there's any content 1187 * at all---this means that the syntactic parse failed (X509 1188 * certificate, for example). 1189 * We follow that up with whether the resources didn't parse. 1190 */ 1191 1192 switch (ent->type) { 1193 case RTYPE_TAL: 1194 st->tals++; 1195 tal = tal_read(proc); 1196 queue_add_from_tal(proc, rsync, q, tal, rt, eid); 1197 tal_free(tal); 1198 break; 1199 case RTYPE_CER: 1200 st->certs++; 1201 io_simple_read(proc, &c, sizeof(int)); 1202 if (c == 0) { 1203 st->certs_fail++; 1204 break; 1205 } 1206 cert = cert_read(proc); 1207 if (cert->valid) { 1208 /* 1209 * Process the revocation list from the 1210 * certificate *first*, since it might mark that 1211 * we're revoked and then we don't want to 1212 * process the MFT. 1213 */ 1214 if (cert->crl != NULL) 1215 queue_add_from_cert(proc, rsync, 1216 q, cert->crl, rt, eid); 1217 if (cert->mft != NULL) 1218 queue_add_from_cert(proc, rsync, 1219 q, cert->mft, rt, eid); 1220 } else 1221 st->certs_invalid++; 1222 cert_free(cert); 1223 break; 1224 case RTYPE_MFT: 1225 st->mfts++; 1226 io_simple_read(proc, &c, sizeof(int)); 1227 if (c == 0) { 1228 st->mfts_fail++; 1229 break; 1230 } 1231 mft = mft_read(proc); 1232 if (mft->stale) 1233 st->mfts_stale++; 1234 queue_add_from_mft_set(proc, q, mft, eid); 1235 mft_free(mft); 1236 break; 1237 case RTYPE_CRL: 1238 st->crls++; 1239 break; 1240 case RTYPE_ROA: 1241 st->roas++; 1242 io_simple_read(proc, &c, sizeof(int)); 1243 if (c == 0) { 1244 st->roas_fail++; 1245 break; 1246 } 1247 roa = roa_read(proc); 1248 if (roa->valid) { 1249 *out = reallocarray(*out, 1250 *outsz + 1, sizeof(struct roa *)); 1251 if (*out == NULL) 1252 err(EXIT_FAILURE, "reallocarray"); 1253 (*out)[*outsz] = roa; 1254 (*outsz)++; 1255 /* We roa_free() on exit. */ 1256 } else { 1257 st->roas_invalid++; 1258 roa_free(roa); 1259 } 1260 break; 1261 default: 1262 abort(); 1263 } 1264} 1265 1266#define TALSZ_MAX 8 1267 1268size_t 1269tal_load_default(const char *tals[], size_t max) 1270{ 1271 static const char *basedir = "/etc/rpki"; 1272 size_t s = 0; 1273 char *path; 1274 DIR *dirp; 1275 struct dirent *dp; 1276 1277 dirp = opendir(basedir); 1278 if (dirp == NULL) 1279 err(EXIT_FAILURE, "open %s", basedir); 1280 while ((dp = readdir(dirp)) != NULL) { 1281 if (fnmatch("*.tal", dp->d_name, FNM_PERIOD) == FNM_NOMATCH) 1282 continue; 1283 if (s >= max) 1284 err(EXIT_FAILURE, "too many tal files found in %s", 1285 basedir); 1286 if (asprintf(&path, "%s/%s", basedir, dp->d_name) == -1) 1287 err(EXIT_FAILURE, "asprintf"); 1288 tals[s++] = path; 1289 } 1290 closedir (dirp); 1291 return (s); 1292} 1293 1294int 1295main(int argc, char *argv[]) 1296{ 1297 int rc = 0, c, proc, st, rsync, 1298 fl = SOCK_STREAM | SOCK_CLOEXEC, noop = 0, 1299 force = 0, norev = 0; 1300 size_t i, j, eid = 1, outsz = 0, talsz = 0, vrps, uniqs; 1301 pid_t procpid, rsyncpid; 1302 int fd[2]; 1303 struct entityq q; 1304 struct entity *ent; 1305 struct pollfd pfd[2]; 1306 struct repotab rt; 1307 struct stats stats; 1308 struct roa **out = NULL; 1309 const char *rsync_prog = "openrsync"; 1310 const char *bind_addr = NULL; 1311 const char *tals[TALSZ_MAX]; 1312 FILE *output = NULL; 1313 1314 if (pledge("stdio rpath wpath cpath proc exec unveil", NULL) == -1) 1315 err(EXIT_FAILURE, "pledge"); 1316 1317 while ((c = getopt(argc, argv, "b:e:fnrt:v")) != -1) 1318 switch (c) { 1319 case 'b': 1320 bind_addr = optarg; 1321 break; 1322 case 'e': 1323 rsync_prog = optarg; 1324 break; 1325 case 'f': 1326 force = 1; 1327 break; 1328 case 'n': 1329 noop = 1; 1330 break; 1331 case 'r': 1332 norev = 1; 1333 break; 1334 case 't': 1335 if (talsz >= TALSZ_MAX) 1336 err(EXIT_FAILURE, 1337 "too many tal files specified"); 1338 tals[talsz++] = optarg; 1339 break; 1340 case 'v': 1341 verbose++; 1342 break; 1343 default: 1344 goto usage; 1345 } 1346 1347 argv += optind; 1348 argc -= optind; 1349 if (argc != 1) 1350 goto usage; 1351 output = fopen(argv[0], "we"); 1352 if (output == NULL) 1353 err(EXIT_FAILURE, "failed to open %s", argv[0]); 1354 1355 if (talsz == 0) 1356 talsz = tal_load_default(tals, TALSZ_MAX); 1357 if (talsz == 0) 1358 err(EXIT_FAILURE, "no TAL files found in %s", "/etc/rpki"); 1359 1360 memset(&rt, 0, sizeof(struct repotab)); 1361 memset(&stats, 0, sizeof(struct stats)); 1362 TAILQ_INIT(&q); 1363 1364 /* 1365 * Create the file reader as a jailed child process. 1366 * It will be responsible for reading all of the files (ROAs, 1367 * manifests, certificates, etc.) and returning contents. 1368 */ 1369 1370 if (socketpair(AF_UNIX, fl, 0, fd) == -1) 1371 err(EXIT_FAILURE, "socketpair"); 1372 if ((procpid = fork()) == -1) 1373 err(EXIT_FAILURE, "fork"); 1374 1375 if (procpid == 0) { 1376 close(fd[1]); 1377 if (pledge("stdio rpath unveil", NULL) == -1) 1378 err(EXIT_FAILURE, "pledge"); 1379 proc_parser(fd[0], force, norev); 1380 /* NOTREACHED */ 1381 } 1382 1383 close(fd[0]); 1384 proc = fd[1]; 1385 1386 /* 1387 * Create a process that will do the rsync'ing. 1388 * This process is responsible for making sure that all the 1389 * repositories referenced by a certificate manifest (or the 1390 * TAL) exists and has been downloaded. 1391 */ 1392 1393 if (socketpair(AF_UNIX, fl, 0, fd) == -1) 1394 err(EXIT_FAILURE, "socketpair"); 1395 if ((rsyncpid = fork()) == -1) 1396 err(EXIT_FAILURE, "fork"); 1397 1398 if (rsyncpid == 0) { 1399 close(proc); 1400 close(fd[1]); 1401 if (pledge("stdio rpath cpath proc exec unveil", NULL) == -1) 1402 err(EXIT_FAILURE, "pledge"); 1403 1404 /* If -n, we don't exec or mkdir. */ 1405 1406 if (noop && pledge("stdio", NULL) == -1) 1407 err(EXIT_FAILURE, "pledge"); 1408 proc_rsync(rsync_prog, bind_addr, fd[0], noop); 1409 /* NOTREACHED */ 1410 } 1411 1412 close(fd[0]); 1413 rsync = fd[1]; 1414 1415 assert(rsync != proc); 1416 1417 /* 1418 * The main process drives the top-down scan to leaf ROAs using 1419 * data downloaded by the rsync process and parsed by the 1420 * parsing process. 1421 */ 1422 1423 if (pledge("stdio", NULL) == -1) 1424 err(EXIT_FAILURE, "pledge"); 1425 1426 /* 1427 * Prime the process with our TAL file. 1428 * This will contain (hopefully) links to our manifest and we 1429 * can get the ball rolling. 1430 */ 1431 1432 for (i = 0; i < talsz; i++) 1433 queue_add_tal(proc, &q, tals[i], &eid); 1434 1435 pfd[0].fd = rsync; 1436 pfd[1].fd = proc; 1437 pfd[0].events = pfd[1].events = POLLIN; 1438 1439 while (!TAILQ_EMPTY(&q)) { 1440 if ((c = poll(pfd, 2, verbose ? 10000 : INFTIM)) == -1) 1441 err(EXIT_FAILURE, "poll"); 1442 1443 /* Debugging: print some statistics if we stall. */ 1444 1445 if (c == 0) { 1446 for (i = j = 0; i < rt.reposz; i++) 1447 if (!rt.repos[i].loaded) 1448 j++; 1449 logx("period stats: %zu pending repos", j); 1450 j = 0; 1451 TAILQ_FOREACH(ent, &q, entries) 1452 j++; 1453 logx("period stats: %zu pending entries", j); 1454 continue; 1455 } 1456 1457 if ((pfd[0].revents & (POLLERR|POLLNVAL)) || 1458 (pfd[1].revents & (POLLERR|POLLNVAL))) 1459 errx(EXIT_FAILURE, "poll: bad fd"); 1460 if ((pfd[0].revents & POLLHUP) || 1461 (pfd[1].revents & POLLHUP)) 1462 errx(EXIT_FAILURE, "poll: hangup"); 1463 1464 /* 1465 * Check the rsync process. 1466 * This means that one of our modules has completed 1467 * downloading and we can flush the module requests into 1468 * the parser process. 1469 */ 1470 1471 if ((pfd[0].revents & POLLIN)) { 1472 io_simple_read(rsync, &i, sizeof(size_t)); 1473 assert(i < rt.reposz); 1474 assert(!rt.repos[i].loaded); 1475 rt.repos[i].loaded = 1; 1476 logx("%s/%s/%s: loaded", BASE_DIR, 1477 rt.repos[i].host, rt.repos[i].module); 1478 stats.repos++; 1479 entityq_flush(proc, &q, &rt.repos[i]); 1480 } 1481 1482 /* 1483 * The parser has finished something for us. 1484 * Dequeue these one by one. 1485 */ 1486 1487 if ((pfd[1].revents & POLLIN)) { 1488 ent = entityq_next(proc, &q); 1489 entity_process(proc, rsync, &stats, 1490 &q, ent, &rt, &eid, &out, &outsz); 1491 if (verbose > 1) 1492 fprintf(stderr, "%s\n", ent->uri); 1493 entity_free(ent); 1494 } 1495 } 1496 1497 assert(TAILQ_EMPTY(&q)); 1498 logx("all files parsed: exiting"); 1499 rc = 1; 1500 1501 /* 1502 * For clean-up, close the input for the parser and rsync 1503 * process. 1504 * This will cause them to exit, then we reap them. 1505 */ 1506 1507 close(proc); 1508 close(rsync); 1509 1510 if (waitpid(procpid, &st, 0) == -1) 1511 err(EXIT_FAILURE, "waitpid"); 1512 if (!WIFEXITED(st) || WEXITSTATUS(st) != EXIT_SUCCESS) { 1513 warnx("parser process exited abnormally"); 1514 rc = 0; 1515 } 1516 if (waitpid(rsyncpid, &st, 0) == -1) 1517 err(EXIT_FAILURE, "waitpid"); 1518 if (!WIFEXITED(st) || WEXITSTATUS(st) != EXIT_SUCCESS) { 1519 warnx("rsync process exited abnormally"); 1520 rc = 0; 1521 } 1522 1523 /* Output and statistics. */ 1524 1525 output_bgpd(output, (const struct roa **)out, 1526 outsz, &vrps, &uniqs); 1527 logx("Route Origin Authorizations: %zu (%zu failed parse, %zu invalid)", 1528 stats.roas, stats.roas_fail, stats.roas_invalid); 1529 logx("Certificates: %zu (%zu failed parse, %zu invalid)", 1530 stats.certs, stats.certs_fail, stats.certs_invalid); 1531 logx("Trust Anchor Locators: %zu", stats.tals); 1532 logx("Manifests: %zu (%zu failed parse, %zu stale)", 1533 stats.mfts, stats.mfts_fail, stats.mfts_stale); 1534 logx("Certificate revocation lists: %zu", stats.crls); 1535 logx("Repositories: %zu", stats.repos); 1536 logx("VRP Entries: %zu (%zu unique)", vrps, uniqs); 1537 1538 /* Memory cleanup. */ 1539 1540 for (i = 0; i < rt.reposz; i++) { 1541 free(rt.repos[i].host); 1542 free(rt.repos[i].module); 1543 } 1544 free(rt.repos); 1545 1546 for (i = 0; i < outsz; i++) 1547 roa_free(out[i]); 1548 free(out); 1549 1550 return rc ? EXIT_SUCCESS : EXIT_FAILURE; 1551 1552usage: 1553 fprintf(stderr, 1554 "usage: rpki-client [-fnqrv] [-b bind_addr] [-e rsync_prog] " 1555 "[-t tal] output\n"); 1556 return EXIT_FAILURE; 1557} 1558