Bug Summary

File:src/usr.sbin/rpki-client/filemode.c
Warning:line 272, column 7
Access to field 'crl' results in a dereference of a null pointer (loaded from field 'cert')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name filemode.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/rpki-client/obj -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/usr.sbin/rpki-client -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/rpki-client/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.sbin/rpki-client/filemode.c
1/* $OpenBSD: filemode.c,v 1.36 2023/10/13 12:06:49 job 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
44extern int verbose;
45
46static X509_STORE_CTX *ctx;
47static struct auth_tree auths = RB_INITIALIZER(&auths){ ((void *)0) };
48static struct crl_tree crlt = RB_INITIALIZER(&crlt){ ((void *)0) };
49
50struct tal *talobj[TALSZ_MAX8];
51
52/*
53 * Use the X509 CRL Distribution Points to locate the CRL needed for
54 * verification.
55 */
56static void
57parse_load_crl(char *uri)
58{
59 struct crl *crl;
60 char *f;
61 size_t flen;
62
63 if (uri == NULL((void *)0))
64 return;
65 if (strncmp(uri, "rsync://", strlen("rsync://")) != 0) {
66 warnx("bad CRL distribution point URI %s", uri);
67 return;
68 }
69 uri += strlen("rsync://");
70
71 f = load_file(uri, &flen);
72 if (f == NULL((void *)0)) {
73 warn("parse file %s", uri);
74 return;
75 }
76
77 crl = crl_parse(uri, f, flen);
78 if (crl != NULL((void *)0) && !crl_insert(&crlt, crl))
79 crl_free(crl);
80
81 free(f);
82}
83
84/*
85 * Parse the cert pointed at by the AIA URI while doing that also load
86 * the CRL of this cert. While the CRL is validated the returned cert
87 * is not. The caller needs to make sure it is validated once all
88 * necessary certs were loaded. Returns NULL on failure.
89 */
90static struct cert *
91parse_load_cert(char *uri)
92{
93 struct cert *cert = NULL((void *)0);
94 char *f;
95 size_t flen;
96
97 if (uri == NULL((void *)0))
98 return NULL((void *)0);
99
100 if (strncmp(uri, "rsync://", strlen("rsync://")) != 0) {
101 warnx("bad authority information access URI %s", uri);
102 return NULL((void *)0);
103 }
104 uri += strlen("rsync://");
105
106 f = load_file(uri, &flen);
107 if (f == NULL((void *)0)) {
108 warn("parse file %s", uri);
109 goto done;
110 }
111
112 cert = cert_parse_pre(uri, f, flen);
113 free(f);
114
115 if (cert == NULL((void *)0))
116 goto done;
117 if (cert->purpose != CERT_PURPOSE_CA) {
118 warnx("AIA reference to bgpsec cert %s", uri);
119 goto done;
120 }
121 /* try to load the CRL of this cert */
122 parse_load_crl(cert->crl);
123
124 return cert;
125
126 done:
127 cert_free(cert);
128 return NULL((void *)0);
129}
130
131/*
132 * Build the certificate chain by using the Authority Information Access.
133 * This requires that the TA are already validated and added to the auths
134 * tree. Once the TA is located in the chain the chain is validated in
135 * reverse order.
136 */
137static void
138parse_load_certchain(char *uri)
139{
140 struct cert *stack[MAX_CERT_DEPTH12] = { 0 };
141 char *filestack[MAX_CERT_DEPTH12];
142 struct cert *cert;
143 struct crl *crl;
144 struct auth *a;
145 const char *errstr;
146 int i;
147
148 for (i = 0; i < MAX_CERT_DEPTH12; i++) {
149 filestack[i] = uri;
150 stack[i] = cert = parse_load_cert(uri);
151 if (cert == NULL((void *)0) || cert->purpose != CERT_PURPOSE_CA) {
152 warnx("failed to build authority chain");
153 goto fail;
154 }
155 if (auth_find(&auths, cert->ski) != NULL((void *)0)) {
156 assert(i == 0)((i == 0) ? (void)0 : __assert2("/usr/src/usr.sbin/rpki-client/filemode.c"
, 156, __func__, "i == 0"))
;
157 goto fail;
158 }
159 if ((a = auth_find(&auths, cert->aki)) != NULL((void *)0))
160 break; /* found chain to TA */
161 uri = cert->aia;
162 }
163
164 if (i >= MAX_CERT_DEPTH12) {
165 warnx("authority chain exceeds max depth of %d",
166 MAX_CERT_DEPTH12);
167 goto fail;
168 }
169
170 /* TA found play back the stack and add all certs */
171 for (; i >= 0; i--) {
172 cert = stack[i];
173 uri = filestack[i];
174
175 crl = crl_get(&crlt, a);
176 if (!valid_x509(uri, ctx, cert->x509, a, crl, &errstr) ||
177 !valid_cert(uri, a, cert)) {
178 if (errstr != NULL((void *)0))
179 warnx("%s: %s", uri, errstr);
180 goto fail;
181 }
182 cert->talid = a->cert->talid;
183 a = auth_insert(&auths, cert, a);
184 stack[i] = NULL((void *)0);
185 }
186
187 return;
188fail:
189 for (i = 0; i < MAX_CERT_DEPTH12; i++)
190 cert_free(stack[i]);
191}
192
193static void
194parse_load_ta(struct tal *tal)
195{
196 const char *filename;
197 struct cert *cert;
198 unsigned char *f = NULL((void *)0);
199 char *file;
200 size_t flen;
201
202 /* does not matter which URI, all end with same filename */
203 filename = strrchr(tal->uri[0], '/');
204 assert(filename)((filename) ? (void)0 : __assert2("/usr/src/usr.sbin/rpki-client/filemode.c"
, 204, __func__, "filename"))
;
205
206 if (asprintf(&file, "ta/%s%s", tal->descr, filename) == -1)
207 err(1, NULL((void *)0));
208
209 f = load_file(file, &flen);
210 if (f == NULL((void *)0)) {
211 warn("parse file %s", file);
212 goto out;
213 }
214
215 /* Extract certificate data. */
216 cert = cert_parse_pre(file, f, flen);
217 cert = ta_parse(file, cert, tal->pkey, tal->pkeysz);
218 if (cert == NULL((void *)0))
219 goto out;
220
221 cert->talid = tal->id;
222
223 if (!valid_ta(file, &auths, cert))
224 cert_free(cert);
225 else
226 auth_insert(&auths, cert, NULL((void *)0));
227out:
228 free(file);
229 free(f);
230}
231
232static struct tal *
233find_tal(struct cert *cert)
234{
235 EVP_PKEY *pk, *opk;
236 struct tal *tal;
237 int i;
238
239 if ((opk = X509_get0_pubkey(cert->x509)) == NULL((void *)0))
240 return NULL((void *)0);
241
242 for (i = 0; i < TALSZ_MAX8; i++) {
243 const unsigned char *pkey;
244
245 if (talobj[i] == NULL((void *)0))
246 break;
247 tal = talobj[i];
248 pkey = tal->pkey;
249 pk = d2i_PUBKEY(NULL((void *)0), &pkey, tal->pkeysz);
250 if (pk == NULL((void *)0))
251 continue;
252 if (EVP_PKEY_cmp(pk, opk) == 1) {
253 EVP_PKEY_free(pk);
254 return tal;
255 }
256 EVP_PKEY_free(pk);
257 }
258 return NULL((void *)0);
259}
260
261static void
262print_signature_path(const char *crl, const char *aia, const struct auth *a)
263{
264 if (crl
36.1
'crl' is not equal to NULL
!= NULL((void *)0))
37
Taking true branch
265 printf("Signature path: %s\n", crl);
266 if (a->cert->mft != NULL((void *)0))
38
Assuming field 'mft' is equal to NULL
39
Taking false branch
267 printf(" %s\n", a->cert->mft);
268 if (aia
39.1
'aia' is not equal to NULL
!= NULL((void *)0))
40
Taking true branch
269 printf(" %s\n", aia);
270
271 for (; a
40.1
'a' is not equal to NULL
46.1
'a' is not equal to NULL
!= NULL((void *)0); a = a->parent) {
41
Loop condition is true. Entering loop body
47
Loop condition is true. Entering loop body
272 if (a->cert->crl != NULL((void *)0))
42
Assuming field 'crl' is equal to NULL
48
Access to field 'crl' results in a dereference of a null pointer (loaded from field 'cert')
273 printf(" %s\n", a->cert->crl);
274 if (a->parent != NULL((void *)0) && a->parent->cert != NULL((void *)0) &&
43
Assuming field 'parent' is not equal to NULL
44
Assuming field 'cert' is equal to NULL
275 a->parent->cert->mft != NULL((void *)0))
276 printf(" %s\n",
277 a->parent->cert->mft);
278 if (a->cert->aia != NULL((void *)0))
45
Assuming field 'aia' is equal to NULL
46
Taking false branch
279 printf(" %s\n", a->cert->aia);
280 }
281}
282
283/*
284 * Parse file passed with -f option.
285 */
286static void
287proc_parser_file(char *file, unsigned char *buf, size_t len)
288{
289 static int num;
290 X509 *x509 = NULL((void *)0);
291 struct aspa *aspa = NULL((void *)0);
292 struct cert *cert = NULL((void *)0);
293 struct crl *crl = NULL((void *)0);
294 struct gbr *gbr = NULL((void *)0);
295 struct geofeed *geofeed = NULL((void *)0);
296 struct mft *mft = NULL((void *)0);
297 struct roa *roa = NULL((void *)0);
298 struct rsc *rsc = NULL((void *)0);
299 struct tak *tak = NULL((void *)0);
300 struct tal *tal = NULL((void *)0);
301 char *aia = NULL((void *)0), *aki = NULL((void *)0);
302 char *crl_uri = NULL((void *)0);
303 time_t *expires = NULL((void *)0), *notafter = NULL((void *)0);
304 struct auth *a;
305 struct crl *c;
306 const char *errstr = NULL((void *)0), *valid;
307 int status = 0;
308 char filehash[SHA256_DIGEST_LENGTH32];
309 char *hash;
310 enum rtype type;
311 int is_ta = 0;
312
313 if (outformats & FORMAT_JSON0x08) {
1
Assuming the condition is false
2
Taking false branch
314 json_do_start(stdout(&__sF[1]));
315 } else {
316 if (num++ > 0)
3
Taking false branch
317 printf("--\n");
318 }
319
320 if (strncmp(file, "rsync://", strlen("rsync://")) == 0) {
4
Assuming the condition is false
5
Taking false branch
321 file += strlen("rsync://");
322 buf = load_file(file, &len);
323 if (buf == NULL((void *)0)) {
324 warn("parse file %s", file);
325 return;
326 }
327 }
328
329 if (!EVP_Digest(buf, len, filehash, NULL((void *)0), EVP_sha256(), NULL((void *)0)))
6
Assuming the condition is false
7
Taking false branch
330 errx(1, "EVP_Digest failed in %s", __func__);
331
332 if (base64_encode(filehash, sizeof(filehash), &hash) == -1)
8
Assuming the condition is false
9
Taking false branch
333 errx(1, "base64_encode failed in %s", __func__);
334
335 if (outformats & FORMAT_JSON0x08) {
10
Assuming the condition is false
11
Taking false branch
336 json_do_string("file", file);
337 json_do_string("hash_id", hash);
338 } else {
339 printf("File: %s\n", file);
340 printf("Hash identifier: %s\n", hash);
341 }
342
343 free(hash);
344
345 type = rtype_from_file_extension(file);
346
347 switch (type) {
12
Control jumps to 'case RTYPE_TAK:' at line 425
348 case RTYPE_ASPA:
349 aspa = aspa_parse(&x509, file, -1, buf, len);
350 if (aspa == NULL((void *)0))
351 break;
352 aia = aspa->aia;
353 aki = aspa->aki;
354 expires = &aspa->expires;
355 notafter = &aspa->notafter;
356 break;
357 case RTYPE_CER:
358 cert = cert_parse_pre(file, buf, len);
359 if (cert == NULL((void *)0))
360 break;
361 is_ta = X509_get_extension_flags(cert->x509) & EXFLAG_SS0x2000;
362 if (!is_ta)
363 cert = cert_parse(file, cert);
364 if (cert == NULL((void *)0))
365 break;
366 aia = cert->aia;
367 aki = cert->aki;
368 x509 = cert->x509;
369 if (X509_up_ref(x509) == 0)
370 errx(1, "%s: X509_up_ref failed", __func__);
371 expires = &cert->expires;
372 notafter = &cert->notafter;
373 break;
374 case RTYPE_CRL:
375 crl = crl_parse(file, buf, len);
376 if (crl == NULL((void *)0))
377 break;
378 crl_print(crl);
379 break;
380 case RTYPE_MFT:
381 mft = mft_parse(&x509, file, -1, buf, len);
382 if (mft == NULL((void *)0))
383 break;
384 aia = mft->aia;
385 aki = mft->aki;
386 expires = &mft->expires;
387 notafter = &mft->nextupdate;
388 break;
389 case RTYPE_GBR:
390 gbr = gbr_parse(&x509, file, -1, buf, len);
391 if (gbr == NULL((void *)0))
392 break;
393 aia = gbr->aia;
394 aki = gbr->aki;
395 expires = &gbr->expires;
396 notafter = &gbr->notafter;
397 break;
398 case RTYPE_GEOFEED:
399 geofeed = geofeed_parse(&x509, file, -1, buf, len);
400 if (geofeed == NULL((void *)0))
401 break;
402 aia = geofeed->aia;
403 aki = geofeed->aki;
404 expires = &geofeed->expires;
405 notafter = &geofeed->notafter;
406 break;
407 case RTYPE_ROA:
408 roa = roa_parse(&x509, file, -1, buf, len);
409 if (roa == NULL((void *)0))
410 break;
411 aia = roa->aia;
412 aki = roa->aki;
413 expires = &roa->expires;
414 notafter = &roa->notafter;
415 break;
416 case RTYPE_RSC:
417 rsc = rsc_parse(&x509, file, -1, buf, len);
418 if (rsc == NULL((void *)0))
419 break;
420 aia = rsc->aia;
421 aki = rsc->aki;
422 expires = &rsc->expires;
423 notafter = &rsc->notafter;
424 break;
425 case RTYPE_TAK:
426 tak = tak_parse(&x509, file, -1, buf, len);
427 if (tak == NULL((void *)0))
13
Assuming 'tak' is not equal to NULL
14
Taking false branch
428 break;
429 aia = tak->aia;
430 aki = tak->aki;
431 expires = &tak->expires;
432 notafter = &tak->notafter;
433 break;
434 case RTYPE_TAL:
435 tal = tal_parse(file, buf, len);
436 if (tal == NULL((void *)0))
437 break;
438 tal_print(tal);
439 break;
440 default:
441 printf("%s: unsupported file type\n", file);
442 break;
443 }
444
445 if (aia != NULL((void *)0)) {
15
Execution continues on line 445
16
Assuming 'aia' is not equal to NULL
17
Taking true branch
446 x509_get_crl(x509, file, &crl_uri);
447 parse_load_crl(crl_uri);
448 if (auth_find(&auths, aki) == NULL((void *)0))
18
Assuming the condition is false
19
Taking false branch
449 parse_load_certchain(aia);
450 a = auth_find(&auths, aki);
451 c = crl_get(&crlt, a);
452
453 if ((status = valid_x509(file, ctx, x509, a, c, &errstr))) {
20
Assuming 'status' is not equal to 0
21
Taking true branch
454 switch (type) {
22
Control jumps to the 'default' case at line 467
455 case RTYPE_ASPA:
456 status = aspa->valid;
457 break;
458 case RTYPE_GEOFEED:
459 status = geofeed->valid;
460 break;
461 case RTYPE_ROA:
462 status = roa->valid;
463 break;
464 case RTYPE_RSC:
465 status = rsc->valid;
466 break;
467 default:
468 break;
469 }
470 }
471 if (status
22.1
'status' is not equal to 0
&& cert
22.2
'cert' is equal to NULL
== NULL((void *)0)) {
23
Taking true branch
472 struct cert *eecert;
473
474 eecert = cert_parse_ee_cert(file, a->cert->talid, x509);
475 if (eecert == NULL((void *)0))
24
Assuming 'eecert' is not equal to NULL
25
Taking false branch
476 status = 0;
477 cert_free(eecert);
478 } else if (status) {
479 cert->talid = a->cert->talid;
480 status = constraints_validate(file, cert);
481 }
482 } else if (is_ta) {
483 if ((tal = find_tal(cert)) != NULL((void *)0)) {
484 cert = ta_parse(file, cert, tal->pkey, tal->pkeysz);
485 status = (cert != NULL((void *)0));
486 if (outformats & FORMAT_JSON0x08)
487 json_do_string("tal", tal->descr);
488 else
489 printf("TAL: %s\n",
490 tal->descr);
491 tal = NULL((void *)0);
492 } else {
493 cert_free(cert);
494 cert = NULL((void *)0);
495 expires = NULL((void *)0);
496 status = 0;
497 }
498 }
499
500 if (expires
25.1
'expires' is not equal to NULL
!= NULL((void *)0)) {
501 if (status
25.2
'status' is not equal to 0
&& aia
25.3
'aia' is not equal to NULL
!= NULL((void *)0))
26
Taking true branch
502 *expires = x509_find_expires(*notafter, a, &crlt);
503
504 switch (type) {
27
Control jumps to 'case RTYPE_TAK:' at line 526
505 case RTYPE_ASPA:
506 aspa_print(x509, aspa);
507 break;
508 case RTYPE_CER:
509 cert_print(cert);
510 break;
511 case RTYPE_GBR:
512 gbr_print(x509, gbr);
513 break;
514 case RTYPE_GEOFEED:
515 geofeed_print(x509, geofeed);
516 break;
517 case RTYPE_MFT:
518 mft_print(x509, mft);
519 break;
520 case RTYPE_ROA:
521 roa_print(x509, roa);
522 break;
523 case RTYPE_RSC:
524 rsc_print(x509, rsc);
525 break;
526 case RTYPE_TAK:
527 tak_print(x509, tak);
528 break;
529 default:
530 break;
531 }
532 }
533
534 if (status
28.1
'status' is not equal to 0
)
28
Execution continues on line 534
29
Taking true branch
535 valid = "OK";
536 else if (aia == NULL((void *)0))
537 valid = "N/A";
538 else
539 valid = "Failed";
540
541 if (outformats & FORMAT_JSON0x08) {
30
Assuming the condition is false
31
Taking false branch
542 json_do_string("validation", valid);
543 if (errstr != NULL((void *)0))
544 json_do_string("error", errstr);
545 } else {
546 printf("Validation: %s", valid);
547 if (errstr != NULL((void *)0))
32
Assuming 'errstr' is equal to NULL
33
Taking false branch
548 printf(", %s", errstr);
549 }
550
551 if (outformats & FORMAT_JSON0x08)
34
Taking false branch
552 json_do_finish();
553 else {
554 printf("\n");
555
556 if (status
34.1
'status' is not equal to 0
&& aia
34.2
'aia' is not equal to NULL
!= NULL((void *)0)) {
35
Taking true branch
557 print_signature_path(crl_uri, aia, a);
36
Calling 'print_signature_path'
558 if (expires != NULL((void *)0))
559 printf("Signature path expires: %s\n",
560 time2str(*expires));
561 }
562
563 if (x509 == NULL((void *)0))
564 goto out;
565 if (type == RTYPE_TAL || type == RTYPE_CRL)
566 goto out;
567
568 if (verbose) {
569 if (!X509_print_fp(stdout(&__sF[1]), x509))
570 errx(1, "X509_print_fp");
571 }
572
573 if (verbose > 1) {
574 if (!PEM_write_X509(stdout(&__sF[1]), x509))
575 errx(1, "PEM_write_X509");
576 }
577 }
578
579 out:
580 free(crl_uri);
581 X509_free(x509);
582 aspa_free(aspa);
583 cert_free(cert);
584 crl_free(crl);
585 gbr_free(gbr);
586 geofeed_free(geofeed);
587 mft_free(mft);
588 roa_free(roa);
589 rsc_free(rsc);
590 tak_free(tak);
591 tal_free(tal);
592}
593
594/*
595 * Process a file request, in general don't send anything back.
596 */
597static void
598parse_file(struct entityq *q, struct msgbuf *msgq)
599{
600 struct entity *entp;
601 struct ibuf *b;
602 struct tal *tal;
603 time_t dummy = 0;
604
605 while ((entp = TAILQ_FIRST(q)((q)->tqh_first)) != NULL((void *)0)) {
606 TAILQ_REMOVE(q, entp, entries)do { if (((entp)->entries.tqe_next) != ((void *)0)) (entp)
->entries.tqe_next->entries.tqe_prev = (entp)->entries
.tqe_prev; else (q)->tqh_last = (entp)->entries.tqe_prev
; *(entp)->entries.tqe_prev = (entp)->entries.tqe_next;
; ; } while (0)
;
607
608 switch (entp->type) {
609 case RTYPE_FILE:
610 proc_parser_file(entp->file, entp->data, entp->datasz);
611 break;
612 case RTYPE_TAL:
613 if ((tal = tal_parse(entp->file, entp->data,
614 entp->datasz)) == NULL((void *)0))
615 errx(1, "%s: could not parse tal file",
616 entp->file);
617 tal->id = entp->talid;
618 talobj[tal->id] = tal;
619 parse_load_ta(tal);
620 break;
621 default:
622 errx(1, "unhandled entity type %d", entp->type);
623 }
624
625 b = io_new_buffer();
626 io_simple_buffer(b, &entp->type, sizeof(entp->type));
627 io_simple_buffer(b, &entp->repoid, sizeof(entp->repoid));
628 io_simple_buffer(b, &entp->talid, sizeof(entp->talid));
629 io_str_buffer(b, entp->file);
630 io_simple_buffer(b, &dummy, sizeof(dummy));
631 io_close_buffer(msgq, b);
632 entity_free(entp);
633 }
634}
635
636/*
637 * Process responsible for parsing and validating content.
638 * All this process does is wait to be told about a file to parse, then
639 * it parses it and makes sure that the data being returned is fully
640 * validated and verified.
641 * The process will exit cleanly only when fd is closed.
642 */
643void
644proc_filemode(int fd)
645{
646 struct entityq q;
647 struct msgbuf msgq;
648 struct pollfd pfd;
649 struct entity *entp;
650 struct ibuf *b, *inbuf = NULL((void *)0);
651
652 /* Only allow access to the cache directory. */
653 if (unveil(".", "r") == -1)
654 err(1, "unveil cachedir");
655 if (pledge("stdio rpath", NULL((void *)0)) == -1)
656 err(1, "pledge");
657
658 ERR_load_crypto_strings();
659 OpenSSL_add_all_ciphers();
660 OpenSSL_add_all_digests();
661 x509_init_oid();
662 constraints_parse();
663
664 if ((ctx = X509_STORE_CTX_new()) == NULL((void *)0))
665 err(1, "X509_STORE_CTX_new");
666 TAILQ_INIT(&q)do { (&q)->tqh_first = ((void *)0); (&q)->tqh_last
= &(&q)->tqh_first; } while (0)
;
667
668 msgbuf_init(&msgq);
669 msgq.fd = fd;
670
671 pfd.fd = fd;
672
673 for (;;) {
674 pfd.events = POLLIN0x0001;
675 if (msgq.queued)
676 pfd.events |= POLLOUT0x0004;
677
678 if (poll(&pfd, 1, INFTIM(-1)) == -1) {
679 if (errno(*__errno()) == EINTR4)
680 continue;
681 err(1, "poll");
682 }
683 if ((pfd.revents & (POLLERR0x0008|POLLNVAL0x0020)))
684 errx(1, "poll: bad descriptor");
685
686 /* If the parent closes, return immediately. */
687
688 if ((pfd.revents & POLLHUP0x0010))
689 break;
690
691 if ((pfd.revents & POLLIN0x0001)) {
692 b = io_buf_read(fd, &inbuf);
693 if (b != NULL((void *)0)) {
694 entp = calloc(1, sizeof(struct entity));
695 if (entp == NULL((void *)0))
696 err(1, NULL((void *)0));
697 entity_read_req(b, entp);
698 TAILQ_INSERT_TAIL(&q, entp, entries)do { (entp)->entries.tqe_next = ((void *)0); (entp)->entries
.tqe_prev = (&q)->tqh_last; *(&q)->tqh_last = (
entp); (&q)->tqh_last = &(entp)->entries.tqe_next
; } while (0)
;
699 ibuf_free(b);
700 }
701 }
702
703 if (pfd.revents & POLLOUT0x0004) {
704 switch (msgbuf_write(&msgq)) {
705 case 0:
706 errx(1, "write: connection closed");
707 case -1:
708 err(1, "write");
709 }
710 }
711
712 parse_file(&q, &msgq);
713 }
714
715 msgbuf_clear(&msgq);
716 while ((entp = TAILQ_FIRST(&q)((&q)->tqh_first)) != NULL((void *)0)) {
717 TAILQ_REMOVE(&q, entp, entries)do { if (((entp)->entries.tqe_next) != ((void *)0)) (entp)
->entries.tqe_next->entries.tqe_prev = (entp)->entries
.tqe_prev; else (&q)->tqh_last = (entp)->entries.tqe_prev
; *(entp)->entries.tqe_prev = (entp)->entries.tqe_next;
; ; } while (0)
;
718 entity_free(entp);
719 }
720
721 auth_tree_free(&auths);
722 crl_tree_free(&crlt);
723
724 X509_STORE_CTX_free(ctx);
725 ibuf_free(inbuf);
726
727 exit(0);
728}