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