src/sync_impl.c
author Krista Bennett <krista@pep-project.org>
Fri, 03 Nov 2017 13:32:38 +0100
changeset 2271 25bfd109320c
child 2287 026ab4dae779
child 2312 b078c7c38b51
child 2461 85c8e5aad3bc
permissions -rw-r--r--
SYNC HAS RETURNED. Keysync still removed from Engine.
krista@2271
     1
// This file is under GNU General Public License 3.0
krista@2271
     2
// see LICENSE.txt
krista@2271
     3
krista@2271
     4
#include "platform.h"
krista@2271
     5
krista@2271
     6
// it seems pEp_internal.h needs to be the first pEp include due to the 
krista@2271
     7
// #define for the dllimport / dllexport DYNAMIC_API stuff.
krista@2271
     8
#include "pEp_internal.h"
krista@2271
     9
krista@2271
    10
#include "sync_impl.h"
krista@2271
    11
#include "keymanagement.h"
krista@2271
    12
#include "message_api.h"
krista@2271
    13
#include "map_asn1.h"
krista@2271
    14
#include "baseprotocol.h"
krista@2271
    15
krista@2271
    16
#define SYNC_VERSION_MAJOR 1
krista@2271
    17
#define SYNC_VERSION_MINOR 0
krista@2271
    18
krista@2271
    19
#define SYNC_INHIBIT_TIME (60*10)
krista@2271
    20
#define SYNC_MSG_EXPIRE_TIME (60 * 10)
krista@2271
    21
krista@2271
    22
struct _sync_msg_t {
krista@2271
    23
    bool is_a_message;
krista@2271
    24
    union {
krista@2271
    25
        DeviceGroup_Protocol_t *message;
krista@2271
    26
        struct {
krista@2271
    27
            DeviceState_event event;
krista@2271
    28
            Identity partner;
krista@2271
    29
            void *extra;
krista@2271
    30
        } event;
krista@2271
    31
    } u;
krista@2271
    32
};
krista@2271
    33
krista@2271
    34
static bool _is_own_uuid( PEP_SESSION session, UTF8String_t *uuid)
krista@2271
    35
{
krista@2271
    36
    return strncmp(session->sync_session->sync_uuid,
krista@2271
    37
                   (const char*)uuid->buf, uuid->size) == 0;
krista@2271
    38
}
krista@2271
    39
krista@2271
    40
static bool _is_own_group_uuid( PEP_SESSION session, UTF8String_t *uuid, char** our_group)
krista@2271
    41
{
krista@2271
    42
    PEP_STATUS status = PEP_STATUS_OK;
krista@2271
    43
    char *devgrp = NULL;
krista@2271
    44
krista@2271
    45
    if(our_group == NULL || *our_group == NULL)
krista@2271
    46
        status = get_device_group(session, &devgrp);
krista@2271
    47
    else
krista@2271
    48
        devgrp = *our_group;
krista@2271
    49
krista@2271
    50
    bool res = (status == PEP_STATUS_OK && devgrp && devgrp[0] &&
krista@2271
    51
        strncmp(devgrp,(const char*)uuid->buf, uuid->size) == 0);
krista@2271
    52
krista@2271
    53
    if(our_group == NULL)
krista@2271
    54
        free(devgrp);
krista@2271
    55
    else if(*our_group == NULL)
krista@2271
    56
        *our_group = devgrp;
krista@2271
    57
krista@2271
    58
    return res;
krista@2271
    59
}
krista@2271
    60
krista@2271
    61
PEP_STATUS receive_sync_msg(
krista@2271
    62
        PEP_SESSION session,
krista@2271
    63
        sync_msg_t *sync_msg,
krista@2271
    64
        time_t *timeout
krista@2271
    65
    )
krista@2271
    66
{
krista@2271
    67
    PEP_STATUS status;
krista@2271
    68
    void *extra = NULL;
krista@2271
    69
    Identity partner = NULL;
krista@2271
    70
    DeviceState_event event = DeviceState_event_NONE;
krista@2271
    71
    assert(session && sync_msg);
krista@2271
    72
    if (!(session && sync_msg))
krista@2271
    73
        return PEP_ILLEGAL_VALUE;
krista@2271
    74
krista@2271
    75
    bool msgIsFromGroup = false;
krista@2271
    76
    if(sync_msg->is_a_message){
krista@2271
    77
        DeviceGroup_Protocol_t *msg = sync_msg->u.message;
krista@2271
    78
        assert(msg && msg->payload.present != DeviceGroup_Protocol__payload_PR_NOTHING);
krista@2271
    79
        if (!(msg && msg->payload.present != DeviceGroup_Protocol__payload_PR_NOTHING)){
krista@2271
    80
            status = PEP_OUT_OF_MEMORY;
krista@2271
    81
            goto error;
krista@2271
    82
        }
krista@2271
    83
krista@2271
    84
        partner = Identity_to_Struct(&msg->header.me, NULL);
krista@2271
    85
        if (!partner){
krista@2271
    86
            status = PEP_OUT_OF_MEMORY;
krista@2271
    87
            ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
krista@2271
    88
            goto error;
krista@2271
    89
        }
krista@2271
    90
krista@2271
    91
        msgIsFromGroup = msg->header.devicegroup;
krista@2271
    92
krista@2271
    93
        switch (msg->payload.present) {
krista@2271
    94
            case DeviceGroup_Protocol__payload_PR_beacon:
krista@2271
    95
                event = Beacon;
krista@2271
    96
                break;
krista@2271
    97
krista@2271
    98
            case DeviceGroup_Protocol__payload_PR_handshakeRequest:
krista@2271
    99
            {
krista@2271
   100
                // re-check uuid in case sync_uuid or group changed while in the queue
krista@2271
   101
                char *own_group_id = NULL;
krista@2271
   102
                bool is_for_me = _is_own_uuid(session, 
krista@2271
   103
                    msg->payload.choice.handshakeRequest.partner_id);
krista@2271
   104
                bool is_for_group = !is_for_me && _is_own_group_uuid(session, 
krista@2271
   105
                    msg->payload.choice.handshakeRequest.partner_id, &own_group_id);
krista@2271
   106
                if (!(is_for_me || is_for_group)){
krista@2271
   107
                    status = PEP_MESSAGE_IGNORE;
krista@2271
   108
                    goto error;
krista@2271
   109
                }
krista@2271
   110
krista@2271
   111
                UTF8String_t *guuid = msg->payload.choice.handshakeRequest.group_id;
krista@2271
   112
                if(msgIsFromGroup && guuid && guuid->buf && guuid->size) {
krista@2271
   113
                    bool is_from_own_group = _is_own_group_uuid(session, 
krista@2271
   114
                                                                guuid, &own_group_id);
krista@2271
   115
krista@2271
   116
                    // Filter handshake requests from own group
krista@2271
   117
                    if(is_from_own_group) {
krista@2271
   118
                        status = PEP_MESSAGE_IGNORE;
krista@2271
   119
                        goto error;
krista@2271
   120
                    }
krista@2271
   121
krista@2271
   122
                    // if it comes from another group, 
krista@2271
   123
                    // we want to communicate with that group
krista@2271
   124
                    // insert group_id given in handshake request 
krista@2271
   125
                    // into partner's id
krista@2271
   126
krista@2271
   127
                    free(partner->user_id);
krista@2271
   128
                    partner->user_id = strndup((const char*)guuid->buf, guuid->size);
krista@2271
   129
                    if(partner->user_id == NULL){
krista@2271
   130
                        status = PEP_OUT_OF_MEMORY;
krista@2271
   131
                        goto error;
krista@2271
   132
                    }
krista@2271
   133
krista@2271
   134
                    // if it comes from another group, and we are grouped,
krista@2271
   135
                    // then this is groupmerge
krista@2271
   136
                }
krista@2271
   137
krista@2271
   138
                event = HandshakeRequest;
krista@2271
   139
                break;
krista@2271
   140
krista@2271
   141
            }
krista@2271
   142
            case DeviceGroup_Protocol__payload_PR_updateRequest:
krista@2271
   143
                event = UpdateRequest;
krista@2271
   144
                break;
krista@2271
   145
krista@2271
   146
            case DeviceGroup_Protocol__payload_PR_groupKeys:
krista@2271
   147
            {
krista@2271
   148
                // re-check uuid in case sync_uuid or group_uuid changed while in the queue
krista@2271
   149
                char *own_group_id = NULL;
krista@2271
   150
                UTF8String_t *puuid = msg->payload.choice.groupKeys.partner_id;
krista@2271
   151
                bool is_for_me = _is_own_uuid(session, puuid);
krista@2271
   152
                bool is_for_group = !is_for_me &&
krista@2271
   153
                                    _is_own_group_uuid(session, 
krista@2271
   154
                                        puuid, &own_group_id);
krista@2271
   155
                if (!(is_for_me || is_for_group)){
krista@2271
   156
                    status = PEP_MESSAGE_IGNORE;
krista@2271
   157
                    goto error;
krista@2271
   158
                }
krista@2271
   159
krista@2271
   160
                UTF8String_t *guuid = msg->payload.choice.groupKeys.group_id;
krista@2271
   161
krista@2271
   162
                // GroupKeys come from groups, no choice
krista@2271
   163
                if(!(msgIsFromGroup && guuid && guuid->buf && guuid->size)) {
krista@2271
   164
                    status = PEP_SYNC_ILLEGAL_MESSAGE;
krista@2271
   165
                    goto error;
krista@2271
   166
                }
krista@2271
   167
krista@2271
   168
                // Filter groupKeys from own group
krista@2271
   169
                bool is_from_own_group = _is_own_group_uuid(session, 
krista@2271
   170
                                                            guuid, 
krista@2271
   171
                                                            &own_group_id);
krista@2271
   172
                if(is_from_own_group) {
krista@2271
   173
                    // FixMe : protocol shouldn't allow this
krista@2271
   174
                    status = PEP_SYNC_ILLEGAL_MESSAGE;
krista@2271
   175
                    goto error;
krista@2271
   176
                }
krista@2271
   177
krista@2271
   178
                // insert group_id given in groupKeys into partner's id
krista@2271
   179
                free(partner->user_id);
krista@2271
   180
                partner->user_id = strndup((const char*)guuid->buf, guuid->size);
krista@2271
   181
                if(partner->user_id == NULL){
krista@2271
   182
                    status = PEP_OUT_OF_MEMORY;
krista@2271
   183
                    goto error;
krista@2271
   184
                }
krista@2271
   185
krista@2271
   186
                // if it comes from another group, and we are grouped,
krista@2271
   187
                // then this is groupmerge's groupKeys
krista@2271
   188
krista@2271
   189
                group_keys_extra_t *group_keys_extra;
krista@2271
   190
                group_keys_extra = malloc(sizeof(group_keys_extra_t));
krista@2271
   191
                if(group_keys_extra == NULL){
krista@2271
   192
                    status = PEP_OUT_OF_MEMORY;
krista@2271
   193
                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
krista@2271
   194
                    goto error;
krista@2271
   195
                }
krista@2271
   196
krista@2271
   197
                char *group_id = strndup((char*)guuid->buf, guuid->size);
krista@2271
   198
krista@2271
   199
                if (!group_id){
krista@2271
   200
                    status = PEP_OUT_OF_MEMORY;
krista@2271
   201
                    free(group_keys_extra);
krista@2271
   202
                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
krista@2271
   203
                    goto error;
krista@2271
   204
                }
krista@2271
   205
                group_keys_extra->group_id = group_id;
krista@2271
   206
krista@2271
   207
                identity_list *group_keys = IdentityList_to_identity_list(
krista@2271
   208
                        &msg->payload.choice.groupKeys.ownIdentities,
krista@2271
   209
                        NULL);
krista@2271
   210
                if (!group_keys) {
krista@2271
   211
                    status = PEP_OUT_OF_MEMORY;
krista@2271
   212
                    free(group_id);
krista@2271
   213
                    free(group_keys_extra);
krista@2271
   214
                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
krista@2271
   215
                    goto error;
krista@2271
   216
                }
krista@2271
   217
                group_keys_extra->group_keys = group_keys;
krista@2271
   218
krista@2271
   219
                extra = (void *) group_keys_extra;
krista@2271
   220
                event = GroupKeys;
krista@2271
   221
krista@2271
   222
                break;
krista@2271
   223
            }
krista@2271
   224
            case DeviceGroup_Protocol__payload_PR_groupUpdate:
krista@2271
   225
            {
krista@2271
   226
                identity_list *group_keys = IdentityList_to_identity_list(
krista@2271
   227
                        &msg->payload.choice.groupUpdate.ownIdentities, NULL);
krista@2271
   228
                if (!group_keys) {
krista@2271
   229
                    status = PEP_OUT_OF_MEMORY;
krista@2271
   230
                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
krista@2271
   231
                    goto error;
krista@2271
   232
                }
krista@2271
   233
                extra = (void *) group_keys;
krista@2271
   234
                event = GroupUpdate;
krista@2271
   235
                break;
krista@2271
   236
            }
krista@2271
   237
krista@2271
   238
            default:
krista@2271
   239
                status = PEP_SYNC_ILLEGAL_MESSAGE;
krista@2271
   240
                ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
krista@2271
   241
                goto error;
krista@2271
   242
        }
krista@2271
   243
krista@2271
   244
    }
krista@2271
   245
    else{
krista@2271
   246
        partner = sync_msg->u.event.partner;
krista@2271
   247
        extra = sync_msg->u.event.extra;
krista@2271
   248
        event = sync_msg->u.event.event;
krista@2271
   249
    }
krista@2271
   250
krista@2271
   251
    // Event inhibition, to limit mailbox and prevent cycles
krista@2271
   252
    time_t *last = NULL;
krista@2271
   253
    switch(event){
krista@2271
   254
        case CannotDecrypt:
krista@2271
   255
            last = &session->LastCannotDecrypt;
krista@2271
   256
            break;
krista@2271
   257
krista@2271
   258
        case UpdateRequest:
krista@2271
   259
            last = &session->LastUpdateRequest;
krista@2271
   260
            break;
krista@2271
   261
krista@2271
   262
        default:
krista@2271
   263
            break;
krista@2271
   264
    }
krista@2271
   265
krista@2271
   266
    if(last != NULL){
krista@2271
   267
        time_t now = time(NULL);
krista@2271
   268
        if(*last != 0 && (*last + SYNC_INHIBIT_TIME) > now ){
krista@2271
   269
            status = PEP_STATEMACHINE_INHIBITED_EVENT;
krista@2271
   270
            goto error;
krista@2271
   271
        }
krista@2271
   272
        *last = now;
krista@2271
   273
    }
krista@2271
   274
krista@2271
   275
    // partner identity must be explicitely added DB to later
krista@2271
   276
    // be able to communicate securely with it.
krista@2271
   277
    if(partner){
krista@2271
   278
        // protect virtual user IDs 
krista@2271
   279
        if((strncmp("TOFU_", partner->user_id, 6) == 0 &&
krista@2271
   280
           strlen(partner->user_id) == strlen(partner->address) + 6 &&
krista@2271
   281
           strcmp(partner->user_id + 6, partner->address)) ||
krista@2271
   282
        // protect own ID 
krista@2271
   283
           (strcmp(PEP_OWN_USERID, partner->user_id) == 0)){
krista@2271
   284
            status = PEP_SYNC_ILLEGAL_MESSAGE;
krista@2271
   285
            goto error;
krista@2271
   286
        }
krista@2271
   287
krista@2271
   288
        // partner IDs are UUIDs bound to session lifespan
krista@2271
   289
        // and therefore partner identities are not supposed
krista@2271
   290
        // to mutate over time, but just not be used anymore.
krista@2271
   291
        // It should then be safe to accept given identity if not 
krista@2271
   292
        // already pre-existing
krista@2271
   293
        pEp_identity *stored_identity = NULL;
krista@2271
   294
        status = get_identity(session,
krista@2271
   295
                              partner->address,
krista@2271
   296
                              partner->user_id,
krista@2271
   297
                              &stored_identity);
krista@2271
   298
krista@2271
   299
        if (!stored_identity) {
krista@2271
   300
            // make a safe copy of partner, with no flags or comm_type
krista@2271
   301
            pEp_identity *tmpident = new_identity(partner->address,
krista@2271
   302
                                                  partner->fpr,
krista@2271
   303
                                                  partner->user_id,
krista@2271
   304
                                                  partner->username);
krista@2271
   305
            if (tmpident == NULL){
krista@2271
   306
                status = PEP_OUT_OF_MEMORY;
krista@2271
   307
                goto error;
krista@2271
   308
            }
krista@2271
   309
krista@2271
   310
            // finaly add partner to DB
krista@2271
   311
            status = set_identity(session, tmpident);
krista@2271
   312
            assert(status == PEP_STATUS_OK);
krista@2271
   313
            if(status == PEP_STATUS_OK && msgIsFromGroup)
krista@2271
   314
                status = set_identity_flags(session, tmpident, PEP_idf_devicegroup);
krista@2271
   315
            free_identity(tmpident);
krista@2271
   316
            assert(status == PEP_STATUS_OK);
krista@2271
   317
            if (status != PEP_STATUS_OK) {
krista@2271
   318
                goto error;
krista@2271
   319
            }
krista@2271
   320
        }
krista@2271
   321
        else if (status == PEP_STATUS_OK) {
krista@2271
   322
            free_identity(stored_identity);
krista@2271
   323
        } 
krista@2271
   324
        else
krista@2271
   325
            goto error;
krista@2271
   326
    }
krista@2271
   327
krista@2271
   328
    status = fsm_DeviceState_inject(session, event, partner, extra, timeout);
krista@2271
   329
krista@2271
   330
error:
krista@2271
   331
krista@2271
   332
    free_identity(partner);
krista@2271
   333
krista@2271
   334
    switch(event){
krista@2271
   335
        case GroupKeys:
krista@2271
   336
        {
krista@2271
   337
            free_group_keys_extra((group_keys_extra_t*)extra);
krista@2271
   338
            break;
krista@2271
   339
        }
krista@2271
   340
        case GroupUpdate:
krista@2271
   341
        {
krista@2271
   342
            identity_list *group_keys = (identity_list*) extra;
krista@2271
   343
            free_identity_list(group_keys);
krista@2271
   344
            break;
krista@2271
   345
        }
krista@2271
   346
        default:
krista@2271
   347
            assert(extra==NULL);
krista@2271
   348
            break;
krista@2271
   349
    }
krista@2271
   350
krista@2271
   351
    free(sync_msg);
krista@2271
   352
krista@2271
   353
    return status;
krista@2271
   354
}
krista@2271
   355
krista@2271
   356
// TODO: DYNAMIC_API was here, but broke the windows build. 
krista@2271
   357
// We need to check whether it belongs here or it's a bug.
krista@2271
   358
/* DYNAMIC_API */ void free_sync_msg(sync_msg_t *sync_msg)
krista@2271
   359
{
krista@2271
   360
    if (!sync_msg)
krista@2271
   361
        return;
krista@2271
   362
krista@2271
   363
    if(sync_msg->is_a_message){
krista@2271
   364
        DeviceGroup_Protocol_t *msg = sync_msg->u.message;
krista@2271
   365
        assert(msg);
krista@2271
   366
        if (!(msg))
krista@2271
   367
            return;
krista@2271
   368
krista@2271
   369
        ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
krista@2271
   370
    }
krista@2271
   371
    else{
krista@2271
   372
        Identity partner = NULL;
krista@2271
   373
        partner = sync_msg->u.event.partner;
krista@2271
   374
        if(partner != NULL)
krista@2271
   375
            free_identity(partner);
krista@2271
   376
    }
krista@2271
   377
krista@2271
   378
    free(sync_msg);
krista@2271
   379
krista@2271
   380
    return;
krista@2271
   381
}
krista@2271
   382
krista@2271
   383
// from sync.c
krista@2271
   384
int call_inject_sync_msg(PEP_SESSION session, void *msg);
krista@2271
   385
krista@2271
   386
PEP_STATUS inject_DeviceState_event(
krista@2271
   387
    PEP_SESSION session, 
krista@2271
   388
    DeviceState_event event,
krista@2271
   389
    Identity partner,
krista@2271
   390
    void *extra)
krista@2271
   391
{
krista@2271
   392
    PEP_STATUS status;
krista@2271
   393
krista@2271
   394
    assert(session);
krista@2271
   395
    if (!(session))
krista@2271
   396
        return PEP_ILLEGAL_VALUE;
krista@2271
   397
krista@2271
   398
    sync_msg_t *sync_msg = malloc(sizeof(sync_msg_t));
krista@2271
   399
    if(sync_msg == NULL)
krista@2271
   400
        return PEP_OUT_OF_MEMORY;
krista@2271
   401
krista@2271
   402
    sync_msg->is_a_message = false;
krista@2271
   403
    sync_msg->u.event.partner = partner;
krista@2271
   404
    sync_msg->u.event.extra = extra;
krista@2271
   405
    sync_msg->u.event.event = event;
krista@2271
   406
krista@2271
   407
    status = call_inject_sync_msg(session, sync_msg);
krista@2271
   408
    if (status == PEP_SYNC_NO_INJECT_CALLBACK){
krista@2271
   409
        free(sync_msg);
krista@2271
   410
    }
krista@2271
   411
krista@2271
   412
    return status;
krista@2271
   413
}
krista@2271
   414
krista@2271
   415
PEP_STATUS receive_DeviceState_msg(
krista@2271
   416
    PEP_SESSION session, 
krista@2271
   417
    message *src, 
krista@2271
   418
    PEP_rating rating, 
krista@2271
   419
    stringlist_t *keylist)
krista@2271
   420
{
krista@2271
   421
    assert(session && src);
krista@2271
   422
    if (!(session && src))
krista@2271
   423
        return PEP_ILLEGAL_VALUE;
krista@2271
   424
krista@2271
   425
    bool consume = false;
krista@2271
   426
    bool discard = false;
krista@2271
   427
    bool force_keep_msg = false;
krista@2271
   428
krista@2271
   429
    for (bloblist_t *bl = src->attachments; bl && bl->value; bl = bl->next) {
krista@2271
   430
        if (bl->mime_type && strcasecmp(bl->mime_type, "application/pEp.sync") == 0
krista@2271
   431
                && bl->size) {
krista@2271
   432
            DeviceGroup_Protocol_t *msg = NULL;
krista@2271
   433
            uper_decode_complete(NULL, &asn_DEF_DeviceGroup_Protocol, (void **)
krista@2271
   434
                    &msg, bl->value, bl->size);
krista@2271
   435
krista@2271
   436
            if (msg) {
krista@2271
   437
                PEP_STATUS status = PEP_STATUS_OK;
krista@2271
   438
krista@2271
   439
                char *user_id = strndup((char *) msg->header.me.user_id->buf,
krista@2271
   440
                        msg->header.me.user_id->size);
krista@2271
   441
                assert(user_id);
krista@2271
   442
                if (!user_id) {
krista@2271
   443
                    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
krista@2271
   444
                    return PEP_OUT_OF_MEMORY;
krista@2271
   445
                }
krista@2271
   446
krista@2271
   447
                // detect and mitigate address spoofing
krista@2271
   448
                Identity check_me = NULL;
krista@2271
   449
                char* null_terminated_address = 
krista@2271
   450
                    strndup((char *) msg->header.me.address->buf,
krista@2271
   451
                            msg->header.me.address->size);
krista@2271
   452
krista@2271
   453
                if(null_terminated_address){
krista@2271
   454
                    status = get_identity(session, 
krista@2271
   455
                                          null_terminated_address, 
krista@2271
   456
                                          PEP_OWN_USERID, 
krista@2271
   457
                                          &check_me);
krista@2271
   458
                    free(null_terminated_address);
krista@2271
   459
                } 
krista@2271
   460
                else
krista@2271
   461
                    status = PEP_OUT_OF_MEMORY;
krista@2271
   462
krista@2271
   463
                if (status == PEP_OUT_OF_MEMORY)
krista@2271
   464
                    goto free_all;
krista@2271
   465
krista@2271
   466
                free_identity(check_me);
krista@2271
   467
krista@2271
   468
                bool not_own_address = status != PEP_STATUS_OK;
krista@2271
   469
                status = PEP_STATUS_OK;
krista@2271
   470
krista@2271
   471
                if (not_own_address || 
krista@2271
   472
                    strncmp(src->from->address,
krista@2271
   473
                            (char *) msg->header.me.address->buf,
krista@2271
   474
                            msg->header.me.address->size) != 0 ||
krista@2271
   475
                    strncmp(src->to->ident->address,
krista@2271
   476
                            (char *) msg->header.me.address->buf,
krista@2271
   477
                            msg->header.me.address->size) != 0) {
krista@2271
   478
                    consume = true;
krista@2271
   479
                    goto free_all;
krista@2271
   480
                }
krista@2271
   481
krista@2271
   482
                // if encrypted, ensure that header.me.fpr match signer's fpr
krista@2271
   483
                if (rating >= PEP_rating_reliable && (
krista@2271
   484
                        !keylist ||
krista@2271
   485
                        !_same_fpr((char *) msg->header.me.fpr.buf,
krista@2271
   486
                                   msg->header.me.fpr.size,
krista@2271
   487
                                   keylist->value,
krista@2271
   488
                                   strlen(keylist->value)))) {
krista@2271
   489
                    consume = true;
krista@2271
   490
                    goto free_all;
krista@2271
   491
                }
krista@2271
   492
krista@2271
   493
                // check message expiry 
krista@2271
   494
                if(src->recv) {
krista@2271
   495
                    time_t expiry = timegm(src->recv) + SYNC_MSG_EXPIRE_TIME;
krista@2271
   496
                    time_t now = time(NULL);
krista@2271
   497
                    if(expiry != 0 && now != 0 && expiry < now){
krista@2271
   498
                        consume = true;
krista@2271
   499
                        goto free_all;
krista@2271
   500
                    }
krista@2271
   501
                }
krista@2271
   502
krista@2271
   503
                int32_t value = (int32_t) msg->header.sequence;
krista@2271
   504
                if (value < 1) {
krista@2271
   505
                    status = PEP_SEQUENCE_VIOLATED;
krista@2271
   506
                } else {
krista@2271
   507
                    status = sequence_value(session, (char *) user_id,
krista@2271
   508
                            &value);
krista@2271
   509
                }
krista@2271
   510
krista@2271
   511
                if (status == PEP_STATUS_OK) {
krista@2271
   512
                    switch (msg->payload.present) {
krista@2271
   513
                        // HandshakeRequest needs encryption
krista@2271
   514
                        case DeviceGroup_Protocol__payload_PR_handshakeRequest:
krista@2271
   515
                        {
krista@2271
   516
                            UTF8String_t *puuid = 
krista@2271
   517
                              msg->payload.choice.handshakeRequest.partner_id;
krista@2271
   518
                            bool is_for_me = _is_own_uuid(session, puuid);
krista@2271
   519
                            bool is_for_group = !is_for_me && 
krista@2271
   520
                                                _is_own_group_uuid(
krista@2271
   521
                                                    session, puuid, NULL);
krista@2271
   522
krista@2271
   523
                            // Reject handshake requests not addressed to us
krista@2271
   524
                            if (rating < PEP_rating_reliable ||
krista@2271
   525
                                !(is_for_me || is_for_group)){
krista@2271
   526
                                discard = true;
krista@2271
   527
                                goto free_all;
krista@2271
   528
                            }
krista@2271
   529
krista@2271
   530
                            // do not consume handshake request for group
krista@2271
   531
                            if(is_for_group){ 
krista@2271
   532
                                force_keep_msg = true;
krista@2271
   533
                            }
krista@2271
   534
                            break;
krista@2271
   535
                        }
krista@2271
   536
                        // accepting GroupKeys needs encryption and trust of peer device
krista@2271
   537
                        case DeviceGroup_Protocol__payload_PR_groupKeys:
krista@2271
   538
                        {
krista@2271
   539
                            UTF8String_t *puuid = msg->payload.choice.groupKeys.partner_id;
krista@2271
   540
                            bool is_for_me = _is_own_uuid(session, puuid);
krista@2271
   541
                            bool is_for_group = !is_for_me &&
krista@2271
   542
                                                _is_own_group_uuid(session, 
krista@2271
   543
                                                    puuid, NULL);
krista@2271
   544
                            if (!keylist || rating < PEP_rating_reliable ||
krista@2271
   545
                                // message is only consumed by instance it is addressed to
krista@2271
   546
                                !(is_for_me || is_for_group)){
krista@2271
   547
                                discard = true;
krista@2271
   548
                                goto free_all;
krista@2271
   549
                            }
krista@2271
   550
krista@2271
   551
                            // do not consume groupKeys for group
krista@2271
   552
                            if(is_for_group){ 
krista@2271
   553
                                // This happens in case case of groupmerge
krista@2271
   554
                                force_keep_msg = true;
krista@2271
   555
                            }
krista@2271
   556
krista@2271
   557
                            // Trust check disabled here but it still it should be safe.
krista@2271
   558
                            // SameIdentity checks in state machine ensures that we only
krista@2271
   559
                            // store groupkeys signed by device or group that have been 
krista@2271
   560
                            // previously accepted in handshake.
krista@2271
   561
                            //
krista@2271
   562
                            // // check trust of identity using user_id given in msg.header.me
krista@2271
   563
                            // // to exacly match identity of device, the one trusted in
krista@2271
   564
                            // // case of accepted handshake from a sole device
krista@2271
   565
                            // pEp_identity *_from = new_identity(NULL, 
krista@2271
   566
                            //                                    keylist->value,
krista@2271
   567
                            //                                    user_id,
krista@2271
   568
                            //                                    NULL);
krista@2271
   569
                            // if (_from == NULL){
krista@2271
   570
                            //     status = PEP_OUT_OF_MEMORY;
krista@2271
   571
                            //     goto free_all;
krista@2271
   572
                            // }
krista@2271
   573
                            // status = get_trust(session, _from);
krista@2271
   574
                            // if (status != PEP_STATUS_OK || _from->comm_type < PEP_ct_strong_encryption) {
krista@2271
   575
krista@2271
   576
                            //     // re-try with group_id instead, in case of handshake with pre-existing group
krista@2271
   577
                            //     UTF8String_t *guuid = msg->payload.choice.groupKeys.group_id;
krista@2271
   578
                            //     free(_from->user_id);
krista@2271
   579
                            //     if ((_from->user_id = strndup((const char*)guuid->buf, guuid->size)) == NULL){
krista@2271
   580
                            //         free_identity(_from);
krista@2271
   581
                            //         status = PEP_OUT_OF_MEMORY;
krista@2271
   582
                            //         goto free_all;
krista@2271
   583
                            //     }
krista@2271
   584
                            //     _from->comm_type = PEP_ct_unknown;
krista@2271
   585
krista@2271
   586
                            //     status = get_trust(session, _from);
krista@2271
   587
                            //     if (status != PEP_STATUS_OK || _from->comm_type < PEP_ct_strong_encryption) {
krista@2271
   588
                            //         status = PEP_STATUS_OK;
krista@2271
   589
                            //         free_identity(_from);
krista@2271
   590
                            //         discard = true;
krista@2271
   591
                            //         goto free_all;
krista@2271
   592
                            //     }
krista@2271
   593
                            // }
krista@2271
   594
                            // free_identity(_from);
krista@2271
   595
                            break;
krista@2271
   596
                        }
krista@2271
   597
                        case DeviceGroup_Protocol__payload_PR_groupUpdate:
krista@2271
   598
                        case DeviceGroup_Protocol__payload_PR_updateRequest:
krista@2271
   599
                        {
krista@2271
   600
                            // inject message but don't consume it, so 
krista@2271
   601
                            // that other group members can also be updated
krista@2271
   602
                            force_keep_msg = true;
krista@2271
   603
                            
krista@2271
   604
                            if (!keylist || rating < PEP_rating_reliable){
krista@2271
   605
                                discard = true;
krista@2271
   606
                                goto free_all;
krista@2271
   607
                            }
krista@2271
   608
                            // GroupUpdate and UpdateRequests come from group.
krista@2271
   609
                            // check trust relation in between signer key and 
krista@2271
   610
                            // own id to be sure.
krista@2271
   611
                            pEp_identity *_from = new_identity(NULL, 
krista@2271
   612
                                                               keylist->value,
krista@2271
   613
                                                               PEP_OWN_USERID,
krista@2271
   614
                                                               NULL);
krista@2271
   615
                            if (_from == NULL){
krista@2271
   616
                                status = PEP_OUT_OF_MEMORY;
krista@2271
   617
                                goto free_all;
krista@2271
   618
                            }
krista@2271
   619
                            status = get_trust(session, _from);
krista@2271
   620
                            if (status != PEP_STATUS_OK || _from->comm_type < PEP_ct_pEp) {
krista@2271
   621
                                status = PEP_STATUS_OK;
krista@2271
   622
                                free_identity(_from);
krista@2271
   623
                                discard = true;
krista@2271
   624
                                goto free_all;
krista@2271
   625
                            }
krista@2271
   626
                            free_identity(_from);
krista@2271
   627
                        }
krista@2271
   628
                        default:
krista@2271
   629
                            break;
krista@2271
   630
                    }
krista@2271
   631
krista@2271
   632
krista@2271
   633
                    consume = true;
krista@2271
   634
                    sync_msg_t *sync_msg = malloc(sizeof(sync_msg_t));
krista@2271
   635
                    if(sync_msg == NULL){
krista@2271
   636
                        status = PEP_OUT_OF_MEMORY;
krista@2271
   637
                        goto free_all;
krista@2271
   638
                    }
krista@2271
   639
                    sync_msg->is_a_message = true;
krista@2271
   640
                    sync_msg->u.message = msg;
krista@2271
   641
                    status = call_inject_sync_msg(session, sync_msg);
krista@2271
   642
                    if (status != PEP_STATUS_OK){
krista@2271
   643
                        if (status == PEP_SYNC_NO_INJECT_CALLBACK){
krista@2271
   644
                            free(sync_msg);
krista@2271
   645
                        }
krista@2271
   646
                        goto free_all;
krista@2271
   647
                    }
krista@2271
   648
                    // don't free message now that it is in the queue
krista@2271
   649
                    goto free_userid;
krista@2271
   650
                }
krista@2271
   651
                else if (status == PEP_OWN_SEQUENCE || status == PEP_SEQUENCE_VIOLATED) {
krista@2271
   652
                    status = PEP_STATUS_OK;
krista@2271
   653
                    discard = true;
krista@2271
   654
                    goto free_all;
krista@2271
   655
                }
krista@2271
   656
krista@2271
   657
            free_all:
krista@2271
   658
                ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
krista@2271
   659
            free_userid:
krista@2271
   660
                free(user_id);
krista@2271
   661
krista@2271
   662
                if (status != PEP_STATUS_OK)
krista@2271
   663
                    return status;
krista@2271
   664
            }
krista@2271
   665
        }
krista@2271
   666
    }
krista@2271
   667
krista@2271
   668
    if (force_keep_msg) {
krista@2271
   669
        return PEP_MESSAGE_IGNORE;
krista@2271
   670
    }
krista@2271
   671
krista@2271
   672
    if (consume && !session->keep_sync_msg) {
krista@2271
   673
        for (stringpair_list_t *spl = src->opt_fields ; spl && spl->value ;
krista@2271
   674
                spl = spl->next) {
krista@2271
   675
            if (spl->value->key &&
krista@2271
   676
                    strcasecmp(spl->value->key, "pEp-auto-consume") == 0) {
krista@2271
   677
                if (spl->value->value &&
krista@2271
   678
                        strcasecmp(spl->value->value, "yes") == 0)
krista@2271
   679
                    return PEP_MESSAGE_CONSUME;
krista@2271
   680
            }
krista@2271
   681
        }
krista@2271
   682
        return PEP_MESSAGE_IGNORE;
krista@2271
   683
    }
krista@2271
   684
krista@2271
   685
    if(discard)
krista@2271
   686
        return PEP_MESSAGE_IGNORE;
krista@2271
   687
krista@2271
   688
    if (!session->keep_sync_msg) {
krista@2271
   689
        bloblist_t *last = NULL;
krista@2271
   690
        for (bloblist_t *bl = src->attachments; bl && bl->value; ) {
krista@2271
   691
            if (bl->mime_type && strcasecmp(bl->mime_type, "application/pEp.sync") == 0) {
krista@2271
   692
                bloblist_t *b = bl;
krista@2271
   693
                bl = bl->next;
krista@2271
   694
                if (!last)
krista@2271
   695
                    src->attachments = bl;
krista@2271
   696
                else
krista@2271
   697
                    last->next = bl;
krista@2271
   698
                free(b->mime_type);
krista@2271
   699
                free(b->filename);
krista@2271
   700
                free(b->value);
krista@2271
   701
                free(b);
krista@2271
   702
            }
krista@2271
   703
            else {
krista@2271
   704
                last = bl;
krista@2271
   705
                bl = bl->next;
krista@2271
   706
            }
krista@2271
   707
        }
krista@2271
   708
    }
krista@2271
   709
krista@2271
   710
    return PEP_STATUS_OK;
krista@2271
   711
}
krista@2271
   712
krista@2271
   713
DeviceGroup_Protocol_t *new_DeviceGroup_Protocol_msg(DeviceGroup_Protocol__payload_PR type)
krista@2271
   714
{
krista@2271
   715
    DeviceGroup_Protocol_t *msg = (DeviceGroup_Protocol_t *)
krista@2271
   716
            calloc(1, sizeof(DeviceGroup_Protocol_t));
krista@2271
   717
    assert(msg);
krista@2271
   718
    if (!msg)
krista@2271
   719
        return NULL;
krista@2271
   720
    msg->payload.present = type;
krista@2271
   721
    return msg;
krista@2271
   722
}
krista@2271
   723
krista@2271
   724
void free_DeviceGroup_Protocol_msg(DeviceGroup_Protocol_t *msg)
krista@2271
   725
{
krista@2271
   726
    ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
krista@2271
   727
}
krista@2271
   728
krista@2271
   729
krista@2271
   730
#ifndef NDEBUG
krista@2271
   731
static int _append(const void *buffer, size_t size, void *appkey)
krista@2271
   732
{
krista@2271
   733
    char **dest_ptr = (char **)appkey;
krista@2271
   734
    size_t osize = strlen(*dest_ptr);
krista@2271
   735
    size_t nsize = size + osize;
krista@2271
   736
    *dest_ptr = realloc(*dest_ptr, nsize + 1);
krista@2271
   737
    if(*dest_ptr == NULL) return -1;
krista@2271
   738
    memcpy(*dest_ptr + osize, buffer, size);
krista@2271
   739
    (*dest_ptr)[nsize] = '\0';
krista@2271
   740
    return 0;
krista@2271
   741
}
krista@2271
   742
#endif
krista@2271
   743
krista@2271
   744
PEP_STATUS unicast_msg(
krista@2271
   745
        PEP_SESSION session,
krista@2271
   746
        const Identity partner,
krista@2271
   747
        DeviceState_state state,
krista@2271
   748
        DeviceGroup_Protocol_t *msg,
krista@2271
   749
        bool encrypted
krista@2271
   750
    )
krista@2271
   751
{
krista@2271
   752
    PEP_STATUS status = PEP_STATUS_OK;
krista@2271
   753
    char *payload = NULL;
krista@2271
   754
    message *_message = NULL;
krista@2271
   755
    pEp_identity *me = NULL;
krista@2271
   756
    pEp_identity *_me = NULL;
krista@2271
   757
krista@2271
   758
    assert(session && partner && state && msg);
krista@2271
   759
    if (!(session && partner && state && msg))
krista@2271
   760
        return PEP_ILLEGAL_VALUE;
krista@2271
   761
krista@2271
   762
    assert(session->messageToSend);
krista@2271
   763
    if (!session->messageToSend) {
krista@2271
   764
        status = PEP_SEND_FUNCTION_NOT_REGISTERED;
krista@2271
   765
        goto error;
krista@2271
   766
    }
krista@2271
   767
krista@2271
   768
    msg->header.version.major = SYNC_VERSION_MAJOR;
krista@2271
   769
    msg->header.version.minor = SYNC_VERSION_MINOR;
krista@2271
   770
krista@2271
   771
    status = get_identity(session, partner->address, PEP_OWN_USERID, &me);
krista@2271
   772
    if (status != PEP_STATUS_OK)
krista@2271
   773
        goto error;
krista@2271
   774
    
krista@2271
   775
    int32_t seq = 0;
krista@2271
   776
krista@2271
   777
    status = sequence_value(session, session->sync_session->sync_uuid, &seq);
krista@2271
   778
    if (status != PEP_OWN_SEQUENCE && status != PEP_STATUS_OK)
krista@2271
   779
        goto error;
krista@2271
   780
krista@2271
   781
    msg->header.sequence = (long) seq;
krista@2271
   782
krista@2271
   783
    _me = identity_dup(me);
krista@2271
   784
    if (!_me)
krista@2271
   785
        goto enomem;
krista@2271
   786
krista@2271
   787
    free(_me->user_id);
krista@2271
   788
    _me->user_id = strndup(session->sync_session->sync_uuid, 36);
krista@2271
   789
    assert(_me->user_id);
krista@2271
   790
    if (!_me->user_id)
krista@2271
   791
        goto enomem;
krista@2271
   792
krista@2271
   793
    if (Identity_from_Struct(_me, &msg->header.me) == NULL)
krista@2271
   794
        goto enomem;
krista@2271
   795
krista@2271
   796
    free_identity(_me);
krista@2271
   797
    _me = NULL;
krista@2271
   798
krista@2271
   799
    msg->header.state = (long) state;
krista@2271
   800
krista@2271
   801
    bool devicegroup = deviceGrouped(session);
krista@2271
   802
    if (devicegroup)
krista@2271
   803
        msg->header.devicegroup = 1;
krista@2271
   804
    else
krista@2271
   805
        msg->header.devicegroup = 0;
krista@2271
   806
krista@2271
   807
    if (asn_check_constraints(&asn_DEF_DeviceGroup_Protocol, msg, NULL, NULL)) {
krista@2271
   808
        status = PEP_CONTRAINTS_VIOLATED;
krista@2271
   809
        goto error;
krista@2271
   810
    }
krista@2271
   811
krista@2271
   812
    ssize_t size = uper_encode_to_new_buffer(&asn_DEF_DeviceGroup_Protocol,
krista@2271
   813
            NULL, msg, (void **) &payload);
krista@2271
   814
    if (size == -1) {
krista@2271
   815
        status = PEP_CANNOT_ENCODE;
krista@2271
   816
        goto error;
krista@2271
   817
    }
krista@2271
   818
krista@2271
   819
    status = prepare_message(me, partner, payload, size, &_message);
krista@2271
   820
    if (status != PEP_STATUS_OK)
krista@2271
   821
        goto error;
krista@2271
   822
    payload = NULL;
krista@2271
   823
    free_identity(me);
krista@2271
   824
    me = NULL;
krista@2271
   825
krista@2271
   826
#ifndef NDEBUG
krista@2271
   827
    asn_enc_rval_t er;
krista@2271
   828
    er = xer_encode(&asn_DEF_DeviceGroup_Protocol, msg, 
krista@2271
   829
                    XER_F_BASIC, _append, &_message->longmsg);
krista@2271
   830
    if(er.encoded == -1)
krista@2271
   831
        goto error;
krista@2271
   832
#endif
krista@2271
   833
krista@2271
   834
    if (encrypted) {
krista@2271
   835
        if (msg->payload.present == DeviceGroup_Protocol__payload_PR_groupKeys || 
krista@2271
   836
            msg->payload.present == DeviceGroup_Protocol__payload_PR_groupUpdate) {
krista@2271
   837
            PEP_rating rating = PEP_rating_undefined;
krista@2271
   838
            status = outgoing_message_rating(session, _message, &rating);
krista@2271
   839
            if (status != PEP_STATUS_OK)
krista@2271
   840
                goto error;
krista@2271
   841
            if (rating < PEP_rating_trusted) {
krista@2271
   842
                status = PEP_SYNC_NO_TRUST;
krista@2271
   843
                goto error;
krista@2271
   844
            }
krista@2271
   845
            
krista@2271
   846
            stringlist_t *keylist = NULL;
krista@2271
   847
            status = _own_keys_retrieve(session, &keylist, PEP_idf_not_for_sync);
krista@2271
   848
            if (status != PEP_STATUS_OK)
krista@2271
   849
                goto error;
krista@2271
   850
krista@2271
   851
            for (stringlist_t *_keylist=keylist; _keylist!=NULL; _keylist=_keylist->next) {
krista@2271
   852
                char *fpr = _keylist->value;
krista@2271
   853
                static char filename[MAX_LINELENGTH];
krista@2271
   854
                int result = snprintf(filename, MAX_LINELENGTH, "file://%s-sec.asc", fpr);
krista@2271
   855
                if (result < 0)
krista@2271
   856
                    goto enomem;
krista@2271
   857
                char *key = NULL;
krista@2271
   858
                size_t size = 0;
krista@2271
   859
                status = export_secrect_key(session, fpr, &key, &size);
krista@2271
   860
                if (status != PEP_STATUS_OK)
krista@2271
   861
                    goto error;
krista@2271
   862
                bloblist_t *bl = bloblist_add(_message->attachments,
krista@2271
   863
                        (char *) key, size, "application/pgp-keys", filename);
krista@2271
   864
                if (!bl)
krista@2271
   865
                    goto enomem;
krista@2271
   866
                if (!_message->attachments)
krista@2271
   867
                    _message->attachments = bl;
krista@2271
   868
            }
krista@2271
   869
        }
krista@2271
   870
krista@2271
   871
        message *_encrypted = NULL;
krista@2271
   872
        status = encrypt_message(session, _message, NULL, &_encrypted, PEP_enc_PEP, 0);
krista@2271
   873
        if (status != PEP_STATUS_OK)
krista@2271
   874
            goto error;
krista@2271
   875
        free_message(_message);
krista@2271
   876
        _message = _encrypted;
krista@2271
   877
    }
krista@2271
   878
    else {
krista@2271
   879
        attach_own_key(session, _message);
krista@2271
   880
    }
krista@2271
   881
krista@2271
   882
    status = session->messageToSend(session->sync_obj, _message);
krista@2271
   883
    return status;
krista@2271
   884
krista@2271
   885
enomem:
krista@2271
   886
    status = PEP_OUT_OF_MEMORY;
krista@2271
   887
error:
krista@2271
   888
    free_identity(_me);
krista@2271
   889
    free(payload);
krista@2271
   890
    free_message(_message);
krista@2271
   891
    free_identity(me);
krista@2271
   892
    return status;
krista@2271
   893
}
krista@2271
   894
krista@2271
   895
PEP_STATUS multicast_self_msg(
krista@2271
   896
        PEP_SESSION session,
krista@2271
   897
        DeviceState_state state,
krista@2271
   898
        DeviceGroup_Protocol_t *msg,
krista@2271
   899
        bool encrypted
krista@2271
   900
    )
krista@2271
   901
{
krista@2271
   902
    PEP_STATUS status = PEP_STATUS_OK;
krista@2271
   903
krista@2271
   904
    assert(session && state && msg);
krista@2271
   905
    if (!(session && state && msg))
krista@2271
   906
        return PEP_ILLEGAL_VALUE;
krista@2271
   907
krista@2271
   908
    identity_list *own_identities = NULL;
krista@2271
   909
    status = _own_identities_retrieve(session, &own_identities, PEP_idf_not_for_sync);
krista@2271
   910
    if (status != PEP_STATUS_OK)
krista@2271
   911
        return status;
krista@2271
   912
krista@2271
   913
    for (identity_list *_i = own_identities; _i && _i->ident; _i = _i->next) {
krista@2271
   914
        pEp_identity *me = _i->ident;
krista@2271
   915
krista@2271
   916
        // FIXME: no deep copy for multicast supported yet
krista@2271
   917
        // DeviceGroup_Protocol_t *_msg = malloc(sizeof(DeviceGroup_Protocol_t));
krista@2271
   918
        // assert(_msg);
krista@2271
   919
        // if (_msg == NULL){
krista@2271
   920
        //     status = PEP_OUT_OF_MEMORY;
krista@2271
   921
        //     goto error;
krista@2271
   922
        // }
krista@2271
   923
        // memcpy(_msg, msg, sizeof(DeviceGroup_Protocol_t));
krista@2271
   924
        status = unicast_msg(session, me, state, msg, encrypted);
krista@2271
   925
        //status = unicast_msg(session, me, state, _msg, encrypted);
krista@2271
   926
        //free_DeviceGroup_Protocol_msg(_msg);
krista@2271
   927
    }
krista@2271
   928
krista@2271
   929
    free_identity_list(own_identities);
krista@2271
   930
    return PEP_STATUS_OK;
krista@2271
   931
krista@2271
   932
// error:
krista@2271
   933
//     free_identity_list(own_identities);
krista@2271
   934
//     return status;
krista@2271
   935
}
krista@2271
   936
krista@2271
   937
void free_group_keys_extra(group_keys_extra_t* group_keys_extra)
krista@2271
   938
{
krista@2271
   939
    identity_list *group_keys = group_keys_extra->group_keys;
krista@2271
   940
    char *group_id = group_keys_extra->group_id;
krista@2271
   941
    free_identity_list(group_keys);
krista@2271
   942
    free(group_id);
krista@2271
   943
    free(group_keys_extra);
krista@2271
   944
}
krista@2271
   945
krista@2271
   946
group_keys_extra_t* group_keys_extra_dup(group_keys_extra_t* group_key_extra_src)
krista@2271
   947
{
krista@2271
   948
    group_keys_extra_t *group_key_extra_dst;
krista@2271
   949
    group_key_extra_dst = calloc(1,sizeof(group_keys_extra_t));
krista@2271
   950
    if(group_key_extra_dst == NULL){
krista@2271
   951
        return NULL;
krista@2271
   952
    }
krista@2271
   953
krista@2271
   954
    char *group_id = strdup(group_key_extra_src->group_id);
krista@2271
   955
krista@2271
   956
    if (group_key_extra_dst->group_id && !group_id){
krista@2271
   957
        free(group_key_extra_dst);
krista@2271
   958
        return NULL;
krista@2271
   959
    }
krista@2271
   960
    group_key_extra_dst->group_id = group_id;
krista@2271
   961
krista@2271
   962
    identity_list *group_keys = identity_list_dup(group_key_extra_src->group_keys);;
krista@2271
   963
    if (!group_keys) {
krista@2271
   964
        free(group_id);
krista@2271
   965
        free(group_key_extra_dst);
krista@2271
   966
        return NULL;
krista@2271
   967
    }
krista@2271
   968
    group_key_extra_dst->group_keys = group_keys;
krista@2271
   969
krista@2271
   970
    return group_key_extra_dst;
krista@2271
   971
}