diff options
Diffstat (limited to 'src/exchange/taler-exchange-httpd_management_extensions.c')
-rw-r--r-- | src/exchange/taler-exchange-httpd_management_extensions.c | 190 |
1 files changed, 92 insertions, 98 deletions
diff --git a/src/exchange/taler-exchange-httpd_management_extensions.c b/src/exchange/taler-exchange-httpd_management_extensions.c index 17db8e8c4..3b24bace7 100644 --- a/src/exchange/taler-exchange-httpd_management_extensions.c +++ b/src/exchange/taler-exchange-httpd_management_extensions.c @@ -31,7 +31,6 @@ #include "taler_extensions.h" #include "taler_dbevents.h" - /** * Extension carries the necessary data for a particular extension. * @@ -39,7 +38,7 @@ struct Extension { enum TALER_Extension_Type type; - json_t *config; + json_t *manifest; }; /** @@ -53,7 +52,7 @@ struct SetExtensionsContext }; /** - * Function implementing database transaction to set the configuration of + * Function implementing database transaction to set the manifests of * extensions. It runs the transaction logic. * - IF it returns a non-error code, the transaction logic MUST NOT queue a * MHD response. @@ -75,24 +74,24 @@ set_extensions (void *cls, { struct SetExtensionsContext *sec = cls; - /* save the configurations of all extensions */ + /* save the manifests of all extensions */ for (uint32_t i = 0; i<sec->num_extensions; i++) { struct Extension *ext = &sec->extensions[i]; + const struct TALER_Extension *taler_ext; enum GNUNET_DB_QueryStatus qs; - char *config; + char *manifest; - /* Sanity check. - * TODO: This will not work anymore, once we have plugable extensions - */ - if (0 > ext->type || TALER_Extension_MaxPredefined <= ext->type) + taler_ext = TALER_extensions_get_by_type (ext->type); + if (NULL == taler_ext) { + /* No such extension found */ GNUNET_break (0); return GNUNET_DB_STATUS_HARD_ERROR; } - config = json_dumps (ext->config, JSON_COMPACT | JSON_SORT_KEYS); - if (NULL == config) + manifest = json_dumps (ext->manifest, JSON_COMPACT | JSON_SORT_KEYS); + if (NULL == manifest) { GNUNET_break (0); *mhd_ret = TALER_MHD_reply_with_error (connection, @@ -102,10 +101,12 @@ set_extensions (void *cls, return GNUNET_DB_STATUS_HARD_ERROR; } - qs = TEH_plugin->set_extension_config ( + qs = TEH_plugin->set_extension_manifest ( TEH_plugin->cls, - TEH_extensions[ext->type]->name, - config); + taler_ext->name, + manifest); + + free (manifest); if (qs < 0) { @@ -120,37 +121,90 @@ set_extensions (void *cls, /* Success, trigger event */ { - enum TALER_Extension_Type *type = &sec->extensions[i].type; + uint32_t nbo_type = htonl (sec->extensions[i].type); struct GNUNET_DB_EventHeaderP ev = { .size = htons (sizeof (ev)), .type = htons (TALER_DBEVENT_EXCHANGE_EXTENSIONS_UPDATED) }; + TEH_plugin->event_notify (TEH_plugin->cls, &ev, - type, - sizeof(*type)); + &nbo_type, + sizeof(nbo_type)); } } /* All extensions configured, update the signature */ TEH_extensions_sig = sec->extensions_sig; + TEH_extensions_signed = true; return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; /* only 'success', so >=0, matters here */ } +static enum GNUNET_GenericReturnValue +verify_extensions_from_json ( + const json_t *extensions, + struct SetExtensionsContext *sec) +{ + const char*name; + const struct TALER_Extension *extension; + size_t i = 0; + json_t *manifest; + + GNUNET_assert (NULL != extensions); + GNUNET_assert (json_is_object (extensions)); + + sec->num_extensions = json_object_size (extensions); + sec->extensions = GNUNET_new_array (sec->num_extensions, + struct Extension); + + json_object_foreach ((json_t *) extensions, name, manifest) + { + int critical = 0; + json_t *config; + const char *version = NULL; + + /* load and verify criticality, version, etc. */ + extension = TALER_extensions_get_by_name (name); + if (NULL == extension) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "no such extension: %s\n", name); + return GNUNET_SYSERR; + } + + if (GNUNET_OK != + TALER_extensions_parse_manifest ( + manifest, &critical, &version, &config)) + return GNUNET_SYSERR; + + if (critical != extension->critical + || 0 != strcmp (version, extension->version) // FIXME-oec: libtool compare + || NULL == config + || GNUNET_OK != extension->load_config (config, NULL)) + return GNUNET_SYSERR; + + sec->extensions[i].type = extension->type; + sec->extensions[i].manifest = json_copy (manifest); + } + + return GNUNET_OK; +} + + MHD_RESULT TEH_handler_management_post_extensions ( struct MHD_Connection *connection, const json_t *root) { MHD_RESULT ret; - json_t *extensions; + const json_t *extensions; struct SetExtensionsContext sec = {0}; struct GNUNET_JSON_Specification top_spec[] = { - GNUNET_JSON_spec_json ("extensions", - &extensions), + GNUNET_JSON_spec_object_const ("extensions", + &extensions), GNUNET_JSON_spec_fixed_auto ("extensions_sig", &sec.extensions_sig), GNUNET_JSON_spec_end () @@ -169,36 +223,19 @@ TEH_handler_management_post_extensions ( return MHD_YES; /* failure */ } - /* Ensure we have an object */ - if (! json_is_object (extensions)) - { - GNUNET_JSON_parse_free (top_spec); - return TALER_MHD_reply_with_error ( - connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "invalid object"); - } - /* Verify the signature */ { - struct TALER_ExtensionConfigHash h_config; - if (GNUNET_OK != TALER_extension_config_hash (extensions, &h_config)) - { - GNUNET_JSON_parse_free (top_spec); - return TALER_MHD_reply_with_error ( - connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "invalid object, non-hashable"); - } - - if (GNUNET_OK != TALER_exchange_offline_extension_config_hash_verify ( - &h_config, + struct TALER_ExtensionManifestsHashP h_manifests; + + if (GNUNET_OK != + TALER_JSON_extensions_manifests_hash (extensions, + &h_manifests) || + GNUNET_OK != + TALER_exchange_offline_extension_manifests_hash_verify ( + &h_manifests, &TEH_master_public_key, &sec.extensions_sig)) { - GNUNET_JSON_parse_free (top_spec); return TALER_MHD_reply_with_error ( connection, MHD_HTTP_BAD_REQUEST, @@ -207,62 +244,20 @@ TEH_handler_management_post_extensions ( } } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received /management/extensions\n"); - sec.num_extensions = json_object_size (extensions); - sec.extensions = GNUNET_new_array (sec.num_extensions, - struct Extension); - /* Now parse individual extensions and signatures from those objects. */ + if (GNUNET_OK != + verify_extensions_from_json (extensions, &sec)) { - const struct TALER_Extension *extension; - const char *name; - json_t *config; - int idx = 0; - - json_object_foreach (extensions, name, config){ - - /* 1. Make sure name refers to a supported extension */ - if (GNUNET_OK != TALER_extension_get_by_name (name, - (const struct - TALER_Extension **) - TEH_extensions, - &extension)) - { - ret = TALER_MHD_reply_with_error ( - connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "invalid extension type"); - goto CLEANUP; - } - - sec.extensions[idx].config = config; - sec.extensions[idx].type = extension->type; - - /* 2. Make sure the config is sound */ - if (GNUNET_OK != extension->test_config (sec.extensions[idx].config)) - { - ret = TALER_MHD_reply_with_error ( - connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "invalid configuration for extension"); - goto CLEANUP; - } - - /* We have a validly signed JSON object for the extension. Increment its - * refcount. - */ - json_incref (sec.extensions[idx].config); - idx++; - - } /* json_object_foreach */ + return TALER_MHD_reply_with_error ( + connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "invalid object"); } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received %u extensions\n", sec.num_extensions); @@ -273,7 +268,7 @@ TEH_handler_management_post_extensions ( res = TEH_DB_run_transaction (connection, "set extensions", - TEH_MT_OTHER, + TEH_MT_REQUEST_OTHER, &ret, &set_extensions, &sec); @@ -292,13 +287,12 @@ TEH_handler_management_post_extensions ( CLEANUP: for (unsigned int i = 0; i < sec.num_extensions; i++) { - if (NULL != sec.extensions[i].config) + if (NULL != sec.extensions[i].manifest) { - json_decref (sec.extensions[i].config); + json_decref (sec.extensions[i].manifest); } } GNUNET_free (sec.extensions); - GNUNET_JSON_parse_free (top_spec); return ret; } |