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