ENGINE-289: Intermittent commit - need to refactor some logic big-time. ENGINE-289
authorKrista Bennett <krista@pep-project.org>
Mon, 18 Dec 2017 13:27:42 +0100
branchENGINE-289
changeset 2324de5b5578fc16
parent 2323 b0dcaf9cf1e6
child 2325 781d887c83f4
ENGINE-289: Intermittent commit - need to refactor some logic big-time.
src/keymanagement.c
src/pEpEngine.c
src/pEpEngine.h
src/pEp_internal.h
     1.1 --- a/src/keymanagement.c	Sun Dec 17 18:21:08 2017 +0100
     1.2 +++ b/src/keymanagement.c	Mon Dec 18 13:27:42 2017 +0100
     1.3 @@ -22,6 +22,29 @@
     1.4  #define KEY_EXPIRE_DELTA (60 * 60 * 24 * 365)
     1.5  
     1.6  
     1.7 +static bool key_matches_address(PEP_SESSION session, const char* address,
     1.8 +                                const char* fpr) {
     1.9 +    if (!session || !address || !fpr)
    1.10 +        return false;
    1.11 +    
    1.12 +    bool retval = false;
    1.13 +    stringlist_t *keylist = NULL;
    1.14 +    PEP_STATUS status = find_keys(session, address, &keylist);
    1.15 +    if (status == PEP_STATUS_OK && keylist) {
    1.16 +        stringlist_t* curr = keylist;
    1.17 +        if (curr->value) {
    1.18 +            if (strcasecmp(curr->value, fpr)) {
    1.19 +                retval = true;
    1.20 +                break;
    1.21 +            }
    1.22 +        }
    1.23 +        curr = curr->next;
    1.24 +    }
    1.25 +    
    1.26 +    free_stringlist(keylist);
    1.27 +    return retval;                             
    1.28 +}
    1.29 +
    1.30  PEP_STATUS elect_pubkey(
    1.31          PEP_SESSION session, pEp_identity * identity
    1.32      )
    1.33 @@ -78,8 +101,15 @@
    1.34  
    1.35  static PEP_STATUS validate_fpr(PEP_SESSION session, pEp_identity* ident) {
    1.36      
    1.37 +    if (!session || !ident || !ident->fpr)
    1.38 +        return PEP_ILLEGAL_VALUE;    
    1.39 +        
    1.40      char* fpr = ident->fpr;
    1.41 -    PEP_comm_type ct = ident->comm_type;
    1.42 +    
    1.43 +    PEP_STATUS status = get_trust(session, ident);
    1.44 +    if (status != PEP_STATUS_OK)
    1.45 +        return ADD_TO_LOG(status);
    1.46 +    
    1.47      bool done = false;
    1.48      
    1.49      bool revoked, expired;
    1.50 @@ -156,49 +186,60 @@
    1.51  // without an fpr, there wasn't one in the trust DB for this
    1.52  // identity.
    1.53  PEP_STATUS get_valid_pubkey(PEP_STATUS session,
    1.54 -                            PEP_STATUS stored_identity) {
    1.55 +                            PEP_STATUS stored_identity,
    1.56 +                            bool* is_identity_default,
    1.57 +                            bool* is_user_default,
    1.58 +                            bool* is_address_default) {
    1.59      
    1.60      PEP_STATUS status = PEP_STATUS_OK;
    1.61  
    1.62 -    if (!stored_identity || !stored_identity->user_id)
    1.63 +    if (!stored_identity || !stored_identity->user_id
    1.64 +        || !is_identity_default || !is_user_default || !is_address_default)
    1.65          return PEP_ILLEGAL_VALUE;
    1.66          
    1.67 +    *is_identity_default = *is_user_default = *is_address_default = false;
    1.68 +    
    1.69      char* stored_fpr = stored_identity->fpr;
    1.70      // Input: stored identity retrieved from database
    1.71      // if stored identity contains a default key
    1.72      if (stored_fpr) {
    1.73          status = validate_fpr(session, stored_identity);    
    1.74 -        if (status == PEP_STATUS_OK && stored_identity->fpr)
    1.75 +        if (status == PEP_STATUS_OK && stored_identity->fpr) {
    1.76 +            *is_identity_default = *is_address_default = true;
    1.77              return status;
    1.78 +        }
    1.79      }
    1.80      // if no valid default stored identity key found
    1.81 +    free(stored_identity->fpr);
    1.82 +    stored_identity->fpr = NULL;
    1.83 +    
    1.84      // try to get default key for user_data
    1.85      sqlite3_reset(session->get_user_default_key);
    1.86      sqlite3_bind_text(session->get_user_default_key, 1, stored_identity->user_id, 
    1.87                        -1, SQLITE_STATIC);
    1.88      
    1.89      const int result = sqlite3_step(session->get_user_default_key);
    1.90 -    const char* user_fpr;
    1.91 -    bool found = false;
    1.92 +    const char* user_fpr = NULL;
    1.93      if (result == SQLITE_ROW) {
    1.94          user_fpr = 
    1.95              (const char *) sqlite3_column_text(session->get_user_default_key, 0);
    1.96 -        if (user_fpr)
    1.97 -            found = true;
    1.98      }
    1.99 -    if (!found)
   1.100 -        return NULL;
   1.101 -         
   1.102 -    // There exists a default key for user, so validate
   1.103 -    // FIXME: we have to be able to validate comm_type too.
   1.104 -    retval = validate_fpr(session, user_fpr, WTF,
   1.105 -                          stored_identity->me);
   1.106 +    sqlite3_reset(session->get_user_default_key);
   1.107      
   1.108 -    if (!retval) {
   1.109 -        
   1.110 +    if (user_fpr) {             
   1.111 +        // There exists a default key for user, so validate
   1.112 +        stored_identity->fpr = user_fpr;
   1.113 +        status = validate_fpr(session, stored_identity);
   1.114 +        if (status == PEP_STATUS_OK && stored_identity->fpr) {
   1.115 +            *is_user_default = true;
   1.116 +            *is_address_default = key_matches_address(session, 
   1.117 +                                                      stored_identity->address,
   1.118 +                                                      stored_identity->fpr);
   1.119 +            return status;
   1.120 +        }        
   1.121      }
   1.122 -                          
   1.123 -    return retval;
   1.124 +    
   1.125 +    return elect_pubkey(session, stored_identity);
   1.126  }
   1.127  
   1.128  PEP_STATUS _myself(PEP_SESSION session, pEp_identity * identity, bool do_keygen, bool ignore_flags);
   1.129 @@ -233,10 +274,14 @@
   1.130      // We have, at least, an address.
   1.131      // Retrieve stored identity information!    
   1.132      pEp_identity* stored_ident = NULL;
   1.133 +    char* identity_default_fpr = NULL;
   1.134 +    char* user_default_fpr = NULL;
   1.135 +    char* passed_in_fpr = identity->fpr;
   1.136 +
   1.137      if (identity->user_id) {            
   1.138 -        // (we're gonna update the trust/fpr anyway, so we user the no-fpr variant)
   1.139 +        // (we're gonna update the trust/fpr anyway, so we user the no-fpr-from-trust-db variant)
   1.140          //      * do get_identity() to retrieve stored identity information
   1.141 -        status = get_identity_without_fpr(session, identity->address, identity->user_id, &stored_ident);
   1.142 +        status = get_identity_without_trust_check(session, identity->address, identity->user_id, &stored_ident);
   1.143  
   1.144          // Before we start - if there was no stored identity, we should check to make sure we don't
   1.145          // have a stored identity with a temporary user_id that differs from the input user_id. This
   1.146 @@ -255,21 +300,30 @@
   1.147                              // FIXME: should we also be fixing pEp_own_userId in this
   1.148                              // function here?
   1.149                              
   1.150 -                            // Ok, we have a temp ID. We have to replace this
   1.151 -                            // with the real ID.
   1.152 -                            status = replace_userid(this_uid, identity->user_id);
   1.153 -                            if (status != PEP_STATUS_OK) {
   1.154 -                                free_identity_list(id_list);
   1.155 -                                return status;
   1.156 -                            }
   1.157 +                            // if usernames match, we replace the userid. Or if the temp username
   1.158 +                            // is anonymous.
   1.159 +                            if (!this_id->username ||
   1.160 +                                strcasecmp(this_id->username, "anonymous") == 0 ||
   1.161 +                                (identity->username && 
   1.162 +                                 strcasecmp(identity->username, 
   1.163 +                                            this_id->username) == 0)) {
   1.164                                  
   1.165 -                            free(this_uid);
   1.166 -                            
   1.167 -                            // Reflect the change we just made to the DB
   1.168 -                            this_id->user_id = strdup(identity->user_id);
   1.169 -                            stored_ident = this_id;
   1.170 -                            // FIXME: free list.
   1.171 -                            break;
   1.172 +                                // Ok, we have a temp ID. We have to replace this
   1.173 +                                // with the real ID.
   1.174 +                                status = replace_userid(this_uid, identity->user_id);
   1.175 +                                if (status != PEP_STATUS_OK) {
   1.176 +                                    free_identity_list(id_list);
   1.177 +                                    return status;
   1.178 +                                }
   1.179 +                                    
   1.180 +                                free(this_uid);
   1.181 +                                
   1.182 +                                // Reflect the change we just made to the DB
   1.183 +                                this_id->user_id = strdup(identity->user_id);
   1.184 +                                stored_ident = this_id;
   1.185 +                                // FIXME: free list.
   1.186 +                                break;                                
   1.187 +                            }                            
   1.188                          } 
   1.189                      }
   1.190                      id_curr = id_curr->next;
   1.191 @@ -277,88 +331,148 @@
   1.192              }
   1.193          } 
   1.194          
   1.195 +        if (stored_ident && stored_ident->fpr)
   1.196 +            identity_default_fpr = strdup(stored_ident->fpr);
   1.197 +        
   1.198          // Ok, now we start the real algorithm:
   1.199 -        if (identity->username) {
   1.200 -            /*
   1.201 -             * Retrieving information of an identity with username supplied
   1.202 -             *      Input: user_id, address, username
   1.203 -             */
   1.204 -            if (status == PEP_STATUS_OK && stored_ident) { 
   1.205 -                //  * if identity available
   1.206 -                //      * patch it with username
   1.207 -                //          (note: this will happen when 
   1.208 -                //           setting automatically below...)
   1.209 -                //      * elect valid key for identity
   1.210 -                //    * if valid key existS
   1.211 -                //        * set return value's fpr
   1.212 -                status = get_valid_pubkey(session, stored_ident);
   1.213 -                if (status == PEP_STATUS_OK && stored_ident->fpr) {
   1.214 -                //        * set identity comm_type from trust db (user_id, FPR)
   1.215 +        if (status == PEP_STATUS_OK && stored_ident) { 
   1.216 +            //  * if identity available
   1.217 +            //      * patch it with username
   1.218 +            //          (note: this will happen when 
   1.219 +            //           setting automatically below...)
   1.220 +            //      * elect valid key for identity
   1.221 +            //    * if valid key exists
   1.222 +            //        * set return value's fpr
   1.223 +            bool fpr_changed = false;
   1.224 +            bool is_identity_default, is_user_default, is_address_default;
   1.225 +            status = get_valid_pubkey(session, stored_ident,
   1.226 +                                        &is_identity_default,
   1.227 +                                        &is_user_default,
   1.228 +                                        &is_address_default);
   1.229 +                                        
   1.230 +            if (status == PEP_STATUS_OK && stored_ident->fpr) {
   1.231 +            //        * set identity comm_type from trust db (user_id, FPR)
   1.232 +                status = get_trust(session, stored_ident);
   1.233 +                if (status != PEP_STATUS_OK)
   1.234 +                    return status; // FIXME - free mem
   1.235 +                if (identity->fpr &&
   1.236 +                         strcasecmp(stored_ident->fpr, identity->fpr) != 0) {
   1.237 +                    free(identity->fpr);
   1.238 +                    strdup(identity->fpr, stored_ident->fpr);
   1.239 +                    
   1.240 +                    // We have to call this because we didn't get it during
   1.241 +                    // get identity above
   1.242                      status = get_trust(session, stored_ident);
   1.243 -                    if (status != PEP_STATUS_OK)
   1.244 -                        return status; // FIXME - free mem
   1.245 -                    if (identity->fpr && 
   1.246 -                             strcasecmp(stored_ident->fpr, identity->fpr) != 0) {
   1.247 -                        free(identity->fpr);
   1.248 -                        strdup(identity->fpr, stored_ident->fpr);
   1.249 -                        identity->comm_type = stored_ident->comm_type;
   1.250 -                    }
   1.251 +                    identity->comm_type = stored_ident->comm_type;
   1.252                  }
   1.253 -                else {
   1.254 -                    return status; // Couldn't find a key.
   1.255 +            }
   1.256 +            else {
   1.257 +                return status; // Couldn't find a key.
   1.258 +            }
   1.259 +                        
   1.260 +            // We patch the DB with the input username, but if we didn't have
   1.261 +            // one, we pull it out of storage if available.
   1.262 +            // (also, if the input username is "anonymous" and there exists
   1.263 +            //  a DB username, we replace)
   1.264 +            if (stored_ident->username) {
   1.265 +                if (identity->username && 
   1.266 +                    (strcasecmp(identity->username, "anonymous") == 0)) {
   1.267 +                    free(identity->username);
   1.268 +                    identity->username = NULL;
   1.269                  }
   1.270 -                //    * call set_identity() to store
   1.271 +                if (!identity->username)
   1.272 +                    identity->username = strdup(stored_ident->username);
   1.273 +            }
   1.274 +                
   1.275 +            // Call set_identity() to store
   1.276 +            if ((is_identity_default || is_user_default) &&
   1.277 +                 is_address_default) {                 
   1.278 +                 // if we got an fpr which is default for either user
   1.279 +                 // or identity AND is valid for this address, set in DB
   1.280 +                 // as default
   1.281 +                 status = set_identity(identity);
   1.282 +            }
   1.283 +            else {
   1.284 +                // Store without default fpr/ct, but return the fpr and ct 
   1.285 +                // for current use
   1.286 +                char* save_fpr = identity->fpr;
   1.287 +                PEP_comm_type save_ct = identity->comm_type;
   1.288 +                identity->fpr = NULL;
   1.289 +                identity->comm_type = PEP_ct_unknown;
   1.290                  status = set_identity(identity);
   1.291 -            }
   1.292 -            //  * else (identity unavailable)
   1.293 -            else {
   1.294 -            //      * create identity with user_id, address, username
   1.295 -            //    * search for a temporary identity for address and username
   1.296 -            //    * if temporary identity available
   1.297 -            //      * modify identity with username
   1.298 -            //    * else
   1.299 -            //    * call set_identity() to store
   1.300 -            //  * Return: modified or created identity
   1.301 -             // 
   1.302 +                identity->fpr = save_fpr;
   1.303 +                identity->comm_type = save_ct;
   1.304              }
   1.305          }
   1.306 +        //  * else (identity unavailable)
   1.307          else {
   1.308 -            /*
   1.309 -             * Retrieving information of an identity without username supplied
   1.310 -             *      Input: user_id, address
   1.311 -             */
   1.312 -            //    * doing get_identity() to retrieve stored identity information
   1.313 -            //    * if identity not available
   1.314 +            //  if we only have user_id and address and identity not available
   1.315              //      * return error status (identity not found)
   1.316 -            //    * else
   1.317 -            //      * elect valid key for identity (see below)
   1.318 -            //      * if valid key exists
   1.319 -            //        * set identity comm_type from trust db (user_id, FPR)
   1.320 -            //        * set return value's fpr
   1.321 -            //        * ...? (do we also set the stored fpr?)
   1.322 -            //      * Return: identity if available
   1.323 -
   1.324 +            if (!identity->username)
   1.325 +                status PEP_CANNOT_FIND_IDENTITY;
   1.326              
   1.327 -        }
   1.328 +            // Otherwise, if we had user_id, address, and username:
   1.329 +            //    * create identity with user_id, address, username
   1.330 +            //      (this is the input id without the fpr + comm type!)
   1.331 +            free(identity->fpr);
   1.332 +            identity->fpr = NULL;
   1.333 +            identity->comm_type = PEP_ct_unknown;
   1.334 +            
   1.335 +            //    * We've already checked and retrieved
   1.336 +            //      any applicable temporary identities above. If we're 
   1.337 +            //      here, none of them fit.
   1.338 +            //    * call set_identity() to store
   1.339 +            if (status == PEP_STATUS_OK) {
   1.340 +                status = set_identity(session, identity);
   1.341 +            }
   1.342 +            //  * Return: created identity
   1.343 +        }        
   1.344      }
   1.345      else if (identity->username) {
   1.346          /*
   1.347           * Temporary identity information with username supplied
   1.348              * Input: address, username (no others)
   1.349           */
   1.350 -         
   1.351 +        identity_list* id_list = NULL;
   1.352 +        status = get_identities_by_address(session, identity->address, &id_list);
   1.353 +
   1.354          //  * Search for an identity with non-temporary user_id with that mapping
   1.355 -        //  * if one found
   1.356 -        //    * find valid key for identity (see below)
   1.357 -        //    * if valid key exists
   1.358 -        //      * set identity comm_type from trust db (user_id, FPR)
   1.359 -        //      * set return value's fpr
   1.360 -        //      * ...? (do we also set the stored fpr?)
   1.361 -        //    * Return this identity
   1.362 -        //  * if many found
   1.363 -        //    * Return the one with newest modification date (yes, this is a heuristics)
   1.364 -        //  * else
   1.365 -        //    * create temporary identity, store it, and Return this
   1.366 +        if (id_list) {
   1.367 +            identity_list* id_curr = id_list;
   1.368 +            while (id_curr) {
   1.369 +                pEp_identity* this_id = id_curr->ident;
   1.370 +                if (this_id) {
   1.371 +                    char* this_uid = this_id->user_id;
   1.372 +                    if (this_uid && (strstr(this_uid, "TOFU_") == NULL)) {
   1.373 +                        // FIXME: should we also be fixing pEp_own_userId in this
   1.374 +                        // function here?
   1.375 +                        
   1.376 +                        // if usernames match, we replace the userid.
   1.377 +                        if (identity->username && 
   1.378 +                            strcasecmp(identity->username, 
   1.379 +                                       this_id->username) == 0) {
   1.380 +                            
   1.381 +                            // Ok, we have a real ID. Copy it!
   1.382 +                            identity->user_id = strdup(this_uid);
   1.383 +                            
   1.384 +                            if (!identity->user_id)
   1.385 +                                status = PEP_OUT_OF_MEMORY;
   1.386 +                            stored_ident = this_id;
   1.387 +                            
   1.388 +                            break;                                
   1.389 +                        }                            
   1.390 +                    } 
   1.391 +                }
   1.392 +                id_curr = id_curr->next;
   1.393 +            }
   1.394 +        }
   1.395 +
   1.396 +        if (stored_ident) {
   1.397 +            
   1.398 +        }
   1.399 +        else {
   1.400 +            //    * create temporary identity, store it, and Return this            
   1.401 +        }
   1.402      }
   1.403      else {
   1.404          /*
     2.1 --- a/src/pEpEngine.c	Sun Dec 17 18:21:08 2017 +0100
     2.2 +++ b/src/pEpEngine.c	Mon Dec 18 13:27:42 2017 +0100
     2.3 @@ -63,7 +63,7 @@
     2.4      "          end) = 1"
     2.5      "   and identity.user_id = ?2;";
     2.6  
     2.7 -static const char *sql_get_identity_without_fpr =  
     2.8 +static const char *sql_get_identity_without_trust_check =  
     2.9      "select main_key_id, username, comm_type, lang,"
    2.10      "   identity.flags, is_own"
    2.11      "   from identity"
    2.12 @@ -768,9 +768,9 @@
    2.13              (int)strlen(sql_get_identity), &_session->get_identity, NULL);
    2.14      assert(int_result == SQLITE_OK);
    2.15  
    2.16 -    int_result = sqlite3_prepare_v2(_session->db, sql_get_identity_without_fpr,
    2.17 -            (int)strlen(sql_get_identity_without_fpr), 
    2.18 -            &_session->get_identity_without_fpr, NULL);
    2.19 +    int_result = sqlite3_prepare_v2(_session->db, sql_get_identity_without_trust_check,
    2.20 +            (int)strlen(sql_get_identity_without_trust_check), 
    2.21 +            &_session->get_identity_without_trust_check, NULL);
    2.22      assert(int_result == SQLITE_OK);
    2.23  
    2.24      int_result = sqlite3_prepare_v2(_session->db, sql_get_identities_by_address,
    2.25 @@ -1031,8 +1031,8 @@
    2.26                  sqlite3_finalize(session->trustword);
    2.27              if (session->get_identity)
    2.28                  sqlite3_finalize(session->get_identity);
    2.29 -            if (session->get_identity_without_fpr)
    2.30 -                sqlite3_finalize(session->get_identity_without_fpr);
    2.31 +            if (session->get_identity_without_trust_check)
    2.32 +                sqlite3_finalize(session->get_identity_without_trust_check);
    2.33              if (session->get_identities_by_address)
    2.34                  sqlite3_finalize(session->get_identities_by_address);            
    2.35              if (session->get_user_default_key)
    2.36 @@ -1529,7 +1529,7 @@
    2.37                                    session->get_identity);
    2.38  }
    2.39  
    2.40 -PEP_STATUS get_identity_without_fpr(
    2.41 +PEP_STATUS get_identity_without_trust_check(
    2.42          PEP_SESSION session,
    2.43          const char *address,
    2.44          const char *user_id,
    2.45 @@ -1537,7 +1537,7 @@
    2.46      )
    2.47  {
    2.48      return _get_identity_internal(session, address, user_id, identity,
    2.49 -                                  session->get_identity_without_fpr);
    2.50 +                                  session->get_identity_without_trust_check);
    2.51  }
    2.52  
    2.53  PEP_STATUS get_identities_by_address(
     3.1 --- a/src/pEpEngine.h	Sun Dec 17 18:21:08 2017 +0100
     3.2 +++ b/src/pEpEngine.h	Mon Dec 18 13:27:42 2017 +0100
     3.3 @@ -875,7 +875,7 @@
     3.4  //  parameters:
     3.5  //      session (in)            session handle
     3.6  //      identity (inout)        user_id and fpr to check as UTF-8 strings (in)
     3.7 -//                              user_id and comm_type as result (out)
     3.8 +//                              comm_type as result (out)
     3.9  //
    3.10  //  this function modifies the given identity struct; the struct remains in
    3.11  //  the ownership of the caller
     4.1 --- a/src/pEp_internal.h	Sun Dec 17 18:21:08 2017 +0100
     4.2 +++ b/src/pEp_internal.h	Mon Dec 18 13:27:42 2017 +0100
     4.3 @@ -124,7 +124,7 @@
     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_identity_without_trust_check;
     4.9      sqlite3_stmt *get_identities_by_address;
    4.10      sqlite3_stmt *replace_identities_fpr;
    4.11      sqlite3_stmt *set_person;