]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Use a local workspace fort RRDP related files, fixes #39.
authorpcarana <pc.moreno2099@gmail.com>
Tue, 1 Sep 2020 19:29:20 +0000 (14:29 -0500)
committerpcarana <pc.moreno2099@gmail.com>
Tue, 1 Sep 2020 19:29:20 +0000 (14:29 -0500)
+Whenever an RRDP file is identified (ie. update notification URI) create a directory at '--local-repository' where all of the RRDP files (XMLs as well as 'publish' elements at those snapshot/delta files) will be created and read.
+The rsync URIs at the publish/withdraw elements, are mapped to the location <--local-repository>/<rrdp workspace>/<URI part>. Eg. if '--local-repository=/tmp/fort' and the current workspace (each TAL has its own workspace) is 'ABC', then the URI 'rsync://example.com/foo/bar.cer' will be created at '/tmp/fort/ABC/example.com/foo/bar.cer'.
-RSYNC repositories are still created at '--local-repository'.

16 files changed:
src/common.c
src/crypto/hash.c
src/crypto/hash.h
src/object/certificate.c
src/object/manifest.c
src/object/manifest.h
src/rrdp/db/db_rrdp.c
src/rrdp/db/db_rrdp.h
src/rrdp/db/db_rrdp_uris.c
src/rrdp/db/db_rrdp_uris.h
src/rrdp/rrdp_parser.c
src/rsync/rsync.c
src/state.c
src/state.h
src/uri.c
src/uri.h

index 64e2b4e7a8249919ad171a04afbde2e7bd36684d..85d86893b5b4be277abac12bf3b2b1b0e6b45721 100644 (file)
@@ -205,13 +205,15 @@ valid_file_or_dir(char const *location, bool check_file, bool check_dir,
        result = false;
        file = fopen(location, "rb");
        if (file == NULL) {
-               cb(errno, "Could not open location '%s'",
-                   location);
+               if (cb != NULL)
+                       cb(errno, "Could not open location '%s'",
+                           location);
                return false;
        }
 
        if (fstat(fileno(file), &attr) == -1) {
-               cb(errno, "fstat(%s) failed", location);
+               if (cb != NULL)
+                       cb(errno, "fstat(%s) failed", location);
                goto end;
        }
 
@@ -226,7 +228,8 @@ valid_file_or_dir(char const *location, bool check_file, bool check_dir,
 
 end:
        if (fclose(file) == -1)
-               cb(errno, "fclose() failed");
+               if (cb != NULL)
+                       cb(errno, "fclose() failed");
        return result;
 }
 
index a39ee1350318351f1c1e228b54e4b8b0527e4e5d..4b6de3c8b4325252ad9320365ebec176bdd0cd70 100644 (file)
@@ -236,3 +236,28 @@ hash_validate_octet_string(char const *algorithm,
        return hash_validate(algorithm, expected->buf, expected->size,
            data->buf, data->size);
 }
+
+/*
+ * Hash the @str using the specified @algorithm, setting the result at the
+ * @result buffer and its length at @result_len.
+ * 
+ * Return 0 on success, any other value means error.
+ */
+int
+hash_str(char const *algorithm, char const *str, unsigned char *result,
+    unsigned int *result_len)
+{
+       unsigned char *src;
+       int error;
+
+       src = malloc(strlen(str));
+       if (src == NULL)
+               return pr_enomem();
+
+       memcpy(src, str, strlen(str));
+
+       error = hash_buffer(algorithm, src, strlen(str), result, result_len);
+
+       free(src);
+       return error;
+}
index 65910287ba0c640db84145e0850e1f7a1ef4b859..d9f31af2dcfd7fad066f937da6317e4ce2e52b6b 100644 (file)
@@ -18,5 +18,6 @@ int hash_validate_octet_string(char const *, OCTET_STRING_t const*,
 int hash_local_file(char const *, char const *, unsigned char *,
     unsigned int *);
 
+int hash_str(char const *, char const *, unsigned char *, unsigned int *);
 
 #endif /* SRC_HASH_H_ */
index 49fa4a897e219ba044059767b832639f72df857e..2446ab004f106f9d6f94759a190207e57041c2ee 100644 (file)
@@ -1536,9 +1536,10 @@ handle_ad(char const *ia_name, SIGNATURE_INFO_ACCESS *ia,
     char const *ad_name, int ad_nid, int uri_flags, bool required,
     int (*cb)(struct rpki_uri *, uint8_t, void *), void *arg)
 {
-# define AD_METHOD (uri_flags == URI_VALID_RSYNC ? \
+# define AD_METHOD ((uri_flags & URI_VALID_RSYNC) == URI_VALID_RSYNC ? \
        "RSYNC" : \
-       ((uri_flags == URI_VALID_HTTPS) ? "HTTPS" : "RSYNC/HTTPS"))
+       (((uri_flags & URI_VALID_HTTPS) == URI_VALID_HTTPS) ? \
+       "HTTPS" : "RSYNC/HTTPS"))
        ACCESS_DESCRIPTION *ad;
        struct rpki_uri *uri;
        bool found = false;
@@ -1638,7 +1639,8 @@ handle_sia_ca(X509_EXTENSION *ext, void *arg)
 
        /* HTTPS RRDP */
        error = handle_ad("SIA", sia, "rpkiNotify", nid_rpkiNotify(),
-           URI_VALID_HTTPS, false, handle_rpkiNotify, &uris->rpkiNotify);
+           URI_VALID_HTTPS | URI_USE_RRDP_WORKSPACE, false, handle_rpkiNotify,
+           &uris->rpkiNotify);
        if (error)
                goto end;
 
@@ -1905,7 +1907,7 @@ get_certificate_type(X509 *cert, bool is_ta)
  * verified to comply with rfc6487#section-4.8.7
  */
 static int
-force_aia_validation(struct rpki_uri *caIssuers, X509 *son, bool is_ta_child)
+force_aia_validation(struct rpki_uri *caIssuers, X509 *son)
 {
        X509 *parent;
        struct rfc5280_name *son_name;
@@ -1914,9 +1916,9 @@ force_aia_validation(struct rpki_uri *caIssuers, X509 *son, bool is_ta_child)
 
        pr_val_debug("AIA's URI didn't matched parent URI, trying to SYNC");
 
-       /* RSYNC is still the preferred access mechanism */
+       /* RSYNC is still the preferred access mechanism, force the sync */
        do {
-               error = download_files(caIssuers, false, false);
+               error = download_files(caIssuers, false, true);
                if (!error)
                        break;
                if (error == EREQFAILED) {
@@ -1926,19 +1928,9 @@ force_aia_validation(struct rpki_uri *caIssuers, X509 *son, bool is_ta_child)
                return error;
        } while (0);
 
-       /*
-        * Consider the scenario where the TA was fetched from a distinct URI
-        * (maybe an HTTPS URI), in that case keep doing the validation since
-        * there's no "right" way to validate the AIA, that's where the flag
-        * 'is_ta_child' comes into play.
-        *
-        * A possible way is to load the certificate from the cert_stack, but
-        * the location itself isn't strictly the location from the AIA (the
-        * solution works, but maybe it isn't right.
-        */
        error = certificate_load(caIssuers, &parent);
        if (error)
-               return !is_ta_child ? error : 0;
+               return error;
 
        error = x509_name_decode(X509_get_subject_name(parent), "subject",
            &parent_name);
@@ -2003,20 +1995,20 @@ certificate_validate_aia(struct rpki_uri *caIssuers, X509 *cert)
         *   of the certificate where this Issuer is the subject (the issuer's
         *   immediate superior certificate)."
         *
-        * January 2020: this isn't a problem, all five RIRs are using one URI
-        * at their TALs, that matches AIA from the first level root certificate
-        * childs. Anyways, we'll try to consult the subject at IETF.
+        * As of today, this is a common scenario, since most of the TALs have
+        * an HTTPS URI.
         */
        if (uri_equals(caIssuers, parent))
                return 0;
 
        /*
-        * URI didn't match, try to match the immediate superior subject with
-        * the current issuer. This will force an RSYNC of AIA's URI, load
-        * the certificate and do the comparison.
+        * Avoid the check at direct TA childs, otherwise try to match the
+        * immediate superior subject with the current issuer. This will force
+        * an RSYNC of AIA's URI, load the certificate and do the comparison.
         */
-       return force_aia_validation(caIssuers, cert,
-           certstack_get_x509_num(validation_certstack(state)) == 1);
+       return certstack_get_x509_num(validation_certstack(state)) == 1 ?
+           0 :
+           force_aia_validation(caIssuers, cert);
 }
 
 /*
@@ -2034,15 +2026,87 @@ verify_mft_loc(struct rpki_uri *mft_uri)
        return 0;
 }
 
+/*
+ * Verify the manifest location at the local RRDP workspace. If the manifest
+ * exists, then update @mft_uri so that its location be at the workspace.
+ * 
+ * Don't log in case the @mft_uri doesn't exist at the RRDP workspace.
+ */
+static int
+verify_rrdp_mft_loc(struct rpki_uri **mft_uri)
+{
+       struct rpki_uri *tmp;
+       int error;
+
+       if (db_rrdp_uris_workspace_get() == NULL)
+               return -ENOENT;
+
+       tmp = NULL;
+       error = uri_create_rsync_str_rrdp(&tmp, uri_get_global(*mft_uri),
+           uri_get_global_len(*mft_uri));
+       if (error)
+               return error;
+
+       if (!valid_file_or_dir(uri_get_local(tmp), true, false, NULL)) {
+               uri_refput(tmp);
+               return -EINVAL;
+       }
+
+       uri_refput(*mft_uri);
+       *mft_uri = tmp;
+       return 0;
+}
+
+static int
+replace_rrdp_mft_uri(struct sia_uri *sia_mft)
+{
+       struct rpki_uri *tmp;
+       int error;
+
+       tmp = NULL;
+       error = uri_create_rsync_str_rrdp(&tmp,
+           uri_get_global(sia_mft->uri),
+           uri_get_global_len(sia_mft->uri));
+       if (error)
+               return error;
+
+       uri_refput(sia_mft->uri);
+       sia_mft->uri = tmp;
+
+       return 0;
+}
+
 static int
 exec_rrdp_method(struct sia_ca_uris *sia_uris)
 {
-       return rrdp_load(sia_uris->rpkiNotify.uri);
+       int error;
+
+       /* Start working on the RRDP local workspace */
+       error = db_rrdp_uris_workspace_enable();
+       if (error)
+               return error;
+
+       error = rrdp_load(sia_uris->rpkiNotify.uri);
+       if (error) {
+               db_rrdp_uris_workspace_disable();
+               return error;
+       }
+
+       /* Successfully loaded (or no updates yet), update MFT local URI */
+       error = replace_rrdp_mft_uri(&sia_uris->mft);
+       if (error) {
+               db_rrdp_uris_workspace_disable();
+               return error;
+       }
+
+       return 0;
 }
 
 static int
 exec_rsync_method(struct sia_ca_uris *sia_uris)
 {
+       /* Stop working on the RRDP local workspace */
+       db_rrdp_uris_workspace_disable();
        return download_files(sia_uris->caRepository.uri, false, false);
 }
 
@@ -2053,33 +2117,56 @@ exec_rsync_method(struct sia_ca_uris *sia_uris)
  */
 static int
 use_access_method(struct sia_ca_uris *sia_uris,
-    access_method_exec rsync_cb, access_method_exec rrdp_cb,
+    access_method_exec rsync_cb, access_method_exec rrdp_cb, bool new_level,
     bool *retry_repo_sync)
 {
        access_method_exec *cb_primary;
        access_method_exec *cb_secondary;
        rrdp_req_status_t rrdp_req_status;
        bool primary_rrdp;
+       int upd_error;
        int error;
 
+       /*
+        * By default, RRDP has a greater priority than rsync.
+        * See "http.priority" default value.
+        */
+       primary_rrdp = true;
+       (*retry_repo_sync) = true;
+
+       /*
+        * Very specific scenario, yet possible:
+        * - Still working at the same repository level
+        * - The previous object was working on an RRDP repository
+        * - This certificate doesn't have an update notification URI
+        *
+        * Probably the object does exist at the RRDP repository, so check if
+        * that's the case. Otherwise, just keep going.
+        *
+        * The main reason, is a (possible) hole at RFC 8182. Apparently, the
+        * CA childs aren't obligated to have the same RRDP accessMethod than
+        * their parent, so there's no problem if they don't use it at all; not
+        * even if such childs (and even the grandchilds or anyone below that
+        * level) "reside" at the RRDP repository.
+        */
+       if (!new_level && db_rrdp_uris_workspace_get() != NULL &&
+           sia_uris->rpkiNotify.uri == NULL &&
+           verify_rrdp_mft_loc(&sia_uris->mft.uri) == 0) {
+               (*retry_repo_sync) = false;
+               return replace_rrdp_mft_uri(&sia_uris->mft);
+       }
+
        /*
         * RSYNC will always be present (at least for now, see
         * rfc6487#section-4.8.8.1). If rsync is disabled, the cb will take
         * care of that.
         */
-       (*retry_repo_sync) = true;
-       if (sia_uris->rpkiNotify.uri == NULL || !config_get_http_enabled()) {
+       if (sia_uris->rpkiNotify.uri == NULL) {
+               primary_rrdp = false;
                error = rsync_cb(sia_uris);
                goto verify_mft;
        }
 
-       /* RSYNC disabled, and RRDP is present, use it */
-       if (!config_get_rsync_enabled()) {
-               (*retry_repo_sync) = false;
-               error = rrdp_cb(sia_uris);
-               goto verify_mft;
-       }
-
        /*
         * There isn't any restriction about the preferred access method of
         * children CAs being the same as the parent CA.
@@ -2097,8 +2184,13 @@ use_access_method(struct sia_ca_uris *sia_uris,
        error = db_rrdp_uris_get_request_status(
            uri_get_global(sia_uris->rpkiNotify.uri), &rrdp_req_status);
        if (error ==  0 && rrdp_req_status == RRDP_URI_REQ_VISITED) {
+               error = db_rrdp_uris_workspace_enable();
+               if (error) {
+                       db_rrdp_uris_workspace_disable();
+                       return error;
+               }
                (*retry_repo_sync) = false;
-               return 0;
+               return replace_rrdp_mft_uri(&sia_uris->mft);
        }
 
        /* Use CA's or configured priority? */
@@ -2136,6 +2228,7 @@ use_access_method(struct sia_ca_uris *sia_uris,
                    uri_get_global(sia_uris->rpkiNotify.uri));
        }
 
+       /* Retry if rrdp was the first option but failed */
        (*retry_repo_sync) = primary_rrdp;
        error = cb_secondary(sia_uris);
        /* No need to remember the working repository anymore */
@@ -2163,6 +2256,15 @@ verify_mft:
        default:
                return error;
        }
+
+       /* Error and the primary access method was RRDP? Use its workspace */
+       if (error && primary_rrdp) {
+               db_rrdp_uris_workspace_enable();
+               upd_error = replace_rrdp_mft_uri(&sia_uris->mft);
+               if (upd_error)
+                       return upd_error;
+       }
+
        /* Look for the manifest */
        return verify_mft_loc(sia_uris->mft.uri);
 }
@@ -2211,7 +2313,7 @@ get_rsync_server_uri(struct rpki_uri *src, char **result, size_t *result_len)
 
 static int
 set_repository_level(bool is_ta, struct validation *state,
-    struct rpki_uri *cert_uri, struct sia_ca_uris *sia_uris)
+    struct rpki_uri *cert_uri, struct sia_ca_uris *sia_uris, bool *updated)
 {
        char *parent_server, *current_server;
        size_t parent_server_len, current_server_len;
@@ -2260,6 +2362,7 @@ end:
        free(parent_server);
        free(current_server);
 
+       (*updated) = update;
        return 0;
 }
 
@@ -2281,6 +2384,7 @@ certificate_traverse(struct rpp *rpp_parent, struct rpki_uri *cert_uri)
        enum cert_type type;
        struct rpp *pp;
        bool repo_retry;
+       bool new_level;
        int error;
 
        state = state_retrieve();
@@ -2374,7 +2478,9 @@ certificate_traverse(struct rpp *rpp_parent, struct rpki_uri *cert_uri)
        }
 
        /* Identify if this is a new repository before fetching it */
-       error = set_repository_level(IS_TA, state, cert_uri, &sia_uris);
+       new_level = false;
+       error = set_repository_level(IS_TA, state, cert_uri, &sia_uris,
+           &new_level);
        if (error)
                goto revert_uris;
 
@@ -2386,12 +2492,12 @@ certificate_traverse(struct rpp *rpp_parent, struct rpki_uri *cert_uri)
         *
         * Trying to avoid this issue, download the CA repository and validate
         * manifest (and its content) again.
-        * 
+        *
         * Avoid to re-download the repo if the mft was fetched with RRDP.
         */
        repo_retry = true;
        error = use_access_method(&sia_uris, exec_rsync_method,
-           exec_rrdp_method, &repo_retry);
+           exec_rrdp_method, new_level, &repo_retry);
        if (error)
                goto revert_uris;
 
@@ -2404,7 +2510,7 @@ certificate_traverse(struct rpp *rpp_parent, struct rpki_uri *cert_uri)
 
                cert = NULL; /* Ownership stolen */
 
-               error = handle_manifest(sia_uris.mft.uri, &pp);
+               error = handle_manifest(sia_uris.mft.uri, !repo_retry, &pp);
                if (error == 0 || !repo_retry)
                        break;
 
index fd269f5988e8c6f2ad3bce27c8f539abb32002fa..327fe52886e4c7a000cd308bf6f54ae84d63dbec 100644 (file)
@@ -150,7 +150,8 @@ validate_manifest(struct Manifest *manifest)
 }
 
 static int
-build_rpp(struct Manifest *mft, struct rpki_uri *mft_uri, struct rpp **pp)
+build_rpp(struct Manifest *mft, struct rpki_uri *mft_uri, bool rrdp_workspace,
+    struct rpp **pp)
 {
        int i;
        struct FileAndHash *fah;
@@ -164,7 +165,8 @@ build_rpp(struct Manifest *mft, struct rpki_uri *mft_uri, struct rpp **pp)
        for (i = 0; i < mft->fileList.list.count; i++) {
                fah = mft->fileList.list.array[i];
 
-               error = uri_create_mft(&uri, mft_uri, &fah->file);
+               error = uri_create_mft(&uri, mft_uri, &fah->file,
+                   rrdp_workspace);
                /*
                 * Not handling ENOTRSYNC is fine because the manifest URL
                 * should have been RSYNC. Something went wrong if an RSYNC URL
@@ -225,10 +227,10 @@ fail:
 
 /**
  * Validates the manifest pointed by @uri, returns the RPP described by it in
- * @pp.
+ * @pp. If @rrdp_workspace is true, use the local RRDP repository.
  */
 int
-handle_manifest(struct rpki_uri *uri, struct rpp **pp)
+handle_manifest(struct rpki_uri *uri, bool rrdp_workspace, struct rpp **pp)
 {
        static OID oid = OID_MANIFEST;
        struct oid_arcs arcs = OID2ARCS("manifest", oid);
@@ -251,7 +253,7 @@ handle_manifest(struct rpki_uri *uri, struct rpp **pp)
                goto revert_sobj;
 
        /* Initialize out parameter (@pp) */
-       error = build_rpp(mft, uri, pp);
+       error = build_rpp(mft, uri, rrdp_workspace, pp);
        if (error)
                goto revert_manifest;
 
index a9cfcb992c972271be1678bca57d365ce18c7216..dbfc0bd68eb13dda2c6e1782ef55fcd9ea1aa2fe 100644 (file)
@@ -1,9 +1,10 @@
 #ifndef SRC_OBJECT_MANIFEST_H_
 #define SRC_OBJECT_MANIFEST_H_
 
+#include <stdbool.h>
 #include "uri.h"
 #include "rpp.h"
 
-int handle_manifest(struct rpki_uri *, struct rpp **);
+int handle_manifest(struct rpki_uri *, bool, struct rpp **);
 
 #endif /* SRC_OBJECT_MANIFEST_H_ */
index b6e0363bfaee6c8c5888b8a55a2919aabf8a0b27..fe4723fdf194fbcc404bf2705cabf689f67e99ed 100644 (file)
@@ -2,15 +2,18 @@
 
 #include <sys/queue.h>
 #include <pthread.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <stdbool.h>
 #include <string.h>
+#include "crypto/hash.h"
 #include "common.h"
 #include "log.h"
 
 struct tal_elem {
        char *file_name;
        struct db_rrdp_uri *uris;
+       char *workspace;
        bool visited;
        SLIST_ENTRY(tal_elem) next;
 };
@@ -26,6 +29,60 @@ static struct db_rrdp db;
 /** Read/write lock, which protects @db. */
 static pthread_rwlock_t lock;
 
+/*
+ * Creates an ID for the RRDP local workspace.
+ *
+ * The ID is generated using the hash (sha-1) of @base. The first 4 bytes of
+ * the hash are "stringified" (8 chars) and a '/' is added at the end to
+ * (later) facilitate the concatenation of the ID at --local-repository.
+ * 
+ * The ID is allocated at @result.
+ */
+static int
+get_workspace_path(char const *base, char **result)
+{
+/* SHA1 produces 20 bytes */
+#define HASH_LEN 20
+/* We'll use the first 4 bytes (8 chars) */
+#define OUT_LEN   8
+       unsigned char *hash;
+       unsigned int hash_len;
+       unsigned int i;
+       char *tmp;
+       char *ptr;
+       int error;
+
+       hash = malloc(HASH_LEN * sizeof(unsigned char));
+       if (hash == NULL)
+               return pr_enomem();
+
+       hash_len = 0;
+       error = hash_str("sha1", base, hash, &hash_len);
+       if (error) {
+               free(hash);
+               return error;
+       }
+
+       /* Get the first bytes + one slash + NUL char */
+       tmp = malloc(OUT_LEN + 2);
+       if (tmp == NULL) {
+               free(hash);
+               return pr_enomem();
+       }
+
+       ptr = tmp;
+       for (i = 0; i < OUT_LEN / 2; i++) {
+               sprintf(ptr, "%02X", hash[i]);
+               ptr += 2;
+       }
+       tmp[OUT_LEN] = '/';
+       tmp[OUT_LEN + 1] = '\0';
+
+       free(hash);
+       *result = tmp;
+       return 0;
+}
+
 static int
 tal_elem_create(struct tal_elem **elem, char const *name)
 {
@@ -39,22 +96,30 @@ tal_elem_create(struct tal_elem **elem, char const *name)
 
        tmp_uris = NULL;
        error = db_rrdp_uris_create(&tmp_uris);
-       if (error) {
-               free(tmp);
-               return error;
-       }
+       if (error)
+               goto end1;
        tmp->uris = tmp_uris;
 
        tmp->visited = true;
        tmp->file_name = strdup(name);
        if (tmp->file_name == NULL) {
-               db_rrdp_uris_destroy(tmp->uris);
-               free(tmp);
-               return pr_enomem();
+               error = pr_enomem();
+               goto end2;
        }
 
+       error = get_workspace_path(name, &tmp->workspace);
+       if (error)
+               goto end3;
+
        *elem = tmp;
        return 0;
+end3:
+       free(tmp->file_name);
+end2:
+       db_rrdp_uris_destroy(tmp->uris);
+end1:
+       free(tmp);
+       return error;
 }
 
 static void
@@ -64,6 +129,7 @@ tal_elem_destroy(struct tal_elem *elem, bool remove_local)
                db_rrdp_uris_remove_all_local(elem->uris);
        db_rrdp_uris_destroy(elem->uris);
        free(elem->file_name);
+       free(elem->workspace);
        free(elem);
 }
 
@@ -157,7 +223,22 @@ db_rrdp_get_uris(char const *tal_name)
        struct tal_elem *found;
 
        found = db_rrdp_find_tal(tal_name);
-       return found != NULL ? found->uris : NULL;
+       if (found == NULL)
+               pr_crit("db_rrdp_find_tal() returned NULL, means it hasn't been initialized");
+
+       return found->uris;
+}
+
+char const *
+db_rrdp_get_workspace(char const *tal_name)
+{
+       struct tal_elem *found;
+
+       found = db_rrdp_find_tal(tal_name);
+       if (found == NULL)
+               pr_crit("db_rrdp_find_tal() returned NULL, means it hasn't been initialized");
+
+       return found->workspace;
 }
 
 /* Set all tals to non-visited */
index b0440e307dc7962d38f87866b5b149a1df0481e0..0607f99c07690f3e0cdcb867aa08d8dadf3bd6b7 100644 (file)
@@ -8,7 +8,9 @@ void db_rrdp_cleanup(void);
 
 int db_rrdp_add_tal(char const *);
 void db_rrdp_rem_tal(char const *);
+
 struct db_rrdp_uri *db_rrdp_get_uris(char const *);
+char const *db_rrdp_get_workspace(char const *);
 
 void db_rrdp_reset_visited_tals(void);
 void db_rrdp_rem_nonvisited_tals(void);
index 082db39ca7691397693be79c14a2e9803478b669..9928a7eb5b3fa67568b37a504e831d6a858d79ee 100644 (file)
@@ -24,6 +24,7 @@ struct uris_table {
 
 struct db_rrdp_uri {
        struct uris_table *table;
+       char const *current_workspace;
 };
 
 static int
@@ -115,6 +116,19 @@ get_thread_rrdp_uris(struct db_rrdp_uri **result)
        return 0;
 }
 
+static int
+get_thread_rrdp_workspace(char const **result)
+{
+       struct validation *state;
+
+       state = state_retrieve();
+       if (state == NULL)
+               return pr_val_err("No state related to this thread");
+
+       *result = validation_get_rrdp_workspace(state);
+       return 0;
+}
+
 int
 db_rrdp_uris_create(struct db_rrdp_uri **uris)
 {
@@ -125,6 +139,7 @@ db_rrdp_uris_create(struct db_rrdp_uri **uris)
                return pr_enomem();
 
        tmp->table = NULL;
+       tmp->current_workspace = NULL;
 
        *uris = tmp;
        return 0;
@@ -349,3 +364,46 @@ db_rrdp_uris_remove_all_local(struct db_rrdp_uri *uris)
 
        return 0;
 }
+
+char const *
+db_rrdp_uris_workspace_get(void)
+{
+       struct db_rrdp_uri *uris;
+       int error;
+
+       uris = NULL;
+       error = get_thread_rrdp_uris(&uris);
+       if (error)
+               return NULL;
+
+       return uris->current_workspace;
+}
+
+int
+db_rrdp_uris_workspace_enable(void)
+{
+       struct db_rrdp_uri *uris;
+       int error;
+
+       uris = NULL;
+       error = get_thread_rrdp_uris(&uris);
+       if (error)
+               return error;
+
+       return get_thread_rrdp_workspace(&uris->current_workspace);
+}
+
+int
+db_rrdp_uris_workspace_disable(void)
+{
+       struct db_rrdp_uri *uris;
+       int error;
+
+       uris = NULL;
+       error = get_thread_rrdp_uris(&uris);
+       if (error)
+               return error;
+
+       uris->current_workspace = NULL;
+       return 0;
+}
index 409dd7314225d02dbeafdf5d401604e1cbbe8b8d..e9896276912f62b150cc730c48c68db937552eb9 100644 (file)
@@ -38,4 +38,8 @@ int db_rrdp_uris_get_visited_uris(char const *, struct visited_uris **);
 
 int db_rrdp_uris_remove_all_local(struct db_rrdp_uri *);
 
+char const *db_rrdp_uris_workspace_get(void);
+int db_rrdp_uris_workspace_enable(void);
+int db_rrdp_uris_workspace_disable(void);
+
 #endif /* SRC_RRDP_DB_DB_RRDP_URIS_H_ */
index 759ec3efa49d1f54ab3f608baa22fe5b161f6ea0..69d33063230fe77fba1f155096b12ac92eccb0eb 100644 (file)
@@ -523,7 +523,7 @@ parse_publish(xmlTextReaderPtr reader, bool parse_hash, bool hash_required,
        uri = NULL;
        if (tmp->doc_data.hash_len > 0) {
                /* Get the current file from the uri */
-               error = uri_create_rsync_str(&uri, tmp->doc_data.uri,
+               error = uri_create_rsync_str_rrdp(&uri, tmp->doc_data.uri,
                    strlen(tmp->doc_data.uri));
                if (error)
                        goto release_base64;
@@ -565,7 +565,7 @@ parse_withdraw(xmlTextReaderPtr reader, struct withdraw **withdraw)
                goto release_tmp;
 
        /* rfc8181#section-2.2, get the file from the uri */
-       error = uri_create_rsync_str(&uri, tmp->doc_data.uri,
+       error = uri_create_rsync_str_rrdp(&uri, tmp->doc_data.uri,
            strlen(tmp->doc_data.uri));
        if (error)
                goto release_tmp;
@@ -596,7 +596,7 @@ write_from_uri(char const *location, unsigned char *content, size_t content_len,
        int error;
 
        /* rfc8181#section-2.2 must be an rsync URI */
-       error = uri_create_rsync_str(&uri, location, strlen(location));
+       error = uri_create_rsync_str_rrdp(&uri, location, strlen(location));
        if (error)
                return error;
 
@@ -655,7 +655,7 @@ __delete_from_uri(char const *location, struct visited_uris *visited_uris)
        int error;
 
        /* rfc8181#section-2.2 must be an rsync URI */
-       error = uri_create_rsync_str(&uri, location, strlen(location));
+       error = uri_create_rsync_str_rrdp(&uri, location, strlen(location));
        if (error)
                return error;
 
@@ -1032,7 +1032,7 @@ process_delta(struct delta_head *delta_head, void *arg)
        head_data = &delta_head->doc_data;
 
        pr_val_debug("Processing delta '%s'.", delta_head->doc_data.uri);
-       error = uri_create_https_str(&uri, head_data->uri,
+       error = uri_create_https_str_rrdp(&uri, head_data->uri,
            strlen(head_data->uri));
        if (error)
                return error;
@@ -1123,7 +1123,7 @@ rrdp_parse_snapshot(struct update_notification *parent,
        args.visited_uris = visited_uris;
 
        pr_val_debug("Processing snapshot '%s'.", parent->snapshot.uri);
-       error = uri_create_https_str(&uri, parent->snapshot.uri,
+       error = uri_create_https_str_rrdp(&uri, parent->snapshot.uri,
            strlen(parent->snapshot.uri));
        if (error)
                return error;
index 6c7f9c55ba3a05583bfbd7b620248a2cdea2f369..4ba18183d5c54dbff73625812f0fb1a674798c90 100644 (file)
@@ -499,7 +499,7 @@ release_args:
  * Returned values if the ancestor URI of @error_uri:
  * 0 - didn't had a previous request error
  * EEXIST - had a previous request error
- * > 0 - nothing, just something bad happened
+ * < 0 - nothing, just something bad happened
  */
 static int
 ancestor_error(char const *error_uri, void *arg)
@@ -509,23 +509,43 @@ ancestor_error(char const *error_uri, void *arg)
        int error;
 
        req_err_uri = NULL;
-       error = uri_create_rsync_str(&req_err_uri, error_uri,
+       error = uri_create_mixed_str(&req_err_uri, error_uri,
            strlen(error_uri));
        switch(error) {
        case 0:
                break;
-       case ENOTRSYNC:
-               return 0;
        default:
                return ENSURE_NEGATIVE(error);
        }
 
+       /* Ignore non rsync error'd URIs */
+       if (!uri_is_rsync(req_err_uri)) {
+               free(req_err_uri);
+               return 0;
+       }
+
        error = is_descendant(req_err_uri, search) ? EEXIST : 0;
 
        free(req_err_uri);
        return error;
 }
 
+/* Validate if the ancestor URI error'd */
+static int
+check_ancestor_error(struct rpki_uri *requested_uri)
+{
+       int error;
+
+       error = reqs_errors_foreach(ancestor_error, requested_uri);
+       if (error < 0)
+               return error;
+       /* Return the requests error'd code */
+       if (error == EEXIST)
+               return EREQFAILED;
+
+       return 0;
+}
+
 /**
  * @is_ta: Are we rsync'ing the TA?
  * The TA rsync will not be recursive, and will force SYNC_STRICT
@@ -560,19 +580,15 @@ download_files(struct rpki_uri *requested_uri, bool is_ta, bool force)
        if (!force && is_already_downloaded(requested_uri, visited_uris)) {
                pr_val_debug("No need to redownload '%s'.",
                    uri_val_get_printable(requested_uri));
-               return 0;
+               return check_ancestor_error(requested_uri);
        }
 
        if (!force)
                error = get_rsync_uri(requested_uri, is_ta, &rsync_uri);
        else {
-               /* Validate if the ancestor URI error'd */
-               error = reqs_errors_foreach(ancestor_error, requested_uri);
-               if (error < 0)
+               error = check_ancestor_error(requested_uri);
+               if (error)
                        return error;
-               /* Return the requests error'd code */
-               if (error == EEXIST)
-                       return EREQFAILED;
                error = handle_strict_strategy(requested_uri, &rsync_uri);
        }
 
@@ -581,18 +597,18 @@ download_files(struct rpki_uri *requested_uri, bool is_ta, bool force)
 
        pr_val_debug("Going to RSYNC '%s'.", uri_val_get_printable(rsync_uri));
 
-       to_op_log = reqs_errors_log_uri(uri_get_global(requested_uri));
+       to_op_log = reqs_errors_log_uri(uri_get_global(rsync_uri));
        error = do_rsync(rsync_uri, is_ta, to_op_log);
        switch(error) {
        case 0:
                /* Don't store when "force" and if its already downloaded */
                if (!(force && is_already_downloaded(rsync_uri, visited_uris)))
                        error = mark_as_downloaded(rsync_uri, visited_uris);
-               reqs_errors_rem_uri(uri_get_global(requested_uri));
+               reqs_errors_rem_uri(uri_get_global(rsync_uri));
                break;
        case EREQFAILED:
                /* All attempts failed, avoid future requests */
-               error = reqs_errors_add_uri(uri_get_global(requested_uri));
+               error = reqs_errors_add_uri(uri_get_global(rsync_uri));
                if (error)
                        break;
                error = mark_as_downloaded(rsync_uri, visited_uris);
index 4d51e0236f9cb2056745c992a7987e7215ef1820..6a962b6a013d19908d7160377d7b20ed950fdd43 100644 (file)
@@ -25,6 +25,9 @@ struct validation {
 
        struct uri_list *rsync_visited_uris;
 
+       /* Local RRDP workspace path */
+       char const *rrdp_workspace;
+
        /* Shallow copy of RRDP URIs and its corresponding visited uris */
        struct db_rrdp_uri *rrdp_uris;
 
@@ -88,7 +91,6 @@ validation_prepare(struct validation **out, struct tal *tal,
     struct validation_handler *validation_handler)
 {
        struct validation *result;
-       struct db_rrdp_uri *uris_table;
        X509_VERIFY_PARAM *params;
        int error;
 
@@ -126,10 +128,8 @@ validation_prepare(struct validation **out, struct tal *tal,
        if (error)
                goto abort4;
 
-       uris_table = db_rrdp_get_uris(tal_get_file_name(tal));
-       if (uris_table == NULL)
-               pr_crit("db_rrdp_get_uris() returned NULL, means it hasn't been initialized");
-       result->rrdp_uris = uris_table;
+       result->rrdp_uris = db_rrdp_get_uris(tal_get_file_name(tal));
+       result->rrdp_workspace = db_rrdp_get_workspace(tal_get_file_name(tal));
 
        result->pubkey_state = PKS_UNTESTED;
        result->validation_handler = *validation_handler;
@@ -223,3 +223,9 @@ validation_get_rrdp_uris(struct validation *state)
 {
        return state->rrdp_uris;
 }
+
+char const *
+validation_get_rrdp_workspace(struct validation *state)
+{
+       return state->rrdp_workspace;
+}
index 190a57194cec8d6e313b3789cfc296d122f755e4..5fceca3086930d26558679556dca79bfb146a7da 100644 (file)
@@ -36,5 +36,6 @@ struct validation_handler const *
 validation_get_validation_handler(struct validation *);
 
 struct db_rrdp_uri *validation_get_rrdp_uris(struct validation *);
+char const *validation_get_rrdp_workspace(struct validation *);
 
 #endif /* SRC_STATE_H_ */
index eb5901e2630f32283a9f8c20e8987c5ddaddcde4..ebdfadae418ddb7660b265818221e9c2ad2efd52 100644 (file)
--- a/src/uri.c
+++ b/src/uri.c
@@ -2,6 +2,7 @@
 
 #include <errno.h>
 #include <strings.h>
+#include "rrdp/db/db_rrdp_uris.h"
 #include "common.h"
 #include "config.h"
 #include "log.h"
@@ -214,19 +215,23 @@ validate_gprefix(char const *global, size_t global_len, uint8_t flags,
        static char const *const PFX_HTTPS = "https://";
        size_t const PFX_RSYNC_LEN = strlen(PFX_RSYNC);
        size_t const PFX_HTTPS_LEN = strlen(PFX_HTTPS);
+       uint8_t l_flags;
        int error;
 
-       if (flags == URI_VALID_RSYNC) {
+       /* Exclude RSYNC RRDP flag, isn't relevant here */
+       l_flags = flags & ~URI_USE_RRDP_WORKSPACE;
+
+       if (l_flags == URI_VALID_RSYNC) {
                (*type) = URI_RSYNC;
                return validate_uri_begin(PFX_RSYNC, PFX_RSYNC_LEN, global,
                    global_len, size, ENOTRSYNC);
        }
-       if (flags == URI_VALID_HTTPS) {
+       if (l_flags == URI_VALID_HTTPS) {
                (*type) = URI_HTTPS;
                return validate_uri_begin(PFX_HTTPS, PFX_HTTPS_LEN, global,
                    global_len, size, ENOTHTTPS);
        }
-       if (flags != (URI_VALID_RSYNC & URI_VALID_HTTPS))
+       if (l_flags != (URI_VALID_RSYNC | URI_VALID_HTTPS))
                pr_crit("Unknown URI flag");
 
        /* It has both flags */
@@ -249,6 +254,28 @@ validate_gprefix(char const *global, size_t global_len, uint8_t flags,
        return 0;
 }
 
+static int
+get_local_workspace(char **result, size_t *result_len)
+{
+       char const *workspace;
+       char *tmp;
+
+       workspace = db_rrdp_uris_workspace_get();
+       if (workspace == NULL) {
+               *result = NULL;
+               *result_len = 0;
+               return 0;
+       }
+
+       tmp = strdup(workspace);
+       if (tmp == NULL)
+               return pr_enomem();
+
+       *result = tmp;
+       *result_len = strlen(tmp);
+       return 0;
+}
+
 /**
  * Initializes @uri->local by converting @uri->global.
  *
@@ -265,10 +292,12 @@ g2l(char const *global, size_t global_len, uint8_t flags, char **result,
 {
        char const *repository;
        char *local;
+       char *workspace;
        size_t prefix_len;
        size_t repository_len;
        size_t extra_slash;
        size_t offset;
+       size_t workspace_len;
        enum rpki_uri_type type;
        int error;
 
@@ -283,9 +312,20 @@ g2l(char const *global, size_t global_len, uint8_t flags, char **result,
        global_len -= prefix_len;
        extra_slash = (repository[repository_len - 1] == '/') ? 0 : 1;
 
-       local = malloc(repository_len + extra_slash + global_len + 1);
-       if (!local)
+       workspace = NULL;
+       workspace_len = 0;
+       if ((flags & URI_USE_RRDP_WORKSPACE) != 0) {
+               error = get_local_workspace(&workspace, &workspace_len);
+               if (error)
+                       return error;
+       }
+
+       local = malloc(repository_len + extra_slash + workspace_len +
+           global_len + 1);
+       if (!local) {
+               free(workspace);
                return pr_enomem();
+       }
 
        offset = 0;
        strcpy(local + offset, repository);
@@ -294,10 +334,15 @@ g2l(char const *global, size_t global_len, uint8_t flags, char **result,
                strcpy(local + offset, "/");
                offset += extra_slash;
        }
+       if (workspace_len > 0) {
+               strcpy(local + offset, workspace);
+               offset += workspace_len;
+       }
        strncpy(local + offset, global, global_len);
        offset += global_len;
        local[offset] = '\0';
 
+       free(workspace);
        *result = local;
        (*result_type) = type;
        return 0;
@@ -340,15 +385,25 @@ uri_create(struct rpki_uri **result, uint8_t flags, void const *guri,
 }
 
 int
-uri_create_rsync_str(struct rpki_uri **uri, char const *guri, size_t guri_len)
+uri_create_rsync_str_rrdp(struct rpki_uri **uri, char const *guri,
+    size_t guri_len)
 {
-       return uri_create(uri, URI_VALID_RSYNC, guri, guri_len);
+       return uri_create(uri, URI_VALID_RSYNC | URI_USE_RRDP_WORKSPACE, guri,
+           guri_len);
+}
+
+int
+uri_create_https_str_rrdp(struct rpki_uri **uri, char const *guri,
+    size_t guri_len)
+{
+       return uri_create(uri, URI_VALID_HTTPS | URI_USE_RRDP_WORKSPACE, guri,
+           guri_len);
 }
 
 int
-uri_create_https_str(struct rpki_uri **uri, char const *guri, size_t guri_len)
+uri_create_rsync_str(struct rpki_uri **uri, char const *guri, size_t guri_len)
 {
-       return uri_create(uri, URI_VALID_HTTPS, guri, guri_len);
+       return uri_create(uri, URI_VALID_RSYNC, guri, guri_len);
 }
 
 /*
@@ -359,7 +414,7 @@ uri_create_https_str(struct rpki_uri **uri, char const *guri, size_t guri_len)
 int
 uri_create_mixed_str(struct rpki_uri **uri, char const *guri, size_t guri_len)
 {
-       return uri_create(uri, URI_VALID_RSYNC & URI_VALID_HTTPS, guri,
+       return uri_create(uri, URI_VALID_RSYNC | URI_VALID_HTTPS, guri,
            guri_len);
 }
 
@@ -367,9 +422,11 @@ uri_create_mixed_str(struct rpki_uri **uri, char const *guri, size_t guri_len)
  * Manifests URIs are a little special in that they are relative.
  */
 int
-uri_create_mft(struct rpki_uri **result, struct rpki_uri *mft, IA5String_t *ia5)
+uri_create_mft(struct rpki_uri **result, struct rpki_uri *mft, IA5String_t *ia5,
+    bool use_rrdp_workspace)
 {
        struct rpki_uri *uri;
+       uint8_t flags;
        int error;
 
        uri = malloc(sizeof(struct rpki_uri));
@@ -382,7 +439,11 @@ uri_create_mft(struct rpki_uri **result, struct rpki_uri *mft, IA5String_t *ia5)
                return error;
        }
 
-       error = autocomplete_local(uri, URI_VALID_RSYNC);
+       flags = URI_VALID_RSYNC;
+       if (use_rrdp_workspace)
+               flags |= URI_USE_RRDP_WORKSPACE;
+
+       error = autocomplete_local(uri, flags);
        if (error) {
                free(uri->global);
                free(uri);
index 0e7be926b3b1c49ca437319a2cb4df1b0907088b..6e2d7c1f43b1ff2c2127969e9a80af568719494c 100644 (file)
--- a/src/uri.h
+++ b/src/uri.h
@@ -6,15 +6,20 @@
 #include "asn1/asn1c/IA5String.h"
 
 /* Flags to indicate expected uri type */
-#define URI_VALID_RSYNC 0x01
-#define URI_VALID_HTTPS 0x02
+#define URI_VALID_RSYNC         0x01
+#define URI_VALID_HTTPS         0x02
+/* Work with a local workspace (eg. map rsync RRPD uri's) */
+#define URI_USE_RRDP_WORKSPACE  0x10
 
 struct rpki_uri;
 
+/* Maps RSYNC URIs of RRDP to a local workspace */
+int uri_create_rsync_str_rrdp(struct rpki_uri **, char const *, size_t);
+int uri_create_https_str_rrdp(struct rpki_uri **, char const *, size_t);
+
 int uri_create_rsync_str(struct rpki_uri **, char const *, size_t);
-int uri_create_https_str(struct rpki_uri **, char const *, size_t);
 int uri_create_mixed_str(struct rpki_uri **, char const *, size_t);
-int uri_create_mft(struct rpki_uri **, struct rpki_uri *, IA5String_t *);
+int uri_create_mft(struct rpki_uri **, struct rpki_uri *, IA5String_t *, bool);
 int uri_create_ad(struct rpki_uri **, ACCESS_DESCRIPTION *, int);
 
 void uri_refget(struct rpki_uri *);