From: Alberto Leiva Popper Date: Tue, 29 Apr 2025 23:53:42 +0000 (-0600) Subject: Strong type-fy URIs X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d128029b4b673b3c2797de88b36f5a393254fb48;p=thirdparty%2FFORT-validator.git Strong type-fy URIs Fixes all the normalization TODOs. ...Well, except the curl URI normalization PR is on hold. I might have to implement something myself later. --- diff --git a/src/asn1/asn1c/RsyncRequest.c b/src/asn1/asn1c/RsyncRequest.c index 4349ad2b..d527079c 100644 --- a/src/asn1/asn1c/RsyncRequest.c +++ b/src/asn1/asn1c/RsyncRequest.c @@ -58,10 +58,11 @@ asn_TYPE_descriptor_t asn_DEF_RsyncRequest = { }; int -RsyncRequest_init(struct RsyncRequest *req, char const *url, char const *path) +RsyncRequest_init(struct RsyncRequest *req, struct uri const *url, + char const *path) { memset(req, 0, sizeof(*req)); - if (OCTET_STRING_fromString(&req->url, url) < 0) + if (OCTET_STRING_fromBuf(&req->url, uri_str(url), uri_len(url)) < 0) return -1; if (OCTET_STRING_fromString(&req->path, path) < 0) return -1; diff --git a/src/asn1/asn1c/RsyncRequest.h b/src/asn1/asn1c/RsyncRequest.h index 13ec8329..66f04780 100644 --- a/src/asn1/asn1c/RsyncRequest.h +++ b/src/asn1/asn1c/RsyncRequest.h @@ -9,6 +9,7 @@ #define _RsyncRequest_H_ /* Including external dependencies */ +#include "types/url.h" #include "asn1/asn1c/OCTET_STRING.h" #include "asn1/asn1c/constr_SEQUENCE.h" @@ -28,7 +29,7 @@ typedef struct RsyncRequest { /* Implementation */ extern asn_TYPE_descriptor_t asn_DEF_RsyncRequest; -int RsyncRequest_init(struct RsyncRequest *, char const *, char const *); +int RsyncRequest_init(struct RsyncRequest *, struct uri const *, char const *); #ifdef __cplusplus } diff --git a/src/cache.c b/src/cache.c index b262f23a..91dd653c 100644 --- a/src/cache.c +++ b/src/cache.c @@ -55,14 +55,18 @@ struct node_key { * If node is rsync, @http is NULL. * If node is HTTP, @http is the simple URL. * If node is RRDP, @http is the rpkiNotify. + * + * Points to @id; do not clean. */ - char const *http; + struct uri http; /* * If node is rsync, @rsync is the simple URL. * If node is HTTP, @rsync is NULL. * If node is RRDP, @rsync is the caRepository. + * + * Points to @id; do not clean. */ - char const *rsync; + struct uri rsync; }; /* @@ -140,13 +144,13 @@ static volatile sig_atomic_t lockfile_owned; struct cache_cage { struct cache_node const *refresh; struct cache_node const *fallback; - char const *rpkiNotify; + struct uri rpkiNotify; struct mft_meta *mft; /* Fallback */ }; struct cache_commit { - char *rpkiNotify; - char *caRepository; + struct uri rpkiNotify; + struct uri caRepository; struct cache_mapping *files; size_t nfiles; struct mft_meta mft; /* RPPs commits only */ @@ -202,25 +206,35 @@ flush_nodes(void) foreach_node(delete_node, NULL); } -char * -get_rsync_module(char const *url) +/* + * - Result must not be cleant. + * - strlen(uri_str(module)) should not be trusted. + */ +static bool +get_rsync_module(struct uri const *url, struct uri *module) { + char const *str; array_index u; unsigned int slashes; + str = uri_str(url); slashes = 0; - for (u = 0; url[u] != 0; u++) - if (url[u] == '/') { + for (u = 0; str[u] != 0; u++) + if (str[u] == '/') { slashes++; - if (slashes == 4) - return pstrndup(url, u); + if (slashes == 4) { + __uri_init(module, str, u); + return true; + } } - if (slashes == 3 && url[u - 1] != '/') - return pstrdup(url); + if (slashes == 3 && str[u - 1] != '/') { + *module = *url; + return true; + } - pr_val_err("Url '%s' does not appear to have an rsync module.", url); - return NULL; + pr_val_err("Url '%s' does not appear to have an rsync module.", str); + return false; } char const * @@ -243,15 +257,18 @@ strip_rsync_module(char const *url) static json_t * node2json(struct cache_node *node) { + char const *str; json_t *json; json = json_obj_new(); if (json == NULL) return NULL; - if (node->key.http && json_add_str(json, "http", node->key.http)) + str = uri_str(&node->key.http); + if (str && json_add_str(json, "http", str)) goto fail; - if (node->key.rsync && json_add_str(json, "rsync", node->key.rsync)) + str = uri_str(&node->key.rsync); + if (str && json_add_str(json, "rsync", str)) goto fail; if (json_add_str(json, "path", node->path)) goto fail; @@ -443,39 +460,46 @@ cache_setup(void) } static void -init_rrdp_fallback_key(struct node_key *key, char const *http, char const *rsync) +init_rrdp_fallback_key(struct node_key *key, struct uri const *http, + struct uri const *rsync) { size_t hlen, rlen; - hlen = strlen(http); - rlen = strlen(rsync); + hlen = uri_len(http); + rlen = uri_len(rsync); key->idlen = hlen + rlen + 1; key->id = pmalloc(key->idlen + 1); - key->http = key->id; - key->rsync = key->id + hlen + 1; + __uri_init(&key->http, key->id, hlen); + __uri_init(&key->rsync, key->id + hlen + 1, rlen); - memcpy(key->id, http, hlen + 1); - memcpy(key->id + hlen + 1, rsync, rlen + 1); + memcpy(key->id, uri_str(http), hlen + 1); + memcpy(key->id + hlen + 1, uri_str(rsync), rlen + 1); } -static bool -init_node_key(struct node_key *key, char const *http, char const *rsync) +static int +init_node_key(struct node_key *key, struct uri const *http, + struct uri const *rsync) { + if (http && (uri_str(http) == NULL)) + http = NULL; + if (rsync && (uri_str(rsync) == NULL)) + rsync = NULL; + if (http != NULL && rsync != NULL) { init_rrdp_fallback_key(key, http, rsync); } else if (rsync != NULL) { - key->id = pstrdup(rsync); - key->idlen = strlen(key->id); - key->http = NULL; - key->rsync = key->id; + key->idlen = uri_len(rsync); + key->id = pstrndup(uri_str(rsync), key->idlen); + memset(&key->http, 0, sizeof(key->http)); + __uri_init(&key->rsync, key->id, key->idlen); } else if (http != NULL) { - key->id = pstrdup(http); - key->idlen = strlen(key->id); - key->http = key->id; - key->rsync = NULL; + key->idlen = uri_len(http); + key->id = pstrndup(uri_str(http), key->idlen); + __uri_init(&key->http, key->id, key->idlen); + memset(&key->rsync, 0, sizeof(key->rsync)); } else { return false; @@ -488,31 +512,37 @@ static struct cache_node * json2node(json_t *json) { struct cache_node *node; - char const *http; - char const *rsync; + struct uri http; + struct uri rsync; char const *path; json_t *rrdp; int error; - error = json_get_str(json, "http", &http); + error = json_get_uri(json, "http", &http); if (error && (error != ENOENT)) { pr_op_debug("http: %s", strerror(error)); return NULL; } - error = json_get_str(json, "rsync", &rsync); + error = json_get_uri(json, "rsync", &rsync); if (error && (error != ENOENT)) { pr_op_debug("rsync: %s", strerror(error)); + uri_cleanup(&http); return NULL; } node = pzalloc(sizeof(struct cache_node)); - if (!init_node_key(&node->key, http, rsync)) { + if (!init_node_key(&node->key, &http, &rsync)) { pr_op_debug("JSON node is missing both http and rsync tags."); + uri_cleanup(&rsync); + uri_cleanup(&http); goto nde; } + uri_cleanup(&http); + uri_cleanup(&rsync); + error = json_get_str(json, "path", &path); if (error) { pr_op_debug("path: %s", strerror(error)); @@ -750,7 +780,7 @@ static int dl_rsync(struct cache_node *module) { int error; - error = rsync_queue(module->key.rsync, module->path); + error = rsync_queue(&module->key.rsync, module->path); return error ? error : EBUSY; } @@ -760,7 +790,7 @@ dl_rrdp(struct cache_node *notif) bool changed; int error; - error = rrdp_update(notif->key.http, notif->path, notif->success_ts, + error = rrdp_update(¬if->key.http, notif->path, notif->success_ts, &changed, ¬if->rrdp); if (error) return error; @@ -776,7 +806,7 @@ dl_http(struct cache_node *file) bool changed; int error; - error = http_download(file->key.http, file->path, + error = http_download(&file->key.http, file->path, file->success_ts, &changed); if (error) return error; @@ -796,7 +826,8 @@ find_node(struct cache_table *tbl, char const *url, size_t urlen) } static struct cache_node * -provide_node(struct cache_table *tbl, char const *http, char const *rsync) +provide_node(struct cache_table *tbl, struct uri const *http, + struct uri const *rsync) { struct node_key key; struct cache_node *node; @@ -870,12 +901,14 @@ write_metadata(struct cache_node *node) * By contract, @result->state will be DLS_FRESH on return 0. */ static int -do_refresh(struct cache_table *tbl, char const *uri, struct cache_node **result) +do_refresh(struct cache_table *tbl, struct uri const *uri, + struct cache_node **result) { + struct uri module; struct cache_node *node; bool downloaded = false; - pr_val_debug("Trying %s (online)...", uri); + pr_val_debug("Trying %s (online)...", uri_str(uri)); if (!tbl->enabled) { pr_val_debug("Protocol disabled."); @@ -883,12 +916,10 @@ do_refresh(struct cache_table *tbl, char const *uri, struct cache_node **result) } if (tbl == &cache.rsync) { - char *module = get_rsync_module(uri); - if (module == NULL) + if (!get_rsync_module(uri, &module)) return EINVAL; mutex_lock(&tbl->lock); - node = provide_node(tbl, NULL, module); - free(module); + node = provide_node(tbl, NULL, &module); } else { mutex_lock(&tbl->lock); node = provide_node(tbl, uri, NULL); @@ -951,10 +982,10 @@ find_rrdp_fallback_node(struct sia_uris *sias) struct node_key key; struct cache_node *result; - if (!sias->rpkiNotify || !sias->caRepository) + if (!uri_str(&sias->rpkiNotify) || !uri_str(&sias->caRepository)) return NULL; - init_rrdp_fallback_key(&key, sias->rpkiNotify, sias->caRepository); + init_rrdp_fallback_key(&key, &sias->rpkiNotify, &sias->caRepository); result = find_node(&cache.fallback, key.id, key.idlen); free(key.id); @@ -968,8 +999,8 @@ get_fallback(struct sia_uris *sias) struct cache_node *rsync; rrdp = find_rrdp_fallback_node(sias); - rsync = find_node(&cache.fallback, sias->caRepository, - strlen(sias->caRepository)); + rsync = find_node(&cache.fallback, uri_str(&sias->caRepository), + uri_len(&sias->caRepository)); if (rrdp == NULL) return rsync; @@ -980,16 +1011,15 @@ get_fallback(struct sia_uris *sias) /* Do not free nor modify the result. */ char * -cache_refresh_by_url(char const *url) +cache_refresh_by_url(struct uri const *url) { struct cache_node *node = NULL; // XXX review result signs - // XXX Normalize @url - if (url_is_https(url)) + if (uri_is_https(url)) do_refresh(&cache.https, url, &node); - else if (url_is_rsync(url)) + else if (uri_is_rsync(url)) do_refresh(&cache.rsync, url, &node); return node ? node->path : NULL; @@ -1000,7 +1030,7 @@ cache_refresh_by_url(char const *url) * Do not free nor modify the result. */ char * -cache_get_fallback(char const *url) +cache_get_fallback(struct uri const *url) { struct cache_node *node; @@ -1009,9 +1039,9 @@ cache_get_fallback(char const *url) * Mutex not needed here. */ - pr_val_debug("Trying %s (offline)...", url); + pr_val_debug("Trying %s (offline)...", uri_str(url)); - node = find_node(&cache.fallback, url, strlen(url)); + node = find_node(&cache.fallback, uri_str(url), uri_len(url)); if (!node) { pr_val_debug("Cache data unavailable."); return NULL; @@ -1032,15 +1062,14 @@ cache_refresh_by_sias(struct sia_uris *sias, struct cache_cage **result) { struct cache_node *node; struct cache_cage *cage; - char const *rpkiNotify; + struct uri rpkiNotify; // XXX Make sure somewhere validates rpkiManifest matches caRepository. // XXX review result signs - // XXX normalize rpkiNotify & caRepository? /* Try RRDP + optional fallback */ - if (sias->rpkiNotify) { - switch (do_refresh(&cache.rrdp, sias->rpkiNotify, &node)) { + if (uri_str(&sias->rpkiNotify) != NULL) { + switch (do_refresh(&cache.rrdp, &sias->rpkiNotify, &node)) { case 0: rpkiNotify = sias->rpkiNotify; goto refresh_success; @@ -1050,9 +1079,9 @@ cache_refresh_by_sias(struct sia_uris *sias, struct cache_cage **result) } /* Try rsync + optional fallback */ - switch (do_refresh(&cache.rsync, sias->caRepository, &node)) { + switch (do_refresh(&cache.rsync, &sias->caRepository, &node)) { case 0: - rpkiNotify = NULL; + memset(&rpkiNotify, 0, sizeof(rpkiNotify)); goto refresh_success; case EBUSY: return EBUSY; @@ -1076,18 +1105,18 @@ refresh_success: } static char const * -node2file(struct cache_node const *node, char const *url) +node2file(struct cache_node const *node, struct uri const *url) { if (node == NULL) return NULL; // XXX RRDP is const, rsync needs to be freed return (node->rrdp) ? /* RRDP */ rrdp_file(node->rrdp, url) - : /* rsync */ path_join(node->path, strip_rsync_module(url)); + : /* rsync */ path_join(node->path, strip_rsync_module(uri_str(url))); } char const * -cage_map_file(struct cache_cage *cage, char const *url) +cage_map_file(struct cache_cage *cage, struct uri const *url) { /* * Remember: In addition to honoring the consts of cache->refresh and @@ -1141,14 +1170,14 @@ cage_mft_fallback(struct cache_cage *cage) * not going to be modified nor deleted until the cache cleanup. */ void -cache_commit_rpp(char const *rpkiNotify, char const *caRepository, +cache_commit_rpp(struct uri const *rpkiNotify, struct uri const *caRepository, struct rpp *rpp) { struct cache_commit *commit; commit = pmalloc(sizeof(struct cache_commit)); - commit->rpkiNotify = rpkiNotify ? pstrdup(rpkiNotify) : NULL; - commit->caRepository = pstrdup(caRepository); + uri_copy(&commit->rpkiNotify, rpkiNotify); + uri_copy(&commit->caRepository, caRepository); commit->files = rpp->files; commit->nfiles = rpp->nfiles; INTEGER_move(&commit->mft.num, &rpp->mft.num); @@ -1167,11 +1196,11 @@ cache_commit_file(struct cache_mapping *map) { struct cache_commit *commit; - commit = pmalloc(sizeof(struct cache_commit)); - commit->rpkiNotify = NULL; - commit->caRepository = NULL; + commit = pzalloc(sizeof(struct cache_commit)); + memset(&commit->rpkiNotify, 0, sizeof(commit->rpkiNotify)); + memset(&commit->caRepository, 0, sizeof(commit->caRepository)); commit->files = pmalloc(sizeof(*map)); - commit->files[0].url = pstrdup(map->url); + uri_copy(&commit->files[0].url, &map->url); commit->files[0].path = pstrdup(map->path); commit->nfiles = 1; memset(&commit->mft, 0, sizeof(commit->mft)); @@ -1182,22 +1211,22 @@ cache_commit_file(struct cache_mapping *map) } void -rsync_finished(char const *url, char const *path) +rsync_finished(struct uri const *url, char const *path) { struct cache_node *node; mutex_lock(&cache.rsync.lock); - node = find_node(&cache.rsync, url, strlen(url)); + node = find_node(&cache.rsync, uri_str(url), uri_len(url)); if (node == NULL) { mutex_unlock(&cache.rsync.lock); pr_op_err("rsync '%s -> %s' finished, but cache node does not exist.", - url, path); + uri_str(url), path); return; } if (node->state != DLS_ONGOING) pr_op_warn("rsync '%s -> %s' finished, but existing node was not in ONGOING state.", - url, path); + uri_str(url), path); node->state = DLS_FRESH; node->dlerr = 0; @@ -1207,10 +1236,10 @@ rsync_finished(char const *url, char const *path) task_wakeup_dormants(); } -char const * +struct uri const * cage_rpkiNotify(struct cache_cage *cage) { - return cage->rpkiNotify; + return &cage->rpkiNotify; } static void @@ -1219,8 +1248,8 @@ cachent_print(struct cache_node *node) if (!node) return; - printf("\thttp:%s rsync:%s (%s): ", node->key.http, node->key.rsync, - node->path); + printf("\thttp:%s rsync:%s (%s): ", uri_str(&node->key.http), + uri_str(&node->key.rsync), node->path); switch (node->state) { case DLS_OUTDATED: printf("stale "); @@ -1288,7 +1317,7 @@ commit_rpp(struct cache_commit *commit, struct cache_node *fb) * Note, this is accidentally working perfectly for rsync too. * Might want to rename some of this. */ - dst = rrdp_create_fallback(fb->path, &fb->rrdp, src->url); + dst = rrdp_create_fallback(fb->path, &fb->rrdp, &src->url); if (!dst) goto skip; @@ -1365,12 +1394,14 @@ commit_fallbacks(time_t now) commit = STAILQ_FIRST(&commits); STAILQ_REMOVE_HEAD(&commits, lh); - if (commit->caRepository) { + if (uri_str(&commit->caRepository) != NULL) { pr_op_debug("Creating fallback for %s (%s)", - commit->caRepository, commit->rpkiNotify); + uri_str(&commit->caRepository), + uri_str(&commit->rpkiNotify)); - fb = provide_node(&cache.fallback, commit->rpkiNotify, - commit->caRepository); + fb = provide_node(&cache.fallback, + &commit->rpkiNotify, + &commit->caRepository); fb->success_ts = now; pr_op_debug("mkdir -f %s", fb->path); @@ -1391,9 +1422,10 @@ commit_fallbacks(time_t now) } else { /* TA */ struct cache_mapping *map = &commit->files[0]; - pr_op_debug("Creating fallback for %s", map->url); + pr_op_debug("Creating fallback for %s", + uri_str(&map->url)); - fb = provide_node(&cache.fallback, map->url, NULL); + fb = provide_node(&cache.fallback, &map->url, NULL); fb->success_ts = now; if (is_fallback(map->path)) goto freshen; @@ -1404,10 +1436,10 @@ commit_fallbacks(time_t now) write_metadata(fb); freshen: fb->state = DLS_FRESH; -skip: free(commit->rpkiNotify); - free(commit->caRepository); +skip: uri_cleanup(&commit->rpkiNotify); + uri_cleanup(&commit->caRepository); for (i = 0; i < commit->nfiles; i++) { - free(commit->files[i].url); + uri_cleanup(&commit->files[i].url); free(commit->files[i].path); } free(commit->files); @@ -1499,10 +1531,10 @@ sias_init(struct sia_uris *sias) void sias_cleanup(struct sia_uris *sias) { - free(sias->caRepository); - free(sias->rpkiNotify); - free(sias->rpkiManifest); - free(sias->crldp); - free(sias->caIssuers); - free(sias->signedObject); + uri_cleanup(&sias->caRepository); + uri_cleanup(&sias->rpkiNotify); + uri_cleanup(&sias->rpkiManifest); + uri_cleanup(&sias->crldp); + uri_cleanup(&sias->caIssuers); + uri_cleanup(&sias->signedObject); } diff --git a/src/cache.h b/src/cache.h index 0be38fff..0b900b1a 100644 --- a/src/cache.h +++ b/src/cache.h @@ -4,6 +4,7 @@ #include #include "types/map.h" #include "types/rpp.h" +#include "types/url.h" int cache_setup(void); /* Init this module */ void cache_atexit(void); @@ -13,42 +14,42 @@ void cache_commit(void); /* Finish validation cycle */ /* XXX might wanna rename */ struct sia_uris { - char *caRepository; /* RPP cage */ - char *rpkiNotify; /* RRDP Notification */ - char *rpkiManifest; + struct uri caRepository; /* RPP cage */ + struct uri rpkiNotify; /* RRDP Notification */ + struct uri rpkiManifest; /** * CRL Distribution Points's fullName. Non-TA certificates only. * RFC 6487, section 4.8.6. */ - char *crldp; + struct uri crldp; /** * AIA's caIssuers. Non-TA certificates only. * RFC 6487, section 4.8.7. */ - char *caIssuers; + struct uri caIssuers; /** * SIA's signedObject. EE certificates only. * RFC 6487, section 4.8.8.2. */ - char *signedObject; + struct uri signedObject; }; void sias_init(struct sia_uris *); void sias_cleanup(struct sia_uris *); -char *cache_refresh_by_url(char const *); -char *cache_get_fallback(char const *); +char *cache_refresh_by_url(struct uri const *); +char *cache_get_fallback(struct uri const *); struct cache_cage; int cache_refresh_by_sias(struct sia_uris *, struct cache_cage **); -char const *cage_map_file(struct cache_cage *, char const *); +char const *cage_map_file(struct cache_cage *, struct uri const *); bool cage_disable_refresh(struct cache_cage *); struct mft_meta const *cage_mft_fallback(struct cache_cage *); -void cache_commit_rpp(char const *, char const *, struct rpp *); +void cache_commit_rpp(struct uri const *, struct uri const *, struct rpp *); void cache_commit_file(struct cache_mapping *); -char const *cage_rpkiNotify(struct cache_cage *); +struct uri const *cage_rpkiNotify(struct cache_cage *); void cache_print(void); /* Dump cache in stdout */ diff --git a/src/certificate_refs.c b/src/certificate_refs.c index 0f3403bf..93c3aa14 100644 --- a/src/certificate_refs.c +++ b/src/certificate_refs.c @@ -7,33 +7,30 @@ #include "log.h" int -validate_cdp(struct sia_uris *sias, char const *crl_url) +validate_cdp(struct sia_uris const *sias, struct uri const *crl_url) { - if (sias->crldp == NULL) + if (uri_str(&sias->crldp) == NULL) pr_crit("Certificate's CRL Distribution Point was not recorded."); - - if (crl_url == NULL) + if (uri_str(crl_url) == NULL) pr_crit("Manifest's CRL was not recorded."); - if (strcmp(sias->crldp, crl_url) != 0) { + if (uri_equals(&sias->crldp, crl_url) != 0) { return pr_val_err("Certificate's CRL Distribution Point ('%s') does not match manifest's CRL ('%s').", - sias->crldp, crl_url); + uri_str(&sias->crldp), uri_str(crl_url)); } return 0; } static int -validate_signedObject(struct sia_uris *sias, char const *url) +validate_signedObject(struct sia_uris const *sias, struct uri const *url) { - if (sias->signedObject == NULL) + if (uri_str(&sias->signedObject) == NULL) pr_crit("Certificate's signedObject was not recorded."); - /* XXX the left one is no longer normalized */ - if (strcmp(sias->signedObject, url) != 0) { + if (!uri_equals(&sias->signedObject, url)) return pr_val_err("Certificate's signedObject ('%s') does not match the URI of its own signed object (%s).", - sias->signedObject, url); - } + uri_str(&sias->signedObject), uri_str(url)); return 0; } @@ -46,7 +43,8 @@ validate_signedObject(struct sia_uris *sias, char const *url) * @url: URL of the signed object that contains the EE certificate. */ int -refs_validate_ee(struct sia_uris *sias, char const *crl_url, char const *url) +refs_validate_ee(struct sia_uris const *sias, struct uri const *crl_url, + struct uri const *url) { int error; diff --git a/src/certificate_refs.h b/src/certificate_refs.h index 2df0890b..851f8a5e 100644 --- a/src/certificate_refs.h +++ b/src/certificate_refs.h @@ -5,7 +5,8 @@ #include "cache.h" -int validate_cdp(struct sia_uris *, char const *); -int refs_validate_ee(struct sia_uris *, char const *, char const *); +int validate_cdp(struct sia_uris const *, struct uri const *); +int refs_validate_ee(struct sia_uris const *, struct uri const *, + struct uri const *); #endif /* SRC_CERTIFICATE_REFS_H_ */ diff --git a/src/common.h b/src/common.h index b93f622e..471910a7 100644 --- a/src/common.h +++ b/src/common.h @@ -7,8 +7,6 @@ #include #include -/* "I think this is not supposed to be implemented." */ -#define ENOTSUPPORTED 3172 /* "I haven't implemented this yet." */ #define ENOTIMPLEMENTED 3173 diff --git a/src/config/string_array.c b/src/config/string_array.c index 80ccb415..b05e62f5 100644 --- a/src/config/string_array.c +++ b/src/config/string_array.c @@ -2,6 +2,7 @@ #include +#include "alloc.h" #include "config/str.h" #include "log.h" #include "types/path.h" diff --git a/src/http.c b/src/http.c index 1f22d0da..177f4bd0 100644 --- a/src/http.c +++ b/src/http.c @@ -219,7 +219,7 @@ validate_file_size(struct write_callback_arg *args) static int get_http_response_code(struct http_handler *handler, long *http_code, - char const *uri) + struct uri const *uri) { CURLcode res; @@ -228,7 +228,7 @@ get_http_response_code(struct http_handler *handler, long *http_code, if (res != CURLE_OK) { return pr_op_err_st("curl_easy_getinfo(CURLINFO_RESPONSE_CODE) returned %d (%s). " "I think this is supposed to be illegal, so I'll have to drop URI '%s'.", - res, curl_err_string(handler, res), uri); + res, curl_err_string(handler, res), uri_str(uri)); } return 0; @@ -245,6 +245,24 @@ handle_http_response_code(long http_code) return -EINVAL; /* Do not retry */ } +static int +check_same_origin(struct uri const *src, char const *redirect) +{ + struct uri redirect_url; + int error; + + error = uri_init(&redirect_url, redirect); + if (error) + return error; + + if (!uri_same_origin(src, &redirect_url)) + error = pr_val_err("%s is redirecting to %s; disallowing because of different origin.", + uri_str(src), uri_str(&redirect_url)); + + uri_cleanup(&redirect_url); + return error; +} + /* * Download @src into @dst; HTTP assumed. * @@ -256,7 +274,8 @@ handle_http_response_code(long http_code) * If @changed is not NULL, initialize it to false. */ int -http_download(char const *src, char const *dst, curl_off_t ims, bool *changed) +http_download(struct uri const *src, char const *dst, + curl_off_t ims, bool *changed) { struct http_handler handler; struct write_callback_arg args; @@ -266,7 +285,7 @@ http_download(char const *src, char const *dst, curl_off_t ims, bool *changed) unsigned int r; int error; - pr_val_info("HTTP GET: %s -> %s", src, dst); + pr_val_info("HTTP GET: %s -> %s", uri_str(src), dst); error = http_easy_init(&handler, ims); if (error) @@ -277,7 +296,8 @@ http_download(char const *src, char const *dst, curl_off_t ims, bool *changed) do { handler.errbuf[0] = 0; - setopt_str(handler.curl, CURLOPT_URL, (redirect != NULL) ? redirect : src); + setopt_str(handler.curl, CURLOPT_URL, + (redirect != NULL) ? redirect : uri_str(src)); args.total_bytes = 0; args.error = 0; @@ -288,7 +308,8 @@ http_download(char const *src, char const *dst, curl_off_t ims, bool *changed) res = curl_easy_perform(handler.curl); /* write_callback() */ if (args.file != NULL) file_close(args.file); - pr_val_debug("Done. Total bytes transferred: %zu", args.total_bytes); + pr_val_debug("Done. Total bytes transferred: %zu", + args.total_bytes); args.error = validate_file_size(&args); if (args.error) { @@ -339,7 +360,8 @@ http_download(char const *src, char const *dst, curl_off_t ims, bool *changed) redirect = NULL; } - res = curl_easy_getinfo(handler.curl, CURLINFO_REDIRECT_URL, &redirect); + res = curl_easy_getinfo(handler.curl, CURLINFO_REDIRECT_URL, + &redirect); if (res != CURLE_OK) { error = pr_op_err("curl_easy_getinfo(CURLINFO_REDIRECT_URL) returned %u.", res); redirect = NULL; @@ -348,19 +370,15 @@ http_download(char const *src, char const *dst, curl_off_t ims, bool *changed) if (redirect == NULL) break; - if (!url_same_origin(src, redirect)) { - error = pr_val_err("%s is redirecting to %s; disallowing because of different origin.", - src, redirect); - redirect = NULL; - goto end; - } - r++; if (r > config_get_max_redirs()) { error = pr_val_err("Too many redirects."); redirect = NULL; goto end; } + error = check_same_origin(src, redirect); + if (error) + goto end; /* The original redirect is destroyed during the next curl_easy_perform(). */ redirect = pstrdup(redirect); diff --git a/src/http.h b/src/http.h index 22113740..3992ddeb 100644 --- a/src/http.h +++ b/src/http.h @@ -4,9 +4,11 @@ #include #include +#include "types/url.h" + int http_init(void); void http_cleanup(void); -int http_download(char const *, char const *, curl_off_t, bool *); +int http_download(struct uri const *, char const *, curl_off_t, bool *); #endif /* SRC_HTTP_H_ */ diff --git a/src/init.c b/src/init.c index 8a3b0fcc..665f12d5 100644 --- a/src/init.c +++ b/src/init.c @@ -7,12 +7,17 @@ static int fetch_url(char const *url, char const *filename) { + struct uri uri; char *path; int error; + error = uri_init(&uri, url); + if (error) + return error; + path = path_join(config_get_tal(), filename); - error = http_download(url, path, 0, NULL); + error = http_download(&uri, path, 0, NULL); if (error) { fprintf(stderr, "Couldn't fetch '%s': %s\n", path, strerror(abs(error))); @@ -21,6 +26,7 @@ fetch_url(char const *url, char const *filename) fprintf(stdout, "Successfully fetched '%s'!\n\n", path); end: free(path); + uri_cleanup(&uri); return error; } diff --git a/src/json_util.c b/src/json_util.c index 14660632..65217ca2 100644 --- a/src/json_util.c +++ b/src/json_util.c @@ -26,6 +26,27 @@ json_get_str(json_t *parent, char const *name, char const **result) return 0; } +/* Result needs to be cleant up. */ +int +json_get_uri(json_t *parent, char const *name, struct uri *result) +{ + char const *str; + int error; + + memset(result, 0, sizeof(*result)); + + error = json_get_str(parent, name, &str); + if (error) + return error; + error = uri_init(result, str); + if (error) { + pr_op_err("Malformed URL: %s", str); + return -error; + } + + return 0; +} + static int json_get_int_t(json_t *parent, char const *name, json_int_t *result) { diff --git a/src/json_util.h b/src/json_util.h index e8f20f9a..9568aef3 100644 --- a/src/json_util.h +++ b/src/json_util.h @@ -18,6 +18,7 @@ #include "asn1/asn1c/INTEGER.h" #include "file.h" +#include "types/url.h" /* * Contract of get functions: @@ -33,6 +34,7 @@ int json_get_ulong(json_t *, char const *, unsigned long *); int json_get_bigint(json_t *, char const *, INTEGER_t *); int json_get_ts(json_t *, char const *, time_t *); int json_get_str(json_t *, char const *, char const **); +int json_get_uri(json_t *, char const *, struct uri *); int json_get_array(json_t *, char const *, json_t **); int json_get_object(json_t *, char const *, json_t **); diff --git a/src/object/certificate.c b/src/object/certificate.c index fee9f9b3..db1f8688 100644 --- a/src/object/certificate.c +++ b/src/object/certificate.c @@ -1175,68 +1175,96 @@ certificate_get_resources(struct rpki_certificate *cert) pr_crit("Unknown policy: %u", cert->policy); } -static bool -is_rsync(ASN1_IA5STRING *uri) -{ - static char const *const PREFIX = "rsync://"; - size_t prefix_len = strlen(PREFIX); - - return (uri->length >= prefix_len) - ? (strncmp((char *) uri->data, PREFIX, strlen(PREFIX)) == 0) - : false; -} - -static void -handle_rpkiManifest(char *uri, void *arg) +static int +handle_rpkiManifest(struct uri const *uri, void *arg) { struct sia_uris *uris = arg; + char const *rm; - pr_clutter("rpkiManifest: %s", uri); + rm = uri_str(uri); + pr_clutter("rpkiManifest: %s", rm); - if (uris->rpkiManifest != NULL) { - pr_val_warn("Ignoring additional rpkiManifest: %s", uri); - free(uri); - } else { - uris->rpkiManifest = uri; + if (!uri_is_rsync(uri)) { + pr_val_debug("Ignoring non-rsync rpkiManifest '%s'.", rm); + return ENOTSUP; + } + + if (uri_str(&uris->rpkiManifest) != NULL) { + pr_val_warn("Ignoring additional rpkiManifest: %s", rm); + return 0; } + + uri_copy(&uris->rpkiManifest, uri); + return 0; } -static void -handle_caRepository(char *uri, void *arg) +static int +handle_caRepository(struct uri const *uri, void *arg) { struct sia_uris *uris = arg; + char const *cr; - pr_clutter("caRepository: %s", uri); + cr = uri_str(uri); + pr_clutter("caRepository: %s", caRepo); - if (uris->caRepository != NULL) { - pr_val_warn("Ignoring additional caRepository: %s", uri); - free(uri); - } else { - uris->caRepository = uri; + if (!uri_is_rsync(uri)) { + pr_val_debug("Ignoring non-rsync caRepository '%s'.", cr); + return ENOTSUP; } + + if (uri_str(&uris->caRepository) != NULL) { + pr_val_warn("Ignoring additional caRepository: %s", cr); + return 0; + } + + uri_copy(&uris->caRepository, uri); + return 0; } -static void -handle_rpkiNotify(char *uri, void *arg) +static int +handle_rpkiNotify(struct uri const *uri, void *arg) { struct sia_uris *uris = arg; + char const *rn; - pr_clutter("rpkiNotify: %s", uri); + rn = uri_str(uri); + pr_clutter("rpkiNotify: %s", rn); - if (uris->rpkiNotify != NULL) { - pr_val_warn("Ignoring additional rpkiNotify: %s", uri); - free(uri); - } else { - uris->rpkiNotify = uri; + if (!uri_is_https(uri)) { + pr_val_debug("Ignoring non-https rpkiNotify '%s'.", rn); + return ENOTSUP; } + + if (uri_str(&uris->rpkiNotify) != NULL) { + pr_val_warn("Ignoring additional rpkiNotify: %s", rn); + return 0; + } + + uri_copy(&uris->rpkiNotify, uri); + return 0; } -static void -handle_signedObject(char *uri, void *arg) +static int +handle_signedObject(struct uri const *uri, void *arg) { struct sia_uris *sias = arg; - pr_clutter("signedObject: %s", uri); - sias->signedObject = uri; + char const *so; + + so = uri_str(uri); + pr_clutter("signedObject: %s", so); + + if (!uri_is_rsync(uri)) { + pr_val_debug("Ignoring non-rsync signedObject '%s'.", so); + return ENOTSUP; + } + + if (uri_str(&sias->signedObject) != NULL) { + pr_val_warn("Ignoring additional signedObject: %s", so); + return 0; + } + + uri_copy(&sias->signedObject, uri); + return 0; } static int @@ -1356,6 +1384,37 @@ handle_ku_ee(void *ext, void *arg) return handle_ku(ext, 0x80); } +static int +gn2uri(GENERAL_NAME *ad, struct uri *uri) +{ + ASN1_STRING *asn1str; + int ptype; + char *str; + int error; + + asn1str = GENERAL_NAME_get0_value(ad, &ptype); + if (ptype != GEN_URI) { + pr_val_debug("Ignoring unknown GENERAL_NAME type: %d", ptype); + return ENOTSUP; + } + + /* + * TODO (testers) According to RFC 5280, accessLocation can be an IRI + * somehow converted into URI form. I don't think that's an issue + * because the RSYNC clone operation should not have performed the + * conversion, so we should be looking at precisely the IA5String + * directory our g2l version of @asn1_string should contain. + * But ask the testers to keep an eye on it anyway. + */ + error = ia5s2string(asn1str, &str); + if (error) + return error; + error = uri_init(uri, str); + free(str); + + return error; +} + static int handle_cdp(void *ext, void *arg) { @@ -1363,10 +1422,7 @@ handle_cdp(void *ext, void *arg) struct sia_uris *sias = arg; DIST_POINT *dp; GENERAL_NAMES *names; - GENERAL_NAME *name; - ASN1_IA5STRING *str; int i; - int type; char const *error_msg; if (sk_DIST_POINT_num(crldp) != 1) { @@ -1404,25 +1460,25 @@ handle_cdp(void *ext, void *arg) names = dp->distpoint->name.fullname; for (i = 0; i < sk_GENERAL_NAME_num(names); i++) { - name = sk_GENERAL_NAME_value(names, i); - str = GENERAL_NAME_get0_value(name, &type); - if (type == GEN_URI && is_rsync(str)) { - /* - * Since we're parsing and validating the manifest's CRL - * at some point, I think that all we need to do now is - * compare this CRL URI to that one's. - * - * But there is a problem: - * The manifest's CRL might not have been parsed at this - * point. In fact, it's guaranteed to not have been - * parsed if the certificate we're validating is the EE - * certificate of the manifest itself. - * - * So we will store the URI in @refs, and validate it - * later. - */ - return ia5s2string(str, &sias->crldp); + /* + * Since we're parsing and validating the manifest's CRL at some + * point, I think that all we need to do now is compare this CRL + * URI to that one's. + * + * But there is a problem: The manifest's CRL might not have + * been parsed at this point. In fact, it's guaranteed to not + * have been parsed if the certificate we're validating is the + * EE certificate of the manifest itself. + * + * So we will store the URI in @sias, and validate it later. + */ + if (gn2uri(sk_GENERAL_NAME_value(names, i), &sias->crldp) != 0) + continue; + if (!uri_is_rsync(&sias->crldp)) { + uri_cleanup(&sias->crldp); + continue; } + return 0; } error_msg = "lacks an RSYNC URI"; @@ -1432,62 +1488,6 @@ dist_point_error: ext_cdp()->name, error_msg); } -/* - * Create @map from the @ad - */ -static int -ad2uri(char **uri, ACCESS_DESCRIPTION *ad) -{ - ASN1_STRING *asn1str; - int ptype; - - asn1str = GENERAL_NAME_get0_value(ad->location, &ptype); - - /* - * RFC 6487: "This extension MUST have an instance of an - * AccessDescription with an accessMethod of id-ad-rpkiManifest, (...) - * with an rsync URI [RFC5781] form of accessLocation." - * - * Ehhhhhh. It's a little annoying in that it seems to be stucking more - * than one requirement in a single sentence, which I think is rather - * rare for an RFC. Normally they tend to hammer things more. - * - * Does it imply that the GeneralName CHOICE is constrained to type - * "uniformResourceIdentifier"? I guess so, though I don't see anything - * stopping a few of the other types from also being capable of storing - * URIs. - * - * Also, nobody seems to be using the other types, and handling them - * would be a titanic pain. So this is what I'm committing to. - */ - if (ptype != GEN_URI) { - pr_val_err("Unknown GENERAL_NAME type: %d", ptype); - return ENOTSUPPORTED; - } - - /* - * GEN_URI signals an IA5String. - * IA5String is a subset of ASCII, so this cast is safe. - * No guarantees of a NULL chara though, which is why we need a dup. - * - * TODO (testers) According to RFC 5280, accessLocation can be an IRI - * somehow converted into URI form. I don't think that's an issue - * because the RSYNC clone operation should not have performed the - * conversion, so we should be looking at precisely the IA5String - * directory our g2l version of @asn1_string should contain. - * But ask the testers to keep an eye on it anyway. - * - * XXX There used to be a map_create() here. Make sure validations are - * restored somewhere: - * 1. ascii - * 2. "rsync://" or "https://" prefix (ENOTRSYNC, ENOTHTTPS) - * 3. URL normalization - */ - *uri = pstrndup((char const *)ASN1_STRING_get0_data(asn1str), - ASN1_STRING_length(asn1str)); - return 0; -} - /* * The RFC does not explain AD validation very well. This is personal * interpretation, influenced by Tim Bruijnzeels's response @@ -1495,7 +1495,6 @@ ad2uri(char **uri, ACCESS_DESCRIPTION *ad) * (I'm being a bit more lax than he suggested.) * * 1. The NID (@nid) can be found more than once. - * 2. All access descriptions that match the NID must be URLs. * 3. Depending on meta->required, zero or one of those matches will be an URL * of the meta->type we're expecting. * (I would have gone with "at least zero of those matches", but I don't know @@ -1511,10 +1510,10 @@ ad2uri(char **uri, ACCESS_DESCRIPTION *ad) */ static int handle_ad(int nid, struct ad_metadata const *meta, SIGNATURE_INFO_ACCESS *ia, - void (*cb)(char *, void *), void *arg) + int (*cb)(struct uri const *, void *), void *arg) { ACCESS_DESCRIPTION *ad; - char *uri; + struct uri uri; bool found; unsigned int i; int error; @@ -1523,23 +1522,22 @@ handle_ad(int nid, struct ad_metadata const *meta, SIGNATURE_INFO_ACCESS *ia, for (i = 0; i < sk_ACCESS_DESCRIPTION_num(ia); i++) { ad = sk_ACCESS_DESCRIPTION_value(ia, i); if (OBJ_obj2nid(ad->method) == nid) { - error = ad2uri(&uri, ad); - switch (error) { - case 0: - break; - case ENOTSUPPORTED: + if (gn2uri(ad->location, &uri) != 0) continue; - default: - return error; - } if (found) { - free(uri); + uri_cleanup(&uri); return pr_val_err("Extension '%s' has multiple '%s' %s URIs.", meta->ia_name, meta->name, meta->type); } - cb(uri, arg); /* Ownership of uri stolen */ + error = cb(&uri, arg); + uri_cleanup(&uri); + if (error == ENOTSUP) + continue; + if (error) + return error; + found = true; } } @@ -1553,18 +1551,23 @@ handle_ad(int nid, struct ad_metadata const *meta, SIGNATURE_INFO_ACCESS *ia, return 0; } -static void -handle_caIssuers(char *uri, void *arg) +static int +handle_caIssuers(struct uri const *uri, void *arg) { struct sia_uris *sias = arg; + + if (!uri_is_rsync(uri)) { + pr_val_debug("Ignoring non-rsync caIssuers '%s'.", uri_str(uri)); + return ENOTSUP; + } + /* * Bringing the parent certificate's URI all the way * over here is too much trouble, so do the handle_cdp() * hack. - * - * XXX Uh... it's extremely easy now. */ - sias->caIssuers = uri; + uri_copy(&sias->caIssuers, uri); + return 0; } static int @@ -1711,7 +1714,7 @@ validate_ca_extensions(struct rpki_certificate *cert) error = certificate_validate_aia(cert); if (error) return error; - return validate_cdp(&cert->sias, cert->parent->rpp.crl.map->url); + return validate_cdp(&cert->sias, &cert->parent->rpp.crl.map->url); } int @@ -1796,11 +1799,11 @@ get_certificate_type(struct rpki_certificate *cert) int certificate_validate_aia(struct rpki_certificate *cert) { - /* - * FIXME Compare the AIA to the parent's URI. - * We're currently not recording the URI, so this can't be solved until - * the #78 refactor. - */ + if (!uri_equals(&cert->parent->map.url, &cert->sias.caIssuers)) + return pr_val_err("Certificate's caIssuers (%s) does not match parent certificate's URL (%s).", + uri_str(&cert->parent->map.url), + uri_str(&cert->sias.caIssuers)); + return 0; } @@ -1895,10 +1898,9 @@ int certificate_traverse(struct rpki_certificate *ca) { struct cache_cage *cage; - char const *mft_path; + struct cache_mapping mft; array_index i; struct cache_mapping *map; - char const *ext; unsigned int queued; int error; @@ -1919,19 +1921,21 @@ certificate_traverse(struct rpki_certificate *ca) default: return pr_val_err("caRepository '%s' could not be refreshed, " "and there is no fallback in the cache. " - "I'm going to have to skip it.", ca->sias.caRepository); + "I'm going to have to skip it.", + uri_str(&ca->sias.caRepository)); } -retry: mft_path = cage_map_file(cage, ca->sias.rpkiManifest); - if (!mft_path) { + mft.url = ca->sias.rpkiManifest; +retry: mft.path = (char *)cage_map_file(cage, &mft.url); /* Will not edit */ + if (!mft.path) { if (cage_disable_refresh(cage)) goto retry; error = pr_val_err("caRepository '%s' is missing a manifest.", - ca->sias.caRepository); + uri_str(&ca->sias.caRepository)); goto end; } - error = manifest_traverse(ca->sias.rpkiManifest, mft_path, cage, ca); + error = manifest_traverse(&mft, cage, ca); if (error) { if (cage_disable_refresh(cage)) goto retry; @@ -1941,18 +1945,18 @@ retry: mft_path = cage_map_file(cage, ca->sias.rpkiManifest); queued = 0; for (i = 0; i < ca->rpp.nfiles; i++) { map = ca->rpp.files + i; - ext = map->url + strlen(map->url) - 4; - if (strcmp(ext, ".cer") == 0) + if (uri_has_extension(&map->url, ".cer")) queued += task_enqueue_rpp(map, ca); - else if (strcmp(ext, ".roa") == 0) + else if (uri_has_extension(&map->url, ".roa")) roa_traverse(map, ca); - else if (strcmp(ext, ".gbr") == 0) + else if (uri_has_extension(&map->url, ".gbr")) ghostbusters_traverse(map, ca); } if (queued > 0) task_wakeup(); - cache_commit_rpp(cage_rpkiNotify(cage), ca->sias.caRepository, &ca->rpp); + cache_commit_rpp(cage_rpkiNotify(cage), &ca->sias.caRepository, + &ca->rpp); end: free(cage); return error; diff --git a/src/object/ghostbusters.c b/src/object/ghostbusters.c index 305d9d4f..d9cffc85 100644 --- a/src/object/ghostbusters.c +++ b/src/object/ghostbusters.c @@ -43,7 +43,7 @@ ghostbusters_traverse(struct cache_mapping *map, error = handle_vcard(&sobj); if (error) goto end3; - error = refs_validate_ee(&ee.sias, parent->rpp.crl.map->url, map->url); + error = refs_validate_ee(&ee.sias, &parent->rpp.crl.map->url, &map->url); end3: rpki_certificate_cleanup(&ee); signed_object_cleanup(&sobj); diff --git a/src/object/manifest.c b/src/object/manifest.c index a5a3372b..b0ae10a3 100644 --- a/src/object/manifest.c +++ b/src/object/manifest.c @@ -288,12 +288,12 @@ check_file_and_hash(struct FileAndHash *fah, char const *path) */ static int -collect_files(char const *mft_url, char const *mft_path, +collect_files(struct cache_mapping const *map, struct Manifest *mft, struct cache_cage *cage, struct rpki_certificate *parent) { struct rpp *rpp; - char *rpp_url; + struct uri rpp_url; unsigned int m; struct FileAndHash *src; struct cache_mapping *dst; @@ -305,7 +305,9 @@ collect_files(char const *mft_url, char const *mft_path, return pr_val_err("Manifest's file list is empty."); rpp = &parent->rpp; - rpp_url = url_parent(mft_url); // XXX + error = uri_parent(&map->url, &rpp_url); + if (error) + return error; rpp->files = pzalloc((mft->fileList.list.count + 1) * sizeof(*rpp->files)); rpp->nfiles = 0; @@ -339,15 +341,14 @@ collect_files(char const *mft_url, char const *mft_path, continue; dst = &rpp->files[rpp->nfiles++]; - dst->url = path_njoin(rpp_url, - (char const *)src->file.buf, - src->file.size); + uri_child(&rpp_url, (char const *)src->file.buf, src->file.size, + &dst->url); - path = cage_map_file(cage, dst->url); + path = cage_map_file(cage, &dst->url); if (!path) { error = pr_val_err( "Manifest file '%s' is absent from the cache.", - dst->url); + uri_str(&dst->url)); goto revert; } dst->path = pstrdup(path); @@ -359,13 +360,12 @@ collect_files(char const *mft_url, char const *mft_path, /* Manifest */ dst = &rpp->files[rpp->nfiles++]; - dst->url = pstrdup(mft_url); - dst->path = pstrdup(mft_path); + uri_copy(&dst->url, &map->url); + dst->path = pstrdup(map->path); return 0; revert: rpp_cleanup(rpp); - free(rpp_url); return error; } @@ -378,7 +378,7 @@ load_crl(struct rpki_certificate *parent) rpp = &parent->rpp; for (f = 0; f < rpp->nfiles; f++) - if (str_ends_with(rpp->files[f].url, ".crl")) { + if (uri_has_extension(&rpp->files[f].url, ".crl")) { if (rpp->crl.map != NULL) return pr_val_err("Manifest has more than one CRL."); rpp->crl.map = &rpp->files[f]; @@ -392,12 +392,12 @@ load_crl(struct rpki_certificate *parent) } static int -build_rpp(char const *mft_url, char const *mft_path, struct Manifest *mft, +build_rpp(struct cache_mapping const *map, struct Manifest *mft, struct cache_cage *cage, struct rpki_certificate *parent) { int error; - error = collect_files(mft_url, mft_path, mft, cage, parent); + error = collect_files(map, mft, cage, parent); if (error) return error; @@ -411,8 +411,8 @@ build_rpp(char const *mft_url, char const *mft_path, struct Manifest *mft, } int -manifest_traverse(char const *mft_url, char const *mft_path, - struct cache_cage *cage, struct rpki_certificate *parent) +manifest_traverse(struct cache_mapping const *map, struct cache_cage *cage, + struct rpki_certificate *parent) { static OID oid = OID_MANIFEST; struct oid_arcs arcs = OID2ARCS("manifest", oid); @@ -422,10 +422,10 @@ manifest_traverse(char const *mft_url, char const *mft_path, int error; /* Prepare */ - fnstack_push(mft_url); + fnstack_push_map(map); /* Decode */ - error = signed_object_decode(&sobj, mft_path); + error = signed_object_decode(&sobj, map->path); if (error) goto end1; error = decode_manifest(&sobj, &mft); @@ -433,7 +433,7 @@ manifest_traverse(char const *mft_url, char const *mft_path, goto end2; /* Initialize @summary */ - error = build_rpp(mft_url, mft_path, mft, cage, parent); + error = build_rpp(map, mft, cage, parent); if (error) goto end3; @@ -447,7 +447,7 @@ manifest_traverse(char const *mft_url, char const *mft_path, error = validate_manifest(mft, cage, &parent->rpp.mft); if (error) goto end5; - error = refs_validate_ee(&ee.sias, parent->rpp.crl.map->url, mft_url); + error = refs_validate_ee(&ee.sias, &parent->rpp.crl.map->url, &map->url); end5: rpki_certificate_cleanup(&ee); if (error) diff --git a/src/object/manifest.h b/src/object/manifest.h index ad09fac1..58be295d 100644 --- a/src/object/manifest.h +++ b/src/object/manifest.h @@ -7,7 +7,7 @@ #include "cache.h" #include "object/certificate.h" -int manifest_traverse(char const *, char const *, struct cache_cage *, +int manifest_traverse(struct cache_mapping const *, struct cache_cage *, struct rpki_certificate *); #endif /* SRC_OBJECT_MANIFEST_H_ */ diff --git a/src/object/roa.c b/src/object/roa.c index e2ea6dbf..9907f426 100644 --- a/src/object/roa.c +++ b/src/object/roa.c @@ -233,7 +233,7 @@ roa_traverse(struct cache_mapping *map, struct rpki_certificate *parent) error = __handle_roa(roa, ee.resources); if (error) goto end4; - error = refs_validate_ee(&ee.sias, parent->rpp.crl.map->url, map->url); + error = refs_validate_ee(&ee.sias, &parent->rpp.crl.map->url, &map->url); end4: rpki_certificate_cleanup(&ee); ASN_STRUCT_FREE(asn_DEF_RouteOriginAttestation, roa); diff --git a/src/object/tal.c b/src/object/tal.c index 8ec75d5d..db4de218 100644 --- a/src/object/tal.c +++ b/src/object/tal.c @@ -19,7 +19,7 @@ struct tal { char const *file_name; - struct strlist urls; + struct uris urls; unsigned char *spki; /* Decoded; not base64. */ size_t spki_len; }; @@ -51,6 +51,7 @@ read_content(char *fc /* File Content */, struct tal *tal) { char *nl; /* New Line */ bool cr; /* Carriage return */ + struct uri url; /* Comment section */ while (fc[0] == '#') { @@ -71,8 +72,14 @@ read_content(char *fc /* File Content */, struct tal *tal) if (is_blank(fc)) break; - if (url_is_https(fc) || url_is_rsync(fc)) - strlist_add(&tal->urls, pstrdup(fc)); + if (uri_init(&url, fc) == 0) { + if (uri_is_https(&url) || uri_is_rsync(&url)) + uris_add(&tal->urls, &url); + else + uri_cleanup(&url); + } else { + pr_op_debug("Cannot parse '%s' as a URI; ignoring.", fc); + } fc = nl + cr + 1; if (*fc == '\0') @@ -106,10 +113,10 @@ tal_init(struct tal *tal, char const *file_path) tal->file_name = path_filename(file_path); - strlist_init(&tal->urls); + uris_init(&tal->urls); error = read_content((char *)file.buffer, tal); if (error) - strlist_cleanup(&tal->urls); + uris_cleanup(&tal->urls, uri_cleanup); file_free(&file); return error; @@ -119,7 +126,7 @@ static void tal_cleanup(struct tal *tal) { free(tal->spki); - strlist_cleanup(&tal->urls); + uris_cleanup(&tal->urls, uri_cleanup); } char const * @@ -165,18 +172,18 @@ validate_ta(struct tal *tal, struct cache_mapping const *ta_map) } static int -try_urls(struct tal *tal, bool (*url_is_protocol)(char const *), - char *(*get_path)(char const *)) +try_urls(struct tal *tal, bool (*url_is_protocol)(struct uri const *), + char *(*get_path)(struct uri const *)) { - char **url; + struct uri *url; struct cache_mapping map; int error; ARRAYLIST_FOREACH(&tal->urls, url) { map.url = *url; - if (!url_is_protocol(map.url)) + if (!url_is_protocol(&map.url)) continue; - map.path = get_path(*url); + map.path = get_path(url); if (!map.path) continue; error = validate_ta(tal, &map); @@ -204,17 +211,17 @@ traverse_tal(char const *tal_path) goto end1; /* Online attempts */ - error = try_urls(&tal, url_is_https, cache_refresh_by_url); + error = try_urls(&tal, uri_is_https, cache_refresh_by_url); if (!error || error == EBUSY) goto end2; - error = try_urls(&tal, url_is_rsync, cache_refresh_by_url); + error = try_urls(&tal, uri_is_rsync, cache_refresh_by_url); if (!error || error == EBUSY) goto end2; /* Offline fallback attempts */ - error = try_urls(&tal, url_is_https, cache_get_fallback); + error = try_urls(&tal, uri_is_https, cache_get_fallback); if (!error || error == EBUSY) goto end2; - error = try_urls(&tal, url_is_rsync, cache_get_fallback); + error = try_urls(&tal, uri_is_rsync, cache_get_fallback); if (!error || error == EBUSY) goto end2; diff --git a/src/print_file.c b/src/print_file.c index 4183f5c6..e7861c96 100644 --- a/src/print_file.c +++ b/src/print_file.c @@ -27,11 +27,18 @@ static BIO * __rsync2bio(char const *src, char const *dst) { + struct uri url; int error; + if (uri_init(&url, src) != 0) + return NULL; + // XXX use the cache - error = rsync_queue(src, dst); + error = rsync_queue(&url, dst); + + uri_cleanup(&url); + if (error) { pr_op_err("rsync download failed: %s", strerror(abs(error))); return NULL; @@ -99,7 +106,7 @@ filename2bio(char const *filename) if (filename == NULL || strcmp(filename, "-") == 0) return BIO_new_fp(stdin, BIO_NOCLOSE); - if (url_is_rsync(filename)) + if (str_starts_with(filename, "rsync://")) return rsync2bio(filename); return BIO_new_file(filename, "rb"); diff --git a/src/rrdp.c b/src/rrdp.c index 4a71c247..e7b15f85 100644 --- a/src/rrdp.c +++ b/src/rrdp.c @@ -78,7 +78,7 @@ struct rrdp_state { }; struct file_metadata { - char *uri; + struct uri uri; unsigned char *hash; /* Array. Sometimes omitted. */ size_t hash_len; }; @@ -97,7 +97,7 @@ struct update_notification { struct rrdp_session session; struct file_metadata snapshot; struct notification_deltas deltas; - char const *url; + struct uri const *url; }; /* A deserialized tag, from a snapshot or delta. */ @@ -144,24 +144,42 @@ session_cleanup(struct rrdp_session *meta) } static struct cache_file * -state_find_file(struct rrdp_state const *state, char const *url, size_t len) +state_find_file(struct rrdp_state const *state, struct uri const *url) { + char const *str; + size_t len; struct cache_file *file; - HASH_FIND(hh, state->files, url, len, file); + + str = uri_str(url); + len = uri_len(url); + + HASH_FIND(hh, state->files, str, len, file); + return file; } +static void +state_add_file(struct rrdp_state *state, struct cache_file *file) +{ + char const *url; + size_t urlen; + + url = uri_str(&file->map.url); + urlen = uri_len(&file->map.url); + + HASH_ADD_KEYPTR(hh, state->files, url, urlen, file); +} + static struct cache_file * -cache_file_add(struct rrdp_state *state, char *url, char *path) +cache_file_add(struct rrdp_state *state, struct uri const *url, char *path) { struct cache_file *file; - size_t urlen; file = pzalloc(sizeof(struct cache_file)); - file->map.url = url; + uri_copy(&file->map.url, url); file->map.path = path; - urlen = strlen(url); - HASH_ADD_KEYPTR(hh, state->files, file->map.url, urlen, file); + + state_add_file(state, file); return file; } @@ -169,7 +187,7 @@ cache_file_add(struct rrdp_state *state, char *url, char *path) static void metadata_cleanup(struct file_metadata *meta) { - free(meta->uri); + uri_cleanup(&meta->uri); free(meta->hash); } @@ -181,7 +199,8 @@ notification_delta_cleanup(struct notification_delta *delta) } static void -update_notification_init(struct update_notification *notif, char const *url) +update_notification_init(struct update_notification *notif, + struct uri const *url) { memset(¬if->session, 0, sizeof(notif->session)); memset(¬if->snapshot, 0, sizeof(notif->snapshot)); @@ -279,22 +298,6 @@ parse_string(xmlTextReaderPtr reader, char const *attr) return result; } -static char * -parse_uri(xmlTextReaderPtr reader) -{ - xmlChar *xmlattr; - char *result; - - xmlattr = parse_string(reader, RRDP_ATTR_URI); - if (xmlattr == NULL) - return NULL; - - result = pstrdup((char const *)xmlattr); - - xmlFree(xmlattr); - return result; -} - static unsigned int hexchar2uint(xmlChar xmlchar) { @@ -473,18 +476,22 @@ end: static int parse_file_metadata(xmlTextReaderPtr reader, struct file_metadata *meta) { + xmlChar *xmlattr; int error; memset(meta, 0, sizeof(*meta)); - meta->uri = parse_uri(reader); - if (meta->uri == NULL) + xmlattr = parse_string(reader, RRDP_ATTR_URI); + if (xmlattr == NULL) + return -EINVAL; + error = uri_init(&meta->uri, (char const *)xmlattr); + xmlFree(xmlattr); + if (error) return -EINVAL; error = parse_hash(reader, &meta->hash, &meta->hash_len); if (error) { - free(meta->uri); - meta->uri = NULL; + uri_cleanup(&meta->uri); return error; } @@ -492,16 +499,16 @@ parse_file_metadata(xmlTextReaderPtr reader, struct file_metadata *meta) } static bool -is_known_extension(char const *uri) +is_known_extension(struct uri const *uri) { size_t len; char const *ext; - len = strlen(uri); + len = uri_len(uri); if (len < 4) return false; - ext = uri + len - 4; + ext = uri_str(uri) + len - 4; return ((strcmp(ext, ".cer") == 0) || (strcmp(ext, ".roa") == 0) || (strcmp(ext, ".mft") == 0) @@ -525,11 +532,11 @@ handle_publish(xmlTextReaderPtr reader, struct parser_args *args) if (xmlTextReaderRead(reader) != 1) { error = pr_val_err( "Couldn't read publish content of element '%s'", - tag.meta.uri + uri_str(&tag.meta.uri) ); goto end; } - if (!is_known_extension(tag.meta.uri)) + if (!is_known_extension(&tag.meta.uri)) goto end; /* Mirror rsync filters */ /* Parse tag content */ @@ -549,7 +556,7 @@ handle_publish(xmlTextReaderPtr reader, struct parser_args *args) pr_clutter("Publish %s", logv_filename(tag.meta.uri)); - file = state_find_file(args->state, tag.meta.uri, strlen(tag.meta.uri)); + file = state_find_file(args->state, &tag.meta.uri); /* rfc8181#section-2.2 */ if (file) { @@ -558,7 +565,7 @@ handle_publish(xmlTextReaderPtr reader, struct parser_args *args) error = pr_val_err("RRDP desync: " " is attempting to create '%s', " "but the file is already cached.", - tag.meta.uri); + uri_str(&tag.meta.uri)); goto end; } @@ -585,7 +592,7 @@ handle_publish(xmlTextReaderPtr reader, struct parser_args *args) error = pr_val_err("RRDP desync: " " is attempting to overwrite '%s', " "but the file is absent in the cache.", - tag.meta.uri); + uri_str(&tag.meta.uri)); goto end; } @@ -594,7 +601,7 @@ handle_publish(xmlTextReaderPtr reader, struct parser_args *args) error = -EINVAL; goto end; } - file = cache_file_add(args->state, pstrdup(tag.meta.uri), path); + file = cache_file_add(args->state, &tag.meta.uri, path); } error = file_write_bin(file->map.path, tag.content, tag.content_len); @@ -609,29 +616,27 @@ handle_withdraw(xmlTextReaderPtr reader, struct parser_args *args) { struct withdraw tag = { 0 }; struct cache_file *file; - size_t len; int error; error = parse_file_metadata(reader, &tag.meta); if (error) - goto end; - if (!is_known_extension(tag.meta.uri)) + return error; + if (!is_known_extension(&tag.meta.uri)) goto end; /* Mirror rsync filters */ if (!tag.meta.hash) { error = pr_val_err("Withdraw '%s' is missing a hash.", - tag.meta.uri); + uri_str(&tag.meta.uri)); goto end; } pr_clutter("Withdraw %s", logv_filename(tag.meta.uri)); - len = strlen(tag.meta.uri); - file = state_find_file(args->state, tag.meta.uri, len); + file = state_find_file(args->state, &tag.meta.uri); if (!file) { error = pr_val_err("Broken RRDP: " " is attempting to delete unknown file '%s'.", - tag.meta.uri); + uri_str(&tag.meta.uri)); goto end; } @@ -665,11 +670,11 @@ parse_notification_snapshot(xmlTextReaderPtr reader, if (!notif->snapshot.hash) return pr_val_err("Snapshot '%s' is missing a hash.", - notif->snapshot.uri); + uri_str(¬if->snapshot.uri)); - if (!url_same_origin(notif->url, notif->snapshot.uri)) + if (!uri_same_origin(notif->url, ¬if->snapshot.uri)) return pr_val_err("Notification '%s' and Snapshot '%s' are not hosted by the same origin.", - notif->url, notif->snapshot.uri); + uri_str(notif->url), uri_str(¬if->snapshot.uri)); return 0; } @@ -687,25 +692,25 @@ parse_notification_delta(xmlTextReaderPtr reader, error = parse_file_metadata(reader, &delta.meta); if (error) - goto fail; + goto srl; if (!delta.meta.hash) { error = pr_val_err("Delta '%s' is missing a hash.", - delta.meta.uri); - goto fail; + uri_str(&delta.meta.uri)); + goto mta; } - if (!url_same_origin(notif->url, delta.meta.uri)) { + if (!uri_same_origin(notif->url, &delta.meta.uri)) { error = pr_val_err("Notification %s and Delta %s are not hosted by the same origin.", - notif->url, delta.meta.uri); - goto fail; + uri_str(notif->url), uri_str(&delta.meta.uri)); + goto mta; } notification_deltas_add(¬if->deltas, &delta); return 0; -fail: serial_cleanup(&delta.serial); - metadata_cleanup(&delta.meta); +mta: metadata_cleanup(&delta.meta); +srl: serial_cleanup(&delta.serial); return error; } @@ -827,7 +832,7 @@ xml_read_notif(xmlTextReaderPtr reader, void *arg) } static int -parse_notification(char const *url, char const *path, +parse_notification(struct uri const *url, char const *path, struct update_notification *result) { int error; @@ -913,7 +918,7 @@ validate_session_desync(struct rrdp_state *old_notif, /* TODO (performance) Stream instead of caching notifs, snapshots & deltas. */ static int -dl_tmp(char const *url, char *path) +dl_tmp(struct uri const *url, char *path) { cache_tmpfile(path); return http_download(url, path, 0, NULL); @@ -923,12 +928,14 @@ static int handle_snapshot(struct update_notification *new, struct rrdp_state *state) { char tmppath[CACHE_TMPFILE_BUFLEN]; + struct uri *url; int error; - pr_val_debug("Processing snapshot."); - fnstack_push(new->snapshot.uri); + url = &new->snapshot.uri; + pr_val_debug("Processing snapshot '%s'.", uri_str(url)); + fnstack_push(uri_str(url)); - error = dl_tmp(new->snapshot.uri, tmppath); + error = dl_tmp(url, tmppath); if (error) goto end; error = validate_hash(&new->snapshot, tmppath); @@ -995,12 +1002,15 @@ handle_delta(struct update_notification *notif, struct notification_delta *delta, struct rrdp_state *state) { char tmppath[CACHE_TMPFILE_BUFLEN]; + struct uri const *url; int error; - pr_val_debug("Processing delta '%s'.", delta->meta.uri); - fnstack_push(delta->meta.uri); + url = &delta->meta.uri; - error = dl_tmp(delta->meta.uri, tmppath); + pr_val_debug("Processing delta '%s'.", uri_str(url)); + fnstack_push(uri_str(url)); + + error = dl_tmp(url, tmppath); if (error) goto end; error = parse_delta(notif, delta, tmppath, state); @@ -1150,7 +1160,7 @@ update_notif(struct rrdp_state *old, struct update_notification *new) } static int -dl_notif(char const *url, time_t mtim, bool *changed, +dl_notif(struct uri const *url, time_t mtim, bool *changed, struct update_notification *new) { char tmppath[CACHE_TMPFILE_BUFLEN]; @@ -1189,7 +1199,7 @@ dl_notif(char const *url, time_t mtim, bool *changed, * snapshot, and explodes them into @notif->path. */ int -rrdp_update(char const *notif, char const *path, time_t mtim, +rrdp_update(struct uri const *notif, char const *path, time_t mtim, bool *changed, struct rrdp_state **state) { struct rrdp_state *old; @@ -1197,7 +1207,7 @@ rrdp_update(char const *notif, char const *path, time_t mtim, int serial_cmp; int error; - fnstack_push(notif); + fnstack_push(uri_str(notif)); pr_val_debug("Processing notification."); error = dl_notif(notif, mtim, changed, &new); @@ -1288,18 +1298,20 @@ end: fnstack_pop(); } char const * -rrdp_file(struct rrdp_state const *state, char const *url) +rrdp_file(struct rrdp_state const *state, struct uri const *url) { struct cache_file *file; - file = state_find_file(state, url, strlen(url)); + file = state_find_file(state, url); return file ? file->map.path : NULL; } char const * -rrdp_create_fallback(char *cage, struct rrdp_state **_state, char const *url) +rrdp_create_fallback(char *cage, struct rrdp_state **_state, + struct uri const *url) { struct rrdp_state *state; struct cache_file *file; + char const *str; size_t len; state = *_state; @@ -1309,16 +1321,17 @@ rrdp_create_fallback(char *cage, struct rrdp_state **_state, char const *url) } file = pzalloc(sizeof(struct cache_file)); - file->map.url = pstrdup(url); + uri_copy(&file->map.url, url); file->map.path = cseq_next(&state->seq); if (!file->map.path) { - free(file->map.url); + uri_cleanup(&file->map.url); free(file); return NULL; } - len = strlen(file->map.url); - HASH_ADD_KEYPTR(hh, state->files, file->map.url, len, file); + str = uri_str(&file->map.url); + len = uri_len(&file->map.url); + HASH_ADD_KEYPTR(hh, state->files, str, len, file); return file->map.path; } @@ -1346,7 +1359,7 @@ files2json(struct rrdp_state *state) return NULL; HASH_ITER(hh, state->files, file, tmp) - if (json_add_str(json, file->map.url, file->map.path)) + if (json_add_str(json, uri_str(&file->map.url), file->map.path)) goto fail; return json; @@ -1456,6 +1469,7 @@ json2files(json_t *jparent, char *parent, struct rrdp_state *state) char const *jkey; json_t *jvalue; size_t parent_len; + struct uri url; char const *path; unsigned long id, max_id; int error; @@ -1476,25 +1490,33 @@ json2files(json_t *jparent, char *parent, struct rrdp_state *state) pr_op_warn("RRDP file URL '%s' is not a string.", jkey); continue; } + error = uri_init(&url, jkey); + if (error) { + pr_op_warn("Cannot parse '%s' as a URI.", jkey); + continue; + } - // XXX sanitize more + // XXX sanitize more? path = json_string_value(jvalue); if (strncmp(path, parent, parent_len) != 0 || path[parent_len] != '/') { pr_op_warn("RRDP path '%s' is not child of '%s'.", path, parent); + uri_cleanup(&url); continue; } error = hex2ulong(path + parent_len + 1, &id); if (error) { pr_op_warn("RRDP file '%s' is not a hexadecimal number.", path); + uri_cleanup(&url); continue; } if (id > max_id) max_id = id; - cache_file_add(state, pstrdup(jkey), pstrdup(path)); + cache_file_add(state, &url, pstrdup(path)); + uri_cleanup(&url); } if (HASH_COUNT(state->files) == 0) { @@ -1640,10 +1662,11 @@ rrdp_print(struct rrdp_state *rs) if (rs == NULL) return; - printf("session:%s/%s\n", rs->session.session_id, rs->session.serial.str); + /* printf("session:%s/%s\n", rs->session.session_id, rs->session.serial.str); */ + printf("\n"); HASH_ITER(hh, rs->files, file, tmp) - printf("\t\tfile: %s\n", /* file->map.url, */ file->map.path); - printf("\t\tseq:%s/%lx\n", rs->seq.prefix, rs->seq.next_id); + printf("\t\tfile: %s (%s)\n", file->map.path, uri_str(&file->map.url)); + printf("\t\tseq: %s/%lx\n", rs->seq.prefix, rs->seq.next_id); STAILQ_FOREACH(hash, &rs->delta_hashes, hook) { printf("\t\thash: "); diff --git a/src/rrdp.h b/src/rrdp.h index f0977ca8..ad67a898 100644 --- a/src/rrdp.h +++ b/src/rrdp.h @@ -6,14 +6,16 @@ #include #include "file.h" +#include "types/url.h" struct rrdp_state; -int rrdp_update(char const *, char const *, time_t, bool *, +int rrdp_update(struct uri const *, char const *, time_t, bool *, struct rrdp_state **); -char const *rrdp_file(struct rrdp_state const *, char const *); +char const *rrdp_file(struct rrdp_state const *, struct uri const *); -char const *rrdp_create_fallback(char *, struct rrdp_state **, char const *); +char const *rrdp_create_fallback(char *, struct rrdp_state **, + struct uri const *); json_t *rrdp_state2json(struct rrdp_state *); int rrdp_json2state(json_t *, char *, struct rrdp_state **); diff --git a/src/rsync.c b/src/rsync.c index 1bde288a..a8d869ec 100644 --- a/src/rsync.c +++ b/src/rsync.c @@ -49,7 +49,7 @@ struct { struct rsync_task { int pid; - char *url; + struct uri url; char *path; int stdoutfd; /* Child rsync's standard output */ int stderrfd; /* Child rsync's standard error */ @@ -131,7 +131,7 @@ notify_parent(struct rsync_task *task) * The asn1 code needs better error reporting. */ - if (RsyncRequest_init(&req, task->url, task->path) < 0) { + if (RsyncRequest_init(&req, &task->url, task->path) < 0) { pr_op_err(RSP "Cannot message parent process: " "The request object cannot be created"); return; @@ -157,7 +157,7 @@ void_task(struct rsync_task *task) { notify_parent(task); - free(task->url); + uri_cleanup(&task->url); free(task->path); free(task); } @@ -220,7 +220,7 @@ create_pipes(int fds[2][2]) } static void -prepare_rsync_args(char **args, char const *url, char const *path) +prepare_rsync_args(char **args, struct uri const *url, char const *path) { size_t i; @@ -231,7 +231,7 @@ prepare_rsync_args(char **args, char const *url, char const *path) for (i = 0; rsync_args[i] != NULL; i++) args[i] = (char *)rsync_args[i]; - args[i++] = (char *)url; + args[i++] = (char *)uri_str(url); args[i++] = (char *)path; args[i++] = NULL; } @@ -257,7 +257,7 @@ duplicate_fds(int fds[2][2]) } static int -execvp_rsync(char const *url, char const *path, int fds[2][2]) +execvp_rsync(struct uri const *url, char const *path, int fds[2][2]) { char *args[20]; @@ -296,7 +296,7 @@ fork_rsync(struct rsync_task *task) } if (task->pid == 0) /* Child code */ - exit(execvp_rsync(task->url, task->path, fork_fds)); + exit(execvp_rsync(&task->url, task->path, fork_fds)); /* Parent code */ @@ -322,6 +322,7 @@ activate_task(struct rsync_tasks *tasks, struct rsync_task *task, tasks->a++; } +/* Steals ownership of @map. */ static void post_task(struct cache_mapping *map, struct rsync_tasks *tasks, struct timespec *now) @@ -358,7 +359,9 @@ again: if (pssk.rd.len > 0) { switch (decres.code) { case RC_OK: - result->url = OCTET_STRING_toString(&pssk.rr->url); + __uri_init(&result->url, + OCTET_STRING_toString(&pssk.rr->url), + pssk.rr->url.size); result->path = OCTET_STRING_toString(&pssk.rr->path); ASN_STRUCT_RESET(asn_DEF_RsyncRequest, pssk.rr); return 0; @@ -557,7 +560,7 @@ activate_queued(struct rsync_tasks *tasks, struct timespec *now) return; pr_op_debug(RSP "Activating queued task %s -> %s.", - task->url, task->path); + uri_str(&task->url), task->path); LIST_REMOVE(task, lh); activate_task(tasks, task, now); } @@ -723,7 +726,7 @@ rcv_spawner_responses(void *arg) struct cache_mapping map = { 0 }; while (next_task(&map) == 0) { - rsync_finished(map.url, map.path); + rsync_finished(&map.url, map.path); map_cleanup(&map); } @@ -823,7 +826,7 @@ fail1: pr_op_warn("rsync will not be available."); * will be automatically called. */ int -rsync_queue(char const *url, char const *path) +rsync_queue(struct uri const *url, char const *path) { struct RsyncRequest req; asn_enc_rval_t result; diff --git a/src/rsync.h b/src/rsync.h index 2d85f147..5d451ca1 100644 --- a/src/rsync.h +++ b/src/rsync.h @@ -1,9 +1,11 @@ #ifndef SRC_RSYNC_RSYNC_H_ #define SRC_RSYNC_RSYNC_H_ +#include "types/url.h" + void rsync_setup(char const *, ...); -int rsync_queue(char const *, char const *); -void rsync_finished(char const *, char const *); +int rsync_queue(struct uri const *, char const *); +void rsync_finished(struct uri const *, char const *); void rsync_teardown(void); #endif /* SRC_RSYNC_RSYNC_H_ */ diff --git a/src/task.c b/src/task.c index b836f6c0..db4d6549 100644 --- a/src/task.c +++ b/src/task.c @@ -143,7 +143,7 @@ task_enqueue_rpp(struct cache_mapping *map, struct rpki_certificate *parent) atomic_fetch_add(&parent->refcount, 1); ca = pzalloc(sizeof(struct rpki_certificate)); - ca->map.url = pstrdup(map->url); + uri_copy(&ca->map.url, &map->url); ca->map.path = pstrdup(map->path); ca->parent = parent; atomic_init(&ca->refcount, 1); @@ -231,7 +231,7 @@ task_dequeue(struct validation_task *prev) STAILQ_REMOVE_HEAD(&waiting, lh); mutex_unlock(&lock); pr_op_debug("task_dequeue(): Claimed task '%s'.", - task->u.ca->map.url); + uri_str(&task->u.ca->map.url)); return task; } diff --git a/src/types/map.c b/src/types/map.c index 4eddaa56..1d3b642a 100644 --- a/src/types/map.c +++ b/src/types/map.c @@ -10,11 +10,11 @@ map_get_printable(struct cache_mapping const *map, enum filename_format format) { switch (format) { case FNF_GLOBAL: - return map->url; + return uri_str(&map->url); case FNF_LOCAL: return map->path; case FNF_NAME: - return path_filename(map->url); + return path_filename(uri_str(&map->url)); } pr_crit("Unknown file name format: %u", format); @@ -36,13 +36,13 @@ map_op_get_printable(struct cache_mapping const *map) void map_copy(struct cache_mapping *dst, struct cache_mapping const *src) { - dst->url = pstrdup(src->url); + uri_copy(&dst->url, &src->url); dst->path = pstrdup(src->path); } void map_cleanup(struct cache_mapping *map) { - free(map->url); + uri_cleanup(&map->url); free(map->path); } diff --git a/src/types/map.h b/src/types/map.h index c7d9a4e6..7d0c06a2 100644 --- a/src/types/map.h +++ b/src/types/map.h @@ -1,12 +1,12 @@ #ifndef SRC_TYPES_MAP_H_ #define SRC_TYPES_MAP_H_ +#include "types/url.h" + // XXX document this better struct cache_mapping { - /* Normalized, ASCII-only, NULL-terminated. */ - char *url; - /* Normalized, ASCII-only, NULL-terminated. */ - char *path; + struct uri url; /* Normalized */ + char *path; /* Normalized */ }; char const *map_val_get_printable(struct cache_mapping const *); diff --git a/src/types/str.c b/src/types/str.c index cbc9a174..671170be 100644 --- a/src/types/str.c +++ b/src/types/str.c @@ -1,8 +1,11 @@ #include "types/str.h" #include +#include #include +#include "alloc.h" +#include "array.h" #include "log.h" #include "types/path.h" @@ -58,10 +61,28 @@ string_clone(void const *string, size_t size) int ia5s2string(ASN1_IA5STRING *ia5, char **result) { - if (ia5->flags & ASN1_STRING_FLAG_BITS_LEFT) - return pr_val_err("CRL URI IA5String has unused bits."); + unsigned char const *data; + size_t len; + array_index i; + + /* Implementation-aware */ + if (ia5->flags & ASN1_STRING_FLAG_BITS_LEFT) { + pr_val_warn("CRL URI IA5String has unused bits."); + return EINVAL; + } - *result = string_clone(ia5->data, ia5->length); + /* TODO (asn1c) This might already be done by the asn1 code. */ + data = ASN1_STRING_get0_data(ia5); + len = ASN1_STRING_length(ia5); + for (i = 0; i < len; i++) + if (data[i] == 0) { + pr_val_warn("Null character found in IA5String index %zu. (Length: %zu)", + i, len); + return EINVAL; + } + + /* No NULL termination guarantee */ + *result = pstrndup((char const *)data, len); return 0; } @@ -172,39 +193,3 @@ token_count(struct string_tokenizer *tokenizer) return count; } - -void -strlist_init(struct strlist *list) -{ - list->array = NULL; - list->len = 0; - list->capacity = 0; -} - -void -strlist_add(struct strlist *list, char *str) -{ - if (list->array == NULL) { - list->capacity = 8; - list->array = pmalloc(list->capacity * sizeof(char *)); - } - - list->len++; - while (list->len >= list->capacity) { - list->capacity *= 2; - list->array = prealloc(list->array, - list->capacity * sizeof(char *)); - } - - list->array[list->len - 1] = str; -} - -/* Call strlist_init() again if you want to reuse the list. */ -void -strlist_cleanup(struct strlist *list) -{ - array_index i; - for (i = 0; i < list->len; i++) - free(list->array[i]); - free(list->array); -} diff --git a/src/types/str.h b/src/types/str.h index 7f6ebc46..6963ea46 100644 --- a/src/types/str.h +++ b/src/types/str.h @@ -5,8 +5,6 @@ #include #include -#include "types/arraylist.h" - char *str_concat(char const *, char const *); int hex2ulong(char const *, unsigned long *); @@ -39,12 +37,4 @@ bool token_equals(struct string_tokenizer *, struct string_tokenizer *); char *token_read(struct string_tokenizer *); size_t token_count(struct string_tokenizer *); -/* Plural */ - -DEFINE_ARRAY_LIST_STRUCT(strlist, char *); - -void strlist_init(struct strlist *); -void strlist_cleanup(struct strlist *); -void strlist_add(struct strlist *, char *); - #endif /* SRC_TYPES_STR_H_ */ diff --git a/src/types/url.c b/src/types/url.c index 24ad0a41..67ccc886 100644 --- a/src/types/url.c +++ b/src/types/url.c @@ -1,6 +1,7 @@ #include "types/url.h" #include +#include #include "alloc.h" #include "common.h" @@ -8,15 +9,15 @@ #include "types/path.h" bool -url_is_rsync(char const *url) +uri_is_rsync(struct uri const *url) { - return str_starts_with(url, "rsync://"); + return str_starts_with(url->_str, "rsync://"); } bool -url_is_https(char const *url) +uri_is_https(struct uri const *url) { - return str_starts_with(url, "https://"); + return str_starts_with(url->_str, "https://"); } /* @@ -55,11 +56,11 @@ validate_url_characters(char const *str) * whose implementation is somewhat flawed (at least until version 8.12.1): * https://github.com/curl/curl/issues/16829 * - * On the other hand, since Fort 2 no longer maps URI paths to literal local - * paths, all normalization does for us is prevent some theoretical redundant - * downloading, so it might not even be that necessary. + * That said, since Fort 2 no longer maps URI paths to literal local paths, all + * normalization does for us is prevent some theoretical redundant downloading, + * so it's fine. */ -char * +static char * url_normalize(char const *url) { CURLU *curlu; @@ -99,21 +100,80 @@ einval: pr_val_err("Error parsing URL: %s", curl_url_strerror(err)); return NULL; } -char * -url_parent(char const *child) +int +uri_init(struct uri *url, char const *str) { - char *slash = strrchr(child, '/'); - return (slash != NULL) ? pstrndup(child, slash - child) : NULL; + str = url_normalize(str); + if (!str) + return EINVAL; + + __URI_INIT(url, str); + return 0; +} + +/* @str must already be normalized. */ +void +__uri_init(struct uri *url, char const *str, size_t len) +{ + url->_str = (char *)str; + url->_len = len; +} + +void +uri_copy(struct uri *dst, struct uri const *src) +{ + dst->_str = src->_str ? pstrdup(src->_str) : NULL; + dst->_len = src->_len; +} + +void +uri_cleanup(struct uri *url) +{ + free(url->_str); + url->_str = NULL; +} + +bool +uri_equals(struct uri const *u1, struct uri const *u2) +{ + return (u1->_len == u2->_len) + ? (memcmp(u1->_str, u2->_str, u1->_len) == 0) + : false; +} + +bool +uri_has_extension(struct uri const *url, char const *ext) +{ + return strcmp(url->_str + url->_len - strlen(ext), ext) == 0; +} + +/* Result is a shallow copy; do not clean. */ +int +uri_parent(struct uri const *child, struct uri *parent) +{ + char *slash; + + slash = strrchr(child->_str, '/'); + if (slash == NULL) + return EINVAL; + + parent->_str = child->_str; + parent->_len = slash - child->_str; + return 0; } bool -url_same_origin(char const *url1, char const *url2) +uri_same_origin(struct uri const *uri1, struct uri const *uri2) { + char const *str1, *str2; size_t c, slashes; + str1 = uri1->_str; + str2 = uri2->_str; slashes = 0; - for (c = 0; url1[c] == url2[c]; c++) { - switch (url1[c]) { + + for (c = 0; str1[c] == str2[c]; c++) { + switch (str1[c]) { case '/': slashes++; if (slashes == 3) @@ -124,10 +184,29 @@ url_same_origin(char const *url1, char const *url2) } } - if (url1[c] == '\0') - return (slashes == 2) && url2[c] == '/'; - if (url2[c] == '\0') - return (slashes == 2) && url1[c] == '/'; + if (str1[c] == '\0') + return (slashes == 2) && str2[c] == '/'; + if (str2[c] == '\0') + return (slashes == 2) && str1[c] == '/'; return false; } + +void +uri_child(struct uri const *parent, char const *name, size_t len, + struct uri *child) +{ + size_t slash; + + slash = parent->_str[parent->_len - 1] != '/'; + + child->_len = parent->_len + slash + len; + child->_str = pmalloc(child->_len + 1); + strncpy(child->_str, parent->_str, parent->_len); + if (slash) + child->_str[parent->_len] = '/'; + strncpy(child->_str + parent->_len + slash, name, len); + child->_str[child->_len] = '\0'; +} + +DEFINE_ARRAY_LIST_FUNCTIONS(uris, struct uri, ) diff --git a/src/types/url.h b/src/types/url.h index 86c93feb..f4f761a7 100644 --- a/src/types/url.h +++ b/src/types/url.h @@ -2,14 +2,40 @@ #define SRC_TYPES_URL_H_ #include +#include + +#include "types/arraylist.h" #define RPKI_SCHEMA_LEN 8 /* strlen("rsync://"), strlen("https://") */ -bool url_is_rsync(char const *); -bool url_is_https(char const *); +struct uri { + char *_str; + size_t _len; +}; + +int uri_init(struct uri *, char const *); +void __uri_init(struct uri *, char const *, size_t); +#define __URI_INIT(uri, str) __uri_init(uri, str, strlen(str)) +void uri_copy(struct uri *, struct uri const *); +void uri_cleanup(struct uri *); + +#define uri_str(u) ((char const *)((u)->_str)) +#define uri_len(u) ((u)->_len) + +bool uri_is_rsync(struct uri const *); +bool uri_is_https(struct uri const *); + +bool uri_equals(struct uri const *, struct uri const *); +bool uri_has_extension(struct uri const *, char const *); +bool uri_same_origin(struct uri const *, struct uri const *); + +int uri_parent(struct uri const *, struct uri *); +void uri_child(struct uri const *, char const *, size_t, struct uri *); +#define URI_CHILD(uri, name, child) uri_child(uri, name, strlen(name), child) + +/* Plural */ -char *url_normalize(char const *); -char *url_parent(char const *); -bool url_same_origin(char const *, char const *); +DEFINE_ARRAY_LIST_STRUCT(uris, struct uri); +DECLARE_ARRAY_LIST_FUNCTIONS(uris, struct uri) #endif /* SRC_TYPES_URL_H_ */ diff --git a/test/Makefile.am b/test/Makefile.am index 416d13eb..0b44a83e 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -45,6 +45,7 @@ base64_test_LDADD = ${CHECK_LIBS} check_PROGRAMS += cache.test cache_test_SOURCES = cache_test.c cache_test_LDADD = ${CHECK_LIBS} +cache_test_LDADD += ${CURL_LIBS} cache_test_LDADD += ${XML2_LIBS} cache_test_LDADD += ${JANSSON_LIBS} @@ -79,18 +80,21 @@ pdu_stream_test_LDADD = ${CHECK_LIBS} check_PROGRAMS += rrdp.test rrdp_test_SOURCES = rrdp_test.c rrdp_test_LDADD = ${CHECK_LIBS} +rrdp_test_LDADD += ${CURL_LIBS} rrdp_test_LDADD += ${XML2_LIBS} rrdp_test_LDADD += ${JANSSON_LIBS} check_PROGRAMS += rrdp_update.test rrdp_update_test_SOURCES = rrdp_update_test.c rrdp_update_test_LDADD = ${CHECK_LIBS} +rrdp_update_test_LDADD += ${CURL_LIBS} rrdp_update_test_LDADD += ${XML2_LIBS} rrdp_update_test_LDADD += ${JANSSON_LIBS} check_PROGRAMS += rsync.test rsync_test_SOURCES = rsync_test.c rsync_test_LDADD = ${CHECK_LIBS} +rsync_test_LDADD += ${CURL_LIBS} check_PROGRAMS += serial.test serial_test_SOURCES = types/serial_test.c @@ -103,6 +107,7 @@ serial_test_LDADD = ${CHECK_LIBS} check_PROGRAMS += tal.test tal_test_SOURCES = object/tal_test.c tal_test_LDADD = ${CHECK_LIBS} +tal_test_LDADD += ${CURL_LIBS} check_PROGRAMS += task.test task_test_SOURCES = task_test.c diff --git a/test/cache_test.c b/test/cache_test.c index 1634624d..feb0f1d9 100644 --- a/test/cache_test.c +++ b/test/cache_test.c @@ -48,11 +48,11 @@ touch_file(char const *dir) ck_assert_int_eq(0, system(cmd)); } -static char *queued_url; +static struct uri queued_url; static char *queued_path; int -rsync_queue(char const *url, char const *path) +rsync_queue(struct uri const *url, char const *path) { rsync_counter++; @@ -61,11 +61,11 @@ rsync_queue(char const *url, char const *path) return dl_error; } - printf("Simulating rsync: %s -> %s\n", url, path); + printf("Simulating rsync: %s -> %s\n", uri_str(url), path); ck_assert_int_eq(0, mkdir(path, CACHE_FILEMODE)); touch_file(path); - queued_url = pstrdup(url); + uri_copy(&queued_url, url); queued_path = pstrdup(path); return 0; @@ -108,8 +108,11 @@ setup_test(void) static struct cache_cage * run_dl_rsync(char *caRepository, int expected_err, unsigned int expected_calls) { - struct sia_uris sias = { .caRepository = caRepository }; - struct cache_cage *cage = NULL; + struct sia_uris sias = { 0 }; + struct cache_cage *cage; + + ck_assert_int_eq(0, uri_init(&sias.caRepository, caRepository)); + cage = NULL; rsync_counter = 0; https_counter = 0; @@ -119,14 +122,15 @@ run_dl_rsync(char *caRepository, int expected_err, unsigned int expected_calls) ck_assert_uint_eq(expected_calls, rsync_counter); ck_assert_uint_eq(0, https_counter); + uri_cleanup(&sias.caRepository); return cage; } static void finish_rsync(void) { - rsync_finished(queued_url, queued_path); - free(queued_url); + rsync_finished(&queued_url, queued_path); + uri_cleanup(&queued_url); free(queued_path); } @@ -142,18 +146,23 @@ static void run_dl_https(char const *url, unsigned int expected_calls, char const *expected_result) { + struct uri uri; char const *result; + ck_assert_int_eq(0, uri_init(&uri, url)); + rsync_counter = 0; https_counter = 0; printf("---- Downloading... ----\n"); - result = cache_refresh_by_url(url); + result = cache_refresh_by_url(&uri); printf("---- Downloaded. ----\n"); ck_assert_uint_eq(0, rsync_counter); ck_assert_uint_eq(expected_calls, https_counter); ck_assert_str(expected_result, result); - ck_assert_str(NULL, cache_get_fallback(url)); + ck_assert_str(NULL, cache_get_fallback(&uri)); + + uri_cleanup(&uri); } @@ -161,16 +170,19 @@ static void ck_cage(struct cache_cage *cage, char const *url, char const *refresh, char const *fallback) { + struct uri uri; struct cache_node const *bkp; - ck_assert_str(refresh, cage_map_file(cage, url)); + ck_assert_int_eq(0, uri_init(&uri, url)); + + ck_assert_str(refresh, cage_map_file(cage, &uri)); bkp = cage->refresh; cage_disable_refresh(cage); - - ck_assert_str(fallback, cage_map_file(cage, url)); - + ck_assert_str(fallback, cage_map_file(cage, &uri)); cage->refresh = bkp; + + uri_cleanup(&uri); } static int @@ -198,15 +210,28 @@ queue_commit(char const *rpkiNotify, char const *caRepository, char const *path1, char const *path2) { struct rpp rpp = { 0 }; + struct uri rn, cr; + + if (rpkiNotify) + ck_assert_int_eq(0, uri_init(&rn, rpkiNotify)); + else + memset(&rn, 0, sizeof(rn)); + if (caRepository) + ck_assert_int_eq(0, uri_init(&cr, caRepository)); + else + memset(&cr, 0, sizeof(cr)); rpp.nfiles = 2; rpp.files = pzalloc(rpp.nfiles * sizeof(struct cache_mapping)); - rpp.files[0].url = path_join(caRepository, "manifest.mft"); + URI_CHILD(&cr, "manifest.mft", &rpp.files[0].url); rpp.files[0].path = pstrdup(path1); - rpp.files[1].url = path_join(caRepository, "cert.cer"); + URI_CHILD(&cr, "cert.cer", &rpp.files[1].url); rpp.files[1].path = pstrdup(path2); - cache_commit_rpp(rpkiNotify, caRepository, &rpp); + cache_commit_rpp(&rn, &cr, &rpp); + + uri_cleanup(&cr); + uri_cleanup(&rn); } /* Only validates the first character of the file. */ @@ -277,7 +302,7 @@ init_node_rsync(struct cache_node *node, char *url, char *path, { node->key.id = url; node->key.idlen = strlen(url); - node->key.rsync = url; + ck_assert_int_eq(0, uri_init(&node->key.rsync, url)); node->path = path; node->state = fresh ? DLS_FRESH : DLS_OUTDATED; /* XXX (test) */ node->dlerr = dlerr; @@ -290,7 +315,7 @@ init_node_https(struct cache_node *node, char *url, char *path, { node->key.id = url; node->key.idlen = strlen(url); - node->key.http = url; + ck_assert_int_eq(0, uri_init(&node->key.http, url)); node->path = path; node->state = fresh ? DLS_FRESH : DLS_OUTDATED; node->dlerr = dlerr; @@ -300,14 +325,8 @@ init_node_https(struct cache_node *node, char *url, char *path, static void ck_node_key(struct node_key *expected, struct node_key *actual) { - if (expected->http) - ck_assert_str_eq(expected->http, actual->http); - else - ck_assert_ptr_eq(NULL, actual->http); - if (expected->rsync) - ck_assert_str_eq(expected->rsync, actual->rsync); - else - ck_assert_ptr_eq(NULL, actual->rsync); + ck_assert(uri_equals(&expected->http, &actual->http)); + ck_assert(uri_equals(&expected->rsync, &actual->rsync)); ck_assert_uint_eq(expected->idlen, actual->idlen); ck_assert_mem_eq(expected->id, actual->id, expected->idlen); } @@ -663,12 +682,16 @@ START_TEST(test_https_cleanup) } /* 3 */ - map.url = "https://domain/rpki/ta50.cer"; - map.path = "https/50"; + ck_assert_int_eq(0, uri_init(&map.url, "https://domain/rpki/ta50.cer")); + map.path = pstrdup("https/50"); cache_commit_file(&map); - map.url = "https://domain/rpki/ta52.cer"; - map.path = "https/52"; + map_cleanup(&map); + + ck_assert_int_eq(0, uri_init(&map.url, "https://domain/rpki/ta52.cer")); + map.path = pstrdup("https/52"); cache_commit_file(&map); + map_cleanup(&map); + cleanup_cache(); ck_filesystem("fallback", "fallback/0", "A", "fallback/0.json", "{", @@ -678,12 +701,16 @@ START_TEST(test_https_cleanup) new_iteration(false); /* 4 */ - map.url = "https://domain/rpki/ta50.cer"; - map.path = "fallback/0"; + ck_assert_int_eq(0, uri_init(&map.url, "https://domain/rpki/ta50.cer")); + map.path = pstrdup("fallback/0"); cache_commit_file(&map); - map.url = "https://domain/rpki/ta51.cer"; - map.path = "https/51"; + map_cleanup(&map); + + ck_assert_int_eq(0, uri_init(&map.url, "https://domain/rpki/ta51.cer")); + map.path = pstrdup("https/51"); cache_commit_file(&map); + map_cleanup(&map); + cleanup_cache(); ck_filesystem("fallback", "fallback/0", "A", "fallback/0.json", "{", @@ -774,6 +801,7 @@ START_TEST(test_context) char *FILE_RSYNC_PATH = "rsync/0/rpp3/a.cer"; struct sia_uris sias = { 0 }; + struct uri file_url; struct cache_cage *cage; struct rpp rpp = { 0 }; @@ -788,58 +816,69 @@ START_TEST(test_context) dls[1] = SHDR("3") PBLSH("rsync://x.y.z/mod5/rpp3/a.cer", "Rm9ydAo=") STAIL; dls[2] = NULL; - /* 1. 1st CA succeeds on RRDP */ - sias.rpkiNotify = RPKI_NOTIFY; - sias.caRepository = CA_REPOSITORY; + ck_assert_int_eq(0, uri_init(&file_url, FILE_URL)); + + printf("1. 1st CA succeeds on RRDP\n"); + print_tree(); + ck_assert_int_eq(0, uri_init(&sias.rpkiNotify, RPKI_NOTIFY)); + ck_assert_int_eq(0, uri_init(&sias.caRepository, CA_REPOSITORY)); ck_assert_int_eq(0, cache_refresh_by_sias(&sias, &cage)); - ck_assert_str_eq(RPKI_NOTIFY, cage->rpkiNotify); - ck_assert_str_eq(FILE_RRDP_PATH, cage_map_file(cage, FILE_URL)); + ck_assert_str_eq(RPKI_NOTIFY, uri_str(&cage->rpkiNotify)); + ck_assert_str_eq(FILE_RRDP_PATH, cage_map_file(cage, &file_url)); ck_assert_int_eq(false, cage_disable_refresh(cage)); - ck_assert_ptr_eq(NULL, cage_map_file(cage, FILE_URL)); + ck_assert_ptr_eq(NULL, cage_map_file(cage, &file_url)); - /* - * 2. 2nd CA points to the same caRepository, - * but does not provide RRDP as an option. - */ - sias.rpkiNotify = NULL; + printf("2. 2nd CA points to the same caRepository,\n"); + printf(" but does not provide RRDP as an option.\n"); + print_tree(); + uri_cleanup(&sias.rpkiNotify); ck_assert_int_eq(EBUSY, cache_refresh_by_sias(&sias, &cage)); finish_rsync(); ck_assert_int_eq(0, cache_refresh_by_sias(&sias, &cage)); - ck_assert_ptr_eq(NULL, cage->rpkiNotify); - ck_assert_str_eq(FILE_RSYNC_PATH, cage_map_file(cage, FILE_URL)); + ck_assert_ptr_eq(NULL, uri_str(&cage->rpkiNotify)); + ck_assert_str_eq(FILE_RSYNC_PATH, cage_map_file(cage, &file_url)); ck_assert_int_eq(false, cage_disable_refresh(cage)); - ck_assert_ptr_eq(NULL, cage_map_file(cage, FILE_URL)); + ck_assert_ptr_eq(NULL, cage_map_file(cage, &file_url)); + + printf("3. Commit\n"); - /* 3. Commit */ + print_tree(); rpp.nfiles = 1; rpp.files = pzalloc(sizeof(struct cache_mapping)); - rpp.files->url = pstrdup(FILE_URL); + uri_copy(&rpp.files->url, &file_url); rpp.files->path = pstrdup(FILE_RRDP_PATH); - cache_commit_rpp(RPKI_NOTIFY, CA_REPOSITORY, &rpp); + ck_assert_int_eq(0, uri_init(&sias.rpkiNotify, RPKI_NOTIFY)); + cache_commit_rpp(&sias.rpkiNotify, &sias.caRepository, &rpp); rpp.nfiles = 1; rpp.files = pzalloc(sizeof(struct cache_mapping)); - rpp.files->url = pstrdup(FILE_URL); + uri_copy(&rpp.files->url, &file_url); rpp.files->path = pstrdup(FILE_RSYNC_PATH); - cache_commit_rpp(NULL, CA_REPOSITORY, &rpp); + uri_cleanup(&sias.rpkiNotify); + cache_commit_rpp(&sias.rpkiNotify, &sias.caRepository, &rpp); commit_fallbacks(time_fatal()); - /* 4. Redo both CAs, check the fallbacks too */ + printf("4. Redo both CAs, check the fallbacks too\n"); + print_tree(); ck_assert_int_eq(0, cache_refresh_by_sias(&sias, &cage)); - ck_assert_ptr_eq(NULL, cage->rpkiNotify); - ck_assert_str_eq(FILE_RSYNC_PATH, cage_map_file(cage, FILE_URL)); + ck_assert_ptr_eq(NULL, uri_str(&cage->rpkiNotify)); + ck_assert_str_eq(FILE_RSYNC_PATH, cage_map_file(cage, &file_url)); ck_assert_int_eq(true, cage_disable_refresh(cage)); - ck_assert_str_eq("fallback/1/0", cage_map_file(cage, FILE_URL)); + ck_assert_str_eq("fallback/1/0", cage_map_file(cage, &file_url)); - sias.rpkiNotify = RPKI_NOTIFY; + ck_assert_int_eq(0, uri_init(&sias.rpkiNotify, RPKI_NOTIFY)); ck_assert_int_eq(0, cache_refresh_by_sias(&sias, &cage)); - ck_assert_str_eq(RPKI_NOTIFY, cage->rpkiNotify); - ck_assert_str_eq(FILE_RRDP_PATH, cage_map_file(cage, FILE_URL)); + ck_assert_str_eq(RPKI_NOTIFY, uri_str(&cage->rpkiNotify)); + ck_assert_str_eq(FILE_RRDP_PATH, cage_map_file(cage, &file_url)); ck_assert_int_eq(true, cage_disable_refresh(cage)); - ck_assert_str_eq("fallback/0/0", cage_map_file(cage, FILE_URL)); + ck_assert_str_eq("fallback/0/0", cage_map_file(cage, &file_url)); + + uri_cleanup(&sias.rpkiNotify); + uri_cleanup(&sias.caRepository); + uri_cleanup(&file_url); cleanup_test(); relax_ng_cleanup(); @@ -865,9 +904,9 @@ ck_rrdp(struct rrdp_state *expected, struct rrdp_state *actual) ck_assert_int_eq(HASH_COUNT(expected->files), HASH_COUNT(actual->files)); HASH_ITER(hh, expected->files, expf, tmp) { - HASH_FIND(hh, actual->files, expf->map.url, strlen(expf->map.url), actf); + HASH_FIND(hh, actual->files, uri_str(&expf->map.url), uri_len(&expf->map.url), actf); ck_assert_ptr_ne(NULL, actf); - ck_assert_str_eq(expf->map.url, actf->map.url); + ck_assert(uri_equals(&expf->map.url, &actf->map.url)); ck_assert_str_eq(expf->map.path, actf->map.path); } @@ -913,7 +952,7 @@ START_TEST(test_json_min) node->key.id = pstrdup("https://a.b.c/sample.cer"); node->key.idlen = strlen(node->key.id); - node->key.http = node->key.id; + __uri_init(&node->key.http, node->key.id, node->key.idlen); node->path = pstrdup("tmp/sample.cer"); node->state = DLS_FRESH; node->dlerr = ENOENT; @@ -921,13 +960,23 @@ START_TEST(test_json_min) ck_json(node); } +static void +CACHE_FILE_ADD(struct rrdp_state *state, char const *url, char *path) +{ + struct uri uri; + + ck_assert_int_eq(0, uri_init(&uri, url)); + ck_assert_ptr_ne(NULL, cache_file_add(state, &uri, pstrdup(path))); + uri_cleanup(&uri); +} + START_TEST(test_json_rrdp_min) { struct cache_node *node = pzalloc(sizeof(struct cache_node)); node->key.id = pstrdup("https://a.b.c/sample.cer"); node->key.idlen = strlen(node->key.id); - node->key.http = node->key.id; + __uri_init(&node->key.http, node->key.id, node->key.idlen); node->path = pstrdup("rrdp/123"); node->state = DLS_FRESH; node->dlerr = ENOENT; @@ -938,7 +987,7 @@ START_TEST(test_json_rrdp_min) ck_assert_ptr_ne(NULL, node->rrdp->session.serial.num); BN_add_word(node->rrdp->session.serial.num, 1357); node->rrdp->session.serial.str = pstrdup("1357"); - cache_file_add(node->rrdp, pstrdup("rsync://a.b.c/d/e.mft"), pstrdup("rrdp/123/0")); + CACHE_FILE_ADD(node->rrdp, "rsync://a.b.c/d/e.mft", "rrdp/123/0"); cseq_init(&node->rrdp->seq, node->path, 1, false); STAILQ_INIT(&node->rrdp->delta_hashes); @@ -952,7 +1001,7 @@ START_TEST(test_json_max) node->key.id = pstrdup("https://a.b.c/sample.cer"); node->key.idlen = strlen(node->key.id); - node->key.http = node->key.id; + __uri_init(&node->key.http, node->key.id, node->key.idlen); node->path = pstrdup("rrdp/123"); node->state = DLS_FRESH; node->dlerr = ENOENT; @@ -967,8 +1016,8 @@ START_TEST(test_json_max) ck_assert_ptr_ne(NULL, node->rrdp->session.serial.num); BN_add_word(node->rrdp->session.serial.num, 1357); node->rrdp->session.serial.str = pstrdup("1357"); - cache_file_add(node->rrdp, pstrdup("rsync://a.b.c/d/e.mft"), pstrdup("rrdp/123/0")); - cache_file_add(node->rrdp, pstrdup("rsync://a.b.c/d/f.crl"), pstrdup("rrdp/123/1")); + CACHE_FILE_ADD(node->rrdp, "rsync://a.b.c/d/e.mft", "rrdp/123/0"); + CACHE_FILE_ADD(node->rrdp, "rsync://a.b.c/d/f.crl", "rrdp/123/1"); cseq_init(&node->rrdp->seq, node->path, 2, false); STAILQ_INIT(&node->rrdp->delta_hashes); hash = pmalloc(sizeof(struct rrdp_hash)); @@ -985,15 +1034,20 @@ START_TEST(test_json_weirdurl) { static char const *NOTIF = "https://a.b.c/notif.xml"; static char const *CAREPO = "rsync://a.b.c/rpp"; + size_t nlen; + size_t clen; + struct cache_node *node; - struct cache_node *node = pzalloc(sizeof(struct cache_node)); + nlen = strlen(NOTIF); + clen = strlen(CAREPO); + node = pzalloc(sizeof(struct cache_node)); - node->key.idlen = strlen(NOTIF) + strlen(CAREPO) + 1; + node->key.idlen = nlen + clen + 1; node->key.id = pmalloc(node->key.idlen + 1); strcpy(node->key.id, NOTIF); - strcpy(node->key.id + strlen(NOTIF) + 1, CAREPO); - node->key.http = node->key.id; - node->key.rsync = node->key.id + strlen(NOTIF) + 1; + strcpy(node->key.id + nlen + 1, CAREPO); + __uri_init(&node->key.http, node->key.id, nlen); + __uri_init(&node->key.rsync, node->key.id + nlen + 1, clen); node->path = pstrdup("tmp/sample.cer"); node->state = DLS_FRESH; node->dlerr = ENOENT; diff --git a/test/mock.c b/test/mock.c index f79e3199..b16de804 100644 --- a/test/mock.c +++ b/test/mock.c @@ -148,3 +148,10 @@ ck_assert_str(char const *expected, char const *actual) else ck_assert_ptr_eq(NULL, actual); } + +void +ck_assert_uri(char const *expected, struct uri const *actual) +{ + ck_assert_str_eq(expected, uri_str(actual)); + ck_assert_uint_eq(strlen(expected), uri_len(actual)); +} diff --git a/test/mock_https.c b/test/mock_https.c index e1d4e210..4f783265 100644 --- a/test/mock_https.c +++ b/test/mock_https.c @@ -8,7 +8,8 @@ static char const *dls[8]; static unsigned int https_counter; /* Times http_download() was called */ int -http_download(char const *url, char const *path, curl_off_t ims, bool *changed) +http_download(struct uri const *url, char const *path, + curl_off_t ims, bool *changed) { char const *content; @@ -20,7 +21,7 @@ http_download(char const *url, char const *path, curl_off_t ims, bool *changed) return dl_error; } - printf("Simulating HTTP download: %s -> %s\n", url, path); + printf("Simulating HTTP download: %s -> %s\n", uri_str(url), path); content = dls[https_counter++]; if (!content) diff --git a/test/object/tal_test.c b/test/object/tal_test.c index eca8ab8c..20135aca 100644 --- a/test/object/tal_test.c +++ b/test/object/tal_test.c @@ -59,7 +59,7 @@ test_1url(char const *file) ck_assert_int_eq(0, tal_init(&tal, file)); ck_assert_uint_eq(1, tal.urls.len); - ck_assert_str_eq("rsync://example.com/rpki/ta.cer", tal.urls.array[0]); + ck_assert_uri("rsync://example.com/rpki/ta.cer", &tal.urls.array[0]); check_spki(&tal); tal_cleanup(&tal); @@ -80,10 +80,10 @@ test_4urls(char const *file) ck_assert_int_eq(0, tal_init(&tal, file)); ck_assert_uint_eq(4, tal.urls.len); - ck_assert_str_eq("rsync://example.com/rpki/ta.cer", tal.urls.array[0]); - ck_assert_str_eq("https://example.com/rpki/ta.cer", tal.urls.array[1]); - ck_assert_str_eq("rsync://www.example.com/potato/ta.cer", tal.urls.array[2]); - ck_assert_str_eq("https://wx3.example.com/tomato/ta.cer", tal.urls.array[3]); + ck_assert_uri("rsync://example.com/rpki/ta.cer", &tal.urls.array[0]); + ck_assert_uri("https://example.com/rpki/ta.cer", &tal.urls.array[1]); + ck_assert_uri("rsync://www.example.com/potato/ta.cer", &tal.urls.array[2]); + ck_assert_uri("https://wx3.example.com/tomato/ta.cer", &tal.urls.array[3]); check_spki(&tal); diff --git a/test/rrdp_test.c b/test/rrdp_test.c index 445354b0..90c8ed4d 100644 --- a/test/rrdp_test.c +++ b/test/rrdp_test.c @@ -288,7 +288,7 @@ init_rrdp_state(struct rrdp_state **result, struct rrdp_hash *hash; size_t i; - notif = pmalloc(sizeof(struct rrdp_state)); + notif = pzalloc(sizeof(struct rrdp_state)); *result = notif; init_rrdp_session(¬if->session, serial); @@ -319,7 +319,7 @@ init_regular_notif(struct update_notification *notif, unsigned long serial, ...) va_start(args, serial); while ((hash_byte = va_arg(args, int)) >= 0) { init_serial(&delta.serial, serial--); - delta.meta.uri = NULL; /* Not needed for now */ + memset(&delta.meta.uri, 0, sizeof(delta.meta.uri)); /* Not needed for now */ delta.meta.hash = pmalloc(RRDP_HASH_LEN); for (i = 0; i < RRDP_HASH_LEN; i++) delta.meta.hash[i] = hash_byte; @@ -400,30 +400,33 @@ END_TEST START_TEST(test_parse_notification_ok) { struct update_notification notif; + struct uri nurl; ck_assert_int_eq(0, relax_ng_init()); - ck_assert_int_eq(0, parse_notification("https://host/notification.xml", + ck_assert_int_eq(0, uri_init(&nurl, "https://host/notification.xml")); + ck_assert_int_eq(0, parse_notification(&nurl, "resources/rrdp/notif-ok.xml", ¬if)); + uri_cleanup(&nurl); ck_assert_str_eq("9df4b597-af9e-4dca-bdda-719cce2c4e28", (char const *)notif.session.session_id); ck_assert_str_eq("3", (char const *)notif.session.serial.str); - ck_assert_str_eq("https://host/9d-8/3/snapshot.xml", notif.snapshot.uri); + ck_assert_uri("https://host/9d-8/3/snapshot.xml", ¬if.snapshot.uri); ck_assert_uint_eq(32, notif.snapshot.hash_len); validate_aaaa_hash(notif.snapshot.hash); ck_assert_uint_eq(2, notif.deltas.len); ck_assert_str_eq("2", (char const *)notif.deltas.array[0].serial.str); - ck_assert_str_eq("https://host/9d-8/2/delta.xml", - notif.deltas.array[0].meta.uri); + ck_assert_uri("https://host/9d-8/2/delta.xml", + ¬if.deltas.array[0].meta.uri); ck_assert_uint_eq(32, notif.deltas.array[0].meta.hash_len); validate_01234_hash(notif.deltas.array[0].meta.hash); ck_assert_str_eq("3", (char const *)notif.deltas.array[1].serial.str); - ck_assert_str_eq("https://host/9d-8/3/delta.xml", - notif.deltas.array[1].meta.uri); + ck_assert_uri("https://host/9d-8/3/delta.xml", + ¬if.deltas.array[1].meta.uri); ck_assert_uint_eq(32, notif.deltas.array[1].meta.hash_len); validate_01234_hash(notif.deltas.array[0].meta.hash); @@ -435,16 +438,19 @@ END_TEST START_TEST(test_parse_notification_0deltas) { struct update_notification notif; + struct uri nurl; ck_assert_int_eq(0, relax_ng_init()); - ck_assert_int_eq(0, parse_notification("https://host/notification.xml", + ck_assert_int_eq(0, uri_init(&nurl, "https://host/notification.xml")); + ck_assert_int_eq(0, parse_notification(&nurl, "resources/rrdp/notif-0deltas.xml", ¬if)); + uri_cleanup(&nurl); ck_assert_str_eq("9df4b597-af9e-4dca-bdda-719cce2c4e28", (char const *)notif.session.session_id); ck_assert_str_eq("3", (char const *)notif.session.serial.str); - ck_assert_str_eq("https://host/9d-8/3/snapshot.xml", notif.snapshot.uri); + ck_assert_uri("https://host/9d-8/3/snapshot.xml", ¬if.snapshot.uri); ck_assert_uint_eq(32, notif.snapshot.hash_len); validate_01234_hash(notif.snapshot.hash); @@ -458,10 +464,13 @@ END_TEST START_TEST(test_parse_notification_large_serial) { struct update_notification notif; + struct uri nurl; ck_assert_int_eq(0, relax_ng_init()); - ck_assert_int_eq(0, parse_notification("https://host/notification.xml", + ck_assert_int_eq(0, uri_init(&nurl, "https://host/notification.xml")); + ck_assert_int_eq(0, parse_notification(&nurl, "resources/rrdp/notif-large-serial.xml", ¬if)); + uri_cleanup(&nurl); ck_assert_str_eq("9df4b597-af9e-4dca-bdda-719cce2c4e28", (char const *)notif.session.session_id); @@ -474,7 +483,7 @@ START_TEST(test_parse_notification_large_serial) ck_assert_str_eq("999999999999999999999999", (char const *)notif.session.serial.str); - ck_assert_str_eq("https://host/9d-8/3/snapshot.xml", notif.snapshot.uri); + ck_assert_uri("https://host/9d-8/3/snapshot.xml", ¬if.snapshot.uri); ck_assert_uint_eq(32, notif.snapshot.hash_len); validate_01234_hash(notif.snapshot.hash); @@ -489,10 +498,12 @@ static void test_parse_notification_error(char *file) { struct update_notification notif; + struct uri nurl; ck_assert_int_eq(0, relax_ng_init()); - ck_assert_int_eq(-EINVAL, - parse_notification("https://host/notification.xml", file, ¬if)); + ck_assert_int_eq(0, uri_init(&nurl, "https://host/notification.xml")); + ck_assert_int_eq(-EINVAL, parse_notification(&nurl, file, ¬if)); + uri_cleanup(&nurl); relax_ng_cleanup(); } diff --git a/test/rrdp_update_test.c b/test/rrdp_update_test.c index b84903f9..3f5f58eb 100644 --- a/test/rrdp_update_test.c +++ b/test/rrdp_update_test.c @@ -60,13 +60,13 @@ ck_state(char const *session, char const *serial, unsigned long seq_id, ck_assert_str_eq(session, actual->session.session_id); ck_assert_str_eq(serial, actual->session.serial.str); - for (m = 0; maps[m].url != NULL; m++) + for (m = 0; uri_str(&maps[m].url) != NULL; m++) ; ck_assert_int_eq(m, HASH_COUNT(actual->files)); m = 0; HASH_ITER(hh, actual->files, node, tmp) { - ck_assert_str_eq(maps[m].url, node->map.url); + ck_assert(uri_equals(&maps[m].url, &node->map.url)); ck_assert_str_eq(maps[m].path, node->map.path); m++; } @@ -79,6 +79,7 @@ START_TEST(startup) static char const *URL = "https://host/notification.xml"; static char const *PATH = "rrdp/0"; struct cache_sequence seq; + struct uri url; struct rrdp_state *state = NULL; struct cache_mapping maps[4]; bool changed; @@ -90,6 +91,8 @@ START_TEST(startup) seq.pathlen = strlen(seq.prefix); seq.free_prefix = false; + ck_assert_int_eq(0, uri_init(&url, URL)); + dls[0] = NHDR("3") NSS("https://host/9d-8/3/snapshot.xml", "0c84fb949e7b5379ae091b86c41bb1a33cb91636b154b86ad1b1dedd44651a25") @@ -98,20 +101,20 @@ START_TEST(startup) dls[2] = NULL; https_counter = 0; - ck_assert_int_eq(0, rrdp_update(URL, PATH, 0, &changed, &state)); + ck_assert_int_eq(0, rrdp_update(&url, PATH, 0, &changed, &state)); ck_assert_uint_eq(2, https_counter); ck_assert_uint_eq(true, changed); ck_file("rrdp/0/0"); /* "rrdp//" */ - maps[0].url = "rsync://a/b/c.cer"; + ck_assert_int_eq(0, uri_init(&maps[0].url, "rsync://a/b/c.cer")); maps[0].path = "rrdp/0/0"; - maps[1].url = NULL; + memset(&maps[1], 0, sizeof(maps[1])); ck_state(TEST_SESSION, "3", 1, maps, state); /* Attempt to update, server hasn't changed anything. */ dls[1] = NULL; /* Snapshot should not redownload */ https_counter = 0; - ck_assert_int_eq(0, rrdp_update(URL, PATH, 0, &changed, &state)); + ck_assert_int_eq(0, rrdp_update(&url, PATH, 0, &changed, &state)); ck_assert_uint_eq(1, https_counter); ck_assert_uint_eq(false, changed); ck_file("rrdp/0/0"); @@ -121,6 +124,7 @@ START_TEST(startup) // XXX Missing a looooooooooooooooooot of tests + uri_cleanup(&url); cleanup_test(); } END_TEST diff --git a/test/rsync_test.c b/test/rsync_test.c index 1de30423..92cc6e26 100644 --- a/test/rsync_test.c +++ b/test/rsync_test.c @@ -6,6 +6,7 @@ #include "rsync.c" #include "stream.c" #include "types/map.c" +#include "types/url.c" #include "asn1/asn1c/ber_decoder.c" #include "asn1/asn1c/ber_tlv_length.c" @@ -48,7 +49,7 @@ static int rsync_expected_duration = -1; static int rsyncs_done = 0; void -rsync_finished(char const *url, char const *path) +rsync_finished(struct uri const *url, char const *path) { struct timespec now; int delta; @@ -74,14 +75,16 @@ rsync_finished(char const *url, char const *path) /* Test RsyncRequest decode, feeding as few bytes as possible every time. */ START_TEST(test_decode_extremely_fragmented) { + struct uri uri; struct RsyncRequest src, *dst; unsigned char encoded[BUFSIZE]; asn_enc_rval_t encres; asn_dec_rval_t decres; unsigned int start, end, max; - ck_assert_int_eq(0, RsyncRequest_init(&src, - "aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789", + __URI_INIT(&uri, "aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789"); + + ck_assert_int_eq(0, RsyncRequest_init(&src, &uri, "AbCdEfGhIjKlMnOpQrStUvWxYz1234567890")); encres = der_encode_to_buffer(&asn_DEF_RsyncRequest, &src, encoded, sizeof(encoded)); @@ -135,7 +138,7 @@ ck_next_task(char const *url, char const *path) struct cache_mapping map; ck_assert_int_eq(0, next_task(&map)); - ck_assert_str_eq(url, map.url); + ck_assert_uri(url, &map.url); ck_assert_str_eq(path, map.path); map_cleanup(&map); @@ -144,10 +147,13 @@ ck_next_task(char const *url, char const *path) static void encode_request(char const *url, char const *path, unsigned char *buffer) { + struct uri uri; struct RsyncRequest rr; asn_enc_rval_t encres; - ck_assert_int_eq(0, RsyncRequest_init(&rr, url, path)); + __URI_INIT(&uri, url); + + ck_assert_int_eq(0, RsyncRequest_init(&rr, &uri, path)); encres = der_encode_to_buffer(&asn_DEF_RsyncRequest, &rr, buffer, BUFSIZE); ck_assert_int_gt(encres.encoded, 0); ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RsyncRequest, &rr); @@ -228,6 +234,14 @@ START_TEST(test_next_task) } END_TEST +static int +RSYNC_QUEUE(char const *a, char const *b) +{ + struct uri uri; + __URI_INIT(&uri, a); + return rsync_queue(&uri, b); +} + /* Makes sure @count rsyncs finish after roughly @millis milliseconds. */ static void wait_rsyncs(unsigned int count, unsigned int millis) @@ -257,7 +271,7 @@ START_TEST(test_fast_single_rsync) ck_assert_int_ne(-1, pssk.rd.fd); ck_assert_int_ne(-1, pssk.wr); - ck_assert_int_eq(0, rsync_queue("A", "B")); + ck_assert_int_eq(0, RSYNC_QUEUE("A", "B")); wait_rsyncs(1, 0); rsync_teardown(); @@ -272,7 +286,7 @@ START_TEST(test_stalled_single_rsync) ck_assert_int_ne(-1, pssk.rd.fd); ck_assert_int_ne(-1, pssk.wr); - ck_assert_int_eq(0, rsync_queue("A", "B")); + ck_assert_int_eq(0, RSYNC_QUEUE("A", "B")); wait_rsyncs(1, 3000); rsync_teardown(); @@ -287,7 +301,7 @@ START_TEST(test_stalled_single_rsync_timeout) ck_assert_int_ne(-1, pssk.rd.fd); ck_assert_int_ne(-1, pssk.wr); - ck_assert_int_eq(0, rsync_queue("A", "B")); + ck_assert_int_eq(0, RSYNC_QUEUE("A", "B")); wait_rsyncs(1, 4000); /* 4000 = timeout */ rsync_teardown(); @@ -302,7 +316,7 @@ START_TEST(test_dripfeed_single_rsync) ck_assert_int_ne(-1, pssk.rd.fd); ck_assert_int_ne(-1, pssk.wr); - ck_assert_int_eq(0, rsync_queue("A", "B")); + ck_assert_int_eq(0, RSYNC_QUEUE("A", "B")); wait_rsyncs(1, 3000); rsync_teardown(); @@ -317,7 +331,7 @@ START_TEST(test_dripfeed_single_rsync_timeout) ck_assert_int_ne(-1, pssk.rd.fd); ck_assert_int_ne(-1, pssk.wr); - ck_assert_int_eq(0, rsync_queue("A", "B")); + ck_assert_int_eq(0, RSYNC_QUEUE("A", "B")); wait_rsyncs(1, 4000); /* 4000 = timeout */ rsync_teardown(); @@ -346,9 +360,9 @@ START_TEST(test_simultaneous_rsyncs) ck_assert_int_ne(-1, pssk.rd.fd); ck_assert_int_ne(-1, pssk.wr); - ck_assert_int_eq(0, rsync_queue("A", "B")); - ck_assert_int_eq(0, rsync_queue("C", "D")); - ck_assert_int_eq(0, rsync_queue("E", "F")); + ck_assert_int_eq(0, RSYNC_QUEUE("A", "B")); + ck_assert_int_eq(0, RSYNC_QUEUE("C", "D")); + ck_assert_int_eq(0, RSYNC_QUEUE("E", "F")); wait_rsyncs(3, 1000); @@ -364,10 +378,10 @@ START_TEST(test_queued_rsyncs) ck_assert_int_ne(-1, pssk.rd.fd); ck_assert_int_ne(-1, pssk.wr); - ck_assert_int_eq(0, rsync_queue("A", "B")); - ck_assert_int_eq(0, rsync_queue("C", "D")); - ck_assert_int_eq(0, rsync_queue("E", "F")); - ck_assert_int_eq(0, rsync_queue("G", "H")); + ck_assert_int_eq(0, RSYNC_QUEUE("A", "B")); + ck_assert_int_eq(0, RSYNC_QUEUE("C", "D")); + ck_assert_int_eq(0, RSYNC_QUEUE("E", "F")); + ck_assert_int_eq(0, RSYNC_QUEUE("G", "H")); wait_rsyncs(3, 2000); /* 2k minus the 100 extra we slept during the previous wait_rsyncs() */ diff --git a/test/task_test.c b/test/task_test.c index 54290d0a..3e9b3310 100644 --- a/test/task_test.c +++ b/test/task_test.c @@ -7,6 +7,7 @@ #include "mock.c" #include "types/array.h" #include "types/map.c" +#include "types/url.c" void rpki_certificate_free(struct rpki_certificate *cert) @@ -23,7 +24,8 @@ queue_1(char *mapstr) struct cache_mapping map; struct rpki_certificate parent = { 0 }; - map.url = map.path = mapstr; + __URI_INIT(&map.url, mapstr); + map.path = mapstr; ck_assert_int_eq(1, task_enqueue_rpp(&map, &parent)); } @@ -32,7 +34,7 @@ dequeue_1(char *mapstr, struct validation_task *prev) { struct validation_task *task; task = task_dequeue(prev); - ck_assert_str_eq(mapstr, task->u.ca->map.url); + ck_assert_uri(mapstr, &task->u.ca->map.url); return task; } @@ -204,12 +206,12 @@ user_thread(void *arg) printf("th%d: Started.\n", thid); while ((task = task_dequeue(task)) != NULL) { - printf("- th%d: Dequeued '%s'\n", thid, task->u.ca->map.url); + printf("- th%d: Dequeued '%s'\n", thid, uri_str(&task->u.ca->map.url)); total_dequeued++; if (certificate_traverse_mock(task->u.ca, thid) == EBUSY) { printf("+ th%d: Requeuing '%s'\n", - thid, task->u.ca->map.url); + thid, uri_str(&task->u.ca->map.url)); task_requeue_dormant(task); task = NULL; } diff --git a/test/types/url_test.c b/test/types/url_test.c index 57bfeee5..ab890a30 100644 --- a/test/types/url_test.c +++ b/test/types/url_test.c @@ -65,25 +65,34 @@ START_TEST(test_normalize) } END_TEST +#define ck_assert_origin(expected, s1, s2) \ + do { \ + __URI_INIT(&u1, s1); \ + __URI_INIT(&u2, s2); \ + ck_assert_int_eq(expected, uri_same_origin(&u1, &u2)); \ + } while (0) + START_TEST(test_same_origin) { - ck_assert_int_eq(true, url_same_origin("https://a.b.c/d/e/f", "https://a.b.c/g/h/i")); - ck_assert_int_eq(false, url_same_origin("https://a.b.cc/d/e/f", "https://a.b.c/g/h/i")); - ck_assert_int_eq(false, url_same_origin("https://a.b.c/d/e/f", "https://a.b.cc/g/h/i")); - ck_assert_int_eq(true, url_same_origin("https://a.b.c", "https://a.b.c")); - ck_assert_int_eq(true, url_same_origin("https://a.b.c/", "https://a.b.c")); - ck_assert_int_eq(true, url_same_origin("https://a.b.c", "https://a.b.c/")); - ck_assert_int_eq(true, url_same_origin("https://", "https://")); - ck_assert_int_eq(false, url_same_origin("https://", "https://a")); - ck_assert_int_eq(false, url_same_origin("https://a", "https://b")); + struct uri u1, u2; + + ck_assert_origin(true, "https://a.b.c/d/e/f", "https://a.b.c/g/h/i"); + ck_assert_origin(false, "https://a.b.cc/d/e/f", "https://a.b.c/g/h/i"); + ck_assert_origin(false, "https://a.b.c/d/e/f", "https://a.b.cc/g/h/i"); + ck_assert_origin(true, "https://a.b.c", "https://a.b.c"); + ck_assert_origin(true, "https://a.b.c/", "https://a.b.c"); + ck_assert_origin(true, "https://a.b.c", "https://a.b.c/"); + ck_assert_origin(true, "https://", "https://"); + ck_assert_origin(false, "https://", "https://a"); + ck_assert_origin(false, "https://a", "https://b"); /* Undefined, but manhandle the code anyway */ - ck_assert_int_eq(false, url_same_origin("", "")); - ck_assert_int_eq(false, url_same_origin("ht", "ht")); - ck_assert_int_eq(false, url_same_origin("https:", "https:")); - ck_assert_int_eq(false, url_same_origin("https:/", "https:/")); - ck_assert_int_eq(false, url_same_origin("https:/a", "https:/a")); - ck_assert_int_eq(true, url_same_origin("https:/a/", "https:/a/")); + ck_assert_origin(false, "", ""); + ck_assert_origin(false, "ht", "ht"); + ck_assert_origin(false, "https:", "https:"); + ck_assert_origin(false, "https:/", "https:/"); + ck_assert_origin(false, "https:/a", "https:/a"); + ck_assert_origin(true, "https:/a/", "https:/a/"); } END_TEST