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