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
uripathcmp(const struct uripath * a,const struct uripath * b)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
uripath_add(const char * uri,struct cert * cert)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 *
uripath_lookup(const char * uri)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
parse_load_crl(char * uri)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 *
parse_load_cert(char * uri)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 *
parse_load_certchain(char * uri)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
parse_load_ta(struct tal * tal)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 *
find_tal(struct cert * cert)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
print_signature_path(const char * crl,const char * aia,const struct auth * a)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
proc_parser_file(char * file,unsigned char * buf,size_t len)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
parse_file(struct entityq * q,struct msgbuf * msgq)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
proc_filemode(int fd)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