]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Oops!... I Did It Again
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Wed, 29 Dec 2021 00:04:55 +0000 (18:04 -0600)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Wed, 29 Dec 2021 00:04:55 +0000 (18:04 -0600)
Goddamnit. This started as a couple of RRDP bugfixes that sprawled into
another massive refactor thorough.

Lots of stuff was simplified. The RRDP code was pretty filthy; some
functions tried to do too much at once, error codes were being
transformed unnecessarily, argument lists were too long, there were
outdated comments, and some awkward logic suggests clumsy and misguided
bugfixes have taken place.

I know I fixed the following bugs, but the refactor was very aggressive.
I have no hope of this list being exhaustive:

**** Corrupted HTTP download on retry ****

If an HTTP dowload failed mid-transfer, Fort would end up appending the
file to itself on retry, because the file descriptor wasn't reset.

**** HTTP code 304 being treated as an error ****

So the "If-Modified-Since" HTTP header was pure liability.

**** Per-TAL namespaces, not per-RPP namespaces ****

This is the original problem:
https://mailarchive.ietf.org/arch/msg/sidrops/FrAjMFWY5a_cofpOoCEO5Yr_ZLI/

Basically, RRDP files (snapshots and deltas) declare URIs for their
contained files (RPKI objects), and there's nothing intrinsically
stopping a malicious CA's RRDP file from overriding some other CA's RPKI
object. So the RP needs to create per-RPP namespaces.

Existing solution was using per-TAL namespaces. This prevented CAs from
one tree from overriding files from a different tree, but not files on
the same tree.

**** Bad fnstack management ****

Some RRDP error messages were referencing the wrong file, because the
file name was pushed too late to the stack.

**** Was always redownloading all RRDP on startup ****

RRDP session IDs and serials were cached on RAM. On top of that,
RRDP files (including notifications) were always being deleted
immediately after use.

This meant that, on startup, there was absolutely no way of telling
whether an RRDP RPP was outdated or not, so the code had to download
everything all over again.

This was particularly egregious in standalone mode, because that counts
as *always* startup. Ugh.

I purged the session cache, as well as that weird eager delete gimmic.
Fort now queries existing notification files to find out RRDP sessions
IDs and serials.

------------------------------------------------------------------------

New deprecations:

**** `rsync.strategy` ****

The `root` and `root-except-ta` strategies were naive optimizations
because they assumed rsync was the only available transfer protocol.
They just cause redundant transfers now that RRDP not only exists,
but has actually eclipsed rsync.

rsync always works in `strict` mode now, and `rsync.strategy` is
deprecated and ignored.

**** `shuffle-uris` ****

I'm willing to return this one if someone argues in its favor, but I
strongly suspect nobody cares.

Weird, annoying, seemingly pointless feature. And I hope no one's using
it, because it encourages rsync when HTTP is obviously preferred.

RFC 8630:

   In the case where a TAL contains multiple TA URIs, an RP MAY use a
   locally defined preference rule to select the URI to retrieve the
   self-signed RPKI CA certificate that is to be used as a TA.  Some
   examples are:

   o  Using the order provided in the TAL

   o  Selecting the TA URI randomly from the available list

   o  Creating a prioritized list of URIs based on RP-specific
      parameters, such as connection establishment delay

It sounds to me the spec is just throwing out ideas, not mandating the
existence of this flag. We don't implement the third point anyway.

`shuffle-uris` is now deprecated and a no-op. TAL URIs are always
queried top-to-bottom, as this is assumed to be the RIR's preference.

------------------------------------------------------------------------

It's gotten increasingly evident that I'm going to be maintaining this
project indefinitely and alone, so I feel like I need to move to a more
stateless model. I deleted or reimplemented the following tables:

- `reqs_errors`: This was very disproportionate overhead for a very
  small (and kind of optional) feature (failed download logging on the
  operation logs), which is going to be superceded by the Prometheus
  endpoint anyway.
  The Prometheus endpoint implementation has reached new levels of
  urgent.
- `visited_uris`: I think the repository cache should be cleansed by way
  of the "Accessed" cached files property, not from a list of "visited
  URIs."
  I'm still working out the details of this mechanism, but I (admittedly
  recklessly) already deleted the existing code to simplify the
  refactor.
- `db_rrdp_uris`: The validation cycle's temporary URI download status
  cache aspect of this sounds useful, so I extracted it into a new
  module: `rpp_dl_status`.
  On the other hand, the RRDP session ID and serial cache aspect was,
  as previously mentioned, problematic, so I removed it.
- `db_rrdp`: Its whole point was to cache the `db_rrdp_uris` and the
  "RRDP workspace" over different validation cycles. Since neither of
  them exist anymore (the latter was purged as part of the "per-RPP
  namespaces" bugfix), `db_rrdp` naturally followed.

------------------------------------------------------------------------

This is a big commit because most of the problems were intertwined. It's
also an unstable checkpoint; I left a bunch of TODOs, and no testing has
taken place. The rest can ship in proper incremental commits.

89 files changed:
docs/usage.md
src/Makefile.am
src/abbreviations.txt
src/asn1/signed_data.c
src/cert_stack.c
src/cert_stack.h
src/certificate_refs.c
src/certificate_refs.h
src/common.c
src/common.h
src/config.c
src/config.h
src/config/rsync_strategy.c
src/config/rsync_strategy.h
src/config/sync_strategy.c [deleted file]
src/config/sync_strategy.h [deleted file]
src/crypto/hash.c
src/data_structure/path_builder.c [new file with mode: 0644]
src/data_structure/path_builder.h [new file with mode: 0644]
src/delete_dir_daemon.c [deleted file]
src/delete_dir_daemon.h [deleted file]
src/extension.c
src/file.c
src/file.h
src/http/http.c
src/http/http.h
src/internal_pool.c [deleted file]
src/internal_pool.h [deleted file]
src/log.c
src/main.c
src/object/certificate.c
src/object/certificate.h
src/object/ghostbusters.c
src/object/ghostbusters.h
src/object/manifest.c
src/object/manifest.h
src/object/name.c
src/object/roa.h
src/object/tal.c
src/object/tal.h
src/random.c
src/reqs_errors.c [deleted file]
src/reqs_errors.h [deleted file]
src/resource.c
src/rpp/rpp.c [moved from src/rpp.c with 89% similarity]
src/rpp/rpp.h [moved from src/rpp.h with 82% similarity]
src/rpp/rpp_dl_status.c [new file with mode: 0644]
src/rpp/rpp_dl_status.h [new file with mode: 0644]
src/rrdp/db/db_rrdp.c [deleted file]
src/rrdp/db/db_rrdp.h [deleted file]
src/rrdp/db/db_rrdp_uris.c [deleted file]
src/rrdp/db/db_rrdp_uris.h [deleted file]
src/rrdp/delta.c [new file with mode: 0644]
src/rrdp/delta.h [new file with mode: 0644]
src/rrdp/notification.c [new file with mode: 0644]
src/rrdp/notification.h [new file with mode: 0644]
src/rrdp/rrdp.c [new file with mode: 0644]
src/rrdp/rrdp.h [new file with mode: 0644]
src/rrdp/rrdp_loader.c [deleted file]
src/rrdp/rrdp_loader.h [deleted file]
src/rrdp/rrdp_objects.c [deleted file]
src/rrdp/rrdp_objects.h [deleted file]
src/rrdp/rrdp_parser.c [deleted file]
src/rrdp/rrdp_parser.h [deleted file]
src/rrdp/snapshot.c [new file with mode: 0644]
src/rrdp/snapshot.h [new file with mode: 0644]
src/rrdp/types.c [new file with mode: 0644]
src/rrdp/types.h [new file with mode: 0644]
src/rsync/rsync.c
src/rsync/rsync.h
src/state.c
src/state.h
src/str_token.c
src/thread_var.c
src/thread_var.h
src/types/uri.c
src/types/uri.h
src/types/uri_list.c [new file with mode: 0644]
src/types/uri_list.h [new file with mode: 0644]
src/validation_handler.c
src/validation_handler.h
src/visited_uris.c [deleted file]
src/visited_uris.h [deleted file]
src/xml/relax_ng.c
src/xml/relax_ng.h
test/impersonator.c
test/rrdp_objects_test.c
test/rsync_test.c
test/tal_test.c

index 3f8c1c2cfa3bbe778c278ae08a399df2d03223eb..fe806f3a7401fa31b11f1d1803f9e03f1f964772 100644 (file)
@@ -955,14 +955,14 @@ See [`--http.priority`](#--httppriority).
 - **Availability:** `argv` and JSON
 - **Default:** `root-except-ta`
 
+> ![img/warn.svg](img/warn.svg) **DEPRECATED**. Because most of the RPKI repository now prefers RRDP, rsync strategies other than `strict` cause excessive redundant transfers.
+> 
+> Fort 1.6.0 is hardcoded to use `strict`.
+
 rsync synchronization strategy. Commands the way rsync URLs are approached during downloads.
 
 #### `strict`
 
-> In order to enable this strategy, recompile using the flag: **_ENABLE\_STRICT\_STRATEGY_**.
->
-> e.g. `$ make FORT_FLAGS='-DENABLE_STRICT_STRATEGY'`
-
 rsyncs every repository publication point separately. Only skips publication points that have already been downloaded during the current validation cycle. (Assuming each synchronization is recursive.)
 
 For example, suppose the validator gets certificates whose caRepository access methods (in their Subject Information Access extensions) point to the following publication points:
index 7d227a196b1c00670b2de726a6572ef906663dc6..9b6cf1463db34630bcbd24946f6bc2b6a870f0df 100644 (file)
@@ -1,7 +1,3 @@
-# Comment these out during releases.
-# Also increase optimization I guess (-O0 -> -On)
-LDFLAGS_DEBUG = -rdynamic
-
 bin_PROGRAMS = fort
 
 fort_SOURCES  = main.c
@@ -12,11 +8,9 @@ fort_SOURCES += cert_stack.h cert_stack.c
 fort_SOURCES += common.c common.h
 fort_SOURCES += config.h config.c
 fort_SOURCES += daemon.h daemon.c
-fort_SOURCES += delete_dir_daemon.h delete_dir_daemon.c
 fort_SOURCES += extension.h extension.c
 fort_SOURCES += file.h file.c
 fort_SOURCES += init.h init.c
-fort_SOURCES += internal_pool.h internal_pool.c
 fort_SOURCES += json_parser.c json_parser.h
 fort_SOURCES += line_file.h line_file.c
 fort_SOURCES += log.h log.c
@@ -24,9 +18,7 @@ fort_SOURCES += nid.h nid.c
 fort_SOURCES += notify.c notify.h
 fort_SOURCES += output_printer.h output_printer.c
 fort_SOURCES += random.h random.c
-fort_SOURCES += reqs_errors.h reqs_errors.c
 fort_SOURCES += resource.h resource.c
-fort_SOURCES += rpp.h rpp.c
 fort_SOURCES += sorted_array.h sorted_array.c
 fort_SOURCES += state.h state.c
 fort_SOURCES += str_token.h str_token.c
@@ -34,7 +26,6 @@ fort_SOURCES += thread_var.h thread_var.c
 fort_SOURCES += json_handler.h json_handler.c
 fort_SOURCES += validation_handler.h validation_handler.c
 fort_SOURCES += validation_run.h validation_run.c
-fort_SOURCES += visited_uris.h visited_uris.c
 
 fort_SOURCES += asn1/content_info.h asn1/content_info.c
 fort_SOURCES += asn1/decode.h asn1/decode.c
@@ -46,6 +37,7 @@ fort_SOURCES += types/delta.c types/delta.h
 fort_SOURCES += types/router_key.c types/router_key.h
 fort_SOURCES += types/serial.h types/serial.c
 fort_SOURCES += types/uri.h types/uri.c
+fort_SOURCES += types/uri_list.h types/uri_list.c
 fort_SOURCES += types/vrp.c types/vrp.h
 
 fort_SOURCES += config/boolean.c config/boolean.h
@@ -59,7 +51,6 @@ fort_SOURCES += config/rrdp_conf.h config/rrdp_conf.c
 fort_SOURCES += config/rsync_strategy.h config/rsync_strategy.c
 fort_SOURCES += config/str.c config/str.h
 fort_SOURCES += config/string_array.h config/string_array.c
-fort_SOURCES += config/sync_strategy.h config/sync_strategy.c
 fort_SOURCES += config/types.h
 fort_SOURCES += config/uint.c config/uint.h
 fort_SOURCES += config/uint32.c config/uint32.h
@@ -70,6 +61,7 @@ fort_SOURCES += crypto/hash.h crypto/hash.c
 
 fort_SOURCES += data_structure/array_list.h
 fort_SOURCES += data_structure/common.h
+fort_SOURCES += data_structure/path_builder.h data_structure/path_builder.c
 fort_SOURCES += data_structure/uthash.h
 fort_SOURCES += data_structure/uthash_nonfatal.h
 
@@ -92,12 +84,14 @@ fort_SOURCES += resource/ip4.h resource/ip4.c
 fort_SOURCES += resource/ip6.h resource/ip6.c
 fort_SOURCES += resource/asn.h resource/asn.c
 
-fort_SOURCES += rrdp/rrdp_loader.h rrdp/rrdp_loader.c
-fort_SOURCES += rrdp/rrdp_objects.h rrdp/rrdp_objects.c
-fort_SOURCES += rrdp/rrdp_parser.h rrdp/rrdp_parser.c
+fort_SOURCES += rpp/rpp.h rpp/rpp.c
+fort_SOURCES += rpp/rpp_dl_status.h rpp/rpp_dl_status.c
 
-fort_SOURCES += rrdp/db/db_rrdp.h rrdp/db/db_rrdp.c
-fort_SOURCES += rrdp/db/db_rrdp_uris.h rrdp/db/db_rrdp_uris.c
+fort_SOURCES += rrdp/types.h rrdp/types.c
+fort_SOURCES += rrdp/rrdp.h rrdp/rrdp.c
+fort_SOURCES += rrdp/notification.h rrdp/notification.c
+fort_SOURCES += rrdp/snapshot.h rrdp/snapshot.c
+fort_SOURCES += rrdp/delta.h rrdp/delta.c
 
 fort_SOURCES += rsync/rsync.h rsync/rsync.c
 
@@ -113,7 +107,6 @@ fort_SOURCES += rtr/rtr.c rtr/rtr.h
 fort_SOURCES += rtr/db/db_table.c rtr/db/db_table.h
 fort_SOURCES += rtr/db/delta.c rtr/db/delta.h
 fort_SOURCES += rtr/db/deltas_array.c rtr/db/deltas_array.h
-fort_SOURCES += rtr/db/roa.h
 fort_SOURCES += rtr/db/vrps.c rtr/db/vrps.h
 
 fort_SOURCES += slurm/db_slurm.c slurm/db_slurm.h
@@ -133,7 +126,7 @@ fort_CFLAGS  = -Wall -Wno-cpp -Wpedantic
 # Feel free to temporarily remove this one if you're not using gcc 7.3.0.
 #fort_CFLAGS += $(GCC_WARNS)
 fort_CFLAGS += -std=gnu11 -O2 -g $(FORT_FLAGS) ${XML2_CFLAGS}
-fort_LDFLAGS = $(LDFLAGS_DEBUG)
+fort_LDFLAGS = -rdynamic
 fort_LDADD   = ${JANSSON_LIBS} ${CURL_LIBS} ${XML2_LIBS}
 
 # I'm tired of scrolling up, but feel free to comment this out.
index d49a33aec0941314c2ee6a3627d216740ac3d379..03bfe526f56be427098200069526a71f6ece3270 100644 (file)
@@ -6,20 +6,27 @@ a bug.
 addr: address
 addr4: IPv4 address
 addr6: IPv6 address
+arg: argument
 be: Big Endian
 cert: certificate
 certstack: certificate stack
 db: database
+dl: download
 eof: end of file
 err: error
 fd: File Descriptor (see `man 2 accept`)
 guri: global URI
 hdr: header
+htable: hash table
 id: identifier
+idx: index
 len: length
 max: maximum
+meta: metadata
+mft: Manifest
 min: minimum
 msg: message
+notif: notification
 pdu: Protocol Data Unit (RFC 6810)
 pp: Publication Point
 pr: print
@@ -29,6 +36,8 @@ refput: reference put (-1 to reference counter)
 rk: Router Key
 rpp: Repository Publication Point
 str: string
+ta: Trust Anchor
+tal: Trust Anchor Locator
 tmp: temporal
 uint: unsigned int
 vrp: Validated ROA Payload (RFC 6811)
index 16e36b00248ff6869640adf6e085cdc920240aec..6a7f691307d9ac0c4ac5317a6393a502cebea243 100644 (file)
@@ -102,7 +102,7 @@ handle_sdata_certificate(ANY_t *cert_encoded, struct signed_object_args *args,
            &policy);
        if (error)
                goto end2;
-       error = certificate_validate_aia(args->refs.caIssuers, cert);
+       error = certificate_validate_aia(&args->refs.caIssuers, cert);
        if (error)
                goto end2;
        error = certificate_validate_signature(cert, signedData, signature);
index 447895860fce36fa873069c9de10702a34f1d1b1..1ec72de7c8d17b634c0112ab99b7e761f6e7aa81 100644 (file)
@@ -56,13 +56,6 @@ struct metadata_node {
        struct serial_numbers serials;
        struct subjects subjects;
 
-       /*
-        * Certificate repository "level". This aims to identify if the
-        * certificate is located at a distinct server than its father (common
-        * case when the RIRs delegate RPKI repositories).
-        */
-       unsigned int level;
-
        /** Used by certstack. Points to the next stacked certificate. */
        SLIST_ENTRY(metadata_node) next;
 };
@@ -86,9 +79,12 @@ struct cert_stack {
        struct defer_stack defers;
 
        /**
-        * x509 stack. Parents of the certificate we're currently iterating
-        * through.
-        * Formatted for immediate libcrypto consumption.
+        * Trusted stack. A chain of certificates that will (because of the
+        * order traversal) validate the next certificate, at any given time.
+        *
+        * Ancestors of the certificate we're currently iterating through.
+        *
+        * Formatted specifically for instant libcrypto consumption.
         */
        STACK_OF(X509) *x509s;
 
@@ -97,7 +93,7 @@ struct cert_stack {
         *
         * (These two stacks should always have the same size. The reason why I
         * don't combine them is because libcrypto's validation function needs
-        * the X509 stack, and I'm not creating it over and over again.)
+        * the X509 stack, and I can't add data to it.)
         *
         * (This is a SLIST and not a STACK_OF because the OpenSSL stack
         * implementation is different than the LibreSSL one, and the latter is
@@ -262,12 +258,6 @@ again:     node = SLIST_FIRST(&stack->defers);
        return 0;
 }
 
-bool
-deferstack_is_empty(struct cert_stack *stack)
-{
-       return SLIST_EMPTY(&stack->defers);
-}
-
 static int
 init_resources(X509 *x509, enum rpki_policy policy, enum cert_type type,
     struct resources **_result)
@@ -304,28 +294,6 @@ fail:
        return error;
 }
 
-static int
-init_level(struct cert_stack *stack, unsigned int *_result)
-{
-       struct metadata_node *head_meta;
-       unsigned int work_repo_level;
-       unsigned int result;
-
-       /*
-        * Bruh, I don't understand the point of this block.
-        * Why can't it just be `result = working_repo_peek_level();`?
-        */
-
-       result = 0;
-       work_repo_level = working_repo_peek_level();
-       head_meta = SLIST_FIRST(&stack->metas);
-       if (head_meta != NULL && work_repo_level > head_meta->level)
-               result = work_repo_level;
-
-       *_result = result;
-       return 0;
-}
-
 static struct defer_node *
 create_separator(void)
 {
@@ -339,11 +307,16 @@ create_separator(void)
        return result;
 }
 
-/** Steals ownership of @x509 on success. */
+/*
+ * Add certificate to the trusted stack.
+ *
+ * Steals ownership of @x509 on success.
+ */
 int
-x509stack_push(struct cert_stack *stack, struct rpki_uri *uri, X509 *x509,
-    enum rpki_policy policy, enum cert_type type)
+x509stack_push(struct rpki_uri *uri, X509 *x509, enum rpki_policy policy,
+    enum cert_type type)
 {
+       struct cert_stack *stack;
        struct metadata_node *meta;
        struct defer_node *defer_separator;
        int ok;
@@ -362,9 +335,7 @@ x509stack_push(struct cert_stack *stack, struct rpki_uri *uri, X509 *x509,
        if (error)
                goto cleanup_subjects;
 
-       error = init_level(stack, &meta->level); /* Does not need a revert */
-       if (error)
-               goto destroy_resources;
+       stack = validation_certstack(state_retrieve());
 
        defer_separator = create_separator();
        if (defer_separator == NULL) {
@@ -404,10 +375,13 @@ cleanup_subjects:
  * deferstack_pop().)
  */
 void
-x509stack_cancel(struct cert_stack *stack)
+x509stack_cancel(void)
 {
+       struct cert_stack *stack;
        struct defer_node *defer_separator;
 
+       stack = validation_certstack(state_retrieve());
+
        x509stack_pop(stack);
 
        defer_separator = SLIST_FIRST(&stack->defers);
@@ -418,8 +392,9 @@ x509stack_cancel(struct cert_stack *stack)
 }
 
 X509 *
-x509stack_peek(struct cert_stack *stack)
+x509stack_peek(void)
 {
+       struct cert_stack *stack = validation_certstack(state_retrieve());
        return sk_X509_value(stack->x509s, sk_X509_num(stack->x509s) - 1);
 }
 
@@ -438,13 +413,6 @@ x509stack_peek_resources(struct cert_stack *stack)
        return (meta != NULL) ? meta->resources : NULL;
 }
 
-unsigned int
-x509stack_peek_level(struct cert_stack *stack)
-{
-       struct metadata_node *meta = SLIST_FIRST(&stack->metas);
-       return (meta != NULL) ? meta->level : 0;
-}
-
 static int
 get_current_file_name(char **_result)
 {
@@ -551,34 +519,94 @@ x509stack_store_subject(struct cert_stack *stack, struct rfc5280_name *subject,
        int error;
 
        /*
-        * There's something that's not clicking with me:
-        *
         * "Each distinct subordinate CA and
         * EE certified by the issuer MUST be identified using a subject name
         * that is unique per issuer.  In this context, 'distinct' is defined as
         * an entity and a given public key."
         *
-        * Does the last sentence have any significance to us? I don't even
-        * understand why the requirement exists. 5280 and 6487 don't even
-        * define "entity." We'll take the closest definition from the context,
-        * specifically from RFC 6484 or RFC 6481 (both RFCs don't define
-        * "entity" explicitly, but use the word in a way that it can be
-        * inferred what it means).
+        * What the hell? Removing redundancy:
+        *
+        *      Each distinct subordinate CA and EE certified by the issuer MUST
+        *      have a unique subject name. In this context, 'distinct' is
+        *      defined as an entity and a given public key.
+        *
+        * Trimming fat:
+        *
+        *      Each distinct child certified by the issuer MUST have a unique
+        *      subject name. In this context, 'distinct' is defined as an
+        *      entity and a given public key.
+        *
+        * Translation:
+        *
+        *      Sibling certificates must have different subject names.
+        *      Among a parent's children, siblings are identified by their
+        *      [entity, public key] tuple.
+        *
+        * From RFC 6484, one can surmise that "entity" means "INR holder."
+        * (INR = Internet Number Resource = IP address or ASN.)
+        *
+        * The requirement is kind of circular because an entity would normally
+        * be identified by its parent certificate and subject name... right?
+        * How else would an RPKI consumer identify the entity?
+        *
+        * Educated flight of fancy:
+        *
+        *      Sibling certificates must have different subject names.
+        *      Among a parent's children, siblings are identified by their
+        *      [parent, subject name, public key] tuple.
+        *
+        * Given that we've established that we're talking about siblings,
+        * the parent is always the same, so it becomes
+        *
+        *      Sibling certificates must have different subject names.
+        *      Among a parent's children, siblings are identified by their
+        *      [subject name, public key] tuple.
+        *
+        * Circular:
+        *
+        *      Given two siblings, if their [subject name, public key] is
+        *      different, then their subject names must also be different.
+        *
+        * In other words:
+        *
+        * - If A = [a, m] and B = [a, m], then no constraints must be imposed.
+        * - If A = [a, m] and B = [a, n], then a != a. This makes no sense.
+        * - If A = [a, m] and B = [b, m], then a != b. Self-evident.
+        * - If A = [a, m] and B = [b, n], then a != b. Self-evident.
+        *
+        * So... assuming my train of thought is correct, the requirement can
+        * therefore be reduced to
+        *
+        *      If two sibling certificates have different public keys, then
+        *      they must have different subject names as well.
+        *
+        * In other words, this whole fucking mess is just a reword of the
+        * (infinitely more competently articulated) immediately following
+        * sentence:
         *
         * "An issuer SHOULD use a different
         * subject name if the subject's key pair has changed (i.e., when the CA
         * issues a certificate as part of re-keying the subject.)"
         *
-        * It's really weird that it seems to be rewording the same requirement
-        * except the first version is defined as MUST and the second one is
-        * defined as SHOULD.
+        * Except... the two requirements are actually contradicting each other:
+        * The former is defined as a MUST and the latter is a SHOULD.
+        *
+        * FFFFFFFFFUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUCK!!!
         *
-        * Ugh. Okay. Let's use some common sense. There are four possible
-        * situations:
+        * There's also another problem: What should we do when we find two
+        * siblings with different public keys and equal names? Are we even
+        * expected to do anything? I mean, does this requirement exist to
+        * simplify the work of RPs, or to be enforced by RPs?
         *
-        * - Certificates do not share name nor public key. We should accept
-        *   this.
-        * - Certificates share name, but not public key. We should reject this.
+        * Sigh. I'm gonna have to ping some people. In the meantime, I'm going
+        * to comment the caller, because this code is conflicting with the
+        * rpki_uri refactors.
+        *
+        * Leftover from the previous version of this comment:
+        *
+        * - Certificates do not share name nor public key. This is the most
+        *   normal situation; accept.
+        * - Certificates share name, but not public key. Illegal.
         * - Certificates share public key, but not name. This is basically
         *   impossible, but fine nonetheless. Accept.
         *   (But maybe issue a warning. It sounds like the two children can
@@ -586,7 +614,6 @@ x509stack_store_subject(struct cert_stack *stack, struct rfc5280_name *subject,
         * - Certificates share name and public key. This likely means that we
         *   are looking at two different versions of the same certificate.
         *   Accept. (see rfc6484#section-4.7.1 for an example)
-        *
         */
 
        meta = SLIST_FIRST(&stack->metas);
index 61c209f4c4f37b7d2790c000ff8aa41fff78d9b6..58e3e68d4ba6de939d51a5755373c76bd8e3d406 100644 (file)
@@ -9,8 +9,8 @@
 #include "types/uri.h"
 
 /*
- * One certificate stack is allocated per validation cycle, and it is used
- * through its entirety to hold the certificates relevant to the ongoing
+ * One certificate stack is allocated per validation cycle thread, and it is
+ * used through its entirety to hold the certificates relevant to the ongoing
  * validation.
  *
  * Keep in mind: This module deals with two different (but correlated) stack
  *   list, and haven't been opened yet.)
  *   It prevents us from having to validate the RPKI tree in a recursive manner,
  *   which would be prone to stack overflow.
- * - x509 stack: It is a chain of certificates, ready to be validated by
- *   libcrypto.
- *   For any given certificate being validated, this stack stores all of its
- *   parents.
+ * - x509 stack: Trusted stack. It is a chain of certificates, meant to be used
+ *   as ancestors of the certificate being presently validated.
  */
 
 struct cert_stack;
@@ -40,15 +38,12 @@ void certstack_destroy(struct cert_stack *);
 
 int deferstack_push(struct cert_stack *, struct deferred_cert *cert);
 int deferstack_pop(struct cert_stack *, struct deferred_cert *cert);
-bool deferstack_is_empty(struct cert_stack *);
 
-int x509stack_push(struct cert_stack *, struct rpki_uri *, X509 *,
-    enum rpki_policy, enum cert_type);
-void x509stack_cancel(struct cert_stack *);
-X509 *x509stack_peek(struct cert_stack *);
+int x509stack_push(struct rpki_uri *, X509 *, enum rpki_policy, enum cert_type);
+void x509stack_cancel(void);
+X509 *x509stack_peek(void);
 struct rpki_uri *x509stack_peek_uri(struct cert_stack *);
 struct resources *x509stack_peek_resources(struct cert_stack *);
-unsigned int x509stack_peek_level(struct cert_stack *);
 int x509stack_store_serial(struct cert_stack *, BIGNUM *);
 typedef int (*subject_pk_check_cb)(bool *, char const *, void *);
 int x509stack_store_subject(struct cert_stack *, struct rfc5280_name *,
index 7fb617cfafee8ad676c96671d4453b38fe68291a..ebb3a4b3b48ee005b4d1fcf43da628c1d181d917 100644 (file)
@@ -14,10 +14,8 @@ void
 refs_cleanup(struct certificate_refs *refs)
 {
        free(refs->crldp);
-       if (refs->caIssuers != NULL)
-               uri_refput(refs->caIssuers);
-       if (refs->signedObject != NULL)
-               uri_refput(refs->signedObject);
+       uris_cleanup(&refs->caIssuers);
+       uris_cleanup(&refs->signedObject);
 }
 
 static int
@@ -32,7 +30,7 @@ validate_cdp(struct certificate_refs *refs, struct rpp const *pp)
        if (pp_crl == NULL)
                pr_crit("Manifest's CRL was not recorded.");
 
-       if (strcmp(refs->crldp, uri_get_global(pp_crl)) != 0) {
+       if (strcmp(uri_get_global(pp_crl), refs->crldp) != 0) {
                return pr_val_err("Certificate's CRL Distribution Point ('%s') does not match manifest's CRL ('%s').",
                    refs->crldp, uri_get_global(pp_crl));
        }
@@ -44,12 +42,11 @@ static int
 validate_signedObject(struct certificate_refs *refs,
     struct rpki_uri *signedObject_uri)
 {
-       if (refs->signedObject == NULL)
+       if (refs->signedObject.len == 0)
                pr_crit("Certificate's signedObject was not recorded.");
 
-       if (!uri_equals(refs->signedObject, signedObject_uri)) {
-               return pr_val_err("Certificate's signedObject ('%s') does not match the URI of its own signed object (%s).",
-                   uri_val_get_printable(refs->signedObject),
+       if (!uris_contains(&refs->signedObject, signedObject_uri)) {
+               return pr_val_err("Certificate's signedObject list does not contain the URI of its own signed object (%s).",
                    uri_val_get_printable(signedObject_uri));
        }
 
@@ -75,9 +72,9 @@ refs_validate_ca(struct certificate_refs *refs, struct rpp const *pp)
        if (error)
                return error;
 
-       if (refs->signedObject != NULL)
-               pr_crit("CA summary has a signedObject ('%s').",
-                   uri_op_get_printable(refs->signedObject));
+       if (refs->signedObject.len != 0)
+               pr_crit("CA summary has at least one signedObject ('%s').",
+                   uri_op_get_printable(refs->signedObject.array[0]));
 
        return 0;
 }
index 17b8384f5ab852cf98d4a4cdea5708c64149128b..3586c8614b4fc5251a8c596a0ed419068ed60d3e 100644 (file)
@@ -1,7 +1,8 @@
 #ifndef SRC_CERTIFICATE_REFS_H_
 #define SRC_CERTIFICATE_REFS_H_
 
-#include "rpp.h"
+#include "rpp/rpp.h"
+#include "types/uri_list.h"
 
 /**
  * Some of the URLs defined in Access Descriptions of a certificate's
@@ -28,12 +29,12 @@ struct certificate_refs {
         * AIA's caIssuers. Non-TA certificates only.
         * RFC 6487, section 4.8.7.
         */
-       struct rpki_uri *caIssuers;
+       struct uri_list caIssuers;
        /**
         * SIA's signedObject. EE certificates only.
         * RFC 6487, section 4.8.8.2.
         */
-       struct rpki_uri *signedObject;
+       struct uri_list signedObject;
 };
 
 void refs_init(struct certificate_refs *);
index 918e4117984fe7edc9e5fed2411609e93b31d78a..9c4dd99aa2b8a25e43e6adba356fcd554b4528f9 100644 (file)
@@ -180,8 +180,10 @@ valid_file_or_dir(char const *location, bool check_file, bool check_dir,
                pr_crit("Wrong usage, at least one check must be 'true'.");
 
        if (stat(location, &attr) == -1) {
-               if (error_fn != NULL)
-                       error_fn(errno, "stat(%s) failed", location);
+               if (error_fn != NULL) {
+                       error_fn(errno, "stat(%s) failed: %s", location,
+                           strerror(errno));
+               }
                return false;
        }
 
@@ -248,6 +250,9 @@ create_dir(char *path)
 /**
  * Apparently, RSYNC does not like to create parent directories.
  * This function fixes that.
+ *
+ * TODO (aaaa) that's not enough. Document this properly.
+ * TODO (aaaa) maybe move this to file.c?
  */
 int
 create_dir_recursive(char const *path)
@@ -303,6 +308,8 @@ remove_file(char const *path)
  * The algorithm is a bit aggressive, but rmdir() won't delete
  * something unless is empty, so in case the dir still has something in
  * it the cycle is finished.
+ *
+ * TODO (aaaa) move to file.c?
  */
 int
 delete_dir_recursive_bottom_up(char const *path)
@@ -372,62 +379,3 @@ get_current_time(time_t *result)
        *result = now;
        return 0;
 }
-
-/*
- * Maps an absolute @uri that begins with @uri_prefix (either 'rsync://' or
- * 'https://') to a local URI. If a @workspace is set, append such location
- * to the local-repository location (this workspace is used at https URIs).
- *
- * @result is allocated with the local URI.
- *
- * Returns 0 on success, otherwise an error code.
- */
-int
-map_uri_to_local(char const *uri, char const *uri_prefix, char const *workspace,
-    char **result)
-{
-       char const *repository;
-       char *local;
-       size_t repository_len;
-       size_t uri_prefix_len;
-       size_t uri_len;
-       size_t workspace_len;
-       size_t extra_slash;
-       size_t offset;
-
-       repository = config_get_local_repository();
-       repository_len = strlen(repository);
-       uri_prefix_len = strlen(uri_prefix);
-       uri_len = strlen(uri);
-
-       uri += uri_prefix_len;
-       uri_len -= uri_prefix_len;
-       extra_slash = (repository[repository_len - 1] == '/') ? 0 : 1;
-
-       workspace_len = 0;
-       if (workspace != NULL)
-               workspace_len = strlen(workspace);
-
-       local = malloc(repository_len + extra_slash + workspace_len + uri_len +
-           1);
-       if (local == NULL)
-               return pr_enomem();
-
-       offset = 0;
-       strcpy(local + offset, repository);
-       offset += repository_len;
-       if (extra_slash) {
-               strcpy(local + offset, "/");
-               offset += extra_slash;
-       }
-       if (workspace_len > 0) {
-               strcpy(local + offset, workspace);
-               offset += workspace_len;
-       }
-       strncpy(local + offset, uri, uri_len);
-       offset += uri_len;
-       local[offset] = '\0';
-
-       *result = local;
-       return 0;
-}
index cf21ccc5419854536142a31ce4e8e289591175b9..23962a3dcf6aac633ff8e8f08c151a36a279ef10 100644 (file)
@@ -7,24 +7,11 @@
 
 /* "I think that this is not supposed to be implemented." */
 #define ENOTSUPPORTED 3172
-/* "I haven't implemented this yet." */
-#define ENOTIMPLEMENTED 3173
-/*
- * "URI was not RSYNC; ignore it."
- * Not really an error. The RFCs usually declare URI lists; usually only one of
- * them is required to be RSYNC and the others should be skipped (until we
- * start supporting them.)
- */
-#define ENOTRSYNC 3174
-/*
- * "URI was not HTTPS; ignore it."
- * Not necessarily an error (just as ENOTRSYNC), since both type of URIs can
- * still coexist in most scenarios.
- */
-#define ENOTHTTPS 3175
 
 /*
  * A request made to a server (eg. rsync, http) has failed, even after retrying
+ *
+ * TODO (aaaa) I think this should just be EAGAIN.
  */
 #define EREQFAILED 3176
 
@@ -58,6 +45,4 @@ int delete_dir_recursive_bottom_up(char const *);
 
 int get_current_time(time_t *);
 
-int map_uri_to_local(char const *, char const*, char const *, char **);
-
 #endif /* SRC_RTR_COMMON_H_ */
index a955c8d778332f7ba23dc7ac24b448f2c6959a80..a603cf90278e164186b2f3809b5f67d7ef4b69be 100644 (file)
@@ -20,7 +20,6 @@
 #include "config/init_tals.h"
 #include "config/rrdp_conf.h"
 #include "config/str.h"
-#include "config/sync_strategy.h"
 #include "config/uint.h"
 #include "config/uint32.h"
 #include "config/work_offline.h"
@@ -40,12 +39,12 @@ struct rpki_config {
        char *tal;
        /** Path of our local clone of the repository */
        char *local_repository;
-       /** TODO (later) Deprecated, remove it. RSYNC download strategy. */
-       enum rsync_strategy sync_strategy;
        /**
         * Handle TAL URIs in random order?
         * (https://tools.ietf.org/html/rfc8630#section-3, last
         * paragraphs)
+        *
+        * Deprecated.
         */
        bool shuffle_tal_uris;
        /**
@@ -93,7 +92,7 @@ struct rpki_config {
                 * their accessMethod extension.
                 */
                unsigned int priority;
-               /* Synchronization download strategy. */
+               /* Synchronization download strategy. TODO Deprecated */
                enum rsync_strategy strategy;
                /* Retry conf, utilized on errors */
                struct {
@@ -105,6 +104,10 @@ struct rpki_config {
                char *program;
                struct {
                        struct string_array flat;
+                       /*
+                        * Not actually --recursive.
+                        * It's used to fetch RPPs, so it uses --dirs.
+                        */
                        struct string_array recursive;
                } args;
        } rsync;
@@ -304,18 +307,12 @@ static const struct option_field options[] = {
                .offset = offsetof(struct rpki_config, local_repository),
                .doc = "Directory where the repository local cache will be stored/read",
                .arg_doc = "<directory>",
-       }, {
-               .id = 1001,
-               .name = "sync-strategy",
-               .type = &gt_sync_strategy,
-               .offset = offsetof(struct rpki_config, sync_strategy),
-               .doc = "RSYNC download strategy. Deprecated; use 'rsync.strategy' instead.",
        }, {
                .id = 2001,
                .name = "shuffle-uris",
                .type = &gt_bool,
                .offset = offsetof(struct rpki_config, shuffle_tal_uris),
-               .doc = "Shuffle URIs in the TAL before accessing them",
+               .doc = "(Deprecated) Shuffle URIs in the TAL before accessing them",
        }, {
                .id = 1002,
                .name = "maximum-certificate-depth",
@@ -506,7 +503,7 @@ static const struct option_field options[] = {
                .name = "rsync.arguments-recursive",
                .type = &gt_string_array,
                .offset = offsetof(struct rpki_config, rsync.args.recursive),
-               .doc = "RSYNC program arguments that will trigger a recursive RSYNC",
+               .doc = "RSYNC program arguments that will synchronize RPPs",
                .availability = AVAILABILITY_JSON,
                /* Unlimited */
                .max = 0,
@@ -515,7 +512,7 @@ static const struct option_field options[] = {
                .name = "rsync.arguments-flat",
                .type = &gt_string_array,
                .offset = offsetof(struct rpki_config, rsync.args.flat),
-               .doc = "RSYNC program arguments that will trigger a non-recursive RSYNC",
+               .doc = "RSYNC program arguments that will synchronize single files",
                .availability = AVAILABILITY_JSON,
                /* Unlimited */
                .max = 0,
@@ -609,7 +606,7 @@ static const struct option_field options[] = {
                .max = UINT_MAX,
        }, {
                .id = 9007,
-               .name = "http.idle-timeout", /* TODO DEPRECATED. */
+               .name = "http.idle-timeout", /* TODO Deprecated. */
                .type = &gt_uint,
                .offset = offsetof(struct rpki_config, http.low_speed_time),
                .doc = "Deprecated; currently an alias for --http.low-speed-time. Use --http.low-speed-time instead.",
@@ -785,7 +782,7 @@ static const struct option_field options[] = {
                .name = "stale-repository-period",
                .type = &gt_uint,
                .offset = offsetof(struct rpki_config, stale_repository_period),
-               .doc = "Time period that must lapse to warn about stale repositories",
+               .doc = "(Deprecated) Time period that must lapse to warn about stale repositories",
                .min = 0,
                .max = UINT_MAX,
        },
@@ -964,7 +961,7 @@ static int
 set_default_values(void)
 {
        static char const *recursive_rsync_args[] = {
-               "--recursive",
+               "--dirs",
                "--delete",
                "--times",
                "--contimeout=20",
@@ -1017,8 +1014,6 @@ set_default_values(void)
                goto revert_port;
        }
 
-       rpki_config.sync_strategy = RSYNC_ROOT_EXCEPT_TA;
-       rpki_config.shuffle_tal_uris = false;
        rpki_config.maximum_certificate_depth = 32;
        rpki_config.mode = SERVER;
        rpki_config.work_offline = false;
@@ -1026,7 +1021,7 @@ set_default_values(void)
 
        rpki_config.rsync.enabled = true;
        rpki_config.rsync.priority = 50;
-       rpki_config.rsync.strategy = RSYNC_ROOT_EXCEPT_TA;
+       rpki_config.rsync.strategy = RSYNC_STRICT;
        rpki_config.rsync.retry.count = 1;
        rpki_config.rsync.retry.interval = 4;
        rpki_config.rsync.program = strdup("rsync");
@@ -1169,10 +1164,6 @@ validate_config(void)
            !valid_file_or_dir(rpki_config.slurm, true, true, __pr_op_err))
                return pr_op_err("Invalid slurm location.");
 
-       /* TODO (later) Remove when sync-strategy is fully deprecated */
-       if (!rpki_config.rsync.enabled)
-               config_set_sync_strategy(RSYNC_OFF);
-
        return 0;
 }
 
@@ -1385,12 +1376,6 @@ config_get_local_repository(void)
        return rpki_config.local_repository;
 }
 
-bool
-config_get_shuffle_tal_uris(void)
-{
-       return rpki_config.shuffle_tal_uris;
-}
-
 unsigned int
 config_get_max_cert_depth(void)
 {
@@ -1520,20 +1505,9 @@ config_get_rsync_program(void)
 struct string_array const *
 config_get_rsync_args(bool is_ta)
 {
-       switch (rpki_config.rsync.strategy) {
-       case RSYNC_ROOT:
-               return &rpki_config.rsync.args.recursive;
-       case RSYNC_ROOT_EXCEPT_TA:
-               return is_ta
-                   ? &rpki_config.rsync.args.flat
-                   : &rpki_config.rsync.args.recursive;
-       case RSYNC_STRICT:
-               return &rpki_config.rsync.args.flat;
-       default:
-               break;
-       }
-
-       pr_crit("Invalid rsync strategy: '%u'", rpki_config.rsync.strategy);
+       return is_ta
+           ? &rpki_config.rsync.args.flat
+           : &rpki_config.rsync.args.recursive;
 }
 
 bool
@@ -1675,18 +1649,6 @@ config_set_rrdp_enabled(bool value)
        rpki_config.rrdp.enabled = value;
 }
 
-void
-config_set_sync_strategy(enum rsync_strategy value)
-{
-       rpki_config.sync_strategy = value;
-}
-
-void
-config_set_rsync_strategy(enum rsync_strategy value)
-{
-       rpki_config.rsync.strategy = value;
-}
-
 void
 config_set_rrdp_priority(unsigned int value)
 {
index f5ffe1b366f2c6dc489318a26a6beccdb5550539..404a45b7e0c7afcbfb3c1e898e836db18893b5ab 100644 (file)
@@ -29,7 +29,6 @@ char const *config_get_slurm(void);
 
 char const *config_get_tal(void);
 char const *config_get_local_repository(void);
-bool config_get_shuffle_tal_uris(void);
 unsigned int config_get_max_cert_depth(void);
 enum mode config_get_mode(void);
 char const *config_get_http_user_agent(void);
@@ -84,10 +83,6 @@ void config_set_http_enabled(bool);
 /* TODO (later) Deprecated */
 void config_set_rrdp_enabled(bool);
 
-/* TODO (later) Remove when sync-strategy is fully deprecated */
-void config_set_sync_strategy(enum rsync_strategy);
-void config_set_rsync_strategy(enum rsync_strategy);
-
 /* TODO (later) Remove once rrdp.* is fully deprecated */
 void config_set_rrdp_priority(unsigned int);
 void config_set_http_priority(unsigned int);
index 0131ec8316dc292c9d92fe71795abca258dc1c39..310f734cc50ca3ac1468a8f28b72ceb9d7f3696b 100644 (file)
@@ -1,80 +1,26 @@
 #include "config/rsync_strategy.h"
 
 #include <getopt.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "config.h"
 #include "log.h"
-#include "config/str.h"
-
-#define RSYNC_VALUE_STRICT             "strict"
-#define RSYNC_VALUE_ROOT               "root"
-#define RSYNC_VALUE_ROOT_EXCEPT_TA     "root-except-ta"
-
-#define DEREFERENCE(void_value) (*((enum rsync_strategy *) void_value))
 
-#ifdef ENABLE_STRICT_STRATEGY
-#define PRINT_STRICT_ARG_DOC "|" RSYNC_VALUE_STRICT
-#define HANDLE_RSYNC_STRICT DEREFERENCE(result) = RSYNC_STRICT;
-#else
-#define PRINT_STRICT_ARG_DOC
-#define HANDLE_RSYNC_STRICT                                            \
-       return pr_op_err("Unknown rsync synchronization strategy: '%s'. In order to use it, recompile using flag ENABLE_STRICT_STRATEGY.",\
-           str);
-#endif
-
-void
+static void
 print_rsync_strategy(struct option_field const *field, void *value)
 {
-       char const *str = "<unknown>";
-
-       switch (DEREFERENCE(value)) {
-       case RSYNC_STRICT:
-               str = RSYNC_VALUE_STRICT;
-               break;
-       case RSYNC_ROOT:
-               str = RSYNC_VALUE_ROOT;
-               break;
-       case RSYNC_ROOT_EXCEPT_TA:
-               str = RSYNC_VALUE_ROOT_EXCEPT_TA;
-               break;
-       default:
-               break;
-       }
-
-       pr_op_info("%s: %s", field->name, str);
+       /* Deprecated. */
 }
 
-int
+static int
 parse_argv_rsync_strategy(struct option_field const *field, char const *str,
     void *result)
 {
-       if (strcmp(str, RSYNC_VALUE_STRICT) == 0)
-               HANDLE_RSYNC_STRICT
-       else if (strcmp(str, RSYNC_VALUE_ROOT) == 0)
-               DEREFERENCE(result) = RSYNC_ROOT;
-       else if (strcmp(str, RSYNC_VALUE_ROOT_EXCEPT_TA) == 0)
-               DEREFERENCE(result) = RSYNC_ROOT_EXCEPT_TA;
-       else
-               return pr_op_err("Unknown rsync synchronization strategy: '%s'",
-                   str);
-
-       /* TODO (later) Remove when sync-strategy is fully deprecated */
-       config_set_sync_strategy(DEREFERENCE(result));
-
-       return 0;
+       return pr_op_warn("--rsync.strategy is deprecated; please remove it.");
 }
 
-int
+static int
 parse_json_rsync_strategy(struct option_field const *opt, struct json_t *json,
     void *result)
 {
-       char const *string;
-       int error;
-
-       error = parse_json_string(json, opt->name, &string);
-       return error ? error : parse_argv_rsync_strategy(opt, string, result);
+       return pr_op_warn("rsync.strategy is deprecated; please remove it.");
 }
 
 const struct global_type gt_rsync_strategy = {
@@ -83,7 +29,5 @@ const struct global_type gt_rsync_strategy = {
        .print = print_rsync_strategy,
        .parse.argv = parse_argv_rsync_strategy,
        .parse.json = parse_json_rsync_strategy,
-       .arg_doc = RSYNC_VALUE_ROOT
-           "|" RSYNC_VALUE_ROOT_EXCEPT_TA
-           PRINT_STRICT_ARG_DOC,
+       .arg_doc = "strict|root|root-except-ta",
 };
index 620cff60f3f75f4d399bbe2567f86fd487249bde..e67796b6cd8bfc3db4498f12ff6eb27d60b2577d 100644 (file)
@@ -4,72 +4,18 @@
 #include "config/types.h"
 
 enum rsync_strategy {
-       /*
-        * TODO (later) Deprecated. Still alive so that 'sync-strategy' and
-        * 'rsync.strategy' can live together.
-        *
-        * 'sync-strategy' type must handle this value to set 'rsync.enabled'
-        * as 'false'.
-        */
-       RSYNC_OFF,
        /**
         * Strictly correct download strategy.
         *
         * The validator will sync each repository publication point separately
         * as requested by each caRepository contained in the CA certificates'
         * SIA extensions.
-        *
-        * No risk of downloading unneeded files, but otherwise slow, as every
-        * different repository publication point requires a separate sync call.
-        *
-        * In order to enable this strategy, compile using the flag:
-        * ENABLE_STRICT_STRATEGY
         */
        RSYNC_STRICT,
-       /**
-        * Always download the likely root of the entire repository.
-        *
-        * For example, if we get the following caRepositories:
-        *
-        * - `rsync://a.b.c/d/e/f/g/h/i`
-        * - `rsync://a.b.c/d/e/f/g/h/j`
-        * - `rsync://a.b.c/d/e/f/k`
-        *
-        * This strategy will synchronize `rsync://a.b.c/d` while parsing the
-        * first caRepository, and then skip synchronization during the second
-        * and third ones. (Because they are already downloaded.)
-        *
-        * This strategy risks downloading unneeded files, and even failing due
-        * to lack of read permissions on stray subdirectories. On the flip
-        * side, if the repository holds no unnecessary subdirectories, then
-        * this strategy is the fastest one, since it generally only requires
-        * one sync call per domain, which often translates into one sync call
-        * per validation cycle.
-        *
-        * Currently, all of the official repositories are actually specifically
-        * structured to benefit this strategy.
-        */
-       RSYNC_ROOT,
-       /**
-        * Same as SYNC_ROOT, except the root certificate is synchronized
-        * separately.
-        * (Either because it's in a separate directory, or because we don't
-        * want to download its entire repository until we've verified its
-        * legitimacy and integrity.)
-        */
-       RSYNC_ROOT_EXCEPT_TA,
+
+       /* The other options have been removed as of Fort 1.6.0. */
 };
 
 extern const struct global_type gt_rsync_strategy;
 
-/*
- * TODO (later) Public to live along with 'sync-strategy', return them to
- * private whenever 'sync-strategy' is deleted.
- */
-void print_rsync_strategy(struct option_field const *, void *);
-int parse_argv_rsync_strategy(struct option_field const *, char const *,
-    void *);
-int parse_json_rsync_strategy(struct option_field const *, struct json_t *,
-    void *);
-
 #endif /* SRC_CONFIG_RSYNC_STRATEGY_H_ */
diff --git a/src/config/sync_strategy.c b/src/config/sync_strategy.c
deleted file mode 100644 (file)
index ada711f..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-#include "config/sync_strategy.h"
-
-#include <getopt.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "config.h"
-#include "log.h"
-#include "config/str.h"
-#include "config/rsync_strategy.h"
-
-/*
- * Yeap, all of this is duplicated, better remove it with the whole source file
- * whenever sync-strategy isn't supported anymore.
- */
-
-#define RSYNC_VALUE_OFF                        "off"
-#define RSYNC_VALUE_STRICT             "strict"
-#define RSYNC_VALUE_ROOT               "root"
-#define RSYNC_VALUE_ROOT_EXCEPT_TA     "root-except-ta"
-
-#define DEREFERENCE(void_value) (*((enum rsync_strategy *) void_value))
-
-#ifdef ENABLE_STRICT_STRATEGY
-#define PRINT_STRICT_ARG_DOC "|" RSYNC_VALUE_STRICT
-#define HANDLE_RSYNC_STRICT DEREFERENCE(result) = RSYNC_STRICT;
-#else
-#define PRINT_STRICT_ARG_DOC
-#define HANDLE_RSYNC_STRICT                                            \
-       return pr_err("Unknown synchronization strategy: '%s'. In order to use it, recompile using flag ENABLE_STRICT_STRATEGY.",\
-           str);
-#endif
-
-static void
-print_sync_strategy(struct option_field const *field, void *value)
-{
-       if (DEREFERENCE(value) == RSYNC_OFF) {
-               pr_op_info("%s: %s", field->name, RSYNC_VALUE_OFF);
-               return;
-       }
-
-       print_rsync_strategy(field, value);
-}
-
-static int
-parse_argv_sync_strategy(struct option_field const *field, char const *str,
-    void *result)
-{
-       int error;
-
-       pr_op_warn("'sync-strategy' is deprecated.");
-       pr_op_warn("Use 'rsync.strategy' instead; or 'rsync.enabled=false' if you wish to use 'off' strategy.");
-
-       if (strcmp(str, RSYNC_VALUE_OFF) == 0) {
-               DEREFERENCE(result) = RSYNC_OFF;
-               config_set_rsync_enabled(false);
-               return 0;
-       }
-
-       error = parse_argv_rsync_strategy(field, str, result);
-       if (!error)
-               config_set_rsync_strategy(DEREFERENCE(result));
-       return error;
-}
-
-static int
-parse_json_sync_strategy(struct option_field const *opt, struct json_t *json,
-    void *result)
-{
-       char const *string;
-       int error;
-
-       error = parse_json_string(json, opt->name, &string);
-       return error ? error : parse_argv_sync_strategy(opt, string, result);
-}
-
-const struct global_type gt_sync_strategy = {
-       .has_arg = required_argument,
-       .size = sizeof(enum rsync_strategy),
-       .print = print_sync_strategy,
-       .parse.argv = parse_argv_sync_strategy,
-       .parse.json = parse_json_sync_strategy,
-       .arg_doc = RSYNC_VALUE_OFF
-           "|" RSYNC_VALUE_ROOT
-           "|" RSYNC_VALUE_ROOT_EXCEPT_TA
-           PRINT_STRICT_ARG_DOC,
-};
diff --git a/src/config/sync_strategy.h b/src/config/sync_strategy.h
deleted file mode 100644 (file)
index 0f8c776..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef SRC_CONFIG_SYNC_STRATEGY_H_
-#define SRC_CONFIG_SYNC_STRATEGY_H_
-
-#include "config/types.h"
-
-extern const struct global_type gt_sync_strategy;
-
-#endif /* SRC_CONFIG_SYNC_STRATEGY_H_ */
index 4b6de3c8b4325252ad9320365ebec176bdd0cd70..ded6f31e71512394ba9d05d8e945db2d35a02f62 100644 (file)
@@ -1,4 +1,4 @@
-#include "hash.h"
+#include "crypto/hash.h"
 
 #include <errno.h>
 #include <openssl/evp.h>
diff --git a/src/data_structure/path_builder.c b/src/data_structure/path_builder.c
new file mode 100644 (file)
index 0000000..85395c4
--- /dev/null
@@ -0,0 +1,106 @@
+#include "data_structure/path_builder.h"
+
+#include "log.h"
+
+/* These are arbitrary; feel free to change them. */
+#define INITIAL_CAPACITY 128
+#define MAX_CAPACITY 4096
+
+void
+path_init(struct path_builder *pb)
+{
+       pb->string = malloc(INITIAL_CAPACITY);
+       pb->len = 0;
+       pb->capacity = INITIAL_CAPACITY;
+       pb->error = (pb->string != NULL) ? pr_enomem() : 0;
+}
+
+static void
+fail(struct path_builder *pb, int error)
+{
+       free(pb->string);
+       pb->error = error;
+}
+
+static void
+add(struct path_builder *pb, char const *addend, size_t addend_len)
+{
+       size_t total_len;
+
+       if (pb->error)
+               return;
+
+       total_len = pb->len + addend_len;
+       if (total_len > pb->capacity) {
+               if (total_len > MAX_CAPACITY) {
+                       fail(pb, pr_val_err("Path too long: %zu > %u characters.",
+                           total_len, MAX_CAPACITY));
+                       return;
+               }
+
+               do {
+                       pb->capacity *= 2;
+               } while (total_len > pb->capacity);
+
+               pb->capacity = total_len;
+               pb->string = realloc(pb->string, pb->capacity);
+               if (pb->string == NULL) {
+                       fail(pb, pr_enomem());
+                       return;
+               }
+       }
+
+       memcpy(pb->string + pb->len, addend, addend_len);
+       pb->len += addend_len;
+}
+
+void
+path_append(struct path_builder *pb, char const *addend)
+{
+       path_append_limited(pb, addend, strlen(addend));
+}
+
+void
+path_append_limited(struct path_builder *pb, char const *addend,
+    size_t addend_len)
+{
+       if (pb->error || addend_len == 0)
+               return;
+
+       if (pb->len != 0 && pb->string[pb->len - 1] != '/')
+               add(pb, "/", 1);
+       add(pb, addend, addend_len);
+}
+
+void
+path_append_url(struct path_builder *pb, struct rpki_uri *uri)
+{
+       char const *guri;
+       char *colon;
+
+       guri = uri_get_global(uri);
+
+       /* Is there really a point to removing the colon? */
+       colon = strchr(guri, ':');
+       if (colon != NULL) {
+               path_append_limited(pb, guri, colon - guri);
+
+               guri = colon + 1;
+               while (guri[0] == '/')
+                       guri++;
+       }
+
+       path_append(pb, guri);
+}
+
+/* Should not be called more than once. */
+int
+path_compile(struct path_builder *pb, char **result)
+{
+       add(pb, "\0", 1);
+       if (pb->error)
+               return pb->error;
+
+       *result = pb->string;
+       return 0;
+}
diff --git a/src/data_structure/path_builder.h b/src/data_structure/path_builder.h
new file mode 100644 (file)
index 0000000..67dc872
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef SRC_DATA_STRUCTURE_PATH_BUILDER_H_
+#define SRC_DATA_STRUCTURE_PATH_BUILDER_H_
+
+/* TODO (aaaa) needs unit tests */
+
+#include <stddef.h>
+#include "types/uri.h"
+
+struct path_builder {
+       char *string;
+       size_t len;
+       size_t capacity;
+       int error;
+};
+
+void path_init(struct path_builder *);
+
+void path_append(struct path_builder *, char const *);
+void path_append_limited(struct path_builder *, char const *, size_t);
+void path_append_url(struct path_builder *, struct rpki_uri *);
+
+int path_compile(struct path_builder *, char **);
+
+#endif /* SRC_DATA_STRUCTURE_PATH_BUILDER_H_ */
diff --git a/src/delete_dir_daemon.c b/src/delete_dir_daemon.c
deleted file mode 100644 (file)
index 0aebaa4..0000000
+++ /dev/null
@@ -1,299 +0,0 @@
-#define _XOPEN_SOURCE 500
-
-#include "delete_dir_daemon.h"
-
-#include <sys/stat.h>
-#include <errno.h>
-#include <ftw.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include "common.h"
-#include "internal_pool.h"
-#include "log.h"
-#include "random.h"
-
-#define MAX_FD_ALLOWED 20
-
-struct rem_dirs {
-       char **arr;
-       size_t arr_len;
-       size_t arr_set;
-};
-
-static int
-remove_file(char const *location)
-{
-       pr_op_debug("Trying to remove file '%s'.", location);
-       if (remove(location))
-               return pr_op_errno(errno, "Couldn't delete file '%s'", location);
-       return 0;
-}
-
-static int
-remove_dir(char const *location)
-{
-       pr_op_debug("Trying to remove dir '%s'.", location);
-       if (rmdir(location))
-               return pr_op_errno(errno, "Couldn't delete directory '%s'",
-                   location);
-       return 0;
-}
-
-static int
-traverse(char const *path, struct stat const *sb, int flag, struct FTW *ftwbuf)
-{
-       /*
-        * FTW_SLN:
-        *   Will never be present since FTW_PHYS flag is utilized
-        */
-       switch (flag) {
-       case FTW_DP:
-               return remove_dir(path);
-       case FTW_F:
-               return remove_file(path);
-       case FTW_DNR:
-               return pr_op_err("Can't access '%s', stop deletion.", path);
-       case FTW_NS:
-               return pr_op_err("Can't get information of '%s', stop deletion.",
-                   path);
-       case FTW_SL:
-               return pr_op_err("Can't delete '%s' since is a symbolic link, stop deletion.",
-                   path);
-       case FTW_D:
-               return pr_op_err("Can't delete '%s' dir before deleting its content.",
-                   path);
-       default:
-               return pr_op_warn("Unknown path flag %d, doing nothing to '%s'.",
-                   flag, path);
-       }
-}
-
-static void
-remove_from_root(void *arg)
-{
-       struct rem_dirs *root_arg = arg;
-       char **dirs_arr;
-       size_t len, i;
-       int error;
-
-       dirs_arr = root_arg->arr;
-       len = root_arg->arr_set;
-
-       /* Release received arg */
-       free(root_arg);
-
-       for (i = 0; i < len; i++) {
-               error = nftw(dirs_arr[i], traverse, MAX_FD_ALLOWED,
-                   FTW_DEPTH|FTW_MOUNT|FTW_PHYS);
-               if (error) {
-                       if (errno)
-                               pr_op_debug("Error deleting directory '%s', please delete it manually: %s",
-                                   dirs_arr[i], strerror(errno));
-                       else
-                               pr_op_debug("Couldn't delete directory '%s', please delete it manually",
-                                   dirs_arr[i]);
-               }
-               /* Release at once, won't be needed anymore */
-               free(dirs_arr[i]);
-       }
-
-       pr_op_debug("Done removing dirs.");
-       free(dirs_arr);
-}
-
-/*
- * Soft/hard error logic utilized, beware to prepare caller:
- * - '> 0' is a soft error
- * - '< 0' is a hard error
- * - '= 0' no error
- */
-static int
-get_local_path(char const *rcvd, char const *workspace, char **result)
-{
-       struct stat attr;
-       char *tmp, *local_path;
-       size_t tmp_size;
-       int error;
-
-       /* Currently, only rsync URIs are utilized */
-       local_path = NULL;
-       error = map_uri_to_local(rcvd, "rsync://", workspace, &local_path);
-       if (error)
-               return error;
-
-       error = stat(local_path, &attr);
-       if (error) {
-               /* Soft error */
-               pr_op_debug("Error reading path '%s' (discarding): %s",
-                   local_path, strerror(errno));
-               error = errno;
-               goto release_local;
-       }
-
-       if (!S_ISDIR(attr.st_mode)) {
-               /* Soft error */
-               pr_op_debug("Path '%s' exists but is not a directory (discarding).",
-                   local_path);
-               error = ENOTDIR;
-               goto release_local;
-       }
-
-       /* Assure that root dir ends without '/' */
-       tmp_size = strlen(local_path);
-       if (strrchr(local_path, '/') == local_path + strlen(local_path) - 1)
-               tmp_size--;
-
-       tmp = malloc(tmp_size + 1);
-       if (tmp == NULL) {
-               error = pr_enomem();
-               goto release_local;
-       }
-       strncpy(tmp, local_path, tmp_size);
-       tmp[tmp_size] = '\0';
-
-       free(local_path);
-
-       *result = tmp;
-       return 0;
-release_local:
-       free(local_path);
-       return error;
-}
-
-/*
- * Soft/hard error logic utilized, beware to prepare caller:
- * - '> 0' is a soft error
- * - '< 0' is a hard error
- * - '= 0' no error
- */
-static int
-rename_local_path(char const *rcvd, char **result)
-{
-       char *tmp;
-       long random_sfx;
-       size_t rcvd_size, tmp_size;
-       int error;
-
-       rcvd_size = strlen(rcvd);
-       /* original size + one underscore + hex random val (8 chars) */
-       tmp_size = rcvd_size + 1 + (sizeof(RAND_MAX) * 2);
-       tmp = malloc(tmp_size + 1);
-       if (tmp == NULL)
-               return pr_enomem();
-
-       /* Rename the path with a random suffix */
-       random_init();
-       random_sfx = random_at_most(RAND_MAX);
-
-       snprintf(tmp, tmp_size + 1, "%s_%08lX", rcvd, random_sfx);
-
-       error = rename(rcvd, tmp);
-       if (error) {
-               free(tmp);
-               pr_op_debug("Couldn't rename '%s' to delete it (discarding): %s",
-                   rcvd, strerror(errno));
-               return errno; /* Soft error */
-       }
-
-       *result = tmp;
-       return 0;
-}
-
-static int
-rename_all_roots(struct rem_dirs *rem_dirs, char **src, char const *workspace)
-{
-       char *local_path, *delete_path;
-       size_t i;
-       int error;
-
-       for (i = 0; i < rem_dirs->arr_len; i++) {
-               local_path = NULL;
-               error = get_local_path(src[(rem_dirs->arr_len - 1) - i],
-                   workspace, &local_path);
-               if (error < 0)
-                       return error;
-               if (error > 0)
-                       continue;
-
-               delete_path = NULL;
-               error = rename_local_path(local_path, &delete_path);
-               free(local_path);
-               if (error < 0)
-                       return error;
-               if (error > 0)
-                       continue;
-               rem_dirs->arr[rem_dirs->arr_set++] = delete_path;
-       }
-
-       return 0;
-}
-
-static int
-rem_dirs_create(size_t arr_len, struct rem_dirs **result)
-{
-       struct rem_dirs *tmp;
-
-       tmp = malloc(sizeof(struct rem_dirs));
-       if (tmp == NULL)
-               return pr_enomem();
-
-       tmp->arr = calloc(arr_len, sizeof(char *));
-       if (tmp->arr == NULL) {
-               free(tmp);
-               return pr_enomem();
-       }
-
-       tmp->arr_len = arr_len;
-       tmp->arr_set = 0;
-
-       *result = tmp;
-       return 0;
-}
-
-static void
-rem_dirs_destroy(struct rem_dirs *rem_dirs)
-{
-       size_t i;
-
-       for (i = 0; i < rem_dirs->arr_set; i++)
-               free(rem_dirs->arr[i]);
-       free(rem_dirs->arr);
-       free(rem_dirs);
-}
-
-/*
- * Remove the files listed at @roots array of @roots_len size. The local files
- * will be searched at the specified HTTP local @workspace.
- * 
- * The daemon will be as quiet as possible, since most of its job is done
- * asynchronously. Also, it works on the best possible effort; some errors are
- * treated as "soft" errors, since the directory deletion still doesn't
- * considers the relations (parent-child) at dirs.
- */
-int
-delete_dir_daemon_start(char **roots, size_t roots_len, char const *workspace)
-{
-       struct rem_dirs *arg;
-       int error;
-
-       arg = NULL;
-       error = rem_dirs_create(roots_len, &arg);
-       if (error)
-               return error;
-
-       error = rename_all_roots(arg, roots, workspace);
-       if (error) {
-               rem_dirs_destroy(arg);
-               return error;
-       }
-
-       /* Thread arg is released at thread */
-       error = internal_pool_push("Directory deleter", remove_from_root, arg);
-       if (error) {
-               rem_dirs_destroy(arg);
-               return error;
-       }
-
-       return 0;
-}
diff --git a/src/delete_dir_daemon.h b/src/delete_dir_daemon.h
deleted file mode 100644 (file)
index 3bee47f..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef SRC_DELETE_DIR_DAEMON_H_
-#define SRC_DELETE_DIR_DAEMON_H_
-
-#include <stddef.h>
-
-int delete_dir_daemon_start(char **, size_t, char const *);
-
-#endif /* SRC_DELETE_DIR_DAEMON_H_ */
index d8bd58ed9305a0da27f74fa79aa10a41119c98e4..eaccca221baab550fd7c8e3c7da0d00b6d1f4284 100644 (file)
@@ -310,7 +310,6 @@ int
 handle_aki(X509_EXTENSION *ext, void *arg)
 {
        AUTHORITY_KEYID *aki;
-       struct validation *state;
        X509 *parent;
        int error;
 
@@ -329,13 +328,7 @@ handle_aki(X509_EXTENSION *ext, void *arg)
                goto end;
        }
 
-       state = state_retrieve();
-       if (state == NULL) {
-               error = -EINVAL;
-               goto end;
-       }
-
-       parent = x509stack_peek(validation_certstack(state));
+       parent = x509stack_peek();
        if (parent == NULL) {
                error = pr_val_err("Certificate has no parent.");
                goto end;
index 89ae166fc7614c54672813450f4483248805af00..fe031e596bbbce6de65196f9e15e35f51c67e2f5 100644 (file)
@@ -1,7 +1,9 @@
 #include "file.h"
 
 #include <errno.h>
+#include <limits.h>
 #include <stdlib.h>
+#include <stdint.h>
 #include "log.h"
 
 static int
@@ -132,3 +134,33 @@ file_valid(char const *file_name)
        file_close(tmp);
        return true;
 }
+
+/*
+ * If the modification time is not computable, will return -1.
+ * (This mirrors `man 2 time`.)
+ *
+ * This is because the result of this function is presently always used by
+ * libcurl, which prefers a long.
+ */
+long
+file_get_modification_time(char const *luri)
+{
+       struct stat metadata;
+
+       if (stat(luri, &metadata) != 0)
+               return -1;
+
+       if (metadata.st_mtim.tv_sec < 0) {
+               pr_val_warn("File modification time is negative: %jd",
+                   (intmax_t)metadata.st_mtim.tv_sec);
+               return -1;
+       }
+       if (metadata.st_mtim.tv_sec > LONG_MAX) {
+               pr_val_warn("File modification time is too big for libcurl: %ju",
+                   /* time_t is not guaranteed to be signed. */
+                   (uintmax_t)metadata.st_mtim.tv_sec);
+               return -1;
+       }
+
+       return metadata.st_mtim.tv_sec;
+}
index 0ce44ba5d9cb46ca784f2e6bd570b05ca283f0ad..9544338737d19b04ced30a2b85416219f2aff2f3 100644 (file)
@@ -24,5 +24,6 @@ int file_load(char const *, struct file_contents *);
 void file_free(struct file_contents *);
 
 bool file_valid(char const *);
+long file_get_modification_time(char const *);
 
 #endif /* SRC_FILE_H_ */
index 3534eb0b117e3d81cb64b6aab6d9bccefc2c2c89..f3ce16b08276abf93b6c1b21721e12a70c9f2090 100644 (file)
@@ -1,4 +1,4 @@
-#include "http.h"
+#include "http/http.h"
 
 #include <errno.h>
 #include <stdio.h>
@@ -9,7 +9,7 @@
 #include "file.h"
 #include "log.h"
 
-struct http_handler {
+struct curl_args {
        CURL *curl;
        char errbuf[CURL_ERROR_SIZE];
 };
@@ -80,8 +80,8 @@ write_callback(void *data, size_t size, size_t nmemb, void *userp)
                 * approach. We already reached the size limit, but we're going
                 * to reject the file anyway.
                 */
-               arg->error = -EFBIG;
-               return 0; /* Ugh. See fread(3) */
+               arg->error = EFBIG;
+               return 0; /* Ugh. See fwrite(3) */
        }
 
        return fwrite(data, size, nmemb, arg->dst);
@@ -112,7 +112,7 @@ setopt_writedata(CURL *curl, struct write_callback_arg *arg)
 }
 
 static int
-http_easy_init(struct http_handler *handler)
+http_easy_init(struct curl_args *handler, long ims)
 {
        CURL *result;
 
@@ -161,19 +161,26 @@ http_easy_init(struct http_handler *handler)
        /* Prepare for multithreading, avoid signals */
        setopt_long(result, CURLOPT_NOSIGNAL, 1L);
 
+       if (ims > 0) {
+               /* Set "If-Modified-Since" header */
+               setopt_long(result, CURLOPT_TIMEVALUE, ims);
+               setopt_long(result, CURLOPT_TIMECONDITION,
+                   CURL_TIMECOND_IFMODSINCE);
+       }
+
        handler->curl = result;
        return 0;
 }
 
 static char const *
-curl_err_string(struct http_handler *handler, CURLcode res)
+curl_err_string(struct curl_args *handler, CURLcode res)
 {
        return strlen(handler->errbuf) > 0 ?
            handler->errbuf : curl_easy_strerror(res);
 }
 
 static int
-get_http_response_code(struct http_handler *handler, long *http_code,
+get_http_response_code(struct curl_args *handler, long *http_code,
     char const *uri)
 {
        CURLcode res;
@@ -194,56 +201,63 @@ handle_http_response_code(long http_code)
 {
        /* This is the same logic from CURL, according to its documentation. */
        if (http_code == 408 || http_code == 429)
-               return EREQFAILED; /* Retry */
+               return EAGAIN; /* Retry */
        if (500 <= http_code && http_code < 600)
-               return EREQFAILED; /* Retry */
+               return EAGAIN; /* Retry */
        return -EINVAL; /* Do not retry */
 }
 
 /*
- * Fetch data from @uri and write result using @cb (which will receive @arg).
+ * *Single* attempt to request URI @src, and store it in file @dst.
+ *
+ * If @dst already exists, it *will* be overwritten without warning. Basically
+ * always. Even if IMS is enabled.
+ *
+ * Leaves a dirty file on error. I'm offloading the responsibility of cleaning
+ * it, because parent directories should also probably be deleted if empty, but
+ * only if we don't need to retry.
  */
 static int
-http_fetch(struct http_handler *handler, char const *uri, long *response_code,
-    long *cond_met, bool log_operation, FILE *file)
+do_single_http_get(struct curl_args *handler, char const *src, char const *dst)
 {
        struct write_callback_arg args;
        CURLcode res;
        long http_code;
-       long unmet = 0;
-
-       handler->errbuf[0] = 0;
-       setopt_str(handler->curl, CURLOPT_URL, uri);
 
        args.total_bytes = 0;
-       args.error = 0;
-       args.dst = file;
+       handler->errbuf[0] = 0;
+       setopt_str(handler->curl, CURLOPT_URL, src);
        setopt_writedata(handler->curl, &args);
 
-       pr_val_debug("HTTP GET: %s", uri);
+       pr_val_debug("HTTP GET: %s", src);
+
+       args.error = file_write(dst, &args.dst);
+       if (args.error)
+               return args.error;
+
        res = curl_easy_perform(handler->curl);
 
-       if (args.error == -EFBIG) {
-               pr_val_err("The file '%s' is too big (read: %zu bytes). Rejecting.",
-                   uri, args.total_bytes);
-               return -EFBIG;
+       file_close(args.dst);
+
+       pr_val_debug("Done. Total bytes transferred: %zu", args.total_bytes);
+
+       if (args.error == EFBIG) {
+               pr_val_err("File too big (read: %zu bytes). Rejecting.",
+                   args.total_bytes);
+               return EFBIG;
        }
 
-       args.error = get_http_response_code(handler, &http_code, uri);
+       args.error = get_http_response_code(handler, &http_code, src);
        if (args.error)
                return args.error;
-       *response_code = http_code;
 
        if (res != CURLE_OK) {
                pr_val_err("Error requesting URL %s: %s. (HTTP code: %ld)",
-                   uri, curl_err_string(handler, res), http_code);
-               if (log_operation)
-                       pr_op_err("Error requesting URL %s: %s. (HTTP code: %ld)",
-                           uri, curl_err_string(handler, res), http_code);
+                   src, curl_err_string(handler, res), http_code);
 
                switch (res) {
                case CURLE_FILESIZE_EXCEEDED:
-                       return -EFBIG; /* Do not retry */
+                       return EFBIG; /* Do not retry */
                case CURLE_OPERATION_TIMEDOUT:
                case CURLE_COULDNT_RESOLVE_HOST:
                case CURLE_COULDNT_RESOLVE_PROXY:
@@ -258,6 +272,11 @@ http_fetch(struct http_handler *handler, char const *uri, long *response_code,
                pr_val_err("HTTP result code: %ld", http_code);
                return handle_http_response_code(http_code);
        }
+       if (http_code == 304) {
+               pr_val_debug("HTTP result code: %ld. No need to download.",
+                   http_code);
+               return ENOTCHANGED;
+       }
        if (http_code >= 300) {
                /*
                 * If you're ever forced to implement this, please remember that
@@ -270,277 +289,135 @@ http_fetch(struct http_handler *handler, char const *uri, long *response_code,
        }
 
        pr_val_debug("HTTP result code: %ld", http_code);
-
-       /*
-        * Scenario: Received an OK code, but the time condition
-        * (if-modified-since) wasn't actually met (ie. the document
-        * has not been modified since we last requested it), so handle
-        * this as a "Not Modified" code.
-        *
-        * This check is due to old libcurl versions, where the impl
-        * doesn't let us get the response content since the library
-        * does the time validation, resulting in "The requested
-        * document is not new enough".
-        *
-        * Update 2021-05-25: I just tested libcurl in my old CentOS 7.7
-        * VM (which is from October 2019, ie. older than the comments
-        * above), and it behaves normally.
-        * Also, the changelog doesn't mention anything about
-        * If-Modified-Since.
-        * This glue code is suspicious to me.
-        *
-        * For the record, this is how it behaves in my today's Ubuntu,
-        * as well as my Centos 7.7.1908:
-        *
-        *      if if-modified-since is included:
-        *              if page was modified:
-        *                      HTTP 200
-        *                      unmet: 0
-        *                      writefunction called
-        *              else:
-        *                      HTTP 304
-        *                      unmet: 1
-        *                      writefunction not called
-        *      else:
-        *              HTTP OK
-        *              unmet: 0
-        *              writefunction called
-        */
-       res = curl_easy_getinfo(handler->curl, CURLINFO_CONDITION_UNMET, &unmet);
-       if (res == CURLE_OK && unmet == 1)
-               *cond_met = 0;
-
        return 0;
 }
 
 static void
-http_easy_cleanup(struct http_handler *handler)
+http_easy_cleanup(struct curl_args *handler)
 {
        curl_easy_cleanup(handler->curl);
 }
 
+/* Retries in accordance with configuration limits. */
 static int
-__http_download_file(struct rpki_uri *uri, long *response_code, long ims_value,
-    long *cond_met, bool log_operation)
+retry_until_done(char const *remote, char const *local,
+    struct curl_args *handler)
 {
-       char const *tmp_suffix = "_tmp";
-       struct http_handler handler;
-       FILE *out;
-       unsigned int retries;
-       char const *original_file;
-       char *tmp_file;
+       unsigned int attempt;
+       unsigned int max_attempts;
+       unsigned int retry_interval;
        int error;
 
-       retries = 0;
-       *cond_met = 1;
-       if (!config_get_http_enabled()) {
-               *response_code = 0; /* Not 200 code, but also not an error */
-               return 0;
-       }
+       error = create_dir_recursive(local);
+       if (error)
+               return error;
 
-       original_file = uri_get_local(uri);
+       max_attempts = config_get_http_retry_count() + 1;
+       retry_interval = config_get_http_retry_interval();
 
-       tmp_file = malloc(strlen(original_file) + strlen(tmp_suffix) + 1);
-       if (tmp_file == NULL)
-               return pr_enomem();
-       strcpy(tmp_file, original_file);
-       strcat(tmp_file, tmp_suffix);
-
-       error = create_dir_recursive(tmp_file);
-       if (error)
-               goto release_tmp;
+       for (attempt = 1; true; attempt++) {
+               pr_val_debug("HTTP GET attempt %u (out of %u)...",
+                   attempt, max_attempts);
+               error = do_single_http_get(handler, remote, local);
+               if (error == 0)
+                       return 0;
+               if (error != EAGAIN)
+                       break;
 
-       error = file_write(tmp_file, &out);
-       if (error)
-               goto delete_dir;
-
-       do {
-               error = http_easy_init(&handler);
-               if (error)
-                       goto close_file;
-
-               /* Set "If-Modified-Since" header only if a value is specified */
-               if (ims_value > 0) {
-                       setopt_long(handler.curl, CURLOPT_TIMEVALUE, ims_value);
-                       setopt_long(handler.curl, CURLOPT_TIMECONDITION,
-                           CURL_TIMECOND_IFMODSINCE);
-               }
-               error = http_fetch(&handler, uri_get_global(uri), response_code,
-                   cond_met, log_operation, out);
-               if (error != EREQFAILED)
-                       break; /* Note: Usually happy path */
-
-               if (retries == config_get_http_retry_count()) {
-                       if (retries > 0)
-                               pr_val_warn("Max HTTP retries (%u) reached requesting for '%s', won't retry again.",
-                                   retries, uri_get_global(uri));
+               if (attempt == max_attempts) {
+                       pr_val_err("HTTP GET attempt %u (out of %u): Failure. Giving up.",
+                           attempt, max_attempts);
                        break;
                }
-               pr_val_warn("Retrying HTTP request '%s' in %u seconds, %u attempts remaining.",
-                   uri_get_global(uri),
-                   config_get_http_retry_interval(),
-                   config_get_http_retry_count() - retries);
-               retries++;
-               http_easy_cleanup(&handler);
-               sleep(config_get_http_retry_interval());
-       } while (true);
 
-       http_easy_cleanup(&handler);
-       file_close(out);
-
-       if (error)
-               goto delete_dir;
-
-       /* Overwrite the original file */
-       error = rename(tmp_file, original_file);
-       if (error) {
-               error = errno;
-               pr_val_errno(error, "Renaming temporal file from '%s' to '%s'",
-                   tmp_file, original_file);
-               goto delete_dir;
+               pr_val_warn("HTTP GET attempt %u (out of %u): Failure. Retrying in %u seconds.",
+                   attempt, max_attempts, retry_interval);
+               sleep(retry_interval);
        }
 
-       free(tmp_file);
-       return 0;
-close_file:
-       file_close(out);
-delete_dir:
-       delete_dir_recursive_bottom_up(tmp_file);
-release_tmp:
-       free(tmp_file);
-       return ENSURE_NEGATIVE(error);
+       delete_dir_recursive_bottom_up(local);
+       return error;
 }
 
 /*
- * Try to download from global @uri into a local directory structure created
- * from local @uri.
+ * Try to download from @remote into @local, full package.
  *
- * Return values: 0 on success, negative value on error, EREQFAILED if the
- * request to the server failed.
- */
-int
-http_download_file(struct rpki_uri *uri, bool log_operation)
-{
-       long response;
-       long cond_met;
-       return __http_download_file(uri, &response, 0, &cond_met,
-           log_operation);
-}
-
-/*
- * Fetch the file from @uri.
+ * @ims is the The "If-Modified-Since" HTTP header.
+ * -1 happens to be an invalid `time()` value, so use it if you don't want to
+ * include the header.
  *
- * The HTTP request is made using the header 'If-Modified-Since' with a value
- * of @value (if @value is 0, the header isn't set).
+ * Return values:
  *
- * Returns:
- *   EREQFAILED the request to the server has failed.
- *   > 0 file was requested but wasn't downloaded since the server didn't sent
- *       a response due to its policy using the header 'If-Modified-Since'.
- *   = 0 file successfully downloaded.
- *   < 0 an actual error happened.
+ * - 0: Download successful.
+ * - ENOTCHANGED: File hasn't changed since `args->ims`.
+ * - < 0: Something went wrong.
  */
 int
-http_download_file_with_ims(struct rpki_uri *uri, long value,
-    bool log_operation)
+http_get(struct rpki_uri *uri, long ims)
 {
-       long response;
-       long cond_met;
+       static char const *TMP_SUFFIX = "_tmp";
+
+       struct curl_args handler;
+       char *tmp_file;
        int error;
 
-       error = __http_download_file(uri, &response, value, &cond_met,
-           log_operation);
+       if (!config_get_http_enabled())
+               return ENOTCHANGED;
+
+       /* TODO (aaaa) this is reusable. Move to the thread. */
+       error = http_easy_init(&handler, ims);
        if (error)
                return error;
 
-       /* rfc7232#section-3.3:
-        * "the origin server SHOULD generate a 304 (Not Modified) response"
-        */
-       if (response == 304)
-               return 1;
-
        /*
-        * Got another HTTP response code (OK or error).
-        *
-        * Check if the time condition was met (in case of error is set as
-        * 'true'), if it wasn't, then do a regular request (no time condition).
+        * We will write the file into a temporal location first.
+        * This will prevent us from overriding the existing file, which is
+        * going to be a problem if the download turns out to fail.
         */
-       if (cond_met)
-               return 0;
+       tmp_file = malloc(strlen(uri_get_local(uri)) + strlen(TMP_SUFFIX) + 1);
+       if (tmp_file == NULL) {
+               error = pr_enomem();
+               goto free_handler;
+       }
+       strcpy(tmp_file, uri_get_local(uri));
+       strcat(tmp_file, TMP_SUFFIX);
 
-       /*
-        * Situation:
-        *
-        * - old libcurl (because libcurl returned HTTP 200 and cond_met == 0,
-        *   which is a contradiction)
-        * - the download was successful (error == 0)
-        * - the page WAS modified since the last update
-        *
-        * libcurl wrote an empty file, so we have to redownload.
-        */
+       error = retry_until_done(uri_get_global(uri), tmp_file, &handler);
+       if (error)
+               goto free_tmp;
 
-       return __http_download_file(uri, &response, 0, &cond_met,
-           log_operation);
+       if (rename(tmp_file, uri_get_local(uri)) == -1) {
+               error = errno;
+               pr_val_errno(error, "Renaming temporal file from '%s' to '%s'",
+                   tmp_file, uri_get_local(uri));
+       }
 
+free_tmp:
+       free(tmp_file);
+free_handler:
+       http_easy_cleanup(&handler);
+       return error;
 }
 
 /*
  * Downloads @remote to the absolute path @dest (no workspace nor directory
  * structure is created).
+ *
+ * TODO (aaaa) this function needs to shrink even more.
  */
 int
 http_direct_download(char const *remote, char const *dest)
 {
-       char const *tmp_suffix = "_tmp";
-       struct http_handler handler;
-       FILE *out;
-       long response_code;
-       long cond_met;
-       char *tmp_file, *tmp;
+       struct curl_args curl;
        int error;
 
-       tmp_file = strdup(dest);
-       if (tmp_file == NULL)
-               return pr_enomem();
-
-       tmp = realloc(tmp_file, strlen(tmp_file) + strlen(tmp_suffix) + 1);
-       if (tmp == NULL) {
-               error = pr_enomem();
-               goto release_tmp;
-       }
-
-       tmp_file = tmp;
-       strcat(tmp_file, tmp_suffix);
-
-       error = file_write(tmp_file, &out);
+       error = http_easy_init(&curl, 0L);
        if (error)
-               goto release_tmp;
-
-       error = http_easy_init(&handler);
-       if (error)
-               goto close_file;
+               return error;
 
-       error = http_fetch(&handler, remote, &response_code, &cond_met, true,
-           out);
-       http_easy_cleanup(&handler);
-       file_close(out);
-       if (error)
-               goto release_tmp;
+       error = do_single_http_get(&curl, remote, dest);
 
-       /* Overwrite the original file */
-       error = rename(tmp_file, dest);
-       if (error) {
-               error = errno;
-               pr_val_errno(error, "Renaming temporal file from '%s' to '%s'",
-                   tmp_file, dest);
-               goto release_tmp;
-       }
+       http_easy_cleanup(&curl);
 
-       free(tmp_file);
-       return 0;
-close_file:
-       file_close(out);
-release_tmp:
-       free(tmp_file);
        return error;
 }
index 1dc40221a403f7035d77ed04171d22c450e95e87..57616d85b3c7faa2bc6de9269e37ab51a77099ba 100644 (file)
@@ -9,8 +9,7 @@
 int http_init(void);
 void http_cleanup(void);
 
-int http_download_file(struct rpki_uri *, bool);
-int http_download_file_with_ims(struct rpki_uri *, long, bool);
+int http_get(struct rpki_uri *, long);
 
 int http_direct_download(char const *, char const *);
 
diff --git a/src/internal_pool.c b/src/internal_pool.c
deleted file mode 100644 (file)
index 22c5338..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#include "internal_pool.h"
-
-#include <stddef.h>
-
-/*
- * This is a basic wrapper for thread_pool functions, but the allocated pool
- * lives at the main thread.
- *
- * Additional threads that must be spawned during execution (those that aren't
- * related to the validation or server thread pool tasks) can be pushed here.
- */
-
-#define INTERNAL_POOL_MAX 10
-
-struct thread_pool *pool;
-
-int
-internal_pool_init(void)
-{
-       int error;
-
-       pool = NULL;
-       error = thread_pool_create("Internal", INTERNAL_POOL_MAX, &pool);
-       if (error)
-               return error;
-
-       return 0;
-}
-
-int
-internal_pool_push(char const *task_name, thread_pool_task_cb cb, void *arg)
-{
-       return thread_pool_push(pool, task_name, cb, arg);
-}
-
-void
-internal_pool_cleanup(void)
-{
-       thread_pool_destroy(pool);
-}
diff --git a/src/internal_pool.h b/src/internal_pool.h
deleted file mode 100644 (file)
index 01aed8c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef SRC_INTERNAL_POOL_H_
-#define SRC_INTERNAL_POOL_H_
-
-#include "thread/thread_pool.h"
-
-int internal_pool_init(void);
-int internal_pool_push(char const *, thread_pool_task_cb, void *);
-void internal_pool_cleanup(void);
-
-#endif /* SRC_INTERNAL_POOL_H_ */
index bdae4b5acb2f9ee0a4bb63fec4aa6991a8e86b01..dcf74cabe0d611226d63610515f970dac04c5f1e 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -63,7 +63,7 @@ static pthread_mutex_t logck;
  * aware that pthread_mutex_lock() can return error codes, which shouldn't
  * prevent critical stack traces from printing.)
  */
-void
+static void
 print_stack_trace(char const *title)
 {
 #define STACK_SIZE 64
@@ -507,6 +507,9 @@ int
 __pr_op_err(int error, const char *format, ...)
 {
        PR_SIMPLE(LOG_ERR, op_config);
+       lock_mutex();
+       print_stack_trace(NULL);
+       unlock_mutex();
        return error;
 }
 
index ebbf2af18b1d8e51bb2202124268255beea1d12b..0ea0c2dfcc72b14a6c4a01fc1ddb3148e33720d3 100644 (file)
@@ -1,15 +1,12 @@
 #include "config.h"
 #include "extension.h"
-#include "internal_pool.h"
 #include "nid.h"
-#include "reqs_errors.h"
 #include "thread_var.h"
 #include "validation_run.h"
 #include "http/http.h"
 #include "rtr/rtr.h"
 #include "rtr/db/vrps.h"
 #include "xml/relax_ng.h"
-#include "rrdp/db/db_rrdp.h"
 
 static int
 run_rtr_server(void)
@@ -91,26 +88,12 @@ main(int argc, char **argv)
        if (error)
                goto revert_nid;
 
-       /*
-        * TODO (performance) this looks like a lot of overhead. Is it really
-        * necessary when mode is STANDALONE?
-        */
-       error = internal_pool_init();
-       if (error)
-               goto revert_http;
-
        error = relax_ng_init();
        if (error)
-               goto revert_pool;
+               goto revert_http;
        error = vrps_init();
        if (error)
                goto revert_relax_ng;
-       error = db_rrdp_init();
-       if (error)
-               goto vrps_cleanup;
-       error = reqs_errors_init();
-       if (error)
-               goto db_rrdp_cleanup;
 
        /* Do stuff */
        switch (config_get_mode()) {
@@ -124,15 +107,9 @@ main(int argc, char **argv)
 
        /* End */
 
-       reqs_errors_cleanup();
-db_rrdp_cleanup:
-       db_rrdp_cleanup();
-vrps_cleanup:
        vrps_destroy();
 revert_relax_ng:
        relax_ng_cleanup();
-revert_pool:
-       internal_pool_cleanup();
 revert_http:
        http_cleanup();
 revert_nid:
index 57d3022a1141170f8cd972f5d48217bd8287c6cb..418118e0390cad4c04acb4c3e9a8719e8f870107 100644 (file)
@@ -5,6 +5,7 @@
 #include <syslog.h>
 #include <time.h>
 #include <openssl/asn1.h>
+#include <openssl/x509v3.h>
 #include <sys/socket.h>
 
 #include "algorithm.h"
@@ -12,7 +13,6 @@
 #include "extension.h"
 #include "log.h"
 #include "nid.h"
-#include "reqs_errors.h"
 #include "str_token.h"
 #include "thread_var.h"
 #include "asn1/decode.h"
 #include "object/name.h"
 #include "object/manifest.h"
 #include "object/signed_object.h"
-#include "rrdp/rrdp_loader.h"
 #include "rsync/rsync.h"
+#include "types/uri_list.h"
 
 /* Just to prevent some line breaking. */
 #define GN_URI uniformResourceIdentifier
 
+#define METHODS_RRDP (1 << 0)
+#define METHODS_RSYNC (1 << 1)
+
 /*
  * The X509V3_EXT_METHOD that references NID_sinfo_access uses the AIA item.
  * The SIA's d2i function, therefore, returns AIAs.
  * They are the same as far as LibreSSL is concerned.
+ *
+ * TODO (aaaa) still needed?
  */
 typedef AUTHORITY_INFO_ACCESS SIGNATURE_INFO_ACCESS;
 
@@ -42,15 +47,24 @@ struct ski_arguments {
        OCTET_STRING_t *sid;
 };
 
-struct sia_uri {
-       uint8_t position;
-       struct rpki_uri *uri;
-};
-
+/* There must be at least one caRepository, or at least one rpkiNotify. */
 struct sia_ca_uris {
-       struct sia_uri caRepository;
-       struct sia_uri rpkiNotify;
-       struct sia_uri mft;
+       /*
+        * caRepository and rpkiNotify.
+        *
+        * rsync URL of the repository, and http URL of the Update Notification,
+        * respectively.
+        */
+       struct uri_list src;
+
+       /*
+        * rpkiManifest: rsync *URI* of the manifest.
+        *
+        * Note, it's a URI, not a URL. It's meant to serve as an identifier,
+        * not a locator. Just because it's defined, it doesn't mean that you
+        * can go rsync it.
+        */
+       struct uri_list mft;
 };
 
 struct bgpsec_ski {
@@ -58,28 +72,14 @@ struct bgpsec_ski {
        unsigned char **ski_data;
 };
 
+struct ad_metadata {
+       int nid;
+       enum rpki_uri_type uri_type;
+};
+
 /* Callback method to fetch repository objects */
 typedef int (access_method_exec)(struct sia_ca_uris *);
 
-static void
-sia_ca_uris_init(struct sia_ca_uris *sia_uris)
-{
-       sia_uris->caRepository.uri = NULL;
-       sia_uris->rpkiNotify.uri = NULL;
-       sia_uris->mft.uri = NULL;
-}
-
-static void
-sia_ca_uris_cleanup(struct sia_ca_uris *sia_uris)
-{
-       if (sia_uris->caRepository.uri != NULL)
-               uri_refput(sia_uris->caRepository.uri);
-       if (sia_uris->rpkiNotify.uri != NULL)
-               uri_refput(sia_uris->rpkiNotify.uri);
-       if (sia_uris->mft.uri != NULL)
-               uri_refput(sia_uris->mft.uri);
-}
-
 static void
 debug_serial_number(BIGNUM *number)
 {
@@ -98,14 +98,9 @@ debug_serial_number(BIGNUM *number)
 static int
 validate_serial_number(X509 *cert)
 {
-       struct validation *state;
        BIGNUM *number;
        int error;
 
-       state = state_retrieve();
-       if (state == NULL)
-               return -EINVAL;
-
        number = ASN1_INTEGER_to_BN(X509_get0_serialNumber(cert), NULL);
        if (number == NULL)
                return val_crypto_err("Could not parse certificate serial number");
@@ -113,7 +108,8 @@ validate_serial_number(X509 *cert)
        if (log_val_enabled(LOG_DEBUG))
                debug_serial_number(number);
 
-       error = x509stack_store_serial(validation_certstack(state), number);
+       error = x509stack_store_serial(validation_certstack(state_retrieve()),
+           number);
        if (error)
                BN_free(number);
 
@@ -245,9 +241,12 @@ check_dup_public_key(bool *duplicated, char const *file, void *arg)
        rcvd_cert = NULL;
        tmp_size = 0;
 
-       error = uri_create_rsync_str(&uri, file, strlen(file));
+       /* TODO (aaaa) what about RRDP? */
+       /*
+       error = uri_create_rsync(&uri, file);
        if (error)
                return error;
+       */
 
        /* Check if it's '.cer', otherwise treat as a signed object */
        if (uri_is_certificate(uri)) {
@@ -305,24 +304,25 @@ free_uri:
        return error;
 }
 
+/*
+ * "An issuer SHOULD use a different subject name if the subject's
+ * key pair has changed"
+ */
 static int
 validate_subject(X509 *cert)
 {
-       struct validation *state;
        struct rfc5280_name *name;
        int error;
 
-       state = state_retrieve();
-       if (state == NULL)
-               return -EINVAL;
-
        error = x509_name_decode(X509_get_subject_name(cert), "subject", &name);
        if (error)
                return error;
        pr_val_debug("Subject: %s", x509_name_commonName(name));
 
-       error = x509stack_store_subject(validation_certstack(state), name,
-           check_dup_public_key, cert);
+       if (false) {
+       error = x509stack_store_subject(validation_certstack(state_retrieve()),
+           name, check_dup_public_key, cert);
+       }
 
        x509_name_put(name);
        return error;
@@ -351,8 +351,6 @@ validate_spki(X509_PUBKEY *cert_spki)
        size_t _tal_spki_len;
 
        state = state_retrieve();
-       if (state == NULL)
-               return -EINVAL;
 
        tal = validation_tal(state);
        if (tal == NULL)
@@ -535,12 +533,7 @@ certificate_validate_rfc6487(X509 *cert, enum cert_type type)
        if (error)
                return error;
 
-       /*
-        * rfc6487#section-4.5
-        *
-        * "An issuer SHOULD use a different subject name if the subject's
-        * key pair has changed" (it's a SHOULD, so [for now] avoid validation)
-        */
+       /* rfc6487#section-4.5 */
        error = validate_subject(cert);
        if (error)
                return error;
@@ -951,8 +944,6 @@ certificate_validate_chain(X509 *cert, STACK_OF(X509_CRL) *crls)
                return 0; /* Certificate is TA; no chain validation needed. */
 
        state = state_retrieve();
-       if (state == NULL)
-               return -EINVAL;
 
        ctx = X509_STORE_CTX_new();
        if (ctx == NULL) {
@@ -1195,48 +1186,6 @@ is_rsync_uri(GENERAL_NAME *name)
        return name->type == GEN_URI && is_rsync(name->d.GN_URI);
 }
 
-static int
-handle_rpkiManifest(struct rpki_uri *uri, uint8_t pos, void *arg)
-{
-       struct sia_uri *mft = arg;
-       mft->position = pos;
-       mft->uri = uri;
-       uri_refget(uri);
-       return 0;
-}
-
-static int
-handle_caRepository(struct rpki_uri *uri, uint8_t pos, void *arg)
-{
-       struct sia_uri *repo = arg;
-       pr_val_debug("caRepository: %s", uri_val_get_printable(uri));
-       repo->position = pos;
-       repo->uri = uri;
-       uri_refget(uri);
-       return 0;
-}
-
-static int
-handle_rpkiNotify(struct rpki_uri *uri, uint8_t pos, void *arg)
-{
-       struct sia_uri *notify = arg;
-       pr_val_debug("rpkiNotify: %s", uri_val_get_printable(uri));
-       notify->position = pos;
-       notify->uri = uri;
-       uri_refget(uri);
-       return 0;
-}
-
-static int
-handle_signedObject(struct rpki_uri *uri, uint8_t pos, void *arg)
-{
-       struct certificate_refs *refs = arg;
-       pr_val_debug("signedObject: %s", uri_val_get_printable(uri));
-       refs->signedObject = uri;
-       uri_refget(uri);
-       return 0;
-}
-
 static int
 handle_bc(X509_EXTENSION *ext, void *arg)
 {
@@ -1484,168 +1433,212 @@ end:
        return error;
 }
 
-/**
- * The RFC does not explain AD validation very well. This is personal
- * interpretation, influenced by Tim Bruijnzeels's response
- * (https://mailarchive.ietf.org/arch/msg/sidr/4ycmff9jEU4VU9gGK5RyhZ7JYsQ)
- * (I'm being a bit more lax than he suggested.)
- *
- * 1. Only one NID needs to be searched at a time. (This is currently somewhat
- *    of a coincidence, and will probably be superseded at some point. But I'm
- *    not going to complicate this until it's necessary.)
- * 2. The NID MUST be found, otherwise the certificate is invalid.
- * 3. The NID can be found more than once.
- * 4. All access descriptions that match the NID must be URLs.
- * 5. Precisely one of those matches will be an RSYNC URL, and it's the only one
- *    we are required to support.
- *    (I would have gone with "at least one of those matches", but I don't know
- *    what to do with the other ones.)
- * 6. Other access descriptions that do not match the NID are allowed and
- *    supposed to be ignored.
- * 7. Other access descriptions that match the NID but do not have RSYNC URIs
- *    are also allowed, and also supposed to be ignored.
- */
 static int
-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)
+asnstr2str(ASN1_STRING *asnstr, char **result)
 {
-# define AD_METHOD ((uri_flags & URI_VALID_RSYNC) == URI_VALID_RSYNC ? \
-       "RSYNC" : \
-       (((uri_flags & URI_VALID_HTTPS) == URI_VALID_HTTPS) ? \
-       "HTTPS" : "RSYNC/HTTPS"))
-       ACCESS_DESCRIPTION *ad;
-       struct rpki_uri *uri;
-       bool found = false;
-       unsigned int i;
-       int error;
-
-       for (i = 0; i < sk_ACCESS_DESCRIPTION_num(ia); i++) {
-               ad = sk_ACCESS_DESCRIPTION_value(ia, i);
-               if (OBJ_obj2nid(ad->method) == ad_nid) {
-                       error = uri_create_ad(&uri, ad, uri_flags);
-                       switch (error) {
-                       case 0:
-                               break;
-                       case ENOTRSYNC:
-                               continue;
-                       case ENOTHTTPS:
-                               continue;
-                       case ENOTSUPPORTED:
-                               continue;
-                       default:
-                               return error;
-                       }
+       char *str;
+       int str_len;
 
-                       if (found) {
-                               uri_refput(uri);
-                               return pr_val_err("Extension '%s' has multiple '%s' %s URIs.",
-                                   ia_name, ad_name, AD_METHOD);
-                       }
+       /*
+        * GEN_URI signals an IA5String.
+        * IA5String is a subset of ASCII, so it can be converted to char *.
+        * No guarantees of a NULL chara, though.
+        */
 
-                       error = cb(uri, i, arg);
-                       if (error) {
-                               uri_refput(uri);
-                               return error;
-                       }
+       str_len = ASN1_STRING_length(asnstr);
+       if (str_len < 0)
+               return pr_val_err("String has invalid length: %d", str_len);
 
-                       uri_refput(uri);
-                       found = true;
-               }
-       }
+       str = malloc(str_len + 1);
+       if (str == NULL)
+               return pr_enomem();
 
-       if (required && !found) {
-               pr_val_err("Extension '%s' lacks a '%s' valid %s URI.", ia_name,
-                   ad_name, AD_METHOD);
-               return -ESRCH;
-       }
+       memcpy(str, ASN1_STRING_get0_data(asnstr), str_len);
+       str[str_len] = '\0';
 
+       *result = str;
        return 0;
 }
 
+/* Create @uri from @ad */
 static int
-handle_caIssuers(struct rpki_uri *uri, uint8_t pos, void *arg)
+add_ad(struct uri_list *uris, ACCESS_DESCRIPTION *ad,
+    enum rpki_uri_type uri_type)
 {
-       struct certificate_refs *refs = arg;
+       ASN1_STRING *asn1_string;
+       char *cstring;
+       int ad_type;
+       int error;
+
+       asn1_string = GENERAL_NAME_get0_value(ad->location, &ad_type);
+
        /*
-        * Bringing the parent certificate's URI all the way
-        * over here is too much trouble, so do the handle_cdp()
-        * hack.
+        * 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 in the ass. So this is what I'm committing
+        * to.
         */
-       refs->caIssuers = uri;
-       uri_refget(uri);
+       if (ad_type != GEN_URI) {
+               pr_val_err("Unknown GENERAL_NAME type: %d", ad_type);
+               return ENOTSUPPORTED;
+       }
+
+       cstring = NULL;
+       error = asnstr2str(asn1_string, &cstring);
+       if (error)
+               return error;
+
+       return uris_add_str(uris, cstring, uri_type);
+}
+
+static int
+ia2uris(AUTHORITY_INFO_ACCESS *ia, char const *ext_name,
+    struct ad_metadata const *ad_metas, char const *ad_name,
+    struct uri_list *uris)
+{
+       ACCESS_DESCRIPTION *ad;
+       struct ad_metadata const *meta;
+       unsigned int i;
+       int ad_nid;
+       int error;
+
+       for (i = 0; i < sk_ACCESS_DESCRIPTION_num(ia); i++) {
+               ad = sk_ACCESS_DESCRIPTION_value(ia, i);
+               ad_nid = OBJ_obj2nid(ad->method);
+
+               for (meta = ad_metas; meta->nid != 0; meta++) {
+                       if (ad_nid == meta->nid) {
+                               error = add_ad(uris, ad, meta->uri_type);
+                               if (error == ENOTSUPPORTED)
+                                       break;
+                               if (error)
+                                       return error;
+                       }
+               }
+       }
+
+       if (uris->len == 0) {
+               return pr_val_err("CA Certificate does not list any (supported) %ss in its %s.",
+                   ad_name, ext_name);
+       }
+
        return 0;
 }
 
+/**
+ * Converts the URI list contained in @ext (which is assumed to be a SIA or AIA)
+ * to @result.
+ *
+ * The RFC's explanation of AD validation is somewhat loose. This is personal
+ * interpretation, influenced by Tim Bruijnzeels's response
+ * (https://mailarchive.ietf.org/arch/msg/sidr/4ycmff9jEU4VU9gGK5RyhZ7JYsQ)
+ *
+ * Implemented ruleset:
+ *
+ * - The NID MUST be found, otherwise the certificate is invalid.
+ * - The NID can be found more than once.
+ * - All access descriptions that match the NID must be rsync URLs.
+ *   (RRDP cannot produce object URLs, so it falls back to rsync URLs as well.)
+ * - Other access descriptions that do not match the NID are allowed and
+ *   supposed to be ignored.
+ * - Other access descriptions that match the NID but do not have RSYNC URIs
+ *   are also allowed, and also supposed to be ignored.
+ */
 static int
-handle_aia(X509_EXTENSION *ext, void *arg)
+ext2uris(X509_EXTENSION *ext, char const *ext_name,
+    struct ad_metadata const *ad_metas, char const *ad_name,
+    struct uri_list *uris)
 {
-       AUTHORITY_INFO_ACCESS *aia;
+       AUTHORITY_INFO_ACCESS *ia;
        int error;
 
-       aia = X509V3_EXT_d2i(ext);
-       if (aia == NULL)
+       ia = X509V3_EXT_d2i(ext);
+       if (ia == NULL)
                return cannot_decode(ext_aia());
 
-       error = handle_ad("AIA", aia, "caIssuers", NID_ad_ca_issuers,
-           URI_VALID_RSYNC, true, handle_caIssuers, arg);
+       error = ia2uris(ia, ext_name, ad_metas, ad_name, uris);
+
+       /* TODO (aaaa) force rsync only */
 
-       AUTHORITY_INFO_ACCESS_free(aia);
+       AUTHORITY_INFO_ACCESS_free(ia);
        return error;
 }
 
+static int
+handle_aia(X509_EXTENSION *ext, void *arg)
+{
+       const struct ad_metadata aia_metadata[] = {
+               { .nid = NID_ad_ca_issuers, .uri_type = URI_TYPE_VOID },
+               { .nid = -1 },
+       };
+       struct certificate_refs *refs = arg;
+
+       return ext2uris(ext, "AIA", aia_metadata, "caIssuer", &refs->caIssuers);
+}
+
 static int
 handle_sia_ca(X509_EXTENSION *ext, void *arg)
 {
+       const struct ad_metadata sia_metadata[] = {
+               { .nid = NID_caRepository, .uri_type = URI_TYPE_RSYNC },
+               { .nid = nid_rpkiNotify(), .uri_type = URI_TYPE_HTTP_SIMPLE },
+               { .nid = -1 },
+
+       };
+       const struct ad_metadata mft_metadata[] = {
+               { .nid = nid_rpkiManifest(), .uri_type = URI_TYPE_VOID },
+               { .nid = -1 },
+       };
+
        SIGNATURE_INFO_ACCESS *sia;
-       struct sia_ca_uris *uris = arg;
+       struct sia_ca_uris *uris;
        int error;
 
        sia = X509V3_EXT_d2i(ext);
        if (sia == NULL)
                return cannot_decode(ext_sia());
 
-       /* rsync, still the preferred and required */
-       error = handle_ad("SIA", sia, "caRepository", NID_caRepository,
-           URI_VALID_RSYNC, true, handle_caRepository, &uris->caRepository);
+       /*
+        * Store the URIs in @sia_uris.
+        * (We won't actually touch this stuff until we know the certificate
+        * is fully valid.)
+        */
+
+       uris = arg;
+       error = ia2uris(sia, "SIA", sia_metadata, "source", &uris->src);
        if (error)
                goto end;
-
-       /* HTTPS RRDP */
-       error = handle_ad("SIA", sia, "rpkiNotify", nid_rpkiNotify(),
-           URI_VALID_HTTPS | URI_USE_RRDP_WORKSPACE, false, handle_rpkiNotify,
-           &uris->rpkiNotify);
+       error = ia2uris(sia, "SIA", mft_metadata, "rpkiManifest", &uris->mft);
        if (error)
                goto end;
 
-       /*
-        * Store the manifest URI in @mft.
-        * (We won't actually touch the manifest until we know the certificate
-        * is fully valid.)
-        */
-       error = handle_ad("SIA", sia, "rpkiManifest", nid_rpkiManifest(),
-           URI_VALID_RSYNC, true, handle_rpkiManifest, &uris->mft);
-
-end:
-       AUTHORITY_INFO_ACCESS_free(sia);
+end:   AUTHORITY_INFO_ACCESS_free(sia);
        return error;
 }
 
 static int
 handle_sia_ee(X509_EXTENSION *ext, void *arg)
 {
-       SIGNATURE_INFO_ACCESS *sia;
-       int error;
-
-       sia = X509V3_EXT_d2i(ext);
-       if (sia == NULL)
-               return cannot_decode(ext_sia());
-
-       error = handle_ad("SIA", sia, "signedObject", nid_signedObject(),
-           URI_VALID_RSYNC, true, handle_signedObject, arg);
+       const struct ad_metadata so_metadata[] = {
+               { .nid = nid_signedObject(), .uri_type = URI_TYPE_VOID },
+               { .nid = -1 },
+       };
+       struct certificate_refs *refs = arg;
 
-       AUTHORITY_INFO_ACCESS_free(sia);
-       return error;
+       return ext2uris(ext, "SIA", so_metadata, "signedObject",
+           &refs->signedObject);
 }
 
 static int
@@ -1726,7 +1719,7 @@ handle_ar(X509_EXTENSION *ext, void *arg)
  * @sia_uris will be allocated.
  */
 static int
-certificate_validate_extensions_ta(X509 *cert, struct sia_ca_uris *sia_uris,
+validate_extensions_ta(X509 *cert, struct sia_ca_uris *sia_uris,
     enum rpki_policy *policy)
 {
        struct extension_handler handlers[] = {
@@ -1757,7 +1750,7 @@ certificate_validate_extensions_ta(X509 *cert, struct sia_ca_uris *sia_uris,
  * extensions.
  */
 static int
-certificate_validate_extensions_ca(X509 *cert, struct sia_ca_uris *sia_uris,
+validate_extensions_ca(X509 *cert, struct sia_ca_uris *sia_uris,
     struct certificate_refs *refs, enum rpki_policy *policy)
 {
        struct extension_handler handlers[] = {
@@ -1831,620 +1824,173 @@ has_bgpsec_router_eku(X509 *cert)
        return false;
 }
 
-/*
- * Assumption: Meant to be used exclusively in the context of parsing a .cer
- * certificate.
- */
-static int
-get_certificate_type(X509 *cert, bool is_ta, enum cert_type *result)
-{
-       if (is_ta) {
-               *result = TA;
-               return 0;
-       }
-
-       if (X509_check_ca(cert) == 1) {
-               *result = CA;
-               return 0;
-       }
-
-       if (has_bgpsec_router_eku(cert)) {
-               *result = BGPSEC;
-               return 0;
-       }
-
-       *result = EE; /* Shuts up nonsense gcc 8.3 warning */
-       return pr_val_err("Certificate is not TA, CA nor BGPsec. Ignoring...");
-}
-
-/*
- * It does some of the things from validate_issuer(), but we can not wait for
- * such validation, since at this point the RSYNC URI at AIA extension must be
- * verified to comply with rfc6487#section-4.8.7
- */
-static int
-force_aia_validation(struct rpki_uri *caIssuers, X509 *son)
+static enum cert_type
+get_certificate_type(X509 *cert, bool is_ta)
 {
-       X509 *parent;
-       struct rfc5280_name *son_name;
-       struct rfc5280_name *parent_name;
-       int error;
-
-       pr_val_debug("AIA's URI didn't matched parent URI, trying to SYNC");
-
-       /* RSYNC is still the preferred access mechanism, force the sync */
-       do {
-               error = rsync_download_files(caIssuers, false, true);
-               if (!error)
-                       break;
-               if (error == EREQFAILED) {
-                       pr_val_info("AIA URI couldn't be downloaded, trying to search locally");
-                       break;
-               }
-               return error;
-       } while (0);
-
-       error = certificate_load(caIssuers, &parent);
-       if (error)
-               return error;
-
-       error = x509_name_decode(X509_get_subject_name(parent), "subject",
-           &parent_name);
-       if (error)
-               goto free_parent;
-
-       error = x509_name_decode(X509_get_issuer_name(son), "issuer",
-           &son_name);
-       if (error)
-               goto free_parent_name;
-
-       if (x509_name_equals(parent_name, son_name))
-               error = 0; /* Everything its ok */
-       else
-               error = pr_val_err("Certificate subject from AIA ('%s') isn't issuer of this certificate.",
-                   uri_val_get_printable(caIssuers));
-
-       x509_name_put(son_name);
-free_parent_name:
-       x509_name_put(parent_name);
-free_parent:
-       X509_free(parent);
-       return error;
+       if (is_ta)
+               return TA;
+       if (X509_check_ca(cert) == 1)
+               return CA;
+       if (has_bgpsec_router_eku(cert))
+               return BGPSEC;
+       return EE; /* I guess; doesn't matter. */
 }
 
+/* TODO (fine) why is this not done in handle_aia(), again? */
 int
-certificate_validate_aia(struct rpki_uri *caIssuers, X509 *cert)
+certificate_validate_aia(struct uri_list *caIssuers, X509 *cert)
 {
-       struct validation *state;
+       struct cert_stack *certstack;
        struct rpki_uri *parent;
 
-       if (caIssuers == NULL)
+       if (caIssuers->len == 0)
                pr_crit("Certificate's AIA was not recorded.");
 
-       state = state_retrieve();
-       if (state == NULL)
-               return -EINVAL;
-       parent = x509stack_peek_uri(validation_certstack(state));
+       certstack = validation_certstack(state_retrieve());
+       parent = x509stack_peek_uri(certstack);
        if (parent == NULL)
                pr_crit("Certificate has no parent.");
 
        /*
-        * There are two possible issues here, specifically at first level root
-        * certificate's childs:
-        *
-        * - Considering that the root certificate can be published at one or
-        *   more rsync or HTTPS URIs (RFC 8630), the validation is done
-        *   considering the first valid downloaded certificate URI from the
-        *   list of URIs; so, that URI doesn't necessarily matches AIA. And
-        *   this issue is more likely to happen if the 'shuffle-uris' flag
-        *   is active an a TAL has more than one rsync/HTTPS uri.
-        *
-        * - If the TAL has only one URI, and such URI is HTTPS, the root
-        *   certificate will be located at a distinct point that what it's
-        *   expected, so this might be an error if such certificate (root
-        *   certificate) isn't published at an rsync repository. See RFC 6487
-        *   section-4.8.7:
-        *
-        *   "The preferred URI access mechanisms is "rsync", and an rsync URI
-        *   [RFC5781] MUST be specified with an accessMethod value of
-        *   id-ad-caIssuers.  The URI MUST reference the point of publication
-        *   of the certificate where this Issuer is the subject (the issuer's
-        *   immediate superior certificate)."
-        *
-        * As of today, this is a common scenario, since most of the TALs have
-        * an HTTPS URI.
+        * Most (read: all) certificates define only one caIssuers.
+        * (Unknown caIssuers are fine.)
         */
-       if (uri_equals(caIssuers, parent))
-               return 0;
-
-       /*
-        * 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 certstack_get_x509_num(validation_certstack(state)) == 1 ?
-           0 :
-           force_aia_validation(caIssuers, cert);
-}
-
-/*
- * Verify that the manifest file actually exists at the local repository, if it
- * doesn't exist then discard the repository (which can result in a attempt
- * to fetch data from another repository).
- */
-static int
-verify_mft_loc(struct rpki_uri *mft_uri)
-{
-       if (!valid_file_or_dir(uri_get_local(mft_uri), true, false,
-           __pr_val_err))
-               return -EINVAL; /* Error already logged */
-
-       return 0;
-}
-
-/*
- * Verify the manifest location at the local RRDP 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 -ENOENT;
+       if (!uris_contains(caIssuers, parent)) {
+               return pr_val_err("Certificate's AIA doesn't point to parent certificate (%s).",
+                   uri_val_get_printable(parent));
        }
 
-       uri_refput(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)
+validate_depth(void)
 {
-       bool data_updated;
-       int error;
-
-       /* Start working on the RRDP local workspace */
-       error = db_rrdp_uris_workspace_enable();
-       if (error)
-               return error;
-
-       data_updated = false;
-       error = rrdp_load(sia_uris->rpkiNotify.uri, &data_updated);
-       if (error)
-               goto err;
-
-       error = verify_rrdp_mft_loc(sia_uris->mft.uri);
-       switch(error) {
-       case 0:
-               /* MFT exists, great! We're good to go. */
-               break;
-       case -ENOENT:
-               /* Doesn't exist and the RRDP data was updated: error */
-               if (data_updated)
-                       goto err;
-
-               /* Otherwise, force the snapshot processing and check again */
-               error = rrdp_reload_snapshot(sia_uris->rpkiNotify.uri);
-               if (error)
-                       goto err;
-               error = verify_rrdp_mft_loc(sia_uris->mft.uri);
-               if (error)
-                       goto err;
-               break;
-       default:
-               goto err;
-       }
+       struct validation *state;
+       int total_parents;
 
-       /* Successfully loaded (or no updates yet), update MFT local URI */
-       error = replace_rrdp_mft_uri(&sia_uris->mft);
-       if (error)
-               goto err;
+       state = state_retrieve();
+       total_parents = certstack_get_x509_num(validation_certstack(state));
+       if (total_parents >= config_get_max_cert_depth())
+               return pr_val_err("Certificate chain maximum depth exceeded.");
 
        return 0;
-err:
-       db_rrdp_uris_workspace_disable();
-       return error;
 }
 
-static int
-exec_rsync_method(struct sia_ca_uris *sia_uris)
+static struct rpki_uri *
+find_effective_mft(struct sia_ca_uris *sia, struct rpki_uri *rpp)
 {
-       int error;
-
-       /* Stop working on the RRDP local workspace */
-       db_rrdp_uris_workspace_disable();
-       error = rsync_download_files(sia_uris->caRepository.uri, false, false);
-       if (error)
-               return error;
-
-       return verify_mft_loc(sia_uris->mft.uri);
+//     /* TODO (aaaa) think I'm going to need some examples. */
+//     char const *local_rpp;
+//
+//     local_rpp = uri_get_local(rpp);
+       return sia->mft.array[0];
 }
 
-/*
- * Currently only two access methods are supported, just consider those two:
- * rsync and RRDP. If a new access method is supported, this function must
- * change (and probably the sia_ca_uris struct as well).
- *
- * Both access method callbacks must verify the manifest existence.
- */
 static int
-use_access_method(struct sia_ca_uris *sia_uris,
-    access_method_exec rsync_cb, access_method_exec rrdp_cb, bool new_level,
-    bool *retry_repo_sync)
+traverse_rpp(struct sia_ca_uris *sia)
 {
-       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.
-        */
-       if (sia_uris->rpkiNotify.uri == NULL) {
-               primary_rrdp = false;
-               error = rsync_cb(sia_uris);
-               if (!error)
-                       return 0;
-               goto verify_mft;
-       }
-
-       /*
-        * There isn't any restriction about the preferred access method of
-        * children CAs being the same as the parent CA.
-        *
-        * Two possible scenarios arise:
-        * 1) CA Parent didn't utilized (or didn't had) an RRDP update
-        *    notification URI.
-        * 2) CA Parent successfully utilized an RRDP update notification URI.
-        *
-        * Step (1) is simple, do the check of the preferred access method.
-        * Step (2) must do something different.
-        * - If RRDP URI was already successfully visited, don't care
-        *   preference, don't execute access method.
-        */
-       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 replace_rrdp_mft_uri(&sia_uris->mft);
-       }
-
-       /* Use CA's or configured priority? */
-       if (config_get_rsync_priority() == config_get_http_priority())
-               primary_rrdp = sia_uris->caRepository.position
-                   > sia_uris->rpkiNotify.position;
-       else
-               primary_rrdp = config_get_rsync_priority()
-                   < config_get_http_priority();
-
-       cb_primary = primary_rrdp ? rrdp_cb : rsync_cb;
-       cb_secondary = primary_rrdp ? rsync_cb : rrdp_cb;
-
-       /* Try with the preferred; in case of error, try with the next one */
-       error = cb_primary(sia_uris);
-       if (!error) {
-               (*retry_repo_sync) = !primary_rrdp;
-               return 0;
-       }
-
-       if (primary_rrdp) {
-               working_repo_push(uri_get_global(sia_uris->rpkiNotify.uri));
-               if (error != -EPERM)
-                       pr_val_info("Couldn't fetch data from RRDP repository '%s', trying to fetch data now from '%s'.",
-                           uri_get_global(sia_uris->rpkiNotify.uri),
-                           uri_get_global(sia_uris->caRepository.uri));
-               else
-                       pr_val_info("RRDP repository '%s' download/processing returned error previously, now I will try to fetch data from '%s'.",
-                           uri_get_global(sia_uris->rpkiNotify.uri),
-                           uri_get_global(sia_uris->caRepository.uri));
-       } else {
-               working_repo_push(uri_get_global(sia_uris->caRepository.uri));
-               pr_val_info("Couldn't fetch data from repository '%s', trying to fetch data now from RRDP '%s'.",
-                   uri_get_global(sia_uris->caRepository.uri),
-                   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 */
-       working_repo_pop();
-
-verify_mft:
-       /* Reach here on error or when both access methods were utilized */
-       switch (error) {
-       case 0:
-               /* Remove the error'd URI, since we got the repo files */
-               if (working_repo_peek() != NULL)
-                       reqs_errors_rem_uri(working_repo_peek());
-               break;
-       case EREQFAILED:
-               /* Log that we'll try to work with a local copy */
-               pr_val_warn("Trying to work with the local cache files.");
-               (*retry_repo_sync) = false;
-               break;
-       case -EPERM:
-               /*
-                * Specific RRPD error: the URI error'd on the first try, so
-                * we'll keep trying with the local files
-                */
-               (*retry_repo_sync) = false;
-               break;
-       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);
-}
-
-/*
- * Get the rsync server part from an rsync URI.
- *
- * If the URI is:
- *   rsync://<server>/<service/<file path>
- * This will return:
- *   rsync://<server>
- */
-static int
-get_rsync_server_uri(struct rpki_uri *src, char **result, size_t *result_len)
-{
-       char const *global;
-       char *tmp;
-       size_t global_len;
-       unsigned int slashes;
-       size_t i;
-
-       global = uri_get_global(src);
-       global_len = uri_get_global_len(src);
-       slashes = 0;
-
-       for (i = 0; i < global_len; i++) {
-               if (global[i] == '/') {
-                       slashes++;
-                       if (slashes == 3)
-                               break;
-               }
-       }
-
-       tmp = malloc(i + 1);
-       if (tmp == NULL)
-               return pr_enomem();
-
-       strncpy(tmp, global, i);
-       tmp[i] = '\0';
-
-       *result_len = i;
-       *result = tmp;
-
-       return 0;
-}
-
-static int
-set_repository_level(bool is_ta, struct validation *state,
-    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;
-       unsigned int new_level;
-       bool update;
+       /* "Effective" = The one we successfully downloaded. */
+       struct rpki_uri *effective_rpp;
+       struct rpki_uri *effective_mft;
+       struct rpp *pp;
        int error;
 
-       new_level = 0;
-       if (is_ta || cert_uri == NULL) {
-               working_repo_push_level(new_level);
-               return 0;
-       }
+       effective_rpp = uris_download(&sia->src);
+       if (effective_rpp == NULL)
+               return -ESRCH;
 
-       /* Warning killer */
-       parent_server = NULL;
-       current_server = NULL;
-       parent_server_len = 0;
-       current_server_len = 0;
+       effective_mft = find_effective_mft(sia, effective_rpp);
+       if (effective_mft == NULL)
+               return -ESRCH;
 
-       /* Both are rsync URIs, check the server part */
-       error = get_rsync_server_uri(cert_uri, &parent_server,
-           &parent_server_len);
+       error = handle_manifest(effective_mft, &pp);
        if (error)
                return error;
 
-       error = get_rsync_server_uri(sia_uris->caRepository.uri,
-           &current_server, &current_server_len);
-       if (error) {
-               free(parent_server);
-               return error;
-       }
-
-       if (parent_server_len != current_server_len) {
-               update = true;
-               goto end;
-       }
-
-       update = (strcmp(parent_server, current_server) != 0);
-end:
-       new_level = x509stack_peek_level(validation_certstack(state));
-       if (update)
-               new_level++;
-
-       working_repo_push_level(new_level);
-
-       free(parent_server);
-       free(current_server);
+       rpp_traverse(pp);
 
-       (*updated) = update;
+       rpp_refput(pp);
        return 0;
 }
 
-/** Boilerplate code for CA certificate validation and recursive traversal. */
+/** Boilerplate code for CA certificate validation and "recursive" traversal. */
 int
 certificate_traverse(struct rpp *rpp_parent, struct rpki_uri *cert_uri)
 {
 /** Is the CA certificate the TA certificate? */
 #define IS_TA (rpp_parent == NULL)
 
-       struct validation *state;
-       int total_parents;
        STACK_OF(X509_CRL) *rpp_parent_crl;
        X509 *cert;
-       struct sia_ca_uris sia_uris;
+       struct sia_ca_uris sia;
        struct certificate_refs refs;
        enum rpki_policy policy;
        enum cert_type type;
-       struct rpp *pp;
-       bool repo_retry;
-       bool new_level;
        int error;
 
-       state = state_retrieve();
-       if (state == NULL)
-               return -EINVAL;
-       total_parents = certstack_get_x509_num(validation_certstack(state));
-       if (total_parents >= config_get_max_cert_depth())
-               return pr_val_err("Certificate chain maximum depth exceeded.");
-
-       /* Debug cert type */
-       if (IS_TA)
-               pr_val_debug("TA Certificate '%s' {",
-                   uri_val_get_printable(cert_uri));
-       else
-               pr_val_debug("Certificate '%s' {",
-                   uri_val_get_printable(cert_uri));
-
+       pr_val_debug("Certificate '%s' {", uri_val_get_printable(cert_uri));
        fnstack_push_uri(cert_uri);
 
-       error = rpp_crl(rpp_parent, &rpp_parent_crl);
+       error = validate_depth();
        if (error)
                goto revert_fnstack_and_debug;
 
-       /* -- Validate the certificate (@cert) -- */
-       error = certificate_load(cert_uri, &cert);
+       /* Load certificate and CRL */
+       error = rpp_crl(rpp_parent, &rpp_parent_crl);
        if (error)
                goto revert_fnstack_and_debug;
-       error = certificate_validate_chain(cert, rpp_parent_crl);
+       error = certificate_load(cert_uri, &cert);
        if (error)
-               goto revert_cert;
+               goto revert_fnstack_and_debug;
 
-       error = get_certificate_type(cert, IS_TA, &type);
+       /* Validate */
+       error = certificate_validate_chain(cert, rpp_parent_crl);
        if (error)
                goto revert_cert;
 
-       /* Debug cert type */
+       type = get_certificate_type(cert, IS_TA);
        switch (type) {
        case TA:
+               pr_val_debug("Type: TA");
                break;
        case CA:
                pr_val_debug("Type: CA");
                break;
        case BGPSEC:
-               pr_val_debug("Type: BGPsec EE. Ignoring...");
+               pr_val_debug("Type: BGPsec EE");
+               pr_val_err("BGP certificates are still unsupported.");
                goto revert_cert;
        case EE:
-               pr_val_debug("Type: unexpected, validated as CA");
-               break;
+               pr_val_debug("Type: Unknown");
+               pr_val_err("Unknown certificate type; discarding.");
+               goto revert_cert;
        }
 
        error = certificate_validate_rfc6487(cert, type);
        if (error)
                goto revert_cert;
 
-       sia_ca_uris_init(&sia_uris);
-       memset(&refs, 0, sizeof(refs));
+       uris_init(&sia.src);
+       uris_init(&sia.mft);
+       refs.crldp = NULL;
+       uris_init(&refs.caIssuers);
+       uris_init(&refs.signedObject);
 
        switch (type) {
        case TA:
-               error = certificate_validate_extensions_ta(cert, &sia_uris,
-                   &policy);
+               error = validate_extensions_ta(cert, &sia, &policy);
                break;
        default:
                /* Validate as a CA */
-               error = certificate_validate_extensions_ca(cert, &sia_uris,
-                   &refs, &policy);
+               error = validate_extensions_ca(cert, &sia, &refs, &policy);
                break;
        }
        if (error)
                goto revert_uris;
 
        if (!IS_TA) {
-               error = certificate_validate_aia(refs.caIssuers, cert);
+               error = certificate_validate_aia(&refs.caIssuers, cert);
                if (error)
                        goto revert_uris;
        }
@@ -2453,76 +1999,19 @@ certificate_traverse(struct rpp *rpp_parent, struct rpki_uri *cert_uri)
        if (error)
                goto revert_uris;
 
-       /* Identify if this is a new repository before fetching it */
-       new_level = false;
-       error = set_repository_level(IS_TA, state, cert_uri, &sia_uris,
-           &new_level);
+       /* Certificate is valid; add it to the trusted stack. */
+       error = x509stack_push(cert_uri, cert, policy, IS_TA);
        if (error)
                goto revert_uris;
+       cert = NULL; /* Ownership stolen by the stack. */
 
-       /*
-        * RFC 6481 section 5: "when the repository publication point contents
-        * are updated, a repository operator cannot assure RPs that the
-        * manifest contents and the repository contents will be precisely
-        * aligned at all times"
-        *
-        * 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, new_level, &repo_retry);
+       error = traverse_rpp(&sia);
        if (error)
-               goto revert_uris;
-
-       do {
-               /* Validate the manifest (@mft) pointed by the certificate */
-               error = x509stack_push(validation_certstack(state), cert_uri,
-                   cert, policy, IS_TA);
-               if (error)
-                       goto revert_uris;
-
-               cert = NULL; /* Ownership stolen */
-
-               error = handle_manifest(sia_uris.mft.uri, !repo_retry, &pp);
-               if (error == 0 || !repo_retry)
-                       break;
+               x509stack_cancel();
 
-               /*
-                * Don't reach here if:
-                * - Manifest is valid.
-                * - Working with local files due to a download error.
-                * - RRDP was utilized to fetch the manifest.
-                * - There was a previous attempt to re-fetch the repository.
-                */
-               pr_val_info("Retrying repository download to discard 'transient inconsistency' manifest issue (see RFC 6481 section 5) '%s'",
-                   uri_val_get_printable(sia_uris.caRepository.uri));
-               error = rsync_download_files(sia_uris.caRepository.uri, false, true);
-               if (error)
-                       break;
-
-               /* Cancel stack, reload certificate (no need to revalidate) */
-               x509stack_cancel(validation_certstack(state));
-               error = certificate_load(cert_uri, &cert);
-               if (error)
-                       goto revert_uris;
-
-               repo_retry = false;
-       } while (true);
-
-       if (error) {
-               x509stack_cancel(validation_certstack(state));
-               goto revert_uris;
-       }
-
-       /* -- Validate & traverse the RPP (@pp) described by the manifest -- */
-       rpp_traverse(pp);
-
-       rpp_refput(pp);
 revert_uris:
-       sia_ca_uris_cleanup(&sia_uris);
+       uris_cleanup(&sia.src);
+       uris_cleanup(&sia.mft);
        refs_cleanup(&refs);
 revert_cert:
        if (cert != NULL)
index b6a18b5954eeb3221ca4e9c0c38a8103b322061c..7fb1d80e2145dc9e8796414328e04f6901997d10 100644 (file)
@@ -5,8 +5,8 @@
 #include <openssl/x509.h>
 #include "certificate_refs.h"
 #include "resource.h"
-#include "rpp.h"
 #include "types/uri.h"
+#include "rpp/rpp.h"
 #include "asn1/asn1c/ANY.h"
 #include "asn1/asn1c/SignatureValue.h"
 
@@ -57,7 +57,7 @@ int certificate_validate_extensions_ee(X509 *, OCTET_STRING_t *,
  * Specific validation of AIA (rfc6487#section-4.8.7) extension, public so that
  * CAs and EEs can access it.
  */
-int certificate_validate_aia(struct rpki_uri *, X509 *);
+int certificate_validate_aia(struct uri_list *, X509 *);
 
 int certificate_traverse(struct rpp *, struct rpki_uri *);
 
index b9372c9ef736bce42bf37cab2ff2bc9e313d0ca3..355a335d583dfa46ed9242953d36a47c9ecd27b4 100644 (file)
@@ -55,7 +55,7 @@ revert_args:
 revert_sobj:
        signed_object_cleanup(&sobj);
 revert_log:
-       pr_val_debug("}");
        fnstack_pop();
+       pr_val_debug("}");
        return error;
 }
index f93db38b954f291071fcf6defa4e8d1e67a1d1b8..43cab56252603ea9e8777ab08056f4edbd5d75c8 100644 (file)
@@ -1,8 +1,7 @@
 #ifndef SRC_OBJECT_GHOSTBUSTERS_H_
 #define SRC_OBJECT_GHOSTBUSTERS_H_
 
-#include "rpp.h"
-#include "types/uri.h"
+#include "rpp/rpp.h"
 
 int ghostbusters_traverse(struct rpki_uri *, struct rpp *);
 
index 1c83cc8556923fcd83db3b51273b4254485f9a88..83dbc3bda05ddce51508ba36d19146e687a32baa 100644 (file)
@@ -150,8 +150,7 @@ validate_manifest(struct Manifest *manifest)
 }
 
 static int
-build_rpp(struct Manifest *mft, struct rpki_uri *mft_uri, bool rrdp_workspace,
-    struct rpp **pp)
+build_rpp(struct Manifest *mft, struct rpki_uri *mft_uri, struct rpp **pp)
 {
        int i;
        struct FileAndHash *fah;
@@ -165,15 +164,8 @@ build_rpp(struct Manifest *mft, struct rpki_uri *mft_uri, bool rrdp_workspace,
        for (i = 0; i < mft->fileList.list.count; i++) {
                fah = mft->fileList.list.array[i];
 
-               error = uri_create_mft(&uri, mft_uri, &fah->file,
-                   rrdp_workspace);
-               if (error == ESKIP)
-                       continue;
-               /*
-                * Not handling ENOTRSYNC is fine because the manifest URL
-                * should have been RSYNC. Something went wrong if an RSYNC URL
-                * plus a relative path is not RSYNC.
-                */
+               /* TODO (aaaa) where's the file validation? */
+               error = uri_create_mft(mft_uri, &fah->file, &uri);
                if (error)
                        goto fail;
 
@@ -229,10 +221,10 @@ fail:
 
 /**
  * Validates the manifest pointed by @uri, returns the RPP described by it in
- * @pp. If @rrdp_workspace is true, use the local RRDP repository.
+ * @pp.
  */
 int
-handle_manifest(struct rpki_uri *uri, bool rrdp_workspace, struct rpp **pp)
+handle_manifest(struct rpki_uri *uri, struct rpp **pp)
 {
        static OID oid = OID_MANIFEST;
        struct oid_arcs arcs = OID2ARCS("manifest", oid);
@@ -255,7 +247,7 @@ handle_manifest(struct rpki_uri *uri, bool rrdp_workspace, struct rpp **pp)
                goto revert_sobj;
 
        /* Initialize out parameter (@pp) */
-       error = build_rpp(mft, uri, rrdp_workspace, pp);
+       error = build_rpp(mft, uri, pp);
        if (error)
                goto revert_manifest;
 
@@ -291,7 +283,7 @@ revert_manifest:
 revert_sobj:
        signed_object_cleanup(&sobj);
 revert_log:
-       pr_val_debug("}");
        fnstack_pop();
+       pr_val_debug("}");
        return error;
 }
index e127cd5407736b3c76be12b88e3452192998b5ac..719cd930ccc8974fd998309c3989c9244135d339 100644 (file)
@@ -1,9 +1,8 @@
 #ifndef SRC_OBJECT_MANIFEST_H_
 #define SRC_OBJECT_MANIFEST_H_
 
-#include <stdbool.h>
-#include "rpp.h"
+#include "rpp/rpp.h"
 
-int handle_manifest(struct rpki_uri *, bool, struct rpp **);
+int handle_manifest(struct rpki_uri *, struct rpp **);
 
 #endif /* SRC_OBJECT_MANIFEST_H_ */
index fd64bb422d268ecea8584c720f110d16d8d27919..2ebcce980791258e4d6f099ac4b4c613686e30e4 100644 (file)
@@ -146,7 +146,6 @@ x509_name_equals(struct rfc5280_name *a, struct rfc5280_name *b)
 int
 validate_issuer_name(char const *container, X509_NAME *issuer)
 {
-       struct validation *state;
        X509 *parent;
        struct rfc5280_name *parent_subject;
        struct rfc5280_name *child_issuer;
@@ -159,10 +158,7 @@ validate_issuer_name(char const *container, X509_NAME *issuer)
         * But let's check it anyway.
         */
 
-       state = state_retrieve();
-       if (state == NULL)
-               return -EINVAL;
-       parent = x509stack_peek(validation_certstack(state));
+       parent = x509stack_peek();
        if (parent == NULL) {
                return pr_val_err("%s appears to have no parent certificate.",
                    container);
index e8de49b541f08afe39a06de3282da3aedcdcae07..d305995c9c732f6148128d6f688ded4df328f7df 100644 (file)
@@ -1,8 +1,7 @@
 #ifndef SRC_OBJECT_ROA_H_
 #define SRC_OBJECT_ROA_H_
 
-#include "rpp.h"
-#include "types/address.h"
+#include "rpp/rpp.h"
 #include "types/uri.h"
 
 int roa_traverse(struct rpki_uri *, struct rpp *);
index 98d58900fa9dd016a60bfc06145ac7756830a81e..4e95d5b81be929942ed2679eb1a0752847b2fd4b 100644 (file)
@@ -1,48 +1,27 @@
 #define _GNU_SOURCE
 
-#include "tal.h"
+#include "object/tal.h"
 
 #include <errno.h>
-#include <pthread.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
 #include <unistd.h>
 #include <sys/queue.h>
 #include <sys/stat.h>
-#include <openssl/evp.h>
+#include <sys/types.h>
 
-#include "cert_stack.h"
 #include "common.h"
-#include "config.h"
 #include "line_file.h"
-#include "log.h"
-#include "random.h"
-#include "reqs_errors.h"
 #include "state.h"
 #include "thread_var.h"
-#include "validation_handler.h"
+#include "types/uri.h"
+#include "types/uri_list.h"
 #include "crypto/base64.h"
-#include "http/http.h"
-#include "object/certificate.h"
-#include "rsync/rsync.h"
 #include "rtr/db/vrps.h"
-#include "rrdp/db/db_rrdp.h"
 
-#define TAL_FILE_EXTENSION     ".tal"
 typedef int (*foreach_uri_cb)(struct tal *, struct rpki_uri *, void *);
 
-struct uris {
-       struct rpki_uri **array; /* This is an array of rpki URIs. */
-       unsigned int count;
-       unsigned int size;
-       unsigned int rsync_count;
-       unsigned int https_count;
-};
-
 struct tal {
        char const *file_name;
-       struct uris uris;
+       struct uri_list ta;
        unsigned char *spki; /* Decoded; not base64. */
        size_t spki_len;
 };
@@ -50,13 +29,6 @@ struct tal {
 struct validation_thread {
        /* TAL file name */
        char *tal_file;
-       /*
-        * Try to use the TA from the local cache? Only if none of the URIs
-        * was sync'd.
-        */
-       bool retry_local;
-       /* Try to sync the current TA URI? */
-       bool sync_files;
        void *arg;
        int exit_status;
        /* This should also only be manipulated by the parent thread. */
@@ -73,110 +45,54 @@ struct tal_param {
 };
 
 static int
-uris_init(struct uris *uris)
-{
-       uris->count = 0;
-       uris->rsync_count = 0;
-       uris->https_count = 0;
-       uris->size = 4; /* Most TALs only define one. */
-       uris->array = malloc(uris->size * sizeof(struct rpki_uri *));
-       return (uris->array != NULL) ? 0 : pr_enomem();
-}
-
-static void
-uris_destroy(struct uris *uris)
-{
-       unsigned int i;
-       for (i = 0; i < uris->count; i++)
-               uri_refput(uris->array[i]);
-       free(uris->array);
-}
-
-static int
-uris_add(struct uris *uris, char *uri)
+read_uris(struct line_file *lfile, struct uri_list *ta)
 {
-       struct rpki_uri **tmp;
-       struct rpki_uri *new;
+       char *line;
        int error;
 
-       error = uri_create_mixed_str(&new, uri, strlen(uri));
-       if (error == ENOTSUPPORTED)
-               return pr_op_err("TAL has non-RSYNC/HTTPS URI.");
-
+       error = lfile_read(lfile, &line);
        if (error)
                return error;
 
-       if (uri_is_rsync(new))
-               uris->rsync_count++;
-       else
-               uris->https_count++;
-
-       if (uris->count + 1 >= uris->size) {
-               uris->size *= 2;
-               tmp = realloc(uris->array,
-                   uris->size * sizeof(struct rpki_uri *));
-               if (tmp == NULL) {
-                       uri_refput(new);
-                       return pr_enomem();
-               }
-               uris->array = tmp;
-       }
-
-       uris->array[uris->count++] = new;
-       return 0;
-}
-
-static int
-read_uris(struct line_file *lfile, struct uris *uris)
-{
-       char *uri;
-       int error;
-
-       error = lfile_read(lfile, &uri);
-       if (error)
-               return error;
-
-       if (uri == NULL)
+       if (line == NULL)
                return pr_op_err("TAL file is empty.");
-       if (strcmp(uri, "") == 0) {
-               free(uri);
+       if (strcmp(line, "") == 0) {
+               free(line);
                return pr_op_err("There's no URI in the first line of the TAL.");
-       } else if (strncmp(uri, "#", 1) == 0) {
+       } else if (strncmp(line, "#", 1) == 0) {
                /* More comments expected, or an URI */
                do {
-                       free(uri); /* Ignore the comment */
-                       error = lfile_read(lfile, &uri);
+                       free(line); /* Ignore the comment */
+                       error = lfile_read(lfile, &line);
                        if (error)
                                return error;
-                       if (uri == NULL)
+                       if (line == NULL)
                                return pr_op_err("TAL file ended prematurely. (Expected more comments or an URI list.)");
-                       if (strcmp(uri, "") == 0) {
-                               free(uri);
+                       if (strcmp(line, "") == 0) {
+                               free(line);
                                return pr_op_err("TAL file comments syntax error. (Expected more comments or an URI list.)");
                        }
                        /* Not a comment, probably the URI(s) */
-                       if (strncmp(uri, "#", 1) != 0)
+                       if (strncmp(line, "#", 1) != 0)
                                break;
                } while (true);
        }
 
        do {
-               error = uris_add(uris, uri);
-               free(uri); /* Won't be needed anymore */
+               error = uris_add_str(ta, line, URI_TYPE_VERSATILE);
                if (error)
                        return error;
 
-               error = lfile_read(lfile, &uri);
+               error = lfile_read(lfile, &line);
                if (error)
                        return error;
 
-               if (uri == NULL)
+               if (line == NULL)
                        return pr_op_err("TAL file ended prematurely. (Expected URI list, blank line and public key.)");
-               if (strcmp(uri, "") == 0) {
-                       free(uri);
-                       return 0; /* Happy path */
-               }
-       } while (true);
+       } while (strcmp(line, "") != 0);
+
+       free(line);
+       return 0;
 }
 
 static size_t
@@ -185,6 +101,7 @@ get_spki_orig_size(struct line_file *lfile)
        struct stat st;
        size_t result;
 
+       /* TODO excuse me? Where's the errno validation? */
        stat(lfile_name(lfile), &st);
        result = st.st_size - lfile_offset(lfile);
        return result;
@@ -364,15 +281,10 @@ tal_load(char const *file_name, struct tal **result)
        }
 
        tal->file_name = file_name;
-
-       error = uris_init(&tal->uris);
-       if (error)
-               goto fail2;
-
-       error = read_uris(lfile, &tal->uris);
+       uris_init(&tal->ta);
+       error = read_uris(lfile, &tal->ta);
        if (error)
                goto fail1;
-
        error = read_spki(lfile, tal);
        if (error)
                goto fail1;
@@ -381,14 +293,10 @@ tal_load(char const *file_name, struct tal **result)
        *result = tal;
        return 0;
 
-fail1:
-       uris_destroy(&tal->uris);
-fail2:
+fail1: uris_cleanup(&tal->ta);
        free(tal);
-fail3:
-       lfile_close(lfile);
-fail4:
-       return error;
+fail3: lfile_close(lfile);
+fail4: return error;
 }
 
 void
@@ -397,87 +305,11 @@ tal_destroy(struct tal *tal)
        if (tal == NULL)
                return;
 
-       uris_destroy(&tal->uris);
+       uris_cleanup(&tal->ta);
        free(tal->spki);
        free(tal);
 }
 
-int
-foreach_uri(struct tal *tal, foreach_uri_cb cb, void *arg)
-{
-       unsigned int i;
-       int error;
-
-       for (i = 0; i < tal->uris.count; i++) {
-               error = cb(tal, tal->uris.array[i], arg);
-               if (error)
-                       return error;
-       }
-
-       return 0;
-}
-
-static void
-tal_shuffle_uris(struct tal *tal)
-{
-       struct rpki_uri **array = tal->uris.array;
-       struct rpki_uri *tmp;
-       unsigned int count = tal->uris.count;
-       long random_index;
-       unsigned int i;
-
-       random_init();
-
-       for (i = 0; i < count; i++) {
-               tmp = array[i];
-               random_index = random_at_most(count - 1 - i) + i;
-               array[i] = array[random_index];
-               array[random_index] = tmp;
-       }
-}
-
-static int
-tal_order_uris(struct tal *tal)
-{
-       struct rpki_uri **ordered;
-       struct rpki_uri **tmp;
-       bool http_first;
-       unsigned int i;
-       unsigned int last_rsync;
-       unsigned int last_https;
-
-       /* First do the shuffle */
-       if (config_get_shuffle_tal_uris())
-               tal_shuffle_uris(tal);
-
-       if (config_get_rsync_priority() == config_get_http_priority())
-               return 0;
-
-       /* Now order according to the priority */
-       http_first = (config_get_http_priority() > config_get_rsync_priority());
-
-       ordered = malloc(tal->uris.size * sizeof(struct rpki_uri *));
-       if (ordered == NULL)
-               return pr_enomem();
-
-       last_rsync = (http_first ? tal->uris.https_count : 0);
-       last_https = (http_first ? 0 : tal->uris.rsync_count);
-
-       for (i = 0; i < tal->uris.count; i++) {
-               if (uri_is_rsync(tal->uris.array[i]))
-                       ordered[last_rsync++] = tal->uris.array[i];
-               else
-                       ordered[last_https++] = tal->uris.array[i];
-       }
-
-       /* Everything is ok, point to the ordered array */
-       tmp = tal->uris.array;
-       tal->uris.array = ordered;
-       free(tmp);
-
-       return 0;
-}
-
 char const *
 tal_get_file_name(struct tal *tal)
 {
@@ -493,10 +325,10 @@ tal_get_spki(struct tal *tal, unsigned char const **buffer, size_t *len)
 
 /**
  * Performs the whole validation walkthrough on uri @uri, which is assumed to
- * have been extracted from a TAL.
+ * point to a successfully downloaded Trust Anchor.
  */
 static int
-handle_tal_uri(struct tal *tal, struct rpki_uri *uri, void *arg)
+handle_ta(struct rpki_uri *uri)
 {
        /*
         * Because of the way the foreach iterates, this function must return
@@ -509,65 +341,17 @@ handle_tal_uri(struct tal *tal, struct rpki_uri *uri, void *arg)
         * retrieved CA certificate public key does not match the TAL public
         * key." (RFC 8630)
         *
+        * TODO (aaaa) comment outdated, "public key not fatal" not implemented
+        *
         * A "hard error" is any other error.
         */
 
-       struct validation_thread *thread_arg = arg;
-       struct validation_handler validation_handler;
        struct validation *state;
        struct cert_stack *certstack;
        struct deferred_cert deferred;
        int error;
 
-       validation_handler.handle_roa_v4 = handle_roa_v4;
-       validation_handler.handle_roa_v6 = handle_roa_v6;
-       validation_handler.handle_router_key = handle_router_key;
-       validation_handler.arg = thread_arg->arg;
-
-       error = validation_prepare(&state, tal, &validation_handler);
-       if (error)
-               return ENSURE_NEGATIVE(error);
-
-       if (thread_arg->sync_files) {
-               if (uri_is_rsync(uri)) {
-                       if (!config_get_rsync_enabled()) {
-                               validation_destroy(state);
-                               return 0; /* Try some other TAL URI */
-                       }
-                       error = rsync_download_files(uri, true, false);
-               } else /* HTTPS */ {
-                       if (!config_get_http_enabled()) {
-                               validation_destroy(state);
-                               return 0; /* Try some other TAL URI */
-                       }
-                       error = http_download_file(uri,
-                           reqs_errors_log_uri(uri_get_global(uri)));
-               }
-
-               /* Reminder: there's a positive error: EREQFAILED */
-               if (error) {
-                       working_repo_push(uri_get_global(uri));
-                       validation_destroy(state);
-                       return pr_val_warn(
-                           "TAL URI '%s' could not be downloaded.",
-                           uri_val_get_printable(uri));
-               }
-       } else {
-               /* Look for local files */
-               if (!valid_file_or_dir(uri_get_local(uri), true, false,
-                   __pr_val_err)) {
-                       validation_destroy(state);
-                       return 0; /* Error already logged */
-               }
-       }
-
-       /* At least one URI was sync'd */
-       thread_arg->retry_local = false;
-       if (thread_arg->sync_files && working_repo_peek() != NULL)
-               reqs_errors_rem_uri(working_repo_peek());
-       working_repo_pop();
-
-       pr_val_debug("TAL URI '%s' {", uri_val_get_printable(uri));
+       pr_val_debug("Trust Anchor '%s' {", uri_val_get_printable(uri));
 
        if (!uri_is_certificate(uri)) {
                error = pr_op_err("TAL URI does not point to a certificate. (Expected .cer, got '%s')",
@@ -575,13 +359,7 @@ handle_tal_uri(struct tal *tal, struct rpki_uri *uri, void *arg)
                goto fail;
        }
 
-       /*
-        * Set all RRDPs URIs to non-requested, this way we will force the
-        * request on every cycle (to check if there are updates).
-        */
-       error = db_rrdp_uris_set_all_unvisited();
-       if (error)
-               goto end;
+       state = state_retrieve();
 
        /* Handle root certificate. */
        error = certificate_traverse(NULL, uri);
@@ -630,78 +408,46 @@ handle_tal_uri(struct tal *tal, struct rpki_uri *uri, void *arg)
        } while (true);
 
 fail:  error = ENSURE_NEGATIVE(error);
-end:   validation_destroy(state);
-       pr_val_debug("}");
+end:   pr_val_debug("}");
        return error;
 }
 
-static int
-__handle_tal_uri_sync(struct tal *tal, struct rpki_uri *uri, void *arg)
-{
-       int error;
-
-       error = handle_tal_uri(tal, uri, arg);
-       if (error)
-               return error;
-       working_repo_push(uri_get_global(uri));
-
-       return 0;
-}
-
-static int
-__handle_tal_uri_local(struct tal *tal, struct rpki_uri *uri, void *arg)
-{
-       return handle_tal_uri(tal, uri, arg);
-}
-
 static void
 do_file_validation(void *thread_arg)
 {
        struct validation_thread *thread = thread_arg;
        struct tal *tal;
+       struct rpki_uri *ta;
+       struct validation_handler validation_handler;
        int error;
 
        fnstack_init();
        fnstack_push(thread->tal_file);
 
-       working_repo_init();
-
        error = tal_load(thread->tal_file, &tal);
        if (error)
-               goto end;
-
-       error = tal_order_uris(tal);
-       if (error)
-               goto destroy_tal;
-
-       error = foreach_uri(tal, __handle_tal_uri_sync, thread_arg);
-       if (error > 0) {
-               error = 0;
-               goto destroy_tal;
-       } else if (error < 0) {
-               goto destroy_tal;
-       }
+               goto undo_fnstack;
 
-       if (!thread->retry_local) {
-               error = pr_op_err("None of the URIs of the TAL '%s' yielded a successful traversal.",
-                   thread->tal_file);
-               goto destroy_tal;
+       ta = uris_download(&tal->ta);
+       if (ta == NULL) {
+               error = -ESRCH;
+               goto undo_tal;
        }
 
-       thread->sync_files = false;
-       pr_val_warn("Looking for the TA certificate at the local files.");
+       validation_handler.handle_roa_v4 = handle_roa_v4;
+       validation_handler.handle_roa_v6 = handle_roa_v6;
+       validation_handler.handle_router_key = handle_router_key;
+       validation_handler.arg = thread->arg;
+       error = validation_prepare(tal, &validation_handler);
+       if (error)
+               goto undo_tal;
 
-       error = foreach_uri(tal, __handle_tal_uri_local, thread_arg);
-       if (error > 0)
-               error = 0;
-       else if (error == 0)
-               error = pr_op_err("None of the URIs of the TAL '%s' yielded a successful traversal.",
-                   thread->tal_file);
+       error = handle_ta(ta);
 
-destroy_tal:
+       validation_destroy();
+undo_tal:
        tal_destroy(tal);
-end:
-       working_repo_cleanup();
+undo_fnstack:
        fnstack_cleanup();
        thread->exit_status = error;
 }
@@ -721,15 +467,9 @@ __do_file_validation(char const *tal_file, void *arg)
        struct validation_thread *thread;
        int error;
 
-       error = db_rrdp_add_tal(tal_file);
-       if (error)
-               return error;
-
        thread = malloc(sizeof(struct validation_thread));
-       if (thread == NULL) {
-               error = pr_enomem();
-               goto free_db_rrdp;
-       }
+       if (thread == NULL)
+               return pr_enomem();
 
        thread->tal_file = strdup(tal_file);
        if (thread->tal_file == NULL) {
@@ -738,8 +478,6 @@ __do_file_validation(char const *tal_file, void *arg)
        }
        thread->arg = t_param->db;
        thread->exit_status = -EINTR;
-       thread->retry_local = true;
-       thread->sync_files = true;
 
        error = thread_pool_push(t_param->pool, thread->tal_file,
            do_file_validation, thread);
@@ -755,8 +493,6 @@ free_tal_file:
        free(thread->tal_file);
 free_thread:
        free(thread);
-free_db_rrdp:
-       db_rrdp_rem_tal(tal_file);
        return error;
 }
 
@@ -772,16 +508,13 @@ perform_standalone_validation(struct thread_pool *pool, struct db_table *table)
        if (param == NULL)
                return pr_enomem();
 
-       /* Set existent tal RRDP info to non visited */
-       db_rrdp_reset_visited_tals();
-
        SLIST_INIT(&threads);
 
        param->pool = pool;
        param->db = table;
        param->threads = &threads;
 
-       error = process_file_or_dir(config_get_tal(), TAL_FILE_EXTENSION, true,
+       error = process_file_or_dir(config_get_tal(), ".tal", true,
            __do_file_validation, param);
        if (error) {
                /* End all thread data */
@@ -809,18 +542,8 @@ perform_standalone_validation(struct thread_pool *pool, struct db_table *table)
                thread_destroy(thread);
        }
 
-       /* The parameter isn't needed anymore */
        free(param);
 
-       /* Log the error'd URIs summary */
-       reqs_errors_log_summary();
-
-       /* One thread has errors, validation can't keep the resulting table */
-       if (t_error)
-               return t_error;
-
-       /* Remove non-visited rrdps URIS by tal */
-       db_rrdp_rem_nonvisited_tals();
-
-       return error;
+       /* If one thread has errors, we can't keep the resulting table. */
+       return t_error;
 }
index aa376dfb3f58fcc645571721bbd5cdc3ee57ed66..977cd70d3d6c4d5309b0e67828e4dff9a395de6b 100644 (file)
@@ -4,7 +4,6 @@
 /* This is RFC 8630. */
 
 #include <stddef.h>
-#include "types/uri.h"
 #include "rtr/db/db_table.h"
 #include "thread/thread_pool.h"
 
index 291ee37c621fcc6aabf4c3569784588297de9aed..427b2ee83e4f002de1095928838a32cabc67609e 100644 (file)
@@ -1,4 +1,5 @@
 #include "random.h"
+
 #include <stdlib.h>
 #include <time.h>
 
diff --git a/src/reqs_errors.c b/src/reqs_errors.c
deleted file mode 100644 (file)
index 1501ce0..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-#include "reqs_errors.h"
-
-#include <pthread.h>
-#include <syslog.h>
-#include <time.h>
-
-#include "data_structure/uthash_nonfatal.h"
-#include "common.h"
-#include "config.h"
-#include "log.h"
-#include "thread_var.h"
-
-/*
- * Only log messages of repositories whose level is less than or equal to this.
- *
- * Level 0 is "top level", mostly used by the root CAs (trust anchors) and RIRs
- * before RPKI servers delegation.
- *
- * Eg. The URIs will have this level (data according to current RPKI state):
- * rsync://repository.lacnic.net/    [level 0]
- * rsync://rpki-repo.registro.br/    [level 1]
- *
- * rsync://rpki.ripe.net/            [level 0]
- * rsync://ca.rg.net/                [level 1]
- * rsync://cc.rg.net/                [level 2]
- */
-#define LOG_REPO_LEVEL 0
-
-struct error_uri {
-       /* Key */
-       char *uri;
-       /* Date when the first attempt was made */
-       time_t first_attempt;
-       /* Related URI (points to a key of another element) */
-       char *uri_related;
-       /* Refered by (where this.uri == that.uri_related) */
-       char *ref_by;
-       /* Log the summary */
-       bool log_summary;
-       UT_hash_handle hh;
-};
-
-static struct error_uri *err_uris_db;
-
-/* Prepare for multithreading. */
-static pthread_rwlock_t db_lock;
-
-static int
-error_uri_create(char const *uri, struct error_uri **err_uri)
-{
-       struct error_uri *tmp;
-       int error;
-
-       tmp = malloc(sizeof(struct error_uri));
-       if (tmp == NULL)
-               return pr_enomem();
-
-       /* Needed by uthash */
-       memset(tmp, 0, sizeof(struct error_uri));
-
-       tmp->uri = strdup(uri);
-       if (tmp->uri == NULL) {
-               error = pr_enomem();
-               goto release_tmp;
-       }
-
-       error = get_current_time(&tmp->first_attempt);
-       if (error)
-               goto release_uri;
-
-       tmp->log_summary = false;
-       tmp->uri_related = NULL;
-       tmp->ref_by = NULL;
-
-       *err_uri = tmp;
-       return 0;
-release_uri:
-       free(tmp->uri);
-release_tmp:
-       free(tmp);
-       return error;
-}
-
-static void
-error_uri_destroy(struct error_uri *err_uri)
-{
-       free(err_uri->uri);
-       free(err_uri);
-}
-
-int
-reqs_errors_init(void)
-{
-       int error;
-
-       error = pthread_rwlock_init(&db_lock, NULL);
-       if (error)
-               return pr_op_errno(error, "pthread_rwlock_init() errored");
-
-       err_uris_db = NULL;
-
-       return 0;
-}
-
-void
-reqs_errors_cleanup(void)
-{
-       /* Remove all the uris */
-       struct error_uri *node, *tmp;
-
-       HASH_ITER(hh, err_uris_db, node, tmp) {
-               HASH_DEL(err_uris_db, node);
-               error_uri_destroy(node);
-       }
-
-       pthread_rwlock_destroy(&db_lock); /* Nothing to do with error code */
-}
-
-static struct error_uri *
-find_error_uri(char const *search, bool lock)
-{
-       struct error_uri *found;
-
-       if (lock)
-               rwlock_read_lock(&db_lock);
-       HASH_FIND_STR(err_uris_db, search, found);
-       if (lock)
-               rwlock_unlock(&db_lock);
-
-       return found;
-}
-
-static void
-set_working_repo(struct error_uri *err_uri)
-{
-       struct error_uri *ref;
-       char const *work_uri;
-
-       work_uri = working_repo_peek();
-       if (work_uri == NULL)
-               return;
-
-       ref = find_error_uri(work_uri, true);
-       if (ref == NULL)
-               return;
-
-       err_uri->uri_related = ref->uri;
-       ref->ref_by = err_uri->uri;
-}
-
-int
-reqs_errors_add_uri(char const *uri)
-{
-       struct error_uri *new_uri, *found_uri;
-       int error;
-
-       /* Don't overwrite if it already exists */
-       found_uri = find_error_uri(uri, true);
-       if (found_uri != NULL)
-               return 0;
-
-       new_uri = NULL;
-       error = error_uri_create(uri, &new_uri);
-       if (error)
-               return error;
-
-       set_working_repo(new_uri);
-
-       /*
-        * Check if this will always be logged, in that case the summary will
-        * be logged also if the level must be logged.
-        */
-       if (config_get_stale_repository_period() == 0)
-               new_uri->log_summary =
-                   (working_repo_peek_level() <= LOG_REPO_LEVEL);
-
-       rwlock_write_lock(&db_lock);
-       HASH_ADD_KEYPTR(hh, err_uris_db, new_uri->uri, strlen(new_uri->uri),
-           new_uri);
-       rwlock_unlock(&db_lock);
-
-       return 0;
-}
-
-void
-reqs_errors_rem_uri(char const *uri)
-{
-       struct error_uri *found_uri;
-       struct error_uri *tmp;
-       char *ref_uri;
-
-       rwlock_write_lock(&db_lock);
-       found_uri = find_error_uri(uri, false);
-       if (found_uri == NULL) {
-               rwlock_unlock(&db_lock);
-               return;
-       }
-
-       while (found_uri->uri_related != NULL) {
-               tmp = find_error_uri(found_uri->uri_related, false);
-               if (tmp == NULL)
-                       break;
-               found_uri = tmp;
-       }
-
-       do {
-               ref_uri = found_uri->ref_by;
-               HASH_DELETE(hh, err_uris_db, found_uri);
-               error_uri_destroy(found_uri);
-               if (ref_uri == NULL)
-                       break;
-               HASH_FIND_STR(err_uris_db, ref_uri, found_uri);
-               if (found_uri == NULL)
-                       break;
-       } while (true);
-       rwlock_unlock(&db_lock);
-}
-
-int
-reqs_errors_foreach(reqs_errors_cb cb, void *arg)
-{
-       struct error_uri *node, *tmp;
-       int error;
-
-       rwlock_read_lock(&db_lock);
-       HASH_ITER(hh, err_uris_db, node, tmp) {
-               error = cb(node->uri, arg);
-               if (error) {
-                       rwlock_unlock(&db_lock);
-                       return error;
-               }
-       }
-       rwlock_unlock(&db_lock);
-
-       return 0;
-}
-
-bool
-reqs_errors_log_uri(char const *uri)
-{
-       struct error_uri *node;
-       time_t now;
-       unsigned int config_period;
-       int error;
-
-       if (log_op_enabled(LOG_DEBUG))
-               return true;
-
-       if (working_repo_peek_level() > LOG_REPO_LEVEL)
-               return false;
-
-       /* Log always? Don't care if the URI exists yet or not */
-       config_period = config_get_stale_repository_period();
-       if (config_period == 0)
-               return true;
-
-       node = find_error_uri(uri, true);
-       if (node == NULL)
-               return false;
-
-       now = 0;
-       error = get_current_time(&now);
-       if (error)
-               return false;
-
-       node->log_summary = (difftime(now, node->first_attempt) >=
-           (double)config_period);
-
-       return node->log_summary;
-}
-
-/*
- * Log a summary of the error'd servers.
- */
-void
-reqs_errors_log_summary(void)
-{
-       /* Remove all the uris */
-       struct error_uri *node, *tmp;
-       time_t now;
-       char *str_time;
-       bool first;
-       int error;
-
-       first = true;
-       now = 0;
-       error = get_current_time(&now);
-       if (error)
-               return;
-
-       rwlock_read_lock(&db_lock);
-       HASH_ITER(hh, err_uris_db, node, tmp) {
-               if (!node->log_summary)
-                       continue;
-               if (first) {
-                       pr_op_warn("The following repositories URIs couldn't be fetched (it can be a local issue or a server issue), please review previous log messages related to such URIs/servers:");
-                       first = false;
-               }
-               str_time = asctime(localtime(&node->first_attempt));
-               if (strrchr(str_time, '\n') != NULL) {
-                       *(str_time + strlen(str_time) - 1) = ' ';
-               }
-               pr_op_warn("- '%s': can't be downloaded since %s", node->uri,
-                   str_time);
-       }
-
-       rwlock_unlock(&db_lock);
-}
diff --git a/src/reqs_errors.h b/src/reqs_errors.h
deleted file mode 100644 (file)
index b13e328..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef SRC_REQS_ERRORS_H_
-#define SRC_REQS_ERRORS_H_
-
-#include <stdbool.h>
-
-int reqs_errors_init(void);
-void reqs_errors_cleanup(void);
-
-int reqs_errors_add_uri(char const *);
-void reqs_errors_rem_uri(char const *);
-
-bool reqs_errors_log_uri(char const *);
-
-typedef int (reqs_errors_cb)(char const *, void *);
-int reqs_errors_foreach(reqs_errors_cb, void *);
-
-void reqs_errors_log_summary(void);
-
-#endif /* SRC_REQS_ERRORS_H_ */
index 92c8f11fb36d581579d477645b5293f1b34d0bdc..7034f8b93ea710413ea78b35267f06881306b341 100644 (file)
@@ -86,10 +86,7 @@ unknown:
 static struct resources *
 get_parent_resources(void)
 {
-       struct validation *state = state_retrieve();
-       return (state != NULL)
-           ? x509stack_peek_resources(validation_certstack(state))
-           : NULL;
+       return x509stack_peek_resources(validation_certstack(state_retrieve()));
 }
 
 static int
similarity index 89%
rename from src/rpp.c
rename to src/rpp/rpp.c
index cd9ea95cd319f7ea7f0bd050b240b70ada81d6bc..7e9052b277523c04c6072ef969420930777c65ae 100644 (file)
--- a/src/rpp.c
@@ -1,4 +1,4 @@
-#include "rpp.h"
+#include "rpp/rpp.h"
 
 #include <stdlib.h>
 #include "cert_stack.h"
 #include "object/ghostbusters.h"
 #include "object/roa.h"
 
-STATIC_ARRAY_LIST(uris, struct rpki_uri *)
-
 /** A Repository Publication Point (RFC 6481), as described by some manifest. */
 struct rpp {
-       struct uris certs; /* Certificates */
+       struct uri_list certs; /* Certificates */
 
        /*
         * uri NULL implies stack NULL and error 0.
@@ -39,9 +37,9 @@ struct rpp {
 
        /* The Manifest is not needed for now. */
 
-       struct uris roas; /* Route Origin Attestations */
+       struct uri_list roas; /* Route Origin Attestations */
 
-       struct uris ghostbusters;
+       struct uri_list ghostbusters;
 
        /*
         * Note that the reference counting functions are not prepared for
@@ -76,24 +74,18 @@ rpp_refget(struct rpp *pp)
        pp->references++;
 }
 
-static void
-__uri_refput(struct rpki_uri **uri)
-{
-       uri_refput(*uri);
-}
-
 void
 rpp_refput(struct rpp *pp)
 {
        pp->references--;
        if (pp->references == 0) {
-               uris_cleanup(&pp->certs, __uri_refput);
+               uris_cleanup(&pp->certs);
                if (pp->crl.uri != NULL)
                        uri_refput(pp->crl.uri);
                if (pp->crl.stack != NULL)
                        sk_X509_CRL_pop_free(pp->crl.stack, X509_CRL_free);
-               uris_cleanup(&pp->roas, __uri_refput);
-               uris_cleanup(&pp->ghostbusters, __uri_refput);
+               uris_cleanup(&pp->roas);
+               uris_cleanup(&pp->ghostbusters);
                free(pp);
        }
 }
@@ -102,21 +94,21 @@ rpp_refput(struct rpp *pp)
 int
 rpp_add_cert(struct rpp *pp, struct rpki_uri *uri)
 {
-       return uris_add(&pp->certs, &uri);
+       return uris_add(&pp->certs, uri);
 }
 
 /** Steals ownership of @uri. */
 int
 rpp_add_roa(struct rpp *pp, struct rpki_uri *uri)
 {
-       return uris_add(&pp->roas, &uri);
+       return uris_add(&pp->roas, uri);
 }
 
 /** Steals ownership of @uri. */
 int
 rpp_add_ghostbusters(struct rpp *pp, struct rpki_uri *uri)
 {
-       return uris_add(&pp->ghostbusters, &uri);
+       return uris_add(&pp->ghostbusters, uri);
 }
 
 /** Steals ownership of @uri. */
@@ -213,7 +205,6 @@ rpp_crl(struct rpp *pp, STACK_OF(X509_CRL) **result)
 static int
 __cert_traverse(struct rpp *pp)
 {
-       struct validation *state;
        struct cert_stack *certstack;
        ssize_t i;
        struct deferred_cert deferred;
@@ -222,10 +213,7 @@ __cert_traverse(struct rpp *pp)
        if (pp->certs.len == 0)
                return 0;
 
-       state = state_retrieve();
-       if (state == NULL)
-               return -EINVAL;
-       certstack = validation_certstack(state);
+       certstack = validation_certstack(state_retrieve());
 
        deferred.pp = pp;
        /*
similarity index 82%
rename from src/rpp.h
rename to src/rpp/rpp.h
index ba75d256c5a6125ae01771b7b069467bdb7bbd05..f9913effc57f3c72b32e3719beccf966c2dde04b 100644 (file)
--- a/src/rpp.h
@@ -1,6 +1,7 @@
-#ifndef SRC_RPP_H_
-#define SRC_RPP_H_
+#ifndef SRC_RPP_RPP_H_
+#define SRC_RPP_RPP_H_
 
+#include <openssl/x509v3.h>
 #include "types/uri.h"
 
 struct rpp;
@@ -19,4 +20,4 @@ int rpp_crl(struct rpp *, STACK_OF(X509_CRL) **);
 
 void rpp_traverse(struct rpp *);
 
-#endif /* SRC_RPP_H_ */
+#endif /* SRC_RPP_RPP_H_ */
diff --git a/src/rpp/rpp_dl_status.c b/src/rpp/rpp_dl_status.c
new file mode 100644 (file)
index 0000000..224a4c5
--- /dev/null
@@ -0,0 +1,112 @@
+#include "rpp/rpp_dl_status.h"
+
+#include "log.h"
+#include "thread_var.h"
+#include "data_structure/uthash_nonfatal.h"
+
+struct visited_rpp {
+       struct rpki_uri *uri;
+       enum rpp_download_status status;
+       UT_hash_handle hh;
+};
+
+struct rpp_dl_status_db {
+       struct visited_rpp *table;
+};
+
+static struct rpp_dl_status_db *
+get_db(void)
+{
+       struct rpp_dl_status_db *db;
+
+       db = validation_get_rppdb(state_retrieve());
+       if (db == NULL)
+               pr_crit("Thread has no RPP table");
+
+       return db;
+}
+
+struct rpp_dl_status_db *
+rdsdb_create(void)
+{
+       struct rpp_dl_status_db *result;
+
+       result = malloc(sizeof(struct rpp_dl_status_db));
+       if (result == NULL)
+               return NULL;
+
+       result->table = NULL;
+       return result;
+}
+
+void
+rdsdb_destroy(struct rpp_dl_status_db *db)
+{
+       struct visited_rpp *node, *tmp;
+
+       HASH_ITER(hh, db->table, node, tmp) {
+               HASH_DEL(db->table, node);
+               uri_refput(node->uri);
+               free(node);
+       }
+       free(db);
+}
+
+/*
+ * Returns the download status (from the current validation cycle) of @uri.
+ */
+enum rpp_download_status
+rdsdb_get(struct rpki_uri *uri)
+{
+       struct rpp_dl_status_db *db;
+       struct visited_rpp *rpp;
+
+       db = get_db();
+       HASH_FIND_STR(db->table, uri_get_global(uri), rpp);
+
+       return (rpp != NULL) ? rpp->status : RDS_NOT_YET;
+}
+
+/*
+ * Remembers @uri's download result code @error during the rest of the current
+ * validation cycle.
+ */
+void
+rdsdb_set(struct rpki_uri *uri, int error)
+{
+       struct rpp_dl_status_db *db;
+       struct visited_rpp *new_rpp;
+       char const *key;
+       size_t key_len;
+
+       /* TODO (aaaa) check both protocols do it like this. */
+       if (error == ENOTCHANGED) {
+               pr_val_debug("No updates.");
+               error = 0;
+       }
+
+       db = get_db();
+
+       new_rpp = malloc(sizeof(struct visited_rpp));
+       if (new_rpp == NULL) {
+               pr_enomem();
+               /*
+                * Might end up redownloading, but it's better than returning
+                * error, because caller would interpret that as "WILL end up
+                * redownloading."
+                *
+                * This sucks.
+                *
+                * TODO You should REALLY implement critical enomems already.
+                */
+               return;
+       }
+
+       new_rpp->status = error ? RDS_ERROR : RDS_SUCCESS;
+       new_rpp->uri = uri;
+       uri_refget(uri);
+
+       key = uri_get_global(uri);
+       key_len = strlen(key);
+       HASH_ADD_KEYPTR(hh, db->table, key, key_len, new_rpp);
+}
diff --git a/src/rpp/rpp_dl_status.h b/src/rpp/rpp_dl_status.h
new file mode 100644 (file)
index 0000000..6a987b6
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef SRC_RPP_RPP_DL_STATUS_H_
+#define SRC_RPP_RPP_DL_STATUS_H_
+
+#include "types/uri.h"
+
+enum rpp_download_status {
+       /* Has not been downloaded in the current iteration. */
+       RDS_NOT_YET,
+       /* Already downloaded successfully in the current iteration. */
+       RDS_SUCCESS,
+       /* Download already attempted; it didn't work, do not retry. */
+       RDS_ERROR,
+};
+
+/*
+ * A table that stores the download status of each RPP during each validation
+ * run. It's meant to prevent us from accidentally downloading an RPP twice
+ * in quick succession.
+ *
+ * Only exists during validation runs.
+ */
+struct rpp_dl_status_db;
+
+/* TODO (aaaa) call these */
+struct rpp_dl_status_db *rdsdb_create(void);
+void rdsdb_destroy(struct rpp_dl_status_db *);
+
+enum rpp_download_status rdsdb_get(struct rpki_uri *);
+void rdsdb_set(struct rpki_uri *, int);
+
+#endif /* SRC_RPP_RPP_DL_STATUS_H_ */
diff --git a/src/rrdp/db/db_rrdp.c b/src/rrdp/db/db_rrdp.c
deleted file mode 100644 (file)
index 7bf328a..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-#include "rrdp/db/db_rrdp.h"
-
-#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;
-};
-
-SLIST_HEAD(tal_list, tal_elem);
-
-struct db_rrdp {
-       struct tal_list tals;
-};
-
-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)
-{
-       struct tal_elem *tmp;
-       struct db_rrdp_uri *tmp_uris;
-       int error;
-
-       tmp = malloc(sizeof(struct tal_elem));
-       if (tmp == NULL)
-               return pr_enomem();
-
-       tmp_uris = NULL;
-       error = db_rrdp_uris_create(&tmp_uris);
-       if (error)
-               goto end1;
-       tmp->uris = tmp_uris;
-
-       tmp->visited = true;
-       tmp->file_name = strdup(name);
-       if (tmp->file_name == NULL) {
-               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
-tal_elem_destroy(struct tal_elem *elem, bool remove_local)
-{
-       if (remove_local)
-               db_rrdp_uris_remove_all_local(elem->uris, elem->workspace);
-       db_rrdp_uris_destroy(elem->uris);
-       free(elem->file_name);
-       free(elem->workspace);
-       free(elem);
-}
-
-int
-db_rrdp_init(void)
-{
-       int error;
-
-       error = pthread_rwlock_init(&lock, NULL);
-       if (error)
-               return pr_op_errno(error, "DB RRDP pthread_rwlock_init() errored");
-
-       SLIST_INIT(&db.tals);
-       return 0;
-}
-
-void
-db_rrdp_cleanup(void)
-{
-       struct tal_elem *elem;
-
-       while (!SLIST_EMPTY(&db.tals)) {
-               elem = db.tals.slh_first;
-               SLIST_REMOVE_HEAD(&db.tals, next);
-               tal_elem_destroy(elem, false);
-       }
-       pthread_rwlock_destroy(&lock);
-}
-
-static struct tal_elem *
-db_rrdp_find_tal(char const *tal_name)
-{
-       struct tal_elem *found;
-
-       rwlock_read_lock(&lock);
-       SLIST_FOREACH(found, &db.tals, next) {
-               if (strcmp(tal_name, found->file_name) == 0) {
-                       rwlock_unlock(&lock);
-                       return found;
-               }
-       }
-       rwlock_unlock(&lock);
-
-       return NULL;
-}
-
-int
-db_rrdp_add_tal(char const *tal_name)
-{
-       struct tal_elem *elem, *found;
-       int error;
-
-       /* Element exists, no need to create it again */
-       found = db_rrdp_find_tal(tal_name);
-       if (found != NULL) {
-               found->visited = true;
-               return 0;
-       }
-
-       error = tal_elem_create(&elem, tal_name);
-       if (error)
-               return error;
-
-       rwlock_write_lock(&lock);
-       SLIST_INSERT_HEAD(&db.tals, elem, next);
-       rwlock_unlock(&lock);
-
-       return 0;
-}
-
-void
-db_rrdp_rem_tal(char const *tal_name)
-{
-       struct tal_elem *found;
-
-       found = db_rrdp_find_tal(tal_name);
-       if (found == NULL)
-               return;
-
-       rwlock_write_lock(&lock);
-       SLIST_REMOVE(&db.tals, found, tal_elem, next);
-       rwlock_unlock(&lock);
-
-       tal_elem_destroy(found, true);
-}
-
-/* Returns the reference to RRDP URIs of a TAL */
-struct db_rrdp_uri *
-db_rrdp_get_uris(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->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 */
-void
-db_rrdp_reset_visited_tals(void)
-{
-       struct tal_elem *found;
-
-       rwlock_write_lock(&lock);
-       SLIST_FOREACH(found, &db.tals, next)
-               found->visited = false;
-       rwlock_unlock(&lock);
-}
-
-/* Remove non-visited tals */
-void
-db_rrdp_rem_nonvisited_tals(void)
-{
-       struct tal_elem *found;
-
-       rwlock_write_lock(&lock);
-       SLIST_FOREACH(found, &db.tals, next) {
-               if (!found->visited) {
-                       SLIST_REMOVE(&db.tals, found, tal_elem, next);
-                       tal_elem_destroy(found, true);
-               }
-       }
-       rwlock_unlock(&lock);
-}
diff --git a/src/rrdp/db/db_rrdp.h b/src/rrdp/db/db_rrdp.h
deleted file mode 100644 (file)
index 0607f99..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef SRC_RRDP_DB_DB_RRDP_H_
-#define SRC_RRDP_DB_DB_RRDP_H_
-
-#include "rrdp/db/db_rrdp_uris.h"
-
-int db_rrdp_init(void);
-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);
-
-#endif /* SRC_RRDP_DB_DB_RRDP_H_ */
diff --git a/src/rrdp/db/db_rrdp_uris.c b/src/rrdp/db/db_rrdp_uris.c
deleted file mode 100644 (file)
index 51f24ee..0000000
+++ /dev/null
@@ -1,410 +0,0 @@
-#include "rrdp/db/db_rrdp_uris.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include "data_structure/uthash_nonfatal.h"
-#include "common.h"
-#include "log.h"
-#include "thread_var.h"
-
-struct uris_table {
-       /* Key */
-       char *uri;
-       /* Last session ID and serial from the URI */
-       struct global_data data;
-       /* Last local update of the URI (after a successful processing) */
-       long last_update;
-       /* The URI has been requested (HTTPS) at this cycle? */
-       rrdp_req_status_t request_status;
-       /* MFT URIs loaded from the @uri */
-       struct visited_uris *visited_uris;
-       UT_hash_handle hh;
-};
-
-struct db_rrdp_uri {
-       struct uris_table *table;
-       char const *current_workspace;
-};
-
-static int
-uris_table_create(char const *uri, char const *session_id,
-    unsigned long serial, rrdp_req_status_t req_status,
-    struct uris_table **result)
-{
-       struct uris_table *tmp;
-       int error;
-
-       tmp = malloc(sizeof(struct uris_table));
-       if (tmp == NULL)
-               return pr_enomem();
-       /* Needed by uthash */
-       memset(tmp, 0, sizeof(struct uris_table));
-
-       tmp->uri = strdup(uri);
-       if (tmp->uri == NULL) {
-               error = pr_enomem();
-               goto release_tmp;
-       }
-
-       tmp->data.session_id = strdup(session_id);
-       if (tmp->data.session_id == NULL) {
-               error = pr_enomem();
-               goto release_uri;
-       }
-
-       tmp->data.serial = serial;
-       tmp->last_update = 0;
-       tmp->request_status = req_status;
-       tmp->visited_uris = NULL;
-
-       *result = tmp;
-       return 0;
-release_uri:
-       free(tmp->uri);
-release_tmp:
-       free(tmp);
-       return error;
-}
-
-static void
-uris_table_destroy(struct uris_table *uri)
-{
-       visited_uris_refput(uri->visited_uris);
-       free(uri->data.session_id);
-       free(uri->uri);
-       free(uri);
-}
-
-static struct uris_table *
-find_rrdp_uri(struct db_rrdp_uri *uris, const char *search)
-{
-       struct uris_table *found;
-       HASH_FIND_STR(uris->table, search, found);
-       return found;
-}
-
-#define RET_NOT_FOUND_URI(uris, search, found)                         \
-       found = find_rrdp_uri(uris, search);                            \
-       if (found == NULL)                                              \
-               return -ENOENT;
-
-static void
-add_rrdp_uri(struct db_rrdp_uri *uris, struct uris_table *new_uri)
-{
-       struct uris_table *old_uri;
-
-       old_uri = find_rrdp_uri(uris, new_uri->uri);
-       if (old_uri != NULL) {
-               HASH_DELETE(hh, uris->table, old_uri);
-               uris_table_destroy(old_uri);
-       }
-       HASH_ADD_KEYPTR(hh, uris->table, new_uri->uri, strlen(new_uri->uri),
-           new_uri);
-}
-
-static int
-get_thread_rrdp_uris(struct db_rrdp_uri **result)
-{
-       struct validation *state;
-
-       state = state_retrieve();
-       if (state == NULL)
-               return pr_val_err("No state related to this thread");
-
-       *result = validation_get_rrdp_uris(state);
-       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)
-{
-       struct db_rrdp_uri *tmp;
-
-       tmp = malloc(sizeof(struct db_rrdp_uri));
-       if (tmp == NULL)
-               return pr_enomem();
-
-       tmp->table = NULL;
-       tmp->current_workspace = NULL;
-
-       *uris = tmp;
-       return 0;
-}
-
-void
-db_rrdp_uris_destroy(struct db_rrdp_uri *uris)
-{
-       struct uris_table *uri_node, *uri_tmp;
-
-       HASH_ITER(hh, uris->table, uri_node, uri_tmp) {
-               HASH_DEL(uris->table, uri_node);
-               uris_table_destroy(uri_node);
-       }
-       free(uris);
-}
-
-int
-db_rrdp_uris_cmp(char const *uri, char const *session_id, unsigned long serial,
-    rrdp_uri_cmp_result_t *result)
-{
-       struct db_rrdp_uri *uris;
-       struct uris_table *found;
-       int error;
-
-       uris = NULL;
-       error = get_thread_rrdp_uris(&uris);
-       if (error)
-               return error;
-
-       found = find_rrdp_uri(uris, uri);
-       if (found == NULL) {
-               *result = RRDP_URI_NOTFOUND;
-               return 0;
-       }
-
-       if (strcmp(session_id, found->data.session_id) != 0) {
-               *result = RRDP_URI_DIFF_SESSION;
-               return 0;
-       }
-
-       if (serial != found->data.serial) {
-               *result = RRDP_URI_DIFF_SERIAL;
-               return 0;
-       }
-
-       *result = RRDP_URI_EQUAL;
-       return 0;
-}
-
-int
-db_rrdp_uris_update(char const *uri, char const *session_id,
-    unsigned long serial, rrdp_req_status_t req_status,
-    struct visited_uris *visited_uris)
-{
-       struct db_rrdp_uri *uris;
-       struct uris_table *db_uri;
-       int error;
-
-       uris = NULL;
-       error = get_thread_rrdp_uris(&uris);
-       if (error)
-               return error;
-
-       db_uri = NULL;
-       error = uris_table_create(uri, session_id, serial, req_status, &db_uri);
-       if (error)
-               return error;
-
-       /* Ownership transfered */
-       db_uri->visited_uris = visited_uris;
-
-       add_rrdp_uri(uris, db_uri);
-
-       return 0;
-}
-
-int
-db_rrdp_uris_get_serial(char const *uri, unsigned long *serial)
-{
-       struct db_rrdp_uri *uris;
-       struct uris_table *found;
-       int error;
-
-       uris = NULL;
-       error = get_thread_rrdp_uris(&uris);
-       if (error)
-               return error;
-
-       RET_NOT_FOUND_URI(uris, uri, found)
-       *serial = found->data.serial;
-       return 0;
-}
-
-int
-db_rrdp_uris_get_last_update(char const *uri, long *date)
-{
-       struct db_rrdp_uri *uris;
-       struct uris_table *found;
-       int error;
-
-       uris = NULL;
-       error = get_thread_rrdp_uris(&uris);
-       if (error)
-               return error;
-
-       RET_NOT_FOUND_URI(uris, uri, found)
-       *date = found->last_update;
-       return 0;
-}
-
-/* Set the last update to now */
-int
-db_rrdp_uris_set_last_update(char const *uri)
-{
-       struct db_rrdp_uri *uris;
-       struct uris_table *found;
-       time_t now;
-       int error;
-
-       uris = NULL;
-       error = get_thread_rrdp_uris(&uris);
-       if (error)
-               return error;
-
-       RET_NOT_FOUND_URI(uris, uri, found)
-
-       now = 0;
-       error = get_current_time(&now);
-       if (error)
-               return error;
-
-       found->last_update = (long)now;
-       return 0;
-}
-
-int
-db_rrdp_uris_get_request_status(char const *uri, rrdp_req_status_t *result)
-{
-       struct db_rrdp_uri *uris;
-       struct uris_table *found;
-       int error;
-
-       uris = NULL;
-       error = get_thread_rrdp_uris(&uris);
-       if (error)
-               return error;
-
-       RET_NOT_FOUND_URI(uris, uri, found)
-       *result = found->request_status;
-       return 0;
-}
-
-int
-db_rrdp_uris_set_request_status(char const *uri, rrdp_req_status_t value)
-{
-       struct db_rrdp_uri *uris;
-       struct uris_table *found;
-       int error;
-
-       uris = NULL;
-       error = get_thread_rrdp_uris(&uris);
-       if (error)
-               return error;
-
-       RET_NOT_FOUND_URI(uris, uri, found)
-       found->request_status = value;
-       return 0;
-}
-
-int
-db_rrdp_uris_set_all_unvisited(void)
-{
-       struct db_rrdp_uri *uris;
-       struct uris_table *uri_node, *uri_tmp;
-       int error;
-
-       uris = NULL;
-       error = get_thread_rrdp_uris(&uris);
-       if (error)
-               return error;
-
-       HASH_ITER(hh, uris->table, uri_node, uri_tmp)
-               uri_node->request_status = RRDP_URI_REQ_UNVISITED;
-
-       return 0;
-}
-
-/*
- * Returns a pointer (set in @result) to the visited_uris of the current
- * thread.
- */
-int
-db_rrdp_uris_get_visited_uris(char const *uri, struct visited_uris **result)
-{
-       struct db_rrdp_uri *uris;
-       struct uris_table *found;
-       int error;
-
-       uris = NULL;
-       error = get_thread_rrdp_uris(&uris);
-       if (error)
-               return error;
-
-       RET_NOT_FOUND_URI(uris, uri, found)
-       *result = found->visited_uris;
-       return 0;
-}
-
-int
-db_rrdp_uris_remove_all_local(struct db_rrdp_uri *uris, char const *workspace)
-{
-       struct uris_table *uri_node, *uri_tmp;
-       int error;
-
-       /* Remove each 'visited_uris' from all the table */
-       HASH_ITER(hh, uris->table, uri_node, uri_tmp) {
-               error = visited_uris_delete_local(uri_node->visited_uris,
-                   workspace);
-               if (error)
-                       return error;
-       }
-
-       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;
-}
diff --git a/src/rrdp/db/db_rrdp_uris.h b/src/rrdp/db/db_rrdp_uris.h
deleted file mode 100644 (file)
index 63ac806..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef SRC_RRDP_DB_DB_RRDP_URIS_H_
-#define SRC_RRDP_DB_DB_RRDP_URIS_H_
-
-#include <stdbool.h>
-#include "rrdp/rrdp_objects.h"
-#include "visited_uris.h"
-
-typedef enum {
-       RRDP_URI_REQ_ERROR,
-       RRDP_URI_REQ_UNVISITED,
-       RRDP_URI_REQ_VISITED,
-} rrdp_req_status_t;
-
-/*
- * RRDP URI fetched from 'rpkiNotify' OID at a CA certificate, each TAL thread
- * may have a reference to one of these (it holds information such as update
- * notification URI, session ID, serial, visited mft uris).
- */
-struct db_rrdp_uri;
-
-int db_rrdp_uris_create(struct db_rrdp_uri **);
-void db_rrdp_uris_destroy(struct db_rrdp_uri *);
-
-int db_rrdp_uris_cmp(char const *, char const *, unsigned long,
-    rrdp_uri_cmp_result_t *);
-int db_rrdp_uris_update(char const *, char const *session_id, unsigned long,
-    rrdp_req_status_t, struct visited_uris *);
-int db_rrdp_uris_get_serial(char const *, unsigned long *);
-
-int db_rrdp_uris_get_last_update(char const *, long *);
-int db_rrdp_uris_set_last_update(char const *);
-
-int db_rrdp_uris_get_request_status(char const *, rrdp_req_status_t *);
-int db_rrdp_uris_set_request_status(char const *, rrdp_req_status_t);
-int db_rrdp_uris_set_all_unvisited(void);
-
-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 *);
-
-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_ */
diff --git a/src/rrdp/delta.c b/src/rrdp/delta.c
new file mode 100644 (file)
index 0000000..3b93e62
--- /dev/null
@@ -0,0 +1,145 @@
+#include "rrdp/delta.h"
+
+#include "common.h"
+#include "log.h"
+#include "thread_var.h"
+#include "http/http.h"
+#include "xml/relax_ng.h"
+#include "rrdp/snapshot.h"
+
+/* Context while reading a delta */
+struct rdr_delta_ctx {
+       /* Parent data to validate session ID */
+       struct rrdp_notification *notification;
+       /* Current serial loaded from update notification deltas list */
+       unsigned long expected_serial;
+};
+
+static int
+parse_withdraw_tag(xmlTextReaderPtr reader, struct rrdp_notification *notif,
+    struct rrdp_file_metadata *meta)
+{
+       int error;
+
+       error = parse_caged_uri_attribute(reader, notif, meta);
+       if (error)
+               return error;
+       return parse_hash_attribute(reader, true, meta);
+}
+
+/*
+ * This function will call 'xmlTextReaderRead' so there's no need to expect any
+ * other type at the caller.
+ */
+static int
+handle_withdraw_tag(xmlTextReaderPtr reader, struct rrdp_notification *notif)
+{
+       struct rrdp_file_metadata meta;
+       int error;
+
+       rrdp_file_metadata_init(&meta);
+
+       error = parse_withdraw_tag(reader, notif, &meta);
+       if (error)
+               goto end;
+
+       error = rrdp_file_metadata_validate_hash(&meta);
+       if (error)
+               goto end;
+
+       error = delete_dir_recursive_bottom_up(uri_get_local(meta.uri));
+
+end:   rrdp_file_metadata_cleanup(&meta);
+       return error;
+}
+
+static int
+xml_read_delta(xmlTextReaderPtr reader, void *arg)
+{
+       static const xmlChar *PUBLISH = BAD_CAST "publish";
+       static const xmlChar *WITHDRAW = BAD_CAST "withdraw";
+       static const xmlChar *DELTA = BAD_CAST "delta";
+
+       struct rdr_delta_ctx *ctx;
+       xmlChar const *name;
+       struct rrdp_session expected;
+
+       if (xmlTextReaderNodeType(reader) != XML_READER_TYPE_ELEMENT)
+               return 0;
+
+       ctx = arg;
+       name = xmlTextReaderConstLocalName(reader);
+
+       if (xmlStrEqual(name, PUBLISH))
+               return handle_publish_tag(reader, ctx->notification);
+       if (xmlStrEqual(name, WITHDRAW))
+               return handle_withdraw_tag(reader, ctx->notification);
+       if (xmlStrEqual(name, DELTA)) {
+               expected.id = ctx->notification->session.id;
+               expected.serial = ctx->expected_serial;
+               return validate_header_tag(reader, &expected);
+       }
+
+       return pr_val_err("Unexpected '%s' element", name);
+}
+
+/* TODO (aaaa) Remember to delete snapshots and deltas at some point */
+static int
+process_delta(struct rrdp_notification_delta *deltas,
+    struct rrdp_notification *notification)
+{
+       struct rpki_uri *uri;
+       struct rdr_delta_ctx ctx;
+       int error;
+
+       uri = deltas->meta.uri;
+
+       pr_val_debug("RRDP Delta '%s' {", uri_val_get_printable(uri));
+       fnstack_push_uri(uri);
+
+       error = http_get(uri, -1);
+       if (error)
+               goto pop;
+
+       error = rrdp_file_metadata_validate_hash(&deltas->meta);
+       if (error)
+               goto pop;
+
+       ctx.notification = notification;
+       ctx.expected_serial = deltas->serial;
+       error = relax_ng_parse(uri, xml_read_delta, &ctx);
+
+pop:   fnstack_pop();
+       pr_val_debug("}");
+       return error;
+}
+
+int
+rrdp_process_deltas(struct rrdp_notification *old,
+    struct rrdp_notification *new)
+{
+       unsigned long from;
+       unsigned long to;
+       size_t start;
+       size_t d;
+
+       if (new->deltas_list.len == 0) {
+               pr_val_warn("There's no delta list to process.");
+               goto snapshot;
+       }
+
+       from = old->session.serial;
+       to = new->session.serial;
+       pr_val_debug("Getting RRDP deltas from serial %lu to %lu.", from, to);
+       start = new->deltas_list.len - (to - from);
+       for (d = start; d < new->deltas_list.len; d++) {
+               if (process_delta(&new->deltas_list.array[d], new) != 0)
+                       goto snapshot;
+       }
+
+       return 0;
+
+snapshot:
+       pr_val_debug("Delta update failed; trying snapshot.");
+       return rrdp_parse_snapshot(new);
+}
diff --git a/src/rrdp/delta.h b/src/rrdp/delta.h
new file mode 100644 (file)
index 0000000..9dc2538
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef SRC_RRDP_DELTA_H_
+#define SRC_RRDP_DELTA_H_
+
+#include "rrdp/types.h"
+
+int rrdp_process_deltas(struct rrdp_notification *, struct rrdp_notification *);
+
+#endif /* SRC_RRDP_DELTA_H_ */
diff --git a/src/rrdp/notification.c b/src/rrdp/notification.c
new file mode 100644 (file)
index 0000000..88b96da
--- /dev/null
@@ -0,0 +1,177 @@
+#include "rrdp/notification.h"
+
+#include <sys/types.h> /* stat() */
+#include <sys/stat.h> /* stat() */
+#include <unistd.h> /* stat() */
+
+#include "file.h"
+#include "http/http.h"
+#include "xml/relax_ng.h"
+
+static int
+parse_notification_snapshot(xmlTextReaderPtr reader,
+    struct rrdp_file_metadata *snapshot)
+{
+       int error;
+
+       error = parse_simple_uri_attribute(reader, snapshot);
+       if (error)
+               return error;
+       error = parse_hash_attribute(reader, true, snapshot);
+       if (error)
+               uri_refput(snapshot->uri);
+
+       return error;
+}
+
+static int
+parse_notification_delta(xmlTextReaderPtr reader,
+    struct rrdp_notification_deltas *deltas)
+{
+       struct rrdp_notification_delta delta;
+       int error;
+
+       error = xml_parse_long(reader, "serial", &delta.serial);
+       if (error)
+               return error;
+       error = parse_simple_uri_attribute(reader, &delta.meta);
+       if (error)
+               return error;
+       error = parse_hash_attribute(reader, true, &delta.meta);
+       if (error) {
+               uri_refput(delta.meta.uri);
+               return error;
+       }
+
+       error = rrdp_notification_deltas_add(deltas, &delta);
+       if (error)
+               rrdp_file_metadata_cleanup(&delta.meta);
+
+       return error;
+}
+
+static int
+xml_read_notification(xmlTextReaderPtr reader, void *arg)
+{
+       static const xmlChar *NOTIFICATION = BAD_CAST "notification";
+       static const xmlChar *SNAPSHOT = BAD_CAST "snapshot";
+       static const xmlChar *DELTA = BAD_CAST "delta";
+
+       struct rrdp_notification *notification;
+       xmlChar const *name;
+
+       if (xmlTextReaderNodeType(reader) != XML_READER_TYPE_ELEMENT)
+               return 0; /* Meh */
+
+       notification = arg;
+       name = xmlTextReaderConstLocalName(reader);
+
+       if (xmlStrEqual(name, NOTIFICATION))
+               return parse_header_tag(reader, &notification->session);
+       if (xmlStrEqual(name, SNAPSHOT))
+               return parse_notification_snapshot(reader,
+                   &notification->snapshot);
+       if (xmlStrEqual(name, DELTA))
+               return parse_notification_delta(reader,
+                   &notification->deltas_list);
+
+       return pr_val_err("Unexpected '%s' element", name);
+}
+
+static int
+swap_until_sorted(struct rrdp_notification_delta *deltas, unsigned int i,
+    unsigned long min, unsigned long max)
+{
+       unsigned int target_slot;
+       struct rrdp_notification_delta tmp;
+
+       while (true) {
+               if (deltas[i].serial < min || max < deltas[i].serial) {
+                       return pr_val_err("Deltas: Serial '%lu' is out of bounds. (min:%lu, max:%lu)",
+                           deltas[i].serial, min, max);
+               }
+
+               target_slot = deltas[i].serial - min;
+               if (i == target_slot)
+                       return 0;
+               if (deltas[target_slot].serial == deltas[i].serial) {
+                       return pr_val_err("Deltas: Serial '%lu' is not unique.",
+                           deltas[i].serial);
+               }
+
+               /* Simple swap */
+               tmp = deltas[target_slot];
+               deltas[target_slot] = deltas[i];
+               deltas[i] = tmp;
+       }
+}
+
+static int
+deltas_head_sort(struct rrdp_notification_deltas *deltas,
+    unsigned long max_serial)
+{
+       unsigned long min_serial;
+       struct rrdp_notification_delta *cursor;
+       array_index i;
+       int error;
+
+       if (max_serial + 1 < deltas->len)
+               return pr_val_err("Deltas: Too many deltas (%zu) for serial %lu. (Negative serials not implemented.)",
+                   deltas->len, max_serial);
+
+       min_serial = max_serial + 1 - deltas->len;
+
+       ARRAYLIST_FOREACH(deltas, cursor, i) {
+               error = swap_until_sorted(deltas->array, i, min_serial,
+                   max_serial);
+               if (error)
+                       return error;
+       }
+
+       return 0;
+}
+
+static int
+read_notification(struct rrdp_notification *notification)
+{
+       int error;
+
+       error = relax_ng_parse(notification->uri, xml_read_notification,
+           notification);
+       if (error)
+               return error;
+
+       return deltas_head_sort(&notification->deltas_list,
+           notification->session.serial);
+}
+
+/*
+ * Download Update Notification file from @uri, and return its contents in
+ * @old and @new. (@old is the already existing notification, @new is the
+ * downloaded one.)
+ *
+ * On success, @old might not be populated, @new always will.
+ *
+ * Zero if the notification was successfully downloaded, nonzero otherwise.
+ * (Note, ENOTCHANGED is not an error in this case.)
+ */
+int
+rrdp_parse_notification(struct rrdp_notification *old,
+    struct rrdp_notification *new)
+{
+       long ims;
+       int error;
+
+       ims = file_get_modification_time(uri_get_local(old->uri));
+
+       if (ims != -1) /* Approx. "file exists and readable?" */ {
+               if (read_notification(old) != 0)
+                       pr_val_warn("Old Update Notification file exists, but I can't read it. Ignoring.");
+       }
+
+       error = http_get(new->uri, ims);
+       if (error)
+               return error;
+
+       return read_notification(new);
+}
diff --git a/src/rrdp/notification.h b/src/rrdp/notification.h
new file mode 100644 (file)
index 0000000..15f58ef
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef SRC_RRDP_NOTIFICATION_H_
+#define SRC_RRDP_NOTIFICATION_H_
+
+#include "rrdp/types.h"
+
+int rrdp_parse_notification(struct rrdp_notification *,
+    struct rrdp_notification *);
+
+#endif /* SRC_RRDP_NOTIFICATION_H_ */
diff --git a/src/rrdp/rrdp.c b/src/rrdp/rrdp.c
new file mode 100644 (file)
index 0000000..0c7d065
--- /dev/null
@@ -0,0 +1,62 @@
+#include "rrdp/rrdp.h"
+
+#include "log.h"
+#include "rpp/rpp_dl_status.h"
+#include "thread_var.h"
+#include "rrdp/types.h"
+#include "rrdp/delta.h"
+#include "rrdp/notification.h"
+#include "rrdp/snapshot.h"
+
+/*
+ * RRDP entry point.
+ * Downloads the Update Notification file pointed by @guri. If there are
+ * changes, downloads and explodes the snapshot or the new deltas.
+ *
+ * Returns zero if our cached version of the repository is now up-to-date
+ * (regardless of whether it was downloaded or not), nonzero otherwise.
+ */
+int
+rrdp_update(struct rpki_uri *uri)
+{
+       struct rrdp_notification old, new;
+       int error;
+
+       pr_val_debug("RRDP Notification '%s' {", uri_val_get_printable(uri));
+       fnstack_push_uri(uri);
+
+       /* Avoid multiple identical requests in the same cycle */
+       switch (rdsdb_get(uri)) {
+       case RDS_NOT_YET:
+               break;
+       case RDS_SUCCESS:
+               pr_val_debug("This RPP was already successfully updated in the current validation cycle.");
+               error = 0;
+               goto end;
+       case RDS_ERROR:
+               pr_val_err("This RPP was already unsuccessfully updated in the current validation cycle; not retrying.");
+               error = -EPERM;
+               goto end;
+       }
+
+       rrdp_notification_init(&old, uri);
+       rrdp_notification_init(&new, uri);
+
+       error = rrdp_parse_notification(&old, &new);
+       if (error)
+               goto cleanup;
+
+       if (old.session.id == NULL || strcmp(old.session.id, new.session.id) != 0)
+               error = rrdp_parse_snapshot(&new);
+       else if (old.session.serial != new.session.serial)
+               error = rrdp_process_deltas(&old, &new);
+
+cleanup:
+       rrdp_notification_cleanup(&old);
+       rrdp_notification_cleanup(&new);
+       rdsdb_set(uri, error);
+end:
+       fnstack_pop();
+       pr_val_debug("}");
+       return error;
+}
diff --git a/src/rrdp/rrdp.h b/src/rrdp/rrdp.h
new file mode 100644 (file)
index 0000000..cb006f5
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef SRC_RRDP_RRDP_H_
+#define SRC_RRDP_RRDP_H_
+
+#include "types/uri.h"
+
+/*
+ * TODO (aaaa)
+ *
+   When the Relying Party downloads an Update Notification File, it MUST
+   verify the file format and validation steps described in
+   Section 3.5.1.3.  If this verification fails, the file MUST be
+   rejected and RRDP cannot be used.  See Section 3.4.5 for
+   considerations.
+ */
+
+int rrdp_update(struct rpki_uri *);
+
+#endif /* SRC_RRDP_RRDP_H_ */
diff --git a/src/rrdp/rrdp_loader.c b/src/rrdp/rrdp_loader.c
deleted file mode 100644 (file)
index ea68709..0000000
+++ /dev/null
@@ -1,302 +0,0 @@
-#include "rrdp_loader.h"
-
-#include "rrdp/db/db_rrdp_uris.h"
-#include "rrdp/rrdp_objects.h"
-#include "rrdp/rrdp_parser.h"
-#include "rsync/rsync.h"
-#include "common.h"
-#include "config.h"
-#include "log.h"
-#include "reqs_errors.h"
-#include "thread_var.h"
-#include "visited_uris.h"
-
-/* Fetch and process the deltas from the @notification */
-static int
-process_diff_serial(struct update_notification *notification,
-    bool log_operation, struct visited_uris **visited)
-{
-       unsigned long serial;
-       int error;
-
-       error = db_rrdp_uris_get_serial(notification->uri, &serial);
-       if (error)
-               return error;
-
-       /* Work with the existent visited uris */
-       error = db_rrdp_uris_get_visited_uris(notification->uri, visited);
-       if (error)
-               return error;
-
-       return rrdp_process_deltas(notification, serial, *visited,
-           log_operation);
-}
-
-/* Fetch and process the snapshot from the @notification */
-static int
-process_snapshot(struct update_notification *notification, bool log_operation,
-    struct visited_uris **visited)
-{
-       struct visited_uris *tmp;
-       int error;
-
-       /* Use a new allocated visited_uris struct */
-       error = visited_uris_create(&tmp);
-       if (error)
-               return error;
-
-       error = rrdp_parse_snapshot(notification, tmp, log_operation);
-       if (error) {
-               visited_uris_refput(tmp);
-               return error;
-       }
-
-       *visited = tmp;
-       return 0;
-}
-
-static int
-remove_rrdp_uri_files(char const *notification_uri)
-{
-       struct visited_uris *tmp;
-       char const *workspace;
-       int error;
-
-       /* Work with the existent visited uris */
-       error = db_rrdp_uris_get_visited_uris(notification_uri, &tmp);
-       if (error)
-               return error;
-
-       workspace = db_rrdp_uris_workspace_get();
-
-       return visited_uris_delete_local(tmp, workspace);
-}
-
-/* Mark the URI as errored with dummy data, so it won't be requested again */
-static int
-mark_rrdp_uri_request_err(char const *notification_uri)
-{
-       struct visited_uris *tmp;
-       int error;
-
-       pr_val_debug("RRDP data of '%s' won't be requested again during this cycle due to previous error.",
-           notification_uri);
-
-       error = visited_uris_create(&tmp);
-       if (error)
-               return error;
-
-       error = db_rrdp_uris_update(notification_uri, "", 0,
-           RRDP_URI_REQ_ERROR, tmp);
-       if (error) {
-               visited_uris_refput(tmp);
-               return error;
-       }
-
-       return 0;
-}
-
-static int
-process_diff_session(struct update_notification *notification,
-    bool log_operation, struct visited_uris **visited)
-{
-       int error;
-
-       error = remove_rrdp_uri_files(notification->uri);
-       if (error)
-               return error;
-
-       return process_snapshot(notification, log_operation, visited);
-}
-
-static int
-__rrdp_load(struct rpki_uri *uri, bool force_snapshot, bool *data_updated)
-{
-       struct update_notification *upd_notification;
-       struct visited_uris *visited;
-       rrdp_req_status_t requested;
-       rrdp_uri_cmp_result_t res;
-       bool log_operation;
-       int error, upd_error;
-
-       (*data_updated) = false;
-
-       if (!config_get_http_enabled()) {
-               (*data_updated) = true;
-               return 0;
-       }
-
-       /* Avoid multiple requests on the same run */
-       requested = RRDP_URI_REQ_UNVISITED;
-       error = db_rrdp_uris_get_request_status(uri_get_global(uri),
-           &requested);
-       if (error && error != -ENOENT)
-               return error;
-
-       if (!force_snapshot) {
-               switch(requested) {
-               case RRDP_URI_REQ_VISITED:
-                       (*data_updated) = true;
-                       return 0;
-               case RRDP_URI_REQ_UNVISITED:
-                       break;
-               case RRDP_URI_REQ_ERROR:
-                       /* Log has been done before this call */
-                       return -EPERM;
-               }
-       } else {
-               if (requested != RRDP_URI_REQ_VISITED) {
-                       pr_val_info("Skipping RRDP snapshot reload");
-                       return -EINVAL;
-               }
-       }
-
-       log_operation = reqs_errors_log_uri(uri_get_global(uri));
-       error = rrdp_parse_notification(uri, log_operation, force_snapshot,
-           &upd_notification);
-       if (error)
-               goto upd_end;
-
-       /* No updates at the file (yet), didn't pushed to fnstack */
-       if (upd_notification == NULL) {
-               pr_val_debug("No updates yet at '%s'.", uri_get_global(uri));
-               goto upd_end;
-       }
-
-       do {
-               /* Same flow as a session update */
-               if (force_snapshot) {
-                       error = process_diff_session(upd_notification,
-                           log_operation, &visited);
-                       if (error)
-                               goto upd_destroy;
-                       (*data_updated) = true;
-                       break;
-               }
-
-               error = db_rrdp_uris_cmp(uri_get_global(uri),
-                   upd_notification->global_data.session_id,
-                   upd_notification->global_data.serial,
-                   &res);
-               if (error)
-                       goto upd_destroy;
-
-               switch (res) {
-               case RRDP_URI_EQUAL:
-                       goto set_update;
-               case RRDP_URI_DIFF_SESSION:
-                       /* Delete the old session files */
-                       error = process_diff_session(upd_notification,
-                           log_operation, &visited);
-                       if (error)
-                               goto upd_destroy;
-                       (*data_updated) = true;
-                       break;
-               case RRDP_URI_DIFF_SERIAL:
-                       error = process_diff_serial(upd_notification,
-                           log_operation, &visited);
-                       if (!error) {
-                               visited_uris_refget(visited);
-                               (*data_updated) = true;
-                               break;
-                       }
-                       /* Something went wrong, use snapshot */
-                       pr_val_info("There was an error processing RRDP deltas, using the snapshot instead.");
-               case RRDP_URI_NOTFOUND:
-                       error = process_snapshot(upd_notification, log_operation,
-                           &visited);
-                       if (error)
-                               goto upd_destroy;
-                       (*data_updated) = true;
-                       break;
-               default:
-                       pr_crit("Unexpected RRDP URI comparison result");
-               }
-       } while (0);
-
-       /* Any update, and no error during the process, update db as well */
-       pr_val_debug("Updating local RRDP data of '%s' to:", uri_get_global(uri));
-       pr_val_debug("- Session ID: %s", upd_notification->global_data.session_id);
-       pr_val_debug("- Serial: %lu", upd_notification->global_data.serial);
-       error = db_rrdp_uris_update(uri_get_global(uri),
-           upd_notification->global_data.session_id,
-           upd_notification->global_data.serial,
-           RRDP_URI_REQ_VISITED,
-           visited);
-       if (error)
-               goto upd_destroy;
-
-set_update:
-       /* Set the last update to now */
-       pr_val_debug("Set last update of RRDP data of '%s' to now.",
-           uri_get_global(uri));
-       db_rrdp_uris_set_last_update(uri_get_global(uri));
-upd_destroy:
-       if (upd_notification != NULL) {
-               update_notification_destroy(upd_notification);
-               fnstack_pop(); /* Pop from rrdp_parse_notification */
-       }
-upd_end:
-       /* Just return on success */
-       if (!error) {
-               /* The repository URI is the notification file URI */
-               reqs_errors_rem_uri(uri_get_global(uri));
-               return 0;
-       }
-
-       /* Request failed, store the repository URI */
-       if (error == EREQFAILED) {
-               upd_error = reqs_errors_add_uri(uri_get_global(uri));
-               if (upd_error)
-                       return upd_error;
-       } else {
-               /* Reset RSYNC visited URIs, this may force the update */
-               /* TODO um, what? */
-               reset_downloaded();
-       }
-
-       upd_error = mark_rrdp_uri_request_err(uri_get_global(uri));
-       if (upd_error)
-               return upd_error;
-
-       return error;
-}
-
-/*
- * Try to get RRDP Update Notification file and process it accordingly.
- *
- * If there's an error that could lead to an inconsistent local repository
- * state, marks the @uri as error'd so that it won't be requested again during
- * the same validation cycle.
- *
- * If there are no errors, updates the local DB and marks the @uri as visited.
- *
- * If the @uri is being visited again, verify its previous visit state. If there
- * were no errors, just return success; otherwise, return error code -EPERM.
- *
- * @data_updated will be true if:
- * - Delta files were processed,
- * - Snapshot file was processed,
- * - or @uri was already visited at this cycle
- */
-int
-rrdp_load(struct rpki_uri *uri, bool *data_updated)
-{
-       return __rrdp_load(uri, false, data_updated);
-}
-
-/*
- * Force the processing of the snapshot. The update notification is requested
- * again, omitting the 'If-Modified-Since' header at the HTTP request.
- *
- * Shouldn't be called if @uri had a previous error or hasn't been requested,
- * still the check is done.
- */
-int
-rrdp_reload_snapshot(struct rpki_uri *uri)
-{
-       bool tmp;
-
-       tmp = false;
-       return __rrdp_load(uri, true, &tmp);
-}
diff --git a/src/rrdp/rrdp_loader.h b/src/rrdp/rrdp_loader.h
deleted file mode 100644 (file)
index 838e4fa..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef SRC_RRDP_RRDP_LOADER_H_
-#define SRC_RRDP_RRDP_LOADER_H_
-
-#include <stdbool.h>
-#include "types/uri.h"
-
-int rrdp_load(struct rpki_uri *, bool *);
-int rrdp_reload_snapshot(struct rpki_uri *);
-
-#endif /* SRC_RRDP_RRDP_LOADER_H_ */
diff --git a/src/rrdp/rrdp_objects.c b/src/rrdp/rrdp_objects.c
deleted file mode 100644 (file)
index 7898c30..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-#include "rrdp_objects.h"
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include "log.h"
-
-DEFINE_ARRAY_LIST_FUNCTIONS(deltas_head, struct delta_head, )
-
-void
-global_data_init(struct global_data *data)
-{
-       data->session_id = NULL;
-}
-
-void
-global_data_cleanup(struct global_data *data)
-{
-       free(data->session_id);
-}
-
-void
-doc_data_init(struct doc_data *data)
-{
-       data->uri = NULL;
-       data->hash = NULL;
-       data->hash_len = 0;
-}
-
-void
-doc_data_cleanup(struct doc_data *data)
-{
-       free(data->hash);
-       free(data->uri);
-}
-
-/* Do the @cb to the delta head elements from @from_serial to @max_serial */
-int
-deltas_head_for_each(struct deltas_head *deltas, unsigned long max_serial,
-    unsigned long from_serial, delta_head_cb cb, void *arg)
-{
-       size_t index;
-       size_t from;
-       int error;
-
-       /* No elements, send error so that the snapshot is processed */
-       if (deltas->len == 0) {
-               pr_val_warn("There's no delta list to process.");
-               return -ENOENT;
-       }
-
-       pr_val_debug("Getting RRDP deltas from serial %lu to %lu.", from_serial,
-           max_serial);
-       from = deltas->len - (max_serial - from_serial);
-       for (index = from; index < deltas->len; index++) {
-               error = cb(&deltas->array[index], arg);
-               if (error)
-                       return error;
-       }
-
-       return 0;
-}
-
-static int
-swap_until_sorted(struct delta_head *deltas, unsigned int i,
-    unsigned long min, unsigned long max)
-{
-       unsigned int target_slot;
-       struct delta_head tmp;
-
-       while (true) {
-               if (deltas[i].serial < min || max < deltas[i].serial) {
-                       return pr_val_err("Deltas: Serial '%lu' is out of bounds. (min:%lu, max:%lu)",
-                           deltas[i].serial, min, max);
-               }
-
-               target_slot = deltas[i].serial - min;
-               if (i == target_slot)
-                       return 0;
-               if (deltas[target_slot].serial == deltas[i].serial) {
-                       return pr_val_err("Deltas: Serial '%lu' is not unique.",
-                           deltas[i].serial);
-               }
-
-               /* Simple swap */
-               tmp = deltas[target_slot];
-               deltas[target_slot] = deltas[i];
-               deltas[i] = tmp;
-       }
-}
-
-int
-deltas_head_sort(struct deltas_head *deltas, unsigned long max_serial)
-{
-       unsigned long min_serial;
-       struct delta_head *cursor;
-       array_index i;
-       int error;
-
-       if (max_serial + 1 < deltas->len)
-               return pr_val_err("Deltas: Too many deltas (%zu) for serial %lu. (Negative serials not implemented.)",
-                   deltas->len, max_serial);
-
-       min_serial = max_serial + 1 - deltas->len;
-
-       ARRAYLIST_FOREACH(deltas, cursor, i) {
-               error = swap_until_sorted(deltas->array, i, min_serial,
-                   max_serial);
-               if (error)
-                       return error;
-       }
-
-       return 0;
-}
-
-struct update_notification *
-update_notification_create(char const *uri)
-{
-       struct update_notification *result;
-
-       result = malloc(sizeof(struct update_notification));
-       if (result == NULL)
-               return NULL;
-
-       global_data_init(&result->global_data);
-       doc_data_init(&result->snapshot);
-       deltas_head_init(&result->deltas_list);
-       result->uri = strdup(uri);
-       if (result->uri == NULL) {
-               free(result);
-               return NULL;
-       }
-
-       return result;
-}
-
-static void
-delta_head_destroy(struct delta_head *delta)
-{
-       doc_data_cleanup(&delta->doc_data);
-}
-
-void
-update_notification_destroy(struct update_notification *file)
-{
-       doc_data_cleanup(&file->snapshot);
-       global_data_cleanup(&file->global_data);
-       deltas_head_cleanup(&file->deltas_list, delta_head_destroy);
-       free(file->uri);
-       free(file);
-}
-
-int
-snapshot_create(struct snapshot **file)
-{
-       struct snapshot *tmp;
-
-       tmp = malloc(sizeof(struct snapshot));
-       if (tmp == NULL)
-               return pr_enomem();
-
-       global_data_init(&tmp->global_data);
-
-       *file = tmp;
-       return 0;
-}
-
-void
-snapshot_destroy(struct snapshot *file)
-{
-       global_data_cleanup(&file->global_data);
-       free(file);
-}
-
-int
-delta_create(struct delta **file)
-{
-       struct delta *tmp;
-
-       tmp = malloc(sizeof(struct delta));
-       if (tmp == NULL)
-               return pr_enomem();
-
-       global_data_init(&tmp->global_data);
-
-       *file = tmp;
-       return 0;
-}
-
-void
-delta_destroy(struct delta *file)
-{
-       global_data_cleanup(&file->global_data);
-       free(file);
-}
-
-int
-publish_create(struct publish **file)
-{
-       struct publish *tmp;
-
-       tmp = malloc(sizeof(struct publish));
-       if (tmp == NULL)
-               return pr_enomem();
-
-       doc_data_init(&tmp->doc_data);
-       tmp->content = NULL;
-       tmp->content_len = 0;
-
-       *file = tmp;
-       return 0;
-}
-
-void
-publish_destroy(struct publish *file)
-{
-       doc_data_cleanup(&file->doc_data);
-       free(file->content);
-       free(file);
-}
-
-int
-withdraw_create(struct withdraw **file)
-{
-       struct withdraw *tmp;
-
-       tmp = malloc(sizeof(struct withdraw));
-       if (tmp == NULL)
-               return pr_enomem();
-
-       doc_data_init(&tmp->doc_data);
-
-       *file = tmp;
-       return 0;
-}
-
-void
-withdraw_destroy(struct withdraw *file)
-{
-       doc_data_cleanup(&file->doc_data);
-       free(file);
-}
diff --git a/src/rrdp/rrdp_objects.h b/src/rrdp/rrdp_objects.h
deleted file mode 100644 (file)
index b34970b..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-#ifndef SRC_RRDP_RRDP_OBJECTS_H_
-#define SRC_RRDP_RRDP_OBJECTS_H_
-
-#include <stddef.h>
-#include <stdbool.h>
-#include "data_structure/array_list.h"
-
-/* Possible results for an RRDP URI comparison */
-typedef enum {
-       /* The URI exists and has the same session ID and serial */
-       RRDP_URI_EQUAL,
-
-       /* The URI exists but has distinct serial */
-       RRDP_URI_DIFF_SERIAL,
-
-       /* The URI exists but has distinct session ID */
-       RRDP_URI_DIFF_SESSION,
-
-       /* The URI doesn't exists */
-       RRDP_URI_NOTFOUND,
-} rrdp_uri_cmp_result_t;
-
-/* Global RRDP files data */
-struct global_data {
-       char *session_id;
-       unsigned long serial;
-};
-
-/* Specific RRDP files data, in some cases the hash can be omitted */
-struct doc_data {
-       char *uri;
-       unsigned char *hash;
-       size_t hash_len;
-};
-
-/* Represents a <publish> element */
-struct publish {
-       struct doc_data doc_data;
-       unsigned char *content;
-       size_t content_len;
-};
-
-/* Represents a <withdraw> element */
-struct withdraw {
-       struct doc_data doc_data;
-};
-
-/*
- * Delta file content.
- * Publish/withdraw list aren't remember, they are processed ASAP.
- */
-struct delta {
-       struct global_data global_data;
-};
-
-/*
- * Snapshot file content
- * Publish list isn't remember, is processed ASAP.
- */
-struct snapshot {
-       struct global_data global_data;
-};
-
-/* Delta element located at an update notification file */
-struct delta_head {
-       /*
-        * TODO this is not an RFC 1982 serial. It's supposed to be unbounded,
-        * so we should probably handle it as a string.
-        */
-       unsigned long serial;
-       struct doc_data doc_data;
-};
-
-/* List of deltas inside an update notification file */
-DEFINE_ARRAY_LIST_STRUCT(deltas_head, struct delta_head);
-DECLARE_ARRAY_LIST_FUNCTIONS(deltas_head, struct delta_head)
-
-/* Update notification file content and location URI */
-struct update_notification {
-       struct global_data global_data;
-       struct doc_data snapshot;
-       struct deltas_head deltas_list;
-       char *uri;
-};
-
-void global_data_init(struct global_data *);
-void global_data_cleanup(struct global_data *);
-
-void doc_data_init(struct doc_data *);
-void doc_data_cleanup(struct doc_data *);
-
-struct update_notification *update_notification_create(char const *);
-void update_notification_destroy(struct update_notification *);
-
-typedef int (*delta_head_cb)(struct delta_head *, void *);
-int deltas_head_for_each(struct deltas_head *, unsigned long, unsigned long,
-    delta_head_cb, void *);
-int deltas_head_sort(struct deltas_head *, unsigned long);
-
-int snapshot_create(struct snapshot **);
-void snapshot_destroy(struct snapshot *);
-
-int delta_create(struct delta **);
-void delta_destroy(struct delta *);
-
-int publish_create(struct publish **);
-void publish_destroy(struct publish *);
-
-int withdraw_create(struct withdraw **);
-void withdraw_destroy(struct withdraw *);
-
-#endif /* SRC_RRDP_RRDP_OBJECTS_H_ */
diff --git a/src/rrdp/rrdp_parser.c b/src/rrdp/rrdp_parser.c
deleted file mode 100644 (file)
index 46808fa..0000000
+++ /dev/null
@@ -1,1033 +0,0 @@
-#include "rrdp_parser.h"
-
-#include <libxml/xmlreader.h>
-#include <openssl/evp.h>
-#include <sys/stat.h>
-#include <ctype.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "rrdp/db/db_rrdp_uris.h"
-#include "crypto/base64.h"
-#include "crypto/hash.h"
-#include "http/http.h"
-#include "xml/relax_ng.h"
-#include "common.h"
-#include "file.h"
-#include "log.h"
-#include "thread_var.h"
-
-/* XML Common Namespace of files */
-#define RRDP_NAMESPACE         "http://www.ripe.net/rpki/rrdp"
-
-/* XML Elements */
-#define RRDP_ELEM_NOTIFICATION "notification"
-#define RRDP_ELEM_SNAPSHOT     "snapshot"
-#define RRDP_ELEM_DELTA                "delta"
-#define RRDP_ELEM_PUBLISH      "publish"
-#define RRDP_ELEM_WITHDRAW     "withdraw"
-
-/* XML Attributes */
-#define RRDP_ATTR_VERSION      "version"
-#define RRDP_ATTR_SESSION_ID   "session_id"
-#define RRDP_ATTR_SERIAL       "serial"
-#define RRDP_ATTR_URI          "uri"
-#define RRDP_ATTR_HASH         "hash"
-
-/* Context while reading a snapshot */
-struct rdr_snapshot_ctx {
-       /* Data being parsed */
-       struct snapshot *snapshot;
-       /* Parent data to validate session ID and serial */
-       struct update_notification *parent;
-       /* Visited URIs related to this thread */
-       struct visited_uris *visited_uris;
-};
-
-/* Context while reading a delta */
-struct rdr_delta_ctx {
-       /* Data being parsed */
-       struct delta *delta;
-       /* Parent data to validate session ID */
-       struct update_notification *parent;
-       /* Current serial loaded from update notification deltas list */
-       unsigned long expected_serial;
-       /* Visited URIs related to this thread */
-       struct visited_uris *visited_uris;
-};
-
-/* Args to send on update (snapshot/delta) files parsing */
-struct proc_upd_args {
-       struct update_notification *parent;
-       struct visited_uris *visited_uris;
-       bool log_operation;
-};
-
-static int
-add_mft_to_list(struct visited_uris *visited_uris, char const *uri)
-{
-       if (strcmp(".mft", strrchr(uri, '.')) != 0)
-               return 0;
-
-       return visited_uris_add(visited_uris, uri);
-}
-
-static int
-rem_mft_from_list(struct visited_uris *visited_uris, char const *uri)
-{
-       if (strcmp(".mft", strrchr(uri, '.')) != 0)
-               return 0;
-
-       return visited_uris_remove(visited_uris, uri);
-}
-
-static int
-download_file(struct rpki_uri *uri, long last_update, bool log_operation)
-{
-       int error;
-
-       if (last_update > 0)
-               error = http_download_file_with_ims(uri, last_update,
-                   log_operation);
-       else
-               error = http_download_file(uri, log_operation);
-
-       /*
-        * Since distinct files can be downloaded (notification, snapshot,
-        * delta) just return the error and let the caller to add only the
-        * update notification URI to the request errors DB.
-        */
-       if (error == -EREQFAILED)
-               return EREQFAILED;
-
-       /* Remember: positive values are expected */
-       return error;
-}
-
-/* Left trim @from, setting the result at @result pointer */
-static int
-ltrim(char *from, char **result, size_t *result_size)
-{
-       char *start;
-       size_t tmp_size;
-
-       start = from;
-       tmp_size = strlen(from);
-       while (isspace(*start)) {
-               start++;
-               tmp_size--;
-       }
-       if (*start == '\0')
-               return pr_val_err("Invalid base64 encoded string (seems to be empty or full of spaces).");
-
-       *result = start;
-       *result_size = tmp_size;
-       return 0;
-}
-
-/*
- * Get the base64 chars from @content and allocate to @out with lines no greater
- * than 65 chars (including line feed).
- *
- * Why? LibreSSL doesn't like lines greater than 80 chars, so use a common
- * length per line.
- */
-static int
-base64_sanitize(char *content, char **out)
-{
-#define BUF_SIZE 65
-       char *result;
-       char *tmp;
-       size_t original_size, new_size;
-       size_t offset, buf_len;
-       int error;
-
-       original_size = 0;
-       error = ltrim(content, &tmp, &original_size);
-       if (error)
-               return error;
-
-       if (original_size <= BUF_SIZE) {
-               result = strdup(content);
-               if (result == NULL)
-                       return pr_enomem();
-               *out = result;
-               return 0;
-       }
-
-       new_size = original_size + (original_size / BUF_SIZE);
-       result = malloc(new_size + 1);
-       if (result == NULL)
-               return pr_enomem();
-
-       offset = 0;
-       while (original_size > 0){
-               buf_len = original_size > BUF_SIZE ? BUF_SIZE : original_size;
-               memcpy(&result[offset], tmp, buf_len);
-               tmp += buf_len;
-               offset += buf_len;
-               original_size -= buf_len;
-
-               if (original_size <= 0)
-                       break;
-               result[offset] = '\n';
-               offset++;
-       }
-
-       /* Reallocate to exact size and add nul char */
-       if (offset != new_size + 1) {
-               tmp = realloc(result, offset + 1);
-               if (tmp == NULL) {
-                       free(result);
-                       return pr_enomem();
-               }
-               result = tmp;
-       }
-
-       result[offset] = '\0';
-       *out = result;
-       return 0;
-#undef BUF_SIZE
-}
-
-static int
-base64_read(char *content, unsigned char **out, size_t *out_len)
-{
-       BIO *encoded; /* base64 encoded. */
-       unsigned char *result;
-       char *sanitized;
-       size_t alloc_size;
-       size_t result_len;
-       int error;
-
-       sanitized = NULL;
-       error = base64_sanitize(content, &sanitized);
-       if (error)
-               return error;
-
-       encoded = BIO_new_mem_buf(sanitized, -1);
-       if (encoded == NULL) {
-               error = val_crypto_err("BIO_new_mem_buf() returned NULL");
-               goto release_sanitized;
-       }
-
-       alloc_size = EVP_DECODE_LENGTH(strlen(content));
-       result = malloc(alloc_size);
-       if (result == NULL) {
-               error = pr_enomem();
-               goto release_bio;
-       }
-
-       error = base64_decode(encoded, result, true, alloc_size, &result_len);
-       if (error)
-               goto release_result;
-
-       free(sanitized);
-       BIO_free(encoded);
-
-       *out = result;
-       (*out_len) = result_len;
-       return 0;
-release_result:
-       free(result);
-release_bio:
-       BIO_free(encoded);
-release_sanitized:
-       free(sanitized);
-       return error;
-}
-
-static int
-parse_string(xmlTextReaderPtr reader, char const *attr, char **result)
-{
-       xmlChar *xml_value;
-       char *tmp;
-
-       if (attr == NULL) {
-               xml_value = xmlTextReaderValue(reader);
-               if (xml_value == NULL)
-                       return pr_val_err("RRDP file: Couldn't find string content from '%s'",
-                           xmlTextReaderConstLocalName(reader));
-       } else {
-               xml_value = xmlTextReaderGetAttribute(reader, BAD_CAST attr);
-               if (xml_value == NULL)
-                       return pr_val_err("RRDP file: Couldn't find xml attribute '%s' from tag '%s'",
-                           attr, xmlTextReaderConstLocalName(reader));
-       }
-
-       tmp = malloc(xmlStrlen(xml_value) + 1);
-       if (tmp == NULL) {
-               xmlFree(xml_value);
-               return pr_enomem();
-       }
-
-       memcpy(tmp, xml_value, xmlStrlen(xml_value));
-       tmp[xmlStrlen(xml_value)] = '\0';
-       xmlFree(xml_value);
-
-       *result = tmp;
-       return 0;
-}
-
-static int
-parse_long(xmlTextReaderPtr reader, char const *attr, unsigned long *result)
-{
-       xmlChar *xml_value;
-       unsigned long tmp;
-
-       xml_value = xmlTextReaderGetAttribute(reader, BAD_CAST attr);
-       if (xml_value == NULL)
-               return pr_val_err("RRDP file: Couldn't find xml attribute '%s'",
-                   attr);
-
-       errno = 0;
-       tmp = strtoul((char *) xml_value, NULL, 10);
-       if (errno) {
-               xmlFree(xml_value);
-               pr_val_errno(errno, "RRDP file: Invalid long value '%s'",
-                   xml_value);
-               return -EINVAL;
-       }
-       xmlFree(xml_value);
-
-       (*result) = tmp;
-       return 0;
-}
-
-static int
-parse_hex_string(xmlTextReaderPtr reader, bool required, char const *attr,
-    unsigned char **result, size_t *result_len)
-{
-       xmlChar *xml_value;
-       unsigned char *tmp, *ptr;
-       char *xml_cur;
-       char buf[2];
-       size_t tmp_len;
-
-       xml_value = xmlTextReaderGetAttribute(reader, BAD_CAST attr);
-       if (xml_value == NULL)
-               return required ?
-                   pr_val_err("RRDP file: Couldn't find xml attribute '%s'", attr)
-                   : 0;
-
-       /* The rest of the checks are done at the schema */
-       if (xmlStrlen(xml_value) % 2 != 0) {
-               xmlFree(xml_value);
-               return pr_val_err("RRDP file: Attribute %s isn't a valid hex string",
-                   attr);
-       }
-
-       tmp_len = xmlStrlen(xml_value) / 2;
-       tmp = malloc(tmp_len);
-       if (tmp == NULL) {
-               xmlFree(xml_value);
-               return pr_enomem();
-       }
-       memset(tmp, 0, tmp_len);
-
-       ptr = tmp;
-       xml_cur = (char *) xml_value;
-       while (ptr - tmp < tmp_len) {
-               memcpy(buf, xml_cur, 2);
-               *ptr = strtol(buf, NULL, 16);
-               xml_cur+=2;
-               ptr++;
-       }
-       xmlFree(xml_value);
-
-       *result = tmp;
-       (*result_len) = tmp_len;
-       return 0;
-}
-
-static int
-validate_version(xmlTextReaderPtr reader, unsigned long expected)
-{
-       unsigned long version;
-       int error;
-
-       error = parse_long(reader, RRDP_ATTR_VERSION, &version);
-       if (error)
-               return error;
-
-       if (version != expected)
-               return pr_val_err("Invalid version, must be '%lu' and is '%lu'.",
-                   expected, version);
-
-       return 0;
-}
-
-/* @gdata elements are allocated */
-static int
-parse_global_data(xmlTextReaderPtr reader, struct global_data *gdata,
-    char const *expected_session, unsigned long expected_serial)
-{
-       char *session_id;
-       unsigned long serial;
-       int error;
-
-       /*
-        * The following rule appies to all files:
-        * - The XML namespace MUST be "http://www.ripe.net/rpki/rrdp".
-        * - The version attribute MUST be "1".
-        */
-       if (!xmlStrEqual(xmlTextReaderConstNamespaceUri(reader),
-           BAD_CAST RRDP_NAMESPACE))
-               return pr_val_err("Namespace isn't '%s', current value is '%s'",
-                   RRDP_NAMESPACE, xmlTextReaderConstNamespaceUri(reader));
-
-       error = validate_version(reader, 1);
-       if (error)
-               return error;
-
-       error = parse_string(reader, RRDP_ATTR_SESSION_ID, &session_id);
-       if (error)
-               return error;
-
-       serial = 0;
-       error = parse_long(reader, RRDP_ATTR_SERIAL, &serial);
-       if (error) {
-               free(session_id);
-               return error;
-       }
-
-       if (expected_session == NULL)
-               goto return_val; /* Error O is OK */
-
-       /*
-        * Positive error value means the file was successfully parsed but it
-        * has a logic error (in this case, session ID doesn't match parent's).
-        */
-       if (strcmp(expected_session, session_id) != 0) {
-               pr_val_info("File session id [%s] doesn't match parent's session id [%s]",
-                   expected_session, session_id);
-               error = EINVAL;
-               goto return_val;
-       }
-
-       /* ...and the serial must match to what's expected at the parent */
-       if (serial != expected_serial) {
-               pr_val_info("File serial '%lu' doesn't match expected serial '%lu'",
-                   serial, expected_serial);
-               error = EINVAL;
-       }
-
-return_val:
-       gdata->session_id = session_id;
-       gdata->serial = serial;
-       return error;
-}
-
-/* @data elements are allocated */
-static int
-parse_doc_data(xmlTextReaderPtr reader, bool parse_hash, bool hash_req,
-    struct doc_data *data)
-{
-       char *uri;
-       unsigned char *hash;
-       size_t hash_len;
-       int error;
-
-       uri = NULL;
-       hash = NULL;
-       hash_len = 0;
-
-       error = parse_string(reader, RRDP_ATTR_URI, &uri);
-       if (error)
-               return error;
-
-       if (!parse_hash)
-               goto end;
-
-       error = parse_hex_string(reader, hash_req, RRDP_ATTR_HASH, &hash,
-           &hash_len);
-       if (error) {
-               free(uri);
-               return error;
-       }
-end:
-       /* Function called just to do the validation */
-       if (data == NULL) {
-               free(hash);
-               free(uri);
-               return 0;
-       }
-       data->uri = uri;
-       data->hash = hash;
-       data->hash_len = hash_len;
-       return 0;
-}
-
-static int
-parse_publish(xmlTextReaderPtr reader, bool parse_hash, bool hash_required,
-    struct publish **publish)
-{
-       struct publish *tmp;
-       struct rpki_uri *uri;
-       char *base64_str;
-       int error;
-
-       error = publish_create(&tmp);
-       if (error)
-               return error;
-
-       error = parse_doc_data(reader, parse_hash, hash_required,
-           &tmp->doc_data);
-       if (error)
-               goto release_tmp;
-
-       /* Read the text */
-       if (xmlTextReaderRead(reader) != 1) {
-               error = pr_val_err("Couldn't read publish content of element '%s'",
-                   tmp->doc_data.uri);
-               goto release_tmp;
-       }
-
-       error = parse_string(reader, NULL, &base64_str);
-       if (error)
-               goto release_tmp;
-
-       error = base64_read(base64_str, &tmp->content, &tmp->content_len);
-       if (error)
-               goto release_base64;
-
-       /* rfc8181#section-2.2 but considering optional hash */
-       uri = NULL;
-       if (tmp->doc_data.hash_len > 0) {
-               /* Get the current file from the uri */
-               error = uri_create_rsync_str_rrdp(&uri, tmp->doc_data.uri,
-                   strlen(tmp->doc_data.uri));
-               if (error)
-                       goto release_base64;
-
-               error = hash_validate_file("sha256", uri, tmp->doc_data.hash,
-                   tmp->doc_data.hash_len);
-               uri_refput(uri);
-               if (error != 0) {
-                       pr_val_info("Hash of base64 decoded element from URI '%s' doesn't match <publish> element hash",
-                           tmp->doc_data.uri);
-                       error = EINVAL;
-                       goto release_base64;
-               }
-       }
-
-       free(base64_str);
-       *publish = tmp;
-       return 0;
-release_base64:
-       free(base64_str);
-release_tmp:
-       publish_destroy(tmp);
-       return error;
-}
-
-static int
-parse_withdraw(xmlTextReaderPtr reader, struct withdraw **withdraw)
-{
-       struct withdraw *tmp;
-       struct rpki_uri *uri;
-       int error;
-
-       error = withdraw_create(&tmp);
-       if (error)
-               return error;
-
-       error = parse_doc_data(reader, true, true, &tmp->doc_data);
-       if (error)
-               goto release_tmp;
-
-       /* rfc8181#section-2.2, get the file from the uri */
-       error = uri_create_rsync_str_rrdp(&uri, tmp->doc_data.uri,
-           strlen(tmp->doc_data.uri));
-       if (error)
-               goto release_tmp;
-
-       error = hash_validate_file("sha256", uri,
-           tmp->doc_data.hash, tmp->doc_data.hash_len);
-       if (error)
-               goto release_uri;
-
-       uri_refput(uri);
-       *withdraw = tmp;
-       return 0;
-release_uri:
-       uri_refput(uri);
-release_tmp:
-       withdraw_destroy(tmp);
-       return error;
-}
-
-static int
-write_from_uri(char const *location, unsigned char *content, size_t content_len,
-    struct visited_uris *visited_uris)
-{
-       struct rpki_uri *uri;
-       FILE *out;
-       size_t written;
-       int error;
-
-       /* rfc8181#section-2.2 must be an rsync URI */
-       error = uri_create_rsync_str_rrdp(&uri, location, strlen(location));
-       if (error)
-               return error;
-
-       error = create_dir_recursive(uri_get_local(uri));
-       if (error) {
-               uri_refput(uri);
-               return error;
-       }
-
-       error = file_write(uri_get_local(uri), &out);
-       if (error) {
-               uri_refput(uri);
-               return error;
-       }
-
-       written = fwrite(content, sizeof(unsigned char), content_len, out);
-       if (written != content_len) {
-               uri_refput(uri);
-               file_close(out);
-               return pr_val_err("Couldn't write bytes to file %s",
-                   uri_get_local(uri));
-       }
-
-       error = add_mft_to_list(visited_uris, uri_get_global(uri));
-       if (error) {
-               uri_refput(uri);
-               file_close(out);
-               return error;
-       }
-
-       uri_refput(uri);
-       file_close(out);
-       return 0;
-}
-
-/* Remove a local file and its directory tree (if empty) */
-static int
-delete_from_uri(struct rpki_uri *uri, struct visited_uris *visited_uris)
-{
-       int error;
-
-       if (visited_uris) {
-               error = rem_mft_from_list(visited_uris, uri_get_global(uri));
-               if (error)
-                       return error;
-       }
-
-       /* Delete parent dirs only if empty. */
-       return delete_dir_recursive_bottom_up(uri_get_local(uri));
-}
-
-static int
-__delete_from_uri(char const *location, struct visited_uris *visited_uris)
-{
-       struct rpki_uri *uri;
-       int error;
-
-       /* rfc8181#section-2.2 must be an rsync URI */
-       error = uri_create_rsync_str_rrdp(&uri, location, strlen(location));
-       if (error)
-               return error;
-
-       error = delete_from_uri(uri, visited_uris);
-
-       /* Error 0 is ok */
-       uri_refput(uri);
-       return error;
-}
-
-/*
- * This function will call 'xmlTextReaderRead' so there's no need to expect any
- * other type at the caller.
- */
-static int
-parse_publish_elem(xmlTextReaderPtr reader, bool parse_hash, bool hash_required,
-    struct visited_uris *visited_uris)
-{
-       struct publish *tmp;
-       int error;
-
-       tmp = NULL;
-       error = parse_publish(reader, parse_hash, hash_required, &tmp);
-       if (error)
-               return error;
-
-       error = write_from_uri(tmp->doc_data.uri, tmp->content,
-           tmp->content_len, visited_uris);
-       publish_destroy(tmp);
-       if (error)
-               return error;
-
-       return 0;
-}
-
-/*
- * This function will call 'xmlTextReaderRead' so there's no need to expect any
- * other type at the caller.
- */
-static int
-parse_withdraw_elem(xmlTextReaderPtr reader, struct visited_uris *visited_uris)
-{
-       struct withdraw *tmp;
-       int error;
-
-       error = parse_withdraw(reader, &tmp);
-       if (error)
-               return error;
-
-       error = __delete_from_uri(tmp->doc_data.uri, visited_uris);
-       withdraw_destroy(tmp);
-       if (error)
-               return error;
-
-       return 0;
-}
-
-static int
-parse_notification_delta(xmlTextReaderPtr reader,
-    struct update_notification *update)
-{
-       struct delta_head delta;
-       int error;
-
-       error = parse_long(reader, RRDP_ATTR_SERIAL, &delta.serial);
-       if (error)
-               return error;
-       error = parse_doc_data(reader, true, true, &delta.doc_data);
-       if (error)
-               return error;
-
-       error = deltas_head_add(&update->deltas_list, &delta);
-       if (error)
-               doc_data_cleanup(&delta.doc_data);
-
-       return error;
-}
-
-static int
-xml_read_notification(xmlTextReaderPtr reader, void *arg)
-{
-       struct update_notification *update = arg;
-       xmlChar const *name;
-
-       name = xmlTextReaderConstLocalName(reader);
-       switch (xmlTextReaderNodeType(reader)) {
-       case XML_READER_TYPE_ELEMENT:
-               if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_DELTA)) {
-                       return parse_notification_delta(reader, update);
-               } else if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_SNAPSHOT)) {
-                       return parse_doc_data(reader, true, true,
-                           &update->snapshot);
-               } else if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_NOTIFICATION)) {
-                       /* No need to validate session ID and serial */
-                       return parse_global_data(reader,
-                           &update->global_data, NULL, 0);
-               }
-
-               return pr_val_err("Unexpected '%s' element", name);
-
-       case XML_READER_TYPE_END_ELEMENT:
-               if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_NOTIFICATION))
-                       return deltas_head_sort(&update->deltas_list,
-                           update->global_data.serial);
-               break;
-       }
-
-       return 0;
-}
-
-static int
-parse_notification(struct rpki_uri *uri, struct update_notification **file)
-{
-       struct update_notification *result;
-       int error;
-
-       result = update_notification_create(uri_get_global(uri));
-       if (result == NULL)
-               return pr_enomem();
-
-       error = relax_ng_parse(uri_get_local(uri), xml_read_notification,
-           result);
-       if (error) {
-               update_notification_destroy(result);
-               return error;
-       }
-
-       *file = result;
-       return 0;
-}
-
-static int
-xml_read_snapshot(xmlTextReaderPtr reader, void *arg)
-{
-       struct rdr_snapshot_ctx *ctx = arg;
-       xmlReaderTypes type;
-       xmlChar const *name;
-       int error;
-
-       name = xmlTextReaderConstLocalName(reader);
-       type = xmlTextReaderNodeType(reader);
-       switch (type) {
-       case XML_READER_TYPE_ELEMENT:
-               if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_PUBLISH))
-                       error = parse_publish_elem(reader, false, false,
-                           ctx->visited_uris);
-               else if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_SNAPSHOT))
-                       error = parse_global_data(reader,
-                           &ctx->snapshot->global_data,
-                           ctx->parent->global_data.session_id,
-                           ctx->parent->global_data.serial);
-               else
-                       return pr_val_err("Unexpected '%s' element", name);
-
-               if (error)
-                       return error;
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static int
-parse_snapshot(struct rpki_uri *uri, struct proc_upd_args *args)
-{
-       struct rdr_snapshot_ctx ctx;
-       struct snapshot *snapshot;
-       int error;
-
-       fnstack_push_uri(uri);
-       /* Hash validation */
-       error = hash_validate_file("sha256", uri, args->parent->snapshot.hash,
-           args->parent->snapshot.hash_len);
-       if (error)
-               goto pop;
-
-       error = snapshot_create(&snapshot);
-       if (error)
-               goto pop;
-
-       ctx.snapshot = snapshot;
-       ctx.parent = args->parent;
-       ctx.visited_uris = args->visited_uris;
-       error = relax_ng_parse(uri_get_local(uri), xml_read_snapshot, &ctx);
-
-       /* Error 0 is ok */
-       snapshot_destroy(snapshot);
-pop:
-       fnstack_pop();
-       return error;
-}
-
-static int
-xml_read_delta(xmlTextReaderPtr reader, void *arg)
-{
-       struct rdr_delta_ctx *ctx = arg;
-       xmlReaderTypes type;
-       xmlChar const *name;
-       int error;
-
-       name = xmlTextReaderConstLocalName(reader);
-       type = xmlTextReaderNodeType(reader);
-       switch (type) {
-       case XML_READER_TYPE_ELEMENT:
-               if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_PUBLISH))
-                       error = parse_publish_elem(reader, true, false,
-                           ctx->visited_uris);
-               else if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_WITHDRAW))
-                       error = parse_withdraw_elem(reader, ctx->visited_uris);
-               else if (xmlStrEqual(name, BAD_CAST RRDP_ELEM_DELTA))
-                       error = parse_global_data(reader,
-                           &ctx->delta->global_data,
-                           ctx->parent->global_data.session_id,
-                           ctx->expected_serial);
-               else
-                       return pr_val_err("Unexpected '%s' element", name);
-
-               if (error)
-                       return error;
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static int
-parse_delta(struct rpki_uri *uri, struct delta_head *parents_data,
-    struct proc_upd_args *args)
-{
-       struct rdr_delta_ctx ctx;
-       struct delta *delta;
-       struct doc_data *expected_data;
-       int error;
-
-       expected_data = &parents_data->doc_data;
-
-       fnstack_push_uri(uri);
-       error = hash_validate_file("sha256", uri, expected_data->hash,
-           expected_data->hash_len);
-       if (error)
-               goto pop_fnstack;
-
-       error = delta_create(&delta);
-       if (error)
-               goto pop_fnstack;
-
-       ctx.delta = delta;
-       ctx.parent = args->parent;
-       ctx.visited_uris = args->visited_uris;
-       ctx.expected_serial = parents_data->serial;
-       error = relax_ng_parse(uri_get_local(uri), xml_read_delta, &ctx);
-
-       delta_destroy(delta);
-       /* Error 0 is ok */
-
-pop_fnstack:
-       fnstack_pop();
-       return error;
-}
-
-static int
-process_delta(struct delta_head *delta_head, void *arg)
-{
-       struct proc_upd_args *args = arg;
-       struct rpki_uri *uri;
-       struct doc_data *head_data;
-       int error;
-
-       head_data = &delta_head->doc_data;
-
-       pr_val_debug("Processing delta '%s'.", head_data->uri);
-       error = uri_create_https_str_rrdp(&uri, head_data->uri,
-           strlen(head_data->uri));
-       if (error)
-               return error;
-
-       error = download_file(uri, 0, args->log_operation);
-       if (error)
-               goto release_uri;
-
-       error = parse_delta(uri, delta_head, args);
-
-       delete_from_uri(uri, NULL);
-       /* Error 0 its ok */
-release_uri:
-       uri_refput(uri);
-       return error;
-}
-
-/*
- * Download from @uri and set result file contents to @result, the file name
- * is pushed into fnstack, so don't forget to do the pop when done working
- * with the file.
- *
- * If the server didn't sent the file, due to the validation of
- * 'If-Modified-Since' header, return 0 and set @result to NULL.
- *
- * Set @force to true to omit 'If-Modified-Since' header.
- */
-int
-rrdp_parse_notification(struct rpki_uri *uri, bool log_operation, bool force,
-    struct update_notification **result)
-{
-       long last_update;
-       int error, vis_err;
-
-       if (uri == NULL || uri_is_rsync(uri))
-               pr_crit("Wrong call, trying to parse a non HTTPS URI");
-
-       pr_val_debug("Processing notification '%s'.", uri_get_global(uri));
-       last_update = 0;
-       if (!force) {
-               error = db_rrdp_uris_get_last_update(uri_get_global(uri), &last_update);
-               if (error && error != -ENOENT)
-                       return error;
-       }
-
-       error = download_file(uri, last_update, log_operation);
-       if (error < 0)
-               return error;
-
-       /* Request error, stop processing to handle as such */
-       if (error == EREQFAILED)
-               return error;
-
-       /*
-        * Mark as visited, if it doesn't exists yet, there's no problem since
-        * this is probably the first time is visited (first run), so it will
-        * be marked as visited when the URI is stored at DB.
-        */
-       vis_err = db_rrdp_uris_set_request_status(uri_get_global(uri),
-           RRDP_URI_REQ_VISITED);
-       if (vis_err && vis_err != -ENOENT)
-               return pr_val_err("Couldn't mark '%s' as visited",
-                   uri_get_global(uri));
-
-       /* No updates yet */
-       if (error > 0) {
-               delete_from_uri(uri, NULL);
-               *result = NULL;
-               return 0;
-       }
-
-       fnstack_push_uri(uri);
-       error = parse_notification(uri, result);
-       delete_from_uri(uri, NULL);
-       if (error) {
-               fnstack_pop();
-               return error;
-       }
-
-       return 0;
-}
-
-int
-rrdp_parse_snapshot(struct update_notification *parent,
-    struct visited_uris *visited_uris, bool log_operation)
-{
-       struct proc_upd_args args;
-       struct rpki_uri *uri;
-       int error;
-
-       args.parent = parent;
-       args.visited_uris = visited_uris;
-
-       pr_val_debug("Processing snapshot '%s'.", parent->snapshot.uri);
-       error = uri_create_https_str_rrdp(&uri, parent->snapshot.uri,
-           strlen(parent->snapshot.uri));
-       if (error)
-               return error;
-
-       error = download_file(uri, 0, log_operation);
-       if (error)
-               goto release_uri;
-
-       error = parse_snapshot(uri, &args);
-
-       delete_from_uri(uri, NULL);
-       /* Error 0 is ok */
-release_uri:
-       uri_refput(uri);
-       return error;
-}
-
-int
-rrdp_process_deltas(struct update_notification *parent,
-    unsigned long cur_serial, struct visited_uris *visited_uris,
-    bool log_operation)
-{
-       struct proc_upd_args args;
-
-       args.parent = parent;
-       args.visited_uris = visited_uris;
-       args.log_operation = log_operation;
-
-       return deltas_head_for_each(&parent->deltas_list,
-           parent->global_data.serial, cur_serial, process_delta, &args);
-}
diff --git a/src/rrdp/rrdp_parser.h b/src/rrdp/rrdp_parser.h
deleted file mode 100644 (file)
index 3aff470..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef SRC_RRDP_RRDP_PARSER_H_
-#define SRC_RRDP_RRDP_PARSER_H_
-
-#include <stdbool.h>
-#include "types/uri.h"
-#include "rrdp/rrdp_objects.h"
-#include "visited_uris.h"
-
-int rrdp_parse_notification(struct rpki_uri *, bool, bool,
-    struct update_notification **);
-int rrdp_parse_snapshot(struct update_notification *, struct visited_uris *,
-    bool);
-
-int rrdp_process_deltas(struct update_notification *,
-    unsigned long serial, struct visited_uris *, bool);
-
-#endif /* SRC_RRDP_RRDP_PARSER_H_ */
diff --git a/src/rrdp/snapshot.c b/src/rrdp/snapshot.c
new file mode 100644 (file)
index 0000000..a1d883a
--- /dev/null
@@ -0,0 +1,55 @@
+#include "rrdp/snapshot.h"
+
+#include "thread_var.h"
+#include "http/http.h"
+#include "xml/relax_ng.h"
+
+static int
+xml_read_snapshot(xmlTextReaderPtr reader, void *arg)
+{
+       static xmlChar const *PUBLISH = BAD_CAST "publish";
+       static xmlChar const *SNAPSHOT = BAD_CAST "snapshot";
+       struct rrdp_notification *notif;
+       xmlChar const *name;
+
+       /* TODO (aaaa) probably make sure the directory is empty before exploding */
+
+       if (xmlTextReaderNodeType(reader) != XML_READER_TYPE_ELEMENT)
+               return 0;
+
+       notif = arg;
+       name = xmlTextReaderConstLocalName(reader);
+
+       if (xmlStrEqual(name, PUBLISH))
+               return handle_publish_tag(reader, notif);
+       if (xmlStrEqual(name, SNAPSHOT))
+               return validate_header_tag(reader, &notif->session);
+
+       return pr_val_err("Unexpected tag: '%s'", name);
+}
+
+int
+rrdp_parse_snapshot(struct rrdp_notification *notification)
+{
+       struct rpki_uri *uri;
+       int error;
+
+       uri = notification->snapshot.uri;
+
+       pr_val_debug("RRDP Snapshot '%s' {", uri_val_get_printable(uri));
+       fnstack_push_uri(uri);
+
+       error = http_get(uri, -1);
+       if (error)
+               goto pop;
+
+       error = rrdp_file_metadata_validate_hash(&notification->snapshot);
+       if (error)
+               goto pop;
+
+       error = relax_ng_parse(uri, xml_read_snapshot, notification);
+
+pop:   fnstack_pop();
+       pr_val_debug("}");
+       return error;
+}
diff --git a/src/rrdp/snapshot.h b/src/rrdp/snapshot.h
new file mode 100644 (file)
index 0000000..04dd4b1
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef SRC_RRDP_SNAPSHOT_H_
+#define SRC_RRDP_SNAPSHOT_H_
+
+#include "rrdp/types.h"
+
+int rrdp_parse_snapshot(struct rrdp_notification *);
+
+#endif /* SRC_RRDP_SNAPSHOT_H_ */
diff --git a/src/rrdp/types.c b/src/rrdp/types.c
new file mode 100644 (file)
index 0000000..0e8a4ce
--- /dev/null
@@ -0,0 +1,506 @@
+#include "rrdp/types.h"
+
+#include <ctype.h>
+#include <openssl/x509v3.h>
+#include "common.h"
+#include "file.h"
+#include "log.h"
+#include "crypto/base64.h"
+#include "crypto/hash.h"
+#include "xml/relax_ng.h"
+
+/* Represents a <publish> element */
+struct rrdp_publish {
+       struct rrdp_file_metadata target;
+       unsigned char *content;
+       size_t content_len;
+};
+
+static void
+rrdp_session_init(struct rrdp_session *session)
+{
+       session->id = NULL;
+}
+
+static void
+rrdp_session_cleanup(struct rrdp_session *session)
+{
+       free(session->id);
+}
+
+DEFINE_ARRAY_LIST_FUNCTIONS(rrdp_notification_deltas,
+    struct rrdp_notification_delta, )
+
+void
+rrdp_notification_init(struct rrdp_notification *notification,
+    struct rpki_uri *uri)
+{
+       notification->uri = uri;
+       rrdp_session_init(&notification->session);
+       rrdp_file_metadata_init(&notification->snapshot);
+       rrdp_notification_deltas_init(&notification->deltas_list);
+}
+
+void
+rrdp_file_metadata_init(struct rrdp_file_metadata *meta)
+{
+       memset(meta, 0, sizeof(*meta));
+}
+
+void
+rrdp_file_metadata_cleanup(struct rrdp_file_metadata *meta)
+{
+       free(meta->hash);
+       uri_refput(meta->uri);
+}
+
+int
+rrdp_file_metadata_validate_hash(struct rrdp_file_metadata *meta)
+{
+       return hash_validate_file("sha256", meta->uri, meta->hash,
+           meta->hash_len);
+}
+
+static void
+rrdp_notification_delta_destroy(struct rrdp_notification_delta *delta)
+{
+       rrdp_file_metadata_cleanup(&delta->meta);
+}
+
+void
+rrdp_notification_cleanup(struct rrdp_notification *notification)
+{
+       rrdp_session_cleanup(&notification->session);
+       rrdp_file_metadata_cleanup(&notification->snapshot);
+       rrdp_notification_deltas_cleanup(&notification->deltas_list,
+           rrdp_notification_delta_destroy);
+}
+
+/* Left trim @from, setting the result at @result pointer */
+static int
+ltrim(char *from, char **result, size_t *result_size)
+{
+       char *start;
+       size_t tmp_size;
+
+       start = from;
+       tmp_size = strlen(from);
+       while (isspace(*start)) {
+               start++;
+               tmp_size--;
+       }
+       if (*start == '\0')
+               return pr_val_err("Invalid base64 encoded string (seems to be empty or full of spaces).");
+
+       *result = start;
+       *result_size = tmp_size;
+       return 0;
+}
+
+/*
+ * Get the base64 chars from @content and allocate to @out with lines no greater
+ * than 65 chars (including line feed).
+ *
+ * Why? LibreSSL doesn't like lines greater than 80 chars, so use a common
+ * length per line.
+ */
+static int
+base64_sanitize(char *content, char **out)
+{
+#define BUF_SIZE 65
+       char *result;
+       char *tmp;
+       size_t original_size, new_size;
+       size_t offset, buf_len;
+       int error;
+
+       original_size = 0;
+       error = ltrim(content, &tmp, &original_size);
+       if (error)
+               return error;
+
+       if (original_size <= BUF_SIZE) {
+               result = strdup(content);
+               if (result == NULL)
+                       return pr_enomem();
+               *out = result;
+               return 0;
+       }
+
+       new_size = original_size + (original_size / BUF_SIZE);
+       result = malloc(new_size + 1);
+       if (result == NULL)
+               return pr_enomem();
+
+       offset = 0;
+       while (original_size > 0){
+               buf_len = original_size > BUF_SIZE ? BUF_SIZE : original_size;
+               memcpy(&result[offset], tmp, buf_len);
+               tmp += buf_len;
+               offset += buf_len;
+               original_size -= buf_len;
+
+               if (original_size <= 0)
+                       break;
+               result[offset] = '\n';
+               offset++;
+       }
+
+       /* Reallocate to exact size and add nul char */
+       if (offset != new_size + 1) {
+               tmp = realloc(result, offset + 1);
+               if (tmp == NULL) {
+                       free(result);
+                       return pr_enomem();
+               }
+               result = tmp;
+       }
+
+       result[offset] = '\0';
+       *out = result;
+       return 0;
+#undef BUF_SIZE
+}
+
+static int
+base64_read(char *content, unsigned char **out, size_t *out_len)
+{
+       BIO *encoded; /* base64 encoded. */
+       unsigned char *result;
+       char *sanitized;
+       size_t alloc_size;
+       size_t result_len;
+       int error;
+
+       sanitized = NULL;
+       error = base64_sanitize(content, &sanitized);
+       if (error)
+               return error;
+
+       encoded = BIO_new_mem_buf(sanitized, -1);
+       if (encoded == NULL) {
+               error = val_crypto_err("BIO_new_mem_buf() returned NULL");
+               goto release_sanitized;
+       }
+
+       alloc_size = EVP_DECODE_LENGTH(strlen(content));
+       result = malloc(alloc_size);
+       if (result == NULL) {
+               error = pr_enomem();
+               goto release_bio;
+       }
+
+       error = base64_decode(encoded, result, true, alloc_size, &result_len);
+       if (error)
+               goto release_result;
+
+       free(sanitized);
+       BIO_free(encoded);
+
+       *out = result;
+       (*out_len) = result_len;
+       return 0;
+release_result:
+       free(result);
+release_bio:
+       BIO_free(encoded);
+release_sanitized:
+       free(sanitized);
+       return error;
+}
+
+/*
+ * TODO (aaaa) at least one caller doesn't benefit from the memory copy.
+ * Analyze.
+ */
+static int
+parse_string(xmlTextReaderPtr reader, char const *attr, char **result)
+{
+       xmlChar *xml_value;
+       char *tmp;
+
+       if (attr == NULL) {
+               xml_value = xmlTextReaderValue(reader);
+               if (xml_value == NULL)
+                       return pr_val_err("RRDP file: Couldn't find string content from '%s'",
+                           xmlTextReaderConstLocalName(reader));
+       } else {
+               xml_value = xmlTextReaderGetAttribute(reader, BAD_CAST attr);
+               if (xml_value == NULL)
+                       return pr_val_err("RRDP file: Couldn't find xml attribute '%s' from tag '%s'",
+                           attr, xmlTextReaderConstLocalName(reader));
+       }
+
+       tmp = malloc(xmlStrlen(xml_value) + 1);
+       if (tmp == NULL) {
+               xmlFree(xml_value);
+               return pr_enomem();
+       }
+
+       memcpy(tmp, xml_value, xmlStrlen(xml_value));
+       tmp[xmlStrlen(xml_value)] = '\0';
+       xmlFree(xml_value);
+
+       *result = tmp;
+       return 0;
+}
+
+static int
+parse_hex_string(xmlTextReaderPtr reader, bool required, char const *attr,
+    unsigned char **result, size_t *result_len)
+{
+       xmlChar *xml_value;
+       unsigned char *tmp, *ptr;
+       char *xml_cur;
+       char buf[2];
+       size_t tmp_len;
+
+       xml_value = xmlTextReaderGetAttribute(reader, BAD_CAST attr);
+       if (xml_value == NULL)
+               return required ?
+                   pr_val_err("RRDP file: Couldn't find xml attribute '%s'", attr)
+                   : 0;
+
+       /* The rest of the checks are done at the schema */
+       if (xmlStrlen(xml_value) % 2 != 0) {
+               xmlFree(xml_value);
+               return pr_val_err("RRDP file: Attribute %s isn't a valid hex string",
+                   attr);
+       }
+
+       tmp_len = xmlStrlen(xml_value) / 2;
+       tmp = malloc(tmp_len);
+       if (tmp == NULL) {
+               xmlFree(xml_value);
+               return pr_enomem();
+       }
+       memset(tmp, 0, tmp_len);
+
+       ptr = tmp;
+       xml_cur = (char *) xml_value;
+       while (ptr - tmp < tmp_len) {
+               memcpy(buf, xml_cur, 2);
+               *ptr = strtol(buf, NULL, 16);
+               xml_cur+=2;
+               ptr++;
+       }
+       xmlFree(xml_value);
+
+       *result = tmp;
+       (*result_len) = tmp_len;
+       return 0;
+}
+
+static int
+validate_version(xmlTextReaderPtr reader)
+{
+       unsigned long version;
+       int error;
+
+       error = xml_parse_long(reader, "version", &version);
+       if (error)
+               return error;
+
+       if (version != 1ul)
+               return pr_val_err("Invalid version. Expected '1', got '%lu'.",
+                   version);
+
+       return 0;
+}
+
+int
+parse_header_tag(xmlTextReaderPtr reader, struct rrdp_session *result)
+{
+       static const xmlChar *NAMESPACE = BAD_CAST "http://www.ripe.net/rpki/rrdp";
+
+       const xmlChar *namespace;
+       int error;
+
+       namespace = xmlTextReaderConstNamespaceUri(reader);
+       if (!xmlStrEqual(namespace, NAMESPACE))
+               return pr_val_err("Unknown namespace: '%s'", namespace);
+       error = validate_version(reader);
+       if (error)
+               return error;
+
+       error = parse_string(reader, "session_id", &result->id);
+       if (error)
+               return error;
+       error = xml_parse_long(reader, "serial", &result->serial);
+       if (error)
+               free(result->id);
+
+       return error;
+}
+
+int
+parse_simple_uri_attribute(xmlTextReaderPtr reader,
+    struct rrdp_file_metadata *meta)
+{
+       char *guri;
+       int error;
+
+       error = parse_string(reader, "uri", &guri);
+       if (error)
+               return error;
+
+       return uri_create(guri, URI_TYPE_HTTP_SIMPLE, &meta->uri);
+}
+
+int
+parse_caged_uri_attribute(xmlTextReaderPtr reader,
+    struct rrdp_notification *notif,
+    struct rrdp_file_metadata *meta)
+{
+       char *guri;
+       int error;
+
+       error = parse_string(reader, "uri", &guri);
+       if (error)
+               return error;
+
+       return uri_create_caged(guri, notif->uri, &meta->uri);
+}
+
+int
+parse_hash_attribute(xmlTextReaderPtr reader, bool required,
+    struct rrdp_file_metadata *meta)
+{
+       return parse_hex_string(reader, required, "hash", &meta->hash,
+           &meta->hash_len);
+}
+
+/*
+ * Returns:
+ *
+ * - 0: session is valid
+ * - ENOENT: session is invalid
+ * - else: bad file
+ */
+int
+validate_header_tag(xmlTextReaderPtr reader, struct rrdp_session *session)
+{
+       struct rrdp_session current;
+       int error;
+
+       rrdp_session_init(&current);
+
+       error = parse_header_tag(reader, &current);
+       if (error)
+               return error;
+
+       if (strcmp(session->id, current.id) != 0) {
+               pr_val_info("session_id [%s] doesn't match notification's session_id [%s].",
+                   current.id, session->id);
+               goto invalid;
+       }
+       if (session->serial != current.serial) {
+               pr_val_info("serial '%lu' doesn't match notification's serial '%lu'.",
+                   current.serial, session->serial);
+               goto invalid;
+       }
+
+       rrdp_session_cleanup(&current);
+       return 0;
+
+invalid:
+       rrdp_session_cleanup(&current);
+       return ENOENT;
+}
+
+static int
+write_from_uri(struct rrdp_publish *publish)
+{
+       char const *file;
+       FILE *out;
+       size_t written;
+       int error;
+
+       file = uri_get_local(publish->target.uri);
+
+       /*
+        * TODO (aaaa) shouldn't this be reverted on error?
+        * Also, shouldn't create_dir_recursive() be inside file_write()?
+        */
+       error = create_dir_recursive(file);
+       if (error)
+               return error;
+
+       error = file_write(file, &out);
+       if (error)
+               return error;
+
+       written = fwrite(publish->content, sizeof(unsigned char),
+           publish->content_len, out);
+
+       file_close(out);
+
+       if (written != (sizeof(unsigned char) * publish->content_len))
+               return pr_val_err("Couldn't write bytes to file '%s'", file);
+
+       return 0;
+}
+
+static int
+parse_publish_tag(xmlTextReaderPtr reader, struct rrdp_notification *notif,
+    struct rrdp_publish *publish)
+{
+       char *base64_str;
+       int error;
+
+       /* Target */
+       error = parse_caged_uri_attribute(reader, notif, &publish->target);
+       if (error)
+               return error;
+       error = parse_hash_attribute(reader, false, &publish->target);
+       if (error)
+               return error;
+
+       /* Content */
+       if (xmlTextReaderRead(reader) != 1)
+               return pr_val_err("Couldn't read publish content of element '%s'",
+                   uri_get_global(publish->target.uri));
+       error = parse_string(reader, NULL, &base64_str);
+       if (error)
+               return error;
+
+       error = base64_read(base64_str, &publish->content,
+           &publish->content_len);
+
+       free(base64_str);
+       return error;
+}
+
+/*
+ * This function will call 'xmlTextReaderRead' so there's no need to expect any
+ * other type at the caller.
+ */
+int
+handle_publish_tag(xmlTextReaderPtr reader, struct rrdp_notification *notif)
+{
+       struct rrdp_publish publish;
+       int error;
+
+       rrdp_file_metadata_init(&publish.target);
+       publish.content = NULL;
+       publish.content_len = 0;
+
+       error = parse_publish_tag(reader, notif, &publish);
+       if (error)
+               goto end;
+
+       /* rfc8181#section-2.2, paragraph 3 */
+       if (publish.target.hash != NULL) {
+               error = rrdp_file_metadata_validate_hash(&publish.target);
+               if (error)
+                       goto end;
+       } else {
+               /* TODO (aaaa) check file does not exist */
+       }
+
+       error = write_from_uri(&publish);
+
+end:   rrdp_file_metadata_cleanup(&publish.target);
+       free(publish.content);
+       return error;
+}
diff --git a/src/rrdp/types.h b/src/rrdp/types.h
new file mode 100644 (file)
index 0000000..b474808
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef SRC_RRDP_TYPES_H_
+#define SRC_RRDP_TYPES_H_
+
+#include <libxml/xmlreader.h>
+#include "types/uri.h"
+#include "data_structure/array_list.h"
+
+struct rrdp_session {
+       char *id;
+       unsigned long serial;
+};
+
+/* An RRDP file, described by the Update Notification file. */
+struct rrdp_file_metadata {
+       struct rpki_uri *uri;
+       unsigned char *hash; /* Can be omitted sometimes. */
+       size_t hash_len;
+};
+
+void rrdp_file_metadata_init(struct rrdp_file_metadata *);
+void rrdp_file_metadata_cleanup(struct rrdp_file_metadata *);
+int rrdp_file_metadata_validate_hash(struct rrdp_file_metadata *);
+
+/* Parsed delta element, from the Update Notification file. */
+struct rrdp_notification_delta {
+       /*
+        * TODO this is not an RFC 1982 serial. It's supposed to be unbounded,
+        * so we should probably handle it as a string.
+        */
+       unsigned long serial;
+       struct rrdp_file_metadata meta;
+};
+
+DEFINE_ARRAY_LIST_STRUCT(rrdp_notification_deltas,
+    struct rrdp_notification_delta);
+DECLARE_ARRAY_LIST_FUNCTIONS(rrdp_notification_deltas,
+    struct rrdp_notification_delta)
+
+/* Update notification file content and location URI */
+struct rrdp_notification {
+       struct rpki_uri *uri;
+       struct rrdp_session session;
+       struct rrdp_file_metadata snapshot;
+       struct rrdp_notification_deltas deltas_list;
+};
+
+void rrdp_notification_init(struct rrdp_notification *, struct rpki_uri *);
+void rrdp_notification_cleanup(struct rrdp_notification *);
+
+int parse_simple_uri_attribute(xmlTextReaderPtr, struct rrdp_file_metadata *);
+int parse_caged_uri_attribute(xmlTextReaderPtr, struct rrdp_notification *,
+    struct rrdp_file_metadata *);
+int parse_hash_attribute(xmlTextReaderPtr, bool, struct rrdp_file_metadata *);
+
+int parse_header_tag(xmlTextReaderPtr, struct rrdp_session *);
+int validate_header_tag(xmlTextReaderPtr, struct rrdp_session *);
+int handle_publish_tag(xmlTextReaderPtr, struct rrdp_notification *);
+
+#endif /* SRC_RRDP_TYPES_H_ */
index cfb907927105a5342d63103aacac88504359b03f..63b40058d2c764b714089110757cbf4b9d08f503 100644 (file)
-#include "rsync.h"
+#include "rsync/rsync.h"
 
 #include <errno.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <signal.h> /* SIGINT, SIGQUIT, etc */
 #include <syslog.h>
-#include <sys/queue.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 
 #include "common.h"
-#include "config.h"
 #include "log.h"
-#include "reqs_errors.h"
-#include "str_token.h"
-#include "thread_var.h"
-
-struct uri {
-       struct rpki_uri *uri;
-       SLIST_ENTRY(uri) next;
-};
-
-/** URIs that we have already downloaded. */
-SLIST_HEAD(uri_list, uri);
-
-/* static char const *const RSYNC_PREFIX = "rsync://"; */
-
-int
-rsync_create(struct uri_list **result)
-{
-       struct uri_list *visited_uris;
-
-       visited_uris = malloc(sizeof(struct uri_list));
-       if (visited_uris == NULL)
-               return pr_enomem();
-
-       SLIST_INIT(visited_uris);
-
-       *result = visited_uris;
-       return 0;
-}
-
-void
-rsync_destroy(struct uri_list *list)
-{
-       struct uri *uri;
-
-       while (!SLIST_EMPTY(list)) {
-               uri = SLIST_FIRST(list);
-               SLIST_REMOVE_HEAD(list, next);
-               uri_refput(uri->uri);
-               free(uri);
-       }
-       free(list);
-}
-
-/*
- * Returns true if @ancestor an ancestor of @descendant, or @descendant itself.
- * Returns false otherwise.
- */
-static bool
-is_descendant(struct rpki_uri *ancestor, struct rpki_uri *descendant)
-{
-       struct string_tokenizer ancestor_tokenizer;
-       struct string_tokenizer descendant_tokenizer;
-
-       string_tokenizer_init(&ancestor_tokenizer, uri_get_global(ancestor),
-           uri_get_global_len(ancestor), '/');
-       string_tokenizer_init(&descendant_tokenizer, uri_get_global(descendant),
-           uri_get_global_len(descendant), '/');
-
-       if (config_get_rsync_strategy() == RSYNC_STRICT)
-               return strcmp(uri_get_global(ancestor),
-                   uri_get_global(descendant)) == 0;
-
-       do {
-               if (!string_tokenizer_next(&ancestor_tokenizer))
-                       return true;
-               if (!string_tokenizer_next(&descendant_tokenizer))
-                       return false;
-               if (!token_equals(&ancestor_tokenizer, &descendant_tokenizer))
-                       return false;
-       } while (true);
-}
-
-/*
- * Returns whether @uri has already been rsync'd during the current validation
- * run.
- */
-static bool
-is_already_downloaded(struct rpki_uri *uri, struct uri_list *visited_uris)
-{
-       struct uri *cursor;
-
-       /* TODO (next iteration) this is begging for a hash set. */
-       SLIST_FOREACH(cursor, visited_uris, next)
-               if (is_descendant(cursor->uri, uri))
-                       return true;
-
-       return false;
-}
-
-static int
-mark_as_downloaded(struct rpki_uri *uri, struct uri_list *visited_uris)
-{
-       struct uri *node;
-
-       node = malloc(sizeof(struct uri));
-       if (node == NULL)
-               return pr_enomem();
-
-       node->uri = uri;
-       uri_refget(uri);
-
-       SLIST_INSERT_HEAD(visited_uris, node, next);
-
-       return 0;
-}
-
-static int
-handle_strict_strategy(struct rpki_uri *requested_uri,
-    struct rpki_uri **rsync_uri)
-{
-       *rsync_uri = requested_uri;
-       uri_refget(requested_uri);
-       return 0;
-}
-
-static int
-handle_root_strategy(struct rpki_uri *src, struct rpki_uri **dst)
-{
-       char const *global;
-       size_t global_len;
-       unsigned int slashes;
-       size_t i;
-
-       global = uri_get_global(src);
-       global_len = uri_get_global_len(src);
-       slashes = 0;
-
-       for (i = 0; i < global_len; i++) {
-               if (global[i] == '/') {
-                       slashes++;
-                       if (slashes == 4)
-                               return uri_create_rsync_str(dst, global, i);
-               }
-       }
-
-       *dst = src;
-       uri_refget(src);
-       return 0;
-}
-
-static int
-get_rsync_uri(struct rpki_uri *requested_uri, bool is_ta,
-    struct rpki_uri **rsync_uri)
-{
-       switch (config_get_rsync_strategy()) {
-       case RSYNC_ROOT:
-               return handle_root_strategy(requested_uri, rsync_uri);
-       case RSYNC_ROOT_EXCEPT_TA:
-               return is_ta
-                   ? handle_strict_strategy(requested_uri, rsync_uri)
-                   : handle_root_strategy(requested_uri, rsync_uri);
-       case RSYNC_STRICT:
-               return handle_strict_strategy(requested_uri, rsync_uri);
-       case RSYNC_OFF:
-               break;
-       }
-
-       pr_crit("Invalid rsync strategy: %u", config_get_rsync_strategy());
-}
+#include "rpp/rpp_dl_status.h"
 
 /*
  * Duplicate parent FDs, to pipe rsync output:
@@ -204,13 +44,13 @@ release_args(char **args, unsigned int size)
 }
 
 static int
-prepare_rsync(struct rpki_uri *uri, bool is_ta, char ***args, size_t *args_len)
+prepare_rsync(struct rpki_uri *uri, bool is_file, char ***args, size_t *args_len)
 {
        struct string_array const *config_args;
        char **copy_args;
        unsigned int i;
 
-       config_args = config_get_rsync_args(is_ta);
+       config_args = config_get_rsync_args(is_file);
        /*
         * We need to work on a copy, because the config args are immutable,
         * and we need to add the program name (for some reason) and NULL
@@ -278,7 +118,7 @@ create_pipes(int fds[2][2])
 }
 
 static int
-log_buffer(char const *buffer, ssize_t read, int type, bool log_operation)
+log_buffer(char const *buffer, ssize_t read, int type)
 {
 #define PRE_RSYNC "[RSYNC exec]: "
        char *cpy, *cur, *tmp;
@@ -299,8 +139,6 @@ log_buffer(char const *buffer, ssize_t read, int type, bool log_operation)
                        continue;
                }
                if (type == 0) {
-                       if (log_operation)
-                               pr_op_err(PRE_RSYNC "%s", cur);
                        pr_val_err(PRE_RSYNC "%s", cur);
                } else {
                        pr_val_info(PRE_RSYNC "%s", cur);
@@ -313,7 +151,7 @@ log_buffer(char const *buffer, ssize_t read, int type, bool log_operation)
 }
 
 static int
-read_pipe(int fd_pipe[2][2], int type, bool log_operation)
+read_pipe(int fd_pipe[2][2], int type)
 {
        char buffer[4096];
        ssize_t count;
@@ -330,7 +168,7 @@ read_pipe(int fd_pipe[2][2], int type, bool log_operation)
                if (count == 0)
                        break;
 
-               error = log_buffer(buffer, count, type, log_operation);
+               error = log_buffer(buffer, count, type);
                if (error)
                        return error;
        }
@@ -343,7 +181,7 @@ read_pipe(int fd_pipe[2][2], int type, bool log_operation)
  * success and on error.
  */
 static int
-read_pipes(int fds[2][2], bool log_operation)
+read_pipes(int fds[2][2])
 {
        int error;
 
@@ -352,7 +190,7 @@ read_pipes(int fds[2][2], bool log_operation)
        close(fds[1][1]);
 
        /* stderr pipe */
-       error = read_pipe(fds, 0, log_operation);
+       error = read_pipe(fds, 0);
        if (error) {
                /* Close the other pipe pending to read */
                close(fds[1][0]);
@@ -360,14 +198,14 @@ read_pipes(int fds[2][2], bool log_operation)
        }
 
        /* stdout pipe, always logs to info */
-       return read_pipe(fds, 1, true);
+       return read_pipe(fds, 1);
 }
 
 /*
- * Downloads the @uri->global file into the @uri->local path.
+ * Downloads the @remote file into the @local path.
  */
 static int
-do_rsync(struct rpki_uri *uri, bool is_ta, bool log_operation)
+do_rsync(struct rpki_uri *uri, bool is_file)
 {
        /* Descriptors to pipe stderr (first element) and stdout (second) */
        char **args;
@@ -382,7 +220,7 @@ do_rsync(struct rpki_uri *uri, bool is_ta, bool log_operation)
        /* Prepare everything for the child exec */
        args = NULL;
        args_len = 0;
-       error = prepare_rsync(uri, is_ta, &args, &args_len);
+       error = prepare_rsync(uri, is_file, &args, &args_len);
        if (error)
                return error;
 
@@ -433,7 +271,7 @@ do_rsync(struct rpki_uri *uri, bool is_ta, bool log_operation)
                }
 
                /* This code is run by us. */
-               error = read_pipes(fork_fds, log_operation);
+               error = read_pipes(fork_fds);
                if (error)
                        kill(child_pid, SIGCHLD); /* Stop the child */
 
@@ -452,7 +290,7 @@ do_rsync(struct rpki_uri *uri, bool is_ta, bool log_operation)
                if (WIFEXITED(child_status)) {
                        /* Happy path (but also sad path sometimes). */
                        error = WEXITSTATUS(child_status);
-                       pr_val_debug("Child terminated with error code %d.",
+                       pr_val_debug("The rsync sub-process terminated with error code %d.",
                            error);
                        if (!error)
                                goto release_args;
@@ -504,150 +342,39 @@ release_args:
        return error;
 }
 
-/*
- * 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
- */
-static int
-ancestor_error(char const *error_uri, void *arg)
-{
-       struct rpki_uri *search = arg;
-       struct rpki_uri *req_err_uri;
-       int error;
-
-       req_err_uri = NULL;
-       error = uri_create_mixed_str(&req_err_uri, error_uri,
-           strlen(error_uri));
-       switch(error) {
-       case 0:
-               break;
-       default:
-               return ENSURE_NEGATIVE(error);
-       }
-
-       /* Ignore non rsync error'd URIs */
-       if (!uri_is_rsync(req_err_uri)) {
-               uri_refput(req_err_uri);
-               return 0;
-       }
-
-       error = is_descendant(req_err_uri, search) ? EEXIST : 0;
-
-       uri_refput(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
- * (unless the strategy has been set to SYNC_OFF.)
- * Why? Because we should probably not trust the repository until we've
- * validated the TA's public key.
+ * @is_file: Send true if you're synchronizing a file, false if you're
+ * synchronizing a directory.
+ * @force: Download regardless of existing download status?
  */
 int
-rsync_download_files(struct rpki_uri *requested_uri, bool is_ta, bool force)
+rsync_download_files(struct rpki_uri *uri, bool is_file)
 {
-       /**
-        * Note:
-        * @requested_uri is the URI we were asked to RSYNC.
-        * @rsync_uri is the URL we're actually going to RSYNC.
-        * (They can differ, depending on config_get_rsync_strategy().)
-        */
-       struct validation *state;
-       struct uri_list *visited_uris;
-       struct rpki_uri *rsync_uri;
-       bool to_op_log;
        int error;
 
-       if (!config_get_rsync_enabled())
+       if (!config_get_rsync_enabled()) {
+               /* TODO (aaaa) equivalent RRDP message */
+               pr_val_debug("rsync disabled; skipping update.");
                return 0;
-
-       state = state_retrieve();
-       if (state == NULL)
-               return -EINVAL;
-
-       visited_uris = validation_rsync_visited_uris(state);
-
-       if (!force && is_already_downloaded(requested_uri, visited_uris)) {
-               pr_val_debug("No need to redownload '%s'.",
-                   uri_val_get_printable(requested_uri));
-               return check_ancestor_error(requested_uri);
        }
 
-       if (!force) {
-               error = get_rsync_uri(requested_uri, is_ta, &rsync_uri);
-       } else {
-               error = check_ancestor_error(requested_uri);
-               if (error)
-                       return error;
-               error = handle_strict_strategy(requested_uri, &rsync_uri);
-       }
-
-       if (error)
-               return error;
-
-       pr_val_debug("Going to RSYNC '%s'.", uri_val_get_printable(rsync_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(rsync_uri));
-               break;
-       case EREQFAILED:
-               /* All attempts failed, avoid future requests */
-               error = reqs_errors_add_uri(uri_get_global(rsync_uri));
-               if (error)
-                       break;
-               error = mark_as_downloaded(rsync_uri, visited_uris);
-               /* Everything went ok? Return the original error */
-               if (!error)
-                       error = EREQFAILED;
+       switch (rdsdb_get(uri)) {
+       case RDS_NOT_YET:
                break;
+       case RDS_SUCCESS:
+               pr_val_debug("'%s' was already successfully downloaded in the current validation cycle.",
+                   uri_get_global(uri));
+               return 0;
+       case RDS_ERROR:
+               pr_val_err("'%s' was already unsuccessfully downloaded in the current validation cycle; not retrying.",
+                   uri_get_global(uri));
+               return -EPERM;
        }
 
-       uri_refput(rsync_uri);
-       return error;
-}
-
-void
-reset_downloaded(void)
-{
-       struct validation *state;
-       struct uri_list *list;
-       struct uri *uri;
+       pr_val_debug("Going to RSYNC '%s'.", uri_get_global(uri));
 
-       state = state_retrieve();
-       if (state == NULL)
-               return;
+       error = do_rsync(uri, is_file);
 
-       list = validation_rsync_visited_uris(state);
-
-       while (!SLIST_EMPTY(list)) {
-               uri = SLIST_FIRST(list);
-               SLIST_REMOVE_HEAD(list, next);
-               uri_refput(uri->uri);
-               free(uri);
-       }
+       rdsdb_set(uri, error);
+       return error;
 }
index b5f8e6edcf0898b554287ef487e4608277b94e48..3dc8d370792d72379fd75274300907df4e50aa2a 100644 (file)
@@ -4,12 +4,6 @@
 #include <stdbool.h>
 #include "types/uri.h"
 
-struct uri_list;
-
-int rsync_download_files(struct rpki_uri *, bool, bool);
-int rsync_create(struct uri_list **);
-void rsync_destroy(struct uri_list *);
-
-void reset_downloaded(void);
+int rsync_download_files(struct rpki_uri *, bool);
 
 #endif /* SRC_RSYNC_RSYNC_H_ */
index 6a962b6a013d19908d7160377d7b20ed950fdd43..ec5df5eeab208ca842f1ba362b5ec3eaaf90717a 100644 (file)
@@ -1,9 +1,9 @@
 #include "state.h"
 
 #include <errno.h>
-#include "rrdp/db/db_rrdp.h"
 #include "log.h"
 #include "thread_var.h"
+#include "rpp/rpp_dl_status.h"
 
 /**
  * The current state of the validation cycle.
@@ -23,13 +23,8 @@ struct validation {
 
        struct cert_stack *certstack;
 
-       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;
+       /* Download statuses. Prevents us from downloading something twice. */
+       struct rpp_dl_status_db *downloads;
 
        /* Did the TAL's public key match the root certificate's public key? */
        enum pubkey_state pubkey_state;
@@ -83,78 +78,78 @@ cb(int ok, X509_STORE_CTX *ctx)
 }
 
 /**
- * Creates a struct validation, puts it in thread local, and (incidentally)
- * returns it.
+ * Creates a struct validation and puts it in thread local.
  */
 int
-validation_prepare(struct validation **out, struct tal *tal,
+validation_prepare(struct tal *tal,
     struct validation_handler *validation_handler)
 {
-       struct validation *result;
+       struct validation *state;
        X509_VERIFY_PARAM *params;
        int error;
 
-       result = malloc(sizeof(struct validation));
-       if (!result)
+       state = malloc(sizeof(struct validation));
+       if (!state)
                return pr_enomem();
 
-       error = state_store(result);
+       error = state_store(state);
        if (error)
-               goto abort1;
+               goto revert_state;
 
-       result->tal = tal;
+       state->tal = tal;
 
-       result->x509_data.store = X509_STORE_new();
-       if (!result->x509_data.store) {
+       state->x509_data.store = X509_STORE_new();
+       if (!state->x509_data.store) {
                error = val_crypto_err("X509_STORE_new() returned NULL");
-               goto abort1;
+               goto revert_state;
        }
 
        params = X509_VERIFY_PARAM_new();
        if (params == NULL) {
                error = pr_enomem();
-               goto abort2;
+               goto revert_store;
        }
 
        X509_VERIFY_PARAM_set_flags(params, X509_V_FLAG_CRL_CHECK);
-       X509_STORE_set1_param(result->x509_data.store, params);
-       X509_STORE_set_verify_cb(result->x509_data.store, cb);
+       X509_STORE_set1_param(state->x509_data.store, params);
+       X509_STORE_set_verify_cb(state->x509_data.store, cb);
 
-       error = certstack_create(&result->certstack);
+       error = certstack_create(&state->certstack);
        if (error)
-               goto abort3;
+               goto revert_params;
 
-       error = rsync_create(&result->rsync_visited_uris);
-       if (error)
-               goto abort4;
+       state->downloads = rdsdb_create();
+       if (state->downloads == NULL)
+               goto revert_certstack;
 
-       result->rrdp_uris = db_rrdp_get_uris(tal_get_file_name(tal));
-       result->rrdp_workspace = db_rrdp_get_workspace(tal_get_file_name(tal));
+       state->pubkey_state = PKS_UNTESTED;
+       state->validation_handler = *validation_handler;
+       state->x509_data.params = params; /* Ownership transfered */
 
-       result->pubkey_state = PKS_UNTESTED;
-       result->validation_handler = *validation_handler;
-       result->x509_data.params = params; /* Ownership transfered */
-
-       *out = result;
        return 0;
-abort4:
-       certstack_destroy(result->certstack);
-abort3:
+
+revert_certstack:
+       certstack_destroy(state->certstack);
+revert_params:
        X509_VERIFY_PARAM_free(params);
-abort2:
-       X509_STORE_free(result->x509_data.store);
-abort1:
-       free(result);
+revert_store:
+       X509_STORE_free(state->x509_data.store);
+revert_state:
+       free(state);
        return error;
 }
 
 void
-validation_destroy(struct validation *state)
+validation_destroy(void)
 {
+       struct validation *state;
+
+       state = state_retrieve();
+
+       rdsdb_destroy(state->downloads);
+       certstack_destroy(state->certstack);
        X509_VERIFY_PARAM_free(state->x509_data.params);
        X509_STORE_free(state->x509_data.store);
-       certstack_destroy(state->certstack);
-       rsync_destroy(state->rsync_visited_uris);
        free(state);
 }
 
@@ -176,12 +171,6 @@ validation_certstack(struct validation *state)
        return state->certstack;
 }
 
-struct uri_list *
-validation_rsync_visited_uris(struct validation *state)
-{
-       return state->rsync_visited_uris;
-}
-
 void
 validation_pubkey_valid(struct validation *state)
 {
@@ -218,14 +207,8 @@ validation_get_validation_handler(struct validation *state)
        return &state->validation_handler;
 }
 
-struct db_rrdp_uri *
-validation_get_rrdp_uris(struct validation *state)
-{
-       return state->rrdp_uris;
-}
-
-char const *
-validation_get_rrdp_workspace(struct validation *state)
+struct rpp_dl_status_db *
+validation_get_rppdb(struct validation *state)
 {
-       return state->rrdp_workspace;
+       return state->downloads;
 }
index 5fceca3086930d26558679556dca79bfb146a7da..b37df7d439a74e42769c118e6ee154dbbd803b4b 100644 (file)
@@ -5,19 +5,15 @@
 #include "cert_stack.h"
 #include "validation_handler.h"
 #include "object/tal.h"
-#include "rsync/rsync.h"
-#include "rrdp/db/db_rrdp_uris.h"
 
 struct validation;
 
-int validation_prepare(struct validation **, struct tal *,
-    struct validation_handler *);
-void validation_destroy(struct validation *);
+int validation_prepare(struct tal *, struct validation_handler *);
+void validation_destroy();
 
 struct tal *validation_tal(struct validation *);
 X509_STORE *validation_store(struct validation *);
 struct cert_stack *validation_certstack(struct validation *);
-struct uri_list *validation_rsync_visited_uris(struct validation *);
 
 enum pubkey_state {
        PKS_VALID,
@@ -35,7 +31,6 @@ char *validation_get_ip_buffer2(struct validation *);
 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 *);
+struct rpp_dl_status_db *validation_get_rppdb(struct validation *);
 
 #endif /* SRC_STATE_H_ */
index 4fac55d8861e57abc9d31e9613374f73e3ba4a20..bdf6f8ce530bed77744b720397e74c3e62abb0be 100644 (file)
@@ -6,6 +6,8 @@
 
 /**
  * Does not assume that @string is NULL-terminated.
+ *
+ * TODO (aaaa) use this more.
  */
 static int
 string_clone(void const *string, size_t size, char **clone)
index e6eab3fa9f2b0dac7e731749767ec29d63cd57e0..d2cfbe762b658623c805e7989dfa0941500e9ef8 100644 (file)
@@ -12,7 +12,6 @@
 
 static pthread_key_t state_key;
 static pthread_key_t filenames_key;
-static pthread_key_t repository_key;
 
 struct filename_stack {
        /* This can be NULL. Abort all operations if this is the case. */
@@ -21,11 +20,6 @@ struct filename_stack {
        unsigned int size;
 };
 
-struct working_repo {
-       char const *uri;
-       unsigned int level;
-};
-
 static void
 fnstack_discard(void *arg)
 {
@@ -34,13 +28,6 @@ fnstack_discard(void *arg)
        free(files);
 }
 
-static void
-working_repo_discard(void *arg)
-{
-       struct working_repo *repo = arg;
-       free(repo);
-}
-
 /** Initializes this entire module. Call once per runtime lifetime. */
 int
 thvar_init(void)
@@ -69,14 +56,6 @@ thvar_init(void)
                return error;
        }
 
-       error = pthread_key_create(&repository_key, working_repo_discard);
-       if (error) {
-               pr_op_err(
-                   "Fatal: Errcode %d while initializing the 'working repository' thread variable.",
-                   error);
-               return error;
-       }
-
        return 0;
 }
 
@@ -93,7 +72,15 @@ state_store(struct validation *state)
        return error;
 }
 
-/* Returns the current thread's validation state. */
+/*
+ * Returns the current thread's validation state.
+ *
+ * The state is stored in the thread because it's needed in both extremely high
+ * and extremely low level functions; it would cause catastrophic clutter if
+ * passed around in argument lists.
+ *
+ * Cannot return NULL.
+ */
 struct validation *
 state_retrieve(void)
 {
@@ -101,7 +88,7 @@ state_retrieve(void)
 
        state = pthread_getspecific(state_key);
        if (state == NULL)
-               pr_op_err("Programming error: This thread lacks a validation state.");
+               pr_crit("Programming error: This thread lacks a validation state.");
 
        return state;
 }
@@ -218,123 +205,11 @@ fnstack_pop(void)
        files->len--;
 }
 
-/** Initializes the current thread's working repo. Call once per thread. */
-void
-working_repo_init(void)
-{
-       struct working_repo *repo;
-       int error;
-
-       repo = malloc(sizeof(struct working_repo));
-       if (repo == NULL)
-               return;
-
-       repo->uri = NULL;
-       repo->level = 0;
-
-       error = pthread_setspecific(repository_key, repo);
-       if (error)
-               pr_op_err("pthread_setspecific() returned %d.", error);
-}
-
-void
-working_repo_cleanup(void)
-{
-       struct working_repo *repo;
-       int error;
-
-       repo = pthread_getspecific(repository_key);
-       if (repo == NULL)
-               return;
-
-       working_repo_discard(repo);
-
-       error = pthread_setspecific(repository_key, NULL);
-       if (error)
-               pr_op_err("pthread_setspecific() returned %d.", error);
-}
-
-/*
- * Call whenever a certificate has more than one repository where its childs
- * live (rsync or RRDP).
- */
-void
-working_repo_push(char const *location)
-{
-       struct working_repo *repo;
-
-       repo = pthread_getspecific(repository_key);
-       if (repo == NULL)
-               return;
-
-       repo->uri = location;
-}
-
-/*
- * Set the current repository level, must be called before trying to fetch the
- * repository.
- *
- * The level "calculation" must be done by the caller.
- */
-void
-working_repo_push_level(unsigned int level)
-{
-       struct working_repo *repo;
-
-       repo = pthread_getspecific(repository_key);
-       if (repo == NULL)
-               return;
-
-       repo->level = level;
-}
-
-char const *
-working_repo_peek(void)
-{
-       struct working_repo *repo;
-
-       repo = pthread_getspecific(repository_key);
-
-       return repo == NULL ? NULL : repo->uri;
-}
-
-unsigned int
-working_repo_peek_level(void)
-{
-       struct working_repo *repo;
-
-       repo = pthread_getspecific(repository_key);
-
-       return repo->level;
-}
-
-/*
- * Call once the certificate's repositories were downloaded (either successful
- * or erroneously).
- */
-void
-working_repo_pop(void)
-{
-       struct working_repo *repo;
-
-       repo = pthread_getspecific(repository_key);
-       if (repo == NULL)
-               return;
-
-       repo->uri = NULL;
-       repo->level = 0;
-}
-
 static char const *
 addr2str(int af, void const *addr, char *(*buffer_cb)(struct validation *))
 {
-       struct validation *state;
-
-       state = state_retrieve();
-       if (state == NULL)
-               return NULL;
-
-       return inet_ntop(af, addr, buffer_cb(state), INET6_ADDRSTRLEN);
+       return inet_ntop(af, addr, buffer_cb(state_retrieve()),
+           INET6_ADDRSTRLEN);
 }
 
 /**
index dff85381b8c53a3a536d4993077c3ea8cbb5cbd2..15769964b090d069de0c9f33fc9882acba9aa932 100644 (file)
@@ -16,15 +16,6 @@ void fnstack_push_uri(struct rpki_uri *);
 char const *fnstack_peek(void);
 void fnstack_pop(void);
 
-void working_repo_init(void);
-void working_repo_cleanup(void);
-
-void working_repo_push(char const *);
-void working_repo_push_level(unsigned int);
-char const *working_repo_peek(void);
-unsigned int working_repo_peek_level(void);
-void working_repo_pop(void);
-
 /* Please remember that these functions can only be used during validations. */
 char const *v4addr2str(struct in_addr const *);
 char const *v4addr2str2(struct in_addr const *);
index 04b1cbe0857d233a5c2bfa4bf7bba18bd11a6543..5e8aa4bdbabdb0a3d239fdfce628cfceb8d48d3c 100644 (file)
@@ -1,21 +1,14 @@
 #include "types/uri.h"
 
-#include <errno.h>
-#include <strings.h>
-#include "rrdp/db/db_rrdp_uris.h"
-#include "common.h"
-#include "config.h"
+#include "file.h"
 #include "log.h"
-#include "str_token.h"
-
-/* Expected URI types */
-enum rpki_uri_type {
-       URI_RSYNC,
-       URI_HTTPS,
-};
-
-static char const *const PFX_RSYNC = "rsync://";
-static char const *const PFX_HTTPS = "https://";
+#include "random.h"
+#include "thread_var.h"
+#include "data_structure/array_list.h"
+#include "data_structure/path_builder.h"
+#include "http/http.h"
+#include "rrdp/rrdp.h"
+#include "rsync/rsync.h"
 
 /**
  * Design notes:
@@ -34,18 +27,17 @@ static char const *const PFX_HTTPS = "https://";
 struct rpki_uri {
        /**
         * "Global URI".
-        * The one that always starts with "rsync://" or "https://".
+        * (Global = The ones that always start with "rsync://" or "https://")
         *
         * These things are IA5-encoded, which means you're not bound to get
         * non-ASCII characters.
         */
        char *global;
-       /** Length of @global. */
-       size_t global_len;
 
        /**
         * "Local URI".
-        * The file pointed by @global, but cached in the local filesystem.
+        * The file pointed by the @global string, but cached in the local
+        * filesystem.
         *
         * I can't find a standard that defines this, but lots of complaints on
         * the Internet imply that Unix file paths are specifically meant to be
@@ -61,447 +53,134 @@ struct rpki_uri {
         * encoding as the output.
         */
        char *local;
-       /* "local_len" is never needed right now. */
 
-       /* Type, currently rysnc and https are valid */
        enum rpki_uri_type type;
 
+       /* Reference counter. */
        unsigned int references;
 };
 
-/*
- * @character is an integer because we sometimes receive signed chars, and other
- * times we get unsigned chars.
- * Casting a negative char into a unsigned char is undefined behavior.
- */
-static int
-validate_url_character(int character)
-{
-       /*
-        * RFCs 1738 and 3986 define a very specific range of allowed
-        * characters, but I don't think we're that concerned about URL
-        * correctness. Validating the URL properly is more involved than simply
-        * checking legal characters, anyway.
-        *
-        * What I really need this validation for is ensure that we won't get
-        * any trouble later, when we attempt to convert the global URI to a
-        * local file.
-        *
-        * Sample trouble: Getting UTF-8 characters. Why are they trouble?
-        * Because we don't have any guarantees that the system's file name
-        * encoding is UTF-8. URIs are not supposed to contain UTF-8 in the
-        * first place, so we have no reason to deal with encoding conversion.
-        *
-        * To be perfectly fair, we have no guarantees that the system's file
-        * name encoding is ASCII-compatible either, but I need to hang onto
-        * SOMETHING.
-        *
-        * (Asking users to use UTF-8 is fine, but asking users to use something
-        * ASCII-compatible is a little better.)
-        *
-        * So just make sure that the character is printable ASCII.
-        *
-        * TODO (next iteration) Consider exhaustive URL validation.
-        */
-       return (0x20 <= character && character <= 0x7E)
-           ? 0
-           : pr_val_err("URL has non-printable character code '%d'.", character);
-}
-
-/**
- * Initializes @uri->global* by cloning @str.
- * This function does not assume that @str is null-terminated.
- */
-static int
-str2global(char const *str, size_t str_len, struct rpki_uri *uri)
+/* Always steals ownership of @global. */
+static struct rpki_uri *
+__uri_create(char *global, enum rpki_uri_type type)
 {
-       int error;
-       size_t i;
-
-       for (i = 0; i < str_len; i++) {
-               error = validate_url_character(str[i]);
-               if (error)
-                       return error;
-       }
-
-       uri->global = malloc(str_len + 1);
-       if (uri->global == NULL)
-               return pr_enomem();
-       strncpy(uri->global, str, str_len);
-       uri->global[str_len] = '\0';
-       uri->global_len = str_len;
-
-       return 0;
-}
-
-static bool
-is_valid_mft_file_chara(uint8_t chara)
-{
-       return ('a' <= chara && chara <= 'z')
-           || ('A' <= chara && chara <= 'Z')
-           || ('0' <= chara && chara <= '9')
-           || (chara == '-')
-           || (chara == '_');
-}
-
-/* RFC 6486bis, section 4.2.2 */
-static int
-validate_mft_file(IA5String_t *ia5)
-{
-       size_t dot;
-       size_t i;
-
-       if (ia5->size < 5)
-               return pr_val_err("File name is too short (%zu < 5).", ia5->size);
-       dot = ia5->size - 4;
-       if (ia5->buf[dot] != '.')
-               return pr_val_err("File name seems to lack a three-letter extension.");
-
-       for (i = 0; i < ia5->size; i++) {
-               if (i != dot && !is_valid_mft_file_chara(ia5->buf[i])) {
-                       return pr_val_err("File name contains illegal character #%u",
-                           ia5->buf[i]);
-               }
-       }
-
-       /*
-        * Actual extension doesn't matter; if there's no handler,
-        * we'll naturally ignore the file.
-        */
-       return 0;
-}
-
-/**
- * Initializes @uri->global given manifest path @mft and its referenced file
- * @ia5.
- *
- * ie. if @mft is "rsync://a/b/c.mft" and @ia5 is "d.cer", @uri->global will
- * be "rsync://a/b/d.cer".
- *
- * Assumes that @mft is a "global" URL. (ie. extracted from rpki_uri.global.)
- */
-static int
-ia5str2global(struct rpki_uri *uri, char const *mft, IA5String_t *ia5)
-{
-       char *joined;
-       char *slash_pos;
-       int dir_len;
-       int error;
-
-       /*
-        * IA5String is a subset of ASCII. However, IA5String_t doesn't seem to
-        * be guaranteed to be NULL-terminated.
-        * `(char *) ia5->buf` is fair, but `strlen(ia5->buf)` is not.
-        */
-
-       error = validate_mft_file(ia5);
-       if (error)
-               return error;
-
-       slash_pos = strrchr(mft, '/');
-       if (slash_pos == NULL)
-               return pr_val_err("Manifest URL '%s' contains no slashes.", mft);
-
-       dir_len = (slash_pos + 1) - mft;
-       joined = malloc(dir_len + ia5->size + 1);
-       if (joined == NULL)
-               return pr_enomem();
-
-       strncpy(joined, mft, dir_len);
-       strncpy(joined + dir_len, (char *) ia5->buf, ia5->size);
-       joined[dir_len + ia5->size] = '\0';
-
-       uri->global = joined;
-       uri->global_len = dir_len + ia5->size;
-       return 0;
-}
+       struct rpki_uri *uri;
 
-static int
-validate_uri_begin(char const *uri_pfx, const size_t uri_pfx_len,
-    char const *global, size_t global_len, int error)
-{
-       if (global_len < uri_pfx_len
-           || strncasecmp(uri_pfx, global, uri_pfx_len) != 0) {
-               if (!error)
-                       return -EINVAL;
-               pr_val_err("Global URI '%s' does not begin with '%s'.",
-                   global, uri_pfx);
-               return error;
+       uri = malloc(sizeof(struct rpki_uri));
+       if (uri == NULL) {
+               free(global);
+               return NULL;
        }
 
-       return 0;
+       uri->global = global;
+       uri->local = NULL;
+       uri->type = type;
+       uri->references = 1;
+       return uri;
 }
 
-static int
-validate_gprefix(char const *global, size_t global_len, uint8_t flags,
-    enum rpki_uri_type *type)
+/* Always steals ownership of @global. */
+int
+uri_create(char *global, enum rpki_uri_type type, struct rpki_uri **result)
 {
-       size_t const PFX_RSYNC_LEN = strlen(PFX_RSYNC);
-       size_t const PFX_HTTPS_LEN = strlen(PFX_HTTPS);
-       uint8_t l_flags;
+       struct rpki_uri *uri;
+       struct path_builder path;
        int error;
 
-       /* 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, ENOTRSYNC);
-       }
-       if (l_flags == URI_VALID_HTTPS) {
-               (*type) = URI_HTTPS;
-               return validate_uri_begin(PFX_HTTPS, PFX_HTTPS_LEN, global,
-                   global_len, ENOTHTTPS);
-       }
-       if (l_flags != (URI_VALID_RSYNC | URI_VALID_HTTPS))
-               pr_crit("Unknown URI flag");
-
-       /* It has both flags */
-       error = validate_uri_begin(PFX_RSYNC, PFX_RSYNC_LEN, global, global_len,
-           0);
-       if (!error) {
-               (*type) = URI_RSYNC;
-               return 0;
-       }
-       error = validate_uri_begin(PFX_HTTPS, PFX_HTTPS_LEN, global, global_len,
-           0);
-       if (error) {
-               pr_val_warn("URI '%s' does not begin with '%s' nor '%s'.",
-                   global, PFX_RSYNC, PFX_HTTPS);
-               return ENOTSUPPORTED;
-       }
-
-       /* @size was already set */
-       (*type) = URI_HTTPS;
-       return 0;
-}
-
-static int
-get_local_workspace(char **result)
-{
-       char const *workspace;
-       char *tmp;
-
-       workspace = db_rrdp_uris_workspace_get();
-       if (workspace == NULL) {
-               *result = NULL;
-               return 0;
-       }
-
-       tmp = strdup(workspace);
-       if (tmp == NULL)
+       uri = __uri_create(global, type);
+       if (uri == NULL)
                return pr_enomem();
 
-       *result = tmp;
-       return 0;
-}
-
-/**
- * Initializes @uri->local by converting @uri->global.
- *
- * For example, given local cache repository "/tmp/rpki" and global uri
- * "rsync://rpki.ripe.net/repo/manifest.mft", initializes @uri->local as
- * "/tmp/rpki/rpki.ripe.net/repo/manifest.mft".
- *
- * By contract, if @guri is not RSYNC nor HTTPS, this will return ENOTRSYNC.
- * This often should not be treated as an error; please handle gracefully.
- */
-static int
-g2l(char const *global, size_t global_len, uint8_t flags, char **result,
-    enum rpki_uri_type *result_type)
-{
-       char *local;
-       char *workspace;
-       enum rpki_uri_type type;
-       int error;
-
-       error = validate_gprefix(global, global_len, flags, &type);
-       if (error)
-               return error;
-
-       workspace = NULL;
-       if ((flags & URI_USE_RRDP_WORKSPACE) != 0) {
-               error = get_local_workspace(&workspace);
-               if (error)
+       switch (type) {
+       case URI_TYPE_VERSATILE:
+       case URI_TYPE_RSYNC:
+       case URI_TYPE_HTTP_SIMPLE:
+               path_init(&path);
+               path_append(&path, config_get_local_repository());
+               path_append_url(&path, uri); /* Note: Must include the protocol */
+               error = path_compile(&path, &uri->local);
+               if (error) {
+                       uri_refput(uri);
                        return error;
-       }
+               }
+               break;
 
-       error = map_uri_to_local(global,
-           type == URI_RSYNC ? PFX_RSYNC : PFX_HTTPS,
-           workspace,
-           &local);
-       if (error) {
-               free(workspace);
-               return error;
+       case URI_TYPE_HTTP_CAGED:
+               pr_crit("Bad constructor for caged URI.");
+               break;
+
+       case URI_TYPE_VOID:
+               break;
        }
 
-       free(workspace);
-       *result = local;
-       (*result_type) = type;
+       *result = uri;
        return 0;
 }
 
-static int
-autocomplete_local(struct rpki_uri *uri, uint8_t flags)
-{
-       return g2l(uri->global, uri->global_len, flags, &uri->local,
-           &uri->type);
-}
-
-static int
-uri_create(struct rpki_uri **result, uint8_t flags, void const *guri,
-    size_t guri_len)
+/* Always steals ownership of @global. */
+int
+uri_create_caged(char *global, struct rpki_uri *notification,
+    struct rpki_uri **result)
 {
        struct rpki_uri *uri;
+       struct path_builder path;
        int error;
 
-       uri = malloc(sizeof(struct rpki_uri));
+       uri = __uri_create(global, URI_TYPE_HTTP_CAGED);
        if (uri == NULL)
                return pr_enomem();
 
-       error = str2global(guri, guri_len, uri);
+       path_init(&path);
+       path_append(&path, config_get_local_repository());
+       path_append(&path, "caged");
+       path_append_url(&path, notification);
+       path_append_url(&path, uri);
+       error = path_compile(&path, &uri->local);
        if (error) {
-               free(uri);
-               return error;
-       }
-
-       error = autocomplete_local(uri, flags);
-       if (error) {
-               free(uri->global);
-               free(uri);
+               uri_refput(uri);
                return error;
        }
 
-       uri->references = 1;
        *result = uri;
        return 0;
 }
 
-int
-uri_create_rsync_str_rrdp(struct rpki_uri **uri, char const *guri,
-    size_t 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_rsync_str(struct rpki_uri **uri, char const *guri, size_t guri_len)
-{
-       return uri_create(uri, URI_VALID_RSYNC, guri, guri_len);
-}
-
-/*
- * A URI that can be rsync or https.
- *
- * Return ENOTSUPPORTED if not an rsync or https URI.
- */
-int
-uri_create_mixed_str(struct rpki_uri **uri, char const *guri, size_t guri_len)
+static int
+create_neighbor(char const *prefix, IA5String_t *suffix, char **result)
 {
-       return uri_create(uri, URI_VALID_RSYNC | URI_VALID_HTTPS, guri,
-           guri_len);
+       struct path_builder path;
+       path_init(&path);
+       path_append_limited(&path, prefix, strrchr(prefix, '/') - prefix);
+       path_append_limited(&path, (char *) suffix->buf, suffix->size);
+       return path_compile(&path, result);
 }
 
-/*
- * Manifest fileList entries are a little special in that they're just file
- * names. This function will infer the rest of the URL.
- */
 int
-uri_create_mft(struct rpki_uri **result, struct rpki_uri *mft, IA5String_t *ia5,
-    bool use_rrdp_workspace)
+uri_create_mft(struct rpki_uri *mft, IA5String_t *file,
+    struct rpki_uri **result)
 {
        struct rpki_uri *uri;
-       uint8_t flags;
+       char *global;
        int error;
 
-       uri = malloc(sizeof(struct rpki_uri));
-       if (uri == NULL)
-               return pr_enomem();
-
-       error = ia5str2global(uri, mft->global, ia5);
-       if (error) {
-               free(uri);
+       error = create_neighbor(uri_get_global(mft), file, &global);
+       if (error)
                return error;
-       }
 
-       flags = URI_VALID_RSYNC;
-       if (use_rrdp_workspace)
-               flags |= URI_USE_RRDP_WORKSPACE;
+       uri = __uri_create(global, URI_TYPE_VOID);
+       if (uri == NULL)
+               return pr_enomem();
 
-       error = autocomplete_local(uri, flags);
+       error = create_neighbor(uri_get_local(mft), file, &uri->local);
        if (error) {
-               free(uri->global);
-               free(uri);
+               uri_refput(uri);
                return error;
        }
 
-       uri->references = 1;
        *result = uri;
        return 0;
 }
 
-/*
- * Create @uri from the @ad, validating that the uri is of type(s) indicated
- * at @flags (can be URI_VALID_RSYNC and/or URI_VALID_HTTPS)
- */
-int
-uri_create_ad(struct rpki_uri **uri, ACCESS_DESCRIPTION *ad, int flags)
-{
-       ASN1_STRING *asn1_string;
-       int type;
-
-       asn1_string = GENERAL_NAME_get0_value(ad->location, &type);
-
-       /*
-        * 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 in the ass. So this is what I'm committing
-        * to.
-        */
-       if (type != GEN_URI) {
-               pr_val_err("Unknown GENERAL_NAME type: %d", type);
-               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.
-        *
-        * 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.
-        */
-       return uri_create(uri, flags,
-           ASN1_STRING_get0_data(asn1_string),
-           ASN1_STRING_length(asn1_string));
-}
-
 void
 uri_refget(struct rpki_uri *uri)
 {
@@ -519,43 +198,47 @@ uri_refput(struct rpki_uri *uri)
        }
 }
 
+/*
+ * This function only really makes sense during or after the file download.
+ * Otherwise it'll just return the arbitrary first global.
+ *
+ * Note, if you're trying to print the URI, then you should most likely use
+ * uri_*_get_printable() instead.
+ */
 char const *
 uri_get_global(struct rpki_uri *uri)
 {
        return uri->global;
 }
 
+/* Can return NULL. TODO (aaaa) Review callers. */
 char const *
 uri_get_local(struct rpki_uri *uri)
 {
        return uri->local;
 }
 
-size_t
-uri_get_global_len(struct rpki_uri *uri)
-{
-       return uri->global_len;
-}
-
-bool
-uri_equals(struct rpki_uri *u1, struct rpki_uri *u2)
+enum rpki_uri_type
+uri_get_type(struct rpki_uri *uri)
 {
-       return strcmp(u1->global, u2->global) == 0;
+       return uri->type;
 }
 
 /* @ext must include the period. */
 bool
 uri_has_extension(struct rpki_uri *uri, char const *ext)
 {
+       char const *global;
+       size_t global_len;
        size_t ext_len;
-       int cmp;
 
+       global = uri_get_global(uri);
+       global_len = strlen(global);
        ext_len = strlen(ext);
-       if (uri->global_len < ext_len)
+       if (global_len < ext_len)
                return false;
 
-       cmp = strncmp(uri->global + uri->global_len - ext_len, ext, ext_len);
-       return cmp == 0;
+       return strncmp(global + global_len - ext_len, ext, ext_len) == 0;
 }
 
 bool
@@ -564,17 +247,13 @@ uri_is_certificate(struct rpki_uri *uri)
        return uri_has_extension(uri, ".cer");
 }
 
-bool
-uri_is_rsync(struct rpki_uri *uri)
-{
-       return uri->type == URI_RSYNC;
-}
-
 static char const *
-get_filename(char const *file_path)
+get_file_name(struct rpki_uri *uri)
 {
-       char *slash = strrchr(file_path, '/');
-       return (slash != NULL) ? (slash + 1) : file_path;
+       char const *global, *slash;
+       global = uri_get_global(uri);
+       slash = strrchr(global, '/');
+       return (slash == NULL) ? global : (slash + 1);
 }
 
 static char const *
@@ -582,11 +261,11 @@ uri_get_printable(struct rpki_uri *uri, enum filename_format format)
 {
        switch (format) {
        case FNF_GLOBAL:
-               return uri->global;
+               return uri_get_global(uri);
        case FNF_LOCAL:
-               return uri->local;
+               return uri_get_local(uri);
        case FNF_NAME:
-               return get_filename(uri->global);
+               return get_file_name(uri);
        }
 
        pr_crit("Unknown file name format: %u", format);
index f7fe5d0be4a1676cbdb7cb0c177b959c581b43ec..73a52547d711f60d7aed7240c5d8b7f015bc64eb 100644 (file)
@@ -2,43 +2,48 @@
 #define SRC_TYPES_URI_H_
 
 #include <stdbool.h>
-#include <openssl/x509v3.h>
+#include "file.h"
 #include "asn1/asn1c/IA5String.h"
 
-/* Flags to indicate expected uri type */
-#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
+#define URI_ALLOW_RSYNC (1 << 0)
+#define URI_ALLOW_HTTP (1 << 1)
 
-#define ESKIP 85830
+#define ENOTCHANGED 95094509
 
 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_mixed_str(struct rpki_uri **, char const *, size_t);
-int uri_create_mft(struct rpki_uri **, struct rpki_uri *, IA5String_t *, bool);
-int uri_create_ad(struct rpki_uri **, ACCESS_DESCRIPTION *, int);
+/*
+ * Straightforward HTTP = Downloads with no fuss.
+ *
+ * Caged HTTP = Downloads into a Notification-specific namespace. See
+ * https://mailarchive.ietf.org/arch/msg/sidrops/FrAjMFWY5a_cofpOoCEO5Yr_ZLI/
+ */
+enum rpki_uri_type {
+       /* rsync or straightforward HTTP */
+       URI_TYPE_VERSATILE,
+       /* rsync only */
+       URI_TYPE_RSYNC,
+       /* Straightforward HTTP only */
+       URI_TYPE_HTTP_SIMPLE,
+       /* Caged HTTP only */
+       URI_TYPE_HTTP_CAGED,
+       /* Never downloaded (simply used to reference some other rpki_uri) */
+       URI_TYPE_VOID,
+};
+
+int uri_create(char *, enum rpki_uri_type, struct rpki_uri **);
+int uri_create_caged(char *, struct rpki_uri *, struct rpki_uri **);
+int uri_create_mft(struct rpki_uri *, IA5String_t *, struct rpki_uri **);
 
 void uri_refget(struct rpki_uri *);
 void uri_refput(struct rpki_uri *);
 
-/*
- * Note that, if you intend to print some URI, you're likely supposed to use
- * uri_get_printable() instead.
- */
 char const *uri_get_global(struct rpki_uri *);
 char const *uri_get_local(struct rpki_uri *);
-size_t uri_get_global_len(struct rpki_uri *);
+enum rpki_uri_type uri_get_type(struct rpki_uri *);
 
-bool uri_equals(struct rpki_uri *, struct rpki_uri *);
 bool uri_has_extension(struct rpki_uri *, char const *);
 bool uri_is_certificate(struct rpki_uri *);
-bool uri_is_rsync(struct rpki_uri *);
 
 char const *uri_val_get_printable(struct rpki_uri *);
 char const *uri_op_get_printable(struct rpki_uri *);
diff --git a/src/types/uri_list.c b/src/types/uri_list.c
new file mode 100644 (file)
index 0000000..bc16ac0
--- /dev/null
@@ -0,0 +1,160 @@
+#include "types/uri_list.h"
+
+#include "random.h"
+#include "http/http.h"
+#include "rrdp/rrdp.h"
+#include "rsync/rsync.h"
+
+DEFINE_ARRAY_LIST_FUNCTIONS(uri_list, struct rpki_uri *, static)
+
+void
+uris_init(struct uri_list *uris)
+{
+       uri_list_init(uris);
+}
+
+static void
+__uri_refput(struct rpki_uri **uri)
+{
+       uri_refput(*uri);
+}
+
+void
+uris_cleanup(struct uri_list *uris)
+{
+       uri_list_cleanup(uris, __uri_refput);
+}
+
+int
+uris_add(struct uri_list *uris, struct rpki_uri *uri)
+{
+       return uri_list_add(uris, &uri);
+}
+
+/* Steals ownership of @str on success. */
+int
+uris_add_str(struct uri_list *uris, char *str, enum rpki_uri_type type)
+{
+       struct rpki_uri *addend;
+       int error;
+
+       error = uri_create(str, type, &addend);
+       if (error)
+               return error;
+
+       return uris_add(uris, addend);
+}
+
+bool
+uris_contains(struct uri_list *list, struct rpki_uri *uri)
+{
+       char const *guri;
+       struct rpki_uri **node;
+       size_t n;
+
+       guri = uri_get_global(uri);
+
+       ARRAYLIST_FOREACH(list, node, n)
+               if (strcmp(guri, uri_get_global(*node)) == 0)
+                       return true;
+
+       return false;
+}
+
+static bool
+starts_with(char const *global, char const *prefix)
+{
+       size_t global_len;
+       size_t prefix_len;
+
+       global_len = strlen(global);
+       prefix_len = strlen(prefix);
+
+       return (global_len < prefix_len)
+           ? false
+           : (strncmp(global, prefix, prefix_len) == 0);
+}
+
+static bool
+is_http(char const *global)
+{
+       return starts_with(global, "https://") ||
+              starts_with(global, "http://");
+}
+
+static bool
+is_rsync(char const *global)
+{
+       return starts_with(global, "rsync://");
+}
+
+static int
+http_update(struct rpki_uri *uri)
+{
+       return http_get(uri, file_get_modification_time(uri_get_local(uri)));
+}
+
+static struct rpki_uri *
+try_download(struct uri_list *uris, bool try_rrdp, bool try_rsync)
+{
+       struct rpki_uri **__uri;
+       struct rpki_uri *uri;
+       char const *guri;
+       size_t u;
+
+       ARRAYLIST_FOREACH(uris, __uri, u) {
+               uri = *__uri;
+               guri = uri_get_global(uri);
+
+               if (try_rrdp && is_http(guri)) {
+                       if (uri_get_type(uri) == URI_TYPE_VERSATILE) {
+                               if (http_update(uri) == 0)
+                                       return uri;
+                       } else {
+                               if (rrdp_update(uri) == 0)
+                                       return uri;
+                       }
+               }
+               if (try_rsync && is_rsync(guri)) {
+                       if (rsync_download_files(uri, false) == 0)
+                               return 0;
+               }
+       }
+
+       return NULL;
+}
+
+/*
+ * Updates the local/cached/cloned version of the content pointed by @uris.
+ * Will download the files, unless it realizes the cache is already up-to-date.
+ * Stops on (and returns) the first success.
+ *
+ * Assumes the parent certificate has already been added to the trusted stack.
+ */
+struct rpki_uri *
+uris_download(struct uri_list *uris)
+{
+       struct rpki_uri *result;
+
+       if (config_get_http_priority() > config_get_rsync_priority()) {
+               result = try_download(uris, true, false);
+               if (result != NULL)
+                       return result;
+               pr_val_debug("RRDP didn't work. Trying rsync...");
+               result = try_download(uris, false, true);
+
+       } else if (config_get_http_priority() < config_get_rsync_priority()) {
+               result = try_download(uris, false, true);
+               if (result != NULL)
+                       return result;
+               pr_val_debug("rsync didn't work. Trying RRDP...");
+               result = try_download(uris, true, false);
+
+       } else {
+               result = try_download(uris, true, true);
+       }
+
+       if (result == NULL)
+               pr_val_err("None of the URLs yielded a successful download.");
+       return result;
+}
diff --git a/src/types/uri_list.h b/src/types/uri_list.h
new file mode 100644 (file)
index 0000000..951944e
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef SRC_TYPES_URI_LIST_H_
+#define SRC_TYPES_URI_LIST_H_
+
+#include "types/uri.h"
+#include "data_structure/array_list.h"
+
+DEFINE_ARRAY_LIST_STRUCT(uri_list, struct rpki_uri *);
+
+void uris_init(struct uri_list *);
+void uris_cleanup(struct uri_list *);
+
+int uris_add(struct uri_list *, struct rpki_uri *);
+int uris_add_str(struct uri_list *uri, char *str, enum rpki_uri_type type);
+
+bool uris_contains(struct uri_list *, struct rpki_uri *);
+struct rpki_uri *uris_download(struct uri_list *);
+
+#endif /* SRC_TYPES_URI_LIST_H_ */
index fd58b72eb2ddfd6259cda369f2c5bfff095cb968..8537819a20121cfb25836f3aca085f93654e1ea5 100644 (file)
@@ -7,13 +7,9 @@
 static int
 get_current_threads_handler(struct validation_handler const **result)
 {
-       struct validation *state;
        struct validation_handler const *handler;
 
-       state = state_retrieve();
-       if (state == NULL)
-               return -EINVAL;
-       handler = validation_get_validation_handler(state);
+       handler = validation_get_validation_handler(state_retrieve());
        if (handler == NULL)
                pr_crit("This thread lacks a validation handler.");
 
index 542a64f03da98e890308145b42607fbfb5ca1016..71870535e3d455a4ebd68566f62d9c03565750ce 100644 (file)
@@ -6,19 +6,10 @@
 #include "object/name.h"
 
 /**
- * Functions that handle validation results.
+ * Functions that handle validation results. It's currently variable so unit
+ * tests can easily check traversal.
  *
- * At some point, I believe we will end up separating the validator code into a
- * library, so it can be used by other applications aside from Fort's RTR
- * server.
- *
- * This structure is designed with that in mind; it's the callback collection
- * that the library's user application will fill up, so it can do whatever it
- * wants with the validated ROAs.
- *
- * Because it's intended to be used by arbitrary applications, it needs to be
- * generic. Please refrain from adding callbacks that are specifically meant for
- * a particular use case.
+ * TODO (fine) Review that. It clutters the code too much IMO.
  *
  * All of these functions can be NULL.
  */
diff --git a/src/visited_uris.c b/src/visited_uris.c
deleted file mode 100644 (file)
index 987c735..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-#include "visited_uris.h"
-
-#include <sys/queue.h>
-#include <stddef.h>
-#include <string.h>
-#include "log.h"
-#include "delete_dir_daemon.h"
-#include "data_structure/array_list.h"
-#include "data_structure/uthash_nonfatal.h"
-
-struct visited_elem {
-       /* key */
-       char *uri;
-       UT_hash_handle hh;
-};
-
-struct visited_uris {
-       struct visited_elem *table;
-       unsigned int refs;
-};
-
-DEFINE_ARRAY_LIST_STRUCT(uris_roots, char *);
-DEFINE_ARRAY_LIST_FUNCTIONS(uris_roots, char *, static)
-
-static int
-visited_elem_create(struct visited_elem **elem, char const *uri)
-{
-       struct visited_elem *tmp;
-
-       tmp = malloc(sizeof(struct visited_elem));
-       if (tmp == NULL)
-               return pr_enomem();
-       /* Needed by uthash */
-       memset(tmp, 0, sizeof(struct visited_elem));
-
-       tmp->uri = strdup(uri);
-       if (tmp->uri == NULL) {
-               free(tmp);
-               return pr_enomem();
-       }
-
-       *elem = tmp;
-       return 0;
-}
-
-static void
-visited_elem_destroy(struct visited_elem *elem)
-{
-       free(elem->uri);
-       free(elem);
-}
-
-int
-visited_uris_create(struct visited_uris **uris)
-{
-       struct visited_uris *tmp;
-
-       tmp = malloc(sizeof(struct visited_uris));
-       if (tmp == NULL)
-               return pr_enomem();
-
-       tmp->table = NULL;
-       tmp->refs = 1;
-
-       *uris = tmp;
-       return 0;
-}
-
-static void
-visited_uris_destroy(struct visited_uris *uris)
-{
-       struct visited_elem *elm_node, *elm_tmp;
-
-       HASH_ITER(hh, uris->table, elm_node, elm_tmp) {
-               HASH_DEL(uris->table, elm_node);
-               visited_elem_destroy(elm_node);
-       }
-       free(uris);
-}
-
-void
-visited_uris_refget(struct visited_uris *uris)
-{
-       uris->refs++;
-}
-
-void
-visited_uris_refput(struct visited_uris *uris)
-{
-       uris->refs--;
-       if (uris->refs == 0)
-               visited_uris_destroy(uris);
-}
-
-static struct visited_elem *
-elem_find(struct visited_uris *list, char const *uri)
-{
-       struct visited_elem *found;
-       HASH_FIND_STR(list->table, uri, found);
-       return found;
-}
-
-int
-visited_uris_add(struct visited_uris *uris, char const *uri)
-{
-       struct visited_elem *elem;
-       int error;
-
-       if (elem_find(uris, uri) != NULL)
-               return 0; /* Exists, don't add again */
-
-       elem = NULL;
-       error = visited_elem_create(&elem, uri);
-       if (error)
-               return error;
-
-       HASH_ADD_KEYPTR(hh, uris->table, elem->uri, strlen(elem->uri),
-           elem);
-
-       return 0;
-}
-
-int
-visited_uris_remove(struct visited_uris *uris, char const *uri)
-{
-       struct visited_elem *elem;
-
-       elem = elem_find(uris, uri);
-       if (elem == NULL)
-               return pr_val_err("Trying to remove a nonexistent URI '%s'", uri);
-
-       HASH_DEL(uris->table, elem);
-       visited_elem_destroy(elem);
-
-       return 0;
-}
-
-static int
-visited_uris_to_arr(struct visited_uris *uris, struct uris_roots *roots)
-{
-       struct visited_elem *elem;
-       char *tmp, *last_slash;
-       size_t size;
-
-       for (elem = uris->table; elem != NULL; elem = elem->hh.next) {
-               last_slash = strrchr(elem->uri, '/');
-               size = last_slash - elem->uri;
-               tmp = malloc(size + 1);
-               if (tmp == NULL)
-                       return pr_enomem();
-               strncpy(tmp, elem->uri, size);
-               tmp[size] = '\0';
-               uris_roots_add(roots, &tmp);
-       }
-
-       return 0;
-}
-
-static void
-uris_root_destroy(char **elem)
-{
-       free(*elem);
-}
-
-/*
- * Delete all the corresponding local files of @uris located at @workspace
- */
-int
-visited_uris_delete_local(struct visited_uris *uris, char const *workspace)
-{
-       struct uris_roots roots;
-       int error;
-
-       uris_roots_init(&roots);
-
-       error = visited_uris_to_arr(uris, &roots);
-       if (error)
-               goto err;
-
-       if (roots.len == 0)
-               goto success;
-
-       error = delete_dir_daemon_start(roots.array, roots.len, workspace);
-       if (error)
-               goto err;
-success:
-       uris_roots_cleanup(&roots, uris_root_destroy);
-       return 0;
-err:
-       uris_roots_cleanup(&roots, uris_root_destroy);
-       return error;
-}
diff --git a/src/visited_uris.h b/src/visited_uris.h
deleted file mode 100644 (file)
index 9557482..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef SRC_VISITED_URIS_H_
-#define SRC_VISITED_URIS_H_
-
-struct visited_uris;
-
-int visited_uris_create(struct visited_uris **);
-void visited_uris_refput(struct visited_uris *);
-void visited_uris_refget(struct visited_uris *);
-
-int visited_uris_add(struct visited_uris *, char const *);
-int visited_uris_remove(struct visited_uris *, char const *);
-int visited_uris_delete_local(struct visited_uris *, char const *);
-
-#endif /* SRC_VISITED_URIS_H_ */
index c35e5a4d7681ac35ee17899be56f559807bb0ce2..05413150a6f810d8971afa6d6e6dce8c7636d5ca 100644 (file)
@@ -1,4 +1,4 @@
-#include "relax_ng.h"
+#include "xml/relax_ng.h"
 
 #include <libxml/parser.h>
 #include <libxml/relaxng.h>
@@ -79,20 +79,22 @@ cleanup_parser:
 }
 
 /*
- * Validate file at @path against globally loaded schema. The file must be
+ * Validate file at @uri against globally loaded schema. The file must be
  * parsed using @cb (will receive @arg as argument).
  */
 int
-relax_ng_parse(const char *path, xml_read_cb cb, void *arg)
+relax_ng_parse(struct rpki_uri *uri, xml_read_cb cb, void *arg)
 {
        xmlTextReaderPtr reader;
        xmlRelaxNGValidCtxtPtr rngvalidctx;
        int read;
        int error;
 
-       reader = xmlNewTextReaderFilename(path);
-       if (reader == NULL)
-               return pr_val_err("Couldn't get XML '%s' file.", path);
+       reader = xmlNewTextReaderFilename(uri_get_local(uri));
+       if (reader == NULL) {
+               return pr_val_err("Couldn't get XML '%s' file.",
+                   uri_get_local(uri));
+       }
 
        error = xmlTextReaderRelaxNGSetSchema(reader, schema);
        if (error) {
@@ -156,3 +158,28 @@ relax_ng_cleanup(void)
        xmlRelaxNGFreeParserCtxt(rngparser);
        xmlCleanupParser();
 }
+
+int
+xml_parse_long(xmlTextReaderPtr reader, char const *attr, unsigned long *result)
+{
+       xmlChar *xml_value;
+       unsigned long tmp;
+
+       xml_value = xmlTextReaderGetAttribute(reader, BAD_CAST attr);
+       if (xml_value == NULL)
+               return pr_val_err("RRDP file: Couldn't find xml attribute '%s'",
+                   attr);
+
+       errno = 0;
+       tmp = strtoul((char *) xml_value, NULL, 10);
+       if (errno) {
+               xmlFree(xml_value);
+               pr_val_errno(errno, "RRDP file: Invalid long value '%s'",
+                   xml_value);
+               return -EINVAL;
+       }
+       xmlFree(xml_value);
+
+       (*result) = tmp;
+       return 0;
+}
index 4a3f780a91fa0bbadb538c8975936915410b210b..a4e5e4edd8cb1a2eea0ba5d378deded2036d5bd5 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <libxml/xmlreader.h>
 #include <string.h>
+#include "types/uri.h"
 
 /*
  * Schema obtained from RFC 8182, converted using the tool rnc2rng
@@ -167,6 +168,8 @@ int relax_ng_init(void);
 void relax_ng_cleanup(void);
 
 typedef int (*xml_read_cb)(xmlTextReaderPtr, void *);
-int relax_ng_parse(const char *, xml_read_cb cb, void *);
+int relax_ng_parse(struct rpki_uri *, xml_read_cb cb, void *);
+
+int xml_parse_long(xmlTextReaderPtr, char const *, unsigned long *);
 
 #endif /* SRC_XML_RELAX_NG_H_ */
index 7ccf6496a86865d0fbfd7d8454a145ff549a7ecd..9a0ec6867053375e375845a2e6636e8eb2469372 100644 (file)
@@ -76,7 +76,7 @@ config_get_local_repository(void)
 enum rsync_strategy
 config_get_rsync_strategy(void)
 {
-       return RSYNC_ROOT;
+       return RSYNC_STRICT;
 }
 
 bool
index d6d41a5b4ad26c17f1ac7f73debabb64442d6435..4dedf976e12a1d19a7f40cfe7c155ab0b0c2926f 100644 (file)
@@ -4,26 +4,26 @@
 
 #include "impersonator.c"
 #include "log.c"
-#include "rrdp/rrdp_objects.c"
+#include "rrdp/notification.c"
 
 #define END 0xFFFF
 
 static void
-add_serials(struct deltas_head *deltas, ...)
+add_serials(struct rrdp_notification_deltas *deltas, ...)
 {
-       struct delta_head delta;
+       struct rrdp_notification_delta delta;
        va_list vl;
 
-       doc_data_init(&delta.doc_data);
+       rrdp_file_metadata_init(&delta.meta);
 
        va_start(vl, deltas);
        while ((delta.serial = va_arg(vl, unsigned long)) != END)
-               ck_assert_int_eq(0, deltas_head_add(deltas, &delta));
+               ck_assert_int_eq(0, rrdp_notification_deltas_add(deltas, &delta));
        va_end(vl);
 }
 
 static void
-validate_serials(struct deltas_head *deltas, ...)
+validate_serials(struct rrdp_notification_deltas *deltas, ...)
 {
        unsigned long serial;
        unsigned int i;
@@ -42,7 +42,7 @@ validate_serials(struct deltas_head *deltas, ...)
 
 START_TEST(test_deltas_head_sort)
 {
-       struct deltas_head deltas;
+       struct rrdp_notification_deltas deltas;
 
        deltas_head_init(&deltas);
        ck_assert_int_eq(0, deltas_head_sort(&deltas, 0));
index ad4a9efe85d212f084ddcd192fe5ae97b8176dd5..62ffef41a9b15be388941b3fea3d86971ab40937 100644 (file)
@@ -22,10 +22,8 @@ assert_descendant(bool expected, char *ancestor, char *descendant)
        struct rpki_uri *ancestor_uri;
        struct rpki_uri *descendant_uri;
 
-       ck_assert_int_eq(0, uri_create_rsync_str(&ancestor_uri, ancestor,
-           strlen(ancestor)));
-       ck_assert_int_eq(0, uri_create_rsync_str(&descendant_uri, descendant,
-           strlen(descendant)));
+       ck_assert_int_eq(0, uri_create_rsync(&ancestor_uri, ancestor));
+       ck_assert_int_eq(0, uri_create_rsync(&descendant_uri, descendant));
 
        ck_assert_int_eq(is_descendant(ancestor_uri, descendant_uri), expected);
 
@@ -57,7 +55,7 @@ static void
 __mark_as_downloaded(char *uri_str, struct uri_list *visited_uris)
 {
        struct rpki_uri *uri;
-       ck_assert_int_eq(0, uri_create_rsync_str(&uri, uri_str, strlen(uri_str)));
+       ck_assert_int_eq(0, uri_create_rsync(&uri, uri_str));
        ck_assert_int_eq(mark_as_downloaded(uri, visited_uris), 0);
        uri_refput(uri);
 }
@@ -66,7 +64,7 @@ static void
 assert_downloaded(char *uri_str, struct uri_list *visited_uris, bool expected)
 {
        struct rpki_uri *uri;
-       ck_assert_int_eq(0, uri_create_rsync_str(&uri, uri_str, strlen(uri_str)));
+       ck_assert_int_eq(0, uri_create_rsync(&uri, uri_str));
        ck_assert_int_eq(is_already_downloaded(uri, visited_uris), expected);
        uri_refput(uri);
 }
@@ -107,7 +105,7 @@ test_root_strategy(char *test, char *expected)
        struct rpki_uri *src;
        struct rpki_uri *dst;
 
-       ck_assert_int_eq(0, uri_create_rsync_str(&src, test, strlen(test)));
+       ck_assert_int_eq(0, uri_create_rsync(&src, test));
        ck_assert_int_eq(handle_root_strategy(src, &dst), 0);
        ck_assert_str_eq(uri_get_global(dst), expected);
 
index 0f7399aba1b11e620dc1548b7f044ce56ed4672b..7079a5d00f6822cb07f9d25a9146d96c054394f7 100644 (file)
@@ -58,7 +58,7 @@ close_thread(pthread_t thread, char const *what)
 }
 
 int
-map_uri_to_local(char const *uri, char const *uri_prefix, char const *workspace,
+autocomplete_local_rsync(char const *uri, char const *uri_prefix, char const *workspace,
     char **result)
 {
        /* These tests focus on global URIs, so set a dummy value */