2022-01-23 01:31:02 +01:00
|
|
|
/*
|
|
|
|
This file is part of TALER
|
|
|
|
Copyright (C) 2021-2022 Taler Systems SA
|
|
|
|
|
|
|
|
TALER is free software; you can redistribute it and/or modify it under the
|
|
|
|
terms of the GNU General Public License as published by the Free Software
|
|
|
|
Foundation; either version 3, or (at your option) any later version.
|
|
|
|
|
|
|
|
TALER 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 General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
|
|
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
|
|
|
*/
|
|
|
|
/**
|
|
|
|
* @file extensions.c
|
|
|
|
* @brief Utility functions for extensions
|
|
|
|
* @author Özgür Kesim
|
|
|
|
*/
|
|
|
|
#include "platform.h"
|
|
|
|
#include "taler_util.h"
|
|
|
|
#include "taler_signatures.h"
|
|
|
|
#include "taler_extensions.h"
|
|
|
|
#include "stdint.h"
|
|
|
|
|
|
|
|
|
|
|
|
/* head of the list of all registered extensions */
|
2022-04-21 12:54:59 +02:00
|
|
|
static struct TALER_Extension *TE_extensions = NULL;
|
2022-01-23 01:31:02 +01:00
|
|
|
|
|
|
|
|
|
|
|
const struct TALER_Extension *
|
|
|
|
TALER_extensions_get_head ()
|
|
|
|
{
|
2022-04-21 12:54:59 +02:00
|
|
|
return TE_extensions;
|
2022-01-23 01:31:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
enum GNUNET_GenericReturnValue
|
|
|
|
TALER_extensions_add (
|
2022-04-21 12:54:59 +02:00
|
|
|
const struct TALER_Extension *extension)
|
2022-01-23 01:31:02 +01:00
|
|
|
{
|
|
|
|
/* Sanity checks */
|
2022-04-21 12:54:59 +02:00
|
|
|
if ((NULL == extension) ||
|
|
|
|
(NULL == extension->name) ||
|
|
|
|
(NULL == extension->version) ||
|
|
|
|
(NULL == extension->disable) ||
|
|
|
|
(NULL == extension->test_json_config) ||
|
|
|
|
(NULL == extension->load_json_config) ||
|
|
|
|
(NULL == extension->config_to_json) ||
|
|
|
|
(NULL == extension->load_taler_config))
|
2022-01-23 01:31:02 +01:00
|
|
|
{
|
2022-03-21 08:35:19 +01:00
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"invalid extension\n");
|
2022-01-23 01:31:02 +01:00
|
|
|
return GNUNET_SYSERR;
|
|
|
|
}
|
|
|
|
|
2022-04-21 12:54:59 +02:00
|
|
|
if (NULL == TE_extensions) /* first extension ?*/
|
|
|
|
TE_extensions = (struct TALER_Extension *) extension;
|
|
|
|
else
|
2022-01-23 01:31:02 +01:00
|
|
|
{
|
2022-04-21 12:54:59 +02:00
|
|
|
struct TALER_Extension *iter;
|
|
|
|
|
|
|
|
/* Check for collisions */
|
|
|
|
for (iter = TE_extensions; NULL != iter; iter = iter->next)
|
2022-01-23 01:31:02 +01:00
|
|
|
{
|
2022-04-21 12:54:59 +02:00
|
|
|
if (extension->type == iter->type ||
|
|
|
|
0 == strcasecmp (extension->name,
|
|
|
|
iter->name))
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"extension collision for `%s'\n",
|
|
|
|
extension->name);
|
|
|
|
return GNUNET_NO;
|
|
|
|
}
|
2022-01-23 01:31:02 +01:00
|
|
|
}
|
|
|
|
|
2022-04-21 12:54:59 +02:00
|
|
|
/* No collisions found, so add this extension to the list */
|
|
|
|
iter->next = (struct TALER_Extension *) extension;
|
|
|
|
}
|
2022-01-23 01:31:02 +01:00
|
|
|
|
|
|
|
return GNUNET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const struct TALER_Extension *
|
|
|
|
TALER_extensions_get_by_type (
|
|
|
|
enum TALER_Extension_Type type)
|
|
|
|
{
|
2022-04-21 12:54:59 +02:00
|
|
|
for (const struct TALER_Extension *it = TE_extensions;
|
2022-01-23 01:31:02 +01:00
|
|
|
NULL != it;
|
|
|
|
it = it->next)
|
|
|
|
{
|
|
|
|
if (it->type == type)
|
|
|
|
return it;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No extension found. */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
TALER_extensions_is_enabled_type (
|
|
|
|
enum TALER_Extension_Type type)
|
|
|
|
{
|
|
|
|
const struct TALER_Extension *ext =
|
|
|
|
TALER_extensions_get_by_type (type);
|
|
|
|
|
|
|
|
return (NULL != ext &&
|
|
|
|
TALER_extensions_is_enabled (ext));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const struct TALER_Extension *
|
|
|
|
TALER_extensions_get_by_name (
|
|
|
|
const char *name)
|
|
|
|
{
|
2022-04-21 12:54:59 +02:00
|
|
|
for (const struct TALER_Extension *it = TE_extensions;
|
2022-01-23 01:31:02 +01:00
|
|
|
NULL != it;
|
|
|
|
it = it->next)
|
|
|
|
{
|
2022-04-19 18:37:48 +02:00
|
|
|
if (0 == strcasecmp (name, it->name))
|
2022-01-23 01:31:02 +01:00
|
|
|
return it;
|
|
|
|
}
|
|
|
|
/* No extension found. */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
enum GNUNET_GenericReturnValue
|
|
|
|
TALER_extensions_verify_json_config_signature (
|
|
|
|
json_t *extensions,
|
|
|
|
struct TALER_MasterSignatureP *extensions_sig,
|
|
|
|
struct TALER_MasterPublicKeyP *master_pub)
|
|
|
|
{
|
2022-02-21 00:23:23 +01:00
|
|
|
struct TALER_ExtensionConfigHashP h_config;
|
2022-01-23 01:31:02 +01:00
|
|
|
|
|
|
|
if (GNUNET_OK !=
|
2022-03-21 08:35:19 +01:00
|
|
|
TALER_JSON_extensions_config_hash (extensions,
|
|
|
|
&h_config))
|
2022-01-23 01:31:02 +01:00
|
|
|
return GNUNET_SYSERR;
|
2022-03-21 08:35:19 +01:00
|
|
|
if (GNUNET_OK !=
|
|
|
|
TALER_exchange_offline_extension_config_hash_verify (
|
2022-01-23 01:31:02 +01:00
|
|
|
&h_config,
|
|
|
|
master_pub,
|
|
|
|
extensions_sig))
|
|
|
|
return GNUNET_NO;
|
|
|
|
return GNUNET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-04-21 12:54:59 +02:00
|
|
|
/*
|
|
|
|
* Closure used in TALER_extensions_load_taler_config during call to
|
|
|
|
* GNUNET_CONFIGURATION_iterate_sections with configure_extension.
|
|
|
|
*/
|
|
|
|
struct LoadConfClosure
|
2022-01-23 01:31:02 +01:00
|
|
|
{
|
|
|
|
const struct GNUNET_CONFIGURATION_Handle *cfg;
|
|
|
|
enum GNUNET_GenericReturnValue error;
|
|
|
|
};
|
|
|
|
|
2022-03-21 08:35:19 +01:00
|
|
|
|
2022-04-21 12:54:59 +02:00
|
|
|
/*
|
|
|
|
* Used in TALER_extensions_load_taler_config during call to
|
|
|
|
* GNUNET_CONFIGURATION_iterate_sections to load the configuration
|
|
|
|
* of supported extensions.
|
|
|
|
*
|
|
|
|
* @param cls Closure of type LoadConfClosure
|
|
|
|
* @param section name of the current section
|
|
|
|
*/
|
2022-01-23 01:31:02 +01:00
|
|
|
static void
|
2022-04-21 12:54:59 +02:00
|
|
|
configure_extension (
|
2022-01-23 01:31:02 +01:00
|
|
|
void *cls,
|
|
|
|
const char *section)
|
|
|
|
{
|
2022-04-21 12:54:59 +02:00
|
|
|
struct LoadConfClosure *col = cls;
|
2022-01-23 01:31:02 +01:00
|
|
|
const char *name;
|
|
|
|
const struct TALER_Extension *extension;
|
|
|
|
|
|
|
|
if (GNUNET_OK != col->error)
|
|
|
|
return;
|
2022-04-21 12:54:59 +02:00
|
|
|
|
2022-01-23 01:31:02 +01:00
|
|
|
if (0 != strncasecmp (section,
|
|
|
|
TALER_EXTENSION_SECTION_PREFIX,
|
|
|
|
sizeof(TALER_EXTENSION_SECTION_PREFIX) - 1))
|
|
|
|
return;
|
|
|
|
|
|
|
|
name = section + sizeof(TALER_EXTENSION_SECTION_PREFIX) - 1;
|
|
|
|
|
2022-04-21 12:54:59 +02:00
|
|
|
if (NULL ==
|
|
|
|
(extension = TALER_extensions_get_by_name (name)))
|
2022-01-23 01:31:02 +01:00
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Unsupported extension `%s` (section [%s]).\n", name,
|
|
|
|
section);
|
|
|
|
col->error = GNUNET_SYSERR;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (GNUNET_OK !=
|
|
|
|
extension->load_taler_config (
|
|
|
|
(struct TALER_Extension *) extension,
|
|
|
|
col->cfg))
|
|
|
|
{
|
|
|
|
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
|
|
"Couldn't parse configuration for extension `%s` (section [%s]).\n",
|
|
|
|
name,
|
|
|
|
section);
|
|
|
|
col->error = GNUNET_SYSERR;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
enum GNUNET_GenericReturnValue
|
|
|
|
TALER_extensions_load_taler_config (
|
|
|
|
const struct GNUNET_CONFIGURATION_Handle *cfg)
|
|
|
|
{
|
2022-04-21 12:54:59 +02:00
|
|
|
struct LoadConfClosure col = {
|
2022-01-23 01:31:02 +01:00
|
|
|
.cfg = cfg,
|
|
|
|
.error = GNUNET_OK,
|
|
|
|
};
|
|
|
|
|
|
|
|
GNUNET_CONFIGURATION_iterate_sections (cfg,
|
2022-04-21 12:54:59 +02:00
|
|
|
&configure_extension,
|
2022-01-23 01:31:02 +01:00
|
|
|
&col);
|
|
|
|
return col.error;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-02-16 22:01:05 +01:00
|
|
|
enum GNUNET_GenericReturnValue
|
|
|
|
TALER_extensions_is_json_config (
|
2022-01-23 01:31:02 +01:00
|
|
|
json_t *obj,
|
|
|
|
int *critical,
|
|
|
|
const char **version,
|
|
|
|
json_t **config)
|
|
|
|
{
|
|
|
|
enum GNUNET_GenericReturnValue ret;
|
2022-02-16 22:01:05 +01:00
|
|
|
json_t *cfg;
|
2022-01-23 01:31:02 +01:00
|
|
|
struct GNUNET_JSON_Specification spec[] = {
|
|
|
|
GNUNET_JSON_spec_boolean ("critical",
|
|
|
|
critical),
|
|
|
|
GNUNET_JSON_spec_string ("version",
|
|
|
|
version),
|
|
|
|
GNUNET_JSON_spec_json ("config",
|
2022-02-16 22:01:05 +01:00
|
|
|
&cfg),
|
2022-01-23 01:31:02 +01:00
|
|
|
GNUNET_JSON_spec_end ()
|
|
|
|
};
|
|
|
|
|
2022-04-21 12:54:59 +02:00
|
|
|
if (GNUNET_OK !=
|
|
|
|
(ret = GNUNET_JSON_parse (obj,
|
|
|
|
spec,
|
|
|
|
NULL,
|
|
|
|
NULL)))
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
*config = json_copy (cfg);
|
|
|
|
GNUNET_JSON_parse_free (spec);
|
2022-01-23 01:31:02 +01:00
|
|
|
|
2022-04-21 12:54:59 +02:00
|
|
|
return GNUNET_OK;
|
2022-01-23 01:31:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
enum GNUNET_GenericReturnValue
|
|
|
|
TALER_extensions_load_json_config (
|
|
|
|
json_t *extensions)
|
|
|
|
{
|
|
|
|
const char*name;
|
|
|
|
json_t *blob;
|
|
|
|
|
|
|
|
GNUNET_assert (NULL != extensions);
|
|
|
|
GNUNET_assert (json_is_object (extensions));
|
|
|
|
|
|
|
|
json_object_foreach (extensions, name, blob)
|
|
|
|
{
|
|
|
|
int critical;
|
|
|
|
const char *version;
|
|
|
|
json_t *config;
|
|
|
|
const struct TALER_Extension *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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* load and verify criticality, version, etc. */
|
|
|
|
if (GNUNET_OK !=
|
2022-02-16 22:01:05 +01:00
|
|
|
TALER_extensions_is_json_config (
|
2022-01-23 01:31:02 +01:00
|
|
|
blob, &critical, &version, &config))
|
|
|
|
return GNUNET_SYSERR;
|
|
|
|
|
|
|
|
if (critical != extension->critical
|
|
|
|
|| 0 != strcmp (version, extension->version) // TODO: libtool compare?
|
|
|
|
|| NULL == config
|
|
|
|
|| GNUNET_OK != extension->test_json_config (config))
|
|
|
|
return GNUNET_SYSERR;
|
|
|
|
|
|
|
|
/* This _should_ work now */
|
|
|
|
if (GNUNET_OK !=
|
|
|
|
extension->load_json_config ((struct TALER_Extension *) extension,
|
|
|
|
config))
|
|
|
|
return GNUNET_SYSERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* make sure to disable all extensions that weren't mentioned in the json */
|
|
|
|
for (const struct TALER_Extension *it = TALER_extensions_get_head ();
|
|
|
|
NULL != it;
|
|
|
|
it = it->next)
|
|
|
|
{
|
|
|
|
if (NULL == json_object_get (extensions, it->name))
|
|
|
|
it->disable ((struct TALER_Extension *) it);
|
|
|
|
}
|
|
|
|
|
|
|
|
return GNUNET_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-02-16 22:01:05 +01:00
|
|
|
bool
|
|
|
|
TALER_extensions_age_restriction_is_enabled ()
|
|
|
|
{
|
|
|
|
const struct TALER_Extension *age =
|
|
|
|
TALER_extensions_get_by_type (TALER_Extension_AgeRestriction);
|
|
|
|
|
|
|
|
return (NULL != age &&
|
|
|
|
NULL != age->config_json &&
|
|
|
|
TALER_extensions_age_restriction_is_configured ());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-01-23 01:31:02 +01:00
|
|
|
/* end of extensions.c */
|