LCOV - code coverage report
Current view: top level - auditor - report-lib.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 142 267 53.2 %
Date: 2021-08-30 06:43:37 Functions: 13 14 92.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2016-2020 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 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 Affero Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU Affero Public License along with
      14             :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : /**
      17             :  * @file auditor/report-lib.c
      18             :  * @brief helper library to facilitate generation of audit reports
      19             :  * @author Christian Grothoff
      20             :  */
      21             : #include "platform.h"
      22             : #include "report-lib.h"
      23             : 
      24             : /**
      25             :  * Handle to access the exchange's database.
      26             :  */
      27             : struct TALER_EXCHANGEDB_Plugin *TALER_ARL_edb;
      28             : 
      29             : /**
      30             :  * Which currency are we doing the audit for?
      31             :  */
      32             : char *TALER_ARL_currency;
      33             : 
      34             : /**
      35             :  * How many fractional digits does the currency use?
      36             :  */
      37             : struct TALER_Amount TALER_ARL_currency_round_unit;
      38             : 
      39             : /**
      40             :  * Our configuration.
      41             :  */
      42             : const struct GNUNET_CONFIGURATION_Handle *TALER_ARL_cfg;
      43             : 
      44             : /**
      45             :  * Handle to access the auditor's database.
      46             :  */
      47             : struct TALER_AUDITORDB_Plugin *TALER_ARL_adb;
      48             : 
      49             : /**
      50             :  * Master public key of the exchange to audit.
      51             :  */
      52             : struct TALER_MasterPublicKeyP TALER_ARL_master_pub;
      53             : 
      54             : /**
      55             :  * Public key of the auditor.
      56             :  */
      57             : struct TALER_AuditorPublicKeyP TALER_ARL_auditor_pub;
      58             : 
      59             : /**
      60             :  * REST API endpoint of the auditor.
      61             :  */
      62             : char *TALER_ARL_auditor_url;
      63             : 
      64             : /**
      65             :  * At what time did the auditor process start?
      66             :  */
      67             : struct GNUNET_TIME_Absolute start_time;
      68             : 
      69             : /**
      70             :  * Results about denominations, cached per-transaction, maps denomination pub hashes
      71             :  * to `struct TALER_DenominationKeyValidityPS`.
      72             :  */
      73             : static struct GNUNET_CONTAINER_MultiHashMap *denominations;
      74             : 
      75             : /**
      76             :  * Flag that is raised to 'true' if the user
      77             :  * presses CTRL-C to abort the audit.
      78             :  */
      79             : static volatile bool abort_flag;
      80             : 
      81             : /**
      82             :  * Context for the SIG-INT (ctrl-C) handler.
      83             :  */
      84             : static struct GNUNET_SIGNAL_Context *sig_int;
      85             : 
      86             : /**
      87             :  * Context for the SIGTERM handler.
      88             :  */
      89             : static struct GNUNET_SIGNAL_Context *sig_term;
      90             : 
      91             : 
      92             : /**
      93             :  * Test if the audit should be aborted because the user
      94             :  * pressed CTRL-C.
      95             :  *
      96             :  * @return false to continue the audit, true to terminate
      97             :  *         cleanly as soon as possible
      98             :  */
      99             : bool
     100        2880 : TALER_ARL_do_abort (void)
     101             : {
     102        2880 :   return abort_flag;
     103             : }
     104             : 
     105             : 
     106             : /**
     107             :  * Add @a object to the report @a array.  Fail hard if this fails.
     108             :  *
     109             :  * @param array report array to append @a object to
     110             :  * @param object object to append, should be check that it is not NULL
     111             :  */
     112             : void
     113         153 : TALER_ARL_report (json_t *array,
     114             :                   json_t *object)
     115             : {
     116         153 :   GNUNET_assert (NULL != object);
     117         153 :   GNUNET_assert (0 ==
     118             :                  json_array_append_new (array,
     119             :                                         object));
     120         153 : }
     121             : 
     122             : 
     123             : /**
     124             :  * Function called with the results of iterate_denomination_info(),
     125             :  * or directly (!).  Used to check and add the respective denomination
     126             :  * to our hash table.
     127             :  *
     128             :  * @param cls closure, NULL
     129             :  * @param denom_pub public key, sometimes NULL (!)
     130             :  * @param validity issuing information with value, fees and other info about the denomination.
     131             :  */
     132             : static void
     133       40380 : add_denomination (
     134             :   void *cls,
     135             :   const struct TALER_DenominationPublicKey *denom_pub,
     136             :   const struct TALER_EXCHANGEDB_DenominationKeyInformationP *validity)
     137             : {
     138       40380 :   const struct TALER_DenominationKeyValidityPS *issue = &validity->properties;
     139             : 
     140             :   (void) cls;
     141             :   (void) denom_pub;
     142       40380 :   if (NULL !=
     143       40380 :       GNUNET_CONTAINER_multihashmap_get (denominations,
     144             :                                          &issue->denom_hash))
     145           0 :     return; /* value already known */
     146             : #if GNUNET_EXTRA_LOGGING >= 1
     147             :   {
     148             :     struct TALER_Amount value;
     149             : 
     150       40380 :     TALER_amount_ntoh (&value,
     151             :                        &issue->value);
     152       40380 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     153             :                 "Tracking denomination `%s' (%s)\n",
     154             :                 GNUNET_h2s (&issue->denom_hash),
     155             :                 TALER_amount2s (&value));
     156       40380 :     TALER_amount_ntoh (&value,
     157             :                        &issue->fee_withdraw);
     158       40380 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     159             :                 "Withdraw fee is %s\n",
     160             :                 TALER_amount2s (&value));
     161       40380 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     162             :                 "Start time is %s\n",
     163             :                 GNUNET_STRINGS_absolute_time_to_string
     164             :                   (GNUNET_TIME_absolute_ntoh (issue->start)));
     165       40380 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     166             :                 "Expire deposit time is %s\n",
     167             :                 GNUNET_STRINGS_absolute_time_to_string
     168             :                   (GNUNET_TIME_absolute_ntoh (issue->expire_deposit)));
     169             :   }
     170             : #endif
     171             :   {
     172             :     struct TALER_DenominationKeyValidityPS *i;
     173             : 
     174       40380 :     i = GNUNET_new (struct TALER_DenominationKeyValidityPS);
     175       40380 :     *i = *issue;
     176       40380 :     i->master = TALER_ARL_master_pub;
     177       40380 :     GNUNET_assert (GNUNET_OK ==
     178             :                    GNUNET_CONTAINER_multihashmap_put (denominations,
     179             :                                                       &issue->denom_hash,
     180             :                                                       i,
     181             :                                                       GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
     182             :   }
     183             : }
     184             : 
     185             : 
     186             : /**
     187             :  * Obtain information about a @a denom_pub.
     188             :  *
     189             :  * @param dh hash of the denomination public key to look up
     190             :  * @param[out] issue set to detailed information about @a denom_pub, NULL if not found, must
     191             :  *                 NOT be freed by caller
     192             :  * @return transaction status code
     193             :  */
     194             : enum GNUNET_DB_QueryStatus
     195        4426 : TALER_ARL_get_denomination_info_by_hash (
     196             :   const struct GNUNET_HashCode *dh,
     197             :   const struct TALER_DenominationKeyValidityPS **issue)
     198             : {
     199             :   enum GNUNET_DB_QueryStatus qs;
     200             : 
     201        4426 :   if (NULL == denominations)
     202             :   {
     203         100 :     denominations = GNUNET_CONTAINER_multihashmap_create (256,
     204             :                                                           GNUNET_NO);
     205         100 :     qs = TALER_ARL_edb->iterate_denomination_info (TALER_ARL_edb->cls,
     206             :                                                    &add_denomination,
     207             :                                                    NULL);
     208         100 :     if (0 > qs)
     209             :     {
     210           0 :       *issue = NULL;
     211           0 :       return qs;
     212             :     }
     213             :   }
     214             :   {
     215             :     const struct TALER_DenominationKeyValidityPS *i;
     216             : 
     217        4426 :     i = GNUNET_CONTAINER_multihashmap_get (denominations,
     218             :                                            dh);
     219        4426 :     if (NULL != i)
     220             :     {
     221             :       /* cache hit */
     222        4426 :       *issue = i;
     223        4426 :       return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
     224             :     }
     225             :   }
     226             :   /* maybe database changed since we last iterated, give it one more shot */
     227             :   {
     228             :     struct TALER_EXCHANGEDB_DenominationKeyInformationP issue;
     229             : 
     230           0 :     qs = TALER_ARL_edb->get_denomination_info (TALER_ARL_edb->cls,
     231             :                                                dh,
     232             :                                                &issue);
     233           0 :     if (qs <= 0)
     234             :     {
     235           0 :       if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
     236           0 :         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     237             :                     "Denomination %s not found\n",
     238             :                     TALER_B2S (dh));
     239           0 :       return qs;
     240             :     }
     241           0 :     add_denomination (NULL,
     242             :                       NULL,
     243             :                       &issue);
     244             :   }
     245             :   {
     246             :     const struct TALER_DenominationKeyValidityPS *i;
     247             : 
     248           0 :     i = GNUNET_CONTAINER_multihashmap_get (denominations,
     249             :                                            dh);
     250           0 :     if (NULL != i)
     251             :     {
     252             :       /* cache hit */
     253           0 :       *issue = i;
     254           0 :       return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
     255             :     }
     256             :   }
     257             :   /* We found more keys, but not the denomination we are looking for :-( */
     258           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     259             :               "Denomination %s not found\n",
     260             :               TALER_B2S (dh));
     261           0 :   return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
     262             : }
     263             : 
     264             : 
     265             : /**
     266             :  * Obtain information about a @a denom_pub.
     267             :  *
     268             :  * @param denom_pub key to look up
     269             :  * @param[out] issue set to detailed information about @a denom_pub, NULL if not found, must
     270             :  *                 NOT be freed by caller
     271             :  * @param[out] dh set to the hash of @a denom_pub, may be NULL
     272             :  * @return transaction status code
     273             :  */
     274             : enum GNUNET_DB_QueryStatus
     275        4279 : TALER_ARL_get_denomination_info (
     276             :   const struct TALER_DenominationPublicKey *denom_pub,
     277             :   const struct TALER_DenominationKeyValidityPS **issue,
     278             :   struct GNUNET_HashCode *dh)
     279             : {
     280             :   struct GNUNET_HashCode hc;
     281             : 
     282        4279 :   if (NULL == dh)
     283        2195 :     dh = &hc;
     284        4279 :   GNUNET_CRYPTO_rsa_public_key_hash (denom_pub->rsa_public_key,
     285             :                                      dh);
     286        4279 :   return TALER_ARL_get_denomination_info_by_hash (dh,
     287             :                                                   issue);
     288             : }
     289             : 
     290             : 
     291             : /**
     292             :  * Perform the given @a analysis within a transaction scope.
     293             :  * Commit on success.
     294             :  *
     295             :  * @param analysis analysis to run
     296             :  * @param analysis_cls closure for @a analysis
     297             :  * @return #GNUNET_OK if @a analysis succeessfully committed,
     298             :  *         #GNUNET_NO if we had an error on commit (retry may help)
     299             :  *         #GNUNET_SYSERR on hard errors
     300             :  */
     301             : static int
     302         332 : transact (TALER_ARL_Analysis analysis,
     303             :           void *analysis_cls)
     304             : {
     305             :   int ret;
     306             :   enum GNUNET_DB_QueryStatus qs;
     307             : 
     308         332 :   ret = TALER_ARL_adb->start (TALER_ARL_adb->cls);
     309         332 :   if (GNUNET_OK != ret)
     310             :   {
     311           0 :     GNUNET_break (0);
     312           0 :     return GNUNET_SYSERR;
     313             :   }
     314         332 :   if (GNUNET_OK !=
     315         332 :       TALER_ARL_edb->preflight (TALER_ARL_edb->cls))
     316             :   {
     317           0 :     GNUNET_break (0);
     318           0 :     return GNUNET_SYSERR;
     319             :   }
     320         332 :   ret = TALER_ARL_edb->start (TALER_ARL_edb->cls,
     321             :                               "auditor");
     322         332 :   if (GNUNET_OK != ret)
     323             :   {
     324           0 :     GNUNET_break (0);
     325           0 :     TALER_ARL_edb->rollback (TALER_ARL_edb->cls);
     326           0 :     return GNUNET_SYSERR;
     327             :   }
     328         332 :   qs = analysis (analysis_cls);
     329         332 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
     330             :   {
     331         266 :     qs = TALER_ARL_edb->commit (TALER_ARL_edb->cls);
     332         266 :     if (0 > qs)
     333             :     {
     334           0 :       GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
     335           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     336             :                   "Exchange DB commit failed, rolling back transaction\n");
     337           0 :       TALER_ARL_adb->rollback (TALER_ARL_adb->cls);
     338             :     }
     339             :     else
     340             :     {
     341         266 :       qs = TALER_ARL_adb->commit (TALER_ARL_adb->cls);
     342         266 :       if (0 > qs)
     343             :       {
     344           0 :         GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
     345           0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     346             :                     "Auditor DB commit failed!\n");
     347             :       }
     348             :     }
     349             :   }
     350             :   else
     351             :   {
     352          66 :     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     353             :                 "Processing failed (or no changes), rolling back transaction\n");
     354          66 :     TALER_ARL_adb->rollback (TALER_ARL_adb->cls);
     355          66 :     TALER_ARL_edb->rollback (TALER_ARL_edb->cls);
     356             :   }
     357         332 :   switch (qs)
     358             :   {
     359           0 :   case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
     360           0 :     return GNUNET_OK;
     361         332 :   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
     362         332 :     return GNUNET_OK;
     363           0 :   case GNUNET_DB_STATUS_SOFT_ERROR:
     364           0 :     return GNUNET_NO;
     365           0 :   case GNUNET_DB_STATUS_HARD_ERROR:
     366           0 :     return GNUNET_SYSERR;
     367             :   }
     368           0 :   return GNUNET_OK;
     369             : }
     370             : 
     371             : 
     372             : /**
     373             :  * Initialize DB sessions and run the analysis.
     374             :  *
     375             :  * @param ana analysis to run
     376             :  * @param ana_cls closure for @a ana
     377             :  * @return #GNUNET_OK on success
     378             :  */
     379             : int
     380         332 : TALER_ARL_setup_sessions_and_run (TALER_ARL_Analysis ana,
     381             :                                   void *ana_cls)
     382             : {
     383         332 :   if (GNUNET_SYSERR ==
     384         332 :       TALER_ARL_edb->preflight (TALER_ARL_edb->cls))
     385             :   {
     386           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     387             :                 "Failed to initialize exchange connection.\n");
     388           0 :     return GNUNET_SYSERR;
     389             :   }
     390         332 :   if (GNUNET_SYSERR ==
     391         332 :       TALER_ARL_adb->preflight (TALER_ARL_adb->cls))
     392             :   {
     393           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     394             :                 "Failed to initialize auditor session.\n");
     395           0 :     return GNUNET_SYSERR;
     396             :   }
     397             : 
     398         332 :   if (0 > transact (ana,
     399             :                     ana_cls))
     400           0 :     return GNUNET_SYSERR;
     401         332 :   return GNUNET_OK;
     402             : }
     403             : 
     404             : 
     405             : /**
     406             :  * Test if the given @a mpub matches the #TALER_ARL_master_pub.
     407             :  * If so, set "found" to GNUNET_YES.
     408             :  *
     409             :  * @param cls a `int *` pointing to "found"
     410             :  * @param mpub exchange master public key to compare
     411             :  * @param exchange_url URL of the exchange (ignored)
     412             :  */
     413             : static void
     414         415 : test_master_present (void *cls,
     415             :                      const struct TALER_MasterPublicKeyP *mpub,
     416             :                      const char *exchange_url)
     417             : {
     418         415 :   int *found = cls;
     419             : 
     420             :   (void) exchange_url;
     421         415 :   if (0 == GNUNET_memcmp (mpub,
     422             :                           &TALER_ARL_master_pub))
     423         415 :     *found = GNUNET_YES;
     424         415 : }
     425             : 
     426             : 
     427             : /**
     428             :  * Perform addition of amounts.  If the addition fails, logs
     429             :  * a detailed error and calls exit() to terminate the process (!).
     430             :  *
     431             :  * Do not call this function directly, use #TALER_ARL_amount_add().
     432             :  *
     433             :  * @param[out] sum where to store @a a1 + @a a2, set to "invalid" on overflow
     434             :  * @param a1 first amount to add
     435             :  * @param a2 second amount to add
     436             :  * @param filename where is the addition called
     437             :  * @param functionname name of the function where the addition is called
     438             :  * @param line line number of the addition
     439             :  */
     440             : void
     441       20745 : TALER_ARL_amount_add_ (struct TALER_Amount *sum,
     442             :                        const struct TALER_Amount *a1,
     443             :                        const struct TALER_Amount *a2,
     444             :                        const char *filename,
     445             :                        const char *functionname,
     446             :                        unsigned int line)
     447             : {
     448             :   enum TALER_AmountArithmeticResult aar;
     449             :   const char *msg;
     450             :   char *a2s;
     451             : 
     452       20745 :   aar = TALER_amount_add (sum,
     453             :                           a1,
     454             :                           a2);
     455       20745 :   if (aar >= 0)
     456       20745 :     return;
     457           0 :   switch (aar)
     458             :   {
     459           0 :   case TALER_AAR_INVALID_RESULT_OVERFLOW:
     460           0 :     msg =
     461             :       "arithmetic overflow in amount addition (likely the database is corrupt, see manual)";
     462           0 :     break;
     463           0 :   case TALER_AAR_INVALID_NORMALIZATION_FAILED:
     464           0 :     msg =
     465             :       "normalization failed in amount addition (likely the database is corrupt, see manual)";
     466           0 :     break;
     467           0 :   case TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE:
     468           0 :     msg =
     469             :       "incompatible currencies in amount addition (likely bad configuration and auditor code missing a sanity check, see manual)";
     470           0 :     break;
     471           0 :   default:
     472           0 :     GNUNET_assert (0); /* should be impossible */
     473             :   }
     474           0 :   a2s = TALER_amount_to_string (a2);
     475           0 :   fprintf (stderr,
     476             :            "Aborting audit due to fatal error in function %s at %s:%d trying to add %s to %s: %s\n",
     477             :            functionname,
     478             :            filename,
     479             :            line,
     480             :            TALER_amount2s (a1),
     481             :            a2s,
     482             :            msg);
     483           0 :   GNUNET_free (a2s);
     484           0 :   exit (42);
     485             : }
     486             : 
     487             : 
     488             : /**
     489             :  * Perform subtraction of amounts. If the subtraction fails, logs
     490             :  * a detailed error and calls exit() to terminate the process (!).
     491             :  *
     492             :  * Do not call this function directly, use #TALER_ARL_amount_subtract().
     493             :  *
     494             :  * @param[out] diff where to store (@a a1 - @a a2)
     495             :  * @param a1 amount to subtract from
     496             :  * @param a2 amount to subtract
     497             :  * @param filename where is the addition called
     498             :  * @param functionname name of the function where the addition is called
     499             :  * @param line line number of the addition
     500             :  */
     501             : void
     502         394 : TALER_ARL_amount_subtract_ (struct TALER_Amount *diff,
     503             :                             const struct TALER_Amount *a1,
     504             :                             const struct TALER_Amount *a2,
     505             :                             const char *filename,
     506             :                             const char *functionname,
     507             :                             unsigned int line)
     508             : {
     509             :   enum TALER_AmountArithmeticResult aar;
     510             :   const char *msg;
     511             :   char *a2s;
     512             : 
     513         394 :   aar = TALER_amount_subtract (diff,
     514             :                                a1,
     515             :                                a2);
     516         394 :   if (aar >= 0)
     517         394 :     return;
     518           0 :   switch (aar)
     519             :   {
     520           0 :   case TALER_AAR_INVALID_NEGATIVE_RESULT:
     521           0 :     msg =
     522             :       "negative result in amount subtraction (likely the database is corrupt, see manual)";
     523           0 :     break;
     524           0 :   case TALER_AAR_INVALID_NORMALIZATION_FAILED:
     525           0 :     msg =
     526             :       "normalization failed in amount subtraction (likely the database is corrupt, see manual)";
     527           0 :     break;
     528           0 :   case TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE:
     529           0 :     msg =
     530             :       "currencies incompatible in amount subtraction (likely bad configuration and auditor code missing a sanity check, see manual)";
     531           0 :     break;
     532           0 :   default:
     533           0 :     GNUNET_assert (0); /* should be impossible */
     534             :   }
     535           0 :   a2s = TALER_amount_to_string (a2);
     536           0 :   fprintf (stderr,
     537             :            "Aborting audit due to fatal error in function %s at %s:%d trying to subtract %s from %s: %s\n",
     538             :            functionname,
     539             :            filename,
     540             :            line,
     541             :            a2s,
     542             :            TALER_amount2s (a1),
     543             :            msg);
     544           0 :   GNUNET_free (a2s);
     545           0 :   exit (42);
     546             : }
     547             : 
     548             : 
     549             : /**
     550             :  * Perform subtraction of amounts. Negative results should be signalled by the
     551             :  * return value (leaving @a diff set to 'invalid'). If the subtraction fails
     552             :  * for other reasons (currency mismatch, normalization failure), logs a
     553             :  * detailed error and calls exit() to terminate the process (!).
     554             :  *
     555             :  * Do not call this function directly, use #TALER_ARL_amount_subtract_neg().
     556             :  *
     557             :  * @param[out] diff where to store (@a a1 - @a a2)
     558             :  * @param a1 amount to subtract from
     559             :  * @param a2 amount to subtract
     560             :  * @param filename where is the addition called
     561             :  * @param functionname name of the function where the addition is called
     562             :  * @param line line number of the addition
     563             :  * @return #TALER_ARL_SR_INVALID_NEGATIVE if the result was negative (and @a diff is now invalid),
     564             :  *         #TALER_ARL_SR_ZERO if the result was zero,
     565             :  *         #TALER_ARL_SR_POSITIVE if the result is positive
     566             :  */
     567             : enum TALER_ARL_SubtractionResult
     568         877 : TALER_ARL_amount_subtract_neg_ (struct TALER_Amount *diff,
     569             :                                 const struct TALER_Amount *a1,
     570             :                                 const struct TALER_Amount *a2,
     571             :                                 const char *filename,
     572             :                                 const char *functionname,
     573             :                                 unsigned int line)
     574             : {
     575             :   enum TALER_AmountArithmeticResult aar;
     576             :   const char *msg;
     577             :   char *a2s;
     578             : 
     579         877 :   aar = TALER_amount_subtract (diff,
     580             :                                a1,
     581             :                                a2);
     582         877 :   switch (aar)
     583             :   {
     584         699 :   case TALER_AAR_RESULT_POSITIVE:
     585         699 :     return TALER_ARL_SR_POSITIVE;
     586         169 :   case TALER_AAR_RESULT_ZERO:
     587         169 :     return TALER_ARL_SR_ZERO;
     588           9 :   case TALER_AAR_INVALID_NEGATIVE_RESULT:
     589           9 :     return TALER_ARL_SR_INVALID_NEGATIVE;
     590           0 :   case TALER_AAR_INVALID_NORMALIZATION_FAILED:
     591           0 :     msg =
     592             :       "normalization failed in amount subtraction (likely the database is corrupt, see manual)";
     593           0 :     break;
     594           0 :   case TALER_AAR_INVALID_CURRENCIES_INCOMPATIBLE:
     595           0 :     msg =
     596             :       "currencies incompatible in amount subtraction (likely bad configuration and auditor code missing a sanity check, see manual)";
     597           0 :     break;
     598           0 :   default:
     599           0 :     GNUNET_assert (0); /* should be impossible */
     600             :   }
     601           0 :   a2s = TALER_amount_to_string (a2);
     602           0 :   fprintf (stderr,
     603             :            "Aborting audit due to fatal error in function %s at %s:%d trying to subtract %s from %s: %s\n",
     604             :            functionname,
     605             :            filename,
     606             :            line,
     607             :            a2s,
     608             :            TALER_amount2s (a1),
     609             :            msg);
     610           0 :   GNUNET_free (a2s);
     611           0 :   exit (42);
     612             : }
     613             : 
     614             : 
     615             : /**
     616             :  * Signal handler called for signals that should cause us to shutdown.
     617             :  */
     618             : static void
     619           0 : handle_sigint (void)
     620             : {
     621           0 :   abort_flag = true;
     622           0 : }
     623             : 
     624             : 
     625             : /**
     626             :  * Setup global variables based on configuration.
     627             :  *
     628             :  * @param c configuration to use
     629             :  * @return #GNUNET_OK on success
     630             :  */
     631             : int
     632         415 : TALER_ARL_init (const struct GNUNET_CONFIGURATION_Handle *c)
     633             : {
     634         415 :   TALER_ARL_cfg = c;
     635         415 :   start_time = GNUNET_TIME_absolute_get ();
     636             : 
     637         415 :   if (GNUNET_OK !=
     638         415 :       GNUNET_CONFIGURATION_get_value_string (TALER_ARL_cfg,
     639             :                                              "auditor",
     640             :                                              "BASE_URL",
     641             :                                              &TALER_ARL_auditor_url))
     642             :   {
     643           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     644             :                                "auditor",
     645             :                                "BASE_URL");
     646           0 :     return GNUNET_SYSERR;
     647             :   }
     648         415 :   if (GNUNET_YES == GNUNET_is_zero (&TALER_ARL_master_pub))
     649             :   {
     650             :     /* -m option not given, try configuration */
     651             :     char *master_public_key_str;
     652             : 
     653          15 :     if (GNUNET_OK !=
     654          15 :         GNUNET_CONFIGURATION_get_value_string (TALER_ARL_cfg,
     655             :                                                "exchange",
     656             :                                                "MASTER_PUBLIC_KEY",
     657             :                                                &master_public_key_str))
     658             :     {
     659           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     660             :                   "Pass option -m or set MASTER_PUBLIC_KEY in the configuration!\n");
     661           0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     662             :                                  "exchange",
     663             :                                  "MASTER_PUBLIC_KEY");
     664           0 :       return GNUNET_SYSERR;
     665             :     }
     666          15 :     if (GNUNET_OK !=
     667          15 :         GNUNET_CRYPTO_eddsa_public_key_from_string (
     668             :           master_public_key_str,
     669             :           strlen (master_public_key_str),
     670             :           &TALER_ARL_master_pub.eddsa_pub))
     671             :     {
     672           0 :       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     673             :                                  "exchange",
     674             :                                  "MASTER_PUBLIC_KEY",
     675             :                                  "invalid key");
     676           0 :       GNUNET_free (master_public_key_str);
     677           0 :       return GNUNET_SYSERR;
     678             :     }
     679          15 :     GNUNET_free (master_public_key_str);
     680             :   } /* end of -m not given */
     681             : 
     682         415 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     683             :               "Taler auditor running for exchange master public key %s\n",
     684             :               TALER_B2S (&TALER_ARL_master_pub));
     685             : 
     686         415 :   if (GNUNET_YES == GNUNET_is_zero (&TALER_ARL_auditor_pub))
     687             :   {
     688             :     /* try loading private key and deriving public key */
     689             :     char *fn;
     690             : 
     691         415 :     if (GNUNET_OK ==
     692         415 :         GNUNET_CONFIGURATION_get_value_filename (c,
     693             :                                                  "auditor",
     694             :                                                  "AUDITOR_PRIV_FILE",
     695             :                                                  &fn))
     696             :     {
     697             :       struct TALER_AuditorPrivateKeyP auditor_priv;
     698             : 
     699         415 :       if (GNUNET_OK ==
     700         415 :           GNUNET_CRYPTO_eddsa_key_from_file (fn,
     701             :                                              GNUNET_NO, /* do NOT create it! */
     702             :                                              &auditor_priv.eddsa_priv))
     703             :       {
     704         415 :         GNUNET_CRYPTO_eddsa_key_get_public (&auditor_priv.eddsa_priv,
     705             :                                             &TALER_ARL_auditor_pub.eddsa_pub);
     706             :       }
     707         415 :       GNUNET_free (fn);
     708             :     }
     709             :   }
     710             : 
     711         415 :   if (GNUNET_YES == GNUNET_is_zero (&TALER_ARL_auditor_pub))
     712             :   {
     713             :     /* private key not available, try configuration for public key */
     714             :     char *auditor_public_key_str;
     715             : 
     716           0 :     if (GNUNET_OK !=
     717           0 :         GNUNET_CONFIGURATION_get_value_string (c,
     718             :                                                "auditor",
     719             :                                                "PUBLIC_KEY",
     720             :                                                &auditor_public_key_str))
     721             :     {
     722           0 :       GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     723             :                                  "auditor",
     724             :                                  "PUBLIC_KEY");
     725           0 :       return GNUNET_SYSERR;
     726             :     }
     727           0 :     if (GNUNET_OK !=
     728           0 :         GNUNET_CRYPTO_eddsa_public_key_from_string (
     729             :           auditor_public_key_str,
     730             :           strlen (auditor_public_key_str),
     731             :           &TALER_ARL_auditor_pub.eddsa_pub))
     732             :     {
     733           0 :       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     734             :                                  "auditor",
     735             :                                  "PUBLIC_KEY",
     736             :                                  "invalid key");
     737           0 :       GNUNET_free (auditor_public_key_str);
     738           0 :       return GNUNET_SYSERR;
     739             :     }
     740           0 :     GNUNET_free (auditor_public_key_str);
     741             :   }
     742             : 
     743         415 :   if (GNUNET_OK !=
     744         415 :       TALER_config_get_currency (TALER_ARL_cfg,
     745             :                                  &TALER_ARL_currency))
     746             :   {
     747           0 :     return GNUNET_SYSERR;
     748             :   }
     749             :   {
     750         415 :     if ( (GNUNET_OK !=
     751         415 :           TALER_config_get_amount (TALER_ARL_cfg,
     752             :                                    "taler",
     753             :                                    "CURRENCY_ROUND_UNIT",
     754         415 :                                    &TALER_ARL_currency_round_unit)) ||
     755         415 :          ( (0 != TALER_ARL_currency_round_unit.fraction) &&
     756         415 :            (0 != TALER_ARL_currency_round_unit.value) ) )
     757             :     {
     758           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     759             :                   "Need non-zero value in section `TALER' under `CURRENCY_ROUND_UNIT'\n");
     760           0 :       return GNUNET_SYSERR;
     761             :     }
     762             :   }
     763         415 :   sig_int = GNUNET_SIGNAL_handler_install (SIGINT,
     764             :                                            &handle_sigint);
     765         415 :   if (NULL == sig_int)
     766             :   {
     767           0 :     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
     768             :                          "signal");
     769           0 :     TALER_ARL_done (NULL);
     770           0 :     return GNUNET_SYSERR;
     771             :   }
     772         415 :   sig_term = GNUNET_SIGNAL_handler_install (SIGTERM,
     773             :                                             &handle_sigint);
     774         415 :   if (NULL == sig_term)
     775             :   {
     776           0 :     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
     777             :                          "signal");
     778           0 :     TALER_ARL_done (NULL);
     779           0 :     return GNUNET_SYSERR;
     780             :   }
     781         415 :   if (NULL ==
     782         415 :       (TALER_ARL_edb = TALER_EXCHANGEDB_plugin_load (TALER_ARL_cfg)))
     783             :   {
     784           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     785             :                 "Failed to initialize exchange database plugin.\n");
     786           0 :     TALER_ARL_done (NULL);
     787           0 :     return GNUNET_SYSERR;
     788             :   }
     789         415 :   if (NULL ==
     790         415 :       (TALER_ARL_adb = TALER_AUDITORDB_plugin_load (TALER_ARL_cfg)))
     791             :   {
     792           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     793             :                 "Failed to initialize auditor database plugin.\n");
     794           0 :     TALER_ARL_done (NULL);
     795           0 :     return GNUNET_SYSERR;
     796             :   }
     797             :   {
     798             :     int found;
     799             : 
     800         415 :     if (GNUNET_SYSERR ==
     801         415 :         TALER_ARL_adb->preflight (TALER_ARL_adb->cls))
     802             :     {
     803           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     804             :                   "Failed to start session with auditor database.\n");
     805           0 :       TALER_ARL_done (NULL);
     806           0 :       return GNUNET_SYSERR;
     807             :     }
     808         415 :     found = GNUNET_NO;
     809         415 :     (void) TALER_ARL_adb->list_exchanges (TALER_ARL_adb->cls,
     810             :                                           &test_master_present,
     811             :                                           &found);
     812         415 :     if (GNUNET_NO == found)
     813             :     {
     814           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     815             :                   "Exchange's master public key `%s' not known to auditor DB. Did you forget to run `taler-auditor-exchange`?\n",
     816             :                   GNUNET_p2s (&TALER_ARL_master_pub.eddsa_pub));
     817           0 :       TALER_ARL_done (NULL);
     818           0 :       return GNUNET_SYSERR;
     819             :     }
     820             :   }
     821         415 :   return GNUNET_OK;
     822             : }
     823             : 
     824             : 
     825             : /**
     826             :  * Generate the report and close connectios to the database.
     827             :  *
     828             :  * @param report the report to output, may be NULL for no report
     829             :  */
     830             : void
     831         415 : TALER_ARL_done (json_t *report)
     832             : {
     833         415 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     834             :               "Audit complete\n");
     835         415 :   if (NULL != sig_int)
     836             :   {
     837         415 :     GNUNET_SIGNAL_handler_uninstall (sig_int);
     838         415 :     sig_int = NULL;
     839             :   }
     840         415 :   if (NULL != sig_term)
     841             :   {
     842         415 :     GNUNET_SIGNAL_handler_uninstall (sig_term);
     843         415 :     sig_term = NULL;
     844             :   }
     845         415 :   if (NULL != TALER_ARL_adb)
     846             :   {
     847         415 :     TALER_AUDITORDB_plugin_unload (TALER_ARL_adb);
     848         415 :     TALER_ARL_adb = NULL;
     849             :   }
     850         415 :   if (NULL != TALER_ARL_edb)
     851             :   {
     852         415 :     TALER_EXCHANGEDB_plugin_unload (TALER_ARL_edb);
     853         415 :     TALER_ARL_edb = NULL;
     854             :   }
     855         415 :   if (NULL != report)
     856             :   {
     857         415 :     json_dumpf (report,
     858             :                 stdout,
     859             :                 JSON_INDENT (2));
     860         415 :     json_decref (report);
     861             :   }
     862         415 :   GNUNET_free (TALER_ARL_auditor_url);
     863         415 : }
     864             : 
     865             : 
     866             : /* end of report-lib.c */

Generated by: LCOV version 1.14