| File: | src/usr.sbin/rpki-client/rrdp_notification.c |
| Warning: | line 101, column 9 Potential leak of memory pointed to by 'd' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: rrdp_notification.c,v 1.12 2021/11/24 15:24:16 claudio 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 | |||||
| 35 | enum 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 | |||||
| 44 | struct 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 | |||||
| 51 | TAILQ_HEAD(delta_q, delta_item)struct delta_q { struct delta_item *tqh_first; struct delta_item **tqh_last; }; | ||||
| 52 | |||||
| 53 | struct 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 | int version; | ||||
| 64 | enum notification_scope scope; | ||||
| 65 | }; | ||||
| 66 | |||||
| 67 | static void free_delta(struct delta_item *); | ||||
| 68 | |||||
| 69 | static int | ||||
| 70 | add_delta(struct notification_xml *nxml, const char *uri, | ||||
| 71 | const char hash[SHA256_DIGEST_LENGTH32], long long serial) | ||||
| 72 | { | ||||
| 73 | struct delta_item *d, *n; | ||||
| 74 | |||||
| 75 | if ((d = calloc(1, sizeof(struct delta_item))) == NULL((void*)0)) | ||||
| 76 | err(1, "%s - calloc", __func__); | ||||
| 77 | |||||
| 78 | d->serial = serial; | ||||
| 79 | d->uri = xstrdup(uri); | ||||
| 80 | memcpy(d->hash, hash, sizeof(d->hash)); | ||||
| 81 | |||||
| 82 | /* optimise for a sorted input */ | ||||
| 83 | n = TAILQ_LAST(&nxml->delta_q, delta_q)(*(((struct delta_q *)((&nxml->delta_q)->tqh_last)) ->tqh_last)); | ||||
| 84 | if (n == NULL((void*)0)) | ||||
| 85 | 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); | ||||
| 86 | else if (n->serial < serial) | ||||
| 87 | 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); | ||||
| 88 | else | ||||
| 89 | TAILQ_FOREACH(n, &nxml->delta_q, q)for((n) = ((&nxml->delta_q)->tqh_first); (n) != ((void *)0); (n) = ((n)->q.tqe_next)) { | ||||
| 90 | if (n->serial == serial) { | ||||
| 91 | warnx("duplicate delta serial %lld ", serial); | ||||
| 92 | free_delta(d); | ||||
| 93 | return 0; | ||||
| 94 | } | ||||
| 95 | if (n->serial > serial) { | ||||
| 96 | 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); | ||||
| 97 | break; | ||||
| 98 | } | ||||
| 99 | } | ||||
| 100 | |||||
| 101 | return 1; | ||||
| |||||
| 102 | } | ||||
| 103 | |||||
| 104 | static void | ||||
| 105 | free_delta(struct delta_item *d) | ||||
| 106 | { | ||||
| 107 | free(d->uri); | ||||
| 108 | free(d); | ||||
| 109 | } | ||||
| 110 | |||||
| 111 | static void | ||||
| 112 | start_notification_elem(struct notification_xml *nxml, const char **attr) | ||||
| 113 | { | ||||
| 114 | XML_Parser p = nxml->parser; | ||||
| 115 | int has_xmlns = 0; | ||||
| 116 | size_t i; | ||||
| 117 | |||||
| 118 | if (nxml->scope != NOTIFICATION_SCOPE_START) | ||||
| 119 | PARSE_FAIL(p,do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - entered notification elem unexpectedely" ); return; } while (0) | ||||
| 120 | "parse failed - entered notification elem unexpectedely")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - entered notification elem unexpectedely" ); return; } while (0); | ||||
| 121 | for (i = 0; attr[i]; i += 2) { | ||||
| 122 | const char *errstr; | ||||
| 123 | if (strcmp("xmlns", attr[i]) == 0) { | ||||
| 124 | has_xmlns = 1; | ||||
| 125 | continue; | ||||
| 126 | } | ||||
| 127 | if (strcmp("session_id", attr[i]) == 0) { | ||||
| 128 | nxml->session_id = xstrdup(attr[i + 1]); | ||||
| 129 | continue; | ||||
| 130 | } | ||||
| 131 | if (strcmp("version", attr[i]) == 0) { | ||||
| 132 | nxml->version = strtonum(attr[i + 1], | ||||
| 133 | 1, MAX_VERSION1, &errstr); | ||||
| 134 | if (errstr == NULL((void*)0)) | ||||
| 135 | continue; | ||||
| 136 | } | ||||
| 137 | if (strcmp("serial", attr[i]) == 0) { | ||||
| 138 | nxml->serial = strtonum(attr[i + 1], | ||||
| 139 | 1, LLONG_MAX9223372036854775807LL, &errstr); | ||||
| 140 | if (errstr == NULL((void*)0)) | ||||
| 141 | continue; | ||||
| 142 | } | ||||
| 143 | 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) | ||||
| 144 | "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); | ||||
| 145 | } | ||||
| 146 | if (!(has_xmlns && nxml->version && nxml->session_id && nxml->serial)) | ||||
| 147 | PARSE_FAIL(p, "parse failed - incomplete "do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - incomplete " "notification attributes"); return; } while (0) | ||||
| 148 | "notification attributes")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - incomplete " "notification attributes"); return; } while (0); | ||||
| 149 | |||||
| 150 | nxml->scope = NOTIFICATION_SCOPE_NOTIFICATION; | ||||
| 151 | } | ||||
| 152 | |||||
| 153 | static void | ||||
| 154 | end_notification_elem(struct notification_xml *nxml) | ||||
| 155 | { | ||||
| 156 | XML_Parser p = nxml->parser; | ||||
| 157 | |||||
| 158 | if (nxml->scope != NOTIFICATION_SCOPE_NOTIFICATION_POST_SNAPSHOT) | ||||
| 159 | PARSE_FAIL(p, "parse failed - exited notification "do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - exited notification " "elem unexpectedely"); return; } while (0) | ||||
| 160 | "elem unexpectedely")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - exited notification " "elem unexpectedely"); return; } while (0); | ||||
| 161 | nxml->scope = NOTIFICATION_SCOPE_END; | ||||
| 162 | } | ||||
| 163 | |||||
| 164 | static void | ||||
| 165 | start_snapshot_elem(struct notification_xml *nxml, const char **attr) | ||||
| 166 | { | ||||
| 167 | XML_Parser p = nxml->parser; | ||||
| 168 | int i, hasUri = 0, hasHash = 0; | ||||
| 169 | |||||
| 170 | if (nxml->scope != NOTIFICATION_SCOPE_NOTIFICATION) | ||||
| 171 | PARSE_FAIL(p,do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - entered snapshot elem unexpectedely" ); return; } while (0) | ||||
| 172 | "parse failed - entered snapshot elem unexpectedely")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - entered snapshot elem unexpectedely" ); return; } while (0); | ||||
| 173 | for (i = 0; attr[i]; i += 2) { | ||||
| 174 | if (strcmp("uri", attr[i]) == 0 && hasUri++ == 0) { | ||||
| 175 | if (valid_uri(attr[i + 1], strlen(attr[i + 1]), | ||||
| 176 | "https://") && | ||||
| 177 | valid_origin(attr[i + 1], nxml->notifyuri)) { | ||||
| 178 | nxml->snapshot_uri = xstrdup(attr[i + 1]); | ||||
| 179 | continue; | ||||
| 180 | } | ||||
| 181 | } | ||||
| 182 | if (strcmp("hash", attr[i]) == 0 && hasHash++ == 0) { | ||||
| 183 | if (hex_decode(attr[i + 1], nxml->snapshot_hash, | ||||
| 184 | sizeof(nxml->snapshot_hash)) == 0) | ||||
| 185 | continue; | ||||
| 186 | } | ||||
| 187 | 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) | ||||
| 188 | "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); | ||||
| 189 | } | ||||
| 190 | if (hasUri != 1 || hasHash != 1) | ||||
| 191 | PARSE_FAIL(p, "parse failed - incomplete snapshot attributes")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - incomplete snapshot attributes" ); return; } while (0); | ||||
| 192 | |||||
| 193 | nxml->scope = NOTIFICATION_SCOPE_SNAPSHOT; | ||||
| 194 | } | ||||
| 195 | |||||
| 196 | static void | ||||
| 197 | end_snapshot_elem(struct notification_xml *nxml) | ||||
| 198 | { | ||||
| 199 | XML_Parser p = nxml->parser; | ||||
| 200 | |||||
| 201 | if (nxml->scope != NOTIFICATION_SCOPE_SNAPSHOT) | ||||
| 202 | PARSE_FAIL(p, "parse failed - exited snapshot "do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - exited snapshot " "elem unexpectedely"); return; } while (0) | ||||
| 203 | "elem unexpectedely")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - exited snapshot " "elem unexpectedely"); return; } while (0); | ||||
| 204 | nxml->scope = NOTIFICATION_SCOPE_NOTIFICATION_POST_SNAPSHOT; | ||||
| 205 | } | ||||
| 206 | |||||
| 207 | static void | ||||
| 208 | start_delta_elem(struct notification_xml *nxml, const char **attr) | ||||
| 209 | { | ||||
| 210 | XML_Parser p = nxml->parser; | ||||
| 211 | int i, hasUri = 0, hasHash = 0; | ||||
| 212 | const char *delta_uri = NULL((void*)0); | ||||
| 213 | char delta_hash[SHA256_DIGEST_LENGTH32]; | ||||
| 214 | long long delta_serial = 0; | ||||
| 215 | |||||
| 216 | if (nxml->scope != NOTIFICATION_SCOPE_NOTIFICATION_POST_SNAPSHOT) | ||||
| 217 | PARSE_FAIL(p, "parse failed - entered delta "do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - entered delta " "elem unexpectedely"); return; } while (0) | ||||
| 218 | "elem unexpectedely")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - entered delta " "elem unexpectedely"); return; } while (0); | ||||
| 219 | for (i = 0; attr[i]; i += 2) { | ||||
| 220 | if (strcmp("uri", attr[i]) == 0 && hasUri++ == 0) { | ||||
| 221 | if (valid_uri(attr[i + 1], strlen(attr[i + 1]), | ||||
| 222 | "https://") && | ||||
| 223 | valid_origin(attr[i + 1], nxml->notifyuri)) { | ||||
| 224 | delta_uri = attr[i + 1]; | ||||
| 225 | continue; | ||||
| 226 | } | ||||
| 227 | } | ||||
| 228 | if (strcmp("hash", attr[i]) == 0 && hasHash++ == 0) { | ||||
| 229 | if (hex_decode(attr[i + 1], delta_hash, | ||||
| 230 | sizeof(delta_hash)) == 0) | ||||
| 231 | continue; | ||||
| 232 | } | ||||
| 233 | if (strcmp("serial", attr[i]) == 0 && delta_serial
| ||||
| 234 | const char *errstr; | ||||
| 235 | |||||
| 236 | delta_serial = strtonum(attr[i + 1], | ||||
| 237 | 1, LLONG_MAX9223372036854775807LL, &errstr); | ||||
| 238 | if (errstr == NULL((void*)0)) | ||||
| 239 | continue; | ||||
| 240 | } | ||||
| 241 | 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) | ||||
| 242 | "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); | ||||
| 243 | } | ||||
| 244 | /* Only add to the list if we are relevant */ | ||||
| 245 | if (hasUri
| ||||
| 246 | PARSE_FAIL(p, "parse failed - incomplete delta attributes")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - incomplete delta attributes" ); return; } while (0); | ||||
| 247 | |||||
| 248 | /* optimisation, add only deltas that could be interesting */ | ||||
| 249 | if (nxml->repository->serial != 0 && | ||||
| 250 | nxml->repository->serial < delta_serial && | ||||
| 251 | nxml->repository->session_id != NULL((void*)0) && | ||||
| 252 | strcmp(nxml->session_id, nxml->repository->session_id) == 0) { | ||||
| 253 | if (add_delta(nxml, delta_uri, delta_hash, delta_serial) == 0) | ||||
| 254 | PARSE_FAIL(p, "parse failed - adding delta failed")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - adding delta failed" ); return; } while (0); | ||||
| 255 | } | ||||
| 256 | |||||
| 257 | nxml->scope = NOTIFICATION_SCOPE_DELTA; | ||||
| 258 | } | ||||
| 259 | |||||
| 260 | static void | ||||
| 261 | end_delta_elem(struct notification_xml *nxml) | ||||
| 262 | { | ||||
| 263 | XML_Parser p = nxml->parser; | ||||
| 264 | |||||
| 265 | if (nxml->scope != NOTIFICATION_SCOPE_DELTA) | ||||
| 266 | 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); | ||||
| 267 | nxml->scope = NOTIFICATION_SCOPE_NOTIFICATION_POST_SNAPSHOT; | ||||
| 268 | } | ||||
| 269 | |||||
| 270 | static void | ||||
| 271 | notification_xml_elem_start(void *data, const char *el, const char **attr) | ||||
| 272 | { | ||||
| 273 | struct notification_xml *nxml = data; | ||||
| 274 | XML_Parser p = nxml->parser; | ||||
| 275 | |||||
| 276 | /* | ||||
| 277 | * Can only enter here once as we should have no ways to get back to | ||||
| 278 | * START scope | ||||
| 279 | */ | ||||
| 280 | if (strcmp("notification", el) == 0) | ||||
| |||||
| 281 | start_notification_elem(nxml, attr); | ||||
| 282 | /* | ||||
| 283 | * Will enter here multiple times, BUT never nested. will start | ||||
| 284 | * collecting character data in that handler | ||||
| 285 | * mem is cleared in end block, (TODO or on parse failure) | ||||
| 286 | */ | ||||
| 287 | else if (strcmp("snapshot", el) == 0) | ||||
| 288 | start_snapshot_elem(nxml, attr); | ||||
| 289 | else if (strcmp("delta", el) == 0) | ||||
| 290 | start_delta_elem(nxml, attr); | ||||
| 291 | else | ||||
| 292 | 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); | ||||
| 293 | } | ||||
| 294 | |||||
| 295 | static void | ||||
| 296 | notification_xml_elem_end(void *data, const char *el) | ||||
| 297 | { | ||||
| 298 | struct notification_xml *nxml = data; | ||||
| 299 | XML_Parser p = nxml->parser; | ||||
| 300 | |||||
| 301 | if (strcmp("notification", el) == 0) | ||||
| 302 | end_notification_elem(nxml); | ||||
| 303 | else if (strcmp("snapshot", el) == 0) | ||||
| 304 | end_snapshot_elem(nxml); | ||||
| 305 | else if (strcmp("delta", el) == 0) | ||||
| 306 | end_delta_elem(nxml); | ||||
| 307 | else | ||||
| 308 | 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); | ||||
| 309 | } | ||||
| 310 | |||||
| 311 | static void | ||||
| 312 | notification_doctype_handler(void *data, const char *doctypeName, | ||||
| 313 | const char *sysid, const char *pubid, int subset) | ||||
| 314 | { | ||||
| 315 | struct notification_xml *nxml = data; | ||||
| 316 | XML_Parser p = nxml->parser; | ||||
| 317 | |||||
| 318 | PARSE_FAIL(p, "parse failed - DOCTYPE not allowed")do { XML_StopParser(p, ((XML_Bool)0)); warnx("parse failed - DOCTYPE not allowed" ); return; } while (0); | ||||
| 319 | } | ||||
| 320 | |||||
| 321 | struct notification_xml * | ||||
| 322 | new_notification_xml(XML_Parser p, struct rrdp_session *repository, | ||||
| 323 | struct rrdp_session *current, const char *notifyuri) | ||||
| 324 | { | ||||
| 325 | struct notification_xml *nxml; | ||||
| 326 | |||||
| 327 | if ((nxml = calloc(1, sizeof(*nxml))) == NULL((void*)0)) | ||||
| 328 | err(1, "%s", __func__); | ||||
| 329 | 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); | ||||
| 330 | nxml->parser = p; | ||||
| 331 | nxml->repository = repository; | ||||
| 332 | nxml->current = current; | ||||
| 333 | nxml->notifyuri = notifyuri; | ||||
| 334 | |||||
| 335 | XML_SetElementHandler(nxml->parser, notification_xml_elem_start, | ||||
| 336 | notification_xml_elem_end); | ||||
| 337 | XML_SetUserData(nxml->parser, nxml); | ||||
| 338 | XML_SetDoctypeDeclHandler(nxml->parser, notification_doctype_handler, | ||||
| 339 | NULL((void*)0)); | ||||
| 340 | |||||
| 341 | return nxml; | ||||
| 342 | } | ||||
| 343 | |||||
| 344 | void | ||||
| 345 | free_notification_xml(struct notification_xml *nxml) | ||||
| 346 | { | ||||
| 347 | if (nxml == NULL((void*)0)) | ||||
| 348 | return; | ||||
| 349 | |||||
| 350 | free(nxml->session_id); | ||||
| 351 | free(nxml->snapshot_uri); | ||||
| 352 | while (!TAILQ_EMPTY(&nxml->delta_q)(((&nxml->delta_q)->tqh_first) == ((void*)0))) { | ||||
| 353 | struct delta_item *d = TAILQ_FIRST(&nxml->delta_q)((&nxml->delta_q)->tqh_first); | ||||
| 354 | 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); | ||||
| 355 | free_delta(d); | ||||
| 356 | } | ||||
| 357 | free(nxml); | ||||
| 358 | } | ||||
| 359 | |||||
| 360 | /* | ||||
| 361 | * Finalize notification step, decide if a delta update is possible | ||||
| 362 | * if either the session_id changed or the delta files fail to cover | ||||
| 363 | * all the steps up to the new serial fall back to a snapshot. | ||||
| 364 | * Return SNAPSHOT or DELTA for snapshot or delta processing. | ||||
| 365 | * Return NOTIFICATION if repository is up to date. | ||||
| 366 | */ | ||||
| 367 | enum rrdp_task | ||||
| 368 | notification_done(struct notification_xml *nxml, char *last_mod) | ||||
| 369 | { | ||||
| 370 | struct delta_item *d; | ||||
| 371 | long long s, last_s = 0; | ||||
| 372 | |||||
| 373 | nxml->current->last_mod = last_mod; | ||||
| 374 | nxml->current->session_id = xstrdup(nxml->session_id); | ||||
| 375 | |||||
| 376 | /* check the that the session_id was valid and still the same */ | ||||
| 377 | if (nxml->repository->session_id == NULL((void*)0) || | ||||
| 378 | strcmp(nxml->session_id, nxml->repository->session_id) != 0) | ||||
| 379 | goto snapshot; | ||||
| 380 | |||||
| 381 | /* if repository serial is 0 fall back to snapshot */ | ||||
| 382 | if (nxml->repository->serial == 0) | ||||
| 383 | goto snapshot; | ||||
| 384 | |||||
| 385 | /* if our serial is equal or bigger, the repo is up to date */ | ||||
| 386 | if (nxml->repository->serial >= nxml->serial) { | ||||
| 387 | nxml->current->serial = nxml->repository->serial; | ||||
| 388 | return NOTIFICATION; | ||||
| 389 | } | ||||
| 390 | |||||
| 391 | /* it makes no sense to process too many deltas */ | ||||
| 392 | if (nxml->serial - nxml->repository->serial > 300) | ||||
| 393 | goto snapshot; | ||||
| 394 | |||||
| 395 | /* check that all needed deltas are available */ | ||||
| 396 | s = nxml->repository->serial + 1; | ||||
| 397 | TAILQ_FOREACH(d, &nxml->delta_q, q)for((d) = ((&nxml->delta_q)->tqh_first); (d) != ((void *)0); (d) = ((d)->q.tqe_next)) { | ||||
| 398 | if (d->serial != s++) | ||||
| 399 | goto snapshot; | ||||
| 400 | last_s = d->serial; | ||||
| 401 | } | ||||
| 402 | if (last_s != nxml->serial) | ||||
| 403 | goto snapshot; | ||||
| 404 | |||||
| 405 | /* update via delta possible */ | ||||
| 406 | nxml->current->serial = nxml->repository->serial; | ||||
| 407 | nxml->repository->serial = nxml->serial; | ||||
| 408 | return DELTA; | ||||
| 409 | |||||
| 410 | snapshot: | ||||
| 411 | /* update via snapshot download */ | ||||
| 412 | nxml->current->serial = nxml->serial; | ||||
| 413 | return SNAPSHOT; | ||||
| 414 | } | ||||
| 415 | |||||
| 416 | const char * | ||||
| 417 | notification_get_next(struct notification_xml *nxml, char *hash, size_t hlen, | ||||
| 418 | enum rrdp_task task) | ||||
| 419 | { | ||||
| 420 | struct delta_item *d; | ||||
| 421 | |||||
| 422 | switch (task) { | ||||
| 423 | case SNAPSHOT: | ||||
| 424 | assert(hlen == sizeof(nxml->snapshot_hash))((hlen == sizeof(nxml->snapshot_hash)) ? (void)0 : __assert2 ("/usr/src/usr.sbin/rpki-client/rrdp_notification.c", 424, __func__ , "hlen == sizeof(nxml->snapshot_hash)")); | ||||
| 425 | memcpy(hash, nxml->snapshot_hash, hlen); | ||||
| 426 | /* | ||||
| 427 | * Ensure that the serial is correct in case a previous | ||||
| 428 | * delta request failed. | ||||
| 429 | */ | ||||
| 430 | nxml->current->serial = nxml->serial; | ||||
| 431 | return nxml->snapshot_uri; | ||||
| 432 | case DELTA: | ||||
| 433 | /* first bump serial, then use first delta */ | ||||
| 434 | nxml->current->serial += 1; | ||||
| 435 | d = TAILQ_FIRST(&nxml->delta_q)((&nxml->delta_q)->tqh_first); | ||||
| 436 | assert(d->serial == nxml->current->serial)((d->serial == nxml->current->serial) ? (void)0 : __assert2 ("/usr/src/usr.sbin/rpki-client/rrdp_notification.c", 436, __func__ , "d->serial == nxml->current->serial")); | ||||
| 437 | assert(hlen == sizeof(d->hash))((hlen == sizeof(d->hash)) ? (void)0 : __assert2("/usr/src/usr.sbin/rpki-client/rrdp_notification.c" , 437, __func__, "hlen == sizeof(d->hash)")); | ||||
| 438 | memcpy(hash, d->hash, hlen); | ||||
| 439 | return d->uri; | ||||
| 440 | default: | ||||
| 441 | errx(1, "%s: bad task", __func__); | ||||
| 442 | } | ||||
| 443 | } | ||||
| 444 | |||||
| 445 | /* | ||||
| 446 | * Pop first element from the delta queue. Return non-0 if this was the last | ||||
| 447 | * delta to fetch. | ||||
| 448 | */ | ||||
| 449 | int | ||||
| 450 | notification_delta_done(struct notification_xml *nxml) | ||||
| 451 | { | ||||
| 452 | struct delta_item *d; | ||||
| 453 | |||||
| 454 | d = TAILQ_FIRST(&nxml->delta_q)((&nxml->delta_q)->tqh_first); | ||||
| 455 | assert(d->serial == nxml->current->serial)((d->serial == nxml->current->serial) ? (void)0 : __assert2 ("/usr/src/usr.sbin/rpki-client/rrdp_notification.c", 455, __func__ , "d->serial == nxml->current->serial")); | ||||
| 456 | 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); | ||||
| 457 | free_delta(d); | ||||
| 458 | |||||
| 459 | 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", 460, __func__ , "!TAILQ_EMPTY(&nxml->delta_q) || nxml->serial == nxml->current->serial" )) | ||||
| 460 | 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", 460, __func__ , "!TAILQ_EMPTY(&nxml->delta_q) || nxml->serial == nxml->current->serial" )); | ||||
| 461 | return TAILQ_EMPTY(&nxml->delta_q)(((&nxml->delta_q)->tqh_first) == ((void*)0)); | ||||
| 462 | } | ||||
| 463 | |||||
| 464 | void | ||||
| 465 | log_notification_xml(struct notification_xml *nxml) | ||||
| 466 | { | ||||
| 467 | struct delta_item *d; | ||||
| 468 | char *hash; | ||||
| 469 | |||||
| 470 | logx("session_id: %s, serial: %lld", nxml->session_id, nxml->serial); | ||||
| 471 | logx("snapshot_uri: %s", nxml->snapshot_uri); | ||||
| 472 | hash = hex_encode(nxml->snapshot_hash, sizeof(nxml->snapshot_hash)); | ||||
| 473 | logx("snapshot hash: %s", hash); | ||||
| 474 | free(hash); | ||||
| 475 | |||||
| 476 | TAILQ_FOREACH(d, &nxml->delta_q, q)for((d) = ((&nxml->delta_q)->tqh_first); (d) != ((void *)0); (d) = ((d)->q.tqe_next)) { | ||||
| 477 | logx("delta serial %lld uri: %s", d->serial, d->uri); | ||||
| 478 | hash = hex_encode(d->hash, sizeof(d->hash)); | ||||
| 479 | logx("delta hash: %s", hash); | ||||
| 480 | free(hash); | ||||
| 481 | } | ||||
| 482 | } |