src/sync_impl.c
author Edouard Tisserant <edouard@pep-project.org>
Thu, 16 Feb 2017 12:43:35 +0100
branchGroupMerge
changeset 1586 599deda50386
parent 1585 655cfb838ac6
child 1587 6db4fde2cdae
permissions -rw-r--r--
KeySync: added device group merge. Builds but still untested.
vb@1513
     1
// This file is under GNU General Public License 3.0
vb@1513
     2
// see LICENSE.txt
vb@1513
     3
edouard@1261
     4
#include "platform.h"
edouard@1260
     5
edouard@1260
     6
// it seems pEp_internal.h needs to be the first pEp include due to the 
markus@1259
     7
// #define for the dllimport / dllexport DYNAMIC_API stuff.
markus@1259
     8
#include "pEp_internal.h"
markus@1259
     9
vb@1059
    10
#include "sync_impl.h"
vb@1059
    11
#include "keymanagement.h"
vb@1076
    12
#include "message_api.h"
vb@1059
    13
#include "map_asn1.h"
vb@1059
    14
#include "baseprotocol.h"
vb@1059
    15
vb@1077
    16
#define SYNC_VERSION_MAJOR 1
vb@1077
    17
#define SYNC_VERSION_MINOR 0
vb@1077
    18
edouard@1316
    19
#define SYNC_INHIBIT_TIME (60*10)
edouard@1316
    20
#define SYNC_MSG_EXPIRE_TIME (60 * 10)
edouard@1316
    21
edouard@1172
    22
struct _sync_msg_t {
edouard@1172
    23
    bool is_a_message;
edouard@1172
    24
    union {
edouard@1172
    25
        DeviceGroup_Protocol_t *message;
edouard@1172
    26
        struct {
edouard@1172
    27
            DeviceState_event event;
edouard@1172
    28
            Identity partner;
edouard@1172
    29
            void *extra;
edouard@1172
    30
        } event;
edouard@1172
    31
    } u;
edouard@1172
    32
};
edouard@1172
    33
vb@1059
    34
PEP_STATUS receive_sync_msg(
vb@1059
    35
        PEP_SESSION session,
edouard@1445
    36
        sync_msg_t *sync_msg,
edouard@1445
    37
        time_t *timeout
vb@1059
    38
    )
vb@1059
    39
{
edouard@1172
    40
    PEP_STATUS status;
vb@1059
    41
    void *extra = NULL;
vb@1059
    42
    Identity partner = NULL;
vb@1059
    43
    DeviceState_event event = DeviceState_event_NONE;
edouard@1172
    44
    assert(session && sync_msg);
edouard@1172
    45
    if (!(session && sync_msg))
edouard@1172
    46
        return PEP_ILLEGAL_VALUE;
vb@1059
    47
edouard@1340
    48
    bool msgIsFromGroup = false;
edouard@1172
    49
    if(sync_msg->is_a_message){
edouard@1172
    50
        DeviceGroup_Protocol_t *msg = sync_msg->u.message;
edouard@1172
    51
        assert(msg && msg->payload.present != DeviceGroup_Protocol__payload_PR_NOTHING);
edouard@1172
    52
        if (!(msg && msg->payload.present != DeviceGroup_Protocol__payload_PR_NOTHING)){
edouard@1172
    53
            status = PEP_OUT_OF_MEMORY;
edouard@1172
    54
            goto error;
edouard@1172
    55
        }
vb@1059
    56
edouard@1340
    57
        msgIsFromGroup = msg->header.devicegroup;
edouard@1340
    58
edouard@1172
    59
        switch (msg->payload.present) {
edouard@1172
    60
            case DeviceGroup_Protocol__payload_PR_beacon:
edouard@1172
    61
                event = Beacon;
edouard@1172
    62
                break;
vb@1059
    63
edouard@1172
    64
            case DeviceGroup_Protocol__payload_PR_handshakeRequest:
edouard@1575
    65
                // re-check uuid in case sync_uuid changed while in the queue
edouard@1575
    66
                if (strncmp(session->sync_uuid,
edouard@1585
    67
                            (const char *)msg->payload.choice.handshakeRequest.partner_id->buf,
edouard@1585
    68
                            msg->payload.choice.handshakeRequest.partner_id->size) != 0){
edouard@1575
    69
                    status = PEP_SYNC_ILLEGAL_MESSAGE;
edouard@1575
    70
                    goto error;
edouard@1575
    71
                }
edouard@1586
    72
edouard@1586
    73
                if(msgIsFromGroup) {
edouard@1586
    74
                    char *devgrp = NULL;
edouard@1586
    75
                    status = get_device_group(session, &devgrp);
edouard@1586
    76
edouard@1586
    77
                    // if handshake request comes from same group ignore, ignore it
edouard@1586
    78
                    if (status == PEP_STATUS_OK && devgrp && devgrp[0] &&
edouard@1586
    79
                        strncmp(devgrp,
edouard@1586
    80
                                (const char *)msg->payload.choice.handshakeRequest.group_id->buf,
edouard@1586
    81
                                msg->payload.choice.handshakeRequest.group_id->size) != 0){
edouard@1586
    82
                        status = PEP_SYNC_ILLEGAL_MESSAGE;
edouard@1586
    83
                        goto error;
edouard@1586
    84
                    }
edouard@1586
    85
                    free(devgrp);
edouard@1586
    86
                    // if it comes from another group, then this is groupmerge
edouard@1586
    87
                }
edouard@1586
    88
edouard@1316
    89
                event = HandshakeRequest;
edouard@1316
    90
                break;
edouard@1256
    91
edouard@1316
    92
            case DeviceGroup_Protocol__payload_PR_updateRequest:
edouard@1316
    93
                event = UpdateRequest;
edouard@1172
    94
                break;
vb@1059
    95
edouard@1172
    96
            case DeviceGroup_Protocol__payload_PR_groupKeys:
edouard@1586
    97
            {
edouard@1575
    98
                // re-check uuid in case sync_uuid changed while in the queue
edouard@1575
    99
                if (strncmp(session->sync_uuid,
edouard@1585
   100
                            (const char *)msg->payload.choice.groupKeys.partner_id->buf,
edouard@1585
   101
                            msg->payload.choice.groupKeys.partner_id->size) != 0){
edouard@1575
   102
                    status = PEP_SYNC_ILLEGAL_MESSAGE;
edouard@1575
   103
                    goto error;
edouard@1575
   104
                }
edouard@1586
   105
                group_keys_extra_t *group_keys_extra;
edouard@1586
   106
                group_keys_extra = malloc(sizeof(group_keys_extra_t));
edouard@1586
   107
                if(group_keys_extra == NULL){
edouard@1586
   108
                    status = PEP_OUT_OF_MEMORY;
edouard@1586
   109
                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
edouard@1586
   110
                    goto error;
edouard@1586
   111
                }
edouard@1586
   112
edouard@1586
   113
                char *group_id = strndup(
edouard@1586
   114
                        (char*)msg->payload.choice.groupKeys.group_id->buf,
edouard@1586
   115
                        msg->payload.choice.groupKeys.group_id->size);
edouard@1586
   116
edouard@1586
   117
                if (msg->payload.choice.groupKeys.group_id && !group_id){
edouard@1586
   118
                    status = PEP_OUT_OF_MEMORY;
edouard@1586
   119
                    free(group_keys_extra);
edouard@1586
   120
                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
edouard@1586
   121
                    goto error;
edouard@1586
   122
                }
edouard@1586
   123
                group_keys_extra->group_id = group_id;
edouard@1586
   124
edouard@1172
   125
                identity_list *group_keys = IdentityList_to_identity_list(
edouard@1281
   126
                        msg->payload.present == 
edouard@1281
   127
                          DeviceGroup_Protocol__payload_PR_groupKeys ?
edouard@1297
   128
                            &msg->payload.choice.groupKeys.ownIdentities :
edouard@1297
   129
                            &msg->payload.choice.groupUpdate.ownIdentities,
edouard@1281
   130
                        NULL);
edouard@1172
   131
                if (!group_keys) {
edouard@1172
   132
                    status = PEP_OUT_OF_MEMORY;
edouard@1586
   133
                    free(group_id);
edouard@1586
   134
                    free(group_keys_extra);
edouard@1586
   135
                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
edouard@1586
   136
                    goto error;
edouard@1586
   137
                }
edouard@1586
   138
                group_keys_extra->group_keys = group_keys;
edouard@1586
   139
edouard@1586
   140
                extra = (void *) group_keys_extra;
edouard@1586
   141
edouard@1586
   142
                break;
edouard@1586
   143
            }
edouard@1586
   144
            case DeviceGroup_Protocol__payload_PR_groupUpdate:
edouard@1586
   145
            {
edouard@1586
   146
                identity_list *group_keys = IdentityList_to_identity_list(
edouard@1586
   147
                        &msg->payload.choice.groupUpdate.ownIdentities, NULL);
edouard@1586
   148
                if (!group_keys) {
edouard@1586
   149
                    status = PEP_OUT_OF_MEMORY;
edouard@1172
   150
                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
edouard@1172
   151
                    goto error;
edouard@1172
   152
                }
edouard@1172
   153
                extra = (void *) group_keys;
edouard@1586
   154
                event = GroupUpdate;
edouard@1172
   155
                break;
edouard@1316
   156
            }
edouard@1172
   157
edouard@1172
   158
            default:
edouard@1172
   159
                status = PEP_SYNC_ILLEGAL_MESSAGE;
edouard@1172
   160
                ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
edouard@1172
   161
                goto error;
edouard@1172
   162
        }
edouard@1316
   163
edouard@1316
   164
        partner = Identity_to_Struct(&msg->header.me, NULL);
edouard@1316
   165
        if (!partner){
edouard@1316
   166
            status = PEP_OUT_OF_MEMORY;
edouard@1316
   167
            ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
edouard@1316
   168
            goto error;
edouard@1316
   169
        }
edouard@1172
   170
    }
edouard@1172
   171
    else{
edouard@1172
   172
        partner = sync_msg->u.event.partner;
edouard@1172
   173
        extra = sync_msg->u.event.extra;
edouard@1172
   174
        event = sync_msg->u.event.event;
vb@1059
   175
    }
vb@1059
   176
edouard@1316
   177
    // Event inhibition, to limit mailbox and prevent cycles
edouard@1316
   178
    time_t *last = NULL;
edouard@1316
   179
    switch(event){
edouard@1316
   180
        case CannotDecrypt:
edouard@1316
   181
            last = &session->LastCannotDecrypt;
edouard@1316
   182
            break;
edouard@1316
   183
edouard@1316
   184
        case UpdateRequest:
edouard@1316
   185
            last = &session->LastUpdateRequest;
edouard@1316
   186
            break;
edouard@1316
   187
edouard@1316
   188
        default:
edouard@1316
   189
            break;
edouard@1316
   190
    }
edouard@1567
   191
edouard@1316
   192
    if(last != NULL){
edouard@1567
   193
        time_t now = time(NULL);
edouard@1316
   194
        if(*last != 0 && (*last + SYNC_INHIBIT_TIME) > now ){
edouard@1316
   195
            free_identity(partner);
edouard@1316
   196
            status = PEP_STATEMACHINE_INHIBITED_EVENT;
edouard@1316
   197
            goto error;
edouard@1316
   198
        }
edouard@1316
   199
        *last = now;
edouard@1316
   200
    }
edouard@1316
   201
edouard@1256
   202
    // partner identity must be explicitely added DB to later
edouard@1256
   203
    // be able to communicate securely with it.
edouard@1256
   204
    if(partner){
edouard@1260
   205
        // protect virtual user IDs 
edouard@1256
   206
        if((strncmp("TOFU_", partner->user_id, 6) == 0 &&
edouard@1256
   207
           strlen(partner->user_id) == strlen(partner->address) + 6 &&
edouard@1256
   208
           strcmp(partner->user_id + 6, partner->address)) ||
edouard@1260
   209
        // protect own ID 
edouard@1256
   210
           (strcmp(PEP_OWN_USERID, partner->user_id) == 0)){
edouard@1256
   211
            status = PEP_SYNC_ILLEGAL_MESSAGE;
edouard@1256
   212
            goto error;
edouard@1256
   213
        }
edouard@1256
   214
edouard@1260
   215
        // partner IDs are UUIDs bound to session lifespan
edouard@1256
   216
        // and therefore partner identities are not supposed
edouard@1260
   217
        // to mutate over time, but just not be used anymore.
edouard@1260
   218
        // It should then be safe to accept given identity if not 
edouard@1256
   219
        // already pre-existing
edouard@1256
   220
        pEp_identity *stored_identity = NULL;
edouard@1256
   221
        status = get_identity(session,
edouard@1256
   222
                              partner->address,
edouard@1256
   223
                              partner->user_id,
edouard@1256
   224
                              &stored_identity);
edouard@1256
   225
edouard@1256
   226
        if (!stored_identity) {
edouard@1260
   227
            // make a safe copy of partner, with no flags or comm_type
edouard@1260
   228
            pEp_identity *tmpident = new_identity(partner->address,
edouard@1260
   229
                                                  partner->fpr,
edouard@1260
   230
                                                  partner->user_id,
edouard@1260
   231
                                                  partner->username);
edouard@1260
   232
            if (tmpident == NULL){
edouard@1260
   233
                status = PEP_OUT_OF_MEMORY;
edouard@1260
   234
                goto error;
edouard@1260
   235
            }
edouard@1260
   236
edouard@1260
   237
            // finaly add partner to DB
edouard@1260
   238
            status = set_identity(session, tmpident);
edouard@1340
   239
            assert(status == PEP_STATUS_OK);
edouard@1340
   240
            if(status == PEP_STATUS_OK && msgIsFromGroup)
edouard@1340
   241
                status = set_identity_flags(session, tmpident, PEP_idf_devicegroup);
edouard@1260
   242
            free_identity(tmpident);
edouard@1256
   243
            assert(status == PEP_STATUS_OK);
edouard@1256
   244
            if (status != PEP_STATUS_OK) {
edouard@1256
   245
                goto error;
edouard@1256
   246
            }
edouard@1256
   247
        }
edouard@1256
   248
        else if (status == PEP_STATUS_OK) {
edouard@1256
   249
            free_identity(stored_identity);
edouard@1256
   250
        } 
edouard@1256
   251
        else
edouard@1256
   252
            goto error;
edouard@1256
   253
    }
edouard@1256
   254
edouard@1445
   255
    status = fsm_DeviceState_inject(session, event, partner, extra, timeout);
edouard@1157
   256
edouard@1157
   257
    free_identity(partner);
edouard@1157
   258
edouard@1172
   259
error:
edouard@1172
   260
    free(sync_msg);
edouard@1172
   261
edouard@1159
   262
    return status;
vb@1059
   263
}
vb@1059
   264
markus@1226
   265
// TODO: DYNAMIC_API was here, but broke the windows build. 
markus@1226
   266
// We need to check whether it belongs here or it's a bug.
markus@1226
   267
/* DYNAMIC_API */ void free_sync_msg(sync_msg_t *sync_msg)
Edouard@1203
   268
{
roker@1482
   269
    if (!sync_msg)
Edouard@1203
   270
        return;
Edouard@1203
   271
Edouard@1203
   272
    if(sync_msg->is_a_message){
Edouard@1203
   273
        DeviceGroup_Protocol_t *msg = sync_msg->u.message;
Edouard@1203
   274
        assert(msg);
Edouard@1203
   275
        if (!(msg))
Edouard@1203
   276
            return;
Edouard@1203
   277
Edouard@1203
   278
        ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
Edouard@1203
   279
    }
Edouard@1203
   280
    else{
Edouard@1203
   281
        Identity partner = NULL;
Edouard@1203
   282
        partner = sync_msg->u.event.partner;
Edouard@1203
   283
        if(partner != NULL)
Edouard@1203
   284
            free_identity(partner);
Edouard@1203
   285
    }
Edouard@1203
   286
Edouard@1203
   287
    free(sync_msg);
Edouard@1203
   288
Edouard@1203
   289
    return;
Edouard@1203
   290
}
Edouard@1203
   291
edouard@1167
   292
// from sync.c
edouard@1167
   293
int call_inject_sync_msg(PEP_SESSION session, void *msg);
edouard@1167
   294
edouard@1172
   295
PEP_STATUS inject_DeviceState_event(
edouard@1172
   296
    PEP_SESSION session, 
edouard@1172
   297
    DeviceState_event event,
edouard@1172
   298
    Identity partner,
edouard@1172
   299
    void *extra)
edouard@1172
   300
{
edouard@1172
   301
    PEP_STATUS status;
edouard@1172
   302
edouard@1172
   303
    assert(session);
edouard@1172
   304
    if (!(session))
edouard@1172
   305
        return PEP_ILLEGAL_VALUE;
edouard@1172
   306
edouard@1172
   307
    sync_msg_t *sync_msg = malloc(sizeof(sync_msg_t));
edouard@1172
   308
    if(sync_msg == NULL)
edouard@1172
   309
        return PEP_OUT_OF_MEMORY;
edouard@1172
   310
edouard@1172
   311
    sync_msg->is_a_message = false;
edouard@1172
   312
    sync_msg->u.event.partner = partner;
edouard@1172
   313
    sync_msg->u.event.extra = extra;
edouard@1172
   314
    sync_msg->u.event.event = event;
edouard@1172
   315
edouard@1172
   316
    status = call_inject_sync_msg(session, sync_msg);
edouard@1172
   317
    if (status == PEP_SYNC_NO_INJECT_CALLBACK){
edouard@1172
   318
        free(sync_msg);
edouard@1172
   319
    }
edouard@1172
   320
edouard@1172
   321
    return status;
edouard@1172
   322
}
edouard@1172
   323
edouard@1165
   324
PEP_STATUS receive_DeviceState_msg(
edouard@1165
   325
    PEP_SESSION session, 
edouard@1165
   326
    message *src, 
edouard@1165
   327
    PEP_rating rating, 
edouard@1165
   328
    stringlist_t *keylist)
vb@1059
   329
{
vb@1059
   330
    assert(session && src);
vb@1059
   331
    if (!(session && src))
vb@1059
   332
        return PEP_ILLEGAL_VALUE;
vb@1059
   333
edouard@1339
   334
    bool consume = false;
edouard@1339
   335
    bool discard = false;
edouard@1248
   336
    bool force_keep_msg = false;
vb@1338
   337
vb@1059
   338
    for (bloblist_t *bl = src->attachments; bl && bl->value; bl = bl->next) {
vb@1132
   339
        if (bl->mime_type && strcasecmp(bl->mime_type, "application/pEp.sync") == 0
vb@1059
   340
                && bl->size) {
vb@1077
   341
            DeviceGroup_Protocol_t *msg = NULL;
vb@1091
   342
            uper_decode_complete(NULL, &asn_DEF_DeviceGroup_Protocol, (void **)
vb@1091
   343
                    &msg, bl->value, bl->size);
edouard@1248
   344
vb@1059
   345
            if (msg) {
edouard@1257
   346
                PEP_STATUS status = PEP_STATUS_OK;
vb@1088
   347
vb@1091
   348
                char *user_id = strndup((char *) msg->header.me.user_id->buf,
vb@1091
   349
                        msg->header.me.user_id->size);
vb@1091
   350
                assert(user_id);
vb@1091
   351
                if (!user_id) {
vb@1091
   352
                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
vb@1091
   353
                    return PEP_OUT_OF_MEMORY;
vb@1091
   354
                }
vb@1091
   355
edouard@1521
   356
                // detect and mitigate address spoofing
edouard@1521
   357
                Identity check_me = NULL;
edouard@1527
   358
                char* null_terminated_address = 
edouard@1521
   359
                    strndup((char *) msg->header.me.address->buf,
edouard@1521
   360
                            msg->header.me.address->size);
edouard@1521
   361
edouard@1527
   362
                if(null_terminated_address){
edouard@1527
   363
                    status = get_identity(session, 
edouard@1527
   364
                                          null_terminated_address, 
edouard@1527
   365
                                          PEP_OWN_USERID, 
edouard@1527
   366
                                          &check_me);
edouard@1527
   367
                    free(null_terminated_address);
edouard@1527
   368
                } 
edouard@1527
   369
                else
edouard@1527
   370
                    status = PEP_OUT_OF_MEMORY;
edouard@1521
   371
edouard@1521
   372
                if (status == PEP_OUT_OF_MEMORY)
edouard@1521
   373
                    goto free_all;
edouard@1521
   374
edouard@1521
   375
                free_identity(check_me);
edouard@1521
   376
edouard@1521
   377
                bool not_own_address = status != PEP_STATUS_OK;
edouard@1521
   378
                status = PEP_STATUS_OK;
edouard@1521
   379
edouard@1521
   380
                if (not_own_address || 
edouard@1521
   381
                    strncmp(src->from->address,
edouard@1521
   382
                            (char *) msg->header.me.address->buf,
edouard@1521
   383
                            msg->header.me.address->size) != 0 ||
edouard@1521
   384
                    strncmp(src->to->ident->address,
edouard@1521
   385
                            (char *) msg->header.me.address->buf,
edouard@1521
   386
                            msg->header.me.address->size) != 0) {
edouard@1521
   387
                    consume = true;
edouard@1521
   388
                    goto free_all;
edouard@1521
   389
                }
edouard@1521
   390
edouard@1521
   391
                // if encrypted, ensure that header.me.fpr match signer's fpr
edouard@1521
   392
                if (rating >= PEP_rating_reliable && (
edouard@1521
   393
                        !keylist ||
edouard@1521
   394
                        !_same_fpr((char *) msg->header.me.fpr.buf,
edouard@1521
   395
                                   msg->header.me.fpr.size,
edouard@1521
   396
                                   keylist->value,
edouard@1521
   397
                                   strlen(keylist->value)))) {
edouard@1521
   398
                    consume = true;
edouard@1521
   399
                    goto free_all;
edouard@1521
   400
                }
edouard@1521
   401
edouard@1248
   402
                // check message expiry 
edouard@1257
   403
                if(src->recv) {
edouard@1316
   404
                    time_t expiry = timegm(src->recv) + SYNC_MSG_EXPIRE_TIME;
edouard@1257
   405
                    time_t now = time(NULL);
edouard@1257
   406
                    if(expiry != 0 && now != 0 && expiry < now){
edouard@1339
   407
                        consume = true;
edouard@1257
   408
                        goto free_all;
edouard@1257
   409
                    }
edouard@1165
   410
                }
edouard@1165
   411
edouard@1248
   412
                int32_t value = (int32_t) msg->header.sequence;
edouard@1568
   413
                if (value < 1) {
edouard@1568
   414
                    status = PEP_SEQUENCE_VIOLATED;
edouard@1568
   415
                } else {
edouard@1568
   416
                    status = sequence_value(session, (char *) user_id,
edouard@1568
   417
                            &value);
edouard@1568
   418
                }
vb@1088
   419
vb@1088
   420
                if (status == PEP_STATUS_OK) {
edouard@1248
   421
                    switch (msg->payload.present) {
edouard@1248
   422
                        // HandshakeRequest needs encryption
edouard@1248
   423
                        case DeviceGroup_Protocol__payload_PR_handshakeRequest:
edouard@1248
   424
                            if (rating < PEP_rating_reliable ||
edouard@1248
   425
                                strncmp(session->sync_uuid,
edouard@1585
   426
                                        (const char *)msg->payload.choice.handshakeRequest.partner_id->buf,
edouard@1585
   427
                                        msg->payload.choice.handshakeRequest.partner_id->size) != 0){
edouard@1339
   428
                                discard = true;
edouard@1256
   429
                                goto free_all;
edouard@1248
   430
                            }
edouard@1339
   431
                            
edouard@1248
   432
                            break;
edouard@1297
   433
                        // accepting GroupKeys needs encryption and trust of peer device
edouard@1248
   434
                        case DeviceGroup_Protocol__payload_PR_groupKeys:
edouard@1297
   435
                        {
edouard@1248
   436
                            if (!keylist || rating < PEP_rating_reliable ||
edouard@1297
   437
                                // message is only consumed by instance it is addressed to
edouard@1297
   438
                                (strncmp(session->sync_uuid,
edouard@1585
   439
                                        (const char *)msg->payload.choice.groupKeys.partner_id->buf,
edouard@1585
   440
                                        msg->payload.choice.groupKeys.partner_id->size) != 0)){
edouard@1339
   441
                                discard = true;
edouard@1256
   442
                                goto free_all;
edouard@1248
   443
                            }
edouard@1248
   444
edouard@1523
   445
                            // check trust of identity using user_id given in msg.header.me
edouard@1297
   446
                            // to exacly match identity of device, the one trusted in
edouard@1297
   447
                            // case of accepted handshake
edouard@1297
   448
                            pEp_identity *_from = new_identity(NULL, 
edouard@1248
   449
                                                               keylist->value,
edouard@1248
   450
                                                               user_id,
edouard@1297
   451
                                                               NULL);
edouard@1248
   452
                            if (_from == NULL){
edouard@1248
   453
                                status = PEP_OUT_OF_MEMORY;
edouard@1256
   454
                                goto free_all;
edouard@1248
   455
                            }
edouard@1297
   456
                            status = get_trust(session, _from);
edouard@1368
   457
                            if (status != PEP_STATUS_OK || _from->comm_type < PEP_ct_strong_encryption) {
edouard@1368
   458
                                status = PEP_STATUS_OK;
edouard@1297
   459
                                free_identity(_from);
edouard@1339
   460
                                discard = true;
edouard@1256
   461
                                goto free_all;
edouard@1248
   462
                            }
edouard@1297
   463
                            free_identity(_from);
edouard@1248
   464
                            break;
edouard@1297
   465
                        }
edouard@1297
   466
                        case DeviceGroup_Protocol__payload_PR_groupUpdate:
edouard@1316
   467
                        case DeviceGroup_Protocol__payload_PR_updateRequest:
edouard@1316
   468
                        {
edouard@1297
   469
                            // inject message but don't consume it, so 
edouard@1297
   470
                            // that other group members can also be updated
edouard@1297
   471
                            force_keep_msg = true;
edouard@1297
   472
                            
edouard@1297
   473
                            if (!keylist || rating < PEP_rating_reliable){
edouard@1339
   474
                                discard = true;
edouard@1297
   475
                                goto free_all;
edouard@1297
   476
                            }
edouard@1297
   477
                            // GroupUpdate and UpdateRequests come from group.
edouard@1297
   478
                            // check trust relation in between signer key and 
edouard@1297
   479
                            // own id to be sure.
edouard@1297
   480
                            pEp_identity *_from = new_identity(NULL, 
edouard@1297
   481
                                                               keylist->value,
edouard@1297
   482
                                                               PEP_OWN_USERID,
edouard@1297
   483
                                                               NULL);
edouard@1297
   484
                            if (_from == NULL){
edouard@1297
   485
                                status = PEP_OUT_OF_MEMORY;
edouard@1297
   486
                                goto free_all;
edouard@1297
   487
                            }
edouard@1297
   488
                            status = get_trust(session, _from);
edouard@1368
   489
                            if (status != PEP_STATUS_OK || _from->comm_type < PEP_ct_pEp) {
edouard@1368
   490
                                status = PEP_STATUS_OK;
edouard@1297
   491
                                free_identity(_from);
edouard@1339
   492
                                discard = true;
edouard@1297
   493
                                goto free_all;
edouard@1297
   494
                            }
edouard@1297
   495
                            free_identity(_from);
edouard@1297
   496
                        }
edouard@1248
   497
                        default:
edouard@1248
   498
                            break;
edouard@1248
   499
                    }
edouard@1248
   500
edouard@1248
   501
edouard@1339
   502
                    consume = true;
edouard@1172
   503
                    sync_msg_t *sync_msg = malloc(sizeof(sync_msg_t));
edouard@1172
   504
                    if(sync_msg == NULL){
edouard@1248
   505
                        status = PEP_OUT_OF_MEMORY;
edouard@1256
   506
                        goto free_all;
edouard@1172
   507
                    }
edouard@1172
   508
                    sync_msg->is_a_message = true;
edouard@1172
   509
                    sync_msg->u.message = msg;
edouard@1172
   510
                    status = call_inject_sync_msg(session, sync_msg);
edouard@1165
   511
                    if (status != PEP_STATUS_OK){
edouard@1172
   512
                        if (status == PEP_SYNC_NO_INJECT_CALLBACK){
edouard@1172
   513
                            free(sync_msg);
edouard@1172
   514
                        }
edouard@1256
   515
                        goto free_all;
edouard@1165
   516
                    }
edouard@1339
   517
                    // don't free message now that it is in the queue
edouard@1256
   518
                    goto free_userid;
edouard@1165
   519
                }
edouard@1165
   520
                else if (status == PEP_OWN_SEQUENCE) {
edouard@1248
   521
                    status = PEP_STATUS_OK;
edouard@1339
   522
                    discard = true;
edouard@1256
   523
                    goto free_all;
vb@1088
   524
                }
edouard@1248
   525
edouard@1256
   526
            free_all:
edouard@1248
   527
                ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
edouard@1256
   528
            free_userid:
edouard@1248
   529
                free(user_id);
edouard@1248
   530
edouard@1248
   531
                if (status != PEP_STATUS_OK)
edouard@1248
   532
                    return status;
vb@1059
   533
            }
vb@1059
   534
        }
vb@1059
   535
    }
vb@1059
   536
edouard@1248
   537
    if (force_keep_msg) {
edouard@1369
   538
        return PEP_MESSAGE_IGNORE;
edouard@1248
   539
    }
edouard@1248
   540
edouard@1339
   541
    if (consume && !session->keep_sync_msg) {
vb@1059
   542
        for (stringpair_list_t *spl = src->opt_fields ; spl && spl->value ;
vb@1059
   543
                spl = spl->next) {
vb@1059
   544
            if (spl->value->key &&
vb@1059
   545
                    strcasecmp(spl->value->key, "pEp-auto-consume") == 0) {
vb@1059
   546
                if (spl->value->value &&
vb@1059
   547
                        strcasecmp(spl->value->value, "yes") == 0)
edouard@1369
   548
                    return PEP_MESSAGE_CONSUME;
vb@1059
   549
            }
vb@1059
   550
        }
edouard@1369
   551
        return PEP_MESSAGE_IGNORE;
vb@1059
   552
    }
vb@1059
   553
edouard@1339
   554
    if(discard)
edouard@1369
   555
        return PEP_MESSAGE_IGNORE;
edouard@1248
   556
vb@1338
   557
    if (!session->keep_sync_msg) {
vb@1338
   558
        bloblist_t *last = NULL;
vb@1338
   559
        for (bloblist_t *bl = src->attachments; bl && bl->value; ) {
vb@1338
   560
            if (bl->mime_type && strcasecmp(bl->mime_type, "application/pEp.sync") == 0) {
vb@1338
   561
                bloblist_t *b = bl;
vb@1338
   562
                bl = bl->next;
vb@1338
   563
                if (!last)
vb@1338
   564
                    src->attachments = bl;
vb@1338
   565
                else
vb@1338
   566
                    last->next = bl;
vb@1338
   567
                free(b->mime_type);
vb@1338
   568
                free(b->filename);
vb@1338
   569
                free(b->value);
vb@1338
   570
                free(b);
vb@1338
   571
            }
vb@1338
   572
            else {
vb@1338
   573
                last = bl;
vb@1338
   574
                bl = bl->next;
vb@1338
   575
            }
vb@1338
   576
        }
vb@1338
   577
    }
vb@1338
   578
vb@1059
   579
    return PEP_STATUS_OK;
vb@1059
   580
}
vb@1059
   581
vb@1059
   582
DeviceGroup_Protocol_t *new_DeviceGroup_Protocol_msg(DeviceGroup_Protocol__payload_PR type)
vb@1059
   583
{
vb@1059
   584
    DeviceGroup_Protocol_t *msg = (DeviceGroup_Protocol_t *)
vb@1073
   585
            calloc(1, sizeof(DeviceGroup_Protocol_t));
vb@1059
   586
    assert(msg);
vb@1059
   587
    if (!msg)
vb@1059
   588
        return NULL;
vb@1059
   589
    msg->payload.present = type;
vb@1059
   590
    return msg;
vb@1059
   591
}
vb@1059
   592
vb@1059
   593
void free_DeviceGroup_Protocol_msg(DeviceGroup_Protocol_t *msg)
vb@1059
   594
{
vb@1059
   595
    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
vb@1059
   596
}
vb@1059
   597
Edouard@1495
   598
Edouard@1495
   599
#ifndef NDEBUG
Edouard@1495
   600
static int _append(const void *buffer, size_t size, void *appkey)
edouard@1494
   601
{
edouard@1494
   602
    char **dest_ptr = (char **)appkey;
edouard@1494
   603
    size_t osize = strlen(*dest_ptr);
edouard@1494
   604
    size_t nsize = size + osize;
edouard@1494
   605
    *dest_ptr = realloc(*dest_ptr, nsize + 1);
edouard@1494
   606
    if(*dest_ptr == NULL) return -1;
edouard@1494
   607
    memcpy(*dest_ptr + osize, buffer, size);
edouard@1494
   608
    (*dest_ptr)[nsize] = '\0';
edouard@1494
   609
    return 0;
edouard@1494
   610
}
Edouard@1495
   611
#endif
edouard@1494
   612
vb@1059
   613
PEP_STATUS unicast_msg(
vb@1059
   614
        PEP_SESSION session,
vb@1091
   615
        const Identity partner,
vb@1059
   616
        DeviceState_state state,
vb@1097
   617
        DeviceGroup_Protocol_t *msg,
vb@1097
   618
        bool encrypted
vb@1059
   619
    )
vb@1059
   620
{
vb@1059
   621
    PEP_STATUS status = PEP_STATUS_OK;
vb@1059
   622
    char *payload = NULL;
vb@1059
   623
    message *_message = NULL;
vb@1059
   624
    pEp_identity *me = NULL;
vb@1088
   625
    pEp_identity *_me = NULL;
vb@1059
   626
vb@1059
   627
    assert(session && partner && state && msg);
vb@1059
   628
    if (!(session && partner && state && msg))
vb@1059
   629
        return PEP_ILLEGAL_VALUE;
vb@1059
   630
vb@1059
   631
    assert(session->messageToSend);
vb@1059
   632
    if (!session->messageToSend) {
vb@1059
   633
        status = PEP_SEND_FUNCTION_NOT_REGISTERED;
vb@1059
   634
        goto error;
vb@1059
   635
    }
vb@1059
   636
vb@1077
   637
    msg->header.version.major = SYNC_VERSION_MAJOR;
vb@1077
   638
    msg->header.version.minor = SYNC_VERSION_MINOR;
vb@1077
   639
vb@1071
   640
    status = get_identity(session, partner->address, PEP_OWN_USERID, &me);
vb@1059
   641
    if (status != PEP_STATUS_OK)
vb@1059
   642
        goto error;
vb@1088
   643
    
vb@1088
   644
    int32_t seq = 0;
vb@1088
   645
edouard@1236
   646
    status = sequence_value(session, session->sync_uuid, &seq);
vb@1088
   647
    if (status != PEP_OWN_SEQUENCE && status != PEP_STATUS_OK)
vb@1088
   648
        goto error;
vb@1088
   649
vb@1088
   650
    msg->header.sequence = (long) seq;
vb@1088
   651
vb@1088
   652
    _me = identity_dup(me);
vb@1088
   653
    if (!_me)
vb@1059
   654
        goto enomem;
vb@1059
   655
vb@1088
   656
    free(_me->user_id);
edouard@1236
   657
    _me->user_id = strndup(session->sync_uuid, 36);
vb@1088
   658
    assert(_me->user_id);
vb@1088
   659
    if (!_me->user_id)
vb@1088
   660
        goto enomem;
vb@1088
   661
vb@1088
   662
    if (Identity_from_Struct(_me, &msg->header.me) == NULL)
vb@1088
   663
        goto enomem;
vb@1088
   664
vb@1088
   665
    free_identity(_me);
vb@1088
   666
    _me = NULL;
vb@1088
   667
vb@1077
   668
    msg->header.state = (long) state;
vb@1077
   669
edouard@1574
   670
    bool devicegroup = deviceGrouped(session);
vb@1077
   671
    if (devicegroup)
vb@1077
   672
        msg->header.devicegroup = 1;
vb@1077
   673
    else
vb@1077
   674
        msg->header.devicegroup = 0;
vb@1077
   675
vb@1059
   676
    if (asn_check_constraints(&asn_DEF_DeviceGroup_Protocol, msg, NULL, NULL)) {
vb@1059
   677
        status = PEP_CONTRAINTS_VIOLATED;
vb@1059
   678
        goto error;
vb@1059
   679
    }
vb@1059
   680
vb@1059
   681
    ssize_t size = uper_encode_to_new_buffer(&asn_DEF_DeviceGroup_Protocol,
vb@1059
   682
            NULL, msg, (void **) &payload);
vb@1059
   683
    if (size == -1) {
vb@1059
   684
        status = PEP_CANNOT_ENCODE;
vb@1059
   685
        goto error;
vb@1059
   686
    }
vb@1059
   687
vb@1059
   688
    status = prepare_message(me, partner, payload, size, &_message);
vb@1059
   689
    if (status != PEP_STATUS_OK)
vb@1059
   690
        goto error;
vb@1059
   691
    payload = NULL;
vb@1059
   692
    free_identity(me);
vb@1059
   693
    me = NULL;
vb@1059
   694
edouard@1494
   695
#ifndef NDEBUG
edouard@1494
   696
    asn_enc_rval_t er;
edouard@1494
   697
    er = xer_encode(&asn_DEF_DeviceGroup_Protocol, msg, 
edouard@1494
   698
                    XER_F_BASIC, _append, &_message->longmsg);
edouard@1494
   699
    if(er.encoded == -1)
edouard@1494
   700
        goto error;
edouard@1494
   701
#endif
edouard@1494
   702
vb@1097
   703
    if (encrypted) {
edouard@1386
   704
        if (msg->payload.present == DeviceGroup_Protocol__payload_PR_groupKeys || 
edouard@1386
   705
            msg->payload.present == DeviceGroup_Protocol__payload_PR_groupUpdate) {
vb@1101
   706
            PEP_rating rating = PEP_rating_undefined;
vb@1101
   707
            status = outgoing_message_rating(session, _message, &rating);
vb@1101
   708
            if (status != PEP_STATUS_OK)
vb@1101
   709
                goto error;
vb@1101
   710
            if (rating < PEP_rating_trusted) {
vb@1101
   711
                status = PEP_SYNC_NO_TRUST;
vb@1101
   712
                goto error;
vb@1101
   713
            }
edouard@1386
   714
            
edouard@1364
   715
            stringlist_t *keylist = NULL;
edouard@1412
   716
            status = _own_keys_retrieve(session, &keylist, PEP_idf_not_for_sync);
edouard@1364
   717
            if (status != PEP_STATUS_OK)
edouard@1364
   718
                goto error;
edouard@1281
   719
edouard@1364
   720
            for (stringlist_t *_keylist=keylist; _keylist!=NULL; _keylist=_keylist->next) {
edouard@1364
   721
                char *fpr = _keylist->value;
vb@1133
   722
                static char filename[MAX_LINELENGTH];
vb@1133
   723
                int result = snprintf(filename, MAX_LINELENGTH, "%s-sec.asc", fpr);
vb@1133
   724
                if (result < 0)
vb@1133
   725
                    goto enomem;
vb@1133
   726
                char *key = NULL;
vb@1133
   727
                size_t size = 0;
vb@1133
   728
                status = export_secrect_key(session, fpr, &key, &size);
vb@1133
   729
                if (status != PEP_STATUS_OK)
vb@1133
   730
                    goto error;
vb@1104
   731
                bloblist_t *bl = bloblist_add(_message->attachments,
vb@1133
   732
                        (char *) key, size, "application/pgp-keys", filename);
vb@1104
   733
                if (!bl)
vb@1104
   734
                    goto enomem;
vb@1104
   735
                if (!_message->attachments)
vb@1104
   736
                    _message->attachments = bl;
vb@1104
   737
            }
vb@1101
   738
        }
vb@1101
   739
vb@1097
   740
        message *_encrypted = NULL;
vb@1097
   741
        status = encrypt_message(session, _message, NULL, &_encrypted, PEP_enc_PEP, 0);
vb@1097
   742
        if (status != PEP_STATUS_OK)
vb@1097
   743
            goto error;
vb@1097
   744
        free_message(_message);
vb@1097
   745
        _message = _encrypted;
vb@1097
   746
    }
vb@1131
   747
    else {
vb@1131
   748
        attach_own_key(session, _message);
vb@1131
   749
    }
vb@1059
   750
vb@1097
   751
    status = session->messageToSend(session->sync_obj, _message);
vb@1059
   752
    return status;
vb@1059
   753
vb@1059
   754
enomem:
vb@1059
   755
    status = PEP_OUT_OF_MEMORY;
vb@1059
   756
error:
vb@1088
   757
    free_identity(_me);
vb@1059
   758
    free(payload);
vb@1059
   759
    free_message(_message);
vb@1059
   760
    free_identity(me);
vb@1059
   761
    return status;
vb@1059
   762
}
vb@1059
   763
vb@1059
   764
PEP_STATUS multicast_self_msg(
vb@1059
   765
        PEP_SESSION session,
vb@1059
   766
        DeviceState_state state,
vb@1097
   767
        DeviceGroup_Protocol_t *msg,
vb@1097
   768
        bool encrypted
vb@1059
   769
    )
vb@1059
   770
{
vb@1059
   771
    PEP_STATUS status = PEP_STATUS_OK;
vb@1059
   772
vb@1059
   773
    assert(session && state && msg);
vb@1059
   774
    if (!(session && state && msg))
vb@1059
   775
        return PEP_ILLEGAL_VALUE;
vb@1059
   776
vb@1059
   777
    identity_list *own_identities = NULL;
edouard@1412
   778
    status = _own_identities_retrieve(session, &own_identities, PEP_idf_not_for_sync);
vb@1059
   779
    if (status != PEP_STATUS_OK)
vb@1059
   780
        return status;
vb@1059
   781
vb@1059
   782
    for (identity_list *_i = own_identities; _i && _i->ident; _i = _i->next) {
vb@1091
   783
        pEp_identity *me = _i->ident;
vb@1059
   784
vb@1065
   785
        // FIXME: no deep copy for multicast supported yet
edouard@1281
   786
        // DeviceGroup_Protocol_t *_msg = malloc(sizeof(DeviceGroup_Protocol_t));
edouard@1281
   787
        // assert(_msg);
edouard@1281
   788
        // if (_msg == NULL){
edouard@1281
   789
        //     status = PEP_OUT_OF_MEMORY;
edouard@1281
   790
        //     goto error;
edouard@1281
   791
        // }
edouard@1281
   792
        // memcpy(_msg, msg, sizeof(DeviceGroup_Protocol_t));
edouard@1281
   793
        status = unicast_msg(session, me, state, msg, encrypted);
edouard@1281
   794
        //status = unicast_msg(session, me, state, _msg, encrypted);
edouard@1281
   795
        //free_DeviceGroup_Protocol_msg(_msg);
vb@1059
   796
    }
vb@1059
   797
vb@1059
   798
    free_identity_list(own_identities);
vb@1059
   799
    return PEP_STATUS_OK;
vb@1065
   800
edouard@1281
   801
// error:
edouard@1281
   802
//     free_identity_list(own_identities);
edouard@1281
   803
//     return status;
vb@1059
   804
}
vb@1059
   805