src/sync_actions.c
author Volker Birk <vb@pep.foundation>
Wed, 10 Aug 2016 14:12:19 +0200
branchkeysync
changeset 991 b230b6418b52
parent 985 087d5d60c082
child 1004 9828752c0751
permissions -rw-r--r--
changing ownership
     1 // Actions for DeviceState state machine
     2 
     3 #include <assert.h>
     4 #include "pEp_internal.h"
     5 #include "message.h"
     6 #include "sync_fsm.h"
     7 #include "map_asn1.h"
     8 #include "../asn.1/DeviceGroup-Protocol.h"
     9 
    10 // conditions
    11 
    12 static const char *sql_stored_group_keys =
    13         "select count(device_group) from person where id = "PEP_OWN_USERID";"; 
    14 
    15 static int _stored_group_keys(void *_gc, int count, char **text, char **name)
    16 {
    17     assert(_gc);
    18     assert(count == 1);
    19     assert(text && text[0]);
    20     if (!(_gc && count == 1 && text && text[0]))
    21         return -1;
    22 
    23     bool *gc = (bool *) _gc;
    24     *gc = atoi(text[0]) != 0;
    25     return 0;
    26 }
    27 
    28 int storedGroupKeys(PEP_SESSION session)
    29 {
    30     assert(session);
    31     if (!session)
    32         return invalid_condition; // error
    33 
    34     bool gc = false;
    35     int int_result = sqlite3_exec(
    36         session->db,
    37         sql_stored_group_keys,
    38         _stored_group_keys,
    39         &gc,
    40         NULL
    41     );
    42     assert(int_result == SQLITE_OK);
    43     if (int_result != SQLITE_OK)
    44         return invalid_condition; // error
    45 
    46     if (gc)
    47         return 1;
    48     else
    49         return 0;
    50 }
    51 
    52 int keyElectionWon(PEP_SESSION session, Identity partner)
    53 {
    54     assert(session);
    55     assert(partner);
    56     if (!(session && partner))
    57         return invalid_condition; // error
    58 
    59     // an already existing group always wins
    60 
    61     if (storedGroupKeys(session)) {
    62         assert(!(partner->flags & PEP_idf_devicegroup));
    63         return 1;
    64     }
    65 
    66     if (partner->flags & PEP_idf_devicegroup)
    67         return 0;
    68 
    69     Identity me = NULL;
    70     PEP_STATUS status = get_identity(session, partner->address, PEP_OWN_USERID,
    71             &me);
    72     if (status == PEP_OUT_OF_MEMORY)
    73         return invalid_out_of_memory;
    74     if (status != PEP_STATUS_OK)
    75         return invalid_condition; // error
    76 
    77     int result = invalid_condition; // error state has to be overwritten
    78 
    79     time_t own_created;
    80     time_t partners_created;
    81 
    82     status = key_created(session, me->fpr, &own_created);
    83     if (status != PEP_STATUS_OK)
    84         goto the_end;
    85 
    86     status = key_created(session, partner->fpr, &partners_created);
    87     if (status != PEP_STATUS_OK)
    88         goto the_end;
    89 
    90     if (own_created > partners_created)
    91         result = 0;
    92     else
    93         result = 1;
    94 
    95 the_end:
    96     free_identity(me);
    97     return result;
    98 }
    99 
   100 // showHandshake() - trigger the handshake dialog of the application
   101 //
   102 //  params:
   103 //      session (in)        session handle
   104 //      state (in)          state the state machine is in
   105 //      partner (in)        partner to communicate with
   106 //
   107 //  returns:
   108 //      PEP_STATUS_OK or any other value on error
   109 
   110 PEP_STATUS showHandshake(
   111         PEP_SESSION session,
   112         DeviceState_state state,
   113         Identity partner,
   114         void *extra
   115     )
   116 {
   117     PEP_STATUS status = PEP_STATUS_OK;
   118 
   119     assert(session);
   120     assert(partner);
   121     assert(extra == NULL);
   122 
   123     if (!(session && partner))
   124         return PEP_ILLEGAL_VALUE;
   125 
   126     assert(session->showHandshake);
   127     if (!session->showHandshake)
   128         return PEP_SYNC_NO_TRUSTWORDS_CALLBACK;
   129 
   130     pEp_identity *me = NULL;
   131     status = get_identity(session, partner->address, PEP_OWN_USERID, &me);
   132     if (status != PEP_STATUS_OK)
   133         goto error;
   134     
   135     status = session->showHandshake(session, me, partner);
   136     if (status != PEP_STATUS_OK)
   137         goto error;
   138 
   139     return status;
   140 
   141 error:
   142     free_identity(me);
   143     free_identity(partner);
   144     return status;
   145 }
   146 
   147 
   148 // reject() - stores rejection of partner
   149 //
   150 //  params:
   151 //      session (in)        session handle
   152 //      state (in)          state the state machine is in
   153 //      partner (in)        partner to communicate with
   154 //
   155 //  returns:
   156 //      PEP_STATUS_OK or any other value on error
   157 
   158 PEP_STATUS reject(
   159         PEP_SESSION session,
   160         DeviceState_state state,
   161         Identity partner,
   162         void *extra
   163     )
   164 {
   165     PEP_STATUS status = PEP_STATUS_OK;
   166 
   167     assert(session);
   168     assert(partner);
   169     assert(extra == NULL);
   170     if (!(session && partner))
   171         return PEP_ILLEGAL_VALUE;
   172 
   173     status = set_identity_flags(session, partner,
   174             partner->flags | PEP_idf_not_for_sync);
   175 
   176     free_identity(partner);
   177     return status;
   178 }
   179 
   180 
   181 // storeGroupKeys() - 
   182 //
   183 //  params:
   184 //      session (in)        session handle
   185 //      state (in)          state the state machine is in
   186 //      partner (in)        partner to communicate with
   187 //      _group_keys (in)    group keys received from partner
   188 //
   189 //  returns:
   190 //      PEP_STATUS_OK or any other value on error
   191 
   192 PEP_STATUS storeGroupKeys(
   193         PEP_SESSION session,
   194         DeviceState_state state,
   195         Identity partner,
   196         void *_group_keys
   197     )
   198 {
   199     PEP_STATUS status = PEP_STATUS_OK;
   200 
   201     assert(session);
   202     assert(partner);
   203     assert(_group_keys);
   204     if (!(session && partner && _group_keys))
   205         return PEP_ILLEGAL_VALUE;
   206 
   207     identity_list *group_keys = (identity_list *) _group_keys;
   208 
   209     for (identity_list *il = group_keys; il && il->ident; il = il->next) {
   210         free(il->ident->user_id);
   211         il->ident->user_id = strdup(PEP_OWN_USERID);
   212         assert(il->ident->user_id);
   213         if (!il->ident->user_id)
   214             goto enomem;
   215         status = set_identity(session, il->ident);
   216         if (status != PEP_STATUS_OK)
   217             break;
   218     }
   219 
   220     free_identity(partner);
   221     free_identity_list(group_keys);
   222     return status;
   223 
   224 enomem:
   225     status = PEP_OUT_OF_MEMORY;
   226     free_identity(partner);
   227     free_identity_list(group_keys);
   228     return status;
   229 }
   230 
   231 static PEP_STATUS receive_sync_msg(
   232         PEP_SESSION session,
   233         DeviceGroup_Protocol_t *msg
   234     )
   235 {
   236     assert(session && msg && msg->present != DeviceGroup_Protocol_PR_NOTHING);
   237     if (!(session && msg && msg->present != DeviceGroup_Protocol_PR_NOTHING))
   238         return PEP_ILLEGAL_VALUE;
   239 
   240     void *extra = NULL;
   241     Identity partner = NULL;
   242     DeviceState_event event = DeviceState_event_NONE;
   243 
   244     switch (msg->present) {
   245         case DeviceGroup_Protocol_PR_beacon:
   246             partner = Identity_to_Struct(&msg->choice.beacon.header.me, NULL);
   247             if (!partner)
   248                 return PEP_OUT_OF_MEMORY;
   249             event = Beacon;
   250             break;
   251 
   252         case DeviceGroup_Protocol_PR_handshakeRequest:
   253             partner = Identity_to_Struct(
   254                     &msg->choice.handshakeRequest.header.me, NULL);
   255             if (!partner)
   256                 return PEP_OUT_OF_MEMORY;
   257             event = HandshakeRequest;
   258             break;
   259 
   260         case DeviceGroup_Protocol_PR_groupKeys:
   261             partner = Identity_to_Struct(&msg->choice.groupKeys.header.me,
   262                     NULL);
   263             if (!partner)
   264                 return PEP_OUT_OF_MEMORY;
   265             identity_list *group_keys = IdentityList_to_identity_list(
   266                     &msg->choice.groupKeys.ownIdentities, NULL);
   267             if (!group_keys) {
   268                 free_identity(partner);
   269                 return PEP_OUT_OF_MEMORY;
   270             }
   271             extra = (void *) group_keys;
   272             event = GroupKeys;
   273             break;
   274 
   275         default:
   276             return PEP_SYNC_ILLEGAL_MESSAGE;
   277     }
   278 
   279     return fsm_DeviceState_inject(session, event, partner, extra);
   280 }
   281 
   282 PEP_STATUS receive_DeviceState_msg(PEP_SESSION session, message *src)
   283 {
   284     assert(session && src);
   285     if (!(session && src))
   286         return PEP_ILLEGAL_VALUE;
   287 
   288     bool found = false;
   289 
   290     for (bloblist_t *bl = src->attachments; bl && bl->value; bl = bl->next) {
   291         if (bl->mime_type && strcasecmp(bl->mime_type, "application/pEp") == 0
   292                 && bl->size) {
   293             DeviceGroup_Protocol_t *msg;
   294             uper_decode_complete(NULL, &asn_DEF_DeviceGroup_Protocol,
   295                     (void **) &msg, bl->value, bl->size);
   296             if (msg) {
   297                 found = true;
   298                 PEP_STATUS status = receive_sync_msg(session, msg);
   299                 ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   300                 if (status != PEP_STATUS_OK)
   301                     return status;
   302             }
   303         }
   304     }
   305 
   306     if (found) {
   307         for (stringpair_list_t *spl = src->opt_fields ; spl && spl->value ;
   308                 spl = spl->next) {
   309             if (spl->value->key &&
   310                     strcasecmp(spl->value->key, "pEp-auto-consume") == 0) {
   311                 if (spl->value->value &&
   312                         strcasecmp(spl->value->value, "yes") == 0)
   313                     return PEP_MESSAGE_CONSUMED;
   314             }
   315         }
   316     }
   317 
   318     return PEP_STATUS_OK;
   319 }
   320