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