src/sync_impl.c
author Edouard Tisserant <edouard@pep-project.org>
Wed, 05 Oct 2016 18:18:41 +0200
changeset 1248 c332c47fe26e
parent 1242 e7b0ff022963
child 1256 8bc2e3636021
permissions -rw-r--r--
KEYSYNC: Added arbitrary hard coded sync message expiry (10m), and made special case when receiving groupKeys message so that they are not consumed giving a chance to other devices in the group to receive it as well.
vb@1059
     1
#include "../asn.1/DeviceGroup-Protocol.h"
vb@1059
     2
#include "sync_impl.h"
vb@1059
     3
#include "pEp_internal.h"
vb@1059
     4
#include "keymanagement.h"
vb@1076
     5
#include "message_api.h"
vb@1059
     6
#include "map_asn1.h"
vb@1059
     7
#include "baseprotocol.h"
vb@1059
     8
vb@1077
     9
#define SYNC_VERSION_MAJOR 1
vb@1077
    10
#define SYNC_VERSION_MINOR 0
vb@1077
    11
edouard@1172
    12
struct _sync_msg_t {
edouard@1172
    13
    bool is_a_message;
edouard@1172
    14
    union {
edouard@1172
    15
        DeviceGroup_Protocol_t *message;
edouard@1172
    16
        struct {
edouard@1172
    17
            DeviceState_event event;
edouard@1172
    18
            Identity partner;
edouard@1172
    19
            void *extra;
edouard@1172
    20
        } event;
edouard@1172
    21
    } u;
edouard@1172
    22
};
edouard@1172
    23
vb@1059
    24
PEP_STATUS receive_sync_msg(
vb@1059
    25
        PEP_SESSION session,
edouard@1172
    26
        sync_msg_t *sync_msg
vb@1059
    27
    )
vb@1059
    28
{
edouard@1172
    29
    PEP_STATUS status;
vb@1059
    30
    void *extra = NULL;
vb@1059
    31
    Identity partner = NULL;
vb@1059
    32
    DeviceState_event event = DeviceState_event_NONE;
edouard@1172
    33
    assert(session && sync_msg);
edouard@1172
    34
    if (!(session && sync_msg))
edouard@1172
    35
        return PEP_ILLEGAL_VALUE;
vb@1059
    36
edouard@1172
    37
    if(sync_msg->is_a_message){
edouard@1172
    38
        DeviceGroup_Protocol_t *msg = sync_msg->u.message;
edouard@1172
    39
        assert(msg && msg->payload.present != DeviceGroup_Protocol__payload_PR_NOTHING);
edouard@1172
    40
        if (!(msg && msg->payload.present != DeviceGroup_Protocol__payload_PR_NOTHING)){
edouard@1172
    41
            status = PEP_OUT_OF_MEMORY;
edouard@1172
    42
            goto error;
edouard@1172
    43
        }
vb@1059
    44
edouard@1172
    45
        switch (msg->payload.present) {
edouard@1172
    46
            case DeviceGroup_Protocol__payload_PR_beacon:
edouard@1172
    47
                partner = Identity_to_Struct(&msg->header.me, NULL);
edouard@1172
    48
                if (!partner){
edouard@1172
    49
                    status = PEP_OUT_OF_MEMORY;
edouard@1172
    50
                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
edouard@1172
    51
                    goto error;
edouard@1172
    52
                }
edouard@1172
    53
                event = Beacon;
edouard@1172
    54
                break;
vb@1059
    55
edouard@1172
    56
            case DeviceGroup_Protocol__payload_PR_handshakeRequest:
edouard@1172
    57
                partner = Identity_to_Struct(&msg->header.me, NULL);
edouard@1172
    58
                if (!partner){
edouard@1172
    59
                    status = PEP_OUT_OF_MEMORY;
edouard@1172
    60
                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
edouard@1172
    61
                    goto error;
edouard@1172
    62
                }
edouard@1172
    63
                event = HandshakeRequest;
edouard@1172
    64
                break;
vb@1059
    65
edouard@1172
    66
            case DeviceGroup_Protocol__payload_PR_groupKeys:
edouard@1172
    67
                partner = Identity_to_Struct(&msg->header.me, NULL);
edouard@1172
    68
                if (!partner){
edouard@1172
    69
                    status = PEP_OUT_OF_MEMORY;
edouard@1172
    70
                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
edouard@1172
    71
                    goto error;
edouard@1172
    72
                }
edouard@1172
    73
                identity_list *group_keys = IdentityList_to_identity_list(
edouard@1172
    74
                        &msg->payload.choice.groupKeys.ownIdentities, NULL);
edouard@1172
    75
                if (!group_keys) {
edouard@1172
    76
                    free_identity(partner);
edouard@1172
    77
                    status = PEP_OUT_OF_MEMORY;
edouard@1172
    78
                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
edouard@1172
    79
                    goto error;
edouard@1172
    80
                }
edouard@1172
    81
                extra = (void *) group_keys;
edouard@1172
    82
                event = GroupKeys;
edouard@1172
    83
                break;
edouard@1172
    84
edouard@1172
    85
            default:
edouard@1172
    86
                status = PEP_SYNC_ILLEGAL_MESSAGE;
edouard@1172
    87
                ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
edouard@1172
    88
                goto error;
edouard@1172
    89
        }
edouard@1172
    90
    }
edouard@1172
    91
    else{
edouard@1172
    92
        partner = sync_msg->u.event.partner;
edouard@1172
    93
        extra = sync_msg->u.event.extra;
edouard@1172
    94
        event = sync_msg->u.event.event;
vb@1059
    95
    }
vb@1059
    96
edouard@1172
    97
    status = fsm_DeviceState_inject(session, event, partner, extra);
edouard@1157
    98
edouard@1157
    99
    free_identity(partner);
edouard@1157
   100
edouard@1172
   101
error:
edouard@1172
   102
    free(sync_msg);
edouard@1172
   103
edouard@1159
   104
    return status;
vb@1059
   105
}
vb@1059
   106
markus@1226
   107
// TODO: DYNAMIC_API was here, but broke the windows build. 
markus@1226
   108
// We need to check whether it belongs here or it's a bug.
markus@1226
   109
/* DYNAMIC_API */ void free_sync_msg(sync_msg_t *sync_msg)
Edouard@1203
   110
{
Edouard@1203
   111
    assert(sync_msg);
Edouard@1203
   112
    if (!(sync_msg))
Edouard@1203
   113
        return;
Edouard@1203
   114
Edouard@1203
   115
    if(sync_msg->is_a_message){
Edouard@1203
   116
        DeviceGroup_Protocol_t *msg = sync_msg->u.message;
Edouard@1203
   117
        assert(msg);
Edouard@1203
   118
        if (!(msg))
Edouard@1203
   119
            return;
Edouard@1203
   120
Edouard@1203
   121
        ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
Edouard@1203
   122
    }
Edouard@1203
   123
    else{
Edouard@1203
   124
        Identity partner = NULL;
Edouard@1203
   125
        partner = sync_msg->u.event.partner;
Edouard@1203
   126
        if(partner != NULL)
Edouard@1203
   127
            free_identity(partner);
Edouard@1203
   128
    }
Edouard@1203
   129
Edouard@1203
   130
    free(sync_msg);
Edouard@1203
   131
Edouard@1203
   132
    return;
Edouard@1203
   133
}
Edouard@1203
   134
edouard@1167
   135
// from sync.c
edouard@1167
   136
int call_inject_sync_msg(PEP_SESSION session, void *msg);
edouard@1167
   137
edouard@1172
   138
PEP_STATUS inject_DeviceState_event(
edouard@1172
   139
    PEP_SESSION session, 
edouard@1172
   140
    DeviceState_event event,
edouard@1172
   141
    Identity partner,
edouard@1172
   142
    void *extra)
edouard@1172
   143
{
edouard@1172
   144
    PEP_STATUS status;
edouard@1172
   145
edouard@1172
   146
    assert(session);
edouard@1172
   147
    if (!(session))
edouard@1172
   148
        return PEP_ILLEGAL_VALUE;
edouard@1172
   149
edouard@1172
   150
    sync_msg_t *sync_msg = malloc(sizeof(sync_msg_t));
edouard@1172
   151
    if(sync_msg == NULL)
edouard@1172
   152
        return PEP_OUT_OF_MEMORY;
edouard@1172
   153
edouard@1172
   154
    sync_msg->is_a_message = false;
edouard@1172
   155
    sync_msg->u.event.partner = partner;
edouard@1172
   156
    sync_msg->u.event.extra = extra;
edouard@1172
   157
    sync_msg->u.event.event = event;
edouard@1172
   158
edouard@1172
   159
    status = call_inject_sync_msg(session, sync_msg);
edouard@1172
   160
    if (status == PEP_SYNC_NO_INJECT_CALLBACK){
edouard@1172
   161
        free(sync_msg);
edouard@1172
   162
    }
edouard@1172
   163
edouard@1172
   164
    return status;
edouard@1172
   165
}
edouard@1172
   166
edouard@1165
   167
PEP_STATUS receive_DeviceState_msg(
edouard@1165
   168
    PEP_SESSION session, 
edouard@1165
   169
    message *src, 
edouard@1165
   170
    PEP_rating rating, 
edouard@1165
   171
    stringlist_t *keylist)
vb@1059
   172
{
vb@1059
   173
    assert(session && src);
vb@1059
   174
    if (!(session && src))
vb@1059
   175
        return PEP_ILLEGAL_VALUE;
vb@1059
   176
vb@1059
   177
    bool found = false;
edouard@1248
   178
    bool expired = false;
edouard@1248
   179
    bool discarded = false;
edouard@1248
   180
    bool force_keep_msg = false;
vb@1092
   181
    
vb@1092
   182
    bloblist_t *last = NULL;
vb@1059
   183
    for (bloblist_t *bl = src->attachments; bl && bl->value; bl = bl->next) {
vb@1132
   184
        if (bl->mime_type && strcasecmp(bl->mime_type, "application/pEp.sync") == 0
vb@1059
   185
                && bl->size) {
vb@1077
   186
            DeviceGroup_Protocol_t *msg = NULL;
vb@1091
   187
            uper_decode_complete(NULL, &asn_DEF_DeviceGroup_Protocol, (void **)
vb@1091
   188
                    &msg, bl->value, bl->size);
edouard@1248
   189
vb@1059
   190
            if (msg) {
vb@1088
   191
vb@1091
   192
                char *user_id = strndup((char *) msg->header.me.user_id->buf,
vb@1091
   193
                        msg->header.me.user_id->size);
vb@1091
   194
                assert(user_id);
vb@1091
   195
                if (!user_id) {
vb@1091
   196
                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
vb@1091
   197
                    return PEP_OUT_OF_MEMORY;
vb@1091
   198
                }
vb@1091
   199
edouard@1248
   200
                // check message expiry 
edouard@1248
   201
                time_t expiry = GeneralizedTime_to_time_t(&msg->header.expiry);
edouard@1248
   202
                time_t now = time(NULL);
edouard@1248
   203
                if(expiry != 0 && now != 0 && expiry < now){
edouard@1248
   204
                    expired = true;
edouard@1248
   205
                    goto flush;
edouard@1165
   206
                }
edouard@1165
   207
edouard@1248
   208
                int32_t value = (int32_t) msg->header.sequence;
vb@1091
   209
                PEP_STATUS status = sequence_value(session, (char *) user_id,
vb@1091
   210
                        &value);
vb@1088
   211
vb@1088
   212
                if (status == PEP_STATUS_OK) {
edouard@1248
   213
                    switch (msg->payload.present) {
edouard@1248
   214
                        // HandshakeRequest needs encryption
edouard@1248
   215
                        case DeviceGroup_Protocol__payload_PR_handshakeRequest:
edouard@1248
   216
                            if (rating < PEP_rating_reliable ||
edouard@1248
   217
                                strncmp(session->sync_uuid,
edouard@1248
   218
                                        (const char *)msg->payload.choice.handshakeRequest.partner.user_id->buf,
edouard@1248
   219
                                        msg->payload.choice.handshakeRequest.partner.user_id->size) != 0){
edouard@1248
   220
                                discarded = true;
edouard@1248
   221
                                goto flush;
edouard@1248
   222
                            }
edouard@1248
   223
                            break;
edouard@1248
   224
                        // accepting GroupKeys needs encryption and trust
edouard@1248
   225
                        case DeviceGroup_Protocol__payload_PR_groupKeys:
edouard@1248
   226
                            if (!keylist || rating < PEP_rating_reliable ||
edouard@1248
   227
                                // if header.state is HandshakingSole, then
edouard@1248
   228
                                // group is just forming in between 2 devices
edouard@1248
   229
                                // message must be addressed to that instance
edouard@1248
   230
                                // to be consumed
edouard@1248
   231
                                (msg->header.state == HandshakingSole && 
edouard@1248
   232
                                 strncmp(session->sync_uuid,
edouard@1248
   233
                                        (const char *)msg->payload.choice.groupKeys.partner.user_id->buf,
edouard@1248
   234
                                        msg->payload.choice.groupKeys.partner.user_id->size) != 0)){
edouard@1248
   235
                                discarded = true;
edouard@1248
   236
                                goto flush;
edouard@1248
   237
                            }
edouard@1248
   238
edouard@1248
   239
                            // otherwise, when group keys are sent from a 
edouard@1248
   240
                            // pre-existing group, inject message but flag is 
edouard@1248
   241
                            // as discarded to prevent app to delete it, so 
edouard@1248
   242
                            // that other group members can also be updated
edouard@1248
   243
                            if(msg->header.state != HandshakingSole){
edouard@1248
   244
                                force_keep_msg = true;
edouard@1248
   245
                            }
edouard@1248
   246
edouard@1248
   247
                            // check trust of identity with the right user_id
edouard@1248
   248
                            pEp_identity *_from = new_identity(src->from->address, 
edouard@1248
   249
                                                               keylist->value,
edouard@1248
   250
                                                               user_id,
edouard@1248
   251
                                                               src->from->username);
edouard@1248
   252
                            if (_from == NULL){
edouard@1248
   253
                                status = PEP_OUT_OF_MEMORY;
edouard@1248
   254
                                goto flush;
edouard@1248
   255
                            }
edouard@1248
   256
                            PEP_rating this_user_id_rating = PEP_rating_undefined;
edouard@1248
   257
                            identity_rating(session, _from, &this_user_id_rating);
edouard@1248
   258
                            free_identity(_from);
edouard@1248
   259
edouard@1248
   260
                            if (this_user_id_rating < PEP_rating_trusted ) {
edouard@1248
   261
                                discarded = true;
edouard@1248
   262
                                goto flush;
edouard@1248
   263
                            }
edouard@1248
   264
                            break;
edouard@1248
   265
                        default:
edouard@1248
   266
                            break;
edouard@1248
   267
                    }
edouard@1248
   268
edouard@1248
   269
edouard@1165
   270
                    found = true;
edouard@1172
   271
                    sync_msg_t *sync_msg = malloc(sizeof(sync_msg_t));
edouard@1172
   272
                    if(sync_msg == NULL){
edouard@1248
   273
                        status = PEP_OUT_OF_MEMORY;
edouard@1248
   274
                        goto flush;
edouard@1172
   275
                    }
edouard@1172
   276
                    sync_msg->is_a_message = true;
edouard@1172
   277
                    sync_msg->u.message = msg;
edouard@1172
   278
                    status = call_inject_sync_msg(session, sync_msg);
edouard@1165
   279
                    if (status != PEP_STATUS_OK){
edouard@1172
   280
                        if (status == PEP_SYNC_NO_INJECT_CALLBACK){
edouard@1172
   281
                            free(sync_msg);
edouard@1172
   282
                        }
edouard@1248
   283
                        goto flush;
edouard@1165
   284
                    }
edouard@1165
   285
                }
edouard@1165
   286
                else if (status == PEP_OWN_SEQUENCE) {
edouard@1248
   287
                    status = PEP_STATUS_OK;
edouard@1248
   288
                    discarded = true;
edouard@1248
   289
                    goto flush;
vb@1088
   290
                }
edouard@1248
   291
edouard@1248
   292
            flush:
edouard@1248
   293
                ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
edouard@1248
   294
                free(user_id);
edouard@1248
   295
edouard@1248
   296
                if (status != PEP_STATUS_OK)
edouard@1248
   297
                    return status;
edouard@1248
   298
vb@1059
   299
            }
vb@1092
   300
vb@1110
   301
            if (!session->keep_sync_msg) {
vb@1110
   302
                bloblist_t *blob = bl;
vb@1110
   303
                if (last)
vb@1110
   304
                    last->next = bl->next;
vb@1110
   305
                else
vb@1110
   306
                    src->attachments = bl->next;
vb@1092
   307
vb@1110
   308
                blob->next = NULL;
vb@1110
   309
                free_bloblist(blob);
vb@1110
   310
            }
vb@1110
   311
            else {
vb@1110
   312
                last = bl;
vb@1110
   313
            }
vb@1092
   314
        }
vb@1092
   315
        else {
vb@1092
   316
            last = bl;
vb@1059
   317
        }
vb@1059
   318
    }
vb@1059
   319
edouard@1248
   320
    if (force_keep_msg) {
edouard@1248
   321
        return PEP_MESSAGE_DISCARDED;
edouard@1248
   322
    }
edouard@1248
   323
edouard@1248
   324
    if ((expired || found) && !session->keep_sync_msg) {
vb@1059
   325
        for (stringpair_list_t *spl = src->opt_fields ; spl && spl->value ;
vb@1059
   326
                spl = spl->next) {
vb@1059
   327
            if (spl->value->key &&
vb@1059
   328
                    strcasecmp(spl->value->key, "pEp-auto-consume") == 0) {
vb@1059
   329
                if (spl->value->value &&
vb@1059
   330
                        strcasecmp(spl->value->value, "yes") == 0)
vb@1059
   331
                    return PEP_MESSAGE_CONSUMED;
vb@1059
   332
            }
vb@1059
   333
        }
edouard@1248
   334
        return PEP_MESSAGE_DISCARDED;
vb@1059
   335
    }
vb@1059
   336
edouard@1248
   337
    if(discarded)
edouard@1248
   338
        return PEP_MESSAGE_DISCARDED;
edouard@1248
   339
vb@1059
   340
    return PEP_STATUS_OK;
vb@1059
   341
}
vb@1059
   342
vb@1059
   343
DeviceGroup_Protocol_t *new_DeviceGroup_Protocol_msg(DeviceGroup_Protocol__payload_PR type)
vb@1059
   344
{
vb@1059
   345
    DeviceGroup_Protocol_t *msg = (DeviceGroup_Protocol_t *)
vb@1073
   346
            calloc(1, sizeof(DeviceGroup_Protocol_t));
vb@1059
   347
    assert(msg);
vb@1059
   348
    if (!msg)
vb@1059
   349
        return NULL;
vb@1059
   350
    msg->payload.present = type;
vb@1059
   351
    return msg;
vb@1059
   352
}
vb@1059
   353
vb@1059
   354
void free_DeviceGroup_Protocol_msg(DeviceGroup_Protocol_t *msg)
vb@1059
   355
{
vb@1059
   356
    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
vb@1059
   357
}
vb@1059
   358
edouard@1248
   359
// Ten minutes
edouard@1248
   360
#define SYNC_MSG_EXPIRE_DELTA (60 * 10)
edouard@1248
   361
vb@1059
   362
PEP_STATUS unicast_msg(
vb@1059
   363
        PEP_SESSION session,
vb@1091
   364
        const Identity partner,
vb@1059
   365
        DeviceState_state state,
vb@1097
   366
        DeviceGroup_Protocol_t *msg,
vb@1097
   367
        bool encrypted
vb@1059
   368
    )
vb@1059
   369
{
vb@1059
   370
    PEP_STATUS status = PEP_STATUS_OK;
vb@1059
   371
    char *payload = NULL;
vb@1059
   372
    message *_message = NULL;
vb@1059
   373
    pEp_identity *me = NULL;
vb@1088
   374
    pEp_identity *_me = NULL;
vb@1059
   375
vb@1059
   376
    assert(session && partner && state && msg);
vb@1059
   377
    if (!(session && partner && state && msg))
vb@1059
   378
        return PEP_ILLEGAL_VALUE;
vb@1059
   379
vb@1059
   380
    assert(session->messageToSend);
vb@1059
   381
    if (!session->messageToSend) {
vb@1059
   382
        status = PEP_SEND_FUNCTION_NOT_REGISTERED;
vb@1059
   383
        goto error;
vb@1059
   384
    }
vb@1059
   385
vb@1077
   386
    msg->header.version.major = SYNC_VERSION_MAJOR;
vb@1077
   387
    msg->header.version.minor = SYNC_VERSION_MINOR;
vb@1077
   388
vb@1071
   389
    status = get_identity(session, partner->address, PEP_OWN_USERID, &me);
vb@1059
   390
    if (status != PEP_STATUS_OK)
vb@1059
   391
        goto error;
vb@1088
   392
    
vb@1088
   393
    int32_t seq = 0;
vb@1088
   394
edouard@1236
   395
    status = sequence_value(session, session->sync_uuid, &seq);
vb@1088
   396
    if (status != PEP_OWN_SEQUENCE && status != PEP_STATUS_OK)
vb@1088
   397
        goto error;
vb@1088
   398
vb@1088
   399
    msg->header.sequence = (long) seq;
vb@1088
   400
vb@1088
   401
    _me = identity_dup(me);
vb@1088
   402
    if (!_me)
vb@1059
   403
        goto enomem;
vb@1059
   404
vb@1088
   405
    free(_me->user_id);
edouard@1236
   406
    _me->user_id = strndup(session->sync_uuid, 36);
vb@1088
   407
    assert(_me->user_id);
vb@1088
   408
    if (!_me->user_id)
vb@1088
   409
        goto enomem;
vb@1088
   410
vb@1088
   411
    if (Identity_from_Struct(_me, &msg->header.me) == NULL)
vb@1088
   412
        goto enomem;
vb@1088
   413
vb@1088
   414
    free_identity(_me);
vb@1088
   415
    _me = NULL;
vb@1088
   416
vb@1077
   417
    msg->header.state = (long) state;
vb@1077
   418
vb@1077
   419
    bool devicegroup = storedGroupKeys(session);
vb@1077
   420
    if (devicegroup)
vb@1077
   421
        msg->header.devicegroup = 1;
vb@1077
   422
    else
vb@1077
   423
        msg->header.devicegroup = 0;
vb@1077
   424
edouard@1248
   425
    timestamp *expiry = new_timestamp(time(NULL) + SYNC_MSG_EXPIRE_DELTA);
edouard@1248
   426
    if(timestamp_to_GeneralizedTime(expiry, &msg->header.expiry) == NULL){
edouard@1248
   427
        free_timestamp(expiry);
edouard@1248
   428
        goto enomem;
edouard@1248
   429
    }
edouard@1248
   430
    free_timestamp(expiry);
edouard@1248
   431
vb@1059
   432
    if (asn_check_constraints(&asn_DEF_DeviceGroup_Protocol, msg, NULL, NULL)) {
vb@1059
   433
        status = PEP_CONTRAINTS_VIOLATED;
vb@1059
   434
        goto error;
vb@1059
   435
    }
vb@1059
   436
vb@1059
   437
    ssize_t size = uper_encode_to_new_buffer(&asn_DEF_DeviceGroup_Protocol,
vb@1059
   438
            NULL, msg, (void **) &payload);
vb@1059
   439
    if (size == -1) {
vb@1059
   440
        status = PEP_CANNOT_ENCODE;
vb@1059
   441
        goto error;
vb@1059
   442
    }
vb@1059
   443
vb@1059
   444
    status = prepare_message(me, partner, payload, size, &_message);
vb@1059
   445
    if (status != PEP_STATUS_OK)
vb@1059
   446
        goto error;
vb@1059
   447
    payload = NULL;
vb@1059
   448
    free_identity(me);
vb@1059
   449
    me = NULL;
vb@1059
   450
vb@1097
   451
    if (encrypted) {
vb@1101
   452
        if (msg->payload.present == DeviceGroup_Protocol__payload_PR_groupKeys) {
vb@1101
   453
            PEP_rating rating = PEP_rating_undefined;
vb@1101
   454
            status = outgoing_message_rating(session, _message, &rating);
vb@1101
   455
            if (status != PEP_STATUS_OK)
vb@1101
   456
                goto error;
vb@1101
   457
            if (rating < PEP_rating_trusted) {
vb@1101
   458
                status = PEP_SYNC_NO_TRUST;
vb@1101
   459
                goto error;
vb@1101
   460
            }
vb@1104
   461
            
vb@1104
   462
            IdentityList_t *list = &msg->payload.choice.groupKeys.ownIdentities;
vb@1104
   463
            for (int i=0; i<list->list.count; i++) {
vb@1104
   464
                Identity_t *ident = list->list.array[i];
vb@1133
   465
                char *fpr = strndup((const char *)ident->fpr.buf, ident->fpr.size);
vb@1133
   466
                assert(fpr);
vb@1133
   467
                if (!fpr)
vb@1133
   468
                    goto enomem;
vb@1133
   469
                static char filename[MAX_LINELENGTH];
vb@1133
   470
                int result = snprintf(filename, MAX_LINELENGTH, "%s-sec.asc", fpr);
vb@1133
   471
                if (result < 0)
vb@1133
   472
                    goto enomem;
vb@1133
   473
                char *key = NULL;
vb@1133
   474
                size_t size = 0;
vb@1133
   475
                status = export_secrect_key(session, fpr, &key, &size);
vb@1133
   476
                free(fpr);
vb@1133
   477
                if (status != PEP_STATUS_OK)
vb@1133
   478
                    goto error;
vb@1104
   479
                bloblist_t *bl = bloblist_add(_message->attachments,
vb@1133
   480
                        (char *) key, size, "application/pgp-keys", filename);
vb@1104
   481
                if (!bl)
vb@1104
   482
                    goto enomem;
vb@1104
   483
                if (!_message->attachments)
vb@1104
   484
                    _message->attachments = bl;
vb@1104
   485
            }
vb@1101
   486
        }
vb@1101
   487
vb@1097
   488
        message *_encrypted = NULL;
vb@1097
   489
        status = encrypt_message(session, _message, NULL, &_encrypted, PEP_enc_PEP, 0);
vb@1097
   490
        if (status != PEP_STATUS_OK)
vb@1097
   491
            goto error;
vb@1097
   492
        free_message(_message);
vb@1097
   493
        _message = _encrypted;
vb@1097
   494
    }
vb@1131
   495
    else {
vb@1131
   496
        attach_own_key(session, _message);
vb@1131
   497
    }
vb@1059
   498
vb@1097
   499
    status = session->messageToSend(session->sync_obj, _message);
vb@1059
   500
    return status;
vb@1059
   501
vb@1059
   502
enomem:
vb@1059
   503
    status = PEP_OUT_OF_MEMORY;
vb@1059
   504
error:
vb@1088
   505
    free_identity(_me);
vb@1059
   506
    free(payload);
vb@1059
   507
    free_message(_message);
vb@1059
   508
    free_identity(me);
vb@1059
   509
    return status;
vb@1059
   510
}
vb@1059
   511
vb@1059
   512
PEP_STATUS multicast_self_msg(
vb@1059
   513
        PEP_SESSION session,
vb@1059
   514
        DeviceState_state state,
vb@1097
   515
        DeviceGroup_Protocol_t *msg,
vb@1097
   516
        bool encrypted
vb@1059
   517
    )
vb@1059
   518
{
vb@1059
   519
    PEP_STATUS status = PEP_STATUS_OK;
vb@1059
   520
vb@1059
   521
    assert(session && state && msg);
vb@1059
   522
    if (!(session && state && msg))
vb@1059
   523
        return PEP_ILLEGAL_VALUE;
vb@1059
   524
vb@1059
   525
    identity_list *own_identities = NULL;
vb@1059
   526
    status = own_identities_retrieve(session, &own_identities);
vb@1059
   527
    if (status != PEP_STATUS_OK)
vb@1059
   528
        return status;
vb@1059
   529
edouard@1236
   530
    // FIXME: exclude previously rejected identities
vb@1059
   531
    for (identity_list *_i = own_identities; _i && _i->ident; _i = _i->next) {
vb@1091
   532
        pEp_identity *me = _i->ident;
vb@1059
   533
vb@1065
   534
        // FIXME: no deep copy for multicast supported yet
vb@1065
   535
        DeviceGroup_Protocol_t *_msg = malloc(sizeof(DeviceGroup_Protocol_t));
vb@1065
   536
        assert(_msg);
vb@1065
   537
        if (_msg == NULL)
vb@1065
   538
            goto enomem;
vb@1065
   539
        memcpy(_msg, msg, sizeof(DeviceGroup_Protocol_t));
vb@1097
   540
        status = unicast_msg(session, me, state, _msg, encrypted);
vb@1067
   541
        free_DeviceGroup_Protocol_msg(_msg);
vb@1059
   542
    }
vb@1059
   543
vb@1059
   544
    free_identity_list(own_identities);
vb@1059
   545
    return PEP_STATUS_OK;
vb@1065
   546
vb@1065
   547
enomem:
vb@1065
   548
    free_identity_list(own_identities);
vb@1065
   549
    return PEP_OUT_OF_MEMORY;
vb@1059
   550
}
vb@1059
   551