src/sync_actions.c
author Volker Birk <vb@pep.foundation>
Sat, 20 Aug 2016 18:04:13 +0200
branchkeysync
changeset 1046 73be5d9af815
parent 1043 f786ee22e281
child 1047 2a4a2ec1340b
permissions -rw-r--r--
adding broadcast function
vb@623
     1
// Actions for DeviceState state machine
vb@623
     2
vb@623
     3
#include <assert.h>
vb@690
     4
#include "pEp_internal.h"
vb@690
     5
#include "message.h"
vb@623
     6
#include "sync_fsm.h"
vb@951
     7
#include "map_asn1.h"
vb@1046
     8
#include "baseprotocol.h"
vb@985
     9
#include "../asn.1/DeviceGroup-Protocol.h"
vb@623
    10
vb@951
    11
// conditions
vb@951
    12
vb@951
    13
static const char *sql_stored_group_keys =
vb@1004
    14
        "select count(device_group) from person where id = '" PEP_OWN_USERID "';"; 
vb@951
    15
vb@951
    16
static int _stored_group_keys(void *_gc, int count, char **text, char **name)
vb@951
    17
{
vb@951
    18
    assert(_gc);
vb@951
    19
    assert(count == 1);
vb@951
    20
    assert(text && text[0]);
vb@951
    21
    if (!(_gc && count == 1 && text && text[0]))
vb@951
    22
        return -1;
vb@951
    23
vb@951
    24
    bool *gc = (bool *) _gc;
vb@951
    25
    *gc = atoi(text[0]) != 0;
vb@951
    26
    return 0;
vb@951
    27
}
vb@951
    28
vb@959
    29
int storedGroupKeys(PEP_SESSION session)
vb@951
    30
{
vb@951
    31
    assert(session);
vb@951
    32
    if (!session)
vb@964
    33
        return invalid_condition; // error
vb@951
    34
vb@951
    35
    bool gc = false;
vb@951
    36
    int int_result = sqlite3_exec(
vb@951
    37
        session->db,
vb@951
    38
        sql_stored_group_keys,
vb@951
    39
        _stored_group_keys,
vb@951
    40
        &gc,
vb@951
    41
        NULL
vb@951
    42
    );
vb@951
    43
    assert(int_result == SQLITE_OK);
vb@959
    44
    if (int_result != SQLITE_OK)
vb@964
    45
        return invalid_condition; // error
vb@959
    46
vb@959
    47
    if (gc)
vb@959
    48
        return 1;
vb@959
    49
    else
vb@959
    50
        return 0;
vb@951
    51
}
vb@951
    52
vb@959
    53
int keyElectionWon(PEP_SESSION session, Identity partner)
vb@951
    54
{
vb@951
    55
    assert(session);
vb@951
    56
    assert(partner);
vb@951
    57
    if (!(session && partner))
vb@964
    58
        return invalid_condition; // error
vb@951
    59
vb@951
    60
    // an already existing group always wins
vb@951
    61
vb@951
    62
    if (storedGroupKeys(session)) {
vb@951
    63
        assert(!(partner->flags & PEP_idf_devicegroup));
vb@959
    64
        return 1;
vb@951
    65
    }
vb@951
    66
vb@951
    67
    if (partner->flags & PEP_idf_devicegroup)
vb@959
    68
        return 0;
vb@951
    69
vb@951
    70
    Identity me = NULL;
vb@951
    71
    PEP_STATUS status = get_identity(session, partner->address, PEP_OWN_USERID,
vb@951
    72
            &me);
vb@964
    73
    if (status == PEP_OUT_OF_MEMORY)
vb@964
    74
        return invalid_out_of_memory;
vb@951
    75
    if (status != PEP_STATUS_OK)
vb@964
    76
        return invalid_condition; // error
vb@951
    77
vb@964
    78
    int result = invalid_condition; // error state has to be overwritten
vb@951
    79
vb@959
    80
    time_t own_created;
vb@959
    81
    time_t partners_created;
vb@959
    82
vb@959
    83
    status = key_created(session, me->fpr, &own_created);
vb@959
    84
    if (status != PEP_STATUS_OK)
vb@959
    85
        goto the_end;
vb@959
    86
vb@959
    87
    status = key_created(session, partner->fpr, &partners_created);
vb@959
    88
    if (status != PEP_STATUS_OK)
vb@959
    89
        goto the_end;
vb@959
    90
vb@959
    91
    if (own_created > partners_created)
vb@959
    92
        result = 0;
vb@959
    93
    else
vb@959
    94
        result = 1;
vb@951
    95
vb@951
    96
the_end:
vb@951
    97
    free_identity(me);
vb@951
    98
    return result;
vb@951
    99
}
vb@650
   100
vb@884
   101
// showHandshake() - trigger the handshake dialog of the application
vb@623
   102
//
vb@623
   103
//  params:
vb@627
   104
//      session (in)        session handle
vb@690
   105
//      state (in)          state the state machine is in
vb@807
   106
//      partner (in)        partner to communicate with
vb@623
   107
//
vb@623
   108
//  returns:
vb@623
   109
//      PEP_STATUS_OK or any other value on error
vb@623
   110
vb@690
   111
PEP_STATUS showHandshake(
vb@690
   112
        PEP_SESSION session,
vb@690
   113
        DeviceState_state state,
vb@939
   114
        Identity partner,
vb@939
   115
        void *extra
vb@690
   116
    )
vb@623
   117
{
vb@623
   118
    PEP_STATUS status = PEP_STATUS_OK;
vb@939
   119
vb@650
   120
    assert(session);
vb@665
   121
    assert(partner);
vb@939
   122
    assert(extra == NULL);
vb@939
   123
vb@665
   124
    if (!(session && partner))
vb@665
   125
        return PEP_ILLEGAL_VALUE;
vb@939
   126
vb@907
   127
    assert(session->showHandshake);
vb@884
   128
    if (!session->showHandshake)
vb@884
   129
        return PEP_SYNC_NO_TRUSTWORDS_CALLBACK;
vb@623
   130
vb@884
   131
    pEp_identity *me = NULL;
vb@884
   132
    status = get_identity(session, partner->address, PEP_OWN_USERID, &me);
vb@884
   133
    if (status != PEP_STATUS_OK)
vb@884
   134
        goto error;
vb@884
   135
    
vb@884
   136
    status = session->showHandshake(session, me, partner);
vb@884
   137
    if (status != PEP_STATUS_OK)
vb@884
   138
        goto error;
vb@623
   139
vb@623
   140
    return status;
vb@650
   141
vb@650
   142
error:
vb@884
   143
    free_identity(me);
vb@951
   144
    free_identity(partner);
vb@650
   145
    return status;
vb@623
   146
}
vb@623
   147
vb@650
   148
vb@907
   149
// reject() - stores rejection of partner
vb@623
   150
//
vb@623
   151
//  params:
vb@627
   152
//      session (in)        session handle
vb@690
   153
//      state (in)          state the state machine is in
vb@807
   154
//      partner (in)        partner to communicate with
vb@623
   155
//
vb@623
   156
//  returns:
vb@623
   157
//      PEP_STATUS_OK or any other value on error
vb@623
   158
vb@690
   159
PEP_STATUS reject(
vb@690
   160
        PEP_SESSION session,
vb@690
   161
        DeviceState_state state,
vb@939
   162
        Identity partner,
vb@939
   163
        void *extra
vb@690
   164
    )
vb@623
   165
{
vb@623
   166
    PEP_STATUS status = PEP_STATUS_OK;
vb@623
   167
vb@650
   168
    assert(session);
vb@665
   169
    assert(partner);
vb@939
   170
    assert(extra == NULL);
vb@665
   171
    if (!(session && partner))
vb@665
   172
        return PEP_ILLEGAL_VALUE;
vb@623
   173
vb@939
   174
    status = set_identity_flags(session, partner,
vb@939
   175
            partner->flags | PEP_idf_not_for_sync);
vb@623
   176
vb@951
   177
    free_identity(partner);
vb@623
   178
    return status;
vb@623
   179
}
vb@623
   180
vb@650
   181
vb@657
   182
// storeGroupKeys() - 
vb@623
   183
//
vb@623
   184
//  params:
vb@627
   185
//      session (in)        session handle
vb@690
   186
//      state (in)          state the state machine is in
vb@807
   187
//      partner (in)        partner to communicate with
vb@939
   188
//      _group_keys (in)    group keys received from partner
vb@623
   189
//
vb@623
   190
//  returns:
vb@623
   191
//      PEP_STATUS_OK or any other value on error
vb@623
   192
vb@690
   193
PEP_STATUS storeGroupKeys(
vb@690
   194
        PEP_SESSION session,
vb@690
   195
        DeviceState_state state,
vb@939
   196
        Identity partner,
vb@939
   197
        void *_group_keys
vb@690
   198
    )
vb@623
   199
{
vb@623
   200
    PEP_STATUS status = PEP_STATUS_OK;
vb@623
   201
vb@650
   202
    assert(session);
vb@665
   203
    assert(partner);
vb@939
   204
    assert(_group_keys);
vb@939
   205
    if (!(session && partner && _group_keys))
vb@665
   206
        return PEP_ILLEGAL_VALUE;
vb@623
   207
vb@951
   208
    identity_list *group_keys = (identity_list *) _group_keys;
vb@623
   209
vb@964
   210
    for (identity_list *il = group_keys; il && il->ident; il = il->next) {
vb@964
   211
        free(il->ident->user_id);
vb@964
   212
        il->ident->user_id = strdup(PEP_OWN_USERID);
vb@964
   213
        assert(il->ident->user_id);
vb@964
   214
        if (!il->ident->user_id)
vb@964
   215
            goto enomem;
vb@964
   216
        status = set_identity(session, il->ident);
vb@964
   217
        if (status != PEP_STATUS_OK)
vb@964
   218
            break;
vb@964
   219
    }
vb@964
   220
vb@951
   221
    free_identity(partner);
vb@951
   222
    free_identity_list(group_keys);
vb@623
   223
    return status;
vb@650
   224
vb@650
   225
enomem:
vb@650
   226
    status = PEP_OUT_OF_MEMORY;
vb@951
   227
    free_identity(partner);
vb@951
   228
    free_identity_list(group_keys);
vb@650
   229
    return status;
vb@623
   230
}
vb@623
   231
vb@1043
   232
PEP_STATUS receive_sync_msg(
vb@954
   233
        PEP_SESSION session,
vb@954
   234
        DeviceGroup_Protocol_t *msg
vb@954
   235
    )
vb@951
   236
{
vb@951
   237
    assert(session && msg && msg->present != DeviceGroup_Protocol_PR_NOTHING);
vb@951
   238
    if (!(session && msg && msg->present != DeviceGroup_Protocol_PR_NOTHING))
vb@951
   239
        return PEP_ILLEGAL_VALUE;
vb@951
   240
vb@951
   241
    void *extra = NULL;
vb@951
   242
    Identity partner = NULL;
vb@951
   243
    DeviceState_event event = DeviceState_event_NONE;
vb@951
   244
vb@951
   245
    switch (msg->present) {
vb@951
   246
        case DeviceGroup_Protocol_PR_beacon:
vb@951
   247
            partner = Identity_to_Struct(&msg->choice.beacon.header.me, NULL);
vb@951
   248
            if (!partner)
vb@951
   249
                return PEP_OUT_OF_MEMORY;
vb@951
   250
            event = Beacon;
vb@951
   251
            break;
vb@951
   252
vb@951
   253
        case DeviceGroup_Protocol_PR_handshakeRequest:
vb@954
   254
            partner = Identity_to_Struct(
vb@954
   255
                    &msg->choice.handshakeRequest.header.me, NULL);
vb@951
   256
            if (!partner)
vb@951
   257
                return PEP_OUT_OF_MEMORY;
vb@951
   258
            event = HandshakeRequest;
vb@951
   259
            break;
vb@951
   260
vb@951
   261
        case DeviceGroup_Protocol_PR_groupKeys:
vb@954
   262
            partner = Identity_to_Struct(&msg->choice.groupKeys.header.me,
vb@954
   263
                    NULL);
vb@951
   264
            if (!partner)
vb@951
   265
                return PEP_OUT_OF_MEMORY;
vb@951
   266
            identity_list *group_keys = IdentityList_to_identity_list(
vb@951
   267
                    &msg->choice.groupKeys.ownIdentities, NULL);
vb@951
   268
            if (!group_keys) {
vb@951
   269
                free_identity(partner);
vb@951
   270
                return PEP_OUT_OF_MEMORY;
vb@951
   271
            }
vb@951
   272
            extra = (void *) group_keys;
vb@951
   273
            event = GroupKeys;
vb@951
   274
            break;
vb@951
   275
vb@951
   276
        default:
vb@951
   277
            return PEP_SYNC_ILLEGAL_MESSAGE;
vb@951
   278
    }
vb@951
   279
vb@951
   280
    return fsm_DeviceState_inject(session, event, partner, extra);
vb@951
   281
}
vb@951
   282
vb@952
   283
PEP_STATUS receive_DeviceState_msg(PEP_SESSION session, message *src)
vb@952
   284
{
vb@952
   285
    assert(session && src);
vb@952
   286
    if (!(session && src))
vb@952
   287
        return PEP_ILLEGAL_VALUE;
vb@952
   288
vb@953
   289
    bool found = false;
vb@953
   290
vb@953
   291
    for (bloblist_t *bl = src->attachments; bl && bl->value; bl = bl->next) {
vb@953
   292
        if (bl->mime_type && strcasecmp(bl->mime_type, "application/pEp") == 0
vb@953
   293
                && bl->size) {
vb@953
   294
            DeviceGroup_Protocol_t *msg;
vb@954
   295
            uper_decode_complete(NULL, &asn_DEF_DeviceGroup_Protocol,
vb@953
   296
                    (void **) &msg, bl->value, bl->size);
vb@953
   297
            if (msg) {
vb@953
   298
                found = true;
vb@1043
   299
                PEP_STATUS status = session->inject_sync_msg(msg, session->sync_obj);
vb@953
   300
                ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
vb@953
   301
                if (status != PEP_STATUS_OK)
vb@953
   302
                    return status;
vb@953
   303
            }
vb@953
   304
        }
vb@953
   305
    }
vb@953
   306
vb@953
   307
    if (found) {
vb@953
   308
        for (stringpair_list_t *spl = src->opt_fields ; spl && spl->value ;
vb@953
   309
                spl = spl->next) {
vb@953
   310
            if (spl->value->key &&
vb@953
   311
                    strcasecmp(spl->value->key, "pEp-auto-consume") == 0) {
vb@953
   312
                if (spl->value->value &&
vb@953
   313
                        strcasecmp(spl->value->value, "yes") == 0)
vb@953
   314
                    return PEP_MESSAGE_CONSUMED;
vb@953
   315
            }
vb@953
   316
        }
vb@953
   317
    }
vb@953
   318
vb@952
   319
    return PEP_STATUS_OK;
vb@952
   320
}
vb@952
   321
vb@1046
   322
PEP_STATUS broadcast_msg(PEP_SESSION session, Identity partner, char *payload,
vb@1046
   323
        size_t size)
vb@1046
   324
{
vb@1046
   325
    PEP_STATUS status = PEP_STATUS_OK;
vb@1046
   326
vb@1046
   327
    assert(session && partner && payload);
vb@1046
   328
    if (!(session && partner && payload))
vb@1046
   329
        return PEP_ILLEGAL_VALUE;
vb@1046
   330
vb@1046
   331
    if (size == 0)
vb@1046
   332
        return PEP_STATUS_OK;
vb@1046
   333
vb@1046
   334
    stringlist_t *own_addresses = NULL;
vb@1046
   335
    status = get_own_addresses(session, &own_addresses);
vb@1046
   336
    if (status != PEP_STATUS_OK)
vb@1046
   337
        return status;
vb@1046
   338
vb@1046
   339
    Identity me = NULL;
vb@1046
   340
    message *_message = NULL;
vb@1046
   341
vb@1046
   342
    for (stringlist_t *_a = own_addresses; _a && _a->value; _a = _a->next) {
vb@1046
   343
        me = new_identity(_a->value, NULL, PEP_OWN_USERID, NULL);
vb@1046
   344
        if (!me) {
vb@1046
   345
            status = PEP_OUT_OF_MEMORY;
vb@1046
   346
            goto the_end;
vb@1046
   347
        }
vb@1046
   348
vb@1046
   349
        status = myself(session, me);
vb@1046
   350
        if (status == PEP_OUT_OF_MEMORY)
vb@1046
   351
            goto the_end;
vb@1046
   352
        if (status != PEP_STATUS_OK)
vb@1046
   353
            continue;
vb@1046
   354
vb@1046
   355
        status = prepare_message(me, partner, payload, size, &_message);
vb@1046
   356
        if (status != PEP_STATUS_OK)
vb@1046
   357
            goto the_end;
vb@1046
   358
        
vb@1046
   359
        free_identity(me);
vb@1046
   360
        me = NULL;
vb@1046
   361
vb@1046
   362
        status = session->messageToSend(session->sync_obj, _message);
vb@1046
   363
        if (status == PEP_OUT_OF_MEMORY)
vb@1046
   364
            goto the_end;
vb@1046
   365
        assert(status == PEP_STATUS_OK);
vb@1046
   366
    }
vb@1046
   367
vb@1046
   368
the_end:
vb@1046
   369
    free_stringlist(own_addresses);
vb@1046
   370
    free_identity(me);
vb@1046
   371
    free_message(_message);
vb@1046
   372
    return status;
vb@1046
   373
}
vb@1046
   374