@ -0,0 +1,288 @@ | |||
// This file is under GNU General Public License 3.0 | |||
// see LICENSE.txt | |||
#include "pEp_internal.h" | |||
#include <memory.h> | |||
#include <assert.h> | |||
#include "asn1_helper.h" | |||
#include "../asn.1/DeviceGroup-Protocol.h" | |||
// receive_sync_msg is defined in the sync_impl | |||
PEP_STATUS receive_sync_msg( | |||
PEP_SESSION session, | |||
sync_msg_t *sync_msg, | |||
time_t *timeout | |||
); | |||
DYNAMIC_API PEP_STATUS register_sync_callbacks( | |||
PEP_SESSION session, | |||
void *management, | |||
messageToSend_t messageToSend, | |||
notifyHandshake_t notifyHandshake, | |||
inject_sync_msg_t inject_sync_msg, | |||
retrieve_next_sync_msg_t retrieve_next_sync_msg | |||
) | |||
{ | |||
assert(session && management && messageToSend && notifyHandshake && inject_sync_msg && retrieve_next_sync_msg); | |||
if (!(session && management && messageToSend && notifyHandshake && inject_sync_msg && retrieve_next_sync_msg)) | |||
return PEP_ILLEGAL_VALUE; | |||
pEpUUID uuid; | |||
uuid_generate_random(uuid); | |||
uuid_unparse_upper(uuid, session->sync_uuid); | |||
session->sync_management = management; | |||
session->messageToSend = messageToSend; | |||
session->notifyHandshake = notifyHandshake; | |||
session->inject_sync_msg = inject_sync_msg; | |||
session->retrieve_next_sync_msg = retrieve_next_sync_msg; | |||
// start state machine | |||
session->sync_state = InitState; | |||
time_t unused = 0; | |||
PEP_STATUS status = fsm_DeviceState_inject(session, Init, NULL, NULL, &unused); | |||
if (status != PEP_STATUS_OK) | |||
unregister_sync_callbacks(session); | |||
return status; | |||
} | |||
DYNAMIC_API PEP_STATUS attach_sync_session( | |||
PEP_SESSION session, | |||
PEP_SESSION sync_session | |||
) | |||
{ | |||
assert(session && sync_session && sync_session->sync_management && sync_session->inject_sync_msg ); | |||
if (!(session && sync_session && sync_session->sync_management && sync_session->inject_sync_msg )) | |||
return PEP_ILLEGAL_VALUE; | |||
session->sync_session = sync_session; | |||
// memcpy(session->sync_uuid, sync_session->sync_uuid, 37); | |||
// session->sync_management = sync_session->sync_management; | |||
// session->inject_sync_msg = sync_session->inject_sync_msg; | |||
return PEP_STATUS_OK; | |||
} | |||
DYNAMIC_API PEP_STATUS detach_sync_session(PEP_SESSION session) | |||
{ | |||
assert(session); | |||
if (!(session)) | |||
return PEP_ILLEGAL_VALUE; | |||
session->sync_session = session; | |||
// memset(session->sync_uuid, 0, 37); | |||
// session->sync_management = NULL; | |||
// session->inject_sync_msg = NULL; | |||
return PEP_STATUS_OK; | |||
} | |||
int call_inject_sync_msg(PEP_SESSION session, void *msg) | |||
{ | |||
if(session->sync_session->inject_sync_msg && | |||
session->sync_session->sync_management) | |||
return session->sync_session->inject_sync_msg(msg, | |||
session->sync_session->sync_management); | |||
else | |||
return PEP_SYNC_NO_INJECT_CALLBACK; | |||
} | |||
DYNAMIC_API void unregister_sync_callbacks(PEP_SESSION session) { | |||
// stop state machine | |||
session->sync_state = DeviceState_state_NONE; | |||
// unregister | |||
session->sync_management = NULL; | |||
session->messageToSend = NULL; | |||
session->notifyHandshake = NULL; | |||
session->inject_sync_msg = NULL; | |||
session->retrieve_next_sync_msg = NULL; | |||
} | |||
DYNAMIC_API PEP_STATUS deliverHandshakeResult( | |||
PEP_SESSION session, | |||
Identity partner, | |||
sync_handshake_result result | |||
) | |||
{ | |||
assert(session); | |||
if (!session) | |||
return PEP_ILLEGAL_VALUE; | |||
PEP_STATUS status = PEP_STATUS_OK; | |||
DeviceState_event event; | |||
bool need_partner = false; | |||
switch (result) { | |||
case SYNC_HANDSHAKE_CANCEL: | |||
event = Cancel; | |||
break; | |||
case SYNC_HANDSHAKE_ACCEPTED: | |||
{ | |||
event = HandshakeAccepted; | |||
need_partner = true; | |||
break; | |||
} | |||
case SYNC_HANDSHAKE_REJECTED: | |||
{ | |||
event = HandshakeRejected; | |||
need_partner = true; | |||
break; | |||
} | |||
default: | |||
return PEP_ILLEGAL_VALUE; | |||
} | |||
pEp_identity *_partner = NULL; | |||
if(need_partner){ | |||
_partner = identity_dup(partner); | |||
if (_partner == NULL) | |||
return PEP_OUT_OF_MEMORY; | |||
} | |||
status = inject_DeviceState_event(session, event, _partner, NULL); | |||
return status; | |||
} | |||
DYNAMIC_API PEP_STATUS do_sync_protocol( | |||
PEP_SESSION session, | |||
void *obj | |||
) | |||
{ | |||
sync_msg_t *msg = NULL; | |||
PEP_STATUS status = PEP_STATUS_OK; | |||
time_t timeout = 0; | |||
assert(session && session->retrieve_next_sync_msg); | |||
assert(obj); | |||
if (!(session && session->retrieve_next_sync_msg) || !obj) | |||
return PEP_ILLEGAL_VALUE; | |||
log_event(session, "sync_protocol thread started", "pEp sync protocol", NULL, NULL); | |||
session->sync_obj = obj; | |||
while (true) | |||
{ | |||
msg = (sync_msg_t *) session->retrieve_next_sync_msg(session->sync_management, &timeout); | |||
if(msg == NULL && timeout == 0) | |||
break; | |||
else if(msg == NULL && timeout != 0){ | |||
status = fsm_DeviceState_inject(session, Timeout, NULL, NULL, &timeout); | |||
#ifndef NDEBUG | |||
char buffer[MAX_LINELENGTH]; | |||
memset(buffer, 0, MAX_LINELENGTH); | |||
snprintf(buffer, MAX_LINELENGTH, "problem with timeout event : %d\n", (int) status); | |||
log_event(session, buffer, "pEp sync protocol", NULL, NULL); | |||
continue; | |||
#endif | |||
} | |||
else { | |||
status = receive_sync_msg(session, msg, &timeout); | |||
if (status != PEP_STATUS_OK && status != PEP_MESSAGE_IGNORE) { | |||
#ifndef NDEBUG | |||
char buffer[MAX_LINELENGTH]; | |||
memset(buffer, 0, MAX_LINELENGTH); | |||
snprintf(buffer, MAX_LINELENGTH, "problem with msg received: %d\n", (int) status); | |||
log_event(session, buffer, "pEp sync protocol", NULL, NULL); | |||
#endif | |||
} | |||
} | |||
} | |||
log_event(session, "sync_protocol thread shutdown", "pEp sync protocol", NULL, NULL); | |||
session->sync_obj = NULL; | |||
return PEP_STATUS_OK; | |||
} | |||
DYNAMIC_API PEP_STATUS decode_sync_msg( | |||
const char *data, | |||
size_t size, | |||
char **text | |||
) | |||
{ | |||
PEP_STATUS status = PEP_STATUS_OK; | |||
assert(data && text); | |||
if (!(data && text)) | |||
return PEP_ILLEGAL_VALUE; | |||
*text = NULL; | |||
DeviceGroup_Protocol_t *msg = NULL; | |||
uper_decode_complete(NULL, &asn_DEF_DeviceGroup_Protocol, (void **) &msg, | |||
data, size); | |||
if (!msg) | |||
return PEP_SYNC_ILLEGAL_MESSAGE; | |||
growing_buf_t *dst = new_growing_buf(); | |||
if (!dst) { | |||
status = PEP_OUT_OF_MEMORY; | |||
goto the_end; | |||
} | |||
asn_enc_rval_t er = xer_encode(&asn_DEF_DeviceGroup_Protocol, msg, | |||
XER_F_BASIC, (asn_app_consume_bytes_f *) consume_bytes, (void *) dst); | |||
if (er.encoded == -1) { | |||
status = PEP_CANNOT_ENCODE; | |||
goto the_end; | |||
} | |||
*text = dst->data; | |||
dst->data = NULL; | |||
the_end: | |||
free_growing_buf(dst); | |||
ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); | |||
return status; | |||
} | |||
DYNAMIC_API PEP_STATUS encode_sync_msg( | |||
const char *text, | |||
char **data, | |||
size_t *size | |||
) | |||
{ | |||
PEP_STATUS status = PEP_STATUS_OK; | |||
assert(text && data && size); | |||
if (!(text && data && size)) | |||
return PEP_ILLEGAL_VALUE; | |||
*data = NULL; | |||
*size = 0; | |||
DeviceGroup_Protocol_t *msg = NULL; | |||
asn_dec_rval_t dr = xer_decode(NULL, &asn_DEF_DeviceGroup_Protocol, | |||
(void **) &msg, (const void *) text, strlen(text)); | |||
if (dr.code != RC_OK) { | |||
status = PEP_SYNC_ILLEGAL_MESSAGE; | |||
goto the_end; | |||
} | |||
char *payload = NULL; | |||
ssize_t _size = uper_encode_to_new_buffer(&asn_DEF_DeviceGroup_Protocol, | |||
NULL, msg, (void **) &payload); | |||
if (_size == -1) { | |||
status = PEP_CANNOT_ENCODE; | |||
goto the_end; | |||
} | |||
*data = payload; | |||
*size = (size_t) _size; | |||
the_end: | |||
ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); | |||
return status; | |||
} | |||
@ -0,0 +1,417 @@ | |||
// This file is under GNU General Public License 3.0 | |||
// see LICENSE.txt | |||
/* | |||
==================================== | |||
Engine/adapter/app KeySync interface | |||
==================================== | |||
Engine | Adapter | App | |||
| | | |||
. . . . . . . . . . . .|. . . . . . . . . . . . . . .|. . Attached session . | |||
,---------, | | | |||
,-| decrypt |<--------------------------------------- Incomming message | |||
| | message | | | | |||
| '---------' | | | |||
| ,----------, | | | |||
|-| myself |<-------------------------------------- Create new account | |||
| | (keygen) | | | | |||
| '----------' | | | |||
| ,-----------, | | | |||
|-| deliver |<------------------------------------------- Accept/reject | |||
| | handshake | | KeySync | handshake | |||
| | result | | Message | | |||
| '-----------' | Queue | | |||
| | ,---, | | |||
'-----------------------inject_sync_msg---->| | | | |||
. . . . . . . . . . . .|. . . . . . . . . . . |---| .|. . . . Sync session . | |||
* * * * * * * * * * * * * * * *| |* | | |||
| |---| | | |||
* ,------------------retrieve_next_sync_msg-| |* | | |||
,-v--------, | '---' | | |||
* | Driver | | * | | |||
'----------' | | | |||
* ||'-event-----, | * | | |||
|'--partner--,| | | | |||
* '---extra---,|| | SYNC THREAD *<-------------- Start Sync | |||
,---vvv---, | | | |||
* ,----| FSM | | * | | |||
| '---------' | | | |||
* | ,-------, | * | | |||
'->|actions|---------messageToSend-------------------> Send mail to self | |||
* '-------' | * | | |||
'-------------notifyHandshake-----------------> Ask for handshake | |||
* | * | display group status | |||
| | | |||
* * * * * * * * |* * * * * * * * * * | | |||
| | | |||
Emails to self | |||
-------------- | |||
With e-mail as a transport KeySync message handling is done when an incoming | |||
email to self is passed to decrypt_message(), assuming that all incoming email | |||
messages are passed to decrypt_massage(). | |||
In case of an email containing a KeySync paload, KeySync may consume or ignore | |||
the message. decrypt_message() signals this to the app with decrypt flags | |||
PEP_decrypt_flag_consume and PEP_decrypt_flag_ignore. | |||
In case of PEP_decrypt_flag_consume, app should delete the message. | |||
In case of PEP_decrypt_flag_ignore, app should ignore message. | |||
In both cases, message should be hidden. | |||
States, events, actions | |||
----------------------- | |||
In the engine, KeySync is implemented through a finite state machine (FSM) [1]. | |||
KeySync state machine is driven [2] by events, triggering actions [3] and | |||
transitions to new states. | |||
Events happen on : | |||
- decryption of email messages | |||
- key generation | |||
- user interaction through the app | |||
- timeout when staying too long in some particular states. | |||
[1] sync/devicegroup.fsm , src/sync_fsm.c (generated) | |||
[2] src/sync_driver.c (generated) | |||
[3] src/sync_actions.c , src/sync_send_actions.c (generated) | |||
Sync session, attached sessions | |||
------------------------------- | |||
To use KeySync, the adapter has to create a session dedicated to handle the | |||
protocol, register some callbacks [4] to the engine, and then call protocol's | |||
event consumer loop [5] in a dedicated thread. KeySync actions are executed as | |||
callback invoked from that thread. | |||
When a session is attached [6] to a KeySync session, decryption of pEp email | |||
messages in the attached session may trigger operations in KeySync session. In | |||
case of an adapter capable to serve multiple apps, each app is associated to a | |||
different KeySync session, and sessions created for use in that app are | |||
attached to that session. | |||
Adapters present different approaches regarding session and client abstraction, | |||
and may not propose to explicitely create or attach session or sync session. | |||
[4] register_sync_callbacks() | |||
[5] do_sync_protocol() | |||
[6] attach_sync_session() | |||
KeySync Messages and queue | |||
-------------------------- | |||
KeySync messages [7], not to be confused with pEp (email) messages, are either | |||
directly events to be processed by the state machine, or KeySync payloads | |||
collected from decrypted messages. | |||
KeySync messages can be emitted by different sessions, and could naturally come | |||
from different threads. They must be serialized in a locked queue. | |||
KeySync messages queue is implemented by adapter, along with thread handling | |||
KeySync protocol. | |||
Attached sessions inject [8] KeySync messages in the queue. Protocol loop | |||
retrieves [9] them from the queue. KeySync message is received [10] by the | |||
state machine, where event, partner and extra parameters are eventually deduced | |||
from payload. | |||
A state timeout event is a particular case. It doesn't traverse the queue, and | |||
isn't emitted by a session. It is triggered by a timeout on the retrieve | |||
operation. Value of the timeout is determined when entering a new state, and is | |||
passed as a parameter of the call to the blocking queue retrieve operation on | |||
next protocol loop iteraton. | |||
[7] type sync_msg_t | |||
[8] callback inject_sync_msg | |||
[9] callback retrieve_next_sync_msg | |||
[10] receive_sync_msg() (src/sync_impl.c) | |||
Application callbacks | |||
--------------------- | |||
Some Keysync actions require the application to act, through callbacks : | |||
- messageToSend : send pEp messages through app's transport. | |||
Messages are already encrypted and just need to be passed as-is to | |||
transport for transmission, as for messages returned by encrypt_message(). | |||
- notifyHandshake : display KeySync status and handshake to the user. | |||
notifyHandshake callback receives 2 identities, 'me' and 'partner', together | |||
with a sync_handshake_signal enum : | |||
SYNC_NOTIFY_INIT_ADD_OUR_DEVICE : | |||
Device (me) is sole, about to enter a group (partner). | |||
App displays trustwords, and requests user accept or reject | |||
App calls deliverHandshakeResult with user's answer | |||
SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE : | |||
Device (me) is grouped, another device (partner) wants to join group. | |||
App displays trustwords, and requests user accept or reject | |||
App calls deliverHandshakeResult with user's answer | |||
SYNC_NOTIFY_INIT_FORM_GROUP : | |||
Device (me) is forming a group, including another device (partner) | |||
App displays trustwords, and requests user accept or reject | |||
App calls deliverHandshakeResult with user's answer | |||
SYNC_NOTIFY_INIT_MOVE_OUR_DEVICE | |||
Device (me) is grouped and will leave current group to join another | |||
device's (partner) group. | |||
App displays trustwords, and requests user accept or reject | |||
App calls deliverHandshakeResult with user's answer | |||
SYNC_NOTIFY_TIMEOUT : | |||
KeySync operation timed out. | |||
Identities are set reflecting peers involved in aborted operation. | |||
App displays error message. No feedback to engine. | |||
SYNC_NOTIFY_ACCEPTED_DEVICE_ADDED, | |||
New device was added to group. | |||
App displays message. No feedback to engine. | |||
SYNC_NOTIFY_ACCEPTED_GROUP_CREATED | |||
New group created. | |||
App displays message. No feedback to engine. | |||
SYNC_NOTIFY_ACCEPTED_DEVICE_MOVED | |||
New device was moved from one group to another. | |||
App displays message. No feedback to engine. | |||
To deliver handshake result back to engine once user reacted, | |||
deliver_handshake_result is used. Result can be : | |||
SYNC_HANDSHAKE_CANCEL | |||
Gives no answer. User doesn't know id TrustWord are good or bad. | |||
For example in case peering device is away. | |||
Handshake will re-appear later. | |||
SYNC_HANDSHAKE_ACCEPTED | |||
Trustwords match with other device and user accepts handshake. | |||
SYNC_HANDSHAKE_REJECTED | |||
Trustwords do not match with any device and user rejects handshake. | |||
*/ | |||
#pragma once | |||
#include "message.h" | |||
#include "sync_fsm.h" | |||
#include "sync_app.h" | |||
// this module is for being used WITHOUT the Transport API in transport.h | |||
// DO NOT USE IT WHEN USING Transport API! | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
// messageToSend() - send a message | |||
// | |||
// parameters: | |||
// obj (in) object handle (implementation defined) | |||
// msg (in) message struct with message to send | |||
// | |||
// return value: | |||
// PEP_STATUS_OK or any other value on error | |||
// | |||
// caveat: | |||
// the ownership of msg goes to the callee | |||
typedef PEP_STATUS (*messageToSend_t)(void *obj, message *msg); | |||
// notifyHandshake() - notify UI about sync handshaking process | |||
// | |||
// parameters: | |||
// obj (in) object handle (implementation defined) | |||
// me (in) own identity | |||
// partner (in) identity of partner | |||
// signal (in) reason of the notification | |||
// | |||
// return value: | |||
// PEP_STATUS_OK or any other value on error | |||
// | |||
// caveat: | |||
// ownership of self and partner go to the callee | |||
typedef PEP_STATUS (*notifyHandshake_t)( | |||
void *obj, | |||
pEp_identity *me, | |||
pEp_identity *partner, | |||
sync_handshake_signal signal | |||
); | |||
typedef enum _sync_handshake_result { | |||
SYNC_HANDSHAKE_CANCEL = -1, | |||
SYNC_HANDSHAKE_ACCEPTED = 0, | |||
SYNC_HANDSHAKE_REJECTED = 1 | |||
} sync_handshake_result; | |||
// deliverHandshakeResult() - give the result of the handshake dialog | |||
// | |||
// parameters: | |||
// session (in) session handle | |||
// result (in) handshake result | |||
DYNAMIC_API PEP_STATUS deliverHandshakeResult( | |||
PEP_SESSION session, | |||
Identity partner, | |||
sync_handshake_result result | |||
); | |||
// sync_msg_t - items queued for serialized handling by protocol engine | |||
typedef struct _sync_msg_t sync_msg_t; | |||
// inject_sync_msg - inject sync protocol message | |||
// | |||
// parameters: | |||
// msg (in) message to inject | |||
// management (in) application defined | |||
// | |||
// *** BEWARE: msg is 1st parameter, obj is second!!! *** | |||
// return value: | |||
// 0 if msg could be stored successfully or nonzero otherwise | |||
typedef int (*inject_sync_msg_t)(void *msg, void *management); | |||
// retrieve_next_sync_msg - receive next sync message | |||
// | |||
// parameters: | |||
// management (in) application defined | |||
// timeout (in,out) do not wait longer than timeout for message | |||
// timeout == NULL or *timeout == 0 is blocking | |||
// | |||
// return value: | |||
// next message, then timeout[out] == remaining time | |||
// NULL and timeout[out] != 0 for timeout occurence | |||
// NULL and timeout[out] == 0 for termination | |||
typedef void *(*retrieve_next_sync_msg_t)(void *management, time_t *timeout); | |||
// register_sync_callbacks() - register adapter's callbacks | |||
// | |||
// parameters: | |||
// session (in) session where to store obj handle | |||
// management (in) application defined | |||
// messageToSend (in) callback for sending message | |||
// notifyHandshake (in) callback for doing the handshake | |||
// retrieve_next_sync_msg (in) callback for receiving sync messages | |||
// | |||
// return value: | |||
// PEP_STATUS_OK or any other value on errror | |||
// | |||
// caveat: | |||
// call that BEFORE you're using any other part of the engine | |||
DYNAMIC_API PEP_STATUS register_sync_callbacks( | |||
PEP_SESSION session, | |||
void *management, | |||
messageToSend_t messageToSend, | |||
notifyHandshake_t notifyHandshake, | |||
inject_sync_msg_t inject_sync_msg, | |||
retrieve_next_sync_msg_t retrieve_next_sync_msg | |||
); | |||
// attach_sync_session() - attach session to a session running keysync state machine | |||
// | |||
// parameters: | |||
// session (in) session to attach | |||
// sync_session (in) session running keysync | |||
// | |||
// return value: | |||
// PEP_STATUS_OK or any other value on errror | |||
// | |||
// caveat: | |||
// register_sync_callbacks must have been called on sync_session | |||
// call that BEFORE you're using that session in any other part of the engine | |||
DYNAMIC_API PEP_STATUS attach_sync_session( | |||
PEP_SESSION session, | |||
PEP_SESSION sync_session | |||
); | |||
// detach_sync_session() - detach previously attached sync session | |||
// | |||
// parameters: | |||
// session (in) session to detach | |||
DYNAMIC_API PEP_STATUS detach_sync_session(PEP_SESSION session); | |||
// unregister_sync_callbacks() - unregister adapter's callbacks | |||
// | |||
// parameters: | |||
// session (in) session to unregister | |||
DYNAMIC_API void unregister_sync_callbacks(PEP_SESSION session); | |||
// do_sync_protocol() - function to be run on an extra thread | |||
// | |||
// parameters: | |||
// session pEp session to use | |||
// retrieve_next_sync_msg pointer to retrieve_next_identity() callback | |||
// which returns at least a valid address field in | |||
// the identity struct | |||
// obj application defined sync object | |||
// | |||
// return value: | |||
// PEP_STATUS_OK if thread has to terminate successfully or any other | |||
// value on failure | |||
// | |||
// caveat: | |||
// to ensure proper working of this library, a thread has to be started | |||
// with this function immediately after initialization | |||
DYNAMIC_API PEP_STATUS do_sync_protocol( | |||
PEP_SESSION session, | |||
void *obj | |||
); | |||
// free_sync_msg() - free sync_msg_t struct when not passed to do_sync_protocol | |||
// | |||
// parameters: | |||
// sync_msg (in) pointer to sync_msg_t struct to free. | |||
// pointer can be NULL. | |||
DYNAMIC_API void free_sync_msg(sync_msg_t *sync_msg); | |||
// decode_sync_msg() - decode sync message from PER into XER | |||
// | |||
// parameters: | |||
// data (in) PER encoded data | |||
// size (in) size of PER encoded data | |||
// text (out) XER text of the same sync message | |||
DYNAMIC_API PEP_STATUS decode_sync_msg( | |||
const char *data, | |||
size_t size, | |||
char **text | |||
); | |||
// encode_sync_msg() - encode sync message from XER into PER | |||
// | |||
// parameters: | |||
// text (in) string with XER text of the sync message | |||
// data (out) PER encoded data | |||
// size (out) size of PER encoded data | |||
DYNAMIC_API PEP_STATUS encode_sync_msg( | |||
const char *text, | |||
char **data, | |||
size_t *size | |||
); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
@ -0,0 +1,434 @@ | |||
// This file is under GNU General Public License 3.0 | |||
// see LICENSE.txt | |||
// Actions for DeviceState state machine | |||
#include <assert.h> | |||
#include "pEp_internal.h" | |||
#include "message.h" | |||
#include "sync_fsm.h" | |||
#include "sync_impl.h" | |||
#include "map_asn1.h" | |||
#include "baseprotocol.h" | |||
// conditions | |||
int deviceGrouped(PEP_SESSION session) | |||
{ | |||
assert(session); | |||
if (!session) | |||
return invalid_condition; // error | |||
char *devgrp = NULL; | |||
int res = 0; | |||
PEP_STATUS status; | |||
status = get_device_group(session, &devgrp); | |||
if (status == PEP_STATUS_OK && devgrp && devgrp[0]) | |||
res = 1; | |||
free(devgrp); | |||
return res; | |||
} | |||
int keyElectionWon(PEP_SESSION session, Identity partner) | |||
{ | |||
assert(session); | |||
assert(partner); | |||
if (!(session && partner)) | |||
return invalid_condition; // error | |||
int partner_is_group = partner->flags & PEP_idf_devicegroup; | |||
if (deviceGrouped(session)){ | |||
// existing group always wins against sole device | |||
if(!partner_is_group) | |||
return 1; | |||
} else { | |||
// sole device always loses against group | |||
if(partner_is_group) | |||
return 0; | |||
} | |||
// two groups or two sole are elected based on key age | |||
// key created first wins | |||
Identity me = NULL; | |||
PEP_STATUS status = get_identity(session, partner->address, PEP_OWN_USERID, | |||
&me); | |||
if (status == PEP_OUT_OF_MEMORY) | |||
return invalid_out_of_memory; | |||
if (status != PEP_STATUS_OK) | |||
return invalid_condition; // error | |||
int result = invalid_condition; // error state has to be overwritten | |||
time_t own_created; | |||
time_t partners_created; | |||
status = key_created(session, me->fpr, &own_created); | |||
if (status != PEP_STATUS_OK) | |||
goto the_end; | |||
status = key_created(session, partner->fpr, &partners_created); | |||
if (status != PEP_STATUS_OK) | |||
goto the_end; | |||
if (own_created > partners_created) | |||
result = 0; | |||
else | |||
result = 1; | |||
the_end: | |||
free_identity(me); | |||
return result; | |||
} | |||
int sameIdentities(PEP_SESSION session, Identity a, Identity b) | |||
{ | |||
assert(session); | |||
assert(a); | |||
assert(b); | |||
if (!(session && a && b)) | |||
return invalid_condition; // error | |||
if (a->fpr == NULL || b->fpr == NULL || | |||
(!_same_fpr(a->fpr, strlen(a->fpr), b->fpr, strlen(b->fpr))) || | |||
a->address == NULL || b->address == NULL || | |||
strcmp(a->address, b->address) != 0 || | |||
a->user_id == NULL || b->user_id == NULL || | |||
strcmp(a->user_id, b->user_id) != 0) | |||
return 0; | |||
return 1; | |||
} | |||
int sameKeyAndAddress(PEP_SESSION session, Identity a, Identity b) | |||
{ | |||
assert(session); | |||
assert(a); | |||
assert(b); | |||
if (!(session && a && b)) | |||
return invalid_condition; // error | |||
if (a->fpr == NULL || b->fpr == NULL || | |||
(!_same_fpr(a->fpr, strlen(a->fpr), b->fpr, strlen(b->fpr))) || | |||
a->address == NULL || b->address == NULL || | |||
strcmp(a->address, b->address) != 0) | |||
return 0; | |||
return 1; | |||
} | |||
// actions | |||
PEP_STATUS _notifyHandshake( | |||
PEP_SESSION session, | |||
Identity partner, | |||
sync_handshake_signal signal | |||
) | |||
{ | |||
PEP_STATUS status = PEP_STATUS_OK; | |||
assert(session); | |||
assert(partner); | |||
if (!(session && partner)) | |||
return PEP_ILLEGAL_VALUE; | |||
assert(session->notifyHandshake); | |||
if (!session->notifyHandshake) | |||
return PEP_SYNC_NO_NOTIFY_CALLBACK; | |||
// notifyHandshake take ownership of given identities | |||
pEp_identity *me = NULL; | |||
status = get_identity(session, partner->address, PEP_OWN_USERID, &me); | |||
if (status != PEP_STATUS_OK) | |||
goto error; | |||
pEp_identity *_partner = NULL; | |||
_partner = identity_dup(partner); | |||
if (_partner == NULL){ | |||
status = PEP_OUT_OF_MEMORY; | |||
goto error; | |||
} | |||
status = session->notifyHandshake(session->sync_obj, me, _partner, signal); | |||
if (status != PEP_STATUS_OK) | |||
goto error; | |||
return status; | |||
error: | |||
free_identity(me); | |||
return status; | |||
} | |||
// acceptHandshake() - stores acception of partner | |||
// | |||
// params: | |||
// session (in) session handle | |||
// state (in) state the state machine is in | |||
// partner (in) partner to communicate with | |||
// | |||
// returns: | |||
// PEP_STATUS_OK or any other value on error | |||
PEP_STATUS acceptHandshake( | |||
PEP_SESSION session, | |||
DeviceState_state state, | |||
Identity partner, | |||
void *extra | |||
) | |||
{ | |||
PEP_STATUS status = PEP_STATUS_OK; | |||
assert(session); | |||
assert(partner); | |||
assert(extra == NULL); | |||
if (!(session && partner)) | |||
return PEP_ILLEGAL_VALUE; | |||
status = trust_personal_key(session, partner); | |||
return status; | |||
} | |||
// rejectHandshake() - stores rejection of partner | |||
// | |||
// params: | |||
// session (in) session handle | |||
// state (in) state the state machine is in | |||
// partner (in) partner to communicate with | |||
// | |||
// returns: | |||
// PEP_STATUS_OK or any other value on error | |||
PEP_STATUS rejectHandshake( | |||
PEP_SESSION session, | |||
DeviceState_state state, | |||
Identity partner, | |||
void *extra | |||
) | |||
{ | |||
PEP_STATUS status = PEP_STATUS_OK; | |||
assert(session); | |||
assert(partner); | |||
assert(extra == NULL); | |||
if (!(session && partner)) | |||
return PEP_ILLEGAL_VALUE; | |||
// TODO : disable sync globally if not in a group | |||
status = set_identity_flags(session, partner, | |||
partner->flags | PEP_idf_not_for_sync); | |||
return status; | |||
} | |||
PEP_STATUS _storeGroupKeys( | |||
PEP_SESSION session, | |||
identity_list *group_keys | |||
) | |||
{ | |||
PEP_STATUS status = PEP_STATUS_OK; | |||
for (identity_list *il = group_keys; il && il->ident; il = il->next) { | |||
if (strcmp(il->ident->user_id, PEP_OWN_USERID)!=0) { | |||
assert(0); | |||
continue; | |||
} | |||
// Check that identity isn't excluded from sync. | |||
pEp_identity *stored_identity = NULL; | |||
status = get_identity(session, il->ident->address, PEP_OWN_USERID, | |||
&stored_identity); | |||
if (status == PEP_STATUS_OK) { | |||
if(stored_identity->flags & PEP_idf_not_for_sync){ | |||
free_identity(stored_identity); | |||
continue; | |||
} | |||
free_identity(stored_identity); | |||
} | |||
status = set_identity(session, il->ident); | |||
if (status != PEP_STATUS_OK) | |||
break; | |||
} | |||
return status; | |||
} | |||
// storeGroupKeys() - | |||
// | |||
// params: | |||
// session (in) session handle | |||
// state (in) state the state machine is in | |||
// partner (in) partner to communicate with | |||
// _group_keys (in) group keys received from partner | |||
// | |||
// returns: | |||
// PEP_STATUS_OK or any other value on error | |||
PEP_STATUS storeGroupKeys( | |||
PEP_SESSION session, | |||
DeviceState_state state, | |||
Identity partner, | |||
void *group_keys_extra_ | |||
) | |||
{ | |||
PEP_STATUS status = PEP_STATUS_OK; | |||
assert(session); | |||
assert(partner); | |||
assert(group_keys_extra_); | |||
if (!(session && partner && group_keys_extra_)) | |||
return PEP_ILLEGAL_VALUE; | |||
group_keys_extra_t *group_keys_extra = | |||
(group_keys_extra_t*) group_keys_extra_; | |||
identity_list *group_keys = group_keys_extra->group_keys; | |||
char *group_id = group_keys_extra->group_id; | |||
status = _storeGroupKeys(session, group_keys); | |||
if (status != PEP_STATUS_OK) | |||
return status; | |||
// set group id according to given group-id | |||
status = set_device_group(session, group_id); | |||
if (status != PEP_STATUS_OK) | |||
return status; | |||
return status; | |||
} | |||
// storeGroupUpdate() - | |||
// | |||
// params: | |||
// session (in) session handle | |||
// state (in) state the state machine is in | |||
// partner (in) partner to communicate with | |||
// _group_keys (in) group keys received from partner | |||
// | |||
// returns: | |||
// PEP_STATUS_OK or any other value on error | |||
PEP_STATUS storeGroupUpdate( | |||
PEP_SESSION session, | |||
DeviceState_state state, | |||
Identity partner, | |||
void *group_keys_ | |||
) | |||
{ | |||
PEP_STATUS status = PEP_STATUS_OK; | |||
assert(session); | |||
assert(partner); | |||
assert(group_keys_); | |||
if (!(session && partner && group_keys_)) | |||
return PEP_ILLEGAL_VALUE; | |||
identity_list *group_keys = (identity_list*) group_keys_; | |||
status = _storeGroupKeys(session, group_keys); | |||
return status; | |||
} | |||
// makeGroup() - | |||
// | |||
// params: | |||
// session (in) session handle | |||
// state (in) state the state machine is in | |||
// partner (in) ignored | |||
// extra (in) ignored | |||
// | |||
// returns: | |||
// PEP_STATUS_OK or any other value on error | |||
PEP_STATUS makeGroup( | |||
PEP_SESSION session, | |||
DeviceState_state state, | |||
Identity partner, | |||
void *extra | |||
) | |||
{ | |||
PEP_STATUS status = PEP_STATUS_OK; | |||
assert(session); | |||
// make a new uuid | |||
char new_uuid[37]; | |||
pEpUUID uuid; | |||
uuid_generate_random(uuid); | |||
uuid_unparse_upper(uuid, new_uuid); | |||
// take that new uuid as group-id | |||
status = set_device_group(session, new_uuid); | |||
return status; | |||
} | |||
// renewUUID() - | |||
// | |||
// params: | |||
// session (in) session handle | |||
// state (in) state the state machine is in | |||
// partner (in) ignored | |||
// extra (in) ignored | |||
// | |||
// returns: | |||
// PEP_STATUS_OK or any other value on error | |||
PEP_STATUS renewUUID( | |||
PEP_SESSION session, | |||
DeviceState_state state, | |||
Identity partner, | |||
void *extra | |||
) | |||
{ | |||
PEP_STATUS status = PEP_STATUS_OK; | |||
assert(session); | |||
// change sync_uuid when entering group | |||
// thus ignoring unprocessed handshakes | |||
// addressed to previous self (sole) once in. | |||
pEpUUID uuid; | |||
uuid_generate_random(uuid); | |||
uuid_unparse_upper(uuid, session->sync_uuid); | |||
return status; | |||
} | |||
// leaveGroup() - | |||
// | |||
// params: | |||
// session (in) session handle | |||
// state (in) state the state machine is in | |||
// partner (in) ignored | |||
// extra (in) ignored | |||
// | |||
// returns: | |||
// PEP_STATUS_OK or any other value on error | |||
PEP_STATUS leaveGroup( | |||
PEP_SESSION session, | |||
DeviceState_state state, | |||
Identity partner, | |||
void *extra | |||
) | |||
{ | |||
PEP_STATUS status = PEP_STATUS_OK; | |||
assert(session); | |||
status = set_device_group(session, NULL); | |||
return status; | |||
} |
@ -0,0 +1,34 @@ | |||
// | |||
// sync_app.h | |||
// pEpEngine | |||
// | |||
// Created by Dirk Zimmermann on 16.05.17. | |||
// Copyright © 2017 Edouard Tisserant. All rights reserved. | |||
// | |||
#ifndef sync_app_h | |||
#define sync_app_h | |||
// TODO add this to generated code. | |||
typedef enum _sync_handshake_signal { | |||
SYNC_NOTIFY_UNDEFINED = 0, | |||
// request show handshake dialog | |||
SYNC_NOTIFY_INIT_ADD_OUR_DEVICE, | |||
SYNC_NOTIFY_INIT_ADD_OTHER_DEVICE, | |||
SYNC_NOTIFY_INIT_FORM_GROUP, | |||
SYNC_NOTIFY_INIT_MOVE_OUR_DEVICE, | |||
// handshake process timed out | |||
SYNC_NOTIFY_TIMEOUT, | |||
// handshake accepted by user | |||
SYNC_NOTIFY_ACCEPTED_DEVICE_ADDED, | |||
SYNC_NOTIFY_ACCEPTED_GROUP_CREATED, | |||
SYNC_NOTIFY_ACCEPTED_DEVICE_MOVED, | |||
// handshake dialog must be closed | |||
SYNC_NOTIFY_OVERTAKEN | |||
} sync_handshake_signal; | |||
#endif /* sync_app_h */ |
@ -0,0 +1,971 @@ | |||
// This file is under GNU General Public License 3.0 | |||
// see LICENSE.txt | |||
#include "platform.h" | |||
// it seems pEp_internal.h needs to be the first pEp include due to the | |||
// #define for the dllimport / dllexport DYNAMIC_API stuff. | |||
#include "pEp_internal.h" | |||
#include "sync_impl.h" | |||
#include "keymanagement.h" | |||
#include "message_api.h" | |||
#include "map_asn1.h" | |||
#include "baseprotocol.h" | |||
#define SYNC_VERSION_MAJOR 1 | |||
#define SYNC_VERSION_MINOR 0 | |||
#define SYNC_INHIBIT_TIME (60*10) | |||
#define SYNC_MSG_EXPIRE_TIME (60 * 10) | |||
struct _sync_msg_t { | |||
bool is_a_message; | |||
union { | |||
DeviceGroup_Protocol_t *message; | |||
struct { | |||
DeviceState_event event; | |||
Identity partner; | |||
void *extra; | |||
} event; | |||
} u; | |||
}; | |||
static bool _is_own_uuid( PEP_SESSION session, UTF8String_t *uuid) | |||
{ | |||
return strncmp(session->sync_session->sync_uuid, | |||
(const char*)uuid->buf, uuid->size) == 0; | |||
} | |||
static bool _is_own_group_uuid( PEP_SESSION session, UTF8String_t *uuid, char** our_group) | |||
{ | |||
PEP_STATUS status = PEP_STATUS_OK; | |||
char *devgrp = NULL; | |||
if(our_group == NULL || *our_group == NULL) | |||
status = get_device_group(session, &devgrp); | |||
else | |||
devgrp = *our_group; | |||
bool res = (status == PEP_STATUS_OK && devgrp && devgrp[0] && | |||
strncmp(devgrp,(const char*)uuid->buf, uuid->size) == 0); | |||
if(our_group == NULL) | |||
free(devgrp); | |||
else if(*our_group == NULL) | |||
*our_group = devgrp; | |||
return res; | |||
} | |||
PEP_STATUS receive_sync_msg( | |||
PEP_SESSION session, | |||
sync_msg_t *sync_msg, | |||
time_t *timeout | |||
) | |||
{ | |||
PEP_STATUS status; | |||
void *extra = NULL; | |||
Identity partner = NULL; | |||
DeviceState_event event = DeviceState_event_NONE; | |||
assert(session && sync_msg); | |||
if (!(session && sync_msg)) | |||
return PEP_ILLEGAL_VALUE; | |||
bool msgIsFromGroup = false; | |||
if(sync_msg->is_a_message){ | |||
DeviceGroup_Protocol_t *msg = sync_msg->u.message; | |||
assert(msg && msg->payload.present != DeviceGroup_Protocol__payload_PR_NOTHING); | |||
if (!(msg && msg->payload.present != DeviceGroup_Protocol__payload_PR_NOTHING)){ | |||
status = PEP_OUT_OF_MEMORY; | |||
goto error; | |||
} | |||
partner = Identity_to_Struct(&msg->header.me, NULL); | |||
if (!partner){ | |||
status = PEP_OUT_OF_MEMORY; | |||
ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); | |||
goto error; | |||
} | |||
msgIsFromGroup = msg->header.devicegroup; | |||
switch (msg->payload.present) { | |||
case DeviceGroup_Protocol__payload_PR_beacon: | |||
event = Beacon; | |||
break; | |||
case DeviceGroup_Protocol__payload_PR_handshakeRequest: | |||
{ | |||
// re-check uuid in case sync_uuid or group changed while in the queue | |||
char *own_group_id = NULL; | |||
bool is_for_me = _is_own_uuid(session, | |||
msg->payload.choice.handshakeRequest.partner_id); | |||
bool is_for_group = !is_for_me && _is_own_group_uuid(session, | |||
msg->payload.choice.handshakeRequest.partner_id, &own_group_id); | |||
if (!(is_for_me || is_for_group)){ | |||
status = PEP_MESSAGE_IGNORE; | |||
goto error; | |||
} | |||
UTF8String_t *guuid = msg->payload.choice.handshakeRequest.group_id; | |||
if(msgIsFromGroup && guuid && guuid->buf && guuid->size) { | |||
bool is_from_own_group = _is_own_group_uuid(session, | |||
guuid, &own_group_id); | |||
// Filter handshake requests from own group | |||
if(is_from_own_group) { | |||
status = PEP_MESSAGE_IGNORE; | |||
goto error; | |||
} | |||
// if it comes from another group, | |||
// we want to communicate with that group | |||
// insert group_id given in handshake request | |||
// into partner's id | |||
free(partner->user_id); | |||
partner->user_id = strndup((const char*)guuid->buf, guuid->size); | |||
if(partner->user_id == NULL){ | |||
status = PEP_OUT_OF_MEMORY; | |||
goto error; | |||
} | |||
// if it comes from another group, and we are grouped, | |||
// then this is groupmerge | |||
} | |||
event = HandshakeRequest; | |||
break; | |||
} | |||
case DeviceGroup_Protocol__payload_PR_updateRequest: | |||
event = UpdateRequest; | |||
break; | |||
case DeviceGroup_Protocol__payload_PR_groupKeys: | |||
{ | |||
// re-check uuid in case sync_uuid or group_uuid changed while in the queue | |||
char *own_group_id = NULL; | |||
UTF8String_t *puuid = msg->payload.choice.groupKeys.partner_id; | |||
bool is_for_me = _is_own_uuid(session, puuid); | |||
bool is_for_group = !is_for_me && | |||
_is_own_group_uuid(session, | |||
puuid, &own_group_id); | |||
if (!(is_for_me || is_for_group)){ | |||
status = PEP_MESSAGE_IGNORE; | |||
goto error; | |||
} | |||
UTF8String_t *guuid = msg->payload.choice.groupKeys.group_id; | |||
// GroupKeys come from groups, no choice | |||
if(!(msgIsFromGroup && guuid && guuid->buf && guuid->size)) { | |||
status = PEP_SYNC_ILLEGAL_MESSAGE; | |||
goto error; | |||
} | |||
// Filter groupKeys from own group | |||
bool is_from_own_group = _is_own_group_uuid(session, | |||
guuid, | |||
&own_group_id); | |||
if(is_from_own_group) { | |||
// FixMe : protocol shouldn't allow this | |||
status = PEP_SYNC_ILLEGAL_MESSAGE; | |||
goto error; | |||
} | |||
// insert group_id given in groupKeys into partner's id | |||
free(partner->user_id); | |||
partner->user_id = strndup((const char*)guuid->buf, guuid->size); | |||
if(partner->user_id == NULL){ | |||
status = PEP_OUT_OF_MEMORY; | |||
goto error; | |||
} | |||
// if it comes from another group, and we are grouped, | |||
// then this is groupmerge's groupKeys | |||
group_keys_extra_t *group_keys_extra; | |||
group_keys_extra = malloc(sizeof(group_keys_extra_t)); | |||
if(group_keys_extra == NULL){ | |||
status = PEP_OUT_OF_MEMORY; | |||
ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); | |||
goto error; | |||
} | |||
char *group_id = strndup((char*)guuid->buf, guuid->size); | |||
if (!group_id){ | |||
status = PEP_OUT_OF_MEMORY; | |||
free(group_keys_extra); | |||
ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); | |||
goto error; | |||
} | |||
group_keys_extra->group_id = group_id; | |||
identity_list *group_keys = IdentityList_to_identity_list( | |||
&msg->payload.choice.groupKeys.ownIdentities, | |||
NULL); | |||
if (!group_keys) { | |||
status = PEP_OUT_OF_MEMORY; | |||
free(group_id); | |||
free(group_keys_extra); | |||
ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); | |||
goto error; | |||
} | |||
group_keys_extra->group_keys = group_keys; | |||
extra = (void *) group_keys_extra; | |||
event = GroupKeys; | |||
break; | |||
} | |||
case DeviceGroup_Protocol__payload_PR_groupUpdate: | |||
{ | |||
identity_list *group_keys = IdentityList_to_identity_list( | |||
&msg->payload.choice.groupUpdate.ownIdentities, NULL); | |||
if (!group_keys) { | |||
status = PEP_OUT_OF_MEMORY; | |||
ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); | |||
goto error; | |||
} | |||
extra = (void *) group_keys; | |||
event = GroupUpdate; | |||
break; | |||
} | |||
default: | |||
status = PEP_SYNC_ILLEGAL_MESSAGE; | |||
ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); | |||
goto error; | |||
} | |||
} | |||
else{ | |||
partner = sync_msg->u.event.partner; | |||
extra = sync_msg->u.event.extra; | |||
event = sync_msg->u.event.event; | |||
} | |||
// Event inhibition, to limit mailbox and prevent cycles | |||
time_t *last = NULL; | |||
switch(event){ | |||
case CannotDecrypt: | |||
last = &session->LastCannotDecrypt; | |||
break; | |||
case UpdateRequest: | |||
last = &session->LastUpdateRequest; | |||
break; | |||
default: | |||
break; | |||
} | |||
if(last != NULL){ | |||
time_t now = time(NULL); | |||
if(*last != 0 && (*last + SYNC_INHIBIT_TIME) > now ){ | |||
status = PEP_STATEMACHINE_INHIBITED_EVENT; | |||
goto error; | |||
} | |||
*last = now; | |||
} | |||
// partner identity must be explicitely added DB to later | |||
// be able to communicate securely with it. | |||
if(partner){ | |||
// protect virtual user IDs | |||
if((strncmp("TOFU_", partner->user_id, 6) == 0 && | |||
strlen(partner->user_id) == strlen(partner->address) + 6 && | |||
strcmp(partner->user_id + 6, partner->address)) || | |||
// protect own ID | |||
(strcmp(PEP_OWN_USERID, partner->user_id) == 0)){ | |||
status = PEP_SYNC_ILLEGAL_MESSAGE; | |||
goto error; | |||
} | |||
// partner IDs are UUIDs bound to session lifespan | |||
// and therefore partner identities are not supposed | |||
// to mutate over time, but just not be used anymore. | |||
// It should then be safe to accept given identity if not | |||
// already pre-existing | |||
pEp_identity *stored_identity = NULL; | |||
status = get_identity(session, | |||
partner->address, | |||
partner->user_id, | |||
&stored_identity); | |||
if (!stored_identity) { | |||
// make a safe copy of partner, with no flags or comm_type | |||
pEp_identity *tmpident = new_identity(partner->address, | |||
partner->fpr, | |||
partner->user_id, | |||
partner->username); | |||
if (tmpident == NULL){ | |||
status = PEP_OUT_OF_MEMORY; | |||
goto error; | |||
} | |||
// finaly add partner to DB | |||
status = set_identity(session, tmpident); | |||
assert(status == PEP_STATUS_OK); | |||
if(status == PEP_STATUS_OK && msgIsFromGroup) | |||
status = set_identity_flags(session, tmpident, PEP_idf_devicegroup); | |||
free_identity(tmpident); | |||
assert(status == PEP_STATUS_OK); | |||
if (status != PEP_STATUS_OK) { | |||
goto error; | |||
} | |||
} | |||
else if (status == PEP_STATUS_OK) { | |||
free_identity(stored_identity); | |||
} | |||
else | |||
goto error; | |||
} | |||
status = fsm_DeviceState_inject(session, event, partner, extra, timeout); | |||
error: | |||
free_identity(partner); | |||
switch(event){ | |||
case GroupKeys: | |||
{ | |||
free_group_keys_extra((group_keys_extra_t*)extra); | |||
break; | |||
} | |||
case GroupUpdate: | |||
{ | |||
identity_list *group_keys = (identity_list*) extra; | |||
free_identity_list(group_keys); | |||
break; | |||
} | |||
default: | |||
assert(extra==NULL); | |||
break; | |||
} | |||
free(sync_msg); | |||
return status; | |||
} | |||
// TODO: DYNAMIC_API was here, but broke the windows build. | |||
// We need to check whether it belongs here or it's a bug. | |||
/* DYNAMIC_API */ void free_sync_msg(sync_msg_t *sync_msg) | |||
{ | |||
if (!sync_msg) | |||
return; | |||
if(sync_msg->is_a_message){ | |||
DeviceGroup_Protocol_t *msg = sync_msg->u.message; | |||
assert(msg); | |||
if (!(msg)) | |||
return; | |||
ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg); | |||
} | |||
else{ | |||
Identity partner = NULL; | |||
partner = sync_msg->u.event.partner; | |||
if(partner != NULL) | |||
free_identity(partner); | |||
} | |||
free(sync_msg); | |||
return; | |||
} | |||
// from sync.c | |||
int call_inject_sync_msg(PEP_SESSION session, void *msg); | |||
PEP_STATUS inject_DeviceState_event( | |||
PEP_SESSION session, | |||
DeviceState_event event, | |||
Identity partner, | |||
void *extra) | |||
{ | |||
PEP_STATUS status; | |||
assert(session); | |||
if (!(session)) | |||
return PEP_ILLEGAL_VALUE; | |||
sync_msg_t *sync_msg = malloc(sizeof(sync_msg_t)); | |||
if(sync_msg == NULL) | |||