src/sync_actions.c
author Krista Bennett <krista@pep-project.org>
Fri, 04 May 2018 16:30:21 +0200
branchlocal_cpptest
changeset 2652 43b913f99a27
parent 2462 48b526a0daac
child 2829 e444c3c960bb
permissions -rw-r--r--
Shelving broken things to break other things
     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     
    60     char* own_id = NULL;
    61     PEP_STATUS status = get_default_own_userid(session, &own_id);
    62     if (own_id) {
    63         status = get_identity(session, partner->address, own_id,
    64                               &me);
    65         free(own_id);
    66     }
    67     if (status == PEP_OUT_OF_MEMORY)
    68         return invalid_out_of_memory;
    69     if (status != PEP_STATUS_OK)
    70         return invalid_condition; // error
    71 
    72     int result = invalid_condition; // error state has to be overwritten
    73 
    74     time_t own_created;
    75     time_t partners_created;
    76 
    77     status = key_created(session, me->fpr, &own_created);
    78     if (status != PEP_STATUS_OK)
    79         goto the_end;
    80 
    81     status = key_created(session, partner->fpr, &partners_created);
    82     if (status != PEP_STATUS_OK)
    83         goto the_end;
    84 
    85     if (own_created > partners_created)
    86         result = 0;
    87     else
    88         result = 1;
    89 
    90 the_end:
    91     free_identity(me);
    92     return result;
    93 }
    94 
    95 int sameIdentities(PEP_SESSION session, Identity a, Identity b)
    96 {
    97     assert(session);
    98     assert(a);
    99     assert(b);
   100 
   101     if (!(session && a && b))
   102         return invalid_condition; // error
   103 
   104     if (a->fpr == NULL || b->fpr == NULL ||
   105         (!_same_fpr(a->fpr, strlen(a->fpr), b->fpr, strlen(b->fpr))) ||
   106         a->address == NULL || b->address == NULL ||
   107         strcmp(a->address, b->address) != 0 ||
   108         a->user_id == NULL || b->user_id == NULL ||
   109         strcmp(a->user_id, b->user_id) != 0)
   110             return 0;
   111     return 1;
   112 }
   113 
   114 int sameKeyAndAddress(PEP_SESSION session, Identity a, Identity b)
   115 {
   116     assert(session);
   117     assert(a);
   118     assert(b);
   119 
   120     if (!(session && a && b))
   121         return invalid_condition; // error
   122 
   123     if (a->fpr == NULL || b->fpr == NULL ||
   124         (!_same_fpr(a->fpr, strlen(a->fpr), b->fpr, strlen(b->fpr))) ||
   125         a->address == NULL || b->address == NULL ||
   126         strcmp(a->address, b->address) != 0)
   127             return 0;
   128     return 1;
   129 }
   130 
   131 // actions
   132 
   133 PEP_STATUS _notifyHandshake(
   134         PEP_SESSION session,
   135         Identity partner,
   136         sync_handshake_signal signal
   137     )
   138 {
   139     PEP_STATUS status = PEP_STATUS_OK;
   140 
   141     assert(session);
   142     assert(partner);
   143 
   144     if (!(session && partner))
   145         return PEP_ILLEGAL_VALUE;
   146 
   147     assert(session->notifyHandshake);
   148     if (!session->notifyHandshake)
   149         return PEP_SYNC_NO_NOTIFY_CALLBACK;
   150 
   151     char* own_id = NULL;
   152     status = get_default_own_userid(session, &own_id);
   153         
   154     // notifyHandshake take ownership of given identities
   155     pEp_identity *me = NULL;
   156     if (own_id) {
   157         status = get_identity(session, partner->address, own_id, &me);
   158         free(own_id);
   159     }
   160     if (status != PEP_STATUS_OK)
   161         goto error;
   162     
   163     pEp_identity *_partner = NULL;
   164     _partner = identity_dup(partner);
   165     if (_partner == NULL){
   166         status = PEP_OUT_OF_MEMORY;
   167         goto error;
   168     }
   169 
   170     status = session->notifyHandshake(session->sync_obj, me, _partner, signal);
   171     if (status != PEP_STATUS_OK)
   172         goto error;
   173 
   174     return status;
   175 
   176 error:
   177     free_identity(me);
   178     return status;
   179 }
   180 
   181 // acceptHandshake() - stores acception of partner
   182 //
   183 //  params:
   184 //      session (in)        session handle
   185 //      state (in)          state the state machine is in
   186 //      partner (in)        partner to communicate with
   187 //
   188 //  returns:
   189 //      PEP_STATUS_OK or any other value on error
   190 
   191 PEP_STATUS acceptHandshake(
   192         PEP_SESSION session,
   193         DeviceState_state state,
   194         Identity partner,
   195         void *extra
   196     )
   197 {
   198     PEP_STATUS status = PEP_STATUS_OK;
   199 
   200     assert(session);
   201     assert(partner);
   202     assert(extra == NULL);
   203     if (!(session && partner))
   204         return PEP_ILLEGAL_VALUE;
   205 
   206     status = trust_personal_key(session, partner);
   207 
   208     return status;
   209 }
   210 
   211 
   212 // rejectHandshake() - stores rejection of partner
   213 //
   214 //  params:
   215 //      session (in)        session handle
   216 //      state (in)          state the state machine is in
   217 //      partner (in)        partner to communicate with
   218 //
   219 //  returns:
   220 //      PEP_STATUS_OK or any other value on error
   221 
   222 PEP_STATUS rejectHandshake(
   223         PEP_SESSION session,
   224         DeviceState_state state,
   225         Identity partner,
   226         void *extra
   227     )
   228 {
   229     PEP_STATUS status = PEP_STATUS_OK;
   230 
   231     assert(session);
   232     assert(partner);
   233     assert(extra == NULL);
   234     if (!(session && partner))
   235         return PEP_ILLEGAL_VALUE;
   236 
   237     // TODO : disable sync globally if not in a group
   238     status = set_identity_flags(session, partner,
   239             partner->flags | PEP_idf_not_for_sync);
   240 
   241     return status;
   242 }
   243 
   244 PEP_STATUS _storeGroupKeys(
   245         PEP_SESSION session,
   246         identity_list *group_keys
   247     )
   248 {
   249     PEP_STATUS status = PEP_STATUS_OK;
   250     
   251     char* own_id = NULL;
   252     status = get_default_own_userid(session, &own_id);
   253     
   254     // FIXME: Is this where and what we wanna do with this?
   255     if (status != PEP_STATUS_OK)
   256         return status;
   257         
   258     for (identity_list *il = group_keys; il && il->ident; il = il->next) {
   259 
   260         if (strcmp(il->ident->user_id, own_id)!=0) {
   261             assert(0);
   262             continue;
   263         }
   264         // Check that identity isn't excluded from sync.
   265         pEp_identity *stored_identity = NULL;
   266         status = get_identity(session, il->ident->address, own_id,
   267                 &stored_identity);
   268         if (status == PEP_STATUS_OK) {
   269             if(stored_identity->flags & PEP_idf_not_for_sync){
   270                 free_identity(stored_identity);
   271                 continue;
   272             }
   273             free_identity(stored_identity);
   274         }
   275 
   276         status = set_identity(session, il->ident);
   277         if (status != PEP_STATUS_OK)
   278             break;
   279     }
   280     
   281     free(own_id);
   282     return status;
   283 }
   284     
   285 
   286 // storeGroupKeys() - 
   287 //
   288 //  params:
   289 //      session (in)        session handle
   290 //      state (in)          state the state machine is in
   291 //      partner (in)        partner to communicate with
   292 //      _group_keys (in)    group keys received from partner
   293 //
   294 //  returns:
   295 //      PEP_STATUS_OK or any other value on error
   296 
   297 PEP_STATUS storeGroupKeys(
   298         PEP_SESSION session,
   299         DeviceState_state state,
   300         Identity partner,
   301         void *group_keys_extra_
   302     )
   303 {
   304     PEP_STATUS status = PEP_STATUS_OK;
   305 
   306     assert(session);
   307     assert(partner);
   308     assert(group_keys_extra_);
   309     if (!(session && partner && group_keys_extra_))
   310         return PEP_ILLEGAL_VALUE;
   311 
   312     group_keys_extra_t *group_keys_extra = 
   313         (group_keys_extra_t*) group_keys_extra_;
   314     identity_list *group_keys = group_keys_extra->group_keys;
   315     char *group_id = group_keys_extra->group_id;
   316 
   317     status = _storeGroupKeys(session, group_keys);
   318     if (status != PEP_STATUS_OK)
   319         return status;
   320 
   321     // set group id according to given group-id
   322     status = set_device_group(session, group_id);
   323     if (status != PEP_STATUS_OK)
   324         return status;
   325     
   326     return status;
   327 }
   328 
   329 // storeGroupUpdate() - 
   330 //
   331 //  params:
   332 //      session (in)        session handle
   333 //      state (in)          state the state machine is in
   334 //      partner (in)        partner to communicate with
   335 //      _group_keys (in)    group keys received from partner
   336 //
   337 //  returns:
   338 //      PEP_STATUS_OK or any other value on error
   339 
   340 PEP_STATUS storeGroupUpdate(
   341         PEP_SESSION session,
   342         DeviceState_state state,
   343         Identity partner,
   344         void *group_keys_
   345     )
   346 {
   347     PEP_STATUS status = PEP_STATUS_OK;
   348 
   349     assert(session);
   350     assert(partner);
   351     assert(group_keys_);
   352     if (!(session && partner && group_keys_))
   353         return PEP_ILLEGAL_VALUE;
   354 
   355     identity_list *group_keys = (identity_list*) group_keys_;
   356 
   357     status = _storeGroupKeys(session, group_keys);
   358 
   359 
   360     return status;
   361 }
   362 
   363 // makeGroup() - 
   364 //
   365 //  params:
   366 //      session (in)        session handle
   367 //      state (in)          state the state machine is in
   368 //      partner (in)        ignored
   369 //      extra (in)          ignored
   370 //
   371 //  returns:
   372 //      PEP_STATUS_OK or any other value on error
   373 
   374 PEP_STATUS makeGroup(
   375         PEP_SESSION session,
   376         DeviceState_state state,
   377         Identity partner,
   378         void *extra
   379     )
   380 {
   381     PEP_STATUS status = PEP_STATUS_OK;
   382 
   383     assert(session);
   384    
   385     // make a new uuid 
   386     char new_uuid[37];
   387     pEpUUID uuid;
   388     uuid_generate_random(uuid);
   389     uuid_unparse_upper(uuid, new_uuid);
   390 
   391     // take that new uuid as group-id
   392     status = set_device_group(session, new_uuid);
   393 
   394     return status;
   395 }
   396 
   397 // renewUUID() - 
   398 //
   399 //  params:
   400 //      session (in)        session handle
   401 //      state (in)          state the state machine is in
   402 //      partner (in)        ignored
   403 //      extra (in)          ignored
   404 //
   405 //  returns:
   406 //      PEP_STATUS_OK or any other value on error
   407 
   408 PEP_STATUS renewUUID(
   409         PEP_SESSION session,
   410         DeviceState_state state,
   411         Identity partner,
   412         void *extra
   413     )
   414 {
   415     PEP_STATUS status = PEP_STATUS_OK;
   416 
   417     assert(session);
   418 
   419     // change sync_uuid when entering group 
   420     // thus ignoring unprocessed handshakes
   421     // addressed to previous self (sole) once in.
   422     pEpUUID uuid;
   423     uuid_generate_random(uuid);
   424     uuid_unparse_upper(uuid, session->sync_uuid);
   425     
   426     return status;
   427 }
   428 
   429 // leaveGroup() - 
   430 //
   431 //  params:
   432 //      session (in)        session handle
   433 //      state (in)          state the state machine is in
   434 //      partner (in)        ignored
   435 //      extra (in)          ignored
   436 //
   437 //  returns:
   438 //      PEP_STATUS_OK or any other value on error
   439 
   440 PEP_STATUS leaveGroup(
   441         PEP_SESSION session,
   442         DeviceState_state state,
   443         Identity partner,
   444         void *extra
   445     )
   446 {
   447     PEP_STATUS status = PEP_STATUS_OK;
   448 
   449     assert(session);
   450 
   451     status = set_device_group(session, NULL);
   452     
   453     return status;
   454 }