From cd406409f8854dfc0de8acdb2f0d6c75f8969ee3 Mon Sep 17 00:00:00 2001 From: Otavio Pontes Date: Tue, 26 Jun 2018 16:01:28 +0000 Subject: [PATCH] curl: Set fallback CA paths in swupd_curl_init() Curl initialization were split in 2 different functions, swupd_curl_init(), that creates the curl handles and swupd_curl_check_network() that checks the network and set alternative CA paths, if needed. Merging those two functions in one to perform all curl initialization all at once. Also fixes: - Fix cases where curl was used before calling swupd_curl_check_network() and then the correct CA path wasn't set. - Don't use #ifdef FALLBACK_CAPATHS because FALLBACK_CAPATHS is always defined. It's set to an empty string if fallback ca paths are disabled. - Don't use extra memory to duplicate content of FALLBACK_CAPATHS and store it in a global. --- src/bundle.c | 6 - src/check_update.c | 6 - src/curl.c | 148 +++++++----------- src/manifest.c | 6 - src/packs.c | 5 - src/search.c | 6 - src/swupd.h | 1 - src/update.c | 6 - src/verify.c | 6 - src/version.c | 5 - .../verify/latest-missing/lines-checked | 4 +- .../verify/latest-missing/test.bats | 2 +- 12 files changed, 59 insertions(+), 142 deletions(-) diff --git a/src/bundle.c b/src/bundle.c index e40036e7..578bed17 100644 --- a/src/bundle.c +++ b/src/bundle.c @@ -53,12 +53,6 @@ int list_installable_bundles() int current_version; bool mix_exists; - int ret = swupd_curl_check_network(); - if (ret) { - fprintf(stderr, "Error: Network issue, unable to download manifest\n"); - return ret; - } - current_version = get_current_version(path_prefix); if (current_version < 0) { fprintf(stderr, "Error: Unable to determine current OS version\n"); diff --git a/src/check_update.c b/src/check_update.c index 9451a7e4..933a5c1f 100644 --- a/src/check_update.c +++ b/src/check_update.c @@ -139,12 +139,6 @@ static int check_update() } swupd_curl_init(); - int ret = swupd_curl_check_network(); - if (ret) { - fprintf(stderr, "Error: Network issue, unable to check for update\n"); - return ret; - } - read_versions(¤t_version, &server_version, path_prefix); if (server_version < 0) { diff --git a/src/curl.c b/src/curl.c index 28c21df0..966d4287 100644 --- a/src/curl.c +++ b/src/curl.c @@ -48,10 +48,8 @@ static CURL *curl = NULL; -/* these are used to handle alternative trust locations */ -static char *capath; -static char **fallback_capaths; -static char fallback_capaths_no; +/* alternative CA Path */ +static char *capath = NULL; /* Pretty print curl return status */ static void swupd_curl_strerror(CURLcode curl_ret) @@ -59,9 +57,50 @@ static void swupd_curl_strerror(CURLcode curl_ret) fprintf(stderr, "Curl error: (%d) %s\n", curl_ret, curl_easy_strerror(curl_ret)); } +static int check_connection(const char *test_capath) +{ + CURLcode curl_ret; + + curl_ret = curl_easy_setopt(curl, CURLOPT_URL, version_url); + if (curl_ret != CURLE_OK) { + return -1; + } + + curl_ret = curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); + if (curl_ret != CURLE_OK) { + return -1; + } + + if (test_capath) { + curl_ret = curl_easy_setopt(curl, CURLOPT_CAPATH, test_capath); + if (curl_ret != CURLE_OK) { + return -1; + } + } + + curl_ret = curl_easy_perform(curl); + + switch (curl_ret) { + case CURLE_OK: + return 0; + case CURLE_SSL_CACERT: + fprintf(stderr, "Error: unable to verify server SSL certificate\n"); + return -EBADCERT; + default: + swupd_curl_strerror(curl_ret); + /* something bad, stop */ + return -1; + } +} + int swupd_curl_init(void) { CURLcode curl_ret; + char *str; + char *tok; + char *ctx; + int ret; + struct stat st; curl_ret = curl_global_init(CURL_GLOBAL_ALL); if (curl_ret != CURLE_OK) { @@ -76,20 +115,13 @@ int swupd_curl_init(void) return -1; } -#ifdef FALLBACK_CAPATHS - /* parse and initialize CA paths. */ - { - char *str = strdup(FALLBACK_CAPATHS); - char *tok; - char *ctx; - struct stat st; - int i; - int sz = 1; - - fallback_capaths = (char **)malloc(sz * sizeof(char *)); - fallback_capaths[0] = NULL; - i = 1; + ret = check_connection(NULL); + if (ret == 0) { + return 0; + } + if (FALLBACK_CAPATHS[0]) { + str = strdup_or_die(FALLBACK_CAPATHS); for (tok = strtok_r(str, ":", &ctx); tok; tok = strtok_r(NULL, ":", &ctx)) { if (stat(tok, &st)) { continue; @@ -97,87 +129,16 @@ int swupd_curl_init(void) if ((st.st_mode & S_IFMT) != S_IFDIR) { continue; } - if (i == sz) { - sz <<= 1; - fallback_capaths = (char **)realloc(fallback_capaths, sz * sizeof(char *)); - } - fallback_capaths[i] = strdup(tok); - i++; - } - fallback_capaths_no = i; - free_string(&str); - } -#else - fallback_capaths = (char **)malloc(sizeof(char *)); - fallback_capaths[0] = NULL; - fallback_capaths_no = 1; -#endif - return 0; -} - -int swupd_curl_check_network(void) -{ - CURLcode curl_ret; - int ret = -1; - int i; - CURL *c; - static int has_network = 0; - - if (has_network) { - return 0; - } - - if (!curl) { - return -1; - } - - c = curl_easy_duphandle(curl); - if (!c) { - return -1; - } - - for (i = 0; i < fallback_capaths_no; i++) { - curl_easy_reset(c); - - curl_ret = curl_easy_setopt(c, CURLOPT_URL, version_url); - if (curl_ret != CURLE_OK) { - goto cleanup; - } - - curl_ret = curl_easy_setopt(c, CURLOPT_NOBODY, 1L); - if (curl_ret != CURLE_OK) { - goto cleanup; - } - - if (i) { /* first element represents default CApath, means no explicit setting */ - curl_ret = curl_easy_setopt(c, CURLOPT_CAPATH, fallback_capaths[i]); - if (curl_ret != CURLE_OK) { + ret = check_connection(tok); + if (ret == 0) { + capath = strdup_or_die(tok); break; } } - - curl_ret = curl_easy_perform(c); - - switch (curl_ret) { - case CURLE_OK: - capath = fallback_capaths[i]; - ret = 0; - has_network = 1; - goto cleanup; - case CURLE_SSL_CACERT: - fprintf(stderr, "Error: unable to verify server SSL certificate\n"); - ret = EBADCERT; - break; - default: - swupd_curl_strerror(curl_ret); - /* something bad, stop */ - goto cleanup; - } + free_string(&str); } -cleanup: - curl_easy_cleanup(c); return ret; } @@ -187,6 +148,9 @@ void swupd_curl_deinit(void) curl_easy_cleanup(curl); } curl = NULL; + + free_string(&capath); + curl_global_cleanup(); } diff --git a/src/manifest.c b/src/manifest.c index f4508e15..ab83dc47 100644 --- a/src/manifest.c +++ b/src/manifest.c @@ -472,12 +472,6 @@ static int retrieve_manifests(int current, int version, char *component, struct } free_string(&filename); - ret = swupd_curl_check_network(); - if (ret) { - ret = -ret; - goto out; - } - string_or_die(&dir, "%s/%i", state_dir, version); ret = mkdir(dir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); if ((ret != 0) && (errno != EEXIST)) { diff --git a/src/packs.c b/src/packs.c index c1c58836..e3819f75 100644 --- a/src/packs.c +++ b/src/packs.c @@ -109,11 +109,6 @@ int download_subscribed_packs(struct list *subs, struct manifest *mom, bool requ unsigned int list_length = list_len(subs); unsigned int complete = 0; - int ret = swupd_curl_check_network(); - if (ret) { - return -ret; - } - fprintf(stderr, "Downloading packs...\n"); iter = list_head(subs); while (iter) { diff --git a/src/search.c b/src/search.c index 5f3c1136..e22f08cc 100644 --- a/src/search.c +++ b/src/search.c @@ -870,12 +870,6 @@ int search_main(int argc, char **argv) return ret; } - ret = swupd_curl_check_network(); - if (ret) { - fprintf(stderr, "Error: Network issue, unable to proceed with update\n"); - goto clean_exit; - } - if (!init) { fprintf(stderr, "Searching for '%s'\n\n", search_string); } diff --git a/src/swupd.h b/src/swupd.h index 9047f6db..b5511017 100644 --- a/src/swupd.h +++ b/src/swupd.h @@ -295,7 +295,6 @@ extern int update_device_latest_version(int version); extern int swupd_curl_init(void); extern void swupd_curl_deinit(void); -extern int swupd_curl_check_network(void); extern double swupd_query_url_content_size(char *url); extern CURLcode swupd_download_file_start(struct file *file); extern CURLcode swupd_download_file_complete(CURLcode curl_ret, struct file *file); diff --git a/src/update.c b/src/update.c index fee290cb..43dfc910 100644 --- a/src/update.c +++ b/src/update.c @@ -236,12 +236,6 @@ static int main_update() clock_gettime(CLOCK_MONOTONIC_RAW, &ts_start); grabtime_start(×, "Main Update"); - ret = swupd_curl_check_network(); - if (ret) { - fprintf(stderr, "Error: Network issue, unable to proceed with update\n"); - goto clean_curl; - } - mix_exists = check_mix_exists(); fprintf(stderr, "Update started.\n"); diff --git a/src/verify.c b/src/verify.c index 1c1b9222..1de1343a 100644 --- a/src/verify.c +++ b/src/verify.c @@ -706,12 +706,6 @@ int verify_main(int argc, char **argv) fprintf(stderr, "Verifying version %i\n", version); - ret = swupd_curl_check_network(); - if (ret) { - fprintf(stderr, "Error: Network issue, unable to download manifest\n"); - goto clean_and_exit; - } - read_subscriptions(&subs); /* diff --git a/src/version.c b/src/version.c index 3a0ec72e..220bca34 100644 --- a/src/version.c +++ b/src/version.c @@ -147,11 +147,6 @@ int check_versions(int *current_version, int requested_version, char *path_prefix) { - - if (swupd_curl_check_network()) { - return -1; - } - read_versions(current_version, server_version, path_prefix); if (*current_version < 0) { diff --git a/test/functional/verify/latest-missing/lines-checked b/test/functional/verify/latest-missing/lines-checked index d9abec11..2065643b 100644 --- a/test/functional/verify/latest-missing/lines-checked +++ b/test/functional/verify/latest-missing/lines-checked @@ -1,2 +1,2 @@ -Unable to get latest version for install -Error: Fix did not fully succeed +Curl error: (37) Couldn't read a file:// file +Failed verify initialization, exiting now. diff --git a/test/functional/verify/latest-missing/test.bats b/test/functional/verify/latest-missing/test.bats index 6ad32900..dce6f0e0 100755 --- a/test/functional/verify/latest-missing/test.bats +++ b/test/functional/verify/latest-missing/test.bats @@ -5,7 +5,7 @@ load "../../swupdlib" @test "verify install using latest with missing version file on server" { run sudo sh -c "$SWUPD verify $SWUPD_OPTS --install -m latest" - check_lines "$output" + check_lines "$(echo "$output" | uniq)" } # vi: ft=sh ts=8 sw=2 sts=2 et tw=80