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