Bug Summary

File:src/usr.sbin/rpki-client/rrdp_notification.c
Warning:line 478, column 8
Null pointer passed as 2nd argument to string 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 rrdp_notification.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/rrdp_notification.c
1/* $OpenBSD: rrdp_notification.c,v 1.19 2023/12/27 07:17:39 tb Exp $ */
2/*
3 * Copyright (c) 2020 Nils Fisher <nils_fisher@hotmail.com>
4 * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
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/stat.h>
20
21#include <assert.h>
22#include <err.h>
23#include <errno(*__errno()).h>
24#include <limits.h>
25#include <fcntl.h>
26#include <string.h>
27#include <unistd.h>
28
29#include <expat.h>
30#include <openssl/sha.h>
31
32#include "extern.h"
33#include "rrdp.h"
34
35enum notification_scope {
36 NOTIFICATION_SCOPE_START,
37 NOTIFICATION_SCOPE_NOTIFICATION,
38 NOTIFICATION_SCOPE_SNAPSHOT,
39 NOTIFICATION_SCOPE_NOTIFICATION_POST_SNAPSHOT,
40 NOTIFICATION_SCOPE_DELTA,
41 NOTIFICATION_SCOPE_END
42};
43
44struct delta_item {
45 char *uri;
46 char hash[SHA256_DIGEST_LENGTH32];
47 long long serial;
48 TAILQ_ENTRY(delta_item)struct { struct delta_item *tqe_next; struct delta_item **tqe_prev
; }
q;
49};
50
51TAILQ_HEAD(delta_q, delta_item)struct delta_q { struct delta_item *tqh_first; struct delta_item
**tqh_last; }
;
52
53struct notification_xml {
54 XML_Parser parser;
55 struct rrdp_session *repository;
56 struct rrdp_session *current;
57 const char *notifyuri;
58 char *session_id;
59 char *snapshot_uri;
60 char snapshot_hash[SHA256_DIGEST_LENGTH32];
61 struct delta_q delta_q;
62 long long serial;
63 long long min_serial;
64 int version;
65 enum notification_scope scope;
66};
67
68static void free_delta(struct delta_item *);
69
70static int
71add_delta(struct notification_xml *nxml, const char *uri,
72 const char hash[SHA256_DIGEST_LENGTH32], long long serial)
73{
74 struct delta_item *d, *n;
75
76 if ((d = calloc(1, sizeof(struct delta_item))) == NULL((void *)0))
77 err(1, "%s - calloc", __func__);
78
79 d->serial = serial;
80 d->uri = xstrdup(uri);
81 memcpy(d->hash, hash, sizeof(d->hash));
82
83 /* optimise for a sorted input */
84 n = TAILQ_LAST(&nxml->delta_q, delta_q)(*(((struct delta_q *)((&nxml->delta_q)->tqh_last))
->tqh_last))
;
85 if (n == NULL((void *)0))
86 TAILQ_INSERT_HEAD(&nxml->delta_q, d, q)do { if (((d)->q.tqe_next = (&nxml->delta_q)->tqh_first
) != ((void *)0)) (&nxml->delta_q)->tqh_first->q
.tqe_prev = &(d)->q.tqe_next; else (&nxml->delta_q
)->tqh_last = &(d)->q.tqe_next; (&nxml->delta_q
)->tqh_first = (d); (d)->q.tqe_prev = &(&nxml->
delta_q)->tqh_first; } while (0)
;
87 else if (n->serial < serial)
88 TAILQ_INSERT_TAIL(&nxml->delta_q, d, q)do { (d)->q.tqe_next = ((void *)0); (d)->q.tqe_prev = (
&nxml->delta_q)->tqh_last; *(&nxml->delta_q)
->tqh_last = (d); (&nxml->delta_q)->tqh_last = &
(d)->q.tqe_next; } while (0)
;
89 else
90 TAILQ_FOREACH(n, &nxml->delta_q, q)for((n) = ((&nxml->delta_q)->tqh_first); (n) != ((void
*)0); (n) = ((n)->q.tqe_next))
{
91 if (n->serial == serial) {
92 warnx("duplicate delta serial %lld ", serial);
93 free_delta(d);
94 return 0;
95 }
96 if (n->serial > serial) {
97 TAILQ_INSERT_BEFORE(n, d, q)do { (d)->q.tqe_prev = (n)->q.tqe_prev; (d)->q.tqe_next
= (n); *(n)->q.tqe_prev = (d); (n)->q.tqe_prev = &
(d)->q.tqe_next; } while (0)
;
98 break;
99 }
100 }
101
102 return 1;
103}
104
105/* check that there are no holes in the list */
106static int
107check_delta(struct notification_xml *nxml)
108{
109 struct delta_item *d;
110 long long serial = 0;
111
112 TAILQ_FOREACH(d, &nxml->delta_q, q)for((d) = ((&nxml->delta_q)->tqh_first); (d) != ((void
*)0); (d) = ((d)->q.tqe_next))
{
113 if (serial != 0 && serial + 1 != d->serial)
114 return 0;
115 serial = d->serial;
116 }
117 return 1;
118}
119
120static void
121free_delta(struct delta_item *d)
122{
123 free(d->uri);
124 free(d);
125}
126
127/*
128 * Parse a delta serial and hash line at idx from the rrdp session state.
129 * Return the serial or 0 on error. If hash is non-NULL, it is set to the
130 * start of the hash string on success.
131 */
132static long long
133delta_parse(struct rrdp_session *s, size_t idx, char **hash)
134{
135 long long serial;
136 char *line, *ep;
137
138 if (hash
6.1
'hash' is not equal to NULL
!= NULL((void *)0))
7
Taking true branch
139 *hash = NULL((void *)0);
8
Null pointer value stored to 'exp_hash'
140 if (idx
8.1
'idx' is >= 0
< 0 || idx >= sizeof(s->deltas) / sizeof(s->deltas[0]))
9
Taking false branch
141 return 0;
142 if ((line = s->deltas[idx]) == NULL((void *)0))
10
Assuming the condition is true
11
Taking true branch
143 return 0;
144
145 errno(*__errno()) = 0;
146 serial = strtoll(line, &ep, 10);
147 if (line[0] == '\0' || *ep != ' ')
148 return 0;
149 if (serial <= 0 || (errno(*__errno()) == ERANGE34 && serial == LLONG_MAX0x7fffffffffffffffLL))
150 return 0;
151
152 if (hash != NULL((void *)0))
153 *hash = ep + 1;
154 return serial;
155}
156
157static void
158start_notification_elem(struct notification_xml *nxml, const char **attr)
159{
160 XML_Parser p = nxml->parser;
161 int has_xmlns = 0;
162 size_t i;
163
164 if (nxml->scope != NOTIFICATION_SCOPE_START)
165 PARSE_FAIL(p,do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - entered notification elem unexpectedely"
); return; } while (0)
166 "parse failed - entered notification elem unexpectedely")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - entered notification elem unexpectedely"
); return; } while (0)
;
167 for (i = 0; attr[i]; i += 2) {
168 const char *errstr;
169 if (strcmp("xmlns", attr[i]) == 0 &&
170 strcmp(RRDP_XMLNS"http://www.ripe.net/rpki/rrdp", attr[i + 1]) == 0) {
171 has_xmlns = 1;
172 continue;
173 }
174 if (strcmp("session_id", attr[i]) == 0 &&
175 valid_uuid(attr[i + 1])) {
176 nxml->session_id = xstrdup(attr[i + 1]);
177 continue;
178 }
179 if (strcmp("version", attr[i]) == 0) {
180 nxml->version = strtonum(attr[i + 1],
181 1, MAX_VERSION1, &errstr);
182 if (errstr == NULL((void *)0))
183 continue;
184 }
185 if (strcmp("serial", attr[i]) == 0) {
186 nxml->serial = strtonum(attr[i + 1],
187 1, LLONG_MAX0x7fffffffffffffffLL, &errstr);
188 if (errstr == NULL((void *)0))
189 continue;
190 }
191 PARSE_FAIL(p, "parse failed - non conforming "do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - non conforming "
"attribute '%s' found in notification elem", attr[i]); return
; } while (0)
192 "attribute '%s' found in notification elem", attr[i])do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - non conforming "
"attribute '%s' found in notification elem", attr[i]); return
; } while (0)
;
193 }
194 if (!(has_xmlns && nxml->version && nxml->session_id && nxml->serial))
195 PARSE_FAIL(p, "parse failed - incomplete "do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - incomplete "
"notification attributes"); return; } while (0)
196 "notification attributes")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - incomplete "
"notification attributes"); return; } while (0)
;
197
198 /* Limit deltas to the ones which matter for us. */
199 if (nxml->min_serial == 0 && nxml->serial > MAX_RRDP_DELTAS300)
200 nxml->min_serial = nxml->serial - MAX_RRDP_DELTAS300;
201
202 nxml->scope = NOTIFICATION_SCOPE_NOTIFICATION;
203}
204
205static void
206end_notification_elem(struct notification_xml *nxml)
207{
208 XML_Parser p = nxml->parser;
209
210 if (nxml->scope != NOTIFICATION_SCOPE_NOTIFICATION_POST_SNAPSHOT)
211 PARSE_FAIL(p, "parse failed - exited notification "do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - exited notification "
"elem unexpectedely"); return; } while (0)
212 "elem unexpectedely")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - exited notification "
"elem unexpectedely"); return; } while (0)
;
213 nxml->scope = NOTIFICATION_SCOPE_END;
214
215 if (!check_delta(nxml))
216 PARSE_FAIL(p, "parse failed - delta list has holes")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - delta list has holes"
); return; } while (0)
;
217}
218
219static void
220start_snapshot_elem(struct notification_xml *nxml, const char **attr)
221{
222 XML_Parser p = nxml->parser;
223 int i, hasUri = 0, hasHash = 0;
224
225 if (nxml->scope != NOTIFICATION_SCOPE_NOTIFICATION)
226 PARSE_FAIL(p,do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - entered snapshot elem unexpectedely"
); return; } while (0)
227 "parse failed - entered snapshot elem unexpectedely")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - entered snapshot elem unexpectedely"
); return; } while (0)
;
228 for (i = 0; attr[i]; i += 2) {
229 if (strcmp("uri", attr[i]) == 0 && hasUri++ == 0) {
230 if (valid_uri(attr[i + 1], strlen(attr[i + 1]),
231 "https://") &&
232 valid_origin(attr[i + 1], nxml->notifyuri)) {
233 nxml->snapshot_uri = xstrdup(attr[i + 1]);
234 continue;
235 }
236 }
237 if (strcmp("hash", attr[i]) == 0 && hasHash++ == 0) {
238 if (hex_decode(attr[i + 1], nxml->snapshot_hash,
239 sizeof(nxml->snapshot_hash)) == 0)
240 continue;
241 }
242 PARSE_FAIL(p, "parse failed - non conforming "do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - non conforming "
"attribute '%s' found in snapshot elem", attr[i]); return; }
while (0)
243 "attribute '%s' found in snapshot elem", attr[i])do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - non conforming "
"attribute '%s' found in snapshot elem", attr[i]); return; }
while (0)
;
244 }
245 if (hasUri != 1 || hasHash != 1)
246 PARSE_FAIL(p, "parse failed - incomplete snapshot attributes")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - incomplete snapshot attributes"
); return; } while (0)
;
247
248 nxml->scope = NOTIFICATION_SCOPE_SNAPSHOT;
249}
250
251static void
252end_snapshot_elem(struct notification_xml *nxml)
253{
254 XML_Parser p = nxml->parser;
255
256 if (nxml->scope != NOTIFICATION_SCOPE_SNAPSHOT)
257 PARSE_FAIL(p, "parse failed - exited snapshot "do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - exited snapshot "
"elem unexpectedely"); return; } while (0)
258 "elem unexpectedely")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - exited snapshot "
"elem unexpectedely"); return; } while (0)
;
259 nxml->scope = NOTIFICATION_SCOPE_NOTIFICATION_POST_SNAPSHOT;
260}
261
262static void
263start_delta_elem(struct notification_xml *nxml, const char **attr)
264{
265 XML_Parser p = nxml->parser;
266 int i, hasUri = 0, hasHash = 0;
267 const char *delta_uri = NULL((void *)0);
268 char delta_hash[SHA256_DIGEST_LENGTH32];
269 long long delta_serial = 0;
270
271 if (nxml->scope != NOTIFICATION_SCOPE_NOTIFICATION_POST_SNAPSHOT)
272 PARSE_FAIL(p, "parse failed - entered delta "do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - entered delta "
"elem unexpectedely"); return; } while (0)
273 "elem unexpectedely")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - entered delta "
"elem unexpectedely"); return; } while (0)
;
274 for (i = 0; attr[i]; i += 2) {
275 if (strcmp("uri", attr[i]) == 0 && hasUri++ == 0) {
276 if (valid_uri(attr[i + 1], strlen(attr[i + 1]),
277 "https://") &&
278 valid_origin(attr[i + 1], nxml->notifyuri)) {
279 delta_uri = attr[i + 1];
280 continue;
281 }
282 }
283 if (strcmp("hash", attr[i]) == 0 && hasHash++ == 0) {
284 if (hex_decode(attr[i + 1], delta_hash,
285 sizeof(delta_hash)) == 0)
286 continue;
287 }
288 if (strcmp("serial", attr[i]) == 0 && delta_serial == 0) {
289 const char *errstr;
290
291 delta_serial = strtonum(attr[i + 1],
292 1, LLONG_MAX0x7fffffffffffffffLL, &errstr);
293 if (errstr == NULL((void *)0))
294 continue;
295 }
296 PARSE_FAIL(p, "parse failed - non conforming "do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - non conforming "
"attribute '%s' found in snapshot elem", attr[i]); return; }
while (0)
297 "attribute '%s' found in snapshot elem", attr[i])do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - non conforming "
"attribute '%s' found in snapshot elem", attr[i]); return; }
while (0)
;
298 }
299 /* Only add to the list if we are relevant */
300 if (hasUri != 1 || hasHash != 1 || delta_serial == 0)
301 PARSE_FAIL(p, "parse failed - incomplete delta attributes")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - incomplete delta attributes"
); return; } while (0)
;
302
303 /* Delta serial must be smaller or equal to the notification serial */
304 if (nxml->serial < delta_serial)
305 PARSE_FAIL(p, "parse failed - bad delta serial")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - bad delta serial"
); return; } while (0)
;
306
307 /* optimisation, add only deltas that could be interesting */
308 if (nxml->min_serial < delta_serial) {
309 if (add_delta(nxml, delta_uri, delta_hash, delta_serial) == 0)
310 PARSE_FAIL(p, "parse failed - adding delta failed")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - adding delta failed"
); return; } while (0)
;
311 }
312
313 nxml->scope = NOTIFICATION_SCOPE_DELTA;
314}
315
316static void
317end_delta_elem(struct notification_xml *nxml)
318{
319 XML_Parser p = nxml->parser;
320
321 if (nxml->scope != NOTIFICATION_SCOPE_DELTA)
322 PARSE_FAIL(p, "parse failed - exited delta elem unexpectedely")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - exited delta elem unexpectedely"
); return; } while (0)
;
323 nxml->scope = NOTIFICATION_SCOPE_NOTIFICATION_POST_SNAPSHOT;
324}
325
326static void
327notification_xml_elem_start(void *data, const char *el, const char **attr)
328{
329 struct notification_xml *nxml = data;
330 XML_Parser p = nxml->parser;
331
332 /*
333 * Can only enter here once as we should have no ways to get back to
334 * START scope
335 */
336 if (strcmp("notification", el) == 0)
337 start_notification_elem(nxml, attr);
338 /*
339 * Will enter here multiple times, BUT never nested. will start
340 * collecting character data in that handler
341 * mem is cleared in end block, (TODO or on parse failure)
342 */
343 else if (strcmp("snapshot", el) == 0)
344 start_snapshot_elem(nxml, attr);
345 else if (strcmp("delta", el) == 0)
346 start_delta_elem(nxml, attr);
347 else
348 PARSE_FAIL(p, "parse failed - unexpected elem exit found")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - unexpected elem exit found"
); return; } while (0)
;
349}
350
351static void
352notification_xml_elem_end(void *data, const char *el)
353{
354 struct notification_xml *nxml = data;
355 XML_Parser p = nxml->parser;
356
357 if (strcmp("notification", el) == 0)
358 end_notification_elem(nxml);
359 else if (strcmp("snapshot", el) == 0)
360 end_snapshot_elem(nxml);
361 else if (strcmp("delta", el) == 0)
362 end_delta_elem(nxml);
363 else
364 PARSE_FAIL(p, "parse failed - unexpected elem exit found")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - unexpected elem exit found"
); return; } while (0)
;
365}
366
367static void
368notification_doctype_handler(void *data, const char *doctypeName,
369 const char *sysid, const char *pubid, int subset)
370{
371 struct notification_xml *nxml = data;
372 XML_Parser p = nxml->parser;
373
374 PARSE_FAIL(p, "parse failed - DOCTYPE not allowed")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - DOCTYPE not allowed"
); return; } while (0)
;
375}
376
377struct notification_xml *
378new_notification_xml(XML_Parser p, struct rrdp_session *repository,
379 struct rrdp_session *current, const char *notifyuri)
380{
381 struct notification_xml *nxml;
382
383 if ((nxml = calloc(1, sizeof(*nxml))) == NULL((void *)0))
384 err(1, "%s", __func__);
385 TAILQ_INIT(&(nxml->delta_q))do { (&(nxml->delta_q))->tqh_first = ((void *)0); (
&(nxml->delta_q))->tqh_last = &(&(nxml->
delta_q))->tqh_first; } while (0)
;
386 nxml->parser = p;
387 nxml->repository = repository;
388 nxml->current = current;
389 nxml->notifyuri = notifyuri;
390 nxml->min_serial = delta_parse(repository, 0, NULL((void *)0));
391
392 XML_SetElementHandler(nxml->parser, notification_xml_elem_start,
393 notification_xml_elem_end);
394 XML_SetUserData(nxml->parser, nxml);
395 XML_SetDoctypeDeclHandler(nxml->parser, notification_doctype_handler,
396 NULL((void *)0));
397
398 return nxml;
399}
400
401static void
402free_delta_queue(struct notification_xml *nxml)
403{
404 while (!TAILQ_EMPTY(&nxml->delta_q)(((&nxml->delta_q)->tqh_first) == ((void *)0))) {
405 struct delta_item *d = TAILQ_FIRST(&nxml->delta_q)((&nxml->delta_q)->tqh_first);
406 TAILQ_REMOVE(&nxml->delta_q, d, q)do { if (((d)->q.tqe_next) != ((void *)0)) (d)->q.tqe_next
->q.tqe_prev = (d)->q.tqe_prev; else (&nxml->delta_q
)->tqh_last = (d)->q.tqe_prev; *(d)->q.tqe_prev = (d
)->q.tqe_next; ; ; } while (0)
;
407 free_delta(d);
408 }
409}
410
411void
412free_notification_xml(struct notification_xml *nxml)
413{
414 if (nxml == NULL((void *)0))
415 return;
416
417 free(nxml->session_id);
418 free(nxml->snapshot_uri);
419 free_delta_queue(nxml);
420 free(nxml);
421}
422
423/*
424 * Collect a list of deltas to store in the repository state.
425 */
426static void
427notification_collect_deltas(struct notification_xml *nxml)
428{
429 struct delta_item *d;
430 long long keep_serial = 0;
431 size_t cur_idx = 0, max_deltas;
432 char *hash;
433
434 max_deltas =
435 sizeof(nxml->current->deltas) / sizeof(nxml->current->deltas[0]);
436
437 if (nxml->serial > (long long)max_deltas)
438 keep_serial = nxml->serial - max_deltas + 1;
439
440 TAILQ_FOREACH(d, &nxml->delta_q, q)for((d) = ((&nxml->delta_q)->tqh_first); (d) != ((void
*)0); (d) = ((d)->q.tqe_next))
{
441 if (d->serial >= keep_serial) {
442 assert(cur_idx < max_deltas)((cur_idx < max_deltas) ? (void)0 : __assert2("/usr/src/usr.sbin/rpki-client/rrdp_notification.c"
, 442, __func__, "cur_idx < max_deltas"))
;
443 hash = hex_encode(d->hash, sizeof(d->hash));
444 if (asprintf(&nxml->current->deltas[cur_idx++],
445 "%lld %s", d->serial, hash) == -1)
446 err(1, NULL((void *)0));
447 free(hash);
448 }
449 }
450}
451
452/*
453 * Validate the delta list with the information from the repository state.
454 * Remove all obsolete deltas so that the list starts with the delta with
455 * serial nxml->repository->serial + 1.
456 * Returns 1 if all deltas were valid and 0 on failure.
457 */
458static int
459notification_check_deltas(struct notification_xml *nxml)
460{
461 struct delta_item *d, *nextd;
462 char *hash, *exp_hash;
463 long long exp_serial, new_serial;
464 size_t exp_idx = 0;
465
466 exp_serial = delta_parse(nxml->repository, exp_idx++, &exp_hash);
6
Calling 'delta_parse'
12
Returning from 'delta_parse'
467 new_serial = nxml->repository->serial + 1;
468
469 /* compare hash of delta against repository state info */
470 TAILQ_FOREACH_SAFE(d, &nxml->delta_q, q, nextd)for ((d) = ((&nxml->delta_q)->tqh_first); (d) != ((
void *)0) && ((nextd) = ((d)->q.tqe_next), 1); (d)
= (nextd))
{
471 while (exp_serial
12.2
'exp_serial' is equal to 0
!= 0 && exp_serial < d->serial) {
472 exp_serial = delta_parse(nxml->repository,
473 exp_idx++, &exp_hash);
474 }
475
476 if (d->serial == exp_serial) {
13
Assuming 'exp_serial' is equal to field 'serial'
14
Taking true branch
477 hash = hex_encode(d->hash, sizeof(d->hash));
478 if (strcmp(hash, exp_hash) != 0) {
15
Null pointer passed as 2nd argument to string comparison function
479 warnx("%s: %s#%lld unexpected delta "
480 "mutation (expected %s, got %s)",
481 nxml->notifyuri, nxml->session_id,
482 exp_serial, hash, exp_hash);
483 free(hash);
484 return 0;
485 }
486 free(hash);
487 exp_serial = delta_parse(nxml->repository,
488 exp_idx++, &exp_hash);
489 }
490
491 /* is this delta needed? */
492 if (d->serial < new_serial) {
493 TAILQ_REMOVE(&nxml->delta_q, d, q)do { if (((d)->q.tqe_next) != ((void *)0)) (d)->q.tqe_next
->q.tqe_prev = (d)->q.tqe_prev; else (&nxml->delta_q
)->tqh_last = (d)->q.tqe_prev; *(d)->q.tqe_prev = (d
)->q.tqe_next; ; ; } while (0)
;
494 free_delta(d);
495 }
496 }
497
498 return 1;
499}
500
501/*
502 * Finalize notification step, decide if a delta update is possible
503 * if either the session_id changed or the delta files fail to cover
504 * all the steps up to the new serial fall back to a snapshot.
505 * Return SNAPSHOT or DELTA for snapshot or delta processing.
506 * Return NOTIFICATION if repository is up to date.
507 */
508enum rrdp_task
509notification_done(struct notification_xml *nxml, char *last_mod)
510{
511 nxml->current->last_mod = last_mod;
512 nxml->current->session_id = xstrdup(nxml->session_id);
513 notification_collect_deltas(nxml);
514
515 /* check the that the session_id was valid and still the same */
516 if (nxml->repository->session_id == NULL((void *)0) ||
1
Assuming field 'session_id' is not equal to NULL
2
Taking false branch
517 strcmp(nxml->session_id, nxml->repository->session_id) != 0)
518 goto snapshot;
519
520 /* if repository serial is 0 fall back to snapshot */
521 if (nxml->repository->serial == 0)
3
Assuming field 'serial' is not equal to 0
4
Taking false branch
522 goto snapshot;
523
524 /* check that all needed deltas are available and valid */
525 if (!notification_check_deltas(nxml))
5
Calling 'notification_check_deltas'
526 goto snapshot;
527
528 if (nxml->repository->serial > nxml->serial)
529 warnx("%s: serial number decreased from %lld to %lld",
530 nxml->notifyuri, nxml->repository->serial, nxml->serial);
531
532 /* if our serial is equal or plus 2, the repo is up to date */
533 if (nxml->repository->serial >= nxml->serial &&
534 nxml->repository->serial - nxml->serial <= 2) {
535 nxml->current->serial = nxml->repository->serial;
536 return NOTIFICATION;
537 }
538
539 /* it makes no sense to process too many deltas */
540 if (nxml->serial - nxml->repository->serial > MAX_RRDP_DELTAS300)
541 goto snapshot;
542
543 /* no deltas queued */
544 if (TAILQ_EMPTY(&nxml->delta_q)(((&nxml->delta_q)->tqh_first) == ((void *)0)))
545 goto snapshot;
546
547 /* first possible delta is no match */
548 if (nxml->repository->serial + 1 != TAILQ_FIRST(&nxml->delta_q)((&nxml->delta_q)->tqh_first)->serial)
549 goto snapshot;
550
551 /* update via delta possible */
552 nxml->current->serial = nxml->repository->serial;
553 nxml->repository->serial = nxml->serial;
554 return DELTA;
555
556snapshot:
557 /* update via snapshot download */
558 free_delta_queue(nxml);
559 nxml->current->serial = nxml->serial;
560 return SNAPSHOT;
561}
562
563const char *
564notification_get_next(struct notification_xml *nxml, char *hash, size_t hlen,
565 enum rrdp_task task)
566{
567 struct delta_item *d;
568
569 switch (task) {
570 case SNAPSHOT:
571 assert(hlen == sizeof(nxml->snapshot_hash))((hlen == sizeof(nxml->snapshot_hash)) ? (void)0 : __assert2
("/usr/src/usr.sbin/rpki-client/rrdp_notification.c", 571, __func__
, "hlen == sizeof(nxml->snapshot_hash)"))
;
572 memcpy(hash, nxml->snapshot_hash, hlen);
573 /*
574 * Ensure that the serial is correct in case a previous
575 * delta request failed.
576 */
577 nxml->current->serial = nxml->serial;
578 return nxml->snapshot_uri;
579 case DELTA:
580 /* first bump serial, then use first delta */
581 nxml->current->serial += 1;
582 d = TAILQ_FIRST(&nxml->delta_q)((&nxml->delta_q)->tqh_first);
583 assert(d->serial == nxml->current->serial)((d->serial == nxml->current->serial) ? (void)0 : __assert2
("/usr/src/usr.sbin/rpki-client/rrdp_notification.c", 583, __func__
, "d->serial == nxml->current->serial"))
;
584 assert(hlen == sizeof(d->hash))((hlen == sizeof(d->hash)) ? (void)0 : __assert2("/usr/src/usr.sbin/rpki-client/rrdp_notification.c"
, 584, __func__, "hlen == sizeof(d->hash)"))
;
585 memcpy(hash, d->hash, hlen);
586 return d->uri;
587 default:
588 errx(1, "%s: bad task", __func__);
589 }
590}
591
592/*
593 * Pop first element from the delta queue. Return non-0 if this was the last
594 * delta to fetch.
595 */
596int
597notification_delta_done(struct notification_xml *nxml)
598{
599 struct delta_item *d;
600
601 d = TAILQ_FIRST(&nxml->delta_q)((&nxml->delta_q)->tqh_first);
602 assert(d->serial == nxml->current->serial)((d->serial == nxml->current->serial) ? (void)0 : __assert2
("/usr/src/usr.sbin/rpki-client/rrdp_notification.c", 602, __func__
, "d->serial == nxml->current->serial"))
;
603 TAILQ_REMOVE(&nxml->delta_q, d, q)do { if (((d)->q.tqe_next) != ((void *)0)) (d)->q.tqe_next
->q.tqe_prev = (d)->q.tqe_prev; else (&nxml->delta_q
)->tqh_last = (d)->q.tqe_prev; *(d)->q.tqe_prev = (d
)->q.tqe_next; ; ; } while (0)
;
604 free_delta(d);
605
606 assert(!TAILQ_EMPTY(&nxml->delta_q) ||((!(((&nxml->delta_q)->tqh_first) == ((void *)0)) ||
nxml->serial == nxml->current->serial) ? (void)0 : __assert2
("/usr/src/usr.sbin/rpki-client/rrdp_notification.c", 607, __func__
, "!TAILQ_EMPTY(&nxml->delta_q) || nxml->serial == nxml->current->serial"
))
607 nxml->serial == nxml->current->serial)((!(((&nxml->delta_q)->tqh_first) == ((void *)0)) ||
nxml->serial == nxml->current->serial) ? (void)0 : __assert2
("/usr/src/usr.sbin/rpki-client/rrdp_notification.c", 607, __func__
, "!TAILQ_EMPTY(&nxml->delta_q) || nxml->serial == nxml->current->serial"
))
;
608 return TAILQ_EMPTY(&nxml->delta_q)(((&nxml->delta_q)->tqh_first) == ((void *)0));
609}
610
611/* Used in regress. */
612void
613log_notification_xml(struct notification_xml *nxml)
614{
615 struct delta_item *d;
616 char *hash;
617
618 logx("session_id: %s, serial: %lld", nxml->session_id, nxml->serial);
619 logx("snapshot_uri: %s", nxml->snapshot_uri);
620 hash = hex_encode(nxml->snapshot_hash, sizeof(nxml->snapshot_hash));
621 logx("snapshot hash: %s", hash);
622 free(hash);
623
624 TAILQ_FOREACH(d, &nxml->delta_q, q)for((d) = ((&nxml->delta_q)->tqh_first); (d) != ((void
*)0); (d) = ((d)->q.tqe_next))
{
625 logx("delta serial %lld uri: %s", d->serial, d->uri);
626 hash = hex_encode(d->hash, sizeof(d->hash));
627 logx("delta hash: %s", hash);
628 free(hash);
629 }
630}