taler-merchant-httpd_post-private-accounts-H_WIRE-kycauth.c (20761B)
1 /* 2 This file is part of TALER 3 (C) 2026 Taler Systems SA 4 5 TALER 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 TALER 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 General Public License for more details. 12 13 You should have received a copy of the GNU Affero General Public License 14 along with TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file src/backend/taler-merchant-httpd_post-private-accounts-H_WIRE-kycauth.c 18 * @brief Handle POST /private/accounts/$H_WIRE/kycauth requests 19 * @author Christian Grothoff 20 */ 21 #include "platform.h" 22 #include <jansson.h> 23 #include <microhttpd.h> 24 #include <gnunet/gnunet_json_lib.h> 25 #include <taler/taler_json_lib.h> 26 #include <taler/taler_mhd_lib.h> 27 #include <taler/taler_bank_service.h> 28 #include "taler-merchant-httpd.h" 29 #include "taler-merchant-httpd_exchanges.h" 30 #include "taler-merchant-httpd_post-private-accounts-H_WIRE-kycauth.h" 31 #include "merchant-database/select_account.h" 32 #include "taler/taler_util.h" 33 34 35 /** 36 * Processing phases for a kycauth POST request. 37 */ 38 enum KycAuthPhase 39 { 40 /** 41 * Parse the request body and URL path. 42 */ 43 KP_PARSE = 0, 44 45 /** 46 * Fetch exchange /keys (and optionally register with bank gateway). 47 * The connection is suspended in this phase. 48 */ 49 KP_CHECK_EXCHANGES, 50 51 /** 52 * Return the prepared response to the client. 53 */ 54 KP_RETURN_RESPONSE, 55 56 /** 57 * Return MHD_YES to finish handling. 58 */ 59 KP_END_YES, 60 61 /** 62 * Return MHD_NO to close the connection. 63 */ 64 KP_END_NO 65 }; 66 67 68 struct ExchangeAccount 69 { 70 71 /** 72 * Payto URI of the exchange, saved from /keys. 73 */ 74 struct TALER_FullPayto payto; 75 76 /** 77 * Pending bank gateway registration handle, or NULL. 78 */ 79 struct TALER_BANK_RegistrationHandle *brh; 80 81 /** 82 * Context we are operating in. 83 */ 84 struct KycAuthContext *kac; 85 86 /** 87 * Transfer subjects to use for the account. 88 */ 89 struct TALER_BANK_TransferSubject *subjects; 90 91 /** 92 * Length of the @e subjects array. 93 */ 94 unsigned int num_subjects; 95 96 /** 97 * Expiration time for the given @e ts. 98 */ 99 struct GNUNET_TIME_Timestamp expiration; 100 }; 101 102 103 /** 104 * Per-request context for POST /private/accounts/$H_WIRE/kycauth. 105 */ 106 struct KycAuthContext 107 { 108 109 /** 110 * Kept in doubly-linked list. 111 */ 112 struct KycAuthContext *next; 113 114 /** 115 * Kept in doubly-linked list. 116 */ 117 struct KycAuthContext *prev; 118 119 /** 120 * MHD connection we are handling. 121 */ 122 struct MHD_Connection *connection; 123 124 /** 125 * Handler context for this request. 126 */ 127 struct TMH_HandlerContext *hc; 128 129 /** 130 * Prepared HTTP response to return, or NULL. 131 */ 132 struct MHD_Response *response; 133 134 /** 135 * Exchange URL from the request body. 136 */ 137 char *exchange_url; 138 139 /** 140 * Payto URI of our merchant bank account (from DB). 141 */ 142 struct TALER_FullPayto payto_uri; 143 144 /** 145 * Pending /keys lookup operation with the exchange. 146 */ 147 struct TMH_EXCHANGES_KeysOperation *fo; 148 149 /** 150 * Tiny amount from exchange /keys, used as the transfer amount. 151 */ 152 struct TALER_Amount tiny_amount; 153 154 /** 155 * Array of exchange wire account payto URIs, saved from /keys. 156 * Length is @e exchange_accounts_len. 157 */ 158 struct ExchangeAccount *exchange_accounts; 159 160 /** 161 * Number of entries in @e exchange_accounts. 162 */ 163 unsigned int exchange_accounts_len; 164 165 /** 166 * Number of active registrations in @e exchange_accounts. 167 */ 168 unsigned int active_registrations; 169 170 /** 171 * HTTP status code to send with @e response. 172 * UINT_MAX indicates a hard error (return MHD_NO). 173 */ 174 unsigned int response_code; 175 176 /** 177 * Current processing phase. 178 */ 179 enum KycAuthPhase phase; 180 181 /** 182 * #GNUNET_NO if the connection is not suspended, 183 * #GNUNET_YES if the connection is suspended, 184 * #GNUNET_SYSERR if suspended and being force-resumed during shutdown. 185 */ 186 enum GNUNET_GenericReturnValue suspended; 187 188 }; 189 190 191 /** 192 * Head of the doubly-linked list of active kycauth contexts. 193 */ 194 static struct KycAuthContext *kac_head; 195 196 /** 197 * Tail of the doubly-linked list of active kycauth contexts. 198 */ 199 static struct KycAuthContext *kac_tail; 200 201 202 void 203 TMH_force_kac_resume (void) 204 { 205 for (struct KycAuthContext *kac = kac_head; 206 NULL != kac; 207 kac = kac->next) 208 { 209 if (NULL != kac->fo) 210 { 211 TMH_EXCHANGES_keys4exchange_cancel (kac->fo); 212 kac->fo = NULL; 213 } 214 if (GNUNET_YES == kac->suspended) 215 { 216 kac->suspended = GNUNET_SYSERR; 217 MHD_resume_connection (kac->connection); 218 } 219 } 220 } 221 222 223 /** 224 * Resume processing of @a kac after an async operation completed. 225 * 226 * @param[in,out] kac context to resume 227 */ 228 static void 229 kac_resume (struct KycAuthContext *kac) 230 { 231 GNUNET_assert (GNUNET_YES == kac->suspended); 232 kac->suspended = GNUNET_NO; 233 MHD_resume_connection (kac->connection); 234 TALER_MHD_daemon_trigger (); 235 } 236 237 238 /** 239 * Clean up a kycauth context, freeing all resources. 240 * 241 * @param cls a `struct KycAuthContext` to clean up 242 */ 243 static void 244 kac_cleanup (void *cls) 245 { 246 struct KycAuthContext *kac = cls; 247 248 if (NULL != kac->fo) 249 { 250 TMH_EXCHANGES_keys4exchange_cancel (kac->fo); 251 kac->fo = NULL; 252 } 253 if (NULL != kac->response) 254 { 255 MHD_destroy_response (kac->response); 256 kac->response = NULL; 257 } 258 GNUNET_free (kac->exchange_url); 259 GNUNET_free (kac->payto_uri.full_payto); 260 for (unsigned int i = 0; i < kac->exchange_accounts_len; i++) 261 { 262 struct ExchangeAccount *acc = &kac->exchange_accounts[i]; 263 264 if (NULL != acc->brh) 265 { 266 TALER_BANK_registration_cancel (acc->brh); 267 acc->brh = NULL; 268 } 269 for (unsigned int j = 0; j<acc->num_subjects; j++) 270 TALER_BANK_transfer_subject_free (&acc->subjects[j]); 271 GNUNET_free (acc->subjects); 272 GNUNET_free (acc->payto.full_payto); 273 } 274 GNUNET_free (kac->exchange_accounts); 275 GNUNET_CONTAINER_DLL_remove (kac_head, 276 kac_tail, 277 kac); 278 GNUNET_free (kac); 279 } 280 281 282 /** 283 * Convert a @a ts (transfer subject) to a JSON object. 284 * The resulting object has a "type" field discriminating the format, 285 * matching the JSON format returned by the bank gateway's /registration. 286 * 287 * @param acc general account details 288 * @param ts the specific transfer subject to convert 289 * @return freshly allocated JSON object, or NULL on error 290 */ 291 static json_t * 292 transfer_subject_to_json (const struct ExchangeAccount *acc, 293 const struct TALER_BANK_TransferSubject *ts) 294 { 295 struct KycAuthContext *kac = acc->kac; 296 297 switch (ts->format) 298 { 299 case TALER_BANK_SUBJECT_FORMAT_SIMPLE: 300 return GNUNET_JSON_PACK ( 301 GNUNET_JSON_pack_string ("type", 302 "SIMPLE"), 303 TALER_JSON_pack_amount ("credit_amount", 304 &kac->tiny_amount), 305 GNUNET_JSON_pack_data_auto ("subject", 306 &kac->hc->instance->merchant_pub)); 307 case TALER_BANK_SUBJECT_FORMAT_URI: 308 return GNUNET_JSON_PACK ( 309 GNUNET_JSON_pack_string ("type", 310 "URI"), 311 TALER_JSON_pack_amount ("credit_amount", 312 &kac->tiny_amount), 313 GNUNET_JSON_pack_string ("uri", 314 ts->details.uri.uri)); 315 case TALER_BANK_SUBJECT_FORMAT_CH_QR_BILL: 316 return GNUNET_JSON_PACK ( 317 GNUNET_JSON_pack_string ("type", 318 "CH_QR_BILL"), 319 TALER_JSON_pack_amount ("credit_amount", 320 &ts->details.ch_qr_bill.credit_amount), 321 GNUNET_JSON_pack_string ("qr_reference_number", 322 ts->details.ch_qr_bill.qr_reference_number)); 323 } 324 GNUNET_break (0); 325 return NULL; 326 } 327 328 329 /** 330 * Generate the final "OK" response for the request in @a kac. 331 * Builds the wire_instructions JSON array from the saved exchange accounts 332 * and the given transfer subject. 333 * 334 * @param[in,out] kac request with all the details ready to build a response 335 */ 336 static void 337 generate_ok_response (struct KycAuthContext *kac) 338 { 339 json_t *arr; 340 341 arr = json_array (); 342 GNUNET_assert (NULL != arr); 343 for (unsigned int i = 0; i < kac->exchange_accounts_len; i++) 344 { 345 const struct ExchangeAccount *acc = &kac->exchange_accounts[i]; 346 json_t *subj; 347 json_t *entry; 348 349 for (unsigned int j = 0; j < acc->num_subjects; j++) 350 { 351 subj = transfer_subject_to_json (acc, 352 &acc->subjects[j]); 353 GNUNET_assert (NULL != subj); 354 entry = GNUNET_JSON_PACK ( 355 TALER_JSON_pack_amount ("amount", 356 &kac->tiny_amount), 357 TALER_JSON_pack_full_payto ("target_payto", 358 acc->payto), 359 GNUNET_JSON_pack_object_steal ("subject", 360 subj), 361 GNUNET_JSON_pack_timestamp ("expiration", 362 acc->expiration)); 363 GNUNET_assert (NULL != entry); 364 GNUNET_assert (0 == 365 json_array_append_new (arr, 366 entry)); 367 } 368 } 369 kac->response_code = MHD_HTTP_OK; 370 kac->response = TALER_MHD_MAKE_JSON_PACK ( 371 GNUNET_JSON_pack_array_steal ("wire_instructions", 372 arr)); 373 kac->phase = KP_RETURN_RESPONSE; 374 kac_resume (kac); 375 } 376 377 378 /** 379 * Callback invoked with the result of the bank gateway /registration request. 380 * 381 * @param cls our `struct KycAuthContext` 382 * @param rr response details 383 */ 384 static void 385 registration_cb (void *cls, 386 const struct TALER_BANK_RegistrationResponse *rr) 387 { 388 struct ExchangeAccount *acc = cls; 389 struct KycAuthContext *kac = acc->kac; 390 391 acc->brh = NULL; 392 kac->active_registrations--; 393 if (MHD_HTTP_OK != rr->http_status) 394 { 395 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 396 "Bank gateway registration failed with HTTP status %u\n", 397 rr->http_status); 398 kac->response_code = MHD_HTTP_BAD_GATEWAY; 399 kac->response = TALER_MHD_make_error ( 400 TALER_EC_MERCHANT_POST_ACCOUNTS_KYCAUTH_BANK_GATEWAY_UNREACHABLE, 401 "bank gateway /registration failed"); 402 } 403 GNUNET_free (acc->subjects); 404 acc->num_subjects = rr->details.ok.num_subjects; 405 acc->subjects = GNUNET_new_array (acc->num_subjects, 406 struct TALER_BANK_TransferSubject); 407 for (unsigned int i = 0; i<acc->num_subjects; i++) 408 { 409 TALER_BANK_transfer_subject_copy (&acc->subjects[i], 410 &rr->details.ok.subjects[i]); 411 } 412 acc->expiration = rr->details.ok.expiration; 413 if (0 != kac->active_registrations) 414 return; /* wait for more replies */ 415 generate_ok_response (kac); 416 } 417 418 419 /** 420 * Callback invoked with the /keys of the selected exchange. 421 * 422 * Saves tiny_amount and exchange account payto URIs from the keys, then 423 * either calls the bank gateway /registration (if wire_transfer_gateway is 424 * present) or directly constructs the SIMPLE-format response. 425 * 426 * @param cls our `struct KycAuthContext` 427 * @param keys the exchange's key material, or NULL on failure 428 * @param exchange internal exchange handle (unused) 429 */ 430 static void 431 process_keys_cb (void *cls, 432 struct TALER_EXCHANGE_Keys *keys, 433 struct TMH_Exchange *exchange) 434 { 435 struct KycAuthContext *kac = cls; 436 struct TMH_MerchantInstance *mi = kac->hc->instance; 437 438 (void) exchange; 439 kac->fo = NULL; 440 if (NULL == keys) 441 { 442 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 443 "Could not get /keys from exchange `%s'\n", 444 kac->exchange_url); 445 kac->response_code = MHD_HTTP_BAD_GATEWAY; 446 kac->response = TALER_MHD_make_error ( 447 TALER_EC_MERCHANT_POST_ACCOUNTS_KYCAUTH_EXCHANGE_UNREACHABLE, 448 kac->exchange_url); 449 kac->phase = KP_RETURN_RESPONSE; 450 kac_resume (kac); 451 return; 452 } 453 if (! keys->tiny_amount_available) 454 { 455 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 456 "Exchange `%s' did not provide tiny_amount in /keys\n", 457 kac->exchange_url); 458 kac->response_code = MHD_HTTP_BAD_GATEWAY; 459 kac->response = TALER_MHD_make_error ( 460 TALER_EC_MERCHANT_POST_ACCOUNTS_EXCHANGE_TOO_OLD, 461 "exchange /keys missing tiny_amount"); 462 kac->phase = KP_RETURN_RESPONSE; 463 kac_resume (kac); 464 return; 465 } 466 467 /* Save tiny_amount and exchange wire accounts from keys */ 468 kac->tiny_amount = keys->tiny_amount; 469 kac->exchange_accounts_len = keys->accounts_len; 470 if (0 == keys->accounts_len) 471 { 472 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 473 "Exchange `%s' did not provide any wire accounts in /keys\n", 474 kac->exchange_url); 475 kac->response_code = MHD_HTTP_BAD_GATEWAY; 476 kac->response = TALER_MHD_make_error ( 477 TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNEXPECTED_STATUS, 478 "exchange /keys missing wire accounts"); 479 kac->phase = KP_RETURN_RESPONSE; 480 kac_resume (kac); 481 return; 482 } 483 484 kac->exchange_accounts 485 = GNUNET_new_array (keys->accounts_len, 486 struct ExchangeAccount); 487 for (unsigned int i = 0; i < keys->accounts_len; i++) 488 { 489 struct ExchangeAccount *acc = &kac->exchange_accounts[i]; 490 struct TALER_PreparedTransferAuthorizationPrivateKeyP apk; 491 492 GNUNET_CRYPTO_eddsa_key_create (&apk.eddsa_priv); 493 acc->kac = kac; 494 acc->payto.full_payto 495 = GNUNET_strdup (keys->accounts[i].fpayto_uri.full_payto); 496 acc->subjects = GNUNET_new (struct TALER_BANK_TransferSubject); 497 acc->num_subjects = 1; 498 acc->subjects[0].format = TALER_BANK_SUBJECT_FORMAT_SIMPLE; 499 acc->expiration = GNUNET_TIME_UNIT_FOREVER_TS; 500 if (NULL == keys->accounts[i].prepared_transfer_url) 501 continue; 502 acc->brh = TALER_BANK_registration ( 503 TMH_curl_ctx, 504 keys->accounts[i].prepared_transfer_url, 505 &keys->accounts[i].fpayto_uri, 506 &kac->tiny_amount, 507 TALER_BANK_REGISTRATION_TYPE_KYC, 508 (const union TALER_AccountPublicKeyP *) &mi->merchant_pub, 509 // FIXME: turn this into an option when modernizing the BANK API... 510 &apk, 511 false, /* recurrent */ 512 ®istration_cb, 513 acc); 514 if (NULL == acc->brh) 515 { 516 GNUNET_break (0); 517 kac->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; 518 kac->response = TALER_MHD_make_error ( 519 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 520 "could not start bank gateway registration"); 521 kac->phase = KP_RETURN_RESPONSE; 522 kac_resume (kac); 523 return; 524 } 525 kac->active_registrations++; 526 } 527 if (0 != kac->active_registrations) 528 return; 529 generate_ok_response (kac); 530 } 531 532 533 /** 534 * Process the PARSE phase: validate the URL path, parse the request body, 535 * and look up the merchant account in the database. 536 * 537 * @param[in,out] kac context to process 538 */ 539 static void 540 phase_parse (struct KycAuthContext *kac) 541 { 542 const char *h_wire_s = kac->hc->infix; 543 struct TALER_MerchantWireHashP h_wire; 544 const char *exchange_url; 545 enum GNUNET_GenericReturnValue res; 546 struct GNUNET_JSON_Specification spec[] = { 547 GNUNET_JSON_spec_string ("exchange_url", 548 &exchange_url), 549 GNUNET_JSON_spec_end () 550 }; 551 552 GNUNET_assert (NULL != h_wire_s); 553 if (GNUNET_OK != 554 GNUNET_STRINGS_string_to_data (h_wire_s, 555 strlen (h_wire_s), 556 &h_wire, 557 sizeof (h_wire))) 558 { 559 GNUNET_break_op (0); 560 kac->response_code = MHD_HTTP_BAD_REQUEST; 561 kac->response = TALER_MHD_make_error ( 562 TALER_EC_MERCHANT_GENERIC_H_WIRE_MALFORMED, 563 h_wire_s); 564 kac->phase = KP_RETURN_RESPONSE; 565 return; 566 } 567 568 res = TALER_MHD_parse_json_data (kac->connection, 569 kac->hc->request_body, 570 spec); 571 if (GNUNET_OK != res) 572 { 573 kac->phase = (GNUNET_NO == res) ? KP_END_YES : KP_END_NO; 574 return; 575 } 576 577 /* Look up the merchant account in the database */ 578 { 579 struct TALER_MERCHANTDB_AccountDetails ad = { 0 }; 580 enum GNUNET_DB_QueryStatus qs; 581 582 qs = TALER_MERCHANTDB_select_account (TMH_db, 583 kac->hc->instance->settings.id, 584 &h_wire, 585 &ad); 586 if (0 > qs) 587 { 588 GNUNET_break (0); 589 GNUNET_JSON_parse_free (spec); 590 kac->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; 591 kac->response = TALER_MHD_make_error ( 592 TALER_EC_GENERIC_DB_FETCH_FAILED, 593 "select_account"); 594 kac->phase = KP_RETURN_RESPONSE; 595 return; 596 } 597 if (0 == qs) 598 { 599 GNUNET_JSON_parse_free (spec); 600 kac->response_code = MHD_HTTP_NOT_FOUND; 601 kac->response = TALER_MHD_make_error ( 602 TALER_EC_MERCHANT_GENERIC_ACCOUNT_UNKNOWN, 603 h_wire_s); 604 kac->phase = KP_RETURN_RESPONSE; 605 return; 606 } 607 kac->payto_uri.full_payto = GNUNET_strdup (ad.payto_uri.full_payto); 608 /* Free fields we do not need */ 609 GNUNET_free (ad.payto_uri.full_payto); 610 GNUNET_free (ad.credit_facade_url); 611 GNUNET_free (ad.extra_wire_subject_metadata); 612 json_decref (ad.credit_facade_credentials); 613 } 614 615 kac->exchange_url = GNUNET_strdup (exchange_url); 616 GNUNET_JSON_parse_free (spec); 617 kac->phase = KP_CHECK_EXCHANGES; 618 } 619 620 621 /** 622 * Process the CHECK_EXCHANGES phase: start an async /keys fetch from 623 * the requested exchange and suspend the connection. 624 * 625 * @param[in,out] kac context to process 626 */ 627 static void 628 phase_check_exchanges (struct KycAuthContext *kac) 629 { 630 kac->fo = TMH_EXCHANGES_keys4exchange (kac->exchange_url, 631 false, 632 &process_keys_cb, 633 kac); 634 if (NULL == kac->fo) 635 { 636 GNUNET_break_op (0); 637 kac->response_code = MHD_HTTP_BAD_REQUEST; 638 kac->response = TALER_MHD_make_error ( 639 TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNTRUSTED, 640 kac->exchange_url); 641 kac->phase = KP_RETURN_RESPONSE; 642 return; 643 } 644 MHD_suspend_connection (kac->connection); 645 kac->suspended = GNUNET_YES; 646 } 647 648 649 /** 650 * Process the RETURN_RESPONSE phase: queue the prepared response into MHD. 651 * 652 * @param[in,out] kac context to process 653 */ 654 static void 655 phase_return_response (struct KycAuthContext *kac) 656 { 657 enum MHD_Result ret; 658 659 if (UINT_MAX == kac->response_code) 660 { 661 GNUNET_break (0); 662 kac->phase = KP_END_NO; 663 return; 664 } 665 GNUNET_assert (0 != kac->response_code); 666 ret = MHD_queue_response (kac->connection, 667 kac->response_code, 668 kac->response); 669 kac->phase = (MHD_YES == ret) ? KP_END_YES : KP_END_NO; 670 } 671 672 673 enum MHD_Result 674 TMH_private_post_accounts_H_WIRE_kycauth ( 675 const struct TMH_RequestHandler *rh, 676 struct MHD_Connection *connection, 677 struct TMH_HandlerContext *hc) 678 { 679 struct KycAuthContext *kac = hc->ctx; 680 681 (void) rh; 682 GNUNET_assert (NULL != hc->infix); 683 if (NULL == kac) 684 { 685 kac = GNUNET_new (struct KycAuthContext); 686 kac->connection = connection; 687 kac->hc = hc; 688 hc->ctx = kac; 689 hc->cc = &kac_cleanup; 690 GNUNET_CONTAINER_DLL_insert (kac_head, 691 kac_tail, 692 kac); 693 } 694 695 while (1) 696 { 697 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 698 "Processing POST /private/accounts/$H_WIRE/kycauth" 699 " in phase %d\n", 700 (int) kac->phase); 701 switch (kac->phase) 702 { 703 case KP_PARSE: 704 phase_parse (kac); 705 break; 706 case KP_CHECK_EXCHANGES: 707 phase_check_exchanges (kac); 708 break; 709 case KP_RETURN_RESPONSE: 710 phase_return_response (kac); 711 break; 712 case KP_END_YES: 713 return MHD_YES; 714 case KP_END_NO: 715 return MHD_NO; 716 default: 717 GNUNET_assert (0); 718 return MHD_NO; 719 } 720 721 switch (kac->suspended) 722 { 723 case GNUNET_SYSERR: 724 /* Shutdown in progress */ 725 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 726 "Processing POST /private/accounts/$H_WIRE/kycauth" 727 " ends due to shutdown in phase %d\n", 728 (int) kac->phase); 729 return MHD_NO; 730 case GNUNET_NO: 731 /* Not suspended, continue with next phase */ 732 break; 733 case GNUNET_YES: 734 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 735 "Processing POST /private/accounts/$H_WIRE/kycauth" 736 " suspended in phase %d\n", 737 (int) kac->phase); 738 return MHD_YES; 739 } 740 } 741 GNUNET_assert (0); 742 return MHD_YES; 743 } 744 745 746 /* end of taler-merchant-httpd_private-post-accounts-H_WIRE-kycauth.c */