anastasis

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

anastasis-httpd_truth-challenge.c (40812B)


      1 /*
      2   This file is part of Anastasis
      3   Copyright (C) 2019-2022 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.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file anastasis-httpd_truth-challenge.c
     18  * @brief functions to handle incoming requests on /truth/$TID/challenge
     19  * @author Dennis Neufeld
     20  * @author Dominik Meister
     21  * @author Christian Grothoff
     22  */
     23 #include "platform.h"
     24 #include "anastasis-httpd.h"
     25 #include "anastasis_service.h"
     26 #include "anastasis-httpd_truth.h"
     27 #include <gnunet/gnunet_util_lib.h>
     28 #include <gnunet/gnunet_rest_lib.h>
     29 #include "anastasis_authorization_lib.h"
     30 #include <taler/taler_merchant_service.h>
     31 #include <taler/taler_json_lib.h>
     32 #include <taler/taler_mhd_lib.h>
     33 #include <taler/taler-merchant/post-private-orders.h>
     34 #include <taler/taler-merchant/get-private-orders-ORDER_ID.h>
     35 #include <taler/taler-merchant/post-private-orders-ORDER_ID-refund.h>
     36 
     37 /**
     38  * What is the maximum frequency at which we allow
     39  * clients to attempt to answer security questions?
     40  */
     41 #define MAX_QUESTION_FREQ GNUNET_TIME_relative_multiply ( \
     42           GNUNET_TIME_UNIT_SECONDS, 30)
     43 
     44 /**
     45  * How long should the wallet check for auto-refunds before giving up?
     46  */
     47 #define AUTO_REFUND_TIMEOUT GNUNET_TIME_relative_multiply ( \
     48           GNUNET_TIME_UNIT_MINUTES, 2)
     49 
     50 /**
     51  * How long should the wallet check for payment before giving up?
     52  */
     53 #define PAYMENT_TIMEOUT GNUNET_TIME_relative_multiply ( \
     54           GNUNET_TIME_UNIT_SECONDS, 15)
     55 
     56 
     57 /**
     58  * How many retries do we allow per code?
     59  */
     60 #define INITIAL_RETRY_COUNTER 3
     61 
     62 
     63 struct ChallengeContext
     64 {
     65 
     66   /**
     67    * Payment Identifier
     68    */
     69   struct ANASTASIS_PaymentSecretP payment_identifier;
     70 
     71   /**
     72    * Public key of the challenge which is solved.
     73    */
     74   struct ANASTASIS_CRYPTO_TruthUUIDP truth_uuid;
     75 
     76   /**
     77    * Key to decrypt the truth.
     78    */
     79   struct ANASTASIS_CRYPTO_TruthKeyP truth_key;
     80 
     81   /**
     82    * Cost for paying the challenge.
     83    */
     84   struct TALER_Amount challenge_cost;
     85 
     86   /**
     87    * Our handler context.
     88    */
     89   struct TM_HandlerContext *hc;
     90 
     91   /**
     92    * Opaque parsing context.
     93    */
     94   void *opaque_post_parsing_context;
     95 
     96   /**
     97    * Uploaded JSON data, NULL if upload is not yet complete.
     98    */
     99   json_t *root;
    100 
    101   /**
    102    * Kept in DLL for shutdown handling while suspended.
    103    */
    104   struct ChallengeContext *next;
    105 
    106   /**
    107    * Kept in DLL for shutdown handling while suspended.
    108    */
    109   struct ChallengeContext *prev;
    110 
    111   /**
    112    * Connection handle for closing or resuming
    113    */
    114   struct MHD_Connection *connection;
    115 
    116   /**
    117    * Reference to the authorization plugin which was loaded
    118    */
    119   struct ANASTASIS_AuthorizationPlugin *authorization;
    120 
    121   /**
    122    * Status of the authorization
    123    */
    124   struct ANASTASIS_AUTHORIZATION_State *as;
    125 
    126   /**
    127    * Used while we are awaiting proposal creation.
    128    */
    129   struct TALER_MERCHANT_PostPrivateOrdersHandle *po;
    130 
    131   /**
    132    * Used while we are waiting payment.
    133    */
    134   struct TALER_MERCHANT_GetPrivateOrderHandle *cpo;
    135 
    136   /**
    137    * HTTP response code to use on resume, if non-NULL.
    138    */
    139   struct MHD_Response *resp;
    140 
    141   /**
    142    * Our entry in the #to_heap, or NULL.
    143    */
    144   struct GNUNET_CONTAINER_HeapNode *hn;
    145 
    146   /**
    147    * When should this request time out?
    148    */
    149   struct GNUNET_TIME_Absolute timeout;
    150 
    151   /**
    152    * Random authorization code we are using.
    153    */
    154   uint64_t code;
    155 
    156   /**
    157    * HTTP response code to use on resume, if resp is set.
    158    */
    159   unsigned int response_code;
    160 
    161   /**
    162    * true if client did not provide a payment secret / order ID.
    163    */
    164   bool no_payment_identifier_provided;
    165 
    166   /**
    167    * True if this entry is in the #gc_head DLL.
    168    */
    169   bool in_list;
    170 
    171   /**
    172    * True if this entry is currently suspended.
    173    */
    174   bool suspended;
    175 
    176 };
    177 
    178 
    179 /**
    180  * Information we track for refunds.
    181  */
    182 struct RefundEntry
    183 {
    184   /**
    185    * Kept in a DLL.
    186    */
    187   struct RefundEntry *next;
    188 
    189   /**
    190    * Kept in a DLL.
    191    */
    192   struct RefundEntry *prev;
    193 
    194   /**
    195    * Operation handle.
    196    */
    197   struct TALER_MERCHANT_PostPrivateOrdersRefundHandle *ro;
    198 
    199   /**
    200    * Which order is being refunded.
    201    */
    202   char *order_id;
    203 
    204   /**
    205    * Payment Identifier
    206    */
    207   struct ANASTASIS_PaymentSecretP payment_identifier;
    208 
    209   /**
    210    * Public key of the challenge which is solved.
    211    */
    212   struct ANASTASIS_CRYPTO_TruthUUIDP truth_uuid;
    213 };
    214 
    215 
    216 /**
    217  * Head of linked list of active refund operations.
    218  */
    219 static struct RefundEntry *re_head;
    220 
    221 /**
    222  * Tail of linked list of active refund operations.
    223  */
    224 static struct RefundEntry *re_tail;
    225 
    226 /**
    227  * Head of linked list over all authorization processes
    228  */
    229 static struct ChallengeContext *gc_head;
    230 
    231 /**
    232  * Tail of linked list over all authorization processes
    233  */
    234 static struct ChallengeContext *gc_tail;
    235 
    236 /**
    237  * Task running #do_timeout().
    238  */
    239 static struct GNUNET_SCHEDULER_Task *to_task;
    240 
    241 
    242 /**
    243  * Generate a response telling the client that answering this
    244  * challenge failed because the rate limit has been exceeded.
    245  *
    246  * @param gc request to answer for
    247  * @return MHD status code
    248  */
    249 static MHD_RESULT
    250 reply_rate_limited (const struct ChallengeContext *gc)
    251 {
    252   return TALER_MHD_REPLY_JSON_PACK (
    253     gc->connection,
    254     MHD_HTTP_TOO_MANY_REQUESTS,
    255     TALER_MHD_PACK_EC (TALER_EC_ANASTASIS_TRUTH_RATE_LIMITED),
    256     GNUNET_JSON_pack_uint64 ("request_limit",
    257                              gc->authorization->retry_counter),
    258     GNUNET_JSON_pack_time_rel ("request_frequency",
    259                                gc->authorization->code_rotation_period));
    260 }
    261 
    262 
    263 /**
    264  * Timeout requests that are past their due date.
    265  *
    266  * @param cls NULL
    267  */
    268 static void
    269 do_timeout (void *cls)
    270 {
    271   struct ChallengeContext *gc;
    272 
    273   (void) cls;
    274   to_task = NULL;
    275   while (NULL !=
    276          (gc = GNUNET_CONTAINER_heap_peek (AH_to_heap)))
    277   {
    278     if (GNUNET_TIME_absolute_is_future (gc->timeout))
    279       break;
    280     if (gc->suspended)
    281     {
    282       /* Test needed as we may have a "concurrent"
    283          wakeup from another task that did not clear
    284          this entry from the heap before the
    285          response process concluded. */
    286       gc->suspended = false;
    287       MHD_resume_connection (gc->connection);
    288     }
    289     GNUNET_assert (NULL != gc->hn);
    290     gc->hn = NULL;
    291     GNUNET_assert (gc ==
    292                    GNUNET_CONTAINER_heap_remove_root (AH_to_heap));
    293   }
    294   if (NULL == gc)
    295     return;
    296   to_task = GNUNET_SCHEDULER_add_at (gc->timeout,
    297                                      &do_timeout,
    298                                      NULL);
    299 }
    300 
    301 
    302 void
    303 AH_truth_challenge_shutdown (void)
    304 {
    305   struct ChallengeContext *gc;
    306   struct RefundEntry *re;
    307 
    308   while (NULL != (re = re_head))
    309   {
    310     GNUNET_CONTAINER_DLL_remove (re_head,
    311                                  re_tail,
    312                                  re);
    313     if (NULL != re->ro)
    314     {
    315       TALER_MERCHANT_post_private_orders_refund_cancel (re->ro);
    316       re->ro = NULL;
    317     }
    318     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    319                 "Refund `%s' failed due to shutdown\n",
    320                 re->order_id);
    321     GNUNET_free (re->order_id);
    322     GNUNET_free (re);
    323   }
    324 
    325   while (NULL != (gc = gc_head))
    326   {
    327     GNUNET_CONTAINER_DLL_remove (gc_head,
    328                                  gc_tail,
    329                                  gc);
    330     gc->in_list = false;
    331     if (NULL != gc->cpo)
    332     {
    333       TALER_MERCHANT_get_private_order_cancel (gc->cpo);
    334       gc->cpo = NULL;
    335     }
    336     if (NULL != gc->po)
    337     {
    338       TALER_MERCHANT_post_private_orders_cancel (gc->po);
    339       gc->po = NULL;
    340     }
    341     if (gc->suspended)
    342     {
    343       gc->suspended = false;
    344       MHD_resume_connection (gc->connection);
    345     }
    346     if (NULL != gc->as)
    347     {
    348       gc->authorization->cleanup (gc->as);
    349       gc->as = NULL;
    350       gc->authorization = NULL;
    351     }
    352   }
    353   ANASTASIS_authorization_plugin_shutdown ();
    354   if (NULL != to_task)
    355   {
    356     GNUNET_SCHEDULER_cancel (to_task);
    357     to_task = NULL;
    358   }
    359 }
    360 
    361 
    362 /**
    363  * Callback to process a POST /orders/ID/refund request
    364  *
    365  * @param cls closure with a `struct RefundEntry *`
    366  * @param rr response details
    367  */
    368 static void
    369 refund_cb (
    370   void *cls,
    371   const struct TALER_MERCHANT_PostPrivateOrdersRefundResponse *rr)
    372 {
    373   struct RefundEntry *re = cls;
    374 
    375   re->ro = NULL;
    376   switch (rr->hr.http_status)
    377   {
    378   case MHD_HTTP_OK:
    379     {
    380       enum GNUNET_DB_QueryStatus qs;
    381 
    382       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    383                   "Refund `%s' succeeded\n",
    384                   re->order_id);
    385       qs = db->record_challenge_refund (db->cls,
    386                                         &re->truth_uuid,
    387                                         &re->payment_identifier);
    388       switch (qs)
    389       {
    390       case GNUNET_DB_STATUS_HARD_ERROR:
    391         GNUNET_break (0);
    392         break;
    393       case GNUNET_DB_STATUS_SOFT_ERROR:
    394         GNUNET_break (0);
    395         break;
    396       case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    397         GNUNET_break (0);
    398         break;
    399       case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    400         break;
    401       }
    402     }
    403     break;
    404   default:
    405     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    406                 "Refund `%s' failed with HTTP status %u: %s (#%u)\n",
    407                 re->order_id,
    408                 rr->hr.http_status,
    409                 rr->hr.hint,
    410                 (unsigned int) rr->hr.ec);
    411     break;
    412   }
    413   GNUNET_CONTAINER_DLL_remove (re_head,
    414                                re_tail,
    415                                re);
    416   GNUNET_free (re->order_id);
    417   GNUNET_free (re);
    418 }
    419 
    420 
    421 /**
    422  * Start to give a refund for the challenge created by @a gc.
    423  *
    424  * @param gc request where we failed and should now grant a refund for
    425  */
    426 static void
    427 begin_refund (const struct ChallengeContext *gc)
    428 {
    429   struct RefundEntry *re;
    430 
    431   re = GNUNET_new (struct RefundEntry);
    432   re->order_id = GNUNET_STRINGS_data_to_string_alloc (
    433     &gc->payment_identifier,
    434     sizeof (gc->payment_identifier));
    435   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    436               "Challenge execution failed, triggering refund for order `%s'\n",
    437               re->order_id);
    438   re->payment_identifier = gc->payment_identifier;
    439   re->truth_uuid = gc->truth_uuid;
    440   re->ro = TALER_MERCHANT_post_private_orders_refund_create (AH_ctx,
    441                                                              AH_backend_url,
    442                                                              re->order_id,
    443                                                              &gc->challenge_cost
    444                                                              ,
    445                                                              "failed to issue challenge");
    446   {
    447     enum TALER_ErrorCode ec;
    448 
    449     ec = TALER_MERCHANT_post_private_orders_refund_start (re->ro,
    450                                                           &refund_cb,
    451                                                           re);
    452     if (TALER_EC_NONE != ec)
    453     {
    454       TALER_MERCHANT_post_private_orders_refund_cancel (re->ro);
    455       re->ro = NULL;
    456       GNUNET_break (0);
    457       GNUNET_free (re->order_id);
    458       GNUNET_free (re);
    459       return;
    460     }
    461   }
    462   GNUNET_CONTAINER_DLL_insert (re_head,
    463                                re_tail,
    464                                re);
    465 }
    466 
    467 
    468 /**
    469  * Callback used to notify the application about completed requests.
    470  * Cleans up the requests data structures.
    471  *
    472  * @param hc
    473  */
    474 static void
    475 request_done (struct TM_HandlerContext *hc)
    476 {
    477   struct ChallengeContext *gc = hc->ctx;
    478 
    479   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    480               "Request completed\n");
    481   if (NULL == gc)
    482     return;
    483   hc->cc = NULL;
    484   GNUNET_assert (! gc->suspended);
    485   if (gc->in_list)
    486   {
    487     GNUNET_CONTAINER_DLL_remove (gc_head,
    488                                  gc_tail,
    489                                  gc);
    490     gc->in_list = false;
    491   }
    492   if (NULL != gc->hn)
    493   {
    494     GNUNET_assert (gc ==
    495                    GNUNET_CONTAINER_heap_remove_node (gc->hn));
    496     gc->hn = NULL;
    497   }
    498   if (NULL != gc->as)
    499   {
    500     gc->authorization->cleanup (gc->as);
    501     gc->authorization = NULL;
    502     gc->as = NULL;
    503   }
    504   if (NULL != gc->cpo)
    505   {
    506     TALER_MERCHANT_get_private_order_cancel (gc->cpo);
    507     gc->cpo = NULL;
    508   }
    509   if (NULL != gc->po)
    510   {
    511     TALER_MERCHANT_post_private_orders_cancel (gc->po);
    512     gc->po = NULL;
    513   }
    514   if (NULL != gc->root)
    515   {
    516     json_decref (gc->root);
    517     gc->root = NULL;
    518   }
    519   TALER_MHD_parse_post_cleanup_callback (gc->opaque_post_parsing_context);
    520   GNUNET_free (gc);
    521   hc->ctx = NULL;
    522 }
    523 
    524 
    525 /**
    526  * Transmit a payment request for @a order_id on @a connection
    527  *
    528  * @param gc context to make payment request for
    529  */
    530 static void
    531 make_payment_request (struct ChallengeContext *gc)
    532 {
    533   struct MHD_Response *resp;
    534 
    535   resp = MHD_create_response_from_buffer (0,
    536                                           NULL,
    537                                           MHD_RESPMEM_PERSISTENT);
    538   GNUNET_assert (NULL != resp);
    539   TALER_MHD_add_global_headers (resp,
    540                                 false);
    541   {
    542     char *hdr;
    543     char *order_id;
    544     const char *pfx;
    545     const char *hn;
    546 
    547     if (0 == strncasecmp ("https://",
    548                           AH_backend_url,
    549                           strlen ("https://")))
    550     {
    551       pfx = "taler://";
    552       hn = &AH_backend_url[strlen ("https://")];
    553     }
    554     else if (0 == strncasecmp ("http://",
    555                                AH_backend_url,
    556                                strlen ("http://")))
    557     {
    558       pfx = "taler+http://";
    559       hn = &AH_backend_url[strlen ("http://")];
    560     }
    561     else
    562     {
    563       /* This invariant holds as per check in anastasis-httpd.c */
    564       GNUNET_assert (0);
    565     }
    566     /* This invariant holds as per check in anastasis-httpd.c */
    567     GNUNET_assert (0 != strlen (hn));
    568 
    569     order_id = GNUNET_STRINGS_data_to_string_alloc (
    570       &gc->payment_identifier,
    571       sizeof (gc->payment_identifier));
    572     GNUNET_asprintf (&hdr,
    573                      "%spay/%s%s/",
    574                      pfx,
    575                      hn,
    576                      order_id);
    577     GNUNET_free (order_id);
    578     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    579                 "Sending payment request `%s'\n",
    580                 hdr);
    581     GNUNET_break (MHD_YES ==
    582                   MHD_add_response_header (resp,
    583                                            ANASTASIS_HTTP_HEADER_TALER,
    584                                            hdr));
    585     GNUNET_free (hdr);
    586   }
    587   gc->resp = resp;
    588   gc->response_code = MHD_HTTP_PAYMENT_REQUIRED;
    589 }
    590 
    591 
    592 /**
    593  * Callbacks of this type are used to serve the result of submitting a
    594  * /contract request to a merchant.
    595  *
    596  * @param cls our `struct ChallengeContext`
    597  * @param por response details
    598  */
    599 static void
    600 proposal_cb (void *cls,
    601              const struct TALER_MERCHANT_PostPrivateOrdersResponse *por)
    602 {
    603   struct ChallengeContext *gc = cls;
    604   enum GNUNET_DB_QueryStatus qs;
    605 
    606   gc->po = NULL;
    607   GNUNET_assert (gc->in_list);
    608   GNUNET_CONTAINER_DLL_remove (gc_head,
    609                                gc_tail,
    610                                gc);
    611   gc->in_list = false;
    612   GNUNET_assert (gc->suspended);
    613   gc->suspended = false;
    614   MHD_resume_connection (gc->connection);
    615   AH_trigger_daemon (NULL);
    616   if (MHD_HTTP_OK != por->hr.http_status)
    617   {
    618     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    619                 "Backend returned status %u/%d\n",
    620                 por->hr.http_status,
    621                 (int) por->hr.ec);
    622     GNUNET_break (0);
    623     gc->resp = TALER_MHD_MAKE_JSON_PACK (
    624       GNUNET_JSON_pack_uint64 ("code",
    625                                TALER_EC_ANASTASIS_TRUTH_PAYMENT_CREATE_BACKEND_ERROR),
    626       GNUNET_JSON_pack_string ("hint",
    627                                "Failed to setup order with merchant backend"),
    628       GNUNET_JSON_pack_uint64 ("backend-ec",
    629                                por->hr.ec),
    630       GNUNET_JSON_pack_uint64 ("backend-http-status",
    631                                por->hr.http_status),
    632       GNUNET_JSON_pack_allow_null (
    633         GNUNET_JSON_pack_object_steal ("backend-reply",
    634                                        (json_t *) por->hr.reply)));
    635     gc->response_code = MHD_HTTP_BAD_GATEWAY;
    636     return;
    637   }
    638   qs = db->record_challenge_payment (db->cls,
    639                                      &gc->truth_uuid,
    640                                      &gc->payment_identifier,
    641                                      &gc->challenge_cost);
    642   if (0 >= qs)
    643   {
    644     GNUNET_break (0);
    645     gc->resp = TALER_MHD_make_error (TALER_EC_GENERIC_DB_STORE_FAILED,
    646                                      "record challenge payment");
    647     gc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
    648     return;
    649   }
    650   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    651               "Setup fresh order, creating payment request\n");
    652   make_payment_request (gc);
    653 }
    654 
    655 
    656 /**
    657  * Callback to process a GET /check-payment request
    658  *
    659  * @param cls our `struct ChallengeContext`
    660  * @param osr order status
    661  */
    662 static void
    663 check_payment_cb (void *cls,
    664                   const struct TALER_MERCHANT_GetPrivateOrderResponse *osr)
    665 
    666 {
    667   struct ChallengeContext *gc = cls;
    668   const struct TALER_MERCHANT_HttpResponse *hr = &osr->hr;
    669 
    670   gc->cpo = NULL;
    671   GNUNET_assert (gc->in_list);
    672   GNUNET_CONTAINER_DLL_remove (gc_head,
    673                                gc_tail,
    674                                gc);
    675   gc->in_list = false;
    676   GNUNET_assert (gc->suspended);
    677   gc->suspended = false;
    678   MHD_resume_connection (gc->connection);
    679   AH_trigger_daemon (NULL);
    680 
    681   switch (hr->http_status)
    682   {
    683   case MHD_HTTP_OK:
    684     GNUNET_assert (NULL != osr);
    685     break;
    686   case MHD_HTTP_NOT_FOUND:
    687     /* We created this order before, how can it be not found now? */
    688     GNUNET_break (0);
    689     gc->resp = TALER_MHD_make_error (TALER_EC_ANASTASIS_TRUTH_ORDER_DISAPPEARED,
    690                                      NULL);
    691     gc->response_code = MHD_HTTP_BAD_GATEWAY;
    692     return;
    693   case MHD_HTTP_BAD_GATEWAY:
    694     gc->resp = TALER_MHD_make_error (
    695       TALER_EC_ANASTASIS_TRUTH_BACKEND_EXCHANGE_BAD,
    696       NULL);
    697     gc->response_code = MHD_HTTP_BAD_GATEWAY;
    698     return;
    699   case MHD_HTTP_GATEWAY_TIMEOUT:
    700     gc->resp = TALER_MHD_make_error (TALER_EC_ANASTASIS_GENERIC_BACKEND_TIMEOUT,
    701                                      "Timeout check payment status");
    702     GNUNET_assert (NULL != gc->resp);
    703     gc->response_code = MHD_HTTP_GATEWAY_TIMEOUT;
    704     return;
    705   default:
    706     {
    707       char status[14];
    708 
    709       GNUNET_snprintf (status,
    710                        sizeof (status),
    711                        "%u",
    712                        hr->http_status);
    713       gc->resp = TALER_MHD_make_error (
    714         TALER_EC_ANASTASIS_TRUTH_UNEXPECTED_PAYMENT_STATUS,
    715         status);
    716       GNUNET_assert (NULL != gc->resp);
    717       gc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
    718       return;
    719     }
    720   }
    721 
    722   GNUNET_assert (MHD_HTTP_OK == hr->http_status);
    723   switch (osr->details.ok.status)
    724   {
    725   case TALER_MERCHANT_OSC_PAID:
    726     {
    727       enum GNUNET_DB_QueryStatus qs;
    728 
    729       qs = db->update_challenge_payment (db->cls,
    730                                          &gc->truth_uuid,
    731                                          &gc->payment_identifier);
    732       if (0 <= qs)
    733       {
    734         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    735                     "Order has been paid, continuing with request processing\n")
    736         ;
    737         return; /* continue as planned */
    738       }
    739       GNUNET_break (0);
    740       gc->resp = TALER_MHD_make_error (TALER_EC_GENERIC_DB_STORE_FAILED,
    741                                        "update challenge payment");
    742       gc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
    743       return; /* continue as planned */
    744     }
    745   case TALER_MERCHANT_OSC_CLAIMED:
    746   case TALER_MERCHANT_OSC_UNPAID:
    747     /* repeat payment request */
    748     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    749                 "Order remains unpaid, sending payment request again\n");
    750     make_payment_request (gc);
    751     return;
    752   }
    753   /* should never get here */
    754   GNUNET_break (0);
    755 }
    756 
    757 
    758 /**
    759  * Helper function used to ask our backend to begin processing a
    760  * payment for the user's account.  May perform asynchronous
    761  * operations by suspending the connection if required.
    762  *
    763  * @param gc context to begin payment for.
    764  * @return MHD status code
    765  */
    766 static MHD_RESULT
    767 begin_payment (struct ChallengeContext *gc)
    768 {
    769   enum GNUNET_DB_QueryStatus qs;
    770   char *order_id;
    771 
    772   qs = db->lookup_challenge_payment (db->cls,
    773                                      &gc->truth_uuid,
    774                                      &gc->payment_identifier);
    775   if (qs < 0)
    776   {
    777     GNUNET_break (0);
    778     return TALER_MHD_reply_with_error (gc->connection,
    779                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    780                                        TALER_EC_GENERIC_DB_FETCH_FAILED,
    781                                        "lookup challenge payment");
    782   }
    783   GNUNET_assert (! gc->in_list);
    784   gc->in_list = true;
    785   GNUNET_CONTAINER_DLL_insert (gc_tail,
    786                                gc_head,
    787                                gc);
    788   GNUNET_assert (! gc->suspended);
    789   gc->suspended = true;
    790   MHD_suspend_connection (gc->connection);
    791   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
    792   {
    793     /* We already created the order, check if it was paid */
    794     struct GNUNET_TIME_Relative timeout;
    795 
    796     order_id = GNUNET_STRINGS_data_to_string_alloc (
    797       &gc->payment_identifier,
    798       sizeof (gc->payment_identifier));
    799     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    800                 "Order exists, checking payment status for order `%s'\n",
    801                 order_id);
    802     timeout = GNUNET_TIME_absolute_get_remaining (gc->timeout);
    803     gc->cpo = TALER_MERCHANT_get_private_order_create (AH_ctx,
    804                                                        AH_backend_url,
    805                                                        order_id);
    806     GNUNET_assert (NULL != gc->cpo);
    807     GNUNET_assert (
    808       GNUNET_OK ==
    809       TALER_MERCHANT_get_private_order_set_options (
    810         gc->cpo,
    811         TALER_MERCHANT_get_private_order_option_timeout (timeout)));
    812     GNUNET_assert (TALER_EC_NONE ==
    813                    TALER_MERCHANT_get_private_order_start (gc->cpo,
    814                                                            &check_payment_cb,
    815                                                            gc));
    816   }
    817   else
    818   {
    819     /* Create a fresh order */
    820     struct GNUNET_TIME_Timestamp pay_deadline;
    821 
    822     GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
    823                                 &gc->payment_identifier,
    824                                 sizeof (struct ANASTASIS_PaymentSecretP));
    825     order_id = GNUNET_STRINGS_data_to_string_alloc (
    826       &gc->payment_identifier,
    827       sizeof (gc->payment_identifier));
    828     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    829                 "Creating fresh order `%s'\n",
    830                 order_id);
    831     pay_deadline = GNUNET_TIME_relative_to_timestamp (
    832       ANASTASIS_CHALLENGE_OFFER_LIFETIME);
    833     {
    834       json_t *order;
    835 
    836       order = GNUNET_JSON_PACK (
    837         TALER_JSON_pack_amount ("amount",
    838                                 &gc->challenge_cost),
    839         GNUNET_JSON_pack_string ("summary",
    840                                  "challenge fee for anastasis service"),
    841         GNUNET_JSON_pack_string ("order_id",
    842                                  order_id),
    843         GNUNET_JSON_pack_time_rel ("auto_refund",
    844                                    AUTO_REFUND_TIMEOUT),
    845         GNUNET_JSON_pack_timestamp ("pay_deadline",
    846                                     pay_deadline));
    847       gc->po = TALER_MERCHANT_post_private_orders_create (AH_ctx,
    848                                                           AH_backend_url,
    849                                                           order);
    850       json_decref (order);
    851     }
    852     GNUNET_assert (NULL != gc->po);
    853     GNUNET_assert (
    854       GNUNET_OK ==
    855       TALER_MERCHANT_post_private_orders_set_options (
    856         gc->po,
    857         TALER_MERCHANT_post_private_orders_option_create_token (false),
    858         TALER_MERCHANT_post_private_orders_option_refund_delay (
    859           AUTO_REFUND_TIMEOUT)));
    860     GNUNET_assert (TALER_EC_NONE ==
    861                    TALER_MERCHANT_post_private_orders_start (
    862                      gc->po,
    863                      &proposal_cb,
    864                      gc));
    865   }
    866   GNUNET_free (order_id);
    867   AH_trigger_curl ();
    868   return MHD_YES;
    869 }
    870 
    871 
    872 /**
    873  * Mark @a gc as suspended and update the respective
    874  * data structures and jobs.
    875  *
    876  * @param[in,out] gc context of the suspended operation
    877  */
    878 static void
    879 gc_suspended (struct ChallengeContext *gc)
    880 {
    881   gc->suspended = true;
    882   if (NULL == AH_to_heap)
    883     AH_to_heap = GNUNET_CONTAINER_heap_create (
    884       GNUNET_CONTAINER_HEAP_ORDER_MIN);
    885   gc->hn = GNUNET_CONTAINER_heap_insert (AH_to_heap,
    886                                          gc,
    887                                          gc->timeout.abs_value_us);
    888   if (NULL != to_task)
    889   {
    890     GNUNET_SCHEDULER_cancel (to_task);
    891     to_task = NULL;
    892   }
    893   {
    894     struct ChallengeContext *rn;
    895 
    896     rn = GNUNET_CONTAINER_heap_peek (AH_to_heap);
    897     to_task = GNUNET_SCHEDULER_add_at (rn->timeout,
    898                                        &do_timeout,
    899                                        NULL);
    900   }
    901 }
    902 
    903 
    904 /**
    905  * Run the authorization method-specific 'process' function and continue
    906  * based on its result with generating an HTTP response.
    907  *
    908  * @param connection the connection we are handling
    909  * @param gc our overall handler context
    910  */
    911 static MHD_RESULT
    912 run_authorization_process (struct MHD_Connection *connection,
    913                            struct ChallengeContext *gc)
    914 {
    915   enum ANASTASIS_AUTHORIZATION_ChallengeResult ret;
    916   enum GNUNET_DB_QueryStatus qs;
    917 
    918   GNUNET_assert (! gc->suspended);
    919   if (NULL == gc->authorization->challenge)
    920   {
    921     GNUNET_break (0);
    922     return TALER_MHD_reply_with_error (gc->connection,
    923                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    924                                        TALER_EC_ANASTASIS_TRUTH_AUTHORIZATION_START_FAILED,
    925                                        "challenge method not implemented for authorization method");
    926   }
    927   ret = gc->authorization->challenge (gc->as,
    928                                       connection);
    929   switch (ret)
    930   {
    931   case ANASTASIS_AUTHORIZATION_CRES_SUCCESS:
    932     /* Challenge sent successfully */
    933     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    934                 "Authorization request %llu for %s sent successfully\n",
    935                 (unsigned long long) gc->code,
    936                 TALER_B2S (&gc->truth_uuid));
    937     qs = db->mark_challenge_sent (db->cls,
    938                                   &gc->payment_identifier,
    939                                   &gc->truth_uuid,
    940                                   gc->code);
    941     GNUNET_break (0 < qs);
    942     gc->authorization->cleanup (gc->as);
    943     gc->as = NULL;
    944     return MHD_YES;
    945   case ANASTASIS_AUTHORIZATION_CRES_FAILED:
    946     if (! gc->no_payment_identifier_provided)
    947     {
    948       begin_refund (gc);
    949     }
    950     gc->authorization->cleanup (gc->as);
    951     gc->as = NULL;
    952     return MHD_YES;
    953   case ANASTASIS_AUTHORIZATION_CRES_SUSPENDED:
    954     /* connection was suspended */
    955     gc_suspended (gc);
    956     return MHD_YES;
    957   case ANASTASIS_AUTHORIZATION_CRES_SUCCESS_REPLY_FAILED:
    958     /* Challenge sent successfully */
    959     qs = db->mark_challenge_sent (db->cls,
    960                                   &gc->payment_identifier,
    961                                   &gc->truth_uuid,
    962                                   gc->code);
    963     GNUNET_break (0 < qs);
    964     gc->authorization->cleanup (gc->as);
    965     gc->as = NULL;
    966     return MHD_NO;
    967   case ANASTASIS_AUTHORIZATION_CRES_FAILED_REPLY_FAILED:
    968     gc->authorization->cleanup (gc->as);
    969     gc->as = NULL;
    970     return MHD_NO;
    971   }
    972   GNUNET_break (0);
    973   return MHD_NO;
    974 }
    975 
    976 
    977 MHD_RESULT
    978 AH_handler_truth_challenge (
    979   struct MHD_Connection *connection,
    980   struct TM_HandlerContext *hc,
    981   const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
    982   const char *upload_data,
    983   size_t *upload_data_size)
    984 {
    985   struct ChallengeContext *gc = hc->ctx;
    986   void *encrypted_truth;
    987   size_t encrypted_truth_size;
    988   void *decrypted_truth;
    989   size_t decrypted_truth_size;
    990   char *truth_mime = NULL;
    991 
    992   if (NULL == gc)
    993   {
    994     /* Fresh request, do initial setup */
    995     gc = GNUNET_new (struct ChallengeContext);
    996     gc->hc = hc;
    997     hc->ctx = gc;
    998     gc->connection = connection;
    999     gc->truth_uuid = *truth_uuid;
   1000     gc->hc->cc = &request_done;
   1001     gc->timeout = GNUNET_TIME_relative_to_absolute (
   1002       PAYMENT_TIMEOUT);
   1003   } /* end of first-time initialization (if NULL == gc) */
   1004   else
   1005   {
   1006     /* might have been woken up by authorization plugin,
   1007        so clear the flag. MDH called us, so we are
   1008        clearly no longer suspended */
   1009     gc->suspended = false;
   1010     if (NULL != gc->resp)
   1011     {
   1012       MHD_RESULT ret;
   1013 
   1014       /* We generated a response asynchronously, queue that */
   1015       ret = MHD_queue_response (connection,
   1016                                 gc->response_code,
   1017                                 gc->resp);
   1018       GNUNET_break (MHD_YES == ret);
   1019       MHD_destroy_response (gc->resp);
   1020       gc->resp = NULL;
   1021       return ret;
   1022     }
   1023     if (NULL != gc->as)
   1024     {
   1025       /* Authorization process is "running", check what is going on */
   1026       GNUNET_assert (NULL != gc->authorization);
   1027       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1028                   "Continuing with running the authorization process\n");
   1029       GNUNET_assert (! gc->suspended);
   1030       return run_authorization_process (connection,
   1031                                         gc);
   1032 
   1033     }
   1034     /* We get here if the async check for payment said this request
   1035        was indeed paid! */
   1036   }
   1037 
   1038   /* parse byte stream upload into JSON */
   1039   if (NULL == gc->root)
   1040   {
   1041     enum GNUNET_GenericReturnValue res;
   1042 
   1043     res = TALER_MHD_parse_post_json (connection,
   1044                                      &gc->opaque_post_parsing_context,
   1045                                      upload_data,
   1046                                      upload_data_size,
   1047                                      &gc->root);
   1048     if (GNUNET_SYSERR == res)
   1049     {
   1050       GNUNET_assert (NULL == gc->root);
   1051       return MHD_NO; /* bad upload, could not even generate error */
   1052     }
   1053     if ( (GNUNET_NO == res) ||
   1054          (NULL == gc->root) )
   1055     {
   1056       GNUNET_assert (NULL == gc->root);
   1057       return MHD_YES; /* so far incomplete upload or parser error */
   1058     }
   1059 
   1060     /* 'root' is now initialized */
   1061     {
   1062       struct GNUNET_JSON_Specification spec[] = {
   1063         GNUNET_JSON_spec_fixed_auto ("truth_decryption_key",
   1064                                      &gc->truth_key),
   1065         GNUNET_JSON_spec_mark_optional (
   1066           GNUNET_JSON_spec_fixed_auto ("payment_secret",
   1067                                        &gc->payment_identifier),
   1068           &gc->no_payment_identifier_provided),
   1069         GNUNET_JSON_spec_end ()
   1070       };
   1071       enum GNUNET_GenericReturnValue pres;
   1072 
   1073       pres = TALER_MHD_parse_json_data (connection,
   1074                                         gc->root,
   1075                                         spec);
   1076       if (GNUNET_SYSERR == pres)
   1077       {
   1078         GNUNET_break (0);
   1079         return MHD_NO; /* hard failure */
   1080       }
   1081       if (GNUNET_NO == pres)
   1082       {
   1083         GNUNET_break_op (0);
   1084         return MHD_YES; /* failure */
   1085       }
   1086       if (! gc->no_payment_identifier_provided)
   1087         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1088                     "Client provided payment identifier `%s'\n",
   1089                     TALER_B2S (&gc->payment_identifier));
   1090     }
   1091   }
   1092 
   1093   {
   1094     /* load encrypted truth from DB */
   1095     enum GNUNET_DB_QueryStatus qs;
   1096     char *method;
   1097 
   1098     qs = db->get_escrow_challenge (db->cls,
   1099                                    &gc->truth_uuid,
   1100                                    &encrypted_truth,
   1101                                    &encrypted_truth_size,
   1102                                    &truth_mime,
   1103                                    &method);
   1104     switch (qs)
   1105     {
   1106     case GNUNET_DB_STATUS_HARD_ERROR:
   1107     case GNUNET_DB_STATUS_SOFT_ERROR:
   1108       GNUNET_break (0);
   1109       return TALER_MHD_reply_with_error (gc->connection,
   1110                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
   1111                                          TALER_EC_GENERIC_DB_FETCH_FAILED,
   1112                                          "get escrow challenge");
   1113     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   1114       return TALER_MHD_reply_with_error (connection,
   1115                                          MHD_HTTP_NOT_FOUND,
   1116                                          TALER_EC_ANASTASIS_TRUTH_UNKNOWN,
   1117                                          NULL);
   1118     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   1119       break;
   1120     }
   1121     if (0 == strcmp ("question",
   1122                      method))
   1123     {
   1124       GNUNET_break_op (0);
   1125       GNUNET_free (encrypted_truth);
   1126       GNUNET_free (truth_mime);
   1127       GNUNET_free (method);
   1128       return TALER_MHD_reply_with_error (connection,
   1129                                          MHD_HTTP_BAD_REQUEST,
   1130                                          TALER_EC_ANASTASIS_TRUTH_CHALLENGE_WRONG_METHOD,
   1131                                          "question");
   1132     }
   1133 
   1134     gc->authorization
   1135       = ANASTASIS_authorization_plugin_load (method,
   1136                                              db,
   1137                                              AH_cfg);
   1138     if (NULL == gc->authorization)
   1139     {
   1140       MHD_RESULT ret;
   1141 
   1142       ret = TALER_MHD_reply_with_error (
   1143         connection,
   1144         MHD_HTTP_INTERNAL_SERVER_ERROR,
   1145         TALER_EC_ANASTASIS_TRUTH_AUTHORIZATION_METHOD_NO_LONGER_SUPPORTED,
   1146         method);
   1147       GNUNET_free (encrypted_truth);
   1148       GNUNET_free (truth_mime);
   1149       GNUNET_free (method);
   1150       return ret;
   1151     }
   1152 
   1153     if (gc->authorization->user_provided_code)
   1154     {
   1155       MHD_RESULT ret;
   1156 
   1157       GNUNET_break_op (0);
   1158       ret = TALER_MHD_reply_with_error (connection,
   1159                                         MHD_HTTP_BAD_REQUEST,
   1160                                         TALER_EC_ANASTASIS_TRUTH_CHALLENGE_WRONG_METHOD,
   1161                                         method);
   1162       GNUNET_free (encrypted_truth);
   1163       GNUNET_free (truth_mime);
   1164       GNUNET_free (method);
   1165       return ret;
   1166     }
   1167 
   1168     gc->challenge_cost = gc->authorization->cost;
   1169     GNUNET_free (method);
   1170   }
   1171 
   1172   if (! gc->authorization->payment_plugin_managed)
   1173   {
   1174     if (! TALER_amount_is_zero (&gc->challenge_cost))
   1175     {
   1176       /* Check database to see if the transaction is paid for */
   1177       enum GNUNET_DB_QueryStatus qs;
   1178       bool paid;
   1179 
   1180       if (gc->no_payment_identifier_provided)
   1181       {
   1182         GNUNET_free (truth_mime);
   1183         GNUNET_free (encrypted_truth);
   1184         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1185                     "Beginning payment, client did not provide payment identifier\n");
   1186         return begin_payment (gc);
   1187       }
   1188       qs = db->check_challenge_payment (db->cls,
   1189                                         &gc->payment_identifier,
   1190                                         &gc->truth_uuid,
   1191                                         &paid);
   1192       switch (qs)
   1193       {
   1194       case GNUNET_DB_STATUS_HARD_ERROR:
   1195       case GNUNET_DB_STATUS_SOFT_ERROR:
   1196         GNUNET_break (0);
   1197         GNUNET_free (truth_mime);
   1198         GNUNET_free (encrypted_truth);
   1199         return TALER_MHD_reply_with_error (gc->connection,
   1200                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
   1201                                            TALER_EC_GENERIC_DB_FETCH_FAILED,
   1202                                            "check challenge payment");
   1203       case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   1204         /* Create fresh payment identifier (cannot trust client) */
   1205         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1206                     "Client-provided payment identifier is unknown.\n");
   1207         GNUNET_free (truth_mime);
   1208         GNUNET_free (encrypted_truth);
   1209         return begin_payment (gc);
   1210       case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   1211         if (! paid)
   1212         {
   1213           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1214                       "Payment identifier known. Checking payment with client's payment identifier\n");
   1215           GNUNET_free (truth_mime);
   1216           GNUNET_free (encrypted_truth);
   1217           return begin_payment (gc);
   1218         }
   1219         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1220                     "Payment confirmed\n");
   1221         break;
   1222       }
   1223     }
   1224     else
   1225     {
   1226       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1227                   "Request is free of charge\n");
   1228     }
   1229   }
   1230 
   1231   /* We've been paid, now validate response */
   1232   {
   1233     /* decrypt encrypted_truth */
   1234     ANASTASIS_CRYPTO_truth_decrypt (&gc->truth_key,
   1235                                     encrypted_truth,
   1236                                     encrypted_truth_size,
   1237                                     &decrypted_truth,
   1238                                     &decrypted_truth_size);
   1239     GNUNET_free (encrypted_truth);
   1240   }
   1241   if (NULL == decrypted_truth)
   1242   {
   1243     GNUNET_free (truth_mime);
   1244     return TALER_MHD_reply_with_error (connection,
   1245                                        MHD_HTTP_CONFLICT,
   1246                                        TALER_EC_ANASTASIS_TRUTH_DECRYPTION_FAILED,
   1247                                        NULL);
   1248   }
   1249 
   1250   /* Not security question and no answer: use plugin to check if
   1251      decrypted truth is a valid challenge! */
   1252   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1253               "No challenge provided, creating fresh challenge\n");
   1254   {
   1255     enum GNUNET_GenericReturnValue ret;
   1256 
   1257     ret = gc->authorization->validate (gc->authorization->cls,
   1258                                        connection,
   1259                                        truth_mime,
   1260                                        decrypted_truth,
   1261                                        decrypted_truth_size);
   1262     GNUNET_free (truth_mime);
   1263     switch (ret)
   1264     {
   1265     case GNUNET_OK:
   1266       /* data valid, continued below */
   1267       break;
   1268     case GNUNET_NO:
   1269       /* data invalid, reply was queued */
   1270       GNUNET_free (decrypted_truth);
   1271       return MHD_YES;
   1272     case GNUNET_SYSERR:
   1273       /* data invalid, reply was NOT queued */
   1274       GNUNET_free (decrypted_truth);
   1275       return MHD_NO;
   1276     }
   1277   }
   1278 
   1279   /* Setup challenge and begin authorization process */
   1280   {
   1281     struct GNUNET_TIME_Timestamp transmission_date;
   1282     enum GNUNET_DB_QueryStatus qs;
   1283 
   1284     qs = db->create_challenge_code (db->cls,
   1285                                     &gc->truth_uuid,
   1286                                     gc->authorization->code_rotation_period,
   1287                                     gc->authorization->code_validity_period,
   1288                                     gc->authorization->retry_counter,
   1289                                     &transmission_date,
   1290                                     &gc->code);
   1291     switch (qs)
   1292     {
   1293     case GNUNET_DB_STATUS_HARD_ERROR:
   1294     case GNUNET_DB_STATUS_SOFT_ERROR:
   1295       GNUNET_break (0);
   1296       GNUNET_free (decrypted_truth);
   1297       return TALER_MHD_reply_with_error (gc->connection,
   1298                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
   1299                                          TALER_EC_GENERIC_DB_FETCH_FAILED,
   1300                                          "create_challenge_code");
   1301     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   1302       /* 0 == retry_counter of existing challenge => rate limit exceeded */
   1303       GNUNET_free (decrypted_truth);
   1304       return reply_rate_limited (gc);
   1305     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   1306       /* challenge code was stored successfully*/
   1307       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1308                   "Created fresh challenge\n");
   1309       break;
   1310     }
   1311 
   1312     if (GNUNET_TIME_relative_cmp (
   1313           GNUNET_TIME_absolute_get_duration (
   1314             transmission_date.abs_time),
   1315           <,
   1316           gc->authorization->code_retransmission_frequency) )
   1317     {
   1318       /* Too early for a retransmission! */
   1319       GNUNET_free (decrypted_truth);
   1320       return TALER_MHD_REPLY_JSON_PACK (
   1321         gc->connection,
   1322         MHD_HTTP_OK,
   1323         GNUNET_JSON_pack_string ("challenge_type",
   1324                                  "TAN_ALREADY_SENT"));
   1325     }
   1326   }
   1327 
   1328   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1329               "Beginning authorization process\n");
   1330   gc->as = gc->authorization->start (gc->authorization->cls,
   1331                                      &AH_trigger_daemon,
   1332                                      NULL,
   1333                                      &gc->truth_uuid,
   1334                                      gc->code,
   1335                                      decrypted_truth,
   1336                                      decrypted_truth_size);
   1337   GNUNET_free (decrypted_truth);
   1338   if (NULL == gc->as)
   1339   {
   1340     GNUNET_break (0);
   1341     return TALER_MHD_reply_with_error (gc->connection,
   1342                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
   1343                                        TALER_EC_ANASTASIS_TRUTH_AUTHORIZATION_START_FAILED,
   1344                                        NULL);
   1345   }
   1346   if (! gc->in_list)
   1347   {
   1348     gc->in_list = true;
   1349     GNUNET_CONTAINER_DLL_insert (gc_head,
   1350                                  gc_tail,
   1351                                  gc);
   1352   }
   1353   GNUNET_assert (! gc->suspended);
   1354   return run_authorization_process (connection,
   1355                                     gc);
   1356 }