src/sync_actions.c
author Volker Birk <vb@pep.foundation>
Mon, 08 Aug 2016 17:32:51 +0200
branchkeysync
changeset 985 087d5d60c082
parent 965 2c833e0a883b
child 991 b230b6418b52
permissions -rw-r--r--
moving #include and installing headers
     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     free_identity(me);
   140     free_identity(partner);
   141     return status;
   142 
   143 error:
   144     free_identity(me);
   145     free_identity(partner);
   146     return status;
   147 }
   148 
   149 
   150 // reject() - stores rejection of partner
   151 //
   152 //  params:
   153 //      session (in)        session handle
   154 //      state (in)          state the state machine is in
   155 //      partner (in)        partner to communicate with
   156 //
   157 //  returns:
   158 //      PEP_STATUS_OK or any other value on error
   159 
   160 PEP_STATUS reject(
   161         PEP_SESSION session,
   162         DeviceState_state state,
   163         Identity partner,
   164         void *extra
   165     )
   166 {
   167     PEP_STATUS status = PEP_STATUS_OK;
   168 
   169     assert(session);
   170     assert(partner);
   171     assert(extra == NULL);
   172     if (!(session && partner))
   173         return PEP_ILLEGAL_VALUE;
   174 
   175     status = set_identity_flags(session, partner,
   176             partner->flags | PEP_idf_not_for_sync);
   177 
   178     free_identity(partner);
   179     return status;
   180 }
   181 
   182 
   183 // storeGroupKeys() - 
   184 //
   185 //  params:
   186 //      session (in)        session handle
   187 //      state (in)          state the state machine is in
   188 //      partner (in)        partner to communicate with
   189 //      _group_keys (in)    group keys received from partner
   190 //
   191 //  returns:
   192 //      PEP_STATUS_OK or any other value on error
   193 
   194 PEP_STATUS storeGroupKeys(
   195         PEP_SESSION session,
   196         DeviceState_state state,
   197         Identity partner,
   198         void *_group_keys
   199     )
   200 {
   201     PEP_STATUS status = PEP_STATUS_OK;
   202 
   203     assert(session);
   204     assert(partner);
   205     assert(_group_keys);
   206     if (!(session && partner && _group_keys))
   207         return PEP_ILLEGAL_VALUE;
   208 
   209     identity_list *group_keys = (identity_list *) _group_keys;
   210 
   211     for (identity_list *il = group_keys; il && il->ident; il = il->next) {
   212         free(il->ident->user_id);
   213         il->ident->user_id = strdup(PEP_OWN_USERID);
   214         assert(il->ident->user_id);
   215         if (!il->ident->user_id)
   216             goto enomem;
   217         status = set_identity(session, il->ident);
   218         if (status != PEP_STATUS_OK)
   219             break;
   220     }
   221 
   222     free_identity(partner);
   223     free_identity_list(group_keys);
   224     return status;
   225 
   226 enomem:
   227     status = PEP_OUT_OF_MEMORY;
   228     free_identity(partner);
   229     free_identity_list(group_keys);
   230     return status;
   231 }
   232 
   233 static PEP_STATUS receive_sync_msg(
   234         PEP_SESSION session,
   235         DeviceGroup_Protocol_t *msg
   236     )
   237 {
   238     assert(session && msg && msg->present != DeviceGroup_Protocol_PR_NOTHING);
   239     if (!(session && msg && msg->present != DeviceGroup_Protocol_PR_NOTHING))
   240         return PEP_ILLEGAL_VALUE;
   241 
   242     void *extra = NULL;
   243     Identity partner = NULL;
   244     DeviceState_event event = DeviceState_event_NONE;
   245 
   246     switch (msg->present) {
   247         case DeviceGroup_Protocol_PR_beacon:
   248             partner = Identity_to_Struct(&msg->choice.beacon.header.me, NULL);
   249             if (!partner)
   250                 return PEP_OUT_OF_MEMORY;
   251             event = Beacon;
   252             break;
   253 
   254         case DeviceGroup_Protocol_PR_handshakeRequest:
   255             partner = Identity_to_Struct(
   256                     &msg->choice.handshakeRequest.header.me, NULL);
   257             if (!partner)
   258                 return PEP_OUT_OF_MEMORY;
   259             event = HandshakeRequest;
   260             break;
   261 
   262         case DeviceGroup_Protocol_PR_groupKeys:
   263             partner = Identity_to_Struct(&msg->choice.groupKeys.header.me,
   264                     NULL);
   265             if (!partner)
   266                 return PEP_OUT_OF_MEMORY;
   267             identity_list *group_keys = IdentityList_to_identity_list(
   268                     &msg->choice.groupKeys.ownIdentities, NULL);
   269             if (!group_keys) {
   270                 free_identity(partner);
   271                 return PEP_OUT_OF_MEMORY;
   272             }
   273             extra = (void *) group_keys;
   274             event = GroupKeys;
   275             break;
   276 
   277         default:
   278             return PEP_SYNC_ILLEGAL_MESSAGE;
   279     }
   280 
   281     return fsm_DeviceState_inject(session, event, partner, extra);
   282 }
   283 
   284 PEP_STATUS receive_DeviceState_msg(PEP_SESSION session, message *src)
   285 {
   286     assert(session && src);
   287     if (!(session && src))
   288         return PEP_ILLEGAL_VALUE;
   289 
   290     bool found = false;
   291 
   292     for (bloblist_t *bl = src->attachments; bl && bl->value; bl = bl->next) {
   293         if (bl->mime_type && strcasecmp(bl->mime_type, "application/pEp") == 0
   294                 && bl->size) {
   295             DeviceGroup_Protocol_t *msg;
   296             uper_decode_complete(NULL, &asn_DEF_DeviceGroup_Protocol,
   297                     (void **) &msg, bl->value, bl->size);
   298             if (msg) {
   299                 found = true;
   300                 PEP_STATUS status = receive_sync_msg(session, msg);
   301                 ASN_STRUCT_FREE(asn_DEF_DeviceGroup_Protocol, msg);
   302                 if (status != PEP_STATUS_OK)
   303                     return status;
   304             }
   305         }
   306     }
   307 
   308     if (found) {
   309         for (stringpair_list_t *spl = src->opt_fields ; spl && spl->value ;
   310                 spl = spl->next) {
   311             if (spl->value->key &&
   312                     strcasecmp(spl->value->key, "pEp-auto-consume") == 0) {
   313                 if (spl->value->value &&
   314                         strcasecmp(spl->value->value, "yes") == 0)
   315                     return PEP_MESSAGE_CONSUMED;
   316             }
   317         }
   318     }
   319 
   320     return PEP_STATUS_OK;
   321 }
   322