src/sync_actions.c
author Edouard Tisserant <edouard@pep-project.org>
Fri, 09 Jun 2017 15:11:11 +0200
changeset 1844 415b5ea8bfd1
parent 1723 c93e1ddf1059
child 2287 026ab4dae779
permissions -rw-r--r--
Tests : use $HOME to sandbox test`s management DB and keyrings
     1 // This file is under GNU General Public License 3.0
     2 // see LICENSE.txt
     3 
     4 // Actions for DeviceState state machine
     5 
     6 #include <assert.h>
     7 #include "pEp_internal.h"
     8 #include "message.h"
     9 #include "sync_fsm.h"
    10 #include "sync_impl.h"
    11 #include "map_asn1.h"
    12 #include "baseprotocol.h"
    13 
    14 // conditions
    15 
    16 int deviceGrouped(PEP_SESSION session)
    17 {
    18     assert(session);
    19     if (!session)
    20         return invalid_condition; // error
    21 
    22     char *devgrp = NULL;
    23     int res = 0;
    24     PEP_STATUS status;
    25 
    26     status = get_device_group(session, &devgrp);
    27 
    28     if (status == PEP_STATUS_OK && devgrp && devgrp[0])
    29         res = 1;
    30 
    31     free(devgrp);
    32 
    33     return res;
    34 }
    35 
    36 int keyElectionWon(PEP_SESSION session, Identity partner)
    37 {
    38     assert(session);
    39     assert(partner);
    40     if (!(session && partner))
    41         return invalid_condition; // error
    42 
    43     int partner_is_group = partner->flags & PEP_idf_devicegroup;
    44 
    45     if (deviceGrouped(session)){
    46         // existing group always wins against sole device
    47         if(!partner_is_group)
    48             return 1;
    49     } else {
    50         // sole device always loses against group
    51         if(partner_is_group)
    52             return 0;
    53     }
    54 
    55     // two groups or two sole are elected based on key age
    56     // key created first wins
    57 
    58     Identity me = NULL;
    59     PEP_STATUS status = get_identity(session, partner->address, PEP_OWN_USERID,
    60             &me);
    61     if (status == PEP_OUT_OF_MEMORY)
    62         return invalid_out_of_memory;
    63     if (status != PEP_STATUS_OK)
    64         return invalid_condition; // error
    65 
    66     int result = invalid_condition; // error state has to be overwritten
    67 
    68     time_t own_created;
    69     time_t partners_created;
    70 
    71     status = key_created(session, me->fpr, &own_created);
    72     if (status != PEP_STATUS_OK)
    73         goto the_end;
    74 
    75     status = key_created(session, partner->fpr, &partners_created);
    76     if (status != PEP_STATUS_OK)
    77         goto the_end;
    78 
    79     if (own_created > partners_created)
    80         result = 0;
    81     else
    82         result = 1;
    83 
    84 the_end:
    85     free_identity(me);
    86     return result;
    87 }
    88 
    89 int sameIdentities(PEP_SESSION session, Identity a, Identity b)
    90 {
    91     assert(session);
    92     assert(a);
    93     assert(b);
    94 
    95     if (!(session && a && b))
    96         return invalid_condition; // error
    97 
    98     if (a->fpr == NULL || b->fpr == NULL ||
    99         (!_same_fpr(a->fpr, strlen(a->fpr), b->fpr, strlen(b->fpr))) ||
   100         a->address == NULL || b->address == NULL ||
   101         strcmp(a->address, b->address) != 0 ||
   102         a->user_id == NULL || b->user_id == NULL ||
   103         strcmp(a->user_id, b->user_id) != 0)
   104             return 0;
   105     return 1;
   106 }
   107 
   108 int sameKeyAndAddress(PEP_SESSION session, Identity a, Identity b)
   109 {
   110     assert(session);
   111     assert(a);
   112     assert(b);
   113 
   114     if (!(session && a && b))
   115         return invalid_condition; // error
   116 
   117     if (a->fpr == NULL || b->fpr == NULL ||
   118         (!_same_fpr(a->fpr, strlen(a->fpr), b->fpr, strlen(b->fpr))) ||
   119         a->address == NULL || b->address == NULL ||
   120         strcmp(a->address, b->address) != 0)
   121             return 0;
   122     return 1;
   123 }
   124 
   125 // actions
   126 
   127 PEP_STATUS _notifyHandshake(
   128         PEP_SESSION session,
   129         Identity partner,
   130         sync_handshake_signal signal
   131     )
   132 {
   133     PEP_STATUS status = PEP_STATUS_OK;
   134 
   135     assert(session);
   136     assert(partner);
   137 
   138     if (!(session && partner))
   139         return PEP_ILLEGAL_VALUE;
   140 
   141     assert(session->notifyHandshake);
   142     if (!session->notifyHandshake)
   143         return PEP_SYNC_NO_NOTIFY_CALLBACK;
   144 
   145     // notifyHandshake take ownership of given identities
   146     pEp_identity *me = NULL;
   147     status = get_identity(session, partner->address, PEP_OWN_USERID, &me);
   148     if (status != PEP_STATUS_OK)
   149         goto error;
   150     
   151     pEp_identity *_partner = NULL;
   152     _partner = identity_dup(partner);
   153     if (_partner == NULL){
   154         status = PEP_OUT_OF_MEMORY;
   155         goto error;
   156     }
   157 
   158     status = session->notifyHandshake(session->sync_obj, me, _partner, signal);
   159     if (status != PEP_STATUS_OK)
   160         goto error;
   161 
   162     return status;
   163 
   164 error:
   165     free_identity(me);
   166     return status;
   167 }
   168 
   169 // acceptHandshake() - stores acception of partner
   170 //
   171 //  params:
   172 //      session (in)        session handle
   173 //      state (in)          state the state machine is in
   174 //      partner (in)        partner to communicate with
   175 //
   176 //  returns:
   177 //      PEP_STATUS_OK or any other value on error
   178 
   179 PEP_STATUS acceptHandshake(
   180         PEP_SESSION session,
   181         DeviceState_state state,
   182         Identity partner,
   183         void *extra
   184     )
   185 {
   186     PEP_STATUS status = PEP_STATUS_OK;
   187 
   188     assert(session);
   189     assert(partner);
   190     assert(extra == NULL);
   191     if (!(session && partner))
   192         return PEP_ILLEGAL_VALUE;
   193 
   194     status = trust_personal_key(session, partner);
   195 
   196     return status;
   197 }
   198 
   199 
   200 // rejectHandshake() - stores rejection of partner
   201 //
   202 //  params:
   203 //      session (in)        session handle
   204 //      state (in)          state the state machine is in
   205 //      partner (in)        partner to communicate with
   206 //
   207 //  returns:
   208 //      PEP_STATUS_OK or any other value on error
   209 
   210 PEP_STATUS rejectHandshake(
   211         PEP_SESSION session,
   212         DeviceState_state state,
   213         Identity partner,
   214         void *extra
   215     )
   216 {
   217     PEP_STATUS status = PEP_STATUS_OK;
   218 
   219     assert(session);
   220     assert(partner);
   221     assert(extra == NULL);
   222     if (!(session && partner))
   223         return PEP_ILLEGAL_VALUE;
   224 
   225     // TODO : disable sync globally if not in a group
   226     status = set_identity_flags(session, partner,
   227             partner->flags | PEP_idf_not_for_sync);
   228 
   229     return status;
   230 }
   231 
   232 PEP_STATUS _storeGroupKeys(
   233         PEP_SESSION session,
   234         identity_list *group_keys
   235     )
   236 {
   237     PEP_STATUS status = PEP_STATUS_OK;
   238 
   239     for (identity_list *il = group_keys; il && il->ident; il = il->next) {
   240 
   241         if (strcmp(il->ident->user_id, PEP_OWN_USERID)!=0) {
   242             assert(0);
   243             continue;
   244         }
   245         // Check that identity isn't excluded from sync.
   246         pEp_identity *stored_identity = NULL;
   247         status = get_identity(session, il->ident->address, PEP_OWN_USERID,
   248                 &stored_identity);
   249         if (status == PEP_STATUS_OK) {
   250             if(stored_identity->flags & PEP_idf_not_for_sync){
   251                 free_identity(stored_identity);
   252                 continue;
   253             }
   254             free_identity(stored_identity);
   255         }
   256 
   257         status = set_identity(session, il->ident);
   258         if (status != PEP_STATUS_OK)
   259             break;
   260     }
   261 
   262     return status;
   263 }
   264     
   265 
   266 // storeGroupKeys() - 
   267 //
   268 //  params:
   269 //      session (in)        session handle
   270 //      state (in)          state the state machine is in
   271 //      partner (in)        partner to communicate with
   272 //      _group_keys (in)    group keys received from partner
   273 //
   274 //  returns:
   275 //      PEP_STATUS_OK or any other value on error
   276 
   277 PEP_STATUS storeGroupKeys(
   278         PEP_SESSION session,
   279         DeviceState_state state,
   280         Identity partner,
   281         void *group_keys_extra_
   282     )
   283 {
   284     PEP_STATUS status = PEP_STATUS_OK;
   285 
   286     assert(session);
   287     assert(partner);
   288     assert(group_keys_extra_);
   289     if (!(session && partner && group_keys_extra_))
   290         return PEP_ILLEGAL_VALUE;
   291 
   292     group_keys_extra_t *group_keys_extra = 
   293         (group_keys_extra_t*) group_keys_extra_;
   294     identity_list *group_keys = group_keys_extra->group_keys;
   295     char *group_id = group_keys_extra->group_id;
   296 
   297     status = _storeGroupKeys(session, group_keys);
   298     if (status != PEP_STATUS_OK)
   299         return status;
   300 
   301     // set group id according to given group-id
   302     status = set_device_group(session, group_id);
   303     if (status != PEP_STATUS_OK)
   304         return status;
   305     
   306     return status;
   307 }
   308 
   309 // storeGroupUpdate() - 
   310 //
   311 //  params:
   312 //      session (in)        session handle
   313 //      state (in)          state the state machine is in
   314 //      partner (in)        partner to communicate with
   315 //      _group_keys (in)    group keys received from partner
   316 //
   317 //  returns:
   318 //      PEP_STATUS_OK or any other value on error
   319 
   320 PEP_STATUS storeGroupUpdate(
   321         PEP_SESSION session,
   322         DeviceState_state state,
   323         Identity partner,
   324         void *group_keys_
   325     )
   326 {
   327     PEP_STATUS status = PEP_STATUS_OK;
   328 
   329     assert(session);
   330     assert(partner);
   331     assert(group_keys_);
   332     if (!(session && partner && group_keys_))
   333         return PEP_ILLEGAL_VALUE;
   334 
   335     identity_list *group_keys = (identity_list*) group_keys_;
   336 
   337     status = _storeGroupKeys(session, group_keys);
   338 
   339 
   340     return status;
   341 }
   342 
   343 // makeGroup() - 
   344 //
   345 //  params:
   346 //      session (in)        session handle
   347 //      state (in)          state the state machine is in
   348 //      partner (in)        ignored
   349 //      extra (in)          ignored
   350 //
   351 //  returns:
   352 //      PEP_STATUS_OK or any other value on error
   353 
   354 PEP_STATUS makeGroup(
   355         PEP_SESSION session,
   356         DeviceState_state state,
   357         Identity partner,
   358         void *extra
   359     )
   360 {
   361     PEP_STATUS status = PEP_STATUS_OK;
   362 
   363     assert(session);
   364    
   365     // make a new uuid 
   366     char new_uuid[37];
   367     pEpUUID uuid;
   368     uuid_generate_random(uuid);
   369     uuid_unparse_upper(uuid, new_uuid);
   370 
   371     // take that new uuid as group-id
   372     status = set_device_group(session, new_uuid);
   373 
   374     return status;
   375 }
   376 
   377 // renewUUID() - 
   378 //
   379 //  params:
   380 //      session (in)        session handle
   381 //      state (in)          state the state machine is in
   382 //      partner (in)        ignored
   383 //      extra (in)          ignored
   384 //
   385 //  returns:
   386 //      PEP_STATUS_OK or any other value on error
   387 
   388 PEP_STATUS renewUUID(
   389         PEP_SESSION session,
   390         DeviceState_state state,
   391         Identity partner,
   392         void *extra
   393     )
   394 {
   395     PEP_STATUS status = PEP_STATUS_OK;
   396 
   397     assert(session);
   398 
   399     // change sync_uuid when entering group 
   400     // thus ignoring unprocessed handshakes
   401     // addressed to previous self (sole) once in.
   402     pEpUUID uuid;
   403     uuid_generate_random(uuid);
   404     uuid_unparse_upper(uuid, session->sync_uuid);
   405     
   406     return status;
   407 }
   408 
   409 // leaveGroup() - 
   410 //
   411 //  params:
   412 //      session (in)        session handle
   413 //      state (in)          state the state machine is in
   414 //      partner (in)        ignored
   415 //      extra (in)          ignored
   416 //
   417 //  returns:
   418 //      PEP_STATUS_OK or any other value on error
   419 
   420 PEP_STATUS leaveGroup(
   421         PEP_SESSION session,
   422         DeviceState_state state,
   423         Identity partner,
   424         void *extra
   425     )
   426 {
   427     PEP_STATUS status = PEP_STATUS_OK;
   428 
   429     assert(session);
   430 
   431     status = set_device_group(session, NULL);
   432     
   433     return status;
   434 }