diff options
| author | Özgür Kesim <oec-taler@kesim.org> | 2022-11-04 12:18:16 +0100 | 
|---|---|---|
| committer | Özgür Kesim <oec-taler@kesim.org> | 2022-11-04 12:18:16 +0100 | 
| commit | 752f10273860d2496fc3eb1e03de6ad4451e7c0f (patch) | |
| tree | 53d51969f58611dbf8afacdcd40a769f5c847dd8 /src/extensions | |
| parent | c89bfa9026d7180eb24ae9480f225b93db22c53a (diff) | |
policy extensions and age restriction refactoring
- refactoring of extension-plugin-mechanism
- refactoring of age restriction extension
- added policy extensions plugin plumbing
- added DB schema and api
  - policy_details
  - policy_fulfillments
Diffstat (limited to 'src/extensions')
| -rw-r--r-- | src/extensions/Makefile.am | 5 | ||||
| -rw-r--r-- | src/extensions/age_restriction/Makefile.am | 33 | ||||
| -rw-r--r-- | src/extensions/age_restriction/age_restriction.c | 258 | ||||
| -rw-r--r-- | src/extensions/age_restriction_helper.c | 73 | ||||
| -rw-r--r-- | src/extensions/extension_age_restriction.c | 409 | ||||
| -rw-r--r-- | src/extensions/extensions.c | 231 | 
6 files changed, 530 insertions, 479 deletions
diff --git a/src/extensions/Makefile.am b/src/extensions/Makefile.am index 5d4ed128..c867a951 100644 --- a/src/extensions/Makefile.am +++ b/src/extensions/Makefile.am @@ -11,7 +11,7 @@ if USE_COVERAGE  endif -# Libraries +# Basic extension handling library  lib_LTLIBRARIES = \    libtalerextensions.la @@ -22,7 +22,7 @@ libtalerextensions_la_LDFLAGS = \  libtalerextensions_la_SOURCES = \    extensions.c \ -  extension_age_restriction.c +  age_restriction_helper.c  libtalerextensions_la_LIBADD = \    $(top_builddir)/src/json/libtalerjson.la \ @@ -31,3 +31,4 @@ libtalerextensions_la_LIBADD = \    -lgnunetutil \    -ljansson \    $(XLIB) + diff --git a/src/extensions/age_restriction/Makefile.am b/src/extensions/age_restriction/Makefile.am new file mode 100644 index 00000000..85d67653 --- /dev/null +++ b/src/extensions/age_restriction/Makefile.am @@ -0,0 +1,33 @@ +# This Makefile.am is in the public domain + +AM_CPPFLAGS = \ +  -I$(top_srcdir)/src/include \ +  $(LIBGCRYPT_CFLAGS) \ +  $(POSTGRESQL_CPPFLAGS) + +if USE_COVERAGE +  AM_CFLAGS = --coverage -O0 +  XLIB = -lgcov +endif + +# Age restriction as extension library + +plugindir = $(libdir)/taler + +plugin_LTLIBRARIES = \ +  libtaler_extension_age_restriction.la + +libtaler_extension_age_restriction_la_LDFLAGS = \ +  -version-info 0:0:0 \ +  -no-undefined + +libtaler_extension_age_restriction_la_SOURCES = \ +  age_restriction.c + +libtaler_extension_age_restriction_la_LIBADD = \ +  $(top_builddir)/src/json/libtalerjson.la \ +  $(top_builddir)/src/util/libtalerutil.la \ +  -lgnunetjson \ +  -lgnunetutil \ +  -ljansson \ +  $(XLIB) diff --git a/src/extensions/age_restriction/age_restriction.c b/src/extensions/age_restriction/age_restriction.c new file mode 100644 index 00000000..58124250 --- /dev/null +++ b/src/extensions/age_restriction/age_restriction.c @@ -0,0 +1,258 @@ +/* +   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 age_restriction.c + * @brief Utility functions regarding age restriction + * @author Özgür Kesim + */ +#include "platform.h" +#include "taler_util.h" +#include "taler_extensions.h" +#include "stdint.h" + +/* ================================================== + * + * Age Restriction  TALER_Extension implementation + * + * ================================================== + */ + +/** + * @brief local configuration + */ + +static struct TALER_AgeRestrictionConfig AR_config = {0}; + +/** + * @brief implements the TALER_Extension.disable interface. + * + * @param ext Pointer to the current extension + */ +static void +age_restriction_disable ( +  struct TALER_Extension *ext) +{ +  if (NULL == ext) +    return; + +  ext->enabled = false; +  ext->config = NULL; + +  AR_config.mask.bits = 0; +  AR_config.num_groups = 0; +} + + +/** + * @brief implements the TALER_Extension.load_config interface. + * + * @param ext if NULL, only tests the configuration + * @param jconfig the configuration as json + */ +static enum GNUNET_GenericReturnValue +age_restriction_load_config ( +  struct TALER_Extension *ext, +  json_t *jconfig) +{ +  struct TALER_AgeMask mask = {0}; +  enum GNUNET_GenericReturnValue ret; + +  ret = TALER_JSON_parse_age_groups (jconfig, &mask); +  if (GNUNET_OK != ret) +    return ret; + +  /* only testing the parser */ +  if (ext == NULL) +    return GNUNET_OK; + +  if (TALER_Extension_AgeRestriction != ext->type) +    return GNUNET_SYSERR; + +  if (mask.bits > 0) +  { +    /* if the mask is not zero, the first bit MUST be set */ +    if (0 == (mask.bits & 1)) +      return GNUNET_SYSERR; + +    AR_config.mask.bits = mask.bits; +    AR_config.num_groups = __builtin_popcount (mask.bits) - 1; +  } + +  ext->config = &AR_config; +  ext->enabled = true; +  json_decref (jconfig); + +  GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +              "loaded new age restriction config with age groups: %s\n", +              TALER_age_mask_to_string (&mask)); + +  return GNUNET_OK; +} + + +/** + * @brief implements the TALER_Extension.manifest interface. + * + * @param ext if NULL, only tests the configuration + * @return configuration as json_t* object, maybe NULL + */ +static json_t * +age_restriction_manifest ( +  const struct TALER_Extension *ext) +{ +  char *mask_str; +  json_t *conf; + +  GNUNET_assert (NULL != ext); + +  if (NULL == ext->config) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                "age restriction not configured"); +    return json_null (); +  } + +  mask_str = TALER_age_mask_to_string (&AR_config.mask); +  conf = GNUNET_JSON_PACK ( +    GNUNET_JSON_pack_string ("age_groups", mask_str) +    ); + +  free (mask_str); + +  return GNUNET_JSON_PACK ( +    GNUNET_JSON_pack_bool ("critical", ext->critical), +    GNUNET_JSON_pack_string ("version", ext->version), +    GNUNET_JSON_pack_object_steal ("config", conf) +    ); +} + + +/* The extension for age restriction */ +struct TALER_Extension TE_age_restriction = { +  .type = TALER_Extension_AgeRestriction, +  .name = "age_restriction", +  .critical = false, +  .version = "1", +  .enabled = false, /* disabled per default */ +  .config = NULL, +  .disable = &age_restriction_disable, +  .load_config = &age_restriction_load_config, +  .manifest = &age_restriction_manifest, + +  /* This extension is not a policy extension */ +  .create_policy_details = NULL, +  .policy_get_handler = NULL, +  .policy_post_handler = NULL, +}; + + +/** + * @brief implements the init() function for GNUNET_PLUGIN_load + * + * @param arg Pointer to the GNUNET_CONFIGURATION_Handle + * @return pointer to TALER_Extension on success or NULL otherwise. + */ +void * +libtaler_extension_age_restriction_init (void *arg) +{ +  const struct GNUNET_CONFIGURATION_Handle *cfg = arg; +  char *groups = NULL; +  struct TALER_AgeMask mask = {0}; + +  if ((GNUNET_YES != +       GNUNET_CONFIGURATION_have_value (cfg, +                                        TALER_EXTENSION_SECTION_AGE_RESTRICTION, +                                        "ENABLED")) +      || +      (GNUNET_YES != +       GNUNET_CONFIGURATION_get_value_yesno (cfg, +                                             TALER_EXTENSION_SECTION_AGE_RESTRICTION, +                                             "ENABLED"))) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                "[age restriction] no section %s found in configuration\n", +                TALER_EXTENSION_SECTION_AGE_RESTRICTION); + +    return NULL; +  } + +  /* Age restriction is enabled, extract age groups */ +  if ((GNUNET_YES == +       GNUNET_CONFIGURATION_have_value (cfg, +                                        TALER_EXTENSION_SECTION_AGE_RESTRICTION, +                                        "AGE_GROUPS")) +      && +      (GNUNET_YES != +       GNUNET_CONFIGURATION_get_value_string (cfg, +                                              TALER_EXTENSION_SECTION_AGE_RESTRICTION, +                                              "AGE_GROUPS", +                                              &groups))) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                "[age restriction] AGE_GROUPS in %s is not a string\n", +                TALER_EXTENSION_SECTION_AGE_RESTRICTION); + +    return NULL; +  } + +  mask.bits = TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_MASK; + +  if ((groups != NULL) && +      (GNUNET_OK != TALER_parse_age_group_string (groups, &mask))) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                "[age restriction] couldn't parse age groups: '%s'\n", +                groups); +    return NULL; +  } + +  AR_config.mask = mask; +  AR_config.num_groups = __builtin_popcount (mask.bits) - 1;   /* no underflow, first bit always set */ + +  GNUNET_log (GNUNET_ERROR_TYPE_INFO, +              "[age restriction] setting age mask to %s with #groups: %d\n", +              TALER_age_mask_to_string (&AR_config.mask), +              __builtin_popcount (AR_config.mask.bits) - 1); + +  TE_age_restriction.config = &AR_config; + +  /* Note: we do now have TE_age_restriction_config set, however the extension +   * is not yet enabled! For age restriction to become active, load_config must +   * have been called. */ + +  GNUNET_free (groups); +  return &TE_age_restriction; +} + + +/** + * @brief implements the done() function for GNUNET_PLUGIN_load + * + * @param cfg unsued + * @return pointer to TALER_Extension on success or NULL otherwise. + */ +void * +libtaler_extension_age_restriction_done (void *arg) +{ +  GNUNET_log (GNUNET_ERROR_TYPE_INFO, +              "[age restriction] disabling and unloading"); +  AR_config.mask.bits = 0; +  AR_config.num_groups = 0; +  return NULL; +} + + +/* end of age_restriction.c */ diff --git a/src/extensions/age_restriction_helper.c b/src/extensions/age_restriction_helper.c new file mode 100644 index 00000000..8ba83511 --- /dev/null +++ b/src/extensions/age_restriction_helper.c @@ -0,0 +1,73 @@ +/* +   This file is part of TALER +   Copyright (C) 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 age_restriction_helper.c + * @brief Helper functions for age restriction + * @author Özgür Kesim + */ + +#include "platform.h" +#include "taler_util.h" +#include "taler_signatures.h" +#include "taler_extensions.h" +#include "stdint.h" + + +const struct TALER_AgeRestrictionConfig * +TALER_extensions_get_age_restriction_config () +{ +  const struct TALER_Extension *ext; + +  ext = TALER_extensions_get_by_type (TALER_Extension_AgeRestriction); +  if (NULL == ext) +    return NULL; + +  return ext->config; +} + + +bool +TALER_extensions_is_age_restriction_enabled () +{ +  const struct TALER_Extension *ext; + +  ext = TALER_extensions_get_by_type (TALER_Extension_AgeRestriction); +  if (NULL == ext) +    return false; + +  return ext->enabled; +} + + +struct TALER_AgeMask +TALER_extensions_get_age_restriction_mask () +{ +  const struct TALER_Extension *ext; +  const struct TALER_AgeRestrictionConfig *conf; + +  ext = TALER_extensions_get_by_type (TALER_Extension_AgeRestriction); + +  if ((NULL == ext) || +      (NULL == ext->config)) +    return (struct TALER_AgeMask) {0} +  ; + +  conf = ext->config; +  return conf->mask; +} + + +/* end age_restriction_helper.c */ diff --git a/src/extensions/extension_age_restriction.c b/src/extensions/extension_age_restriction.c deleted file mode 100644 index 00a03841..00000000 --- a/src/extensions/extension_age_restriction.c +++ /dev/null @@ -1,409 +0,0 @@ -/* -   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 extension_age_restriction.c - * @brief Utility functions regarding age restriction - * @author Özgür Kesim - */ -#include "platform.h" -#include "taler_util.h" -#include "taler_extensions.h" -#include "stdint.h" - -/** - * Carries all the information we need for age restriction - */ -struct age_restriction_config -{ -  struct TALER_AgeMask mask; -  size_t num_groups; -}; - -/** - * Global config for this extension - */ -static struct age_restriction_config TE_age_restriction_config = {0}; - -enum GNUNET_GenericReturnValue -TALER_parse_age_group_string ( -  const char *groups, -  struct TALER_AgeMask *mask) -{ - -  const char *pos = groups; -  unsigned int prev = 0; -  unsigned int val = 0; -  char c; - -  while (*pos) -  { -    c = *pos++; -    if (':' == c) -    { -      if (prev >= val) -        return GNUNET_SYSERR; - -      mask->bits |= 1 << val; -      prev = val; -      val = 0; -      continue; -    } - -    if ('0'>c || '9'<c) -      return GNUNET_SYSERR; - -    val = 10 * val + c - '0'; - -    if (0>=val || 32<=val) -      return GNUNET_SYSERR; -  } - -  if (32<=val || prev>=val) -    return GNUNET_SYSERR; - -  mask->bits |= (1 << val); -  mask->bits |= 1; // mark zeroth group, too - -  return GNUNET_OK; -} - - -char * -TALER_age_mask_to_string ( -  const struct TALER_AgeMask *mask) -{ -  uint32_t bits = mask->bits; -  unsigned int n = 0; -  char *buf = GNUNET_malloc (32 * 3); // max characters possible -  char *pos = buf; - -  if (NULL == buf) -  { -    return buf; -  } - -  while (bits != 0) -  { -    bits >>= 1; -    n++; -    if (0 == (bits & 1)) -    { -      continue; -    } - -    if (n > 9) -    { -      *(pos++) = '0' + n / 10; -    } -    *(pos++) = '0' + n % 10; - -    if (0 != (bits >> 1)) -    { -      *(pos++) = ':'; -    } -  } -  return buf; -} - - -/* ================================================== - * - * Age Restriction  TALER_Extension implementation - * - * ================================================== - */ - -/** - * @brief implements the TALER_Extension.disable interface. - * - * @param ext Pointer to the current extension - */ -static void -age_restriction_disable ( -  struct TALER_Extension *ext) -{ -  if (NULL == ext) -    return; - -  ext->config = NULL; - -  if (NULL != ext->config_json) -  { -    json_decref (ext->config_json); -    ext->config_json = NULL; -  } - -  TE_age_restriction_config.mask.bits = 0; -  TE_age_restriction_config.num_groups = 0; -} - - -/** - * @brief implements the TALER_Extension.load_taler_config interface. - * - * @param ext Pointer to the current extension - * @param cfg Handle to the GNUNET configuration - * @return Error if extension for age restriction was set, but age groups were - *         invalid, OK otherwise. - */ -static enum GNUNET_GenericReturnValue -age_restriction_load_taler_config ( -  struct TALER_Extension *ext, -  const struct GNUNET_CONFIGURATION_Handle *cfg) -{ -  char *groups = NULL; -  enum GNUNET_GenericReturnValue ret = GNUNET_SYSERR; -  struct TALER_AgeMask mask = {0}; - -  if ((GNUNET_YES != -       GNUNET_CONFIGURATION_have_value (cfg, -                                        TALER_EXTENSION_SECTION_AGE_RESTRICTION, -                                        "ENABLED")) -      || -      (GNUNET_YES != -       GNUNET_CONFIGURATION_get_value_yesno (cfg, -                                             TALER_EXTENSION_SECTION_AGE_RESTRICTION, -                                             "ENABLED"))) -  { -    /* Age restriction is not enabled */ -    ext->config = NULL; -    ext->config_json = NULL; -    return GNUNET_OK; -  } - -  /* Age restriction is enabled, extract age groups */ -  if ((GNUNET_YES == -       GNUNET_CONFIGURATION_have_value (cfg, -                                        TALER_EXTENSION_SECTION_AGE_RESTRICTION, -                                        "AGE_GROUPS")) -      && -      (GNUNET_YES != -       GNUNET_CONFIGURATION_get_value_string (cfg, -                                              TALER_EXTENSION_SECTION_AGE_RESTRICTION, -                                              "AGE_GROUPS", -                                              &groups))) -    return GNUNET_SYSERR; - - -  mask.bits = TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_MASK; -  ret = GNUNET_OK; - -  if (groups != NULL) -  { -    ret = TALER_parse_age_group_string (groups, &mask); -    if (GNUNET_OK != ret) -      mask.bits = TALER_EXTENSION_AGE_RESTRICTION_DEFAULT_AGE_MASK; -  } - -  if (GNUNET_OK == ret) -  { -    GNUNET_log (GNUNET_ERROR_TYPE_INFO, -                "setting age mask to %x with #groups: %d\n", mask.bits, -                __builtin_popcount (mask.bits) - 1); -    TE_age_restriction_config.mask.bits = mask.bits; -    TE_age_restriction_config.num_groups = __builtin_popcount (mask.bits) - 1; /* no underflow, first bit always set */ -    ext->config = &TE_age_restriction_config; - -    /* Note: we do now have TE_age_restriction_config set, however -     * ext->config_json is NOT set, i.e. the extension is not yet active! For -     * age restriction to become active, load_json_config must have been -     * called. */ -  } - - -  GNUNET_free (groups); -  return ret; -} - - -/** - * @brief implements the TALER_Extension.load_json_config interface. - * - * @param ext if NULL, only tests the configuration - * @param jconfig the configuration as json - */ -static enum GNUNET_GenericReturnValue -age_restriction_load_json_config ( -  struct TALER_Extension *ext, -  json_t *jconfig) -{ -  struct TALER_AgeMask mask = {0}; -  enum GNUNET_GenericReturnValue ret; - -  ret = TALER_JSON_parse_age_groups (jconfig, &mask); -  if (GNUNET_OK != ret) -    return ret; - -  /* only testing the parser */ -  if (ext == NULL) -    return GNUNET_OK; - -  if (TALER_Extension_AgeRestriction != ext->type) -    return GNUNET_SYSERR; - -  TE_age_restriction_config.mask.bits = mask.bits; -  TE_age_restriction_config.num_groups = 0; - -  if (mask.bits > 0) -  { -    /* if the mask is not zero, the first bit MUST be set */ -    if (0 == (mask.bits & 1)) -      return GNUNET_SYSERR; - -    TE_age_restriction_config.num_groups = __builtin_popcount (mask.bits) - 1; -  } - -  ext->config = &TE_age_restriction_config; - -  if (NULL != ext->config_json) -    json_decref (ext->config_json); - -  ext->config_json = jconfig; - -  GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -              "loaded new age restriction config with age groups: %s\n", -              TALER_age_mask_to_string (&mask)); - -  return GNUNET_OK; -} - - -/** - * @brief implements the TALER_Extension.config_to_json interface. - * - * @param ext if NULL, only tests the configuration - * @return configuration as json_t* object, maybe NULL - */ -static json_t * -age_restriction_config_to_json ( -  const struct TALER_Extension *ext) -{ -  char *mask_str; -  json_t *conf; - -  GNUNET_assert (NULL != ext); - -  if (NULL == ext->config) -  { -    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                "age restriction not configured"); -    return json_null (); -  } - -  if (NULL != ext->config_json) -  { -    return json_copy (ext->config_json); -  } - -  mask_str = TALER_age_mask_to_string (&TE_age_restriction_config.mask); -  conf = GNUNET_JSON_PACK ( -    GNUNET_JSON_pack_string ("age_groups", mask_str) -    ); - -  return GNUNET_JSON_PACK ( -    GNUNET_JSON_pack_bool ("critical", ext->critical), -    GNUNET_JSON_pack_string ("version", ext->version), -    GNUNET_JSON_pack_object_steal ("config", conf) -    ); -} - - -/** - * @brief implements the TALER_Extension.test_json_config interface. - * - * @param config configuration as json_t* to test - * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise. - */ -static enum GNUNET_GenericReturnValue -age_restriction_test_json_config ( -  const json_t *config) -{ -  struct TALER_AgeMask mask = {0}; - -  return TALER_JSON_parse_age_groups (config, &mask); -} - - -/* The extension for age restriction */ -struct TALER_Extension TE_age_restriction = { -  .next = NULL, -  .type = TALER_Extension_AgeRestriction, -  .name = "age_restriction", -  .critical = false, -  .version = "1", -  .config = NULL,   // disabled per default -  .config_json = NULL, -  .disable = &age_restriction_disable, -  .test_json_config = &age_restriction_test_json_config, -  .load_json_config = &age_restriction_load_json_config, -  .config_to_json = &age_restriction_config_to_json, -  .load_taler_config = &age_restriction_load_taler_config, -}; - -enum GNUNET_GenericReturnValue -TALER_extension_age_restriction_register () -{ -  return TALER_extensions_add (&TE_age_restriction); -} - - -bool -TALER_extensions_age_restriction_is_configured () -{ -  return (0 != TE_age_restriction_config.mask.bits); -} - - -struct TALER_AgeMask -TALER_extensions_age_restriction_ageMask () -{ -  return TE_age_restriction_config.mask; -} - - -size_t -TALER_extensions_age_restriction_num_groups () -{ -  return TE_age_restriction_config.num_groups; -} - - -enum GNUNET_GenericReturnValue -TALER_JSON_parse_age_groups (const json_t *root, -                             struct TALER_AgeMask *mask) -{ -  enum GNUNET_GenericReturnValue ret; -  const char *str; -  struct GNUNET_JSON_Specification spec[] = { -    GNUNET_JSON_spec_string ("age_groups", -                             &str), -    GNUNET_JSON_spec_end () -  }; - -  ret = GNUNET_JSON_parse (root, -                           spec, -                           NULL, -                           NULL); -  if (GNUNET_OK == ret) -    TALER_parse_age_group_string (str, mask); - -  GNUNET_JSON_parse_free (spec); - -  return ret; -} - - -/* end of extension_age_restriction.c */ diff --git a/src/extensions/extensions.c b/src/extensions/extensions.c index 0df0bae3..2ed973d9 100644 --- a/src/extensions/extensions.c +++ b/src/extensions/extensions.c @@ -24,51 +24,53 @@  #include "taler_extensions.h"  #include "stdint.h" -  /* head of the list of all registered extensions */ -static struct TALER_Extension *TE_extensions = NULL; - +static struct TALER_Extensions TE_extensions = { +  .next = NULL, +  .extension = NULL, +}; -const struct TALER_Extension * +const struct TALER_Extensions *  TALER_extensions_get_head ()  { -  return TE_extensions; +  return &TE_extensions;  } -enum GNUNET_GenericReturnValue -TALER_extensions_add ( -  struct TALER_Extension *extension) +static enum GNUNET_GenericReturnValue +add_extension ( +  const struct TALER_Extension *extension)  {    /* Sanity checks */    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)) +      (NULL == extension->load_config) || +      (NULL == extension->manifest))    {      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,                  "invalid extension\n");      return GNUNET_SYSERR;    } -  if (NULL == TE_extensions) /* first extension ?*/ -    TE_extensions = (struct TALER_Extension *) extension; +  if (NULL == TE_extensions.extension) /* first extension ?*/ +    TE_extensions.extension = extension;    else    { -    struct TALER_Extension *iter; -    struct TALER_Extension *last; +    struct TALER_Extensions *iter; +    struct TALER_Extensions *last;      /* Check for collisions */ -    for (iter = TE_extensions; NULL != iter; iter = iter->next) +    for (iter = &TE_extensions; +         NULL != iter && NULL != iter->extension; +         iter = iter->next)      { +      const struct TALER_Extension *ext = iter->extension;        last = iter; -      if (extension->type == iter->type || +      if (extension->type == ext->type ||            0 == strcasecmp (extension->name, -                           iter->name)) +                           ext->name))        {          GNUNET_log (GNUNET_ERROR_TYPE_ERROR,                      "extension collision for `%s'\n", @@ -78,7 +80,11 @@ TALER_extensions_add (      }      /* No collisions found, so add this extension to the list */ -    last->next = extension; +    { +      struct TALER_Extensions *extn = GNUNET_new (struct TALER_Extensions); +      extn->extension = extension; +      last->next = extn; +    }    }    return GNUNET_OK; @@ -89,12 +95,12 @@ const struct TALER_Extension *  TALER_extensions_get_by_type (    enum TALER_Extension_Type type)  { -  for (const struct TALER_Extension *it = TE_extensions; -       NULL != it; +  for (const struct TALER_Extensions *it = &TE_extensions; +       NULL != it && NULL != it->extension;         it = it->next)    { -    if (it->type == type) -      return it; +    if (it->extension->type == type) +      return it->extension;    }    /* No extension found. */ @@ -109,8 +115,7 @@ TALER_extensions_is_enabled_type (    const struct TALER_Extension *ext =      TALER_extensions_get_by_type (type); -  return (NULL != ext && -          TALER_extensions_is_enabled (ext)); +  return (NULL != ext && ext->enabled);  } @@ -118,33 +123,34 @@ const struct TALER_Extension *  TALER_extensions_get_by_name (    const char *name)  { -  for (const struct TALER_Extension *it = TE_extensions; +  for (const struct TALER_Extensions *it = &TE_extensions;         NULL != it;         it = it->next)    { -    if (0 == strcasecmp (name, it->name)) -      return it; +    if (0 == strcasecmp (name, it->extension->name)) +      return it->extension;    } -  /* No extension found. */ +  /* No extension found, try to load it. */ +    return NULL;  }  enum GNUNET_GenericReturnValue -TALER_extensions_verify_json_config_signature ( -  json_t *extensions, +TALER_extensions_verify_manifests_signature ( +  json_t *manifests,    struct TALER_MasterSignatureP *extensions_sig,    struct TALER_MasterPublicKeyP *master_pub)  { -  struct TALER_ExtensionConfigHashP h_config; +  struct TALER_ExtensionManifestsHashP h_manifests;    if (GNUNET_OK != -      TALER_JSON_extensions_config_hash (extensions, -                                         &h_config)) +      TALER_JSON_extensions_manifests_hash (manifests, +                                            &h_manifests))      return GNUNET_SYSERR;    if (GNUNET_OK != -      TALER_exchange_offline_extension_config_hash_verify ( -        &h_config, +      TALER_exchange_offline_extension_manifests_hash_verify ( +        &h_manifests,          master_pub,          extensions_sig))      return GNUNET_NO; @@ -178,7 +184,8 @@ configure_extension (  {    struct LoadConfClosure *col = cls;    const char *name; -  const struct TALER_Extension *extension; +  char *lib_name; +  struct TALER_Extension *extension;    if (GNUNET_OK != col->error)      return; @@ -190,33 +197,49 @@ configure_extension (    name = section + sizeof(TALER_EXTENSION_SECTION_PREFIX) - 1; -  if (NULL == -      (extension = TALER_extensions_get_by_name (name))) + +  /* Load the extension library */ +  GNUNET_asprintf (&lib_name, +                   "libtaler_extension_%s", +                   name); +  extension = GNUNET_PLUGIN_load ( +    lib_name, +    (void *) col->cfg); +  if (NULL == extension)    {      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                "Unsupported extension `%s` (section [%s]).\n", name, +                "Couldn't load extension library to `%s` (section [%s]).\n", +                name,                  section);      col->error = GNUNET_SYSERR;      return;    } -  if (GNUNET_OK != -      extension->load_taler_config ( -        (struct TALER_Extension *) extension, -        col->cfg)) + +  if (GNUNET_OK != add_extension (extension))    { +    /* TODO: Ignoring return values here */      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                "Couldn't parse configuration for extension `%s` (section [%s]).\n", +                "Couldn't add extension `%s` (section [%s]).\n",                  name,                  section);      col->error = GNUNET_SYSERR; +    GNUNET_PLUGIN_unload ( +      lib_name, +      (void *) col->cfg);      return;    } + +  GNUNET_log (GNUNET_ERROR_TYPE_INFO, +              "extension library '%s' loaded\n", +              lib_name);  } +static bool extensions_loaded = false; +  enum GNUNET_GenericReturnValue -TALER_extensions_load_taler_config ( +TALER_extensions_init (    const struct GNUNET_CONFIGURATION_Handle *cfg)  {    struct LoadConfClosure col = { @@ -224,15 +247,22 @@ TALER_extensions_load_taler_config (      .error = GNUNET_OK,    }; +  if (extensions_loaded) +    return GNUNET_OK; +    GNUNET_CONFIGURATION_iterate_sections (cfg,                                           &configure_extension,                                           &col); + +  if (GNUNET_OK == col.error) +    extensions_loaded = true; +    return col.error;  }  enum GNUNET_GenericReturnValue -TALER_extensions_is_json_config ( +TALER_extensions_parse_manifest (    json_t *obj,    int *critical,    const char **version, @@ -265,22 +295,23 @@ TALER_extensions_is_json_config (  enum GNUNET_GenericReturnValue -TALER_extensions_load_json_config ( +TALER_extensions_load_manifests (    json_t *extensions)  {    const char*name; -  json_t *blob; +  json_t *manifest;    GNUNET_assert (NULL != extensions);    GNUNET_assert (json_is_object (extensions)); -  json_object_foreach (extensions, name, blob) +  json_object_foreach (extensions, name, manifest)    {      int critical;      const char *version;      json_t *config; -    const struct TALER_Extension *extension = -      TALER_extensions_get_by_name (name); +    struct TALER_Extension *extension =  (struct +                                          TALER_Extension *) +                                        TALER_extensions_get_by_name (name);      if (NULL == extension)      { @@ -291,45 +322,109 @@ TALER_extensions_load_json_config (      /* load and verify criticality, version, etc. */      if (GNUNET_OK != -        TALER_extensions_is_json_config ( -          blob, &critical, &version, &config)) +        TALER_extensions_parse_manifest ( +          manifest, &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)) +        || GNUNET_OK != extension->load_config (NULL, config))        return GNUNET_SYSERR;      /* This _should_ work now */      if (GNUNET_OK != -        extension->load_json_config ((struct TALER_Extension *) extension, -                                     config)) +        extension->load_config (extension, config))        return GNUNET_SYSERR; + +    extension->enabled = true;    }    /* make sure to disable all extensions that weren't mentioned in the json */ -  for (const struct TALER_Extension *it = TALER_extensions_get_head (); +  for (const struct TALER_Extensions *it = TALER_extensions_get_head ();         NULL != it;         it = it->next)    { -    if (NULL == json_object_get (extensions, it->name)) -      it->disable ((struct TALER_Extension *) it); +    if (NULL == json_object_get (extensions, it->extension->name)) +      it->extension->disable ((struct TALER_Extension *) it);    }    return GNUNET_OK;  } -bool -TALER_extensions_age_restriction_is_enabled () +/* + * Policy related + */ + +static char *fulfillment2str[] =  { +  [TALER_PolicyFulfillmentReady]        = "Ready", +  [TALER_PolicyFulfillmentSuccess]      = "Success", +  [TALER_PolicyFulfillmentFailure]      = "Failure", +  [TALER_PolicyFulfillmentTimeout]      = "Timeout", +  [TALER_PolicyFulfillmentInsufficient] = "Insufficient", +}; + +const char * +TALER_policy_fulfillment_state_str ( +  enum TALER_PolicyFulfillmentState state)  { -  const struct TALER_Extension *age = -    TALER_extensions_get_by_type (TALER_Extension_AgeRestriction); +  GNUNET_assert (TALER_PolicyFulfillmentStateCount > state); +  return fulfillment2str[state]; +} + + +enum GNUNET_GenericReturnValue +TALER_extensions_create_policy_details ( +  const json_t *policy_options, +  struct TALER_PolicyDetails *details, +  const char **error_hint) +{ +  enum GNUNET_GenericReturnValue ret; +  const struct TALER_Extension *extension; +  const json_t *jtype; +  const char *type; + +  *error_hint = NULL; + +  if ((NULL == policy_options) || +      (! json_is_object (policy_options))) +  { +    *error_hint = "invalid policy object"; +    return GNUNET_SYSERR; +  } + +  jtype = json_object_get (policy_options, "type"); +  if (NULL == jtype) +  { +    *error_hint = "no type in policy object"; +    return GNUNET_SYSERR; +  } + +  type = json_string_value (jtype); +  if (NULL == type) +  { +    *error_hint = "invalid type in policy object"; +    return GNUNET_SYSERR; +  } + +  extension = TALER_extensions_get_by_name (type); +  if ((NULL == extension) || +      (NULL == extension->create_policy_details)) +  { +    GNUNET_break (0); +    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                "Unsupported extension policy '%s' requested\n", +                type); +    return GNUNET_NO; +  } + +  details->deadline = GNUNET_TIME_UNIT_FOREVER_TS; +  ret = extension->create_policy_details (policy_options, +                                          details, +                                          error_hint); +  return ret; -  return (NULL != age && -          NULL != age->config_json && -          TALER_extensions_age_restriction_is_configured ());  }  | 
