1 /* $OpenBSD: filemode.c,v 1.57 2024/12/16 13:53:37 tb Exp $ */ 2 /* 3 * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org> 4 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/queue.h> 20 #include <sys/tree.h> 21 #include <sys/types.h> 22 23 #include <assert.h> 24 #include <err.h> 25 #include <fcntl.h> 26 #include <poll.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <limits.h> 31 #include <unistd.h> 32 #include <imsg.h> 33 34 #include <openssl/asn1.h> 35 #include <openssl/err.h> 36 #include <openssl/evp.h> 37 #include <openssl/pem.h> 38 #include <openssl/x509.h> 39 #include <openssl/x509v3.h> 40 41 #include "extern.h" 42 #include "json.h" 43 44 extern BN_CTX *bn_ctx; 45 46 static X509_STORE_CTX *ctx; 47 static struct auth_tree auths = RB_INITIALIZER(&auths); 48 static struct crl_tree crlt = RB_INITIALIZER(&crlt); 49 50 struct tal *talobj[TALSZ_MAX]; 51 52 struct uripath { 53 RB_ENTRY(uripath) entry; 54 const char *uri; 55 struct cert *cert; 56 }; 57 58 static RB_HEAD(uripath_tree, uripath) uritree; 59 60 static inline int 61 uripathcmp(const struct uripath *a, const struct uripath *b) 62 { 63 return strcmp(a->uri, b->uri); 64 } 65 66 RB_PROTOTYPE(uripath_tree, uripath, entry, uripathcmp); 67 68 static void 69 uripath_add(const char *uri, struct cert *cert) 70 { 71 struct uripath *up; 72 73 if ((up = calloc(1, sizeof(*up))) == NULL) 74 err(1, NULL); 75 if ((up->uri = strdup(uri)) == NULL) 76 err(1, NULL); 77 up->cert = cert; 78 if (RB_INSERT(uripath_tree, &uritree, up) != NULL) 79 errx(1, "corrupt AIA lookup tree"); 80 } 81 82 static struct cert * 83 uripath_lookup(const char *uri) 84 { 85 struct uripath needle = { .uri = uri }; 86 struct uripath *up; 87 88 up = RB_FIND(uripath_tree, &uritree, &needle); 89 if (up == NULL) 90 return NULL; 91 return up->cert; 92 } 93 94 RB_GENERATE(uripath_tree, uripath, entry, uripathcmp); 95 96 /* 97 * Use the X509 CRL Distribution Points to locate the CRL needed for 98 * verification. 99 */ 100 static void 101 parse_load_crl(char *uri) 102 { 103 struct crl *crl; 104 char *f; 105 size_t flen; 106 107 if (uri == NULL) 108 return; 109 if (strncmp(uri, RSYNC_PROTO, RSYNC_PROTO_LEN) != 0) { 110 warnx("bad CRL distribution point URI %s", uri); 111 return; 112 } 113 uri += RSYNC_PROTO_LEN; 114 115 f = load_file(uri, &flen); 116 if (f == NULL) { 117 warn("parse file %s", uri); 118 return; 119 } 120 121 crl = crl_parse(uri, f, flen); 122 if (crl != NULL && !crl_insert(&crlt, crl)) 123 crl_free(crl); 124 125 free(f); 126 } 127 128 /* 129 * Parse the cert pointed at by the AIA URI while doing that also load 130 * the CRL of this cert. While the CRL is validated the returned cert 131 * is not. The caller needs to make sure it is validated once all 132 * necessary certs were loaded. Returns NULL on failure. 133 */ 134 static struct cert * 135 parse_load_cert(char *uri) 136 { 137 struct cert *cert = NULL; 138 char *f; 139 size_t flen; 140 141 if (uri == NULL) 142 return NULL; 143 144 if (strncmp(uri, RSYNC_PROTO, RSYNC_PROTO_LEN) != 0) { 145 warnx("bad authority information access URI %s", uri); 146 return NULL; 147 } 148 uri += RSYNC_PROTO_LEN; 149 150 f = load_file(uri, &flen); 151 if (f == NULL) { 152 warn("parse file %s", uri); 153 goto done; 154 } 155 156 cert = cert_parse_pre(uri, f, flen); 157 free(f); 158 159 if (cert == NULL) 160 goto done; 161 if (cert->purpose != CERT_PURPOSE_CA) { 162 warnx("AIA reference to %s in %s", 163 purpose2str(cert->purpose), uri); 164 goto done; 165 } 166 /* try to load the CRL of this cert */ 167 parse_load_crl(cert->crl); 168 169 return cert; 170 171 done: 172 cert_free(cert); 173 return NULL; 174 } 175 176 /* 177 * Build the certificate chain by using the Authority Information Access. 178 * This requires that the TA are already validated and added to the auths 179 * tree. Once the TA is located in the chain the chain is validated in 180 * reverse order. 181 */ 182 static struct auth * 183 parse_load_certchain(char *uri) 184 { 185 struct cert *stack[MAX_CERT_DEPTH] = { 0 }; 186 char *filestack[MAX_CERT_DEPTH]; 187 struct cert *cert; 188 struct crl *crl; 189 struct auth *a; 190 const char *errstr; 191 int i; 192 193 for (i = 0; i < MAX_CERT_DEPTH; i++) { 194 if ((cert = uripath_lookup(uri)) != NULL) { 195 a = auth_find(&auths, cert->certid); 196 if (a == NULL) { 197 warnx("failed to find issuer for %s", uri); 198 goto fail; 199 } 200 break; 201 } 202 filestack[i] = uri; 203 stack[i] = cert = parse_load_cert(uri); 204 if (cert == NULL || cert->purpose != CERT_PURPOSE_CA) { 205 warnx("failed to build authority chain: %s", uri); 206 goto fail; 207 } 208 uri = cert->aia; 209 } 210 211 if (i >= MAX_CERT_DEPTH) { 212 warnx("authority chain exceeds max depth of %d", 213 MAX_CERT_DEPTH); 214 goto fail; 215 } 216 217 /* TA found play back the stack and add all certs */ 218 for (; i > 0; i--) { 219 cert = stack[i - 1]; 220 uri = filestack[i - 1]; 221 222 crl = crl_get(&crlt, a); 223 if (!valid_x509(uri, ctx, cert->x509, a, crl, &errstr) || 224 !valid_cert(uri, a, cert)) { 225 if (errstr != NULL) 226 warnx("%s: %s", uri, errstr); 227 goto fail; 228 } 229 cert->talid = a->cert->talid; 230 a = auth_insert(uri, &auths, cert, a); 231 uripath_add(uri, cert); 232 stack[i - 1] = NULL; 233 } 234 235 return a; 236 fail: 237 for (i = 0; i < MAX_CERT_DEPTH; i++) 238 cert_free(stack[i]); 239 return NULL; 240 } 241 242 static void 243 parse_load_ta(struct tal *tal) 244 { 245 const char *filename; 246 struct cert *cert; 247 unsigned char *f = NULL; 248 char *file; 249 size_t flen, i; 250 251 /* does not matter which URI, all end with same filename */ 252 filename = strrchr(tal->uri[0], '/'); 253 assert(filename); 254 255 if (asprintf(&file, "ta/%s%s", tal->descr, filename) == -1) 256 err(1, NULL); 257 258 f = load_file(file, &flen); 259 if (f == NULL) { 260 warn("parse file %s", file); 261 goto out; 262 } 263 264 /* Extract certificate data. */ 265 cert = cert_parse_pre(file, f, flen); 266 cert = ta_parse(file, cert, tal->pkey, tal->pkeysz); 267 if (cert == NULL) 268 goto out; 269 270 cert->talid = tal->id; 271 auth_insert(file, &auths, cert, NULL); 272 for (i = 0; i < tal->num_uris; i++) { 273 if (strncasecmp(tal->uri[i], RSYNC_PROTO, RSYNC_PROTO_LEN) != 0) 274 continue; 275 /* Add all rsync uri since any of them could be used as AIA. */ 276 uripath_add(tal->uri[i], cert); 277 } 278 279 out: 280 free(file); 281 free(f); 282 } 283 284 static struct tal * 285 find_tal(struct cert *cert) 286 { 287 EVP_PKEY *pk, *opk; 288 struct tal *tal; 289 int i; 290 291 if ((opk = X509_get0_pubkey(cert->x509)) == NULL) 292 return NULL; 293 294 for (i = 0; i < TALSZ_MAX; i++) { 295 const unsigned char *pkey; 296 297 if (talobj[i] == NULL) 298 break; 299 tal = talobj[i]; 300 pkey = tal->pkey; 301 pk = d2i_PUBKEY(NULL, &pkey, tal->pkeysz); 302 if (pk == NULL) 303 continue; 304 if (EVP_PKEY_cmp(pk, opk) == 1) { 305 EVP_PKEY_free(pk); 306 return tal; 307 } 308 EVP_PKEY_free(pk); 309 } 310 return NULL; 311 } 312 313 static void 314 print_signature_path(const char *crl, const char *aia, const struct auth *a) 315 { 316 if (crl != NULL) 317 printf("Signature path: %s\n", crl); 318 if (a != NULL && a->cert != NULL && a->cert->mft != NULL) 319 printf(" %s\n", a->cert->mft); 320 if (aia != NULL) 321 printf(" %s\n", aia); 322 323 for (; a != NULL; a = a->issuer) { 324 if (a->cert->crl != NULL) 325 printf(" %s\n", a->cert->crl); 326 if (a->issuer != NULL && a->issuer->cert != NULL && 327 a->issuer->cert->mft != NULL) 328 printf(" %s\n", 329 a->issuer->cert->mft); 330 if (a->cert->aia != NULL) 331 printf(" %s\n", a->cert->aia); 332 } 333 } 334 335 /* 336 * Parse file passed with -f option. 337 */ 338 static void 339 proc_parser_file(char *file, unsigned char *buf, size_t len) 340 { 341 static int num; 342 X509 *x509 = NULL; 343 struct aspa *aspa = NULL; 344 struct cert *cert = NULL; 345 struct crl *crl = NULL; 346 struct gbr *gbr = NULL; 347 struct geofeed *geofeed = NULL; 348 struct mft *mft = NULL; 349 struct roa *roa = NULL; 350 struct rsc *rsc = NULL; 351 struct spl *spl = NULL; 352 struct tak *tak = NULL; 353 struct tal *tal = NULL; 354 char *aia = NULL; 355 char *crl_uri = NULL; 356 time_t *notbefore = NULL, *expires = NULL, *notafter = NULL; 357 time_t now; 358 struct auth *a = NULL; 359 struct crl *c; 360 const char *errstr = NULL, *valid; 361 int status = 0; 362 char filehash[SHA256_DIGEST_LENGTH]; 363 char *hash; 364 enum rtype type; 365 int is_ta = 0; 366 367 now = get_current_time(); 368 369 if (outformats & FORMAT_JSON) { 370 json_do_start(stdout); 371 } else { 372 if (num++ > 0) 373 printf("--\n"); 374 } 375 376 if (strncmp(file, RSYNC_PROTO, RSYNC_PROTO_LEN) == 0) { 377 file += RSYNC_PROTO_LEN; 378 buf = load_file(file, &len); 379 if (buf == NULL) { 380 warn("parse file %s", file); 381 return; 382 } 383 } 384 385 if (!EVP_Digest(buf, len, filehash, NULL, EVP_sha256(), NULL)) 386 errx(1, "EVP_Digest failed in %s", __func__); 387 388 if (base64_encode(filehash, sizeof(filehash), &hash) == -1) 389 errx(1, "base64_encode failed in %s", __func__); 390 391 if (outformats & FORMAT_JSON) { 392 json_do_string("file", file); 393 json_do_string("hash_id", hash); 394 } else { 395 printf("File: %s\n", file); 396 printf("Hash identifier: %s\n", hash); 397 } 398 399 free(hash); 400 401 type = rtype_from_file_extension(file); 402 403 switch (type) { 404 case RTYPE_ASPA: 405 aspa = aspa_parse(&x509, file, -1, buf, len); 406 if (aspa == NULL) 407 break; 408 aia = aspa->aia; 409 expires = &aspa->expires; 410 notbefore = &aspa->notbefore; 411 notafter = &aspa->notafter; 412 break; 413 case RTYPE_CER: 414 cert = cert_parse_pre(file, buf, len); 415 if (cert == NULL) 416 break; 417 is_ta = (cert->purpose == CERT_PURPOSE_TA); 418 if (!is_ta) 419 cert = cert_parse(file, cert); 420 if (cert == NULL) 421 break; 422 aia = cert->aia; 423 x509 = cert->x509; 424 if (X509_up_ref(x509) == 0) 425 errx(1, "%s: X509_up_ref failed", __func__); 426 expires = &cert->expires; 427 notbefore = &cert->notbefore; 428 notafter = &cert->notafter; 429 break; 430 case RTYPE_CRL: 431 crl = crl_parse(file, buf, len); 432 if (crl == NULL) 433 break; 434 crl_print(crl); 435 break; 436 case RTYPE_MFT: 437 mft = mft_parse(&x509, file, -1, buf, len); 438 if (mft == NULL) 439 break; 440 aia = mft->aia; 441 expires = &mft->expires; 442 notbefore = &mft->thisupdate; 443 notafter = &mft->nextupdate; 444 break; 445 case RTYPE_GBR: 446 gbr = gbr_parse(&x509, file, -1, buf, len); 447 if (gbr == NULL) 448 break; 449 aia = gbr->aia; 450 expires = &gbr->expires; 451 notbefore = &gbr->notbefore; 452 notafter = &gbr->notafter; 453 break; 454 case RTYPE_GEOFEED: 455 geofeed = geofeed_parse(&x509, file, -1, buf, len); 456 if (geofeed == NULL) 457 break; 458 aia = geofeed->aia; 459 expires = &geofeed->expires; 460 notbefore = &geofeed->notbefore; 461 notafter = &geofeed->notafter; 462 break; 463 case RTYPE_ROA: 464 roa = roa_parse(&x509, file, -1, buf, len); 465 if (roa == NULL) 466 break; 467 aia = roa->aia; 468 expires = &roa->expires; 469 notbefore = &roa->notbefore; 470 notafter = &roa->notafter; 471 break; 472 case RTYPE_RSC: 473 rsc = rsc_parse(&x509, file, -1, buf, len); 474 if (rsc == NULL) 475 break; 476 aia = rsc->aia; 477 expires = &rsc->expires; 478 notbefore = &rsc->notbefore; 479 notafter = &rsc->notafter; 480 break; 481 case RTYPE_SPL: 482 spl = spl_parse(&x509, file, -1, buf, len); 483 if (spl == NULL) 484 break; 485 aia = spl->aia; 486 expires = &spl->expires; 487 notbefore = &spl->notbefore; 488 notafter = &spl->notafter; 489 break; 490 case RTYPE_TAK: 491 tak = tak_parse(&x509, file, -1, buf, len); 492 if (tak == NULL) 493 break; 494 aia = tak->aia; 495 expires = &tak->expires; 496 notbefore = &tak->notbefore; 497 notafter = &tak->notafter; 498 break; 499 case RTYPE_TAL: 500 tal = tal_parse(file, buf, len); 501 if (tal == NULL) 502 break; 503 tal_print(tal); 504 break; 505 default: 506 printf("%s: unsupported file type\n", file); 507 break; 508 } 509 510 if (aia != NULL) { 511 x509_get_crl(x509, file, &crl_uri); 512 parse_load_crl(crl_uri); 513 a = parse_load_certchain(aia); 514 c = crl_get(&crlt, a); 515 516 if ((status = valid_x509(file, ctx, x509, a, c, &errstr))) { 517 switch (type) { 518 case RTYPE_ASPA: 519 status = aspa->valid; 520 break; 521 case RTYPE_GEOFEED: 522 status = geofeed->valid; 523 break; 524 case RTYPE_ROA: 525 status = roa->valid; 526 break; 527 case RTYPE_RSC: 528 status = rsc->valid; 529 break; 530 case RTYPE_SPL: 531 status = spl->valid; 532 default: 533 break; 534 } 535 } 536 if (status && cert == NULL) { 537 struct cert *eecert; 538 539 eecert = cert_parse_ee_cert(file, a->cert->talid, x509); 540 if (eecert == NULL) 541 status = 0; 542 cert_free(eecert); 543 } else if (status) { 544 cert->talid = a->cert->talid; 545 constraints_validate(file, cert); 546 } 547 } else if (is_ta) { 548 expires = NULL; 549 notafter = NULL; 550 if ((tal = find_tal(cert)) != NULL) { 551 cert = ta_parse(file, cert, tal->pkey, tal->pkeysz); 552 status = (cert != NULL); 553 if (status) { 554 expires = &cert->expires; 555 notafter = &cert->notafter; 556 } 557 if (outformats & FORMAT_JSON) 558 json_do_string("tal", tal->descr); 559 else 560 printf("TAL: %s\n", 561 tal->descr); 562 tal = NULL; 563 } else { 564 cert_free(cert); 565 cert = NULL; 566 status = 0; 567 } 568 } 569 570 if (expires != NULL) { 571 if ((status && aia != NULL) || is_ta) 572 *expires = x509_find_expires(*notafter, a, &crlt); 573 574 switch (type) { 575 case RTYPE_ASPA: 576 aspa_print(x509, aspa); 577 break; 578 case RTYPE_CER: 579 cert_print(cert); 580 break; 581 case RTYPE_GBR: 582 gbr_print(x509, gbr); 583 break; 584 case RTYPE_GEOFEED: 585 geofeed_print(x509, geofeed); 586 break; 587 case RTYPE_MFT: 588 mft_print(x509, mft); 589 break; 590 case RTYPE_ROA: 591 roa_print(x509, roa); 592 break; 593 case RTYPE_RSC: 594 rsc_print(x509, rsc); 595 break; 596 case RTYPE_SPL: 597 spl_print(x509, spl); 598 break; 599 case RTYPE_TAK: 600 tak_print(x509, tak); 601 break; 602 default: 603 break; 604 } 605 } 606 607 if (status) { 608 if (notbefore != NULL && *notbefore > now) 609 valid = "Not yet valid"; 610 else if (notafter != NULL && *notafter < now) 611 valid = "Expired"; 612 else if (expires != NULL && *expires < now) 613 valid = "Signature path expired"; 614 else 615 valid = "OK"; 616 } else if (aia == NULL) 617 valid = "N/A"; 618 else 619 valid = "Failed"; 620 621 if (outformats & FORMAT_JSON) { 622 json_do_string("validation", valid); 623 if (errstr != NULL) 624 json_do_string("error", errstr); 625 } else { 626 printf("Validation: %s", valid); 627 if (errstr != NULL) 628 printf(", %s", errstr); 629 } 630 631 if (outformats & FORMAT_JSON) 632 json_do_finish(); 633 else { 634 printf("\n"); 635 636 if (aia != NULL && status) { 637 print_signature_path(crl_uri, aia, a); 638 if (expires != NULL) 639 printf("Signature path expires: %s\n", 640 time2str(*expires)); 641 } 642 643 if (x509 == NULL) 644 goto out; 645 if (type == RTYPE_TAL || type == RTYPE_CRL) 646 goto out; 647 648 if (verbose) { 649 if (!X509_print_fp(stdout, x509)) 650 errx(1, "X509_print_fp"); 651 } 652 653 if (verbose > 1) { 654 if (!PEM_write_X509(stdout, x509)) 655 errx(1, "PEM_write_X509"); 656 } 657 } 658 659 out: 660 free(crl_uri); 661 X509_free(x509); 662 aspa_free(aspa); 663 cert_free(cert); 664 crl_free(crl); 665 gbr_free(gbr); 666 geofeed_free(geofeed); 667 mft_free(mft); 668 roa_free(roa); 669 rsc_free(rsc); 670 tak_free(tak); 671 tal_free(tal); 672 } 673 674 /* 675 * Process a file request, in general don't send anything back. 676 */ 677 static void 678 parse_file(struct entityq *q, struct msgbuf *msgq) 679 { 680 struct entity *entp; 681 struct ibuf *b; 682 struct tal *tal; 683 time_t dummy = 0; 684 685 while ((entp = TAILQ_FIRST(q)) != NULL) { 686 TAILQ_REMOVE(q, entp, entries); 687 688 switch (entp->type) { 689 case RTYPE_FILE: 690 proc_parser_file(entp->file, entp->data, entp->datasz); 691 break; 692 case RTYPE_TAL: 693 if ((tal = tal_parse(entp->file, entp->data, 694 entp->datasz)) == NULL) 695 errx(1, "%s: could not parse tal file", 696 entp->file); 697 tal->id = entp->talid; 698 talobj[tal->id] = tal; 699 parse_load_ta(tal); 700 break; 701 default: 702 errx(1, "unhandled entity type %d", entp->type); 703 } 704 705 b = io_new_buffer(); 706 io_simple_buffer(b, &entp->type, sizeof(entp->type)); 707 io_simple_buffer(b, &entp->repoid, sizeof(entp->repoid)); 708 io_simple_buffer(b, &entp->talid, sizeof(entp->talid)); 709 io_str_buffer(b, entp->file); 710 io_simple_buffer(b, &dummy, sizeof(dummy)); 711 io_close_buffer(msgq, b); 712 entity_free(entp); 713 } 714 } 715 716 /* 717 * Process responsible for parsing and validating content. 718 * All this process does is wait to be told about a file to parse, then 719 * it parses it and makes sure that the data being returned is fully 720 * validated and verified. 721 * The process will exit cleanly only when fd is closed. 722 */ 723 void 724 proc_filemode(int fd) 725 { 726 struct entityq q; 727 struct pollfd pfd; 728 struct msgbuf *msgq; 729 struct entity *entp; 730 struct ibuf *b, *inbuf = NULL; 731 732 /* Only allow access to the cache directory. */ 733 if (unveil(".", "r") == -1) 734 err(1, "unveil cachedir"); 735 if (pledge("stdio rpath", NULL) == -1) 736 err(1, "pledge"); 737 738 ERR_load_crypto_strings(); 739 OpenSSL_add_all_ciphers(); 740 OpenSSL_add_all_digests(); 741 x509_init_oid(); 742 constraints_parse(); 743 744 if ((ctx = X509_STORE_CTX_new()) == NULL) 745 err(1, "X509_STORE_CTX_new"); 746 if ((bn_ctx = BN_CTX_new()) == NULL) 747 err(1, "BN_CTX_new"); 748 749 TAILQ_INIT(&q); 750 751 if ((msgq = msgbuf_new_reader(sizeof(size_t), io_parse_hdr, NULL)) == 752 NULL) 753 err(1, NULL); 754 pfd.fd = fd; 755 756 for (;;) { 757 pfd.events = POLLIN; 758 if (msgbuf_queuelen(msgq) > 0) 759 pfd.events |= POLLOUT; 760 761 if (poll(&pfd, 1, INFTIM) == -1) { 762 if (errno == EINTR) 763 continue; 764 err(1, "poll"); 765 } 766 if ((pfd.revents & (POLLERR|POLLNVAL))) 767 errx(1, "poll: bad descriptor"); 768 769 /* If the parent closes, return immediately. */ 770 771 if ((pfd.revents & POLLHUP)) 772 break; 773 774 if ((pfd.revents & POLLIN)) { 775 switch (ibuf_read(fd, msgq)) { 776 case -1: 777 err(1, "ibuf_read"); 778 case 0: 779 errx(1, "ibuf_read: connection closed"); 780 } 781 while ((b = io_buf_get(msgq)) != NULL) { 782 entp = calloc(1, sizeof(struct entity)); 783 if (entp == NULL) 784 err(1, NULL); 785 entity_read_req(b, entp); 786 TAILQ_INSERT_TAIL(&q, entp, entries); 787 ibuf_free(b); 788 } 789 } 790 791 if (pfd.revents & POLLOUT) { 792 if (msgbuf_write(fd, msgq) == -1) { 793 if (errno == EPIPE) 794 errx(1, "write: connection closed"); 795 else 796 err(1, "write"); 797 } 798 } 799 800 parse_file(&q, msgq); 801 } 802 803 msgbuf_free(msgq); 804 while ((entp = TAILQ_FIRST(&q)) != NULL) { 805 TAILQ_REMOVE(&q, entp, entries); 806 entity_free(entp); 807 } 808 809 auth_tree_free(&auths); 810 crl_tree_free(&crlt); 811 812 X509_STORE_CTX_free(ctx); 813 BN_CTX_free(bn_ctx); 814 815 ibuf_free(inbuf); 816 817 exit(0); 818 } 819