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