]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Automatically download if file is an rsync URL
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Fri, 10 May 2024 21:05:30 +0000 (15:05 -0600)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Fri, 10 May 2024 21:05:30 +0000 (15:05 -0600)
rsync cannot download into standard output... which means rsync'd files
cannot be elegantly piped as standard output to --mode=print. So either
the rsync has to be done manually by the user... or --mode=print has to
do it internally by itself.

And looking at the code that resulted... I now wish I had gone with the
former option. Because of the long overdue cache refactors, the user
needs to include --tal for this rsync to be compatible with the cache.
This sucks.

As a workaround, Fort will rsync into /tmp if --tal and/or --local-cache
aren't supplied:

$ fort --mode=print \
--validation-log.enabled \
--validation-log.level debug \
rsync://a.b.c/d/CRL.crl
...
May 10 13:32:44 DBG [Validation]: Executing rsync:
May 10 13:32:44 DBG [Validation]:     rsync
May 10 13:32:44 DBG [Validation]:     ...
May 10 13:32:44 DBG [Validation]:     rsync://a.b.c/d/CRL.crl
May 10 13:32:44 DBG [Validation]:     /tmp/fort-Q7tMhz/CRL.crl
...
{
"tbsCertList": {
"version": 1,
...

src/cache/local_cache.c
src/print_file.c
src/rsync/rsync.c
src/rsync/rsync.h

index 86e981b0df5ed72b9bf4d04bbc9585bede218c85..5ea743a587ee1e0c80045d10997a076101a6acac 100644 (file)
@@ -595,7 +595,7 @@ cache_download(struct rpki_cache *cache, struct rpki_uri *uri, bool *changed)
        switch (uri_get_type(url)) {
        case UT_RSYNC:
                error = config_get_rsync_enabled()
-                   ? rsync_download(url)
+                   ? rsync_download(uri_get_global(url), uri_get_local(url), true)
                    : cache_check(url);
                break;
        case UT_HTTPS:
index c16aff73b8498ebbc3be41d0a1876a5a983e80a5..3a1cb1b3233d0738ce97f1a708d299336fe5611a 100644 (file)
@@ -1,6 +1,8 @@
 #include "print_file.h"
 
 #include <errno.h>
+#include <stdlib.h>
+
 #include "common.h"
 #include "config.h"
 #include "file.h"
 #include "asn1/content_info.h"
 #include "asn1/asn1c/Certificate.h"
 #include "asn1/asn1c/CRL.h"
+#include "data_structure/path_builder.h"
+#include "rsync/rsync.h"
 #include "types/bio_seq.h"
+#include "types/uri.h"
 
 #define HDRSIZE 32
 
+static BIO *
+__rsync2bio(char const *src, char const *dst)
+{
+       int error;
+
+       error = rsync_download(src, dst, false);
+       if (error) {
+               pr_op_err("rysnc download failed: %s", strerror(abs(error)));
+               return NULL;
+       }
+
+       return BIO_new_file(dst, "rb");
+}
+
+static BIO *
+rsync2bio_tmpdir(char const *src)
+{
+#define TMPDIR "/tmp/fort-XXXXXX"
+
+       struct path_builder pb;
+       char buf[strlen(TMPDIR) + 1];
+       char *tmpdir;
+       BIO *result = NULL;
+       int error;
+
+       strcpy(buf, TMPDIR);
+       tmpdir = mkdtemp(buf);
+       if (tmpdir == NULL) {
+               pr_op_err("Unable to create " TMPDIR ": %s", strerror(errno));
+               return NULL;
+       }
+
+       pb_init(&pb);
+       error = pb_append(&pb, tmpdir);
+       if (error)
+               goto end;
+       error = pb_append(&pb, strrchr(src, '/') + 1);
+       if (error)
+               goto end;
+
+       result = __rsync2bio(src, pb.string);
+
+end:   pb_cleanup(&pb);
+       return result;
+}
+
+static BIO *
+rsync2bio_cache(char const *src)
+{
+       char const *tal;
+       struct rpki_uri *uri;
+       BIO *bio;
+       int error;
+
+       tal = strrchr(config_get_tal(), '/');
+       tal = (tal != NULL) ? (tal + 1) : config_get_tal();
+       uri = NULL;
+
+       error = uri_create(&uri, tal, UT_RSYNC, false, NULL, src);
+       if (error) {
+               pr_op_err("Unparseable rsync URI: %s", strerror(abs(error)));
+               return NULL;
+       }
+
+       bio = __rsync2bio(uri_get_global(uri), uri_get_local(uri));
+
+       uri_refput(uri);
+       return bio;
+}
+
+static BIO *
+rsync2bio(char const *src)
+{
+       return (config_get_tal() && config_get_local_repository())
+            ? rsync2bio_cache(src)
+            : rsync2bio_tmpdir(src);
+}
+
+static BIO *
+filename2bio(char const *filename)
+{
+       if (filename == NULL || strcmp(filename, "-") == 0)
+               return BIO_new_fp(stdin, BIO_NOCLOSE);
+
+       if (str_starts_with(filename, "rsync://"))
+               return rsync2bio(filename);
+
+       return BIO_new_file(filename, "rb");
+}
+
 static unsigned char *
 skip_sequence(unsigned char *buf, unsigned char *cursor)
 {
@@ -160,16 +255,12 @@ asn1c2json(BIO *bio)
 static int
 __print_file(void)
 {
-       char const *filename;
        BIO *bio;
        unsigned char hdrbuf[HDRSIZE];
        json_t *json = NULL;
        int error;
 
-       filename = config_get_payload();
-       bio = (filename == NULL || strcmp(filename, "-") == 0)
-           ? BIO_new_fp(stdin, BIO_NOCLOSE)
-           : BIO_new_file(filename, "rb");
+       bio = filename2bio(config_get_payload());
        if (bio == NULL)
                return pr_op_err("BIO_new_*() returned NULL.");
 
index 08cb887ae112e5a800909eb34dc9e9bcb052e9c9..2425a95bf6b507cd6d108318e71ff92739c3e90c 100644 (file)
@@ -43,7 +43,7 @@ release_args(char **args, unsigned int size)
 }
 
 static void
-prepare_rsync(struct rpki_uri *uri, char ***args, size_t *args_len)
+prepare_rsync(char const *src, char const *dst, char ***args, size_t *args_len)
 {
        struct string_array const *config_args;
        char **copy_args;
@@ -65,9 +65,9 @@ prepare_rsync(struct rpki_uri *uri, char ***args, size_t *args_len)
 
        for (i = 0; i < config_args->length; i++) {
                if (strcmp(config_args->array[i], "$REMOTE") == 0)
-                       copy_args[i + 1] = pstrdup(uri_get_global(uri));
+                       copy_args[i + 1] = pstrdup(src);
                else if (strcmp(config_args->array[i], "$LOCAL") == 0)
-                       copy_args[i + 1] = pstrdup(uri_get_local(uri));
+                       copy_args[i + 1] = pstrdup(dst);
                else
                        copy_args[i + 1] = pstrdup(config_args->array[i]);
        }
@@ -203,10 +203,11 @@ read_pipes(int fds[2][2])
 }
 
 /*
- * Downloads the @uri->global file into the @uri->local path.
+ * Downloads @src @dst. @src is supposed to be an rsync URL, and @dst is
+ * supposed to be a filesystem path.
  */
 int
-rsync_download(struct rpki_uri *uri)
+rsync_download(char const *src, char const *dst, bool is_directory)
 {
        char **args;
        size_t args_len;
@@ -221,16 +222,16 @@ rsync_download(struct rpki_uri *uri)
        /* Prepare everything for the child exec */
        args = NULL;
        args_len = 0;
-       prepare_rsync(uri, &args, &args_len);
+       prepare_rsync(src, dst, &args, &args_len);
 
-       pr_val_info("rsync: %s", uri_get_global(uri));
+       pr_val_info("rsync: %s", src);
        if (log_val_enabled(LOG_DEBUG)) {
                pr_val_debug("Executing rsync:");
                for (i = 0; i < args_len + 1; i++)
                        pr_val_debug("    %s", args[i]);
        }
 
-       error = mkdir_p(uri_get_local(uri), true);
+       error = mkdir_p(dst, is_directory);
        if (error)
                goto release_args;
 
@@ -300,12 +301,12 @@ rsync_download(struct rpki_uri *uri)
                        if (retries == config_get_rsync_retry_count()) {
                                if (retries > 0)
                                        pr_val_warn("Max RSYNC retries (%u) reached on '%s', won't retry again.",
-                                           retries, uri_get_global(uri));
+                                           retries, src);
                                error = EIO;
                                goto release_args;
                        }
                        pr_val_warn("Retrying RSYNC '%s' in %u seconds, %u attempts remaining.",
-                           uri_get_global(uri),
+                           src,
                            config_get_rsync_retry_interval(),
                            config_get_rsync_retry_count() - retries);
                        retries++;
index a80ea5cb09f45387bfe97af60d492453cd23069d..3476c9c0de6c97c705fedd224e1fb626e9b14bd3 100644 (file)
@@ -1,8 +1,8 @@
 #ifndef SRC_RSYNC_RSYNC_H_
 #define SRC_RSYNC_RSYNC_H_
 
-#include "types/uri.h"
+#include <stdbool.h>
 
-int rsync_download(struct rpki_uri *);
+int rsync_download(char const *, char const *, bool);
 
 #endif /* SRC_RSYNC_RSYNC_H_ */