src/sync_api.c
author Krista 'DarthMama' Bennett <krista@pep.foundation>
Thu, 04 Jun 2020 11:18:45 +0200
changeset 4729 3df9a2a67597
parent 4378 3c491922339d
child 4792 7056435ab9e7
permissions -rw-r--r--
forgot test files
krista@2271
     1
// This file is under GNU General Public License 3.0
krista@2271
     2
// see LICENSE.txt
krista@2271
     3
krista@2271
     4
#include "pEp_internal.h"
krista@2271
     5
krista@2271
     6
#include <memory.h>
krista@2271
     7
#include <assert.h>
krista@2271
     8
vb@2830
     9
#include "KeySync_fsm.h"
krista@2271
    10
krista@2271
    11
DYNAMIC_API PEP_STATUS register_sync_callbacks(
krista@2271
    12
        PEP_SESSION session,
krista@2271
    13
        void *management,
krista@2271
    14
        notifyHandshake_t notifyHandshake,
vb@2839
    15
        retrieve_next_sync_event_t retrieve_next_sync_event
krista@2271
    16
    )
krista@2271
    17
{
vb@2992
    18
    assert(session && notifyHandshake && retrieve_next_sync_event);
vb@2992
    19
    if (!(session && notifyHandshake && retrieve_next_sync_event))
krista@2271
    20
        return PEP_ILLEGAL_VALUE;
krista@2271
    21
vb@3745
    22
    identity_list *own_identities = NULL;
vb@3745
    23
    PEP_STATUS status = own_identities_retrieve(session, &own_identities);
vb@3745
    24
    if (status)
vb@3745
    25
        return status;
vb@3745
    26
    bool own_identities_available = own_identities && own_identities->ident;
vb@3745
    27
    free_identity_list(own_identities);
vb@3745
    28
    if (!own_identities_available)
vb@3745
    29
        return PEP_SYNC_CANNOT_START;
vb@3745
    30
krista@2271
    31
    session->sync_management = management;
krista@2271
    32
    session->notifyHandshake = notifyHandshake;
vb@2839
    33
    session->retrieve_next_sync_event = retrieve_next_sync_event;
krista@2271
    34
vb@2850
    35
    // start state machine
vb@2850
    36
    return Sync_driver(session, Sync_PR_keysync, Init);
krista@2271
    37
}
krista@2271
    38
krista@2271
    39
DYNAMIC_API void unregister_sync_callbacks(PEP_SESSION session) {
krista@2271
    40
    // stop state machine
vb@2837
    41
    free_Sync_state(session);
krista@2271
    42
krista@2271
    43
    // unregister
krista@2271
    44
    session->sync_management = NULL;
krista@2271
    45
    session->notifyHandshake = NULL;
vb@2839
    46
    session->retrieve_next_sync_event = NULL;
krista@2271
    47
}
krista@2271
    48
krista@2271
    49
DYNAMIC_API PEP_STATUS deliverHandshakeResult(
krista@2271
    50
        PEP_SESSION session,
vb@3407
    51
        sync_handshake_result result,
vb@3407
    52
        const identity_list *identities_sharing
krista@2271
    53
    )
krista@2271
    54
{
krista@2271
    55
    assert(session);
krista@2271
    56
    if (!session)
krista@2271
    57
        return PEP_ILLEGAL_VALUE;
krista@2271
    58
vb@3407
    59
    for (const identity_list *_il = identities_sharing; _il && _il->ident;
vb@3407
    60
            _il = _il->next) {
vb@3407
    61
        if (!_il->ident->me || !_il->ident->user_id || !_il->ident->user_id[0]
vb@3407
    62
                || !_il->ident->address || !_il->ident->address[0])
vb@3407
    63
            return PEP_ILLEGAL_VALUE;
vb@3407
    64
    }
vb@3407
    65
krista@2271
    66
    PEP_STATUS status = PEP_STATUS_OK;
vb@2830
    67
    int event;
krista@2271
    68
krista@2271
    69
    switch (result) {
krista@2271
    70
        case SYNC_HANDSHAKE_CANCEL:
krista@2271
    71
            event = Cancel;
krista@2271
    72
            break;
krista@2271
    73
        case SYNC_HANDSHAKE_ACCEPTED:
krista@2271
    74
        {
vb@2830
    75
            event = Accept;
krista@2271
    76
            break;
krista@2271
    77
        }
krista@2271
    78
        case SYNC_HANDSHAKE_REJECTED:
krista@2271
    79
        {
vb@2830
    80
            event = Reject;
krista@2271
    81
            break;
krista@2271
    82
        }
krista@2271
    83
        default:
krista@2271
    84
            return PEP_ILLEGAL_VALUE;
krista@2271
    85
    }
krista@2271
    86
vb@3540
    87
    identity_list *own_identities = NULL;
vb@3410
    88
vb@3411
    89
    if (identities_sharing && identities_sharing->ident) {
vb@3540
    90
        own_identities = identity_list_dup(identities_sharing);
vb@3540
    91
        if (!own_identities)
vb@3540
    92
            return PEP_OUT_OF_MEMORY;
vb@3407
    93
    }
vb@3407
    94
    else {
vb@3540
    95
        status = own_identities_retrieve(session, &own_identities);
vb@3407
    96
    }
vb@3407
    97
vb@3407
    98
    if (!status)
vb@3540
    99
        status = signal_Sync_event(session, Sync_PR_keysync, event, own_identities);
krista@2271
   100
    return status;
krista@2271
   101
}
krista@2271
   102
krista@2271
   103
DYNAMIC_API PEP_STATUS do_sync_protocol(
krista@2271
   104
        PEP_SESSION session,
krista@2271
   105
        void *obj
krista@2271
   106
    )
krista@2271
   107
{
vb@2840
   108
    Sync_event_t *event= NULL;
krista@2271
   109
vb@2839
   110
    assert(session && session->retrieve_next_sync_event);
vb@2839
   111
    if (!(session && session->retrieve_next_sync_event))
krista@2271
   112
        return PEP_ILLEGAL_VALUE;
krista@2271
   113
vb@2909
   114
    log_event(session, "sync_protocol thread started", "pEp sync protocol",
vb@2909
   115
            NULL, NULL);
krista@2271
   116
krista@2271
   117
    while (true) 
krista@2271
   118
    {
vb@2909
   119
        event = session->retrieve_next_sync_event(session->sync_management,
vb@2909
   120
                SYNC_THRESHOLD);
vb@2840
   121
        if (!event)
krista@2271
   122
            break;
vb@2834
   123
vb@2899
   124
        do_sync_protocol_step(session, obj, event);
krista@2271
   125
    }
vb@2834
   126
    session->sync_obj = NULL;
krista@2271
   127
vb@2909
   128
    log_event(session, "sync_protocol thread shutdown", "pEp sync protocol",
vb@2909
   129
            NULL, NULL);
krista@2271
   130
krista@2271
   131
    return PEP_STATUS_OK;
krista@2271
   132
}
krista@2271
   133
vb@2899
   134
DYNAMIC_API PEP_STATUS do_sync_protocol_step(
vb@2899
   135
        PEP_SESSION session,
vb@2899
   136
        void *obj,
vb@2899
   137
        SYNC_EVENT event
vb@2899
   138
    )
vb@2899
   139
{
vb@2899
   140
    assert(session);
vb@2899
   141
    if (!session)
vb@2899
   142
        return PEP_ILLEGAL_VALUE;
vb@2899
   143
vb@2899
   144
    if (!event)
vb@2899
   145
        return PEP_STATUS_OK;
vb@2899
   146
vb@2899
   147
    session->sync_obj = obj;
vb@2899
   148
vb@2899
   149
    PEP_STATUS status = recv_Sync_event(session, event);
vb@2899
   150
    return status == PEP_MESSAGE_IGNORE ? PEP_STATUS_OK : status;
vb@2899
   151
}
vb@2899
   152
vb@2899
   153
DYNAMIC_API bool is_sync_thread(PEP_SESSION session)
vb@2899
   154
{
vb@2899
   155
    assert(session);
vb@2899
   156
    if (!session)
vb@2899
   157
        return false;
vb@2899
   158
    return session->retrieve_next_sync_event != NULL;
vb@2899
   159
}
vb@2899
   160
vb@2911
   161
DYNAMIC_API SYNC_EVENT new_sync_timeout_event()
vb@2911
   162
{
vb@2911
   163
    return SYNC_TIMEOUT_EVENT;
vb@2911
   164
}
vb@2911
   165
vb@3406
   166
DYNAMIC_API PEP_STATUS enter_device_group(
vb@3406
   167
        PEP_SESSION session,
vb@3406
   168
        const identity_list *identities_sharing
vb@3406
   169
    )
vb@3406
   170
{
vb@3406
   171
    assert(session);
vb@3406
   172
    if (!session)
vb@3406
   173
        return PEP_ILLEGAL_VALUE;
vb@3406
   174
vb@3406
   175
    for (const identity_list *_il = identities_sharing; _il && _il->ident;
vb@3406
   176
            _il = _il->next) {
vb@3406
   177
        if (!_il->ident->me || !_il->ident->user_id || !_il->ident->user_id[0]
vb@3406
   178
                || !_il->ident->address || !_il->ident->address[0])
vb@3406
   179
            return PEP_ILLEGAL_VALUE;
vb@3406
   180
    }
vb@3406
   181
vb@3406
   182
    identity_list *own_identities = NULL;
vb@3406
   183
    PEP_STATUS status = own_identities_retrieve(session, &own_identities);
vb@3406
   184
    if (status)
vb@3406
   185
        goto the_end;
vb@3406
   186
vb@3409
   187
    if (identities_sharing && identities_sharing->ident) {
vb@3406
   188
        for (identity_list *_il = own_identities; _il && _il->ident;
vb@3406
   189
                _il = _il->next) {
vb@3406
   190
            bool found = false;
vb@3406
   191
vb@3406
   192
            for (const identity_list *_is = identities_sharing;
vb@3406
   193
                    _is && _is->ident; _is = _is->next) {
vb@3406
   194
                // FIXME: "john@doe.com" and "mailto:john@doe.com" should be equal
vb@3406
   195
                if (strcmp(_il->ident->address, _is->ident->address) == 0
vb@3406
   196
                        && strcmp(_il->ident->user_id, _is->ident->user_id) == 0) {
vb@3406
   197
                    found = true;
vb@3406
   198
vb@3406
   199
                    status = set_identity_flags(session, _il->ident, PEP_idf_devicegroup);
vb@3406
   200
                    if (status)
vb@3406
   201
                        goto the_end;
vb@3406
   202
vb@3406
   203
                    break;
vb@3406
   204
                }
vb@3406
   205
            }
vb@3406
   206
            if (!found) {
vb@3406
   207
                status = unset_identity_flags(session, _il->ident, PEP_idf_devicegroup);
vb@3406
   208
                if (status)
vb@3406
   209
                    goto the_end;
vb@3406
   210
            }
vb@3406
   211
        }
vb@3406
   212
    }
vb@3406
   213
    else {
vb@3406
   214
        for (identity_list *_il = own_identities; _il && _il->ident;
vb@3406
   215
                _il = _il->next) {
vb@3406
   216
            status = set_identity_flags(session, _il->ident, PEP_idf_devicegroup);
vb@3406
   217
            if (status)
vb@3406
   218
                goto the_end;
vb@3406
   219
        }
vb@3406
   220
    }
vb@3406
   221
vb@3406
   222
the_end:
vb@3406
   223
    free_identity_list(own_identities);
vb@3406
   224
    return status;
vb@3406
   225
}
vb@3406
   226
krista@4243
   227
PEP_STATUS disable_sync(PEP_SESSION session)
vb@3406
   228
{
vb@3406
   229
    assert(session);
vb@3406
   230
    if (!session)
vb@3406
   231
        return PEP_ILLEGAL_VALUE;
vb@3406
   232
vb@4183
   233
    if (session->inject_sync_event)
vb@4183
   234
        session->inject_sync_event((void *) SHUTDOWN, NULL);
vb@4183
   235
vb@3406
   236
    identity_list *il = NULL;
vb@3406
   237
    PEP_STATUS status = own_identities_retrieve(session, &il);
vb@3406
   238
    if (status)
vb@3406
   239
        goto the_end;
vb@3406
   240
vb@3406
   241
    for (identity_list *_il = il; _il && _il->ident ; _il = _il->next) {
vb@3406
   242
        status = unset_identity_flags(session, _il->ident, PEP_idf_devicegroup);
vb@3406
   243
        if (status)
vb@3406
   244
            goto the_end;
vb@3406
   245
    }
vb@3406
   246
vb@3406
   247
the_end:
vb@3406
   248
    free_identity_list(il);
vb@3406
   249
    return status;
vb@3406
   250
}
vb@3406
   251
krista@4243
   252
DYNAMIC_API PEP_STATUS leave_device_group(PEP_SESSION session) {
krista@4243
   253
    assert(session);
krista@4243
   254
    if (!session)
krista@4243
   255
        return PEP_ILLEGAL_VALUE;
vb@4377
   256
vb@4377
   257
    bool grouped = false;
vb@4378
   258
    PEP_STATUS status = deviceGrouped(session, &grouped);
vb@4377
   259
    if (status)
vb@4377
   260
        return status;
vb@4377
   261
vb@4378
   262
    if (!grouped) {
vb@4378
   263
        if (session->inject_sync_event)
vb@4378
   264
            session->inject_sync_event((void *) SHUTDOWN, NULL);
vb@4377
   265
        return PEP_STATUS_OK;
vb@4378
   266
    }
vb@4377
   267
vb@4371
   268
    return signal_Sync_event(session, Sync_PR_keysync, LeaveDeviceGroup, NULL);
krista@4243
   269
}
krista@4243
   270
vb@3996
   271
DYNAMIC_API PEP_STATUS enable_identity_for_sync(PEP_SESSION session,
vb@3996
   272
        pEp_identity *ident)
vb@3996
   273
{
vb@4374
   274
    assert(session && ident && ident->user_id && ident->user_id[0] && ident->address && ident->address[0]);
vb@4374
   275
    if (!(session && ident && ident->user_id && ident->user_id[0] && ident->address && ident->address[0]))
vb@3996
   276
        return PEP_ILLEGAL_VALUE;
vb@3996
   277
vb@4374
   278
    // safeguard: in case the delivered identity is not valid fetch flags from the database
vb@4374
   279
    //            while doing this check if this is an own identity and return an error if not
vb@4374
   280
vb@4374
   281
    pEp_identity *stored_ident = NULL;
vb@4374
   282
    PEP_STATUS status = get_identity(session, ident->address, ident->user_id, &stored_ident);
vb@4374
   283
    if (status)
krista@4369
   284
        return status;
vb@4374
   285
    assert(stored_ident);
vb@4374
   286
    if (!stored_ident->me) {
vb@4374
   287
        free_identity(stored_ident);
vb@4374
   288
        return PEP_ILLEGAL_VALUE;
vb@4374
   289
    }
vb@4374
   290
    ident->flags = stored_ident->flags;
vb@4374
   291
    free_identity(stored_ident);
krista@4369
   292
vb@4375
   293
    // this is an invalid state; detect while debugging
vb@4375
   294
vb@4375
   295
    assert(!((ident->flags & PEP_idf_devicegroup) && (ident->flags & PEP_idf_not_for_sync)));
vb@4375
   296
vb@4374
   297
    // if we're grouped and this identity is enabled already we can stop here
vb@4375
   298
krista@4369
   299
    if ((ident->flags & PEP_idf_devicegroup) && !(ident->flags & PEP_idf_not_for_sync))
krista@4369
   300
        return PEP_STATUS_OK;
krista@4369
   301
vb@4374
   302
    // if the identity is marked not for sync unset this to enable
vb@4375
   303
vb@4374
   304
    if (ident->flags & PEP_idf_not_for_sync) {
vb@4374
   305
        status = unset_identity_flags(session, ident, PEP_idf_not_for_sync);
vb@4374
   306
        if (status)
vb@4374
   307
            return status;
vb@4374
   308
    }
vb@4231
   309
vb@4374
   310
    // if we're grouped then add the identity to the group
vb@4375
   311
vb@4374
   312
    bool grouped = false;
vb@4374
   313
    status = deviceGrouped(session, &grouped);
vb@4374
   314
    if (status)
krista@4366
   315
        return status;
vb@4374
   316
    if (grouped) {
vb@4374
   317
        status = set_identity_flags(session, ident, PEP_idf_devicegroup);    
vb@4374
   318
        if (status)
vb@4374
   319
            return status;
vb@4374
   320
        // signal we have a new identity in the group
vb@4374
   321
        signal_Sync_event(session, Sync_PR_keysync, KeyGen, NULL);
vb@4374
   322
    }
krista@4366
   323
krista@4366
   324
    return PEP_STATUS_OK;
vb@3996
   325
}
vb@3996
   326
vb@3996
   327
DYNAMIC_API PEP_STATUS disable_identity_for_sync(PEP_SESSION session,
vb@3996
   328
        pEp_identity *ident)
vb@3996
   329
{
vb@3996
   330
    assert(session && ident);
vb@3996
   331
    if (!(session && ident))
vb@3996
   332
        return PEP_ILLEGAL_VALUE;
vb@3996
   333
vb@4375
   334
    // safeguard: in case the delivered identity is not valid fetch flags from the database
vb@4375
   335
    //            while doing this check if this is an own identity and return an error if not
vb@4375
   336
vb@4375
   337
    pEp_identity *stored_ident = NULL;
vb@4375
   338
    PEP_STATUS status = get_identity(session, ident->address, ident->user_id, &stored_ident);
vb@4375
   339
    if (status)
vb@4231
   340
        return status;
vb@4375
   341
    assert(stored_ident);
vb@4375
   342
    if (!stored_ident->me) {
vb@4375
   343
        free_identity(stored_ident);
vb@4375
   344
        return PEP_ILLEGAL_VALUE;
vb@4375
   345
    }
vb@4375
   346
    ident->flags = stored_ident->flags;
vb@4375
   347
    free_identity(stored_ident);
vb@4375
   348
vb@4375
   349
    // this is an invalid state; detect while debugging
vb@4375
   350
vb@4375
   351
    assert(!((ident->flags & PEP_idf_devicegroup) && (ident->flags & PEP_idf_not_for_sync)));
vb@4375
   352
vb@4375
   353
    // if this identity is disabled already we can end here
vb@4375
   354
vb@4375
   355
    if (ident->flags & PEP_idf_not_for_sync)
krista@4370
   356
        return PEP_STATUS_OK;
vb@4231
   357
vb@4375
   358
    // if the identity is not part of a device group just disable it to keep this
vb@4375
   359
vb@4375
   360
    if (!(ident->flags & PEP_idf_devicegroup)) {
vb@4375
   361
        status = set_identity_flags(session, ident, PEP_idf_not_for_sync);
vb@4375
   362
        return status;
vb@4375
   363
    }
vb@4375
   364
vb@4375
   365
    // we are grouped and this identity is part of a device group => key reset in all cases
vb@4367
   366
vb@4231
   367
    status = unset_identity_flags(session, ident, PEP_idf_devicegroup);
vb@3996
   368
    if (status)
vb@3996
   369
        return status;
vb@3996
   370
vb@3996
   371
    status = set_identity_flags(session, ident, PEP_idf_not_for_sync);
krista@4366
   372
    if (status)
krista@4366
   373
        return status;
krista@4366
   374
vb@4375
   375
    status = key_reset_identity(session, ident, NULL);
vb@3996
   376
    return status;
vb@3996
   377
}