From: Alberto Leiva Popper Date: Fri, 10 May 2024 21:05:30 +0000 (-0600) Subject: Automatically download if file is an rsync URL X-Git-Tag: 1.6.2~20 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2b3ed8c6c10694cd7acc4ea9164e6568e49f3753;p=thirdparty%2FFORT-validator.git Automatically download if file is an rsync URL 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, ... --- diff --git a/src/cache/local_cache.c b/src/cache/local_cache.c index 86e981b0..5ea743a5 100644 --- a/src/cache/local_cache.c +++ b/src/cache/local_cache.c @@ -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: diff --git a/src/print_file.c b/src/print_file.c index c16aff73..3a1cb1b3 100644 --- a/src/print_file.c +++ b/src/print_file.c @@ -1,6 +1,8 @@ #include "print_file.h" #include +#include + #include "common.h" #include "config.h" #include "file.h" @@ -8,10 +10,103 @@ #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."); diff --git a/src/rsync/rsync.c b/src/rsync/rsync.c index 08cb887a..2425a95b 100644 --- a/src/rsync/rsync.c +++ b/src/rsync/rsync.c @@ -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++; diff --git a/src/rsync/rsync.h b/src/rsync/rsync.h index a80ea5cb..3476c9c0 100644 --- a/src/rsync/rsync.h +++ b/src/rsync/rsync.h @@ -1,8 +1,8 @@ #ifndef SRC_RSYNC_RSYNC_H_ #define SRC_RSYNC_RSYNC_H_ -#include "types/uri.h" +#include -int rsync_download(struct rpki_uri *); +int rsync_download(char const *, char const *, bool); #endif /* SRC_RSYNC_RSYNC_H_ */