From 0d2f2bc8dd0a495b75fe1b353ce8b9b59e20dc6f Mon Sep 17 00:00:00 2001 From: dhfelix Date: Fri, 14 Dec 2018 16:48:40 -0600 Subject: [PATCH] Add rsync command execution to download repositories First version of the code, when executing the app, if a 4th arg is detected, the app will not run rsync. Maybe I need to replace the "system()" call with another function to execute the "rsync command" Also needs to read the "rsync command" from a user JSON configuration file. --- src/Makefile.am | 2 + src/main.c | 14 ++ src/object/certificate.c | 50 ++++- src/rsync/rsync.c | 433 +++++++++++++++++++++++++++++++++++++++ src/rsync/rsync.h | 11 + 5 files changed, 499 insertions(+), 11 deletions(-) create mode 100644 src/rsync/rsync.c create mode 100644 src/rsync/rsync.h diff --git a/src/Makefile.am b/src/Makefile.am index 23378d80..6e6149e9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,6 +17,8 @@ rpki_validator_SOURCES += sorted_array.h sorted_array.c rpki_validator_SOURCES += state.h state.c rpki_validator_SOURCES += thread_var.h thread_var.c +rpki_validator_SOURCES += rsync/rsync.h rsync/rsync.c + rpki_validator_SOURCES += asn1/content_info.h asn1/content_info.c rpki_validator_SOURCES += asn1/decode.h asn1/decode.c rpki_validator_SOURCES += asn1/oid.h asn1/oid.c diff --git a/src/main.c b/src/main.c index f3442b56..3d44138b 100644 --- a/src/main.c +++ b/src/main.c @@ -8,6 +8,7 @@ #include "thread_var.h" #include "object/certificate.h" #include "object/tal.h" +#include "rsync/rsync.h" /** * Registers the RPKI-specific OIDs in the SSL library. @@ -42,6 +43,10 @@ handle_tal_uri(char const *uri) if (error) return error; + error = download_files(uri); + if (error) + return error; + error = validation_create(&state, cert_file); if (error) goto end1; @@ -72,6 +77,7 @@ main(int argc, char **argv) { struct tal *tal; int error; + bool is_rsync_active = true; print_stack_trace_on_segfault(); @@ -80,6 +86,13 @@ main(int argc, char **argv) return -EINVAL; } + if (argc >= 4) + is_rsync_active = false; + + error = rsync_init(is_rsync_active); + if (error) + return error; + add_rpki_oids(); thvar_init(); fnstack_store(); @@ -94,5 +107,6 @@ main(int argc, char **argv) error = foreach_uri(tal, handle_tal_uri); tal_destroy(tal); + rsync_destroy(); return error; } diff --git a/src/object/certificate.c b/src/object/certificate.c index ed997f8a..d6671754 100644 --- a/src/object/certificate.c +++ b/src/object/certificate.c @@ -9,6 +9,7 @@ #include "manifest.h" #include "thread_var.h" #include "asn1/decode.h" +#include "../rsync/rsync.h" /* * The X509V3_EXT_METHOD that references NID_sinfo_access uses the AIA item. @@ -381,24 +382,33 @@ certificate_get_resources(X509 *cert, struct resources *resources) return error; } -int certificate_traverse(X509 *cert) +static int +_certificate_traverse(X509 *cert, SIGNATURE_INFO_ACCESS *sia, int sia_len) { - SIGNATURE_INFO_ACCESS *sia; ACCESS_DESCRIPTION *ad; + ACCESS_DESCRIPTION *list[sia_len]; char *uri; - int i; int error; + int i; + int count; - sia = X509_get_ext_d2i(cert, NID_sinfo_access, NULL, NULL); - if (sia == NULL) { - pr_err("Certificate lacks a Subject Information Access extension."); - return -ESRCH; - } - - error = 0; - for (i = 0; i < sk_ACCESS_DESCRIPTION_num(sia); i++) { + for (i = 0, count = 0; i < sia_len; i++) { ad = sk_ACCESS_DESCRIPTION_value(sia, i); + if (OBJ_obj2nid(ad->method) == NID_caRepository) { + error = gn2uri(ad->location, (char const **)&uri); + if (error) + goto end; + error = download_files(uri); + if (error) + goto end; + } else { + list[count] = ad; + count++; + } + } + for (i = 0; i < count; i++) { + ad = list[i]; if (OBJ_obj2nid(ad->method) == NID_rpkiManifest) { error = gn_g2l(ad->location, &uri); if (error) @@ -411,6 +421,24 @@ int certificate_traverse(X509 *cert) } end: + return error; +} + +int certificate_traverse(X509 *cert) +{ + SIGNATURE_INFO_ACCESS *sia; + int error; + + + sia = X509_get_ext_d2i(cert, NID_sinfo_access, NULL, NULL); + if (sia == NULL) { + pr_err("Certificate lacks a Subject Information Access extension."); + return -ESRCH; + } + + error = _certificate_traverse(cert, sia, sk_ACCESS_DESCRIPTION_num(sia)); + AUTHORITY_INFO_ACCESS_free(sia); return error; } + diff --git a/src/rsync/rsync.c b/src/rsync/rsync.c new file mode 100644 index 00000000..c5e41196 --- /dev/null +++ b/src/rsync/rsync.c @@ -0,0 +1,433 @@ +#include "rsync.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../common.h" + +struct uri { + char *string; + size_t len; + SLIST_ENTRY(uri) next; +}; + +SLIST_HEAD(uri_list, uri); + +static struct uri_list *rsync_uris; +static bool execute_rsync = true; + +//static const char *rsync_command[] = {"rsync", "--recursive", "--delete", "--times", NULL}; + +static int create_dir_recursive(char *); +static int create_dir(char *); +static int do_rsync(char const *); +static int get_dest_path(char const *, char **); +static bool is_file(char const *); +static bool dir_exist(char *); + +int +rsync_init(bool is_rsync_active) +{ + // TODO remove the next 2 lines + if (!is_rsync_active) { + execute_rsync = is_rsync_active; + return 0; + } + + rsync_uris = malloc(sizeof(struct uri_list)); + if (!rsync_uris) + return -ENOMEM; + + SLIST_INIT(rsync_uris); + return 0; +} + +void +rsync_destroy() +{ + struct uri *uri; + + // TODO remove the next 2 lines + if (!execute_rsync) + return; + + while (!SLIST_EMPTY(rsync_uris)) { + uri = SLIST_FIRST(rsync_uris); + SLIST_REMOVE_HEAD(rsync_uris, next); + free(uri->string); + free(uri); + } + + free(rsync_uris); +} + +static int +do_rsync(char const *rsync_uri) +{ + int error; + char *command; + char *dest; + char const *rsync_command = "rsync --recursive --delete --times --contimeout=20 "; /* space char at end*/ + + error = get_dest_path(rsync_uri, &dest); + if (error) + return error; + + command = malloc(strlen(rsync_command) + 1 + strlen(rsync_uri) + 1 + strlen(dest) + 1); + if (command == NULL) + return -ENOMEM; + + strcpy(command, rsync_command); + strcat(command, rsync_uri); + strcat(command, " "); + strcat(command, dest); + + free(dest); + + printf("(%s) command = %s \n", __func__, command); + + error = system(command); + if (error) { + printf("result rsync %d\n", error); + perror("rsync"); + } + free(command); + + return error; +} + +static int +get_dest_path(char const *rsync_uri, char **result) +{ + char *local_uri, *temp_str; + unsigned int result_size; + int error; + error = uri_g2l(rsync_uri, &local_uri); + if (error) + return error; + + if (!is_file(local_uri)) { + *result = local_uri; + return 0; + } + + temp_str = strrchr(local_uri, '/'); + if (temp_str == NULL) { + // TODO warning msg + return -EINVAL; + } + result_size = temp_str - local_uri + 1; /* add slash (+1) */ + + temp_str = malloc(result_size + 1); /* null char (+1) */ + if (temp_str == NULL) { + return -ENOMEM; + } + temp_str[result_size] = '\0'; /*Set null char*/ + strncpy(temp_str, local_uri, result_size); + free(local_uri); + + *result = temp_str; + return 0; +} + +//static int +//do_rsync(char *rsync_uri) +//{ +// int temp, result; +// +// char *temp_char; +// char *rsync_command[] = {"rsync", "--recursive", "--delete", "--times", NULL, NULL, NULL}; +// char *src = "rsync://rpki.afrinic.net/repository/AfriNIC.cer"; +// char *dest = "/home/dhf/Desktop/rpkitest/rpki.afrinic.net/repository/"; +// +// rsync_command[4] = src; +// rsync_command[5] = dest; +// temp = 0; +// while (temp < 7) { +// temp_char = rsync_command[temp]; +// printf("[%d] ", temp); +// if (temp_char == NULL) { +// printf("NULL\n"); +// } else { +// printf("%s\n", temp_char); +// } +// temp++; +// } +// printf("pre execv \n"); +//// result = execve(rsync_command[0], rsync_command, NULL); +// +// result = system("rsync --recursive --delete --times rsync://rpki.afrinic.net/repository/AfriNIC.cer /home/dhf/Desktop/rpkitest/rpki.afrinic.net/repository/"); +//// printf("result execv %d\n", result); +// printf("result rsync %d\n", result); +// perror("rsync"); +// return 0; +//} + +static bool +rsync_uri_prefix_equals(struct uri *rsync_uri, char const *new_uri) +{ + size_t uri_len; + uri_len = strlen(new_uri); + + if (rsync_uri->len > uri_len) + return false; + + return !strncasecmp(rsync_uri->string, new_uri, rsync_uri->len); +} + +static bool +is_uri_in_list(char const *rsync_uri) +{ + struct uri *cursor; + bool found; + + if (SLIST_EMPTY(rsync_uris)) { + return false; + } + + found = false; + SLIST_FOREACH(cursor, rsync_uris, next) { + if (rsync_uri_prefix_equals(cursor, rsync_uri)) { + found = true; + break; + } + } + + return found; +} + +static int +add_uri_to_list(char const *rsync_uri_path) +{ + struct uri *rsync_uri; + size_t urilen; + rsync_uri = malloc(sizeof(struct uri)); + if (rsync_uri == NULL) { + warnx("Out of memory"); + return -ENOMEM; + } + urilen = strlen(rsync_uri_path); + + rsync_uri->string = malloc(urilen + 1); + if (!rsync_uri->string) { + free(rsync_uri); + warnx("Out of memory"); + return -ENOMEM; + } + + strcpy(rsync_uri->string, rsync_uri_path); + rsync_uri->len = urilen; + SLIST_INSERT_HEAD(rsync_uris, rsync_uri, next); + + return 0; +} + +static int +short_uri(char const *rsync_uri, char **result) +{ + char const *const PREFIX = "rsync://"; + char const *tmp; + char *short_uri; + size_t result_len; + size_t prefix_len; + + prefix_len = strlen(PREFIX); + + if (strncmp(PREFIX, rsync_uri, prefix_len) != 0) { +// pr_err("Global URI %s does not begin with '%s'.", rsync_uri, +// PREFIX); + return -EINVAL; + } + + do { + tmp = rsync_uri + prefix_len; + tmp = strchr(tmp, '/'); + + if (tmp == NULL) { + result_len = strlen(rsync_uri); + break; + } + + tmp = tmp + 1; + tmp = strchr(tmp, '/'); + + if (tmp != NULL) + result_len = strlen(rsync_uri) - strlen(tmp); + else + result_len = strlen(rsync_uri); + + } while (0); + + short_uri = malloc(result_len + 1 + 1); /* slash + null chara */ + if (!short_uri) + return -ENOMEM; + + strncpy(short_uri, rsync_uri, result_len); + short_uri[result_len] = '/'; + short_uri[result_len + 1] = '\0'; + + *result = short_uri; + return 0; +} + +int +download_files(char const *rsync_uri) +{ + int error; + char *rsync_uri_path, *localuri; + + // TODO remove the next 2 lines + if (!execute_rsync) + return 0; + + if (is_uri_in_list(rsync_uri)){ + printf("(%s) ON LIST: %s\n", __func__, rsync_uri); + error = 0; + goto end; + } else { + printf("(%s) DOWNLOAD: %s\n",__func__, rsync_uri); + } + + error = short_uri(rsync_uri, &rsync_uri_path); + if (error) + return error; + + error = uri_g2l(rsync_uri_path, &localuri); + if (error) + goto free_uri_path; + + error = create_dir_recursive(localuri); + free(localuri); + if (error) + goto free_uri_path; + + error = do_rsync(rsync_uri_path); + if (error) + goto free_uri_path; + + error = add_uri_to_list(rsync_uri_path); + +free_uri_path: + free(rsync_uri_path); +end: + return error; + +} + + +static int +create_dir_recursive(char *localuri) +{ + char *temp_luri; + char path[PATH_MAX]; + char *slash; + size_t localuri_len; + size_t repository_len; + unsigned int offset; + + if (dir_exist(localuri)) + return 0; + + localuri_len = strlen(localuri); + repository_len = strlen(repository); + temp_luri = localuri + repository_len ; + + strcpy(path, repository); + offset = repository_len; + + + slash = strchr(temp_luri, '/'); + while (slash != NULL) { + if (slash == temp_luri) { + temp_luri++; + localuri_len--; + slash = strchr(temp_luri, '/'); + continue; + } + strcpy(path + offset, "/"); + offset += 1; + strncpy(path + offset, temp_luri, slash - temp_luri); + offset += slash - temp_luri; + if (offset > localuri_len) { + break; + } + path[offset] = '\0'; + if (create_dir(path) == -1) { + perror("Error while creating Dir"); + return -1; + } + temp_luri += slash - temp_luri + 1; + slash = strchr(temp_luri, '/'); + } + + if (offset < localuri_len) { + strcpy(path + offset, "/"); + offset += 1; + strcpy(path + offset, temp_luri); + offset = localuri + localuri_len - temp_luri + offset + 1; + path[offset] = '\0'; + } + + if (create_dir(path) == -1) { + perror("Error while creating Dir"); + return -1; + } + return 0; + +} + +static bool +is_file(char const *path) +{ + if (file_has_extension(path, "cer")) + return true; + if (file_has_extension(path, "gbr")) + return true; + if (file_has_extension(path, "mft")) + return true; + + return false; +} + +static bool +dir_exist(char *path) +{ + int error; + struct stat _stat; + error = stat(path, &_stat); + if (error == -1) + return false; /* a dir or file not exist*/ + + return true; +} + +static int +create_dir(char *path) +{ + struct stat _stat; + int error; + mode_t mode = 0777; + + if (is_file(path)) + return 0; + + error = stat(path, &_stat); + if (error != -1) { + /* a dir or file exist*/ + return 0; + } + + if (errno != ENOENT) { + perror("stat"); + return -1; /* another error occurs*/ + } + + error = mkdir(path, mode); + return error; +} diff --git a/src/rsync/rsync.h b/src/rsync/rsync.h new file mode 100644 index 00000000..3287ebe9 --- /dev/null +++ b/src/rsync/rsync.h @@ -0,0 +1,11 @@ +#ifndef SRC_RSYNC_RSYNC_H_ +#define SRC_RSYNC_RSYNC_H_ + +#include + +int download_files(const char *); +int rsync_init(bool); +void rsync_destroy(); + + +#endif /* SRC_RSYNC_RSYNC_H_ */ -- 2.47.3