anastasis

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

anastasis_api_providers.c (7855B)


      1 /*
      2   This file is part of Anastasis
      3   Copyright (C) 2020, 2021, 2022 Anastasis SARL
      4 
      5   Anastasis is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU 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 General Public License for more details.
     12 
     13   You should have received a copy of the GNU General Public License along with
     14   Anastasis; see the file COPYING.GPL.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file reducer/anastasis_api_providers.c
     18  * @brief anastasis provider synchronization logic
     19  * @author Christian Grothoff
     20  */
     21 
     22 #include <platform.h>
     23 #include <jansson.h>
     24 #include "anastasis_redux.h"
     25 #include "anastasis_error_codes.h"
     26 #include "anastasis_api_redux.h"
     27 #include "anastasis_api_redux_state.h"
     28 
     29 
     30 /**
     31  * Main data structure for sync_providers().
     32  */
     33 struct MasterSync;
     34 
     35 
     36 /**
     37  * Data structure for one provider we are syncing /config with.
     38  */
     39 struct SyncEntry
     40 {
     41   /**
     42    * Kept in a DLL.
     43    */
     44   struct SyncEntry *next;
     45 
     46   /**
     47    * Kept in a DLL.
     48    */
     49   struct SyncEntry *prev;
     50 
     51   /**
     52    * Sync operation we are part of.
     53    */
     54   struct MasterSync *ms;
     55 
     56   /**
     57    * Redux action for this provider.
     58    */
     59   struct ANASTASIS_ReduxAction *ra;
     60 };
     61 
     62 
     63 /**
     64  * Main data structure for sync_providers().
     65  */
     66 struct MasterSync
     67 {
     68   /**
     69    * Our own sync action we expose externally.
     70    */
     71   struct ANASTASIS_ReduxAction ra;
     72   /**
     73    * Head of DLL with entries per provider.
     74    */
     75   struct SyncEntry *se_head;
     76   /**
     77    * Tail of DLL with entries per provider.
     78    */
     79   struct SyncEntry *se_tail;
     80 
     81   /**
     82    * Function to call with the result.
     83    */
     84   ANASTASIS_ActionCallback cb;
     85 
     86   /**
     87    * Closure for @e cb.
     88    */
     89   void *cb_cls;
     90 
     91   /**
     92    * State all our entries share.  We own it until the first entry
     93    * reports back, at which point it is handed to @e cb.
     94    */
     95   struct ANASTASIS_ReduxState *rs;
     96 
     97 };
     98 
     99 
    100 /**
    101  * Free @a cls data structure.
    102  *
    103  * @param[in] cls data structure to free, must be a `struct MasterSync *`
    104  */
    105 static void
    106 clean_sync (void *cls)
    107 {
    108   struct MasterSync *ms = cls;
    109   struct SyncEntry *se;
    110 
    111   while (NULL != (se = ms->se_head))
    112   {
    113     GNUNET_CONTAINER_DLL_remove (ms->se_head,
    114                                  ms->se_tail,
    115                                  se);
    116     se->ra->cleanup (se->ra->cleanup_cls);
    117     GNUNET_free (se);
    118   }
    119   ANASTASIS_REDUX_state_free_ (ms->rs);
    120   GNUNET_free (ms);
    121 }
    122 
    123 
    124 /**
    125  * Function called when we have made progress on any of the
    126  * providers we are trying to sync with.  The first one to report wins:
    127  * we return its result and drop the rest.
    128  *
    129  * @param cls closure
    130  * @param error error code, #TALER_EC_NONE if the state is the new successful state
    131  * @param[in] rs the state, updated for the provider that reported
    132  */
    133 static void
    134 sync_progress (void *cls,
    135                enum TALER_ErrorCode error,
    136                struct ANASTASIS_ReduxState *rs)
    137 {
    138   struct SyncEntry *se = cls;
    139   struct MasterSync *ms = se->ms;
    140   ANASTASIS_ActionCallback cb = ms->cb;
    141   void *cb_cls = ms->cb_cls;
    142 
    143   GNUNET_assert (rs == ms->rs);
    144   GNUNET_CONTAINER_DLL_remove (ms->se_head,
    145                                ms->se_tail,
    146                                se);
    147   GNUNET_free (se);
    148   /* The remaining entries are cancelled below; none of them touches the
    149      state once it has been unlinked, so handing it over here is safe. */
    150   ms->rs = NULL;
    151   clean_sync (ms);
    152   ANASTASIS_REDUX_return_ (rs,
    153                            cb,
    154                            cb_cls,
    155                            error);
    156 }
    157 
    158 
    159 struct ANASTASIS_ReduxAction *
    160 ANASTASIS_REDUX_sync_providers_ (struct ANASTASIS_ReduxState *rs,
    161                                  const json_t *arguments,
    162                                  ANASTASIS_ActionCallback cb,
    163                                  void *cb_cls)
    164 {
    165   const struct ANASTASIS_RecoveryInformation *ri;
    166   struct MasterSync *ms;
    167 
    168   if (NULL == rs->details.recovery.r)
    169   {
    170     GNUNET_break (0);
    171     ANASTASIS_REDUX_fail_ (rs,
    172                            cb,
    173                            cb_cls,
    174                            TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
    175                            "'recovery_document' missing");
    176     return NULL;
    177   }
    178   ri = ANASTASIS_recovery_get_info (rs->details.recovery.r);
    179   ms = GNUNET_new (struct MasterSync);
    180   ms->cb = cb;
    181   ms->cb_cls = cb_cls;
    182   ms->rs = rs;
    183   for (unsigned int i = 0; i < ri->cs_len; i++)
    184   {
    185     const struct ANASTASIS_ChallengeDetails *cd;
    186     struct ANASTASIS_CRYPTO_ProviderSaltP provider_salt;
    187     struct SyncEntry *se;
    188 
    189     cd = ANASTASIS_challenge_get_details (ri->cs[i]);
    190     if (GNUNET_OK ==
    191         ANASTASIS_REDUX_lookup_salt_ (&rs->common,
    192                                       cd->provider_url,
    193                                       &provider_salt))
    194       continue; /* provider already ready */
    195     se = GNUNET_new (struct SyncEntry);
    196     se->ms = ms;
    197     GNUNET_CONTAINER_DLL_insert (ms->se_head,
    198                                  ms->se_tail,
    199                                  se);
    200     se->ra = ANASTASIS_REDUX_add_provider_to_state_ (cd->provider_url,
    201                                                      rs,
    202                                                      &sync_progress,
    203                                                      se);
    204   }
    205   if (NULL == ms->se_head)
    206   {
    207     /* everything already synced */
    208     ms->rs = NULL;
    209     clean_sync (ms);
    210     ANASTASIS_REDUX_fail_ (rs,
    211                            cb,
    212                            cb_cls,
    213                            TALER_EC_ANASTASIS_REDUCER_PROVIDERS_ALREADY_SYNCED,
    214                            "already in sync");
    215     return NULL;
    216   }
    217   ms->ra.cleanup = &clean_sync;
    218   ms->ra.cleanup_cls = ms;
    219   return &ms->ra;
    220 }
    221 
    222 
    223 struct ANASTASIS_ReduxAction *
    224 ANASTASIS_REDUX_poll_providers_ (struct ANASTASIS_ReduxState *rs,
    225                                  const json_t *arguments,
    226                                  ANASTASIS_ActionCallback cb,
    227                                  void *cb_cls)
    228 {
    229   struct MasterSync *ms;
    230 
    231   if (! rs->common.have_providers)
    232   {
    233     GNUNET_break (0);
    234     ANASTASIS_REDUX_fail_ (rs,
    235                            cb,
    236                            cb_cls,
    237                            TALER_EC_ANASTASIS_REDUCER_STATE_INVALID,
    238                            "'authentication_providers' missing");
    239     return NULL;
    240   }
    241   ms = GNUNET_new (struct MasterSync);
    242   ms->cb = cb;
    243   ms->cb_cls = cb_cls;
    244   ms->rs = rs;
    245   for (unsigned int i = 0; i < rs->common.providers_len; i++)
    246   {
    247     const char *url = rs->common.providers[i].url.url;
    248     struct ANASTASIS_CRYPTO_ProviderSaltP provider_salt;
    249     struct SyncEntry *se;
    250 
    251     if (GNUNET_OK ==
    252         ANASTASIS_REDUX_lookup_salt_ (&rs->common,
    253                                       url,
    254                                       &provider_salt))
    255       continue;
    256     se = GNUNET_new (struct SyncEntry);
    257     se->ms = ms;
    258     GNUNET_CONTAINER_DLL_insert (ms->se_head,
    259                                  ms->se_tail,
    260                                  se);
    261     se->ra = ANASTASIS_REDUX_add_provider_to_state_ (url,
    262                                                      rs,
    263                                                      &sync_progress,
    264                                                      se);
    265   }
    266   if (NULL == ms->se_head)
    267   {
    268     /* everything already synced */
    269     ms->rs = NULL;
    270     clean_sync (ms);
    271     ANASTASIS_REDUX_fail_ (rs,
    272                            cb,
    273                            cb_cls,
    274                            TALER_EC_ANASTASIS_REDUCER_ACTION_INVALID,
    275                            "already in sync");
    276     return NULL;
    277   }
    278   ms->ra.cleanup = &clean_sync;
    279   ms->ra.cleanup_cls = ms;
    280   return &ms->ra;
    281 }