anastasis

Credential backup and recovery protocol and service
Log | Files | Refs | Submodules | README | LICENSE

anastasis_authorization_plugin_iban.c (23113B)


      1 /*
      2   This file is part of Anastasis
      3   Copyright (C) 2021 Anastasis SARL
      4 
      5   Anastasis is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   Anastasis; see the file COPYING.GPL.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file anastasis_authorization_plugin_iban.c
     18  * @brief authorization plugin wire transfer based
     19  * @author Christian Grothoff
     20  */
     21 #include "platform.h"
     22 #include "anastasis_authorization_plugin.h"
     23 #include <taler/taler_mhd_lib.h>
     24 #include <taler/taler_json_lib.h>
     25 #include <gnunet/gnunet_db_lib.h>
     26 #include "anastasis_authorization_lib.h"
     27 #include "anastasis_database_lib.h"
     28 #include "anastasis_util_lib.h"
     29 #include "iban.h"
     30 
     31 /**
     32  * How long is a code valid once generated? Very long
     33  * here as we do not want to refuse authentication
     34  * just because the user took a while to execute the
     35  * wire transfer (and then get back to their recovery
     36  * operation).
     37  */
     38 #define CODE_VALIDITY_PERIOD GNUNET_TIME_UNIT_MONTHS
     39 
     40 
     41 /**
     42  * Saves the State of a authorization plugin.
     43  */
     44 struct IBAN_Context
     45 {
     46 
     47   /**
     48    * Messages of the plugin, read from a resource file.
     49    */
     50   json_t *messages;
     51 
     52   /**
     53    * IBAN of our business, must be credited in the SEPA
     54    * wire transfer.
     55    */
     56   char *business_iban;
     57 
     58   /**
     59    * Name of our business, for the SEPA wire transfer.
     60    */
     61   char *business_name;
     62 
     63   /**
     64    * Handle to interact with a authorization backend.
     65    */
     66   const struct ANASTASIS_AuthorizationContext *ac;
     67 
     68   /**
     69    * Amount we expect to be transferred.
     70    */
     71   struct TALER_Amount expected_amount;
     72 
     73 };
     74 
     75 
     76 /**
     77  * Saves the State of a authorization process
     78  */
     79 struct ANASTASIS_AUTHORIZATION_State
     80 {
     81   /**
     82    * Public key of the challenge which is authorised
     83    */
     84   struct ANASTASIS_CRYPTO_TruthUUIDP truth_uuid;
     85 
     86   /**
     87    * Code which is sent to the user (here sent via IBAN)
     88    */
     89   uint64_t code;
     90 
     91   /**
     92    * Our plugin context.
     93    */
     94   struct IBAN_Context *ctx;
     95 
     96   /**
     97    * Function to call when we made progress.
     98    */
     99   GNUNET_SCHEDULER_TaskCallback trigger;
    100 
    101   /**
    102    * Closure for @e trigger.
    103    */
    104   void *trigger_cls;
    105 
    106   /**
    107    * holds the truth information
    108    */
    109   char *iban_number;
    110 
    111   /**
    112    * Our client connection, set if suspended.
    113    */
    114   struct MHD_Connection *connection;
    115 
    116   /**
    117    * Handler for database event we are waiting for.
    118    */
    119   struct GNUNET_DB_EventHandler *eh;
    120 
    121   /**
    122    * Amount that was transferred.
    123    */
    124   struct TALER_Amount amount;
    125 };
    126 
    127 
    128 /**
    129  * Obtain internationalized message @a msg_id from @a ctx using
    130  * language preferences of @a conn.
    131  *
    132  * @param messages JSON object to lookup message from
    133  * @param conn connection to lookup message for
    134  * @param msg_id unique message ID
    135  * @return NULL if message was not found
    136  */
    137 static const char *
    138 get_message (const json_t *messages,
    139              struct MHD_Connection *conn,
    140              const char *msg_id)
    141 {
    142   const char *accept_lang;
    143 
    144   accept_lang = MHD_lookup_connection_value (conn,
    145                                              MHD_HEADER_KIND,
    146                                              MHD_HTTP_HEADER_ACCEPT_LANGUAGE);
    147   if (NULL == accept_lang)
    148     accept_lang = "en_US";
    149   {
    150     const char *ret;
    151     struct GNUNET_JSON_Specification spec[] = {
    152       TALER_JSON_spec_i18n_string (msg_id,
    153                                    accept_lang,
    154                                    &ret),
    155       GNUNET_JSON_spec_end ()
    156     };
    157 
    158     if (GNUNET_OK !=
    159         GNUNET_JSON_parse (messages,
    160                            spec,
    161                            NULL, NULL))
    162     {
    163       GNUNET_break (0);
    164       GNUNET_JSON_parse_free (spec);
    165       return NULL;
    166     }
    167     GNUNET_JSON_parse_free (spec);
    168     return ret;
    169   }
    170 }
    171 
    172 
    173 /**
    174  * Validate @a data is a well-formed input into the challenge method,
    175  * i.e. @a data is a well-formed iban number for sending an IBAN, or
    176  * a well-formed e-mail address for sending an e-mail. Not expected to
    177  * check that the iban number or e-mail account actually exists.
    178  *
    179  * To be possibly used before issuing a 402 payment required to the client.
    180  *
    181  * @param cls closure with a `struct IBAN_Context`
    182  * @param connection HTTP client request (for queuing response)
    183  * @param truth_mime mime type of @e data
    184  * @param data input to validate (i.e. is it a valid iban number, etc.)
    185  * @param data_length number of bytes in @a data
    186  * @return #GNUNET_OK if @a data is valid,
    187  *         #GNUNET_NO if @a data is invalid and a reply was successfully queued on @a connection
    188  *         #GNUNET_SYSERR if @a data invalid but we failed to queue a reply on @a connection
    189  */
    190 static enum GNUNET_GenericReturnValue
    191 iban_validate (void *cls,
    192                struct MHD_Connection *connection,
    193                const char *truth_mime,
    194                const char *data,
    195                size_t data_length)
    196 {
    197   char *iban_number;
    198   char *emsg;
    199 
    200   iban_number = GNUNET_strndup (data,
    201                                 data_length);
    202   emsg = TALER_iban_validate (iban_number);
    203   if (NULL != emsg)
    204   {
    205     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    206                 "Invalid IBAN `%s' provided: %s\n",
    207                 iban_number,
    208                 emsg);
    209     GNUNET_free (iban_number);
    210     if (MHD_NO ==
    211         TALER_MHD_reply_with_error (connection,
    212                                     MHD_HTTP_CONFLICT,
    213                                     TALER_EC_ANASTASIS_IBAN_INVALID,
    214                                     emsg))
    215     {
    216       GNUNET_free (emsg);
    217       return GNUNET_SYSERR;
    218     }
    219     GNUNET_free (emsg);
    220     return GNUNET_NO;
    221   }
    222   GNUNET_free (iban_number);
    223   return GNUNET_OK;
    224 }
    225 
    226 
    227 /**
    228  * Begin issuing authentication challenge to user based on @a data.
    229  * Sends IBAN.
    230  *
    231  * @param cls closure with a `struct IBAN_Context`
    232  * @param trigger function to call when we made progress
    233  * @param trigger_cls closure for @a trigger
    234  * @param truth_uuid Identifier of the challenge, to be (if possible) included in the
    235  *             interaction with the user
    236  * @param code secret code that the user has to provide back to satisfy the challenge in
    237  *             the main anastasis protocol
    238  * @param data input to validate (i.e. is it a valid iban number, etc.)
    239  * @param data_length number of bytes in @a data
    240  * @return state to track progress on the authorization operation, NULL on failure
    241  */
    242 static struct ANASTASIS_AUTHORIZATION_State *
    243 iban_start (void *cls,
    244             GNUNET_SCHEDULER_TaskCallback trigger,
    245             void *trigger_cls,
    246             const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
    247             uint64_t code,
    248             const void *data,
    249             size_t data_length)
    250 {
    251   struct IBAN_Context *ctx = cls;
    252   struct ANASTASIS_AUTHORIZATION_State *as;
    253 
    254   as = GNUNET_new (struct ANASTASIS_AUTHORIZATION_State);
    255   as->trigger = trigger;
    256   as->trigger_cls = trigger_cls;
    257   as->ctx = ctx;
    258   as->truth_uuid = *truth_uuid;
    259   as->code = code;
    260   as->iban_number = GNUNET_strndup (data,
    261                                     data_length);
    262   return as;
    263 }
    264 
    265 
    266 /**
    267  * Function called when we received a wire transfer
    268  * with the respective code from the specified IBAN.
    269  *
    270  * @param cls our `struct ANASTASIS_AUHTORIZATION_State`
    271  * @param extra string describing amount transferred
    272  * @param extra_size number of byes in @a extra
    273  */
    274 static void
    275 bank_event_cb (void *cls,
    276                const void *extra,
    277                size_t extra_size)
    278 {
    279   struct ANASTASIS_AUTHORIZATION_State *as = cls;
    280   char *amount_s;
    281 
    282   if (NULL != extra)
    283   {
    284     amount_s = GNUNET_strndup (extra,
    285                                extra_size);
    286     if (GNUNET_OK !=
    287         TALER_string_to_amount (amount_s,
    288                                 &as->amount))
    289     {
    290       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    291                   "Expected amount in event notification, got `%s'\n",
    292                   amount_s);
    293     }
    294     GNUNET_free (amount_s);
    295   }
    296   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    297               "IBAN event triggers resumption of request handling\n");
    298   MHD_resume_connection (as->connection);
    299   as->trigger (as->trigger_cls);
    300 }
    301 
    302 
    303 #include "iban.c"
    304 
    305 
    306 /**
    307  * Check if the @a wire_subject matches the challenge in the context
    308  * and if the @a amount is sufficient. If so, return true.
    309  *
    310  * @param cls a `const struct ANASTASIS_AUTHORIZATION_State *`
    311  * @param amount the amount that was transferred
    312  * @param wire_subject a wire subject we received
    313  * @return true if the wire transfer satisfied the check
    314  */
    315 static bool
    316 check_payment_ok (void *cls,
    317                   const struct TALER_Amount *amount,
    318                   const char *wire_subject)
    319 {
    320   const struct ANASTASIS_AUTHORIZATION_State *as = cls;
    321   struct IBAN_Context *ctx = as->ctx;
    322   uint64_t code;
    323   struct TALER_Amount camount;
    324 
    325   if (GNUNET_OK !=
    326       extract_code (wire_subject,
    327                     &code))
    328     return false;
    329   /* Database uses 'default' currency, but this
    330      plugin may use a different currency (and the
    331      same goes for the bank). So we fix this by
    332      forcing the currency to be 'right'. */
    333   camount = *amount;
    334   strcpy (camount.currency,
    335           ctx->expected_amount.currency);
    336   if (1 ==
    337       TALER_amount_cmp (&ctx->expected_amount,
    338                         &camount))
    339   {
    340     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    341                 "Amount `%s' insufficient for authorization\n",
    342                 TALER_amount2s (&camount));
    343     return false;
    344   }
    345   return (code == as->code);
    346 }
    347 
    348 
    349 /**
    350  * Check if we have received a wire transfer with a subject
    351  * authorizing the disclosure of the credential in the meantime.
    352  *
    353  * @param as state to check for
    354  * @return WTS_SUCCESS if a transfer was received,
    355  *         WTS_NOT_READY if no transfer was received,
    356  *         WTS_FAILED_WITH_REPLY if we had an internal error and queued a reply
    357  *         WTS_FAILED_WITHOUT_REPLY if we had an internal error and failed to queue a reply
    358  */
    359 static enum
    360 {
    361   WTS_SUCCESS,
    362   WTS_NOT_READY,
    363   WTS_FAILED_WITH_REPLY,
    364   WTS_FAILED_WITHOUT_REPLY
    365 }
    366 test_wire_transfers (struct ANASTASIS_AUTHORIZATION_State *as)
    367 {
    368   enum GNUNET_DB_QueryStatus qs;
    369   struct GNUNET_TIME_Absolute now;
    370   struct GNUNET_TIME_Timestamp limit;
    371 
    372   now = GNUNET_TIME_absolute_get ();
    373   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    374               "Testing for wire transfers\n");
    375   limit = GNUNET_TIME_absolute_to_timestamp (
    376     GNUNET_TIME_absolute_subtract (now,
    377                                    CODE_VALIDITY_PERIOD));
    378   qs = ANASTASIS_DB_test_auth_iban_payment (
    379     as->iban_number,
    380     limit,
    381     &check_payment_ok,
    382     as);
    383   switch (qs)
    384   {
    385   case GNUNET_DB_STATUS_HARD_ERROR:
    386   case GNUNET_DB_STATUS_SOFT_ERROR:
    387     return (MHD_YES ==
    388             TALER_MHD_reply_with_error (as->connection,
    389                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
    390                                         TALER_EC_GENERIC_DB_FETCH_FAILED,
    391                                         NULL))
    392            ? WTS_FAILED_WITH_REPLY
    393            : WTS_FAILED_WITHOUT_REPLY;
    394   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    395     return WTS_NOT_READY;
    396   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    397     break;
    398   }
    399   qs = ANASTASIS_DB_mark_challenge_code_satisfied (
    400     &as->truth_uuid,
    401     as->code);
    402   GNUNET_break (qs > 0);
    403   return WTS_SUCCESS;
    404 }
    405 
    406 
    407 /**
    408  * Respond with instructions to the user how to
    409  * satisfy the challenge.
    410  *
    411  * @param as authorization state
    412  * @param connection HTTP client request (for queuing response, such as redirection to video portal)
    413  * @return state of the request
    414  */
    415 static enum ANASTASIS_AUTHORIZATION_ChallengeResult
    416 iban_challenge (struct ANASTASIS_AUTHORIZATION_State *as,
    417                 struct MHD_Connection *connection)
    418 {
    419   struct IBAN_Context *ctx = as->ctx;
    420   const char *mime;
    421   const char *lang;
    422   enum MHD_Result mres;
    423 
    424   mime = MHD_lookup_connection_value (connection,
    425                                       MHD_HEADER_KIND,
    426                                       MHD_HTTP_HEADER_ACCEPT);
    427   if (NULL == mime)
    428     mime = "text/plain";
    429   lang = MHD_lookup_connection_value (connection,
    430                                       MHD_HEADER_KIND,
    431                                       MHD_HTTP_HEADER_ACCEPT_LANGUAGE);
    432   if (NULL == lang)
    433     lang = "en";
    434 
    435   /* Build HTTP response */
    436   {
    437     struct MHD_Response *resp;
    438 
    439     if (0.0 < TALER_pattern_matches (mime,
    440                                      "application/json"))
    441     {
    442       char subject[64];
    443 
    444       GNUNET_snprintf (subject,
    445                        sizeof (subject),
    446                        "Anastasis %llu",
    447                        (unsigned long long) as->code);
    448       resp = TALER_MHD_MAKE_JSON_PACK (
    449         GNUNET_JSON_pack_string ("challenge_type",
    450                                  "IBAN_WIRE"),
    451         GNUNET_JSON_pack_object_steal (
    452           "wire_details",
    453           GNUNET_JSON_PACK (
    454             GNUNET_JSON_pack_uint64 (
    455               "answer_code",
    456               as->code),
    457             TALER_JSON_pack_amount (
    458               "challenge_amount",
    459               &ctx->expected_amount),
    460             GNUNET_JSON_pack_string (
    461               "credit_iban",
    462               ctx->business_iban),
    463             GNUNET_JSON_pack_string (
    464               "business_name",
    465               ctx->business_name),
    466             GNUNET_JSON_pack_string (
    467               "wire_transfer_subject",
    468               subject))));
    469     }
    470     else
    471     {
    472       size_t reply_len;
    473       char *reply;
    474 
    475       reply_len = GNUNET_asprintf (&reply,
    476                                    get_message (ctx->messages,
    477                                                 connection,
    478                                                 "instructions"),
    479                                    TALER_amount2s (&ctx->expected_amount),
    480                                    ctx->business_name,
    481                                    ctx->business_iban,
    482                                    (unsigned long long) as->code);
    483       resp = MHD_create_response_from_buffer (reply_len,
    484                                               reply,
    485                                               MHD_RESPMEM_MUST_COPY);
    486       GNUNET_free (reply);
    487       TALER_MHD_add_global_headers (resp,
    488                                     false);
    489       GNUNET_break (MHD_YES ==
    490                     MHD_add_response_header (resp,
    491                                              MHD_HTTP_HEADER_CONTENT_TYPE,
    492                                              "text/plain"));
    493     }
    494     mres = MHD_queue_response (connection,
    495                                MHD_HTTP_OK,
    496                                resp);
    497     MHD_destroy_response (resp);
    498     if (MHD_YES != mres)
    499       return ANASTASIS_AUTHORIZATION_CRES_SUCCESS_REPLY_FAILED;
    500     return ANASTASIS_AUTHORIZATION_CRES_SUCCESS;
    501   }
    502 }
    503 
    504 
    505 /**
    506  * Begin issuing authentication challenge to user based on @a data.
    507  * I.e. start to send IBAN or e-mail or launch video identification.
    508  *
    509  * @param as authorization state
    510  * @param timeout how long do we have to produce a reply
    511  * @param challenge_response hash of the challenge response, or NULL
    512  * @param connection HTTP client request (for queuing response, such as redirection to video portal)
    513  * @return state of the request
    514  */
    515 static enum ANASTASIS_AUTHORIZATION_SolveResult
    516 iban_solve (struct ANASTASIS_AUTHORIZATION_State *as,
    517             struct GNUNET_TIME_Absolute timeout,
    518             const struct GNUNET_HashCode *challenge_response,
    519             struct MHD_Connection *connection)
    520 {
    521   enum MHD_Result mres;
    522   enum GNUNET_DB_QueryStatus qs;
    523   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
    524   struct GNUNET_TIME_Timestamp after;
    525 
    526   if (NULL == as->eh)
    527   {
    528     struct IbanEventP espec = {
    529       .header.size = htons (sizeof (espec)),
    530       .header.type = htons (TALER_DBEVENT_ANASTASIS_AUTH_IBAN_TRANSFER),
    531       .code = GNUNET_htonll (as->code)
    532     };
    533 
    534     GNUNET_CRYPTO_hash (as->iban_number,
    535                         strlen (as->iban_number),
    536                         &espec.debit_iban_hash);
    537     as->eh = ANASTASIS_DB_event_listen (
    538       &espec.header,
    539       GNUNET_TIME_absolute_get_remaining (
    540         timeout),
    541       &bank_event_cb,
    542       as);
    543   }
    544   after = GNUNET_TIME_absolute_to_timestamp (
    545     GNUNET_TIME_absolute_subtract (now,
    546                                    CODE_VALIDITY_PERIOD));
    547   qs = ANASTASIS_DB_test_challenge_code_satisfied (
    548     &as->truth_uuid,
    549     as->code,
    550     after);
    551   switch (qs)
    552   {
    553   case GNUNET_DB_STATUS_HARD_ERROR:
    554   case GNUNET_DB_STATUS_SOFT_ERROR:
    555     mres = TALER_MHD_reply_with_error (connection,
    556                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    557                                        TALER_EC_GENERIC_DB_FETCH_FAILED,
    558                                        "test challenge code satisfied");
    559     if (MHD_YES != mres)
    560       return ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED;
    561     return ANASTASIS_AUTHORIZATION_SRES_FAILED;
    562   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    563     switch (test_wire_transfers (as))
    564     {
    565     case WTS_SUCCESS:
    566       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    567                   "IBAN authorization finished!\n");
    568       return ANASTASIS_AUTHORIZATION_SRES_FINISHED;
    569     case WTS_NOT_READY:
    570       break;   /* continue below */
    571     case WTS_FAILED_WITH_REPLY:
    572       return ANASTASIS_AUTHORIZATION_SRES_FAILED;
    573     case WTS_FAILED_WITHOUT_REPLY:
    574       return ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED;
    575     }
    576     if (GNUNET_TIME_absolute_is_future (timeout))
    577     {
    578       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    579                   "Suspending IBAN check until %s\n",
    580                   GNUNET_TIME_absolute2s (timeout));
    581       as->connection = connection;
    582       MHD_suspend_connection (connection);
    583       return ANASTASIS_AUTHORIZATION_SRES_SUSPENDED;
    584     }
    585     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    586                 "Timeout reached at %s, failing request\n",
    587                 GNUNET_TIME_absolute2s (timeout));
    588     mres = TALER_MHD_reply_with_error (connection,
    589                                        MHD_HTTP_FORBIDDEN,
    590                                        TALER_EC_ANASTASIS_IBAN_MISSING_TRANSFER,
    591                                        NULL);
    592     if (MHD_YES != mres)
    593       return ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED;
    594     return ANASTASIS_AUTHORIZATION_SRES_FAILED;
    595   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    596     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    597                 "IBAN authorization finished!\n");
    598     return ANASTASIS_AUTHORIZATION_SRES_FINISHED;
    599   }
    600   /* should be impossible */
    601   GNUNET_break (0);
    602   return ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED;
    603 }
    604 
    605 
    606 /**
    607  * Free internal state associated with @a as.
    608  *
    609  * @param as state to clean up
    610  */
    611 static void
    612 iban_cleanup (struct ANASTASIS_AUTHORIZATION_State *as)
    613 {
    614   if (NULL != as->eh)
    615   {
    616     ANASTASIS_DB_event_listen_cancel (as->eh);
    617     as->eh = NULL;
    618   }
    619   GNUNET_free (as->iban_number);
    620   GNUNET_free (as);
    621 }
    622 
    623 
    624 /**
    625  * Initialize email based authorization plugin
    626  *
    627  * @param cls a `struct ANASTASIS_AuthorizationContext`
    628  * @return NULL on error, otherwise a `struct ANASTASIS_AuthorizationPlugin`
    629  */
    630 void *
    631 libanastasis_plugin_authorization_iban_init (void *cls);
    632 
    633 /* declaration to fix compiler warning */
    634 void *
    635 libanastasis_plugin_authorization_iban_init (void *cls)
    636 {
    637   struct ANASTASIS_AuthorizationContext *ac = cls;
    638   struct ANASTASIS_AuthorizationPlugin *plugin;
    639   const struct GNUNET_CONFIGURATION_Handle *cfg = ac->cfg;
    640   struct IBAN_Context *ctx;
    641 
    642   ctx = GNUNET_new (struct IBAN_Context);
    643   if (GNUNET_OK !=
    644       GNUNET_CONFIGURATION_get_value_string (cfg,
    645                                              "authorization-iban",
    646                                              "CREDIT_IBAN",
    647                                              &ctx->business_iban))
    648   {
    649     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    650                                "authorization-iban",
    651                                "CREDIT_IBAN");
    652     GNUNET_free (ctx);
    653     return NULL;
    654   }
    655   if (GNUNET_OK !=
    656       TALER_config_get_amount (cfg,
    657                                "authorization-iban",
    658                                "COST",
    659                                &ctx->expected_amount))
    660   {
    661     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    662                                "authorization-iban",
    663                                "COST");
    664     GNUNET_free (ctx);
    665     return NULL;
    666   }
    667   if (GNUNET_OK !=
    668       GNUNET_CONFIGURATION_get_value_string (cfg,
    669                                              "authorization-iban",
    670                                              "BUSINESS_NAME",
    671                                              &ctx->business_name))
    672   {
    673     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
    674                                "authorization-iban",
    675                                "BUSINESS_NAME");
    676     GNUNET_free (ctx->business_iban);
    677     GNUNET_free (ctx);
    678     return NULL;
    679   }
    680   {
    681     char *fn;
    682     json_error_t err;
    683     char *tmp;
    684 
    685     tmp = GNUNET_OS_installation_get_path (ANASTASIS_project_data (),
    686                                            GNUNET_OS_IPK_DATADIR);
    687     GNUNET_asprintf (&fn,
    688                      "%sauthorization-iban-messages.json",
    689                      tmp);
    690     GNUNET_free (tmp);
    691     ctx->messages = json_load_file (fn,
    692                                     JSON_REJECT_DUPLICATES,
    693                                     &err);
    694     if (NULL == ctx->messages)
    695     {
    696       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    697                   "Failed to load messages from `%s': %s at %d:%d\n",
    698                   fn,
    699                   err.text,
    700                   err.line,
    701                   err.column);
    702       GNUNET_free (ctx->business_iban);
    703       GNUNET_free (ctx->business_name);
    704       GNUNET_free (fn);
    705       GNUNET_free (ctx);
    706       return NULL;
    707     }
    708     GNUNET_free (fn);
    709   }
    710   ctx->ac = ac;
    711   plugin = GNUNET_new (struct ANASTASIS_AuthorizationPlugin);
    712   plugin->payment_plugin_managed = true;
    713   plugin->retry_counter = UINT32_MAX; /* long polling */
    714   plugin->code_validity_period = CODE_VALIDITY_PERIOD;
    715   plugin->code_rotation_period = GNUNET_TIME_UNIT_ZERO;
    716   plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_ZERO; /* not applicable */
    717   plugin->cls = ctx;
    718   plugin->validate = &iban_validate;
    719   plugin->start = &iban_start;
    720   plugin->challenge = &iban_challenge;
    721   plugin->solve = &iban_solve;
    722   plugin->cleanup = &iban_cleanup;
    723   return plugin;
    724 }
    725 
    726 
    727 /**
    728  * Unload authorization plugin
    729  *
    730  * @param cls a `struct ANASTASIS_AuthorizationPlugin`
    731  * @return NULL (always)
    732  */
    733 void *
    734 libanastasis_plugin_authorization_iban_done (void *cls);
    735 
    736 /* declaration to fix compiler warning */
    737 void *
    738 libanastasis_plugin_authorization_iban_done (void *cls)
    739 {
    740   struct ANASTASIS_AuthorizationPlugin *plugin = cls;
    741   struct IBAN_Context *ctx = plugin->cls;
    742 
    743   json_decref (ctx->messages);
    744   GNUNET_free (ctx->business_iban);
    745   GNUNET_free (ctx->business_name);
    746   GNUNET_free (ctx);
    747   GNUNET_free (plugin);
    748   return NULL;
    749 }