Bug Summary

File:src/usr.sbin/rpki-client/parser.c
Warning:line 390, column 16
Null pointer passed as 1st argument to memory comparison function

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 parser.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/parser.c
1/* $OpenBSD: parser.c,v 1.107 2024/01/08 19:46:19 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 <err.h>
24#include <fcntl.h>
25#include <poll.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <limits.h>
30#include <unistd.h>
31#include <imsg.h>
32
33#include <openssl/asn1.h>
34#include <openssl/err.h>
35#include <openssl/evp.h>
36#include <openssl/x509.h>
37#include <openssl/x509v3.h>
38
39#include "extern.h"
40
41extern int noop;
42
43static X509_STORE_CTX *ctx;
44static struct auth_tree auths = RB_INITIALIZER(&auths){ ((void *)0) };
45static struct crl_tree crlt = RB_INITIALIZER(&crlt){ ((void *)0) };
46
47struct parse_repo {
48 RB_ENTRY(parse_repo)struct { struct parse_repo *rbe_left; struct parse_repo *rbe_right
; struct parse_repo *rbe_parent; int rbe_color; }
entry;
49 char *path;
50 char *validpath;
51 unsigned int id;
52};
53
54static RB_HEAD(repo_tree, parse_repo)struct repo_tree { struct parse_repo *rbh_root; } repos = RB_INITIALIZER(&repos){ ((void *)0) };
55
56static inline int
57repocmp(struct parse_repo *a, struct parse_repo *b)
58{
59 return a->id - b->id;
60}
61
62RB_GENERATE_STATIC(repo_tree, parse_repo, entry, repocmp)__attribute__((__unused__)) static void repo_tree_RB_INSERT_COLOR
(struct repo_tree *head, struct parse_repo *elm) { struct parse_repo
*parent, *gparent, *tmp; while ((parent = (elm)->entry.rbe_parent
) && (parent)->entry.rbe_color == 1) { gparent = (
parent)->entry.rbe_parent; if (parent == (gparent)->entry
.rbe_left) { tmp = (gparent)->entry.rbe_right; if (tmp &&
(tmp)->entry.rbe_color == 1) { (tmp)->entry.rbe_color =
0; do { (parent)->entry.rbe_color = 0; (gparent)->entry
.rbe_color = 1; } while (0); elm = gparent; continue; } if ((
parent)->entry.rbe_right == elm) { do { (tmp) = (parent)->
entry.rbe_right; if (((parent)->entry.rbe_right = (tmp)->
entry.rbe_left)) { ((tmp)->entry.rbe_left)->entry.rbe_parent
= (parent); } do {} while (0); if (((tmp)->entry.rbe_parent
= (parent)->entry.rbe_parent)) { if ((parent) == ((parent
)->entry.rbe_parent)->entry.rbe_left) ((parent)->entry
.rbe_parent)->entry.rbe_left = (tmp); else ((parent)->entry
.rbe_parent)->entry.rbe_right = (tmp); } else (head)->rbh_root
= (tmp); (tmp)->entry.rbe_left = (parent); (parent)->entry
.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent
)) do {} while (0); } while (0); tmp = parent; parent = elm; elm
= tmp; } do { (parent)->entry.rbe_color = 0; (gparent)->
entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)->
entry.rbe_left; if (((gparent)->entry.rbe_left = (tmp)->
entry.rbe_right)) { ((tmp)->entry.rbe_right)->entry.rbe_parent
= (gparent); } do {} while (0); if (((tmp)->entry.rbe_parent
= (gparent)->entry.rbe_parent)) { if ((gparent) == ((gparent
)->entry.rbe_parent)->entry.rbe_left) ((gparent)->entry
.rbe_parent)->entry.rbe_left = (tmp); else ((gparent)->
entry.rbe_parent)->entry.rbe_right = (tmp); } else (head)->
rbh_root = (tmp); (tmp)->entry.rbe_right = (gparent); (gparent
)->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->
entry.rbe_parent)) do {} while (0); } while (0); } else { tmp
= (gparent)->entry.rbe_left; if (tmp && (tmp)->
entry.rbe_color == 1) { (tmp)->entry.rbe_color = 0; do { (
parent)->entry.rbe_color = 0; (gparent)->entry.rbe_color
= 1; } while (0); elm = gparent; continue; } if ((parent)->
entry.rbe_left == elm) { do { (tmp) = (parent)->entry.rbe_left
; if (((parent)->entry.rbe_left = (tmp)->entry.rbe_right
)) { ((tmp)->entry.rbe_right)->entry.rbe_parent = (parent
); } do {} while (0); if (((tmp)->entry.rbe_parent = (parent
)->entry.rbe_parent)) { if ((parent) == ((parent)->entry
.rbe_parent)->entry.rbe_left) ((parent)->entry.rbe_parent
)->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent
)->entry.rbe_right = (tmp); } else (head)->rbh_root = (
tmp); (tmp)->entry.rbe_right = (parent); (parent)->entry
.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent
)) do {} while (0); } while (0); tmp = parent; parent = elm; elm
= tmp; } do { (parent)->entry.rbe_color = 0; (gparent)->
entry.rbe_color = 1; } while (0); do { (tmp) = (gparent)->
entry.rbe_right; if (((gparent)->entry.rbe_right = (tmp)->
entry.rbe_left)) { ((tmp)->entry.rbe_left)->entry.rbe_parent
= (gparent); } do {} while (0); if (((tmp)->entry.rbe_parent
= (gparent)->entry.rbe_parent)) { if ((gparent) == ((gparent
)->entry.rbe_parent)->entry.rbe_left) ((gparent)->entry
.rbe_parent)->entry.rbe_left = (tmp); else ((gparent)->
entry.rbe_parent)->entry.rbe_right = (tmp); } else (head)->
rbh_root = (tmp); (tmp)->entry.rbe_left = (gparent); (gparent
)->entry.rbe_parent = (tmp); do {} while (0); if (((tmp)->
entry.rbe_parent)) do {} while (0); } while (0); } } (head->
rbh_root)->entry.rbe_color = 0; } __attribute__((__unused__
)) static void repo_tree_RB_REMOVE_COLOR(struct repo_tree *head
, struct parse_repo *parent, struct parse_repo *elm) { struct
parse_repo *tmp; while ((elm == ((void *)0) || (elm)->entry
.rbe_color == 0) && elm != (head)->rbh_root) { if (
(parent)->entry.rbe_left == elm) { tmp = (parent)->entry
.rbe_right; if ((tmp)->entry.rbe_color == 1) { do { (tmp)->
entry.rbe_color = 0; (parent)->entry.rbe_color = 1; } while
(0); do { (tmp) = (parent)->entry.rbe_right; if (((parent
)->entry.rbe_right = (tmp)->entry.rbe_left)) { ((tmp)->
entry.rbe_left)->entry.rbe_parent = (parent); } do {} while
(0); if (((tmp)->entry.rbe_parent = (parent)->entry.rbe_parent
)) { if ((parent) == ((parent)->entry.rbe_parent)->entry
.rbe_left) ((parent)->entry.rbe_parent)->entry.rbe_left
= (tmp); else ((parent)->entry.rbe_parent)->entry.rbe_right
= (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry
.rbe_left = (parent); (parent)->entry.rbe_parent = (tmp); do
{} while (0); if (((tmp)->entry.rbe_parent)) do {} while (
0); } while (0); tmp = (parent)->entry.rbe_right; } if (((
tmp)->entry.rbe_left == ((void *)0) || ((tmp)->entry.rbe_left
)->entry.rbe_color == 0) && ((tmp)->entry.rbe_right
== ((void *)0) || ((tmp)->entry.rbe_right)->entry.rbe_color
== 0)) { (tmp)->entry.rbe_color = 1; elm = parent; parent
= (elm)->entry.rbe_parent; } else { if ((tmp)->entry.rbe_right
== ((void *)0) || ((tmp)->entry.rbe_right)->entry.rbe_color
== 0) { struct parse_repo *oleft; if ((oleft = (tmp)->entry
.rbe_left)) (oleft)->entry.rbe_color = 0; (tmp)->entry.
rbe_color = 1; do { (oleft) = (tmp)->entry.rbe_left; if ((
(tmp)->entry.rbe_left = (oleft)->entry.rbe_right)) { ((
oleft)->entry.rbe_right)->entry.rbe_parent = (tmp); } do
{} while (0); if (((oleft)->entry.rbe_parent = (tmp)->
entry.rbe_parent)) { if ((tmp) == ((tmp)->entry.rbe_parent
)->entry.rbe_left) ((tmp)->entry.rbe_parent)->entry.
rbe_left = (oleft); else ((tmp)->entry.rbe_parent)->entry
.rbe_right = (oleft); } else (head)->rbh_root = (oleft); (
oleft)->entry.rbe_right = (tmp); (tmp)->entry.rbe_parent
= (oleft); do {} while (0); if (((oleft)->entry.rbe_parent
)) do {} while (0); } while (0); tmp = (parent)->entry.rbe_right
; } (tmp)->entry.rbe_color = (parent)->entry.rbe_color;
(parent)->entry.rbe_color = 0; if ((tmp)->entry.rbe_right
) ((tmp)->entry.rbe_right)->entry.rbe_color = 0; do { (
tmp) = (parent)->entry.rbe_right; if (((parent)->entry.
rbe_right = (tmp)->entry.rbe_left)) { ((tmp)->entry.rbe_left
)->entry.rbe_parent = (parent); } do {} while (0); if (((tmp
)->entry.rbe_parent = (parent)->entry.rbe_parent)) { if
((parent) == ((parent)->entry.rbe_parent)->entry.rbe_left
) ((parent)->entry.rbe_parent)->entry.rbe_left = (tmp);
else ((parent)->entry.rbe_parent)->entry.rbe_right = (
tmp); } else (head)->rbh_root = (tmp); (tmp)->entry.rbe_left
= (parent); (parent)->entry.rbe_parent = (tmp); do {} while
(0); if (((tmp)->entry.rbe_parent)) do {} while (0); } while
(0); elm = (head)->rbh_root; break; } } else { tmp = (parent
)->entry.rbe_left; if ((tmp)->entry.rbe_color == 1) { do
{ (tmp)->entry.rbe_color = 0; (parent)->entry.rbe_color
= 1; } while (0); do { (tmp) = (parent)->entry.rbe_left; if
(((parent)->entry.rbe_left = (tmp)->entry.rbe_right)) {
((tmp)->entry.rbe_right)->entry.rbe_parent = (parent);
} do {} while (0); if (((tmp)->entry.rbe_parent = (parent
)->entry.rbe_parent)) { if ((parent) == ((parent)->entry
.rbe_parent)->entry.rbe_left) ((parent)->entry.rbe_parent
)->entry.rbe_left = (tmp); else ((parent)->entry.rbe_parent
)->entry.rbe_right = (tmp); } else (head)->rbh_root = (
tmp); (tmp)->entry.rbe_right = (parent); (parent)->entry
.rbe_parent = (tmp); do {} while (0); if (((tmp)->entry.rbe_parent
)) do {} while (0); } while (0); tmp = (parent)->entry.rbe_left
; } if (((tmp)->entry.rbe_left == ((void *)0) || ((tmp)->
entry.rbe_left)->entry.rbe_color == 0) && ((tmp)->
entry.rbe_right == ((void *)0) || ((tmp)->entry.rbe_right)
->entry.rbe_color == 0)) { (tmp)->entry.rbe_color = 1; elm
= parent; parent = (elm)->entry.rbe_parent; } else { if (
(tmp)->entry.rbe_left == ((void *)0) || ((tmp)->entry.rbe_left
)->entry.rbe_color == 0) { struct parse_repo *oright; if (
(oright = (tmp)->entry.rbe_right)) (oright)->entry.rbe_color
= 0; (tmp)->entry.rbe_color = 1; do { (oright) = (tmp)->
entry.rbe_right; if (((tmp)->entry.rbe_right = (oright)->
entry.rbe_left)) { ((oright)->entry.rbe_left)->entry.rbe_parent
= (tmp); } do {} while (0); if (((oright)->entry.rbe_parent
= (tmp)->entry.rbe_parent)) { if ((tmp) == ((tmp)->entry
.rbe_parent)->entry.rbe_left) ((tmp)->entry.rbe_parent)
->entry.rbe_left = (oright); else ((tmp)->entry.rbe_parent
)->entry.rbe_right = (oright); } else (head)->rbh_root =
(oright); (oright)->entry.rbe_left = (tmp); (tmp)->entry
.rbe_parent = (oright); do {} while (0); if (((oright)->entry
.rbe_parent)) do {} while (0); } while (0); tmp = (parent)->
entry.rbe_left; } (tmp)->entry.rbe_color = (parent)->entry
.rbe_color; (parent)->entry.rbe_color = 0; if ((tmp)->entry
.rbe_left) ((tmp)->entry.rbe_left)->entry.rbe_color = 0
; do { (tmp) = (parent)->entry.rbe_left; if (((parent)->
entry.rbe_left = (tmp)->entry.rbe_right)) { ((tmp)->entry
.rbe_right)->entry.rbe_parent = (parent); } do {} while (0
); if (((tmp)->entry.rbe_parent = (parent)->entry.rbe_parent
)) { if ((parent) == ((parent)->entry.rbe_parent)->entry
.rbe_left) ((parent)->entry.rbe_parent)->entry.rbe_left
= (tmp); else ((parent)->entry.rbe_parent)->entry.rbe_right
= (tmp); } else (head)->rbh_root = (tmp); (tmp)->entry
.rbe_right = (parent); (parent)->entry.rbe_parent = (tmp);
do {} while (0); if (((tmp)->entry.rbe_parent)) do {} while
(0); } while (0); elm = (head)->rbh_root; break; } } } if
(elm) (elm)->entry.rbe_color = 0; } __attribute__((__unused__
)) static struct parse_repo * repo_tree_RB_REMOVE(struct repo_tree
*head, struct parse_repo *elm) { struct parse_repo *child, *
parent, *old = elm; int color; if ((elm)->entry.rbe_left ==
((void *)0)) child = (elm)->entry.rbe_right; else if ((elm
)->entry.rbe_right == ((void *)0)) child = (elm)->entry
.rbe_left; else { struct parse_repo *left; elm = (elm)->entry
.rbe_right; while ((left = (elm)->entry.rbe_left)) elm = left
; child = (elm)->entry.rbe_right; parent = (elm)->entry
.rbe_parent; color = (elm)->entry.rbe_color; if (child) (child
)->entry.rbe_parent = parent; if (parent) { if ((parent)->
entry.rbe_left == elm) (parent)->entry.rbe_left = child; else
(parent)->entry.rbe_right = child; do {} while (0); } else
(head)->rbh_root = child; if ((elm)->entry.rbe_parent ==
old) parent = elm; (elm)->entry = (old)->entry; if ((old
)->entry.rbe_parent) { if (((old)->entry.rbe_parent)->
entry.rbe_left == old) ((old)->entry.rbe_parent)->entry
.rbe_left = elm; else ((old)->entry.rbe_parent)->entry.
rbe_right = elm; do {} while (0); } else (head)->rbh_root =
elm; ((old)->entry.rbe_left)->entry.rbe_parent = elm; if
((old)->entry.rbe_right) ((old)->entry.rbe_right)->
entry.rbe_parent = elm; if (parent) { left = parent; do { do {
} while (0); } while ((left = (left)->entry.rbe_parent)); }
goto color; } parent = (elm)->entry.rbe_parent; color = (
elm)->entry.rbe_color; if (child) (child)->entry.rbe_parent
= parent; if (parent) { if ((parent)->entry.rbe_left == elm
) (parent)->entry.rbe_left = child; else (parent)->entry
.rbe_right = child; do {} while (0); } else (head)->rbh_root
= child; color: if (color == 0) repo_tree_RB_REMOVE_COLOR(head
, parent, child); return (old); } __attribute__((__unused__))
static struct parse_repo * repo_tree_RB_INSERT(struct repo_tree
*head, struct parse_repo *elm) { struct parse_repo *tmp; struct
parse_repo *parent = ((void *)0); int comp = 0; tmp = (head)
->rbh_root; while (tmp) { parent = tmp; comp = (repocmp)(elm
, parent); if (comp < 0) tmp = (tmp)->entry.rbe_left; else
if (comp > 0) tmp = (tmp)->entry.rbe_right; else return
(tmp); } do { (elm)->entry.rbe_parent = parent; (elm)->
entry.rbe_left = (elm)->entry.rbe_right = ((void *)0); (elm
)->entry.rbe_color = 1; } while (0); if (parent != ((void *
)0)) { if (comp < 0) (parent)->entry.rbe_left = elm; else
(parent)->entry.rbe_right = elm; do {} while (0); } else (
head)->rbh_root = elm; repo_tree_RB_INSERT_COLOR(head, elm
); return (((void *)0)); } __attribute__((__unused__)) static
struct parse_repo * repo_tree_RB_FIND(struct repo_tree *head
, struct parse_repo *elm) { struct parse_repo *tmp = (head)->
rbh_root; int comp; while (tmp) { comp = repocmp(elm, tmp); if
(comp < 0) tmp = (tmp)->entry.rbe_left; else if (comp >
0) tmp = (tmp)->entry.rbe_right; else return (tmp); } return
(((void *)0)); } __attribute__((__unused__)) static struct parse_repo
* repo_tree_RB_NFIND(struct repo_tree *head, struct parse_repo
*elm) { struct parse_repo *tmp = (head)->rbh_root; struct
parse_repo *res = ((void *)0); int comp; while (tmp) { comp =
repocmp(elm, tmp); if (comp < 0) { res = tmp; tmp = (tmp)
->entry.rbe_left; } else if (comp > 0) tmp = (tmp)->
entry.rbe_right; else return (tmp); } return (res); } __attribute__
((__unused__)) static struct parse_repo * repo_tree_RB_NEXT(struct
parse_repo *elm) { if ((elm)->entry.rbe_right) { elm = (elm
)->entry.rbe_right; while ((elm)->entry.rbe_left) elm =
(elm)->entry.rbe_left; } else { if ((elm)->entry.rbe_parent
&& (elm == ((elm)->entry.rbe_parent)->entry.rbe_left
)) elm = (elm)->entry.rbe_parent; else { while ((elm)->
entry.rbe_parent && (elm == ((elm)->entry.rbe_parent
)->entry.rbe_right)) elm = (elm)->entry.rbe_parent; elm
= (elm)->entry.rbe_parent; } } return (elm); } __attribute__
((__unused__)) static struct parse_repo * repo_tree_RB_PREV(struct
parse_repo *elm) { if ((elm)->entry.rbe_left) { elm = (elm
)->entry.rbe_left; while ((elm)->entry.rbe_right) elm =
(elm)->entry.rbe_right; } else { if ((elm)->entry.rbe_parent
&& (elm == ((elm)->entry.rbe_parent)->entry.rbe_right
)) elm = (elm)->entry.rbe_parent; else { while ((elm)->
entry.rbe_parent && (elm == ((elm)->entry.rbe_parent
)->entry.rbe_left)) elm = (elm)->entry.rbe_parent; elm =
(elm)->entry.rbe_parent; } } return (elm); } __attribute__
((__unused__)) static struct parse_repo * repo_tree_RB_MINMAX
(struct repo_tree *head, int val) { struct parse_repo *tmp = (
head)->rbh_root; struct parse_repo *parent = ((void *)0); while
(tmp) { parent = tmp; if (val < 0) tmp = (tmp)->entry.
rbe_left; else tmp = (tmp)->entry.rbe_right; } return (parent
); }
;
63
64static struct parse_repo *
65repo_get(unsigned int id)
66{
67 struct parse_repo needle = { .id = id };
68
69 return RB_FIND(repo_tree, &repos, &needle)repo_tree_RB_FIND(&repos, &needle);
70}
71
72static void
73repo_add(unsigned int id, char *path, char *validpath)
74{
75 struct parse_repo *rp;
76
77 if ((rp = calloc(1, sizeof(*rp))) == NULL((void *)0))
78 err(1, NULL((void *)0));
79 rp->id = id;
80 if (path != NULL((void *)0))
81 if ((rp->path = strdup(path)) == NULL((void *)0))
82 err(1, NULL((void *)0));
83 if (validpath != NULL((void *)0))
84 if ((rp->validpath = strdup(validpath)) == NULL((void *)0))
85 err(1, NULL((void *)0));
86
87 if (RB_INSERT(repo_tree, &repos, rp)repo_tree_RB_INSERT(&repos, rp) != NULL((void *)0))
88 errx(1, "repository already added: id %d, %s", id, path);
89}
90
91/*
92 * Build access path to file based on repoid, path, location and file values.
93 */
94static char *
95parse_filepath(unsigned int repoid, const char *path, const char *file,
96 enum location loc)
97{
98 struct parse_repo *rp;
99 char *fn, *repopath;
100
101 /* build file path based on repoid, entity path and filename */
102 rp = repo_get(repoid);
103 if (rp == NULL((void *)0))
104 errx(1, "build file path: repository %u missing", repoid);
105
106 if (loc == DIR_VALID)
107 repopath = rp->validpath;
108 else
109 repopath = rp->path;
110
111 if (repopath == NULL((void *)0))
112 return NULL((void *)0);
113
114 if (path == NULL((void *)0)) {
115 if (asprintf(&fn, "%s/%s", repopath, file) == -1)
116 err(1, NULL((void *)0));
117 } else {
118 if (asprintf(&fn, "%s/%s/%s", repopath, path, file) == -1)
119 err(1, NULL((void *)0));
120 }
121 return fn;
122}
123
124/*
125 * Parse and validate a ROA.
126 * This is standard stuff.
127 * Returns the roa on success, NULL on failure.
128 */
129static struct roa *
130proc_parser_roa(char *file, const unsigned char *der, size_t len,
131 const struct entity *entp)
132{
133 struct roa *roa;
134 struct auth *a;
135 struct crl *crl;
136 X509 *x509;
137 const char *errstr;
138
139 if ((roa = roa_parse(&x509, file, entp->talid, der, len)) == NULL((void *)0))
140 return NULL((void *)0);
141
142 a = valid_ski_aki(file, &auths, roa->ski, roa->aki, entp->mftaki);
143 crl = crl_get(&crlt, a);
144
145 if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
146 warnx("%s: %s", file, errstr);
147 X509_free(x509);
148 roa_free(roa);
149 return NULL((void *)0);
150 }
151 X509_free(x509);
152
153 roa->talid = a->cert->talid;
154
155 roa->expires = x509_find_expires(roa->notafter, a, &crlt);
156
157 return roa;
158}
159
160/*
161 * Check all files and their hashes in a MFT structure.
162 * Return zero on failure, non-zero on success.
163 */
164static int
165proc_parser_mft_check(const char *fn, struct mft *p)
166{
167 const enum location loc[2] = { DIR_TEMP, DIR_VALID };
168 size_t i;
169 int rc = 1;
170 char *path;
171
172 for (i = 0; i < p->filesz; i++) {
173 struct mftfile *m = &p->files[i];
174 int try, fd = -1, noent = 0, valid = 0;
175 for (try = 0; try < 2 && !valid; try++) {
176 if ((path = parse_filepath(p->repoid, p->path, m->file,
177 loc[try])) == NULL((void *)0))
178 continue;
179 fd = open(path, O_RDONLY0x0000);
180 if (fd == -1 && errno(*__errno()) == ENOENT2)
181 noent++;
182 free(path);
183
184 /* remember which path was checked */
185 m->location = loc[try];
186 valid = valid_filehash(fd, m->hash, sizeof(m->hash));
187 }
188
189 if (!valid) {
190 /* silently skip not-existing unknown files */
191 if (m->type == RTYPE_INVALID && noent == 2)
192 continue;
193 warnx("%s#%s: bad message digest for %s", fn,
194 p->seqnum, m->file);
195 rc = 0;
196 continue;
197 }
198 }
199
200 return rc;
201}
202
203/*
204 * Load the CRL from loc using the info from the MFT.
205 */
206static struct crl *
207parse_load_crl_from_mft(struct entity *entp, struct mft *mft, enum location loc,
208 char **crlfile)
209{
210 struct crl *crl = NULL((void *)0);
211 unsigned char *f = NULL((void *)0);
212 char *fn = NULL((void *)0);
213 size_t flen;
214
215 *crlfile = NULL((void *)0);
216
217 fn = parse_filepath(entp->repoid, entp->path, mft->crl, loc);
218 if (fn == NULL((void *)0))
219 goto out;
220
221 f = load_file(fn, &flen);
222 if (f == NULL((void *)0)) {
223 if (errno(*__errno()) != ENOENT2)
224 warn("parse file %s", fn);
225 goto out;
226 }
227
228 if (!valid_hash(f, flen, mft->crlhash, sizeof(mft->crlhash)))
229 goto out;
230
231 crl = crl_parse(fn, f, flen);
232 if (crl == NULL((void *)0))
233 goto out;
234
235 if (strcmp(crl->aki, mft->aki) != 0) {
236 warnx("%s: AKI doesn't match Manifest AKI", fn);
237 goto out;
238 }
239
240 *crlfile = fn;
241 free(f);
242
243 return crl;
244
245 out:
246 crl_free(crl);
247 free(f);
248 free(fn);
249
250 return NULL((void *)0);
251}
252
253/*
254 * Parse and validate a manifest file. Skip checking the fileandhash
255 * this is done in the post check. After this step we know the mft is
256 * valid and can be compared.
257 * Return the mft on success or NULL on failure.
258 */
259static struct mft *
260proc_parser_mft_pre(struct entity *entp, enum location loc, char **file,
261 struct crl **crl, char **crlfile, const char **errstr)
262{
263 struct mft *mft;
264 X509 *x509;
265 struct auth *a;
266 unsigned char *der;
267 size_t len;
268
269 *crl = NULL((void *)0);
270 *crlfile = NULL((void *)0);
271 *errstr = NULL((void *)0);
272
273 *file = parse_filepath(entp->repoid, entp->path, entp->file, loc);
274 if (*file == NULL((void *)0))
275 return NULL((void *)0);
276
277 der = load_file(*file, &len);
278 if (der == NULL((void *)0) && errno(*__errno()) != ENOENT2)
279 warn("parse file %s", *file);
280
281 if ((mft = mft_parse(&x509, *file, entp->talid, der, len)) == NULL((void *)0)) {
282 free(der);
283 return NULL((void *)0);
284 }
285
286 if (!EVP_Digest(der, len, mft->mfthash, NULL((void *)0), EVP_sha256(), NULL((void *)0)))
287 errx(1, "EVP_Digest failed");
288
289 free(der);
290
291 *crl = parse_load_crl_from_mft(entp, mft, DIR_TEMP, crlfile);
292 if (*crl == NULL((void *)0))
293 *crl = parse_load_crl_from_mft(entp, mft, DIR_VALID, crlfile);
294
295 a = valid_ski_aki(*file, &auths, mft->ski, mft->aki, NULL((void *)0));
296 if (!valid_x509(*file, ctx, x509, a, *crl, errstr)) {
297 X509_free(x509);
298 mft_free(mft);
299 crl_free(*crl);
300 *crl = NULL((void *)0);
301 free(*crlfile);
302 *crlfile = NULL((void *)0);
303 return NULL((void *)0);
304 }
305 X509_free(x509);
306
307 mft->repoid = entp->repoid;
308 mft->talid = a->cert->talid;
309
310 return mft;
311}
312
313/*
314 * Do the end of manifest validation.
315 * Return the mft on success or NULL on failure.
316 */
317static struct mft *
318proc_parser_mft_post(char *file, struct mft *mft, const char *path,
319 const char *errstr, int *warned)
320{
321 /* check that now is not before from */
322 time_t now = get_current_time();
323
324 if (mft == NULL((void *)0)) {
325 if (errstr == NULL((void *)0))
326 errstr = "no valid mft available";
327 if ((*warned)++ > 0)
328 return NULL((void *)0);
329 warnx("%s: %s", file, errstr);
330 return NULL((void *)0);
331 }
332
333 /* check that now is not before from */
334 if (now < mft->thisupdate) {
335 warnx("%s: mft not yet valid %s", file,
336 time2str(mft->thisupdate));
337 mft->stale = 1;
338 }
339 /* check that now is not after until */
340 if (now > mft->nextupdate) {
341 warnx("%s: mft expired on %s", file,
342 time2str(mft->nextupdate));
343 mft->stale = 1;
344 }
345
346 if (path != NULL((void *)0))
347 if ((mft->path = strdup(path)) == NULL((void *)0))
348 err(1, NULL((void *)0));
349
350 if (!mft->stale)
351 if (!proc_parser_mft_check(file, mft)) {
352 mft_free(mft);
353 return NULL((void *)0);
354 }
355
356 return mft;
357}
358
359/*
360 * Load the most recent MFT by opening both options and comparing the two.
361 */
362static char *
363proc_parser_mft(struct entity *entp, struct mft **mp, char **crlfile,
364 time_t *crlmtime)
365{
366 struct mft *mft1 = NULL((void *)0), *mft2 = NULL((void *)0);
367 struct crl *crl, *crl1, *crl2;
368 char *file, *file1, *file2, *crl1file, *crl2file;
369 const char *err1, *err2;
370 int r, warned = 0;
371
372 *mp = NULL((void *)0);
373 *crlmtime = 0;
374
375 mft1 = proc_parser_mft_pre(entp, DIR_TEMP, &file1, &crl1, &crl1file,
376 &err1);
377 mft2 = proc_parser_mft_pre(entp, DIR_VALID, &file2, &crl2, &crl2file,
378 &err2);
379
380 /* overload error from temp file if it is set */
381 if (mft1 == NULL((void *)0) && mft2 == NULL((void *)0))
41
Assuming 'mft1' is equal to NULL
42
Assuming 'mft2' is not equal to NULL
43
Taking false branch
382 if (err2 != NULL((void *)0))
383 err1 = err2;
384
385 r = mft_compare(mft1, mft2);
386 if (r == -1 && mft1 != NULL((void *)0) && mft2 != NULL((void *)0))
44
Assuming the condition is false
387 warnx("%s: unexpected manifest number (want >= #%s, got #%s)",
388 file1, mft2->seqnum, mft1->seqnum);
389
390 if (r == 0 && memcmp(mft1->mfthash, mft2->mfthash,
45
Assuming 'r' is equal to 0
46
Null pointer passed as 1st argument to memory comparison function
391 SHA256_DIGEST_LENGTH32) != 0)
392 warnx("%s: manifest misissuance, #%s was recycled",
393 file1, mft1->seqnum);
394
395 if (!noop && r == 1) {
396 *mp = proc_parser_mft_post(file1, mft1, entp->path, err1,
397 &warned);
398 if (*mp == NULL((void *)0)) {
399 mft1 = NULL((void *)0);
400 if (mft2 != NULL((void *)0))
401 warnx("%s: failed fetch, continuing with #%s"
402 " from cache", file2, mft2->seqnum);
403 }
404 }
405
406 if (*mp != NULL((void *)0)) {
407 mft_free(mft2);
408 crl_free(crl2);
409 free(crl2file);
410 free(file2);
411
412 crl = crl1;
413 file = file1;
414 *crlfile = crl1file;
415 } else {
416 if (err2 == NULL((void *)0))
417 err2 = err1;
418 *mp = proc_parser_mft_post(file2, mft2, entp->path, err2,
419 &warned);
420
421 mft_free(mft1);
422 crl_free(crl1);
423 free(crl1file);
424 free(file1);
425
426 crl = crl2;
427 file = file2;
428 *crlfile = crl2file;
429 }
430
431 if (*mp != NULL((void *)0)) {
432 *crlmtime = crl->lastupdate;
433 if (!crl_insert(&crlt, crl)) {
434 warnx("%s: duplicate AKI %s", file, crl->aki);
435 crl_free(crl);
436 }
437 } else {
438 crl_free(crl);
439 }
440 return file;
441}
442
443/*
444 * Certificates are from manifests (has a digest and is signed with
445 * another certificate) Parse the certificate, make sure its
446 * signatures are valid (with CRLs), then validate the RPKI content.
447 * This returns a certificate (which must not be freed) or NULL on
448 * parse failure.
449 */
450static struct cert *
451proc_parser_cert(char *file, const unsigned char *der, size_t len,
452 const char *mftaki)
453{
454 struct cert *cert;
455 struct crl *crl;
456 struct auth *a;
457 const char *errstr = NULL((void *)0);
458
459 /* Extract certificate data. */
460
461 cert = cert_parse_pre(file, der, len);
462 cert = cert_parse(file, cert);
463 if (cert == NULL((void *)0))
464 return NULL((void *)0);
465
466 a = valid_ski_aki(file, &auths, cert->ski, cert->aki, mftaki);
467 crl = crl_get(&crlt, a);
468
469 if (!valid_x509(file, ctx, cert->x509, a, crl, &errstr) ||
470 !valid_cert(file, a, cert)) {
471 if (errstr != NULL((void *)0))
472 warnx("%s: %s", file, errstr);
473 cert_free(cert);
474 return NULL((void *)0);
475 }
476
477 cert->talid = a->cert->talid;
478
479 if (cert->purpose == CERT_PURPOSE_BGPSEC_ROUTER) {
480 if (!constraints_validate(file, cert)) {
481 cert_free(cert);
482 return NULL((void *)0);
483 }
484 }
485
486 /*
487 * Add validated CA certs to the RPKI auth tree.
488 */
489 if (cert->purpose == CERT_PURPOSE_CA)
490 auth_insert(&auths, cert, a);
491
492 return cert;
493}
494
495/*
496 * Root certificates come from TALs (has a pkey and is self-signed).
497 * Parse the certificate, ensure that its public key matches the
498 * known public key from the TAL, and then validate the RPKI
499 * content.
500 *
501 * This returns a certificate (which must not be freed) or NULL on
502 * parse failure.
503 */
504static struct cert *
505proc_parser_root_cert(char *file, const unsigned char *der, size_t len,
506 unsigned char *pkey, size_t pkeysz, int talid)
507{
508 struct cert *cert;
509
510 /* Extract certificate data. */
511
512 cert = cert_parse_pre(file, der, len);
513 cert = ta_parse(file, cert, pkey, pkeysz);
514 if (cert == NULL((void *)0))
515 return NULL((void *)0);
516
517 if (!valid_ta(file, &auths, cert)) {
518 warnx("%s: certificate not a valid ta", file);
519 cert_free(cert);
520 return NULL((void *)0);
521 }
522
523 cert->talid = talid;
524
525 /*
526 * Add valid roots to the RPKI auth tree.
527 */
528 auth_insert(&auths, cert, NULL((void *)0));
529
530 return cert;
531}
532
533/*
534 * Parse a ghostbuster record
535 */
536static struct gbr *
537proc_parser_gbr(char *file, const unsigned char *der, size_t len,
538 const struct entity *entp)
539{
540 struct gbr *gbr;
541 X509 *x509;
542 struct crl *crl;
543 struct auth *a;
544 const char *errstr;
545
546 if ((gbr = gbr_parse(&x509, file, entp->talid, der, len)) == NULL((void *)0))
547 return NULL((void *)0);
548
549 a = valid_ski_aki(file, &auths, gbr->ski, gbr->aki, entp->mftaki);
550 crl = crl_get(&crlt, a);
551
552 /* return value can be ignored since nothing happens here */
553 if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
554 warnx("%s: %s", file, errstr);
555 X509_free(x509);
556 gbr_free(gbr);
557 return NULL((void *)0);
558 }
559 X509_free(x509);
560
561 gbr->talid = a->cert->talid;
562
563 return gbr;
564}
565
566/*
567 * Parse an ASPA object
568 */
569static struct aspa *
570proc_parser_aspa(char *file, const unsigned char *der, size_t len,
571 const struct entity *entp)
572{
573 struct aspa *aspa;
574 struct auth *a;
575 struct crl *crl;
576 X509 *x509;
577 const char *errstr;
578
579 if ((aspa = aspa_parse(&x509, file, entp->talid, der, len)) == NULL((void *)0))
580 return NULL((void *)0);
581
582 a = valid_ski_aki(file, &auths, aspa->ski, aspa->aki, entp->mftaki);
583 crl = crl_get(&crlt, a);
584
585 if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
586 warnx("%s: %s", file, errstr);
587 X509_free(x509);
588 aspa_free(aspa);
589 return NULL((void *)0);
590 }
591 X509_free(x509);
592
593 aspa->talid = a->cert->talid;
594
595 aspa->expires = x509_find_expires(aspa->notafter, a, &crlt);
596
597 return aspa;
598}
599
600/*
601 * Parse a TAK object.
602 */
603static struct tak *
604proc_parser_tak(char *file, const unsigned char *der, size_t len,
605 const struct entity *entp)
606{
607 struct tak *tak;
608 X509 *x509;
609 struct crl *crl;
610 struct auth *a;
611 const char *errstr;
612 int rc = 0;
613
614 if ((tak = tak_parse(&x509, file, entp->talid, der, len)) == NULL((void *)0))
615 return NULL((void *)0);
616
617 a = valid_ski_aki(file, &auths, tak->ski, tak->aki, entp->mftaki);
618 crl = crl_get(&crlt, a);
619
620 if (!valid_x509(file, ctx, x509, a, crl, &errstr)) {
621 warnx("%s: %s", file, errstr);
622 goto out;
623 }
624
625 /* TAK EE must be signed by self-signed CA */
626 if (a->parent != NULL((void *)0))
627 goto out;
628
629 tak->talid = a->cert->talid;
630 rc = 1;
631 out:
632 if (rc == 0) {
633 tak_free(tak);
634 tak = NULL((void *)0);
635 }
636 X509_free(x509);
637 return tak;
638}
639
640/*
641 * Load the file specified by the entity information.
642 */
643static char *
644parse_load_file(struct entity *entp, unsigned char **f, size_t *flen)
645{
646 char *file;
647
648 file = parse_filepath(entp->repoid, entp->path, entp->file,
649 entp->location);
650 if (file == NULL((void *)0))
651 errx(1, "no path to file");
652
653 *f = load_file(file, flen);
654 if (*f == NULL((void *)0))
655 warn("parse file %s", file);
656
657 return file;
658}
659
660/*
661 * Process an entity and respond to parent process.
662 */
663static void
664parse_entity(struct entityq *q, struct msgbuf *msgq)
665{
666 struct entity *entp;
667 struct tal *tal;
668 struct cert *cert;
669 struct mft *mft;
670 struct roa *roa;
671 struct aspa *aspa;
672 struct gbr *gbr;
673 struct tak *tak;
674 struct ibuf *b;
675 unsigned char *f;
676 time_t mtime, crlmtime;
677 size_t flen;
678 char *file, *crlfile;
679 int c;
680
681 while ((entp = TAILQ_FIRST(q)((q)->tqh_first)) != NULL((void *)0)) {
34
Loop condition is true. Entering loop body
682 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)
;
35
Taking false branch
36
Loop condition is false. Exiting loop
683
684 /* handle RTYPE_REPO first */
685 if (entp->type == RTYPE_REPO) {
37
Assuming field 'type' is not equal to RTYPE_REPO
38
Taking false branch
686 repo_add(entp->repoid, entp->path, entp->file);
687 entity_free(entp);
688 continue;
689 }
690
691 /* pass back at least type, repoid and filename */
692 b = io_new_buffer();
693 io_simple_buffer(b, &entp->type, sizeof(entp->type));
694 io_simple_buffer(b, &entp->repoid, sizeof(entp->repoid));
695 io_simple_buffer(b, &entp->talid, sizeof(entp->talid));
696
697 file = NULL((void *)0);
698 f = NULL((void *)0);
699 mtime = 0;
700 crlmtime = 0;
701
702 switch (entp->type) {
39
Control jumps to 'case RTYPE_MFT:' at line 739
703 case RTYPE_TAL:
704 io_str_buffer(b, entp->file);
705 io_simple_buffer(b, &mtime, sizeof(mtime));
706 if ((tal = tal_parse(entp->file, entp->data,
707 entp->datasz)) == NULL((void *)0))
708 errx(1, "%s: could not parse tal file",
709 entp->file);
710 tal->id = entp->talid;
711 tal_buffer(b, tal);
712 tal_free(tal);
713 break;
714 case RTYPE_CER:
715 file = parse_load_file(entp, &f, &flen);
716 io_str_buffer(b, file);
717 if (entp->data != NULL((void *)0))
718 cert = proc_parser_root_cert(file,
719 f, flen, entp->data, entp->datasz,
720 entp->talid);
721 else
722 cert = proc_parser_cert(file, f, flen,
723 entp->mftaki);
724 if (cert != NULL((void *)0))
725 mtime = cert->notbefore;
726 io_simple_buffer(b, &mtime, sizeof(mtime));
727 c = (cert != NULL((void *)0));
728 io_simple_buffer(b, &c, sizeof(int));
729 if (cert != NULL((void *)0)) {
730 cert->repoid = entp->repoid;
731 cert_buffer(b, cert);
732 }
733 /*
734 * The parsed certificate data "cert" is now
735 * managed in the "auths" table, so don't free
736 * it here.
737 */
738 break;
739 case RTYPE_MFT:
740 file = proc_parser_mft(entp, &mft, &crlfile, &crlmtime);
40
Calling 'proc_parser_mft'
741 io_str_buffer(b, file);
742 if (mft != NULL((void *)0))
743 mtime = mft->signtime;
744 io_simple_buffer(b, &mtime, sizeof(mtime));
745 c = (mft != NULL((void *)0));
746 io_simple_buffer(b, &c, sizeof(int));
747 if (mft != NULL((void *)0))
748 mft_buffer(b, mft);
749
750 /* Push valid CRL together with the MFT. */
751 if (crlfile != NULL((void *)0)) {
752 enum rtype type;
753 struct ibuf *b2;
754
755 b2 = io_new_buffer();
756 type = RTYPE_CRL;
757 io_simple_buffer(b2, &type, sizeof(type));
758 io_simple_buffer(b2, &entp->repoid,
759 sizeof(entp->repoid));
760 io_simple_buffer(b2, &entp->talid,
761 sizeof(entp->talid));
762 io_str_buffer(b2, crlfile);
763 io_simple_buffer(b2, &crlmtime,
764 sizeof(crlmtime));
765 free(crlfile);
766
767 io_close_buffer(msgq, b2);
768 }
769 mft_free(mft);
770 break;
771 case RTYPE_ROA:
772 file = parse_load_file(entp, &f, &flen);
773 io_str_buffer(b, file);
774 roa = proc_parser_roa(file, f, flen, entp);
775 if (roa != NULL((void *)0))
776 mtime = roa->signtime;
777 io_simple_buffer(b, &mtime, sizeof(mtime));
778 c = (roa != NULL((void *)0));
779 io_simple_buffer(b, &c, sizeof(int));
780 if (roa != NULL((void *)0))
781 roa_buffer(b, roa);
782 roa_free(roa);
783 break;
784 case RTYPE_GBR:
785 file = parse_load_file(entp, &f, &flen);
786 io_str_buffer(b, file);
787 gbr = proc_parser_gbr(file, f, flen, entp);
788 if (gbr != NULL((void *)0))
789 mtime = gbr->signtime;
790 io_simple_buffer(b, &mtime, sizeof(mtime));
791 gbr_free(gbr);
792 break;
793 case RTYPE_ASPA:
794 file = parse_load_file(entp, &f, &flen);
795 io_str_buffer(b, file);
796 aspa = proc_parser_aspa(file, f, flen, entp);
797 if (aspa != NULL((void *)0))
798 mtime = aspa->signtime;
799 io_simple_buffer(b, &mtime, sizeof(mtime));
800 c = (aspa != NULL((void *)0));
801 io_simple_buffer(b, &c, sizeof(int));
802 if (aspa != NULL((void *)0))
803 aspa_buffer(b, aspa);
804 aspa_free(aspa);
805 break;
806 case RTYPE_TAK:
807 file = parse_load_file(entp, &f, &flen);
808 io_str_buffer(b, file);
809 tak = proc_parser_tak(file, f, flen, entp);
810 if (tak != NULL((void *)0))
811 mtime = tak->signtime;
812 io_simple_buffer(b, &mtime, sizeof(mtime));
813 tak_free(tak);
814 break;
815 case RTYPE_CRL:
816 default:
817 file = parse_filepath(entp->repoid, entp->path,
818 entp->file, entp->location);
819 io_str_buffer(b, file);
820 io_simple_buffer(b, &mtime, sizeof(mtime));
821 warnx("%s: unhandled type %d", file, entp->type);
822 break;
823 }
824
825 free(f);
826 free(file);
827 io_close_buffer(msgq, b);
828 entity_free(entp);
829 }
830}
831
832/*
833 * Process responsible for parsing and validating content.
834 * All this process does is wait to be told about a file to parse, then
835 * it parses it and makes sure that the data being returned is fully
836 * validated and verified.
837 * The process will exit cleanly only when fd is closed.
838 */
839void
840proc_parser(int fd)
841{
842 struct entityq q;
843 struct msgbuf msgq;
844 struct pollfd pfd;
845 struct entity *entp;
846 struct ibuf *b, *inbuf = NULL((void *)0);
847
848 /* Only allow access to the cache directory. */
849 if (unveil(".", "r") == -1)
1
Assuming the condition is false
2
Taking false branch
850 err(1, "unveil cachedir");
851 if (pledge("stdio rpath", NULL((void *)0)) == -1)
3
Assuming the condition is false
4
Taking false branch
852 err(1, "pledge");
853
854 ERR_load_crypto_strings();
855 OpenSSL_add_all_ciphers();
856 OpenSSL_add_all_digests();
857 x509_init_oid();
858 constraints_parse();
859
860 if ((ctx = X509_STORE_CTX_new()) == NULL((void *)0))
5
Assuming the condition is false
6
Taking false branch
861 err(1, "X509_STORE_CTX_new");
862
863 TAILQ_INIT(&q)do { (&q)->tqh_first = ((void *)0); (&q)->tqh_last
= &(&q)->tqh_first; } while (0)
;
7
Loop condition is false. Exiting loop
864
865 msgbuf_init(&msgq);
866 msgq.fd = fd;
867
868 pfd.fd = fd;
869
870 for (;;) {
8
Loop condition is true. Entering loop body
16
Loop condition is true. Entering loop body
871 pfd.events = POLLIN0x0001;
872 if (msgq.queued
16.1
Field 'queued' is 0
)
9
Assuming field 'queued' is 0
10
Taking false branch
17
Taking false branch
873 pfd.events |= POLLOUT0x0004;
874
875 if (poll(&pfd, 1, INFTIM(-1)) == -1) {
11
Assuming the condition is true
12
Taking true branch
18
Assuming the condition is false
19
Taking false branch
876 if (errno(*__errno()) == EINTR4)
13
Assuming the condition is true
14
Taking true branch
877 continue;
15
Execution continues on line 870
878 err(1, "poll");
879 }
880 if ((pfd.revents & (POLLERR0x0008|POLLNVAL0x0020)))
20
Assuming the condition is false
21
Taking false branch
881 errx(1, "poll: bad descriptor");
882
883 /* If the parent closes, return immediately. */
884
885 if ((pfd.revents & POLLHUP0x0010))
22
Assuming the condition is false
23
Taking false branch
886 break;
887
888 if ((pfd.revents & POLLIN0x0001)) {
24
Assuming the condition is true
25
Taking true branch
889 b = io_buf_read(fd, &inbuf);
890 if (b != NULL((void *)0)) {
26
Assuming 'b' is not equal to NULL
27
Taking true branch
891 entp = calloc(1, sizeof(struct entity));
892 if (entp == NULL((void *)0))
28
Assuming 'entp' is not equal to NULL
29
Taking false branch
893 err(1, NULL((void *)0));
894 entity_read_req(b, entp);
895 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)
;
30
Loop condition is false. Exiting loop
896 ibuf_free(b);
897 }
898 }
899
900 if (pfd.revents & POLLOUT0x0004) {
31
Assuming the condition is false
32
Taking false branch
901 switch (msgbuf_write(&msgq)) {
902 case 0:
903 errx(1, "write: connection closed");
904 case -1:
905 err(1, "write");
906 }
907 }
908
909 parse_entity(&q, &msgq);
33
Calling 'parse_entity'
910 }
911
912 while ((entp = TAILQ_FIRST(&q)((&q)->tqh_first)) != NULL((void *)0)) {
913 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)
;
914 entity_free(entp);
915 }
916
917 auth_tree_free(&auths);
918 crl_tree_free(&crlt);
919
920 X509_STORE_CTX_free(ctx);
921 msgbuf_clear(&msgq);
922
923 ibuf_free(inbuf);
924
925 exit(0);
926}