anastasis_authorization_plugin_iban.c (23569B)
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 struct IBAN_Context *ctx = as->ctx; 369 struct ANASTASIS_DatabasePlugin *db = ctx->ac->db; 370 enum GNUNET_DB_QueryStatus qs; 371 struct GNUNET_TIME_Absolute now; 372 struct GNUNET_TIME_Timestamp limit; 373 374 now = GNUNET_TIME_absolute_get (); 375 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 376 "Testing for wire transfers\n"); 377 limit = GNUNET_TIME_absolute_to_timestamp ( 378 GNUNET_TIME_absolute_subtract (now, 379 CODE_VALIDITY_PERIOD)); 380 qs = db->test_auth_iban_payment ( 381 db->cls, 382 as->iban_number, 383 limit, 384 &check_payment_ok, 385 as); 386 switch (qs) 387 { 388 case GNUNET_DB_STATUS_HARD_ERROR: 389 case GNUNET_DB_STATUS_SOFT_ERROR: 390 return (MHD_YES == 391 TALER_MHD_reply_with_error (as->connection, 392 MHD_HTTP_INTERNAL_SERVER_ERROR, 393 TALER_EC_GENERIC_DB_FETCH_FAILED, 394 NULL)) 395 ? WTS_FAILED_WITH_REPLY 396 : WTS_FAILED_WITHOUT_REPLY; 397 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 398 return WTS_NOT_READY; 399 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 400 break; 401 } 402 qs = db->mark_challenge_code_satisfied ( 403 db->cls, 404 &as->truth_uuid, 405 as->code); 406 GNUNET_break (qs > 0); 407 return WTS_SUCCESS; 408 } 409 410 411 /** 412 * Respond with instructions to the user how to 413 * satisfy the challenge. 414 * 415 * @param as authorization state 416 * @param connection HTTP client request (for queuing response, such as redirection to video portal) 417 * @return state of the request 418 */ 419 static enum ANASTASIS_AUTHORIZATION_ChallengeResult 420 iban_challenge (struct ANASTASIS_AUTHORIZATION_State *as, 421 struct MHD_Connection *connection) 422 { 423 struct IBAN_Context *ctx = as->ctx; 424 const char *mime; 425 const char *lang; 426 MHD_RESULT mres; 427 428 mime = MHD_lookup_connection_value (connection, 429 MHD_HEADER_KIND, 430 MHD_HTTP_HEADER_ACCEPT); 431 if (NULL == mime) 432 mime = "text/plain"; 433 lang = MHD_lookup_connection_value (connection, 434 MHD_HEADER_KIND, 435 MHD_HTTP_HEADER_ACCEPT_LANGUAGE); 436 if (NULL == lang) 437 lang = "en"; 438 439 /* Build HTTP response */ 440 { 441 struct MHD_Response *resp; 442 443 if (0.0 < TALER_pattern_matches (mime, 444 "application/json")) 445 { 446 char subject[64]; 447 448 GNUNET_snprintf (subject, 449 sizeof (subject), 450 "Anastasis %llu", 451 (unsigned long long) as->code); 452 resp = TALER_MHD_MAKE_JSON_PACK ( 453 GNUNET_JSON_pack_string ("challenge_type", 454 "IBAN_WIRE"), 455 GNUNET_JSON_pack_object_steal ( 456 "wire_details", 457 GNUNET_JSON_PACK ( 458 GNUNET_JSON_pack_uint64 ( 459 "answer_code", 460 as->code), 461 TALER_JSON_pack_amount ( 462 "challenge_amount", 463 &ctx->expected_amount), 464 GNUNET_JSON_pack_string ( 465 "credit_iban", 466 ctx->business_iban), 467 GNUNET_JSON_pack_string ( 468 "business_name", 469 ctx->business_name), 470 GNUNET_JSON_pack_string ( 471 "wire_transfer_subject", 472 subject)))); 473 } 474 else 475 { 476 size_t reply_len; 477 char *reply; 478 479 reply_len = GNUNET_asprintf (&reply, 480 get_message (ctx->messages, 481 connection, 482 "instructions"), 483 TALER_amount2s (&ctx->expected_amount), 484 ctx->business_name, 485 ctx->business_iban, 486 (unsigned long long) as->code); 487 resp = MHD_create_response_from_buffer (reply_len, 488 reply, 489 MHD_RESPMEM_MUST_COPY); 490 GNUNET_free (reply); 491 TALER_MHD_add_global_headers (resp, 492 false); 493 GNUNET_break (MHD_YES == 494 MHD_add_response_header (resp, 495 MHD_HTTP_HEADER_CONTENT_TYPE, 496 "text/plain")); 497 } 498 mres = MHD_queue_response (connection, 499 MHD_HTTP_OK, 500 resp); 501 MHD_destroy_response (resp); 502 if (MHD_YES != mres) 503 return ANASTASIS_AUTHORIZATION_CRES_SUCCESS_REPLY_FAILED; 504 return ANASTASIS_AUTHORIZATION_CRES_SUCCESS; 505 } 506 } 507 508 509 /** 510 * Begin issuing authentication challenge to user based on @a data. 511 * I.e. start to send IBAN or e-mail or launch video identification. 512 * 513 * @param as authorization state 514 * @param timeout how long do we have to produce a reply 515 * @param challenge_response hash of the challenge response, or NULL 516 * @param connection HTTP client request (for queuing response, such as redirection to video portal) 517 * @return state of the request 518 */ 519 static enum ANASTASIS_AUTHORIZATION_SolveResult 520 iban_solve (struct ANASTASIS_AUTHORIZATION_State *as, 521 struct GNUNET_TIME_Absolute timeout, 522 const struct GNUNET_HashCode *challenge_response, 523 struct MHD_Connection *connection) 524 { 525 struct IBAN_Context *ctx = as->ctx; 526 struct ANASTASIS_DatabasePlugin *db = ctx->ac->db; 527 MHD_RESULT mres; 528 enum GNUNET_DB_QueryStatus qs; 529 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); 530 struct GNUNET_TIME_Timestamp after; 531 532 if (NULL == as->eh) 533 { 534 struct IbanEventP espec = { 535 .header.size = htons (sizeof (espec)), 536 .header.type = htons (TALER_DBEVENT_ANASTASIS_AUTH_IBAN_TRANSFER), 537 .code = GNUNET_htonll (as->code) 538 }; 539 540 GNUNET_CRYPTO_hash (as->iban_number, 541 strlen (as->iban_number), 542 &espec.debit_iban_hash); 543 as->eh = db->event_listen (db->cls, 544 &espec.header, 545 GNUNET_TIME_absolute_get_remaining ( 546 timeout), 547 &bank_event_cb, 548 as); 549 } 550 after = GNUNET_TIME_absolute_to_timestamp ( 551 GNUNET_TIME_absolute_subtract (now, 552 CODE_VALIDITY_PERIOD)); 553 qs = db->test_challenge_code_satisfied (db->cls, 554 &as->truth_uuid, 555 as->code, 556 after); 557 switch (qs) 558 { 559 case GNUNET_DB_STATUS_HARD_ERROR: 560 case GNUNET_DB_STATUS_SOFT_ERROR: 561 mres = TALER_MHD_reply_with_error (connection, 562 MHD_HTTP_INTERNAL_SERVER_ERROR, 563 TALER_EC_GENERIC_DB_FETCH_FAILED, 564 "test challenge code satisfied"); 565 if (MHD_YES != mres) 566 return ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED; 567 return ANASTASIS_AUTHORIZATION_SRES_FAILED; 568 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 569 switch (test_wire_transfers (as)) 570 { 571 case WTS_SUCCESS: 572 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 573 "IBAN authorization finished!\n"); 574 return ANASTASIS_AUTHORIZATION_SRES_FINISHED; 575 case WTS_NOT_READY: 576 break; /* continue below */ 577 case WTS_FAILED_WITH_REPLY: 578 return ANASTASIS_AUTHORIZATION_SRES_FAILED; 579 case WTS_FAILED_WITHOUT_REPLY: 580 return ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED; 581 } 582 if (GNUNET_TIME_absolute_is_future (timeout)) 583 { 584 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 585 "Suspending IBAN check until %s\n", 586 GNUNET_TIME_absolute2s (timeout)); 587 as->connection = connection; 588 MHD_suspend_connection (connection); 589 return ANASTASIS_AUTHORIZATION_SRES_SUSPENDED; 590 } 591 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 592 "Timeout reached at %s, failing request\n", 593 GNUNET_TIME_absolute2s (timeout)); 594 mres = TALER_MHD_reply_with_error (connection, 595 MHD_HTTP_FORBIDDEN, 596 TALER_EC_ANASTASIS_IBAN_MISSING_TRANSFER, 597 NULL); 598 if (MHD_YES != mres) 599 return ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED; 600 return ANASTASIS_AUTHORIZATION_SRES_FAILED; 601 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 602 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 603 "IBAN authorization finished!\n"); 604 return ANASTASIS_AUTHORIZATION_SRES_FINISHED; 605 } 606 /* should be impossible */ 607 GNUNET_break (0); 608 return ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED; 609 } 610 611 612 /** 613 * Free internal state associated with @a as. 614 * 615 * @param as state to clean up 616 */ 617 static void 618 iban_cleanup (struct ANASTASIS_AUTHORIZATION_State *as) 619 { 620 struct IBAN_Context *ctx = as->ctx; 621 622 if (NULL != as->eh) 623 { 624 ctx->ac->db->event_listen_cancel (as->eh); 625 as->eh = NULL; 626 } 627 GNUNET_free (as->iban_number); 628 GNUNET_free (as); 629 } 630 631 632 /** 633 * Initialize email based authorization plugin 634 * 635 * @param cls a `struct ANASTASIS_AuthorizationContext` 636 * @return NULL on error, otherwise a `struct ANASTASIS_AuthorizationPlugin` 637 */ 638 void * 639 libanastasis_plugin_authorization_iban_init (void *cls); 640 641 /* declaration to fix compiler warning */ 642 void * 643 libanastasis_plugin_authorization_iban_init (void *cls) 644 { 645 struct ANASTASIS_AuthorizationContext *ac = cls; 646 struct ANASTASIS_AuthorizationPlugin *plugin; 647 const struct GNUNET_CONFIGURATION_Handle *cfg = ac->cfg; 648 struct IBAN_Context *ctx; 649 650 ctx = GNUNET_new (struct IBAN_Context); 651 if (GNUNET_OK != 652 GNUNET_CONFIGURATION_get_value_string (cfg, 653 "authorization-iban", 654 "CREDIT_IBAN", 655 &ctx->business_iban)) 656 { 657 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 658 "authorization-iban", 659 "CREDIT_IBAN"); 660 GNUNET_free (ctx); 661 return NULL; 662 } 663 if (GNUNET_OK != 664 TALER_config_get_amount (cfg, 665 "authorization-iban", 666 "COST", 667 &ctx->expected_amount)) 668 { 669 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 670 "authorization-iban", 671 "COST"); 672 GNUNET_free (ctx); 673 return NULL; 674 } 675 if (GNUNET_OK != 676 GNUNET_CONFIGURATION_get_value_string (cfg, 677 "authorization-iban", 678 "BUSINESS_NAME", 679 &ctx->business_name)) 680 { 681 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 682 "authorization-iban", 683 "BUSINESS_NAME"); 684 GNUNET_free (ctx->business_iban); 685 GNUNET_free (ctx); 686 return NULL; 687 } 688 { 689 char *fn; 690 json_error_t err; 691 char *tmp; 692 693 tmp = GNUNET_OS_installation_get_path (ANASTASIS_project_data (), 694 GNUNET_OS_IPK_DATADIR); 695 GNUNET_asprintf (&fn, 696 "%sauthorization-iban-messages.json", 697 tmp); 698 GNUNET_free (tmp); 699 ctx->messages = json_load_file (fn, 700 JSON_REJECT_DUPLICATES, 701 &err); 702 if (NULL == ctx->messages) 703 { 704 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 705 "Failed to load messages from `%s': %s at %d:%d\n", 706 fn, 707 err.text, 708 err.line, 709 err.column); 710 GNUNET_free (ctx->business_iban); 711 GNUNET_free (ctx->business_name); 712 GNUNET_free (fn); 713 GNUNET_free (ctx); 714 return NULL; 715 } 716 GNUNET_free (fn); 717 } 718 ctx->ac = ac; 719 plugin = GNUNET_new (struct ANASTASIS_AuthorizationPlugin); 720 plugin->payment_plugin_managed = true; 721 plugin->retry_counter = UINT32_MAX; /* long polling */ 722 plugin->code_validity_period = CODE_VALIDITY_PERIOD; 723 plugin->code_rotation_period = GNUNET_TIME_UNIT_ZERO; 724 plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_ZERO; /* not applicable */ 725 plugin->cls = ctx; 726 plugin->validate = &iban_validate; 727 plugin->start = &iban_start; 728 plugin->challenge = &iban_challenge; 729 plugin->solve = &iban_solve; 730 plugin->cleanup = &iban_cleanup; 731 return plugin; 732 } 733 734 735 /** 736 * Unload authorization plugin 737 * 738 * @param cls a `struct ANASTASIS_AuthorizationPlugin` 739 * @return NULL (always) 740 */ 741 void * 742 libanastasis_plugin_authorization_iban_done (void *cls); 743 744 /* declaration to fix compiler warning */ 745 void * 746 libanastasis_plugin_authorization_iban_done (void *cls) 747 { 748 struct ANASTASIS_AuthorizationPlugin *plugin = cls; 749 struct IBAN_Context *ctx = plugin->cls; 750 751 json_decref (ctx->messages); 752 GNUNET_free (ctx->business_iban); 753 GNUNET_free (ctx->business_name); 754 GNUNET_free (ctx); 755 GNUNET_free (plugin); 756 return NULL; 757 }