ENGINE-320: intermittent commit ENGINE-289
authorKrista Bennett <krista@pep-project.org>
Fri, 15 Dec 2017 12:49:03 +0100
branchENGINE-289
changeset 2317b80dd91c8869
parent 2311 688b925c3e73
child 2319 93c84d8281d2
ENGINE-320: intermittent commit
src/keymanagement.c
src/pEpEngine.c
src/pEpEngine.h
src/pEp_internal.h
     1.1 --- a/src/keymanagement.c	Wed Dec 13 11:42:23 2017 +0100
     1.2 +++ b/src/keymanagement.c	Fri Dec 15 12:49:03 2017 +0100
     1.3 @@ -224,8 +224,48 @@
     1.4      if (identity->user_id) {            
     1.5          // (we're gonna update the trust/fpr anyway, so we user the no-fpr variant)
     1.6          //      * do get_identity() to retrieve stored identity information
     1.7 -        status = get_identity_without_fpr(session, &stored_ident);
     1.8 +        status = get_identity_without_fpr(session, identity->address, identity->user_id, &stored_ident);
     1.9 +
    1.10 +        // Before we start - if there was no stored identity, we should check to make sure we don't
    1.11 +        // have a stored identity with a temporary user_id that differs from the input user_id. This
    1.12 +        // happens in multithreaded environments sometimes.
    1.13 +        if (!stored_ident) {
    1.14 +            identity_list* id_list = NULL;
    1.15 +            status = get_identities_by_address(session, identity->address, &id_list);
    1.16 +
    1.17 +            if (id_list) {
    1.18 +                identity_list* id_curr = id_list;
    1.19 +                while (id_curr) {
    1.20 +                    pEp_identity* this_id = id_curr->ident;
    1.21 +                    if (this_id) {
    1.22 +                        char* this_uid = this_id->user_id;
    1.23 +                        if (this_uid && (strstr(this_uid, "TOFU_") == this_uid)) {
    1.24 +                            // FIXME: should we also be fixing pEp_own_userId in this
    1.25 +                            // function here?
    1.26 +                            
    1.27 +                            // Ok, we have a temp ID. We have to replace this
    1.28 +                            // with the real ID.
    1.29 +                            status = replace_userid(this_uid, identity->user_id);
    1.30 +                            if (status != PEP_STATUS_OK) {
    1.31 +                                free_identity_list(id_list);
    1.32 +                                return status;
    1.33 +                            }
    1.34 +                                
    1.35 +                            free(this_uid);
    1.36 +                            
    1.37 +                            // Reflect the change we just made to the DB
    1.38 +                            this_id->user_id = strdup(identity->user_id);
    1.39 +                            stored_ident = this_id;
    1.40 +                            // FIXME: free list.
    1.41 +                            break;
    1.42 +                        } 
    1.43 +                    }
    1.44 +                    id_curr = id_curr->next;
    1.45 +                }
    1.46 +            }
    1.47 +        } 
    1.48          
    1.49 +        // Ok, now we start the real algorithm:
    1.50          if (identity->username) {
    1.51              /*
    1.52               * Retrieving information of an identity with username supplied
    1.53 @@ -236,13 +276,30 @@
    1.54                  //      * patch it with username
    1.55                  //          (note: this will happen when 
    1.56                  //           setting automatically below...)
    1.57 -                //      * elect valid key for identity (see below)
    1.58 -                //    * if valid key exists
    1.59 +                //      * elect valid key for identity
    1.60 +                //    * if valid key existS
    1.61 +                //        * set return value's fpr
    1.62 +                status = get_valid_pubkey(session, stored_ident);
    1.63 +                if (status == PEP_STATUS_OK && stored_ident->fpr) {
    1.64                  //        * set identity comm_type from trust db (user_id, FPR)
    1.65 -                //        * set return value's fpr
    1.66 +                    status = get_trust(session, stored_ident);
    1.67 +                    if (status != PEP_STATUS_OK)
    1.68 +                        return status; // FIXME - free mem
    1.69 +                    if (identity->fpr && 
    1.70 +                             strcasecmp(stored_ident->fpr, identity->fpr) != 0) {
    1.71 +                        free(identity->fpr);
    1.72 +                        strdup(identity->fpr, stored_ident->fpr);
    1.73 +                        identity->comm_type = stored_ident->comm_type;
    1.74 +                    }
    1.75 +                }
    1.76 +                else {
    1.77 +                    return status; // Couldn't find a key.
    1.78 +                }
    1.79                  //    * call set_identity() to store
    1.80                  status = set_identity(identity);
    1.81 +            }
    1.82              //  * else (identity unavailable)
    1.83 +            else {
    1.84              //      * create identity with user_id, address, username
    1.85              //    * search for a temporary identity for address and username
    1.86              //    * if temporary identity available
    1.87 @@ -251,6 +308,7 @@
    1.88              //    * call set_identity() to store
    1.89              //  * Return: modified or created identity
    1.90               // 
    1.91 +            }
    1.92          }
    1.93          else {
    1.94              /*
     2.1 --- a/src/pEpEngine.c	Wed Dec 13 11:42:23 2017 +0100
     2.2 +++ b/src/pEpEngine.c	Fri Dec 15 12:49:03 2017 +0100
     2.3 @@ -75,6 +75,16 @@
     2.4      "          end) = 1"
     2.5      "   and identity.user_id = ?2;";
     2.6  
     2.7 +static const char *sql_get_identities_by_address =  
     2.8 +    "select main_key_id, username, comm_type, lang,"
     2.9 +    "   identity.flags, is_own"
    2.10 +    "   from identity"
    2.11 +    "   where (case when (address = ?1) then (1)"
    2.12 +    "               when (lower(address) = lower(?1)) then (1)"
    2.13 +    "               when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)"
    2.14 +    "               else 0"
    2.15 +    "          end) = 1;";
    2.16 +
    2.17  static const char *sql_replace_identities_fpr =  
    2.18      "update identity"
    2.19      "   set main_key_id = ?1 "
    2.20 @@ -167,6 +177,11 @@
    2.21  static const char *sql_i18n_token = 
    2.22      "select phrase from i18n_token where lang = lower(?1) and id = ?2 ;";
    2.23  
    2.24 +// This will cascade to identity and trust
    2.25 +static const char* sql_replace_userid =
    2.26 +    "update id from person"
    2.27 +    "   set id = ?1"
    2.28 +    "   where id = ?2;";
    2.29  
    2.30  // blacklist
    2.31  static const char *sql_blacklist_add = 
    2.32 @@ -473,7 +488,7 @@
    2.33                  "   address text,\n"
    2.34                  "   user_id text\n"
    2.35                  "       references person (id)\n"
    2.36 -                "       on delete cascade,\n"
    2.37 +                "       on delete cascade on update cascade,\n"
    2.38                  "   main_key_id text\n"
    2.39                  "       references pgp_keypair (fpr)\n"
    2.40                  "       on delete set null,\n"
    2.41 @@ -485,7 +500,7 @@
    2.42                  "create table if not exists trust (\n"
    2.43                  "   user_id text not null\n"
    2.44                  "       references person (id)\n"
    2.45 -                "       on delete cascade,\n"
    2.46 +                "       on delete cascade on update cascade,\n"
    2.47                  "   pgp_keypair_fpr text not null\n"
    2.48                  "       references pgp_keypair (fpr)\n"
    2.49                  "       on delete cascade,\n"
    2.50 @@ -668,7 +683,53 @@
    2.51                      NULL,
    2.52                      NULL
    2.53                  );
    2.54 -                assert(int_result == SQLITE_OK);                
    2.55 +                assert(int_result == SQLITE_OK);    
    2.56 +
    2.57 +                // Turns out that just adding "on update cascade" in
    2.58 +                // sqlite is a PITA. We need to be able to cascade
    2.59 +                // person->id replacements (for temp ids like "TOFU_")
    2.60 +                // so here we go...
    2.61 +                int_result = sqlite3_exec(
    2.62 +                    "PRAGMA foreign_keys=off;\n"
    2.63 +                    "BEGIN TRANSACTION;\n"
    2.64 +                    "ALTER TABLE identity RENAME TO _identity_old;\n"
    2.65 +                    "create table identity (\n"
    2.66 +                    "   address text,\n"
    2.67 +                    "   user_id text\n"
    2.68 +                    "       references person (id)\n"
    2.69 +                    "       on delete cascade on update cascade,\n"
    2.70 +                    "   main_key_id text\n"
    2.71 +                    "       references pgp_keypair (fpr)\n"
    2.72 +                    "       on delete set null,\n"
    2.73 +                    "   comment text,\n"
    2.74 +                    "   flags integer default 0,\n"
    2.75 +                    "   is_own integer default 0,\n"
    2.76 +                    "   primary key (address, user_id)\n"
    2.77 +                    ");\n"
    2.78 +                    "INSERT INTO identity SELECT * FROM _identity_old;\n"
    2.79 +                    "DROP TABLE _identity_old;\n"
    2.80 +                    "ALTER TABLE trust RENAME TO _trust_old;\n"
    2.81 +                    "create table trust (\n"
    2.82 +                    "   user_id text not null\n"
    2.83 +                    "       references person (id)\n"
    2.84 +                    "       on delete cascade on update cascade,\n"
    2.85 +                    "   pgp_keypair_fpr text not null\n"
    2.86 +                    "       references pgp_keypair (fpr)\n"
    2.87 +                    "       on delete cascade,\n"
    2.88 +                    "   comm_type integer not null,\n"
    2.89 +                    "   comment text,\n"
    2.90 +                    "   primary key (user_id, pgp_keypair_fpr)\n"
    2.91 +                    ");\n"
    2.92 +                    "INSERT INTO trust SELECT * FROM _trust_old;\n"
    2.93 +                    "DROP TABLE _trust_old;\n"
    2.94 +                    "COMMIT;\n"
    2.95 +                    "\n"
    2.96 +                    "PRAGMA foreign_keys=on;\n",
    2.97 +                    NULL,
    2.98 +                    NULL,
    2.99 +                    NULL
   2.100 +                );
   2.101 +                assert(int_result == SQLITE_OK);    
   2.102              }
   2.103          }
   2.104          else { 
   2.105 @@ -712,6 +773,11 @@
   2.106              &_session->get_identity_without_fpr, NULL);
   2.107      assert(int_result == SQLITE_OK);
   2.108  
   2.109 +    int_result = sqlite3_prepare_v2(_session->db, sql_get_identities_by_address,
   2.110 +            (int)strlen(sql_get_identities_by_address), 
   2.111 +            &_session->get_identities_by_address, NULL);
   2.112 +    assert(int_result == SQLITE_OK);
   2.113 +
   2.114      int_result = sqlite3_prepare_v2(_session->db, sql_get_user_default_key,
   2.115              (int)strlen(sql_get_user_default_key), &_session->get_user_default_key, NULL);
   2.116      assert(int_result == SQLITE_OK);
   2.117 @@ -788,6 +854,10 @@
   2.118      int_result = sqlite3_prepare_v2(_session->system_db, sql_i18n_token,
   2.119              (int)strlen(sql_i18n_token), &_session->i18n_token, NULL);
   2.120      assert(int_result == SQLITE_OK);
   2.121 +    
   2.122 +    int_result = sqlite3_prepare_v2(_session->system_db, sql_replace_userid,
   2.123 +            (int)strlen(sql_replace_userid), &_session->replace_userid, NULL);
   2.124 +    assert(int_result == SQLITE_OK);
   2.125  
   2.126      // blacklist
   2.127  
   2.128 @@ -962,7 +1032,9 @@
   2.129              if (session->get_identity)
   2.130                  sqlite3_finalize(session->get_identity);
   2.131              if (session->get_identity_without_fpr)
   2.132 -                sqlite3_finalize(session->get_identity_without_fpr);    
   2.133 +                sqlite3_finalize(session->get_identity_without_fpr);
   2.134 +            if (session->get_identities_by_address)
   2.135 +                sqlite3_finalize(session->get_identities_by_address);            
   2.136              if (session->get_user_default_key)
   2.137                  sqlite3_finalize(session->get_user_default_key);    
   2.138              if (session->get_own_userid)
   2.139 @@ -999,6 +1071,8 @@
   2.140                  sqlite3_finalize(session->languagelist);
   2.141              if (session->i18n_token)
   2.142                  sqlite3_finalize(session->i18n_token);
   2.143 +            if (session->replace_userid)
   2.144 +                sqlite3_finalize(session->replace_userid);
   2.145              if (session->blacklist_add)
   2.146                  sqlite3_finalize(session->blacklist_add);
   2.147              if (session->blacklist_delete)
   2.148 @@ -1378,7 +1452,6 @@
   2.149      return status;
   2.150  }
   2.151  
   2.152 -
   2.153  static PEP_STATUS _get_identity_internal(
   2.154          PEP_SESSION session,
   2.155          const char *address,
   2.156 @@ -1467,6 +1540,74 @@
   2.157                                    session->get_identity_without_fpr);
   2.158  }
   2.159  
   2.160 +PEP_STATUS get_identities_by_address(
   2.161 +        PEP_SESSION session,
   2.162 +        const char *address,
   2.163 +        identity_list** id_list
   2.164 +    )
   2.165 +{
   2.166 +    pEp_identity* ident;
   2.167 +
   2.168 +    assert(session);
   2.169 +    assert(address);
   2.170 +    assert(address[0]);
   2.171 +    assert(id_list);
   2.172 +
   2.173 +    if (!(session && address && address[0] && id_list))
   2.174 +        return PEP_ILLEGAL_VALUE;
   2.175 +
   2.176 +    *id_list = NULL;
   2.177 +    identity_list* ident_list = NULL;
   2.178 +
   2.179 +    sqlite3_reset(sql->get_identities_by_address);
   2.180 +    sqlite3_bind_text(sql->get_identities_by_address, 1, address, -1, SQLITE_STATIC);
   2.181 +    int result;
   2.182 +
   2.183 +    while ((result = sqlite3_step(sql->get_identities_by_address)) == SQLITE_ROW) {
   2.184 +        
   2.185 +        ident = new_identity(
   2.186 +                address,
   2.187 +                (const char *) sqlite3_column_text(sql->get_identities_by_address, 0),
   2.188 +                user_id,
   2.189 +                (const char *) sqlite3_column_text(sql->get_identities_by_address, 1)
   2.190 +                );
   2.191 +        assert(_identity);
   2.192 +        if (ident == NULL)
   2.193 +            return PEP_OUT_OF_MEMORY;
   2.194 +
   2.195 +        ident->comm_type = (PEP_comm_type)
   2.196 +            sqlite3_column_int(sql->get_identities_by_address, 2);
   2.197 +        const char* const _lang = (const char *)
   2.198 +            sqlite3_column_text(sql->get_identities_by_address, 3);
   2.199 +        if (_lang && _lang[0]) {
   2.200 +            assert(_lang[0] >= 'a' && _lang[0] <= 'z');
   2.201 +            assert(_lang[1] >= 'a' && _lang[1] <= 'z');
   2.202 +            assert(_lang[2] == 0);
   2.203 +            _identity->lang[0] = _lang[0];
   2.204 +            _identity->lang[1] = _lang[1];
   2.205 +            _identity->lang[2] = 0;
   2.206 +        }
   2.207 +        ident->flags = (unsigned int)
   2.208 +            sqlite3_column_int(sql->get_identities_by_address, 4);
   2.209 +        ident->me = (unsigned int)
   2.210 +            sqlite3_column_int(sql->get_identities_by_address, 5);
   2.211 +    
   2.212 +        if (ident_list)
   2.213 +            identity_list_add(ident_list, ident);
   2.214 +        else
   2.215 +            ident_list = new_identity_list(ident);
   2.216 +    }
   2.217 +
   2.218 +    sqlite3_reset(sql->get_identities_by_address);
   2.219 +    
   2.220 +    *id_list = ident_list;
   2.221 +    
   2.222 +    if (!ident_list)
   2.223 +        return PEP_CANNOT_FIND_IDENTITY;
   2.224 +    
   2.225 +    return PEP_STATUS_OK;
   2.226 +}
   2.227 +
   2.228  
   2.229  DYNAMIC_API PEP_STATUS set_identity(
   2.230          PEP_SESSION session, const pEp_identity *identity
   2.231 @@ -1733,8 +1874,8 @@
   2.232      sqlite3_bind_text(session->set_identity_flags, 2, identity->address, -1,
   2.233              SQLITE_STATIC);
   2.234      sqlite3_bind_text(session->set_identity_flags, 3, identity->user_id, -1,
   2.235 +        result = sqlite3_step(session->set_identity_flags);
   2.236              SQLITE_STATIC);
   2.237 -    result = sqlite3_step(session->set_identity_flags);
   2.238      sqlite3_reset(session->set_identity_flags);
   2.239      if (result != SQLITE_DONE)
   2.240          return PEP_CANNOT_SET_IDENTITY;
   2.241 @@ -1774,6 +1915,33 @@
   2.242      return PEP_STATUS_OK;
   2.243  }
   2.244  
   2.245 +
   2.246 +PEP_STATUS replace_userid(PEP_SESSION session, const char* old_uid,
   2.247 +                              const char* new_uid) {
   2.248 +    assert(session);
   2.249 +    assert(old_uid);
   2.250 +    assert(new_uid);
   2.251 +    
   2.252 +    if (!session || !old_uid || !new_uid)
   2.253 +        return PEP_ILLEGAL_VALUE;
   2.254 +
   2.255 +
   2.256 +    int result;
   2.257 +
   2.258 +    sqlite3_reset(session->replace_userid);
   2.259 +    sqlite3_bind_text(session->replace_userid, 1, new_id, -1,
   2.260 +            SQLITE_STATIC);
   2.261 +    sqlite3_bind_text(session->replace_userid, 2, old_id, -1,
   2.262 +            SQLITE_STATIC);
   2.263 +    result = sqlite3_step(session->replace);
   2.264 +    sqlite3_reset(session->replace);
   2.265 +    if (result != SQLITE_DONE)
   2.266 +        return PEP_CANNOT_SET_PERSON; // May need clearer retval
   2.267 +
   2.268 +    return PEP_STATUS_OK;
   2.269 +}
   2.270 +
   2.271 +
   2.272  DYNAMIC_API PEP_STATUS mark_as_compromized(
   2.273          PEP_SESSION session,
   2.274          const char *fpr
     3.1 --- a/src/pEpEngine.h	Wed Dec 13 11:42:23 2017 +0100
     3.2 +++ b/src/pEpEngine.h	Fri Dec 15 12:49:03 2017 +0100
     3.3 @@ -1158,6 +1158,9 @@
     3.4          const char *user_id,
     3.5          pEp_identity **identity
     3.6      );
     3.7 +
     3.8 +PEP_STATUS replace_userid(PEP_SESSION session, const char* old_uid,
     3.9 +                              const char* new_uid);
    3.10      
    3.11  #ifdef __cplusplus
    3.12  }
     4.1 --- a/src/pEp_internal.h	Wed Dec 13 11:42:23 2017 +0100
     4.2 +++ b/src/pEp_internal.h	Fri Dec 15 12:49:03 2017 +0100
     4.3 @@ -124,6 +124,8 @@
     4.4      sqlite3_stmt *log;
     4.5      sqlite3_stmt *trustword;
     4.6      sqlite3_stmt *get_identity;
     4.7 +    sqlite3_stmt *get_identity_without_fpr;
     4.8 +    sqlite3_stmt *get_identities_by_address;
     4.9      sqlite3_stmt *replace_identities_fpr;
    4.10      sqlite3_stmt *set_person;
    4.11      sqlite3_stmt *set_device_group;
    4.12 @@ -141,6 +143,7 @@
    4.13      sqlite3_stmt *crashdump;
    4.14      sqlite3_stmt *languagelist;
    4.15      sqlite3_stmt *i18n_token;
    4.16 +    sqlite3_stmt *replace_userid;
    4.17  
    4.18      // blacklist
    4.19      sqlite3_stmt *blacklist_add;