diff options
Diffstat (limited to 'src/reducer/anastasis_api_backup_redux.c')
-rw-r--r-- | src/reducer/anastasis_api_backup_redux.c | 658 |
1 files changed, 441 insertions, 217 deletions
diff --git a/src/reducer/anastasis_api_backup_redux.c b/src/reducer/anastasis_api_backup_redux.c index cfef852..6ca6de7 100644 --- a/src/reducer/anastasis_api_backup_redux.c +++ b/src/reducer/anastasis_api_backup_redux.c @@ -1,16 +1,16 @@ /* This file is part of Anastasis - Copyright (C) 2020, 2021 Anastasis SARL + Copyright (C) 2020-2023 Anastasis SARL Anastasis is free software; you can redistribute it and/or modify it under the - terms of the GNU Lesser General Public License as published by the Free Software + terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU Affero General Public License along with + You should have received a copy of the GNU General Public License along with Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> */ /** @@ -32,7 +32,7 @@ * anastasis-httpd.h. */ #define ANASTASIS_FREE_STORAGE GNUNET_TIME_relative_multiply ( \ - GNUNET_TIME_UNIT_YEARS, 5) + GNUNET_TIME_UNIT_YEARS, 5) /** * CPU limiter: do not evaluate more than 16k @@ -131,7 +131,7 @@ ANASTASIS_backup_state_from_string_ (const char *state_string) if (0 == strcmp (state_string, backup_strings[i])) return i; - return ANASTASIS_BACKUP_STATE_ERROR; + return ANASTASIS_BACKUP_STATE_INVALID; } @@ -177,11 +177,78 @@ json_t * ANASTASIS_backup_start (const struct GNUNET_CONFIGURATION_Handle *cfg) { json_t *initial_state; + const char *external_reducer = ANASTASIS_REDUX_probe_external_reducer (); + + if (NULL != external_reducer) + { + int pipefd_stdout[2]; + pid_t pid = 0; + int status; + FILE *reducer_stdout; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Using external reducer '%s' for backup start status\n", + external_reducer); + + GNUNET_assert (0 == pipe (pipefd_stdout)); + pid = fork (); + if (pid == 0) + { + close (pipefd_stdout[0]); + dup2 (pipefd_stdout[1], STDOUT_FILENO); + execlp (external_reducer, + external_reducer, + "-b", + NULL); + GNUNET_assert (0); + } + + close (pipefd_stdout[1]); + reducer_stdout = fdopen (pipefd_stdout[0], + "r"); + { + json_error_t err; + + initial_state = json_loadf (reducer_stdout, + 0, + &err); + + if (NULL == initial_state) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "External reducer did not output valid JSON: %s:%d:%d %s\n", + err.source, + err.line, + err.column, + err.text); + GNUNET_assert (0 == fclose (reducer_stdout)); + waitpid (pid, &status, 0); + return NULL; + } + } + + GNUNET_assert (NULL != initial_state); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Waiting for external reducer to terminate.\n"); + GNUNET_assert (0 == fclose (reducer_stdout)); + reducer_stdout = NULL; + waitpid (pid, &status, 0); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "External reducer finished with exit status '%d'\n", + status); + return initial_state; + } (void) cfg; initial_state = ANASTASIS_REDUX_load_continents_ (); if (NULL == initial_state) return NULL; + GNUNET_assert ( + 0 == + json_object_set_new (initial_state, + "reducer_type", + json_string ("backup"))); set_state (initial_state, ANASTASIS_BACKUP_STATE_CONTINENT_SELECTING); return initial_state; @@ -286,22 +353,30 @@ add_authentication (json_t *state, json_object_foreach (auth_providers, url, details) { - json_t *methods; + const json_t *methods = NULL; json_t *method; size_t index; - uint32_t size_limit_in_mb; + uint32_t size_limit_in_mb = 0; + const char *status; + uint32_t http_status = 0; struct GNUNET_JSON_Specification ispec[] = { - GNUNET_JSON_spec_uint32 ("storage_limit_in_megabytes", - &size_limit_in_mb), - GNUNET_JSON_spec_json ("methods", - &methods), + GNUNET_JSON_spec_string ("status", + &status), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_uint32 ("storage_limit_in_megabytes", + &size_limit_in_mb), + NULL), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_uint32 ("http_status", + &http_status), + NULL), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_array_const ("methods", + &methods), + NULL), GNUNET_JSON_spec_end () }; - if (MHD_HTTP_OK != - json_integer_value (json_object_get (details, - "http_status"))) - continue; /* skip providers that are down */ if (GNUNET_OK != GNUNET_JSON_parse (details, ispec, @@ -310,6 +385,17 @@ add_authentication (json_t *state, GNUNET_break (0); continue; } + if (0 != strcmp (status, + "ok")) + continue; + if (MHD_HTTP_OK != http_status) + continue; /* skip providers that are down */ + if ( (NULL == methods) || + (0 == size_limit_in_mb) ) + { + GNUNET_break (0); + continue; + } json_array_foreach (methods, index, method) { const char *type; @@ -325,7 +411,6 @@ add_authentication (json_t *state, break; } } - GNUNET_JSON_parse_free (ispec); if (! challenge_size_ok (size_limit_in_mb, challenge_size)) { @@ -681,17 +766,20 @@ free_costs (struct Costs *costs) * Check if providers @a p1 and @a p2 have equivalent * methods and cost structures. * + * @param pb policy builder with list of providers + * @param p1 name of provider to compare + * @param p2 name of provider to compare * @return true if the providers are fully equivalent */ static bool -equiv_provider (struct PolicyBuilder *pb, +equiv_provider (const struct PolicyBuilder *pb, const char *p1, const char *p2) { - json_t *j1; - json_t *j2; - json_t *m1; - json_t *m2; + const json_t *j1; + const json_t *j2; + const json_t *m1; + const json_t *m2; struct TALER_Amount uc1; struct TALER_Amount uc2; @@ -708,8 +796,8 @@ equiv_provider (struct PolicyBuilder *pb, { struct GNUNET_JSON_Specification s1[] = { - GNUNET_JSON_spec_json ("methods", - &m1), + GNUNET_JSON_spec_array_const ("methods", + &m1), TALER_JSON_spec_amount_any ("truth_upload_fee", &uc1), GNUNET_JSON_spec_end () @@ -727,8 +815,8 @@ equiv_provider (struct PolicyBuilder *pb, { struct GNUNET_JSON_Specification s2[] = { - GNUNET_JSON_spec_json ("methods", - &m2), + GNUNET_JSON_spec_array_const ("methods", + &m2), TALER_JSON_spec_amount_any ("truth_upload_fee", &uc2), GNUNET_JSON_spec_end () @@ -847,7 +935,7 @@ eval_provider_selection (struct PolicyBuilder *pb, pb->m_idx[i]); const json_t *provider_cfg = json_object_get (pb->providers, prov_sel[i]); - json_t *provider_methods; + const json_t *provider_methods; const char *method_type; json_t *md; size_t index; @@ -857,8 +945,8 @@ eval_provider_selection (struct PolicyBuilder *pb, struct GNUNET_JSON_Specification pspec[] = { GNUNET_JSON_spec_uint32 ("storage_limit_in_megabytes", &size_limit_in_mb), - GNUNET_JSON_spec_json ("methods", - &provider_methods), + GNUNET_JSON_spec_array_const ("methods", + &provider_methods), TALER_JSON_spec_amount_any ("truth_upload_fee", &upload_cost), GNUNET_JSON_spec_end () @@ -930,7 +1018,6 @@ eval_provider_selection (struct PolicyBuilder *pb, GNUNET_break (0); pb->ec = TALER_EC_ANASTASIS_REDUCER_STATE_INVALID; pb->hint = "'methods' of provider"; - GNUNET_JSON_parse_free (pspec); for (unsigned int i = 0; i<pb->req_methods; i++) free_costs (policy_ent[i].usage_fee); return; @@ -952,14 +1039,12 @@ eval_provider_selection (struct PolicyBuilder *pb, { /* Provider does not OFFER this method, combination not possible. Cost is basically 'infinite', but we simply then skip this. */ - GNUNET_JSON_parse_free (pspec); GNUNET_JSON_parse_free (mspec); for (unsigned int i = 0; i<pb->req_methods; i++) free_costs (policy_ent[i].usage_fee); return; } GNUNET_JSON_parse_free (mspec); - GNUNET_JSON_parse_free (pspec); } /* calculate provider diversity by counting number of different @@ -1082,6 +1167,34 @@ provider_candidate (struct PolicyBuilder *pb, json_object_foreach (pb->providers, url, pconfig) { + const char *status; + uint32_t http_status = 0; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ("status", + &status), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_uint32 ("http_status", + &http_status), + NULL), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (pconfig, + spec, + NULL, NULL)) + { + GNUNET_break (0); + continue; + } + if ( (MHD_HTTP_OK != http_status) || + (0 == strcmp (status, + "disabled")) ) + { + GNUNET_JSON_parse_free (spec); + continue; + } + GNUNET_JSON_parse_free (spec); prov_sel[i] = url; if (i == pb->req_methods - 1) { @@ -1171,58 +1284,6 @@ method_candidate (struct PolicyBuilder *pb, /** - * Lookup @a salt of @a provider_url in @a state. - * - * @param state the state to inspect - * @param provider_url provider to look into - * @param[out] salt value to extract - * @return #GNUNET_OK on success - */ -static int -lookup_salt (const json_t *state, - const char *provider_url, - struct ANASTASIS_CRYPTO_ProviderSaltP *salt) -{ - const json_t *aps; - const json_t *cfg; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("salt", - salt), - GNUNET_JSON_spec_end () - }; - - aps = json_object_get (state, - "authentication_providers"); - if (NULL == aps) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - cfg = json_object_get (aps, - provider_url); - if (NULL == cfg) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - if (MHD_HTTP_OK != - json_integer_value (json_object_get (cfg, - "http_status"))) - return GNUNET_NO; /* skip providers that are down */ - if (GNUNET_OK != - GNUNET_JSON_parse (cfg, - spec, - NULL, NULL)) - { - /* provider not working */ - GNUNET_break_op (0); - return GNUNET_NO; - } - return GNUNET_OK; -} - - -/** * Compare two cost lists. * * @param my cost to compare @@ -1604,7 +1665,8 @@ done_authentication (json_t *state, pb.methods = json_object_get (state, "authentication_methods"); if ( (NULL == pb.methods) || - (! json_is_array (pb.methods)) ) + (! json_is_array (pb.methods)) || + (json_array_size (pb.methods) > UINT_MAX) ) { ANASTASIS_redux_fail_ (cb, cb_cls, @@ -1612,7 +1674,8 @@ done_authentication (json_t *state, "'authentication_methods' must be provided"); return NULL; } - pb.num_methods = json_array_size (pb.methods); + pb.num_methods + = (unsigned int) json_array_size (pb.methods); switch (pb.num_methods) { case 0: @@ -1622,6 +1685,11 @@ done_authentication (json_t *state, "'authentication_methods' must not be empty"); return NULL; case 1: + ANASTASIS_redux_fail_ (cb, + cb_cls, + TALER_EC_ANASTASIS_REDUCER_STATE_INVALID, + "Two factor authentication (2-FA) is required"); + return NULL; case 2: pb.req_methods = pb.num_methods; break; @@ -1685,9 +1753,9 @@ done_authentication (json_t *state, struct ANASTASIS_CRYPTO_ProviderSaltP salt; if (GNUNET_OK != - lookup_salt (state, - url, - &salt)) + ANASTASIS_reducer_lookup_salt (state, + url, + &salt)) continue; /* skip providers that are down */ provider = GNUNET_JSON_PACK ( GNUNET_JSON_pack_string ("provider_url", @@ -1714,9 +1782,9 @@ done_authentication (json_t *state, url_str = json_string_value (url); if ( (NULL == url_str) || (GNUNET_OK != - lookup_salt (state, - url_str, - &salt)) ) + ANASTASIS_reducer_lookup_salt (state, + url_str, + &salt)) ) { GNUNET_break (0); ANASTASIS_redux_fail_ (cb, @@ -1877,8 +1945,8 @@ add_policy (json_t *state, { const char *provider_url; uint32_t method_idx; - json_t *prov_methods; const char *method_type; + const json_t *prov_methods; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_string ("provider", &provider_url), @@ -1904,11 +1972,19 @@ add_policy (json_t *state, { const json_t *prov_cfg; uint32_t limit; + const char *status; + uint32_t http_status = 0; struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ("status", + &status), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_uint32 ("http_status", + &http_status), + NULL), GNUNET_JSON_spec_uint32 ("storage_limit_in_megabytes", &limit), - GNUNET_JSON_spec_json ("methods", - &prov_methods), + GNUNET_JSON_spec_array_const ("methods", + &prov_methods), GNUNET_JSON_spec_end () }; @@ -1924,10 +2000,6 @@ add_policy (json_t *state, "provider URL unknown"); return NULL; } - if (MHD_HTTP_OK != - json_integer_value (json_object_get (prov_cfg, - "http_status"))) - continue; if (GNUNET_OK != GNUNET_JSON_parse (prov_cfg, spec, @@ -1937,16 +2009,13 @@ add_policy (json_t *state, json_decref (methods); continue; } - if (! json_is_array (prov_methods)) + if ( (MHD_HTTP_OK != http_status) || + (0 != strcmp (status, + "ok")) ) { - GNUNET_break (0); + /* skip provider, disabled or down */ json_decref (methods); - json_decref (prov_methods); - ANASTASIS_redux_fail_ (cb, - cb_cls, - TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID, - "provider lacks authentication methods"); - return NULL; + continue; } } @@ -1959,7 +2028,6 @@ add_policy (json_t *state, { GNUNET_break (0); json_decref (methods); - json_decref (prov_methods); ANASTASIS_redux_fail_ (cb, cb_cls, TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID, @@ -1972,7 +2040,6 @@ add_policy (json_t *state, { GNUNET_break (0); json_decref (methods); - json_decref (prov_methods); ANASTASIS_redux_fail_ (cb, cb_cls, TALER_EC_ANASTASIS_REDUCER_INPUT_INVALID, @@ -2004,7 +2071,6 @@ add_policy (json_t *state, { GNUNET_break (0); json_decref (methods); - json_decref (prov_methods); ANASTASIS_redux_fail_ (cb, cb_cls, TALER_EC_ANASTASIS_REDUCER_STATE_INVALID, @@ -2021,7 +2087,6 @@ add_policy (json_t *state, { GNUNET_break (0); json_decref (methods); - json_decref (prov_methods); ANASTASIS_redux_fail_ (cb, cb_cls, TALER_EC_ANASTASIS_REDUCER_STATE_INVALID, @@ -2032,7 +2097,6 @@ add_policy (json_t *state, GNUNET_assert (0 == json_array_append (methods, method)); - json_decref (prov_methods); } /* end of json_array_foreach (arg_array, index, method) */ } @@ -2323,12 +2387,12 @@ del_challenge (json_t *state, * @return number of years of service to pay for */ static unsigned int -expiration_to_years (struct GNUNET_TIME_Absolute expiration) +expiration_to_years (struct GNUNET_TIME_Timestamp expiration) { struct GNUNET_TIME_Relative rem; unsigned int years; - rem = GNUNET_TIME_absolute_get_remaining (expiration); + rem = GNUNET_TIME_absolute_get_remaining (expiration.abs_time); years = rem.rel_value_us / GNUNET_TIME_UNIT_YEARS.rel_value_us; if (0 != rem.rel_value_us % GNUNET_TIME_UNIT_YEARS.rel_value_us) years++; @@ -2348,7 +2412,7 @@ expiration_to_years (struct GNUNET_TIME_Absolute expiration) */ static enum GNUNET_GenericReturnValue update_expiration_cost (json_t *state, - struct GNUNET_TIME_Absolute expiration) + struct GNUNET_TIME_Timestamp expiration) { struct Costs *costs = NULL; unsigned int years; @@ -2373,26 +2437,33 @@ update_expiration_cost (json_t *state, json_object_foreach (providers, url, provider) { struct TALER_Amount annual_fee; + const char *status; + uint32_t http_status = 0; struct GNUNET_JSON_Specification pspec[] = { + GNUNET_JSON_spec_string ("status", + &status), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_uint32 ("http_status", + &http_status), + NULL), TALER_JSON_spec_amount_any ("annual_fee", &annual_fee), GNUNET_JSON_spec_end () }; struct TALER_Amount fee; - if (MHD_HTTP_OK != - json_integer_value (json_object_get (provider, - "http_status"))) - continue; /* skip providers that are down */ if (GNUNET_OK != GNUNET_JSON_parse (provider, pspec, NULL, NULL)) { - /* strange, skip as well */ - GNUNET_break_op (0); + /* likely down, skip */ continue; } + if ( (MHD_HTTP_OK != http_status) || + (0 != strcmp (status, + "ok")) ) + continue; /* skip providers that are down or disabled */ if (0 > TALER_amount_multiply (&fee, &annual_fee, @@ -2473,7 +2544,15 @@ update_expiration_cost (json_t *state, off++; { struct TALER_Amount upload_cost; + const char *status; + uint32_t http_status = 0; struct GNUNET_JSON_Specification pspec[] = { + GNUNET_JSON_spec_string ("status", + &status), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_uint32 ("http_status", + &http_status), + NULL), TALER_JSON_spec_amount_any ("truth_upload_fee", &upload_cost), GNUNET_JSON_spec_end () @@ -2491,6 +2570,13 @@ update_expiration_cost (json_t *state, GNUNET_break (0); return GNUNET_SYSERR; } + if ( (MHD_HTTP_OK != http_status) || + (0 != strcmp (status, + "ok")) ) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } if (0 > TALER_amount_multiply (&fee, &upload_cost, @@ -2519,8 +2605,7 @@ update_expiration_cost (json_t *state, { struct Costs *nxt = costs->next; - if ( (0 != costs->cost.value) || - (0 != costs->cost.fraction) ) + if (! TALER_amount_is_zero (&costs->cost)) { json_t *ao; @@ -2542,13 +2627,12 @@ update_expiration_cost (json_t *state, } if (is_free) - expiration = GNUNET_TIME_relative_to_absolute (ANASTASIS_FREE_STORAGE); + expiration = GNUNET_TIME_relative_to_timestamp (ANASTASIS_FREE_STORAGE); /* update 'expiration' in state */ { json_t *eo; - (void) GNUNET_TIME_round_abs (&expiration); - eo = GNUNET_JSON_from_time_abs (expiration); + eo = GNUNET_JSON_from_timestamp (expiration); GNUNET_assert (0 == json_object_set_new (state, "expiration", @@ -2589,11 +2673,13 @@ done_policy_review (json_t *state, return NULL; } { - struct GNUNET_TIME_Absolute exp = {0}; + struct GNUNET_TIME_Timestamp exp + = GNUNET_TIME_UNIT_ZERO_TS; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_absolute_time ("expiration", - &exp)), + GNUNET_JSON_spec_timestamp ("expiration", + &exp), + NULL), GNUNET_JSON_spec_end () }; @@ -2608,8 +2694,8 @@ done_policy_review (json_t *state, "invalid expiration specified"); return NULL; } - if (0 == exp.abs_value_us) - exp = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_YEARS); + if (GNUNET_TIME_absolute_is_zero (exp.abs_time)) + exp = GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_YEARS); if (GNUNET_OK != update_expiration_cost (state, exp)) @@ -2869,6 +2955,62 @@ serialize_truth (struct UploadContext *uc) /** + * Test if the given @a provider_url is used by any of the + * authentication methods and thus the provider should be + * considered mandatory for storing the policy. + * + * @param state state to inspect + * @param provider_url provider to test + * @return false if the provider can be removed from policy + * upload considerations without causing a problem + */ +static bool +provider_required (const json_t *state, + const char *provider_url) +{ + json_t *policies + = json_object_get (state, + "policies"); + size_t pidx; + json_t *policy; + + json_array_foreach (policies, pidx, policy) + { + json_t *methods = json_object_get (policy, + "methods"); + size_t midx; + json_t *method; + + json_array_foreach (methods, midx, method) + { + const char *provider + = json_string_value (json_object_get (method, + "provider")); + + if (NULL == provider) + { + GNUNET_break (0); + continue; + } + if (0 == strcmp (provider, + provider_url)) + return true; + } + } + return false; +} + + +/** + * All truth uploads are done, begin with uploading the policy. + * + * @param[in,out] uc context for the operation + */ +static void +share_secret (struct UploadContext *uc); + + +/** * Function called with the results of a #ANASTASIS_secret_share(). * * @param cls closure with a `struct UploadContext *` @@ -2901,8 +3043,8 @@ secret_share_result_cb (void *cls, d = GNUNET_JSON_PACK ( GNUNET_JSON_pack_uint64 ("policy_version", pssi->policy_version), - GNUNET_JSON_pack_time_abs ("policy_expiration", - pssi->policy_expiration)); + GNUNET_JSON_pack_timestamp ("policy_expiration", + pssi->policy_expiration)); GNUNET_assert (NULL != d); GNUNET_assert (0 == json_object_set_new (sa, @@ -2952,7 +3094,8 @@ secret_share_result_cb (void *cls, json_array_foreach (providers, off, provider) { const char *purl = json_string_value (json_object_get (provider, - "provider_url")); + "provider_url") + ); if (NULL == purl) { @@ -2993,13 +3136,53 @@ secret_share_result_cb (void *cls, { json_t *details; + if (! provider_required (uc->state, + sr->details.provider_failure.provider_url)) + { + /* try again without that provider */ + json_t *provider; + json_t *providers; + size_t idx; + + provider + = json_object_get ( + json_object_get (uc->state, + "authentication_providers"), + sr->details.provider_failure.provider_url); + GNUNET_break (0 == + json_object_set_new (provider, + "status", + json_string ("disabled"))); + providers + = json_object_get (uc->state, + "policy_providers"); + json_array_foreach (providers, idx, provider) + { + const char *url + = json_string_value (json_object_get (provider, + "provider_url")); + + if ( (NULL != url) && + (0 == strcmp (sr->details.provider_failure.provider_url, + url)) ) + { + GNUNET_break (0 == + json_array_remove (providers, + idx)); + break; + } + } + share_secret (uc); + return; + } details = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("backup_state", - "ERROR"), GNUNET_JSON_pack_uint64 ("http_status", sr->details.provider_failure.http_status), - GNUNET_JSON_pack_uint64 ("upload_status", + GNUNET_JSON_pack_uint64 ("code", sr->details.provider_failure.ec), + GNUNET_JSON_pack_string ("hint", + TALER_ErrorCode_get_hint ( + sr->details.provider_failure.ec)), GNUNET_JSON_pack_string ("provider_url", sr->details.provider_failure.provider_url)); uc->cb (uc->cb_cls, @@ -3028,26 +3211,29 @@ secret_share_result_cb (void *cls, static void share_secret (struct UploadContext *uc) { - json_t *user_id; - json_t *core_secret; - json_t *jpolicies; - json_t *providers = NULL; + const json_t *user_id; + const json_t *core_secret; + const json_t *jpolicies; + const json_t *providers = NULL; size_t policies_len; const char *secret_name = NULL; unsigned int pds_len; struct GNUNET_TIME_Relative timeout = GNUNET_TIME_UNIT_ZERO; struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_json ("identity_attributes", - &user_id), - GNUNET_JSON_spec_json ("policies", - &jpolicies), - GNUNET_JSON_spec_json ("policy_providers", - &providers), - GNUNET_JSON_spec_json ("core_secret", - &core_secret), + GNUNET_JSON_spec_object_const ("identity_attributes", + &user_id), + GNUNET_JSON_spec_array_const ("policies", + &jpolicies), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_array_const ("policy_providers", + &providers), + NULL), + GNUNET_JSON_spec_object_const ("core_secret", + &core_secret), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_string ("secret_name", - &secret_name)), + &secret_name), + NULL), GNUNET_JSON_spec_end () }; @@ -3069,12 +3255,13 @@ share_secret (struct UploadContext *uc) struct GNUNET_JSON_Specification pspec[] = { GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_relative_time ("timeout", - &timeout)), + &timeout), + NULL), GNUNET_JSON_spec_end () }; args = json_object_get (uc->state, - "pay-arguments"); + "pay_arguments"); if ( (NULL != args) && (GNUNET_OK != GNUNET_JSON_parse (args, @@ -3094,40 +3281,43 @@ share_secret (struct UploadContext *uc) } } - if ( (! json_is_object (user_id)) || - (! json_is_array (jpolicies)) || - (0 == json_array_size (jpolicies)) || - ( (NULL != providers) && - (! json_is_array (providers)) ) ) + policies_len = json_array_size (jpolicies); + if (0 == policies_len) { ANASTASIS_redux_fail_ (uc->cb, uc->cb_cls, TALER_EC_ANASTASIS_REDUCER_STATE_INVALID, "State parsing failed checks when preparing to share secret"); - GNUNET_JSON_parse_free (spec); upload_cancel_cb (uc); return; } - policies_len = json_array_size (jpolicies); - pds_len = json_array_size (providers); - + if (json_array_size (providers) > UINT_MAX) + { + GNUNET_break_op (0); + ANASTASIS_redux_fail_ (uc->cb, + uc->cb_cls, + TALER_EC_ANASTASIS_REDUCER_STATE_INVALID, + "provider array excessively long"); + upload_cancel_cb (uc); + return; + } + pds_len + = (unsigned int) json_array_size (providers); if (0 == pds_len) { ANASTASIS_redux_fail_ (uc->cb, uc->cb_cls, TALER_EC_ANASTASIS_REDUCER_STATE_INVALID, "no workable providers in state"); - GNUNET_JSON_parse_free (spec); upload_cancel_cb (uc); return; } - { struct ANASTASIS_Policy *vpolicies[policies_len]; const struct ANASTASIS_Policy *policies[policies_len]; - struct ANASTASIS_ProviderDetails pds[GNUNET_NZL (pds_len)]; + struct ANASTASIS_ProviderDetails pds[pds_len]; /* initialize policies/vpolicies arrays */ memset (pds, @@ -3142,18 +3332,19 @@ share_secret (struct UploadContext *uc) unsigned int methods_len; if ( (! json_is_array (jmethods)) || - (0 == json_array_size (jmethods)) ) + (0 == json_array_size (jmethods)) || + (json_array_size (jmethods) > UINT_MAX) ) { GNUNET_break (0); ANASTASIS_redux_fail_ (uc->cb, uc->cb_cls, TALER_EC_ANASTASIS_REDUCER_STATE_INVALID, - "'methods' must be an array"); - GNUNET_JSON_parse_free (spec); + "'methods' must be an array of sane length"); upload_cancel_cb (uc); return; } - methods_len = json_array_size (jmethods); + methods_len + = (unsigned int) json_array_size (jmethods); { struct ANASTASIS_Policy *p; struct ANASTASIS_Truth *truths[methods_len]; @@ -3163,13 +3354,14 @@ share_secret (struct UploadContext *uc) { const json_t *jmethod = json_array_get (jmethods, j); - json_t *jtruth = NULL; + const json_t *jtruth = NULL; uint32_t truth_index; const char *provider_url; struct GNUNET_JSON_Specification ispec[] = { GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_json ("truth", - &jtruth)), + GNUNET_JSON_spec_object_const ("truth", + &jtruth), + NULL), GNUNET_JSON_spec_string ("provider", &provider_url), GNUNET_JSON_spec_uint32 ("authentication_method", @@ -3190,7 +3382,6 @@ share_secret (struct UploadContext *uc) uc->cb_cls, TALER_EC_ANASTASIS_REDUCER_STATE_INVALID, "'truth' failed to decode"); - GNUNET_JSON_parse_free (spec); upload_cancel_cb (uc); return; } @@ -3207,8 +3398,6 @@ share_secret (struct UploadContext *uc) uc->cb_cls, TALER_EC_ANASTASIS_REDUCER_STATE_INVALID, "'truth' failed to decode"); - GNUNET_JSON_parse_free (ispec); - GNUNET_JSON_parse_free (spec); upload_cancel_cb (uc); return; } @@ -3246,13 +3435,10 @@ share_secret (struct UploadContext *uc) uc->cb_cls, TALER_EC_ANASTASIS_REDUCER_STATE_INVALID, "'truth' failed to decode"); - GNUNET_JSON_parse_free (ispec); - GNUNET_JSON_parse_free (spec); upload_cancel_cb (uc); return; } } - GNUNET_JSON_parse_free (ispec); ctruths[j] = truths[j]; } p = ANASTASIS_policy_create (ctruths, @@ -3272,7 +3458,8 @@ share_secret (struct UploadContext *uc) struct GNUNET_JSON_Specification ispec[] = { GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_fixed_auto ("payment_secret", - &pds[i].payment_secret)), + &pds[i].payment_secret), + NULL), GNUNET_JSON_spec_string ("provider_url", &pds[i].provider_url), GNUNET_JSON_spec_end () @@ -3283,9 +3470,9 @@ share_secret (struct UploadContext *uc) ispec, NULL, NULL)) || (GNUNET_OK != - lookup_salt (uc->state, - pds[i].provider_url, - &pds[i].provider_salt)) ) + ANASTASIS_reducer_lookup_salt (uc->state, + pds[i].provider_url, + &pds[i].provider_salt)) ) { GNUNET_break (0); ANASTASIS_redux_fail_ (uc->cb, @@ -3295,7 +3482,6 @@ share_secret (struct UploadContext *uc) for (unsigned int i = 0; i<policies_len; i++) ANASTASIS_policy_destroy (vpolicies[i]); upload_cancel_cb (uc); - GNUNET_JSON_parse_free (spec); return; } } @@ -3326,7 +3512,6 @@ share_secret (struct UploadContext *uc) for (unsigned int i = 0; i<policies_len; i++) ANASTASIS_policy_destroy (vpolicies[i]); } - GNUNET_JSON_parse_free (spec); if (NULL == uc->ss) { GNUNET_break (0); @@ -3519,7 +3704,8 @@ add_truth_object (struct UploadContext *uc, struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_uint32 ("upload_status", - &status)), + &status), + NULL), GNUNET_JSON_spec_end () }; if (GNUNET_OK != @@ -3568,9 +3754,9 @@ add_truth_object (struct UploadContext *uc, }; if (GNUNET_OK != - lookup_salt (uc->state, - provider_url, - &salt)) + ANASTASIS_reducer_lookup_salt (uc->state, + provider_url, + &salt)) { GNUNET_break (0); return GNUNET_SYSERR; @@ -3703,10 +3889,12 @@ check_truth_upload (struct UploadContext *uc, &type), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_string ("mime_type", - &mime_type)), + &mime_type), + NULL), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_string ("instructions", - &instructions)), + &instructions), + NULL), GNUNET_JSON_spec_varsize ("challenge", &truth_data, &truth_data_size), @@ -3737,9 +3925,9 @@ check_truth_upload (struct UploadContext *uc, tue->am_idx = am_idx; tue->policies_length = 1; if (GNUNET_OK != - lookup_salt (uc->state, - provider_url, - &provider_salt)) + ANASTASIS_reducer_lookup_salt (uc->state, + provider_url, + &provider_salt)) { GNUNET_break (0); GNUNET_JSON_parse_free (spec); @@ -3755,7 +3943,6 @@ check_truth_upload (struct UploadContext *uc, struct ANASTASIS_CRYPTO_TruthKeyP truth_key; struct ANASTASIS_CRYPTO_KeyShareP key_share; struct ANASTASIS_CRYPTO_NonceP nonce; - struct GNUNET_JSON_Specification jspec[] = { GNUNET_JSON_spec_fixed_auto ("salt", &question_salt), @@ -3841,10 +4028,10 @@ upload (json_t *state, struct UploadContext *uc; json_t *auth_methods; json_t *policies; - struct GNUNET_TIME_Absolute expiration; + struct GNUNET_TIME_Timestamp expiration; struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_absolute_time ("expiration", - &expiration), + GNUNET_JSON_spec_timestamp ("expiration", + &expiration), GNUNET_JSON_spec_end () }; @@ -3895,12 +4082,13 @@ upload (json_t *state, struct GNUNET_JSON_Specification pspec[] = { GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_relative_time ("timeout", - &uc->timeout)), + &uc->timeout), + NULL), GNUNET_JSON_spec_end () }; args = json_object_get (uc->state, - "pay-arguments"); + "pay_arguments"); if ( (NULL != args) && (GNUNET_OK != GNUNET_JSON_parse (args, @@ -3954,7 +4142,8 @@ upload (json_t *state, &am_idx), GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_json ("truth", - &truth)), + &truth), + NULL), GNUNET_JSON_spec_end () }; @@ -4111,17 +4300,23 @@ check_upload_size_limit (json_t *state, see #6760. */ json_object_foreach (aps, url, ap) { - uint32_t limit; + uint32_t limit = 0; + const char *status; + uint32_t http_status = 0; struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_uint32 ("storage_limit_in_megabytes", - &limit), + GNUNET_JSON_spec_string ("status", + &status), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_uint32 ("http_status", + &http_status), + NULL), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_uint32 ("storage_limit_in_megabytes", + &limit), + NULL), GNUNET_JSON_spec_end () }; - if (MHD_HTTP_OK != - json_integer_value (json_object_get (ap, - "http_status"))) - continue; /* skip providers that are down */ if (GNUNET_OK != GNUNET_JSON_parse (ap, spec, @@ -4131,6 +4326,10 @@ check_upload_size_limit (json_t *state, GNUNET_break_op (0); continue; } + if ( (MHD_HTTP_OK != http_status) || + (0 != strcmp (status, + "ok")) ) + continue; if (0 == limit) return GNUNET_SYSERR; min_limit = GNUNET_MIN (min_limit, @@ -4161,13 +4360,15 @@ enter_secret (json_t *state, void *cb_cls) { json_t *jsecret; - struct GNUNET_TIME_Absolute expiration = {0}; + struct GNUNET_TIME_Timestamp expiration + = GNUNET_TIME_UNIT_ZERO_TS; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_json ("secret", &jsecret), GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_absolute_time ("expiration", - &expiration)), + GNUNET_JSON_spec_timestamp ("expiration", + &expiration), + NULL), GNUNET_JSON_spec_end () }; @@ -4215,7 +4416,7 @@ enter_secret (json_t *state, break; } } - if (0 != expiration.abs_value_us) + if (! GNUNET_TIME_absolute_is_zero (expiration.abs_time)) { if (GNUNET_OK != update_expiration_cost (state, @@ -4346,10 +4547,10 @@ update_expiration (json_t *state, ANASTASIS_ActionCallback cb, void *cb_cls) { - struct GNUNET_TIME_Absolute expiration; + struct GNUNET_TIME_Timestamp expiration; struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_absolute_time ("expiration", - &expiration), + GNUNET_JSON_spec_timestamp ("expiration", + &expiration), GNUNET_JSON_spec_end () }; @@ -4483,7 +4684,7 @@ pay_truths_backup (json_t *state, if (NULL != arguments) GNUNET_assert (0 == json_object_set (state, - "pay-arguments", + "pay_arguments", (json_t *) arguments)); return upload (state, cb, @@ -4513,7 +4714,7 @@ pay_policies_backup (json_t *state, if (NULL != arguments) GNUNET_assert (0 == json_object_set (state, - "pay-arguments", + "pay_arguments", (json_t *) arguments)); return upload (state, cb, @@ -4596,6 +4797,11 @@ ANASTASIS_backup_action_ (json_t *state, }, { ANASTASIS_BACKUP_STATE_AUTHENTICATIONS_EDITING, + "poll_providers", + &ANASTASIS_REDUX_poll_providers_ + }, + { + ANASTASIS_BACKUP_STATE_AUTHENTICATIONS_EDITING, "back", &ANASTASIS_back_generic_decrement_ }, @@ -4674,7 +4880,7 @@ ANASTASIS_backup_action_ (json_t *state, "back", &back_finished }, - { ANASTASIS_BACKUP_STATE_ERROR, NULL, NULL } + { ANASTASIS_BACKUP_STATE_INVALID, NULL, NULL } }; const char *s = json_string_value (json_object_get (state, "backup_state")); @@ -4682,7 +4888,7 @@ ANASTASIS_backup_action_ (json_t *state, GNUNET_assert (NULL != s); /* holds as per invariant of caller */ bs = ANASTASIS_backup_state_from_string_ (s); - if (ANASTASIS_BACKUP_STATE_ERROR == bs) + if (ANASTASIS_BACKUP_STATE_INVALID == bs) { ANASTASIS_redux_fail_ (cb, cb_cls, @@ -4935,7 +5141,25 @@ ANASTASIS_REDUX_backup_begin_ (json_t *state, json_object_foreach (provider_list, url, prov) { struct BackupStartStateProviderEntry *pe; json_t *istate; + const char *status; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ("status", + &status), + GNUNET_JSON_spec_end () + }; + if (GNUNET_OK != + GNUNET_JSON_parse (prov, + spec, + NULL, NULL)) + { + /* skip malformed provider entry */ + GNUNET_break_op (0); + continue; + } + if (0 == strcmp (status, + "disabled")) + continue; pe = GNUNET_new (struct BackupStartStateProviderEntry); pe->bss = bss; istate = json_object (); |