src/keymanagement.c
author Krista Bennett <krista@pep-project.org>
Fri, 04 May 2018 16:30:21 +0200
branchlocal_cpptest
changeset 2652 43b913f99a27
parent 2612 2c6bad8b4a69
child 2805 65829c954ea7
child 2830 d6f044e43e1a
permissions -rw-r--r--
Shelving broken things to break other things
     1 // This file is under GNU General Public License 3.0
     2 // see LICENSE.txt
     3 
     4 #include "platform.h"
     5 
     6 #include <string.h>
     7 #include <stdio.h>
     8 #include <stdlib.h>
     9 #include <assert.h>
    10 #include <ctype.h>
    11 
    12 #include "pEp_internal.h"
    13 #include "keymanagement.h"
    14 
    15 #include "sync_fsm.h"
    16 #include "blacklist.h"
    17 
    18 static bool key_matches_address(PEP_SESSION session, const char* address,
    19                                 const char* fpr) {
    20     if (!session || !address || !fpr)
    21         return false;
    22     
    23     bool retval = false;
    24     stringlist_t *keylist = NULL;
    25     PEP_STATUS status = find_keys(session, address, &keylist);
    26     if (status == PEP_STATUS_OK && keylist) {
    27         stringlist_t* curr = keylist;
    28         while (curr) {
    29             if (curr->value) {
    30                 if (strcasecmp(curr->value, fpr)) {
    31                     retval = true;
    32                     break;
    33                 }
    34             }
    35             curr = curr->next;
    36         }
    37     }
    38     
    39     free_stringlist(keylist);
    40     return retval;                             
    41 }
    42 
    43 PEP_STATUS elect_pubkey(
    44         PEP_SESSION session, pEp_identity * identity, bool check_blacklist
    45     )
    46 {
    47     PEP_STATUS status;
    48     stringlist_t *keylist = NULL;
    49     char *_fpr = "";
    50     identity->comm_type = PEP_ct_unknown;
    51 
    52     status = find_keys(session, identity->address, &keylist);
    53     assert(status != PEP_OUT_OF_MEMORY);
    54     if (status == PEP_OUT_OF_MEMORY)
    55         return PEP_OUT_OF_MEMORY;
    56     
    57     if (!keylist || !keylist->value)
    58         identity->comm_type = PEP_ct_key_not_found;    
    59     else {
    60         stringlist_t *_keylist;
    61         for (_keylist = keylist; _keylist && _keylist->value; _keylist = _keylist->next) {
    62             PEP_comm_type _comm_type_key;
    63 
    64             status = get_key_rating(session, _keylist->value, &_comm_type_key);
    65             assert(status != PEP_OUT_OF_MEMORY);
    66             if (status == PEP_OUT_OF_MEMORY) {
    67                 free_stringlist(keylist);
    68                 return PEP_OUT_OF_MEMORY;
    69             }
    70 
    71             if (_comm_type_key != PEP_ct_compromised &&
    72                 _comm_type_key != PEP_ct_unknown)
    73             {
    74                 if (identity->comm_type == PEP_ct_unknown ||
    75                     _comm_type_key > identity->comm_type)
    76                 {
    77                     bool blacklisted = false;
    78                     bool mistrusted = false;
    79                     status = is_mistrusted_key(session, _keylist->value, &mistrusted);
    80                     if (status == PEP_STATUS_OK && check_blacklist)
    81                         status = blacklist_is_listed(session, _keylist->value, &blacklisted);
    82                     if (status == PEP_STATUS_OK && !mistrusted && !blacklisted) {
    83                         identity->comm_type = _comm_type_key;
    84                         _fpr = _keylist->value;
    85                     }
    86                 }
    87             }
    88         }
    89     }
    90     free(identity->fpr);
    91 
    92     if (!_fpr || _fpr[0] == '\0')
    93         identity->fpr = NULL;
    94     else {    
    95         identity->fpr = strdup(_fpr);
    96         if (identity->fpr == NULL) {
    97             free_stringlist(keylist);
    98             return PEP_OUT_OF_MEMORY;
    99         }
   100     }
   101     
   102     free_stringlist(keylist);
   103     return PEP_STATUS_OK;
   104 }
   105 
   106 static PEP_STATUS validate_fpr(PEP_SESSION session, 
   107                                pEp_identity* ident,
   108                                bool check_blacklist) {
   109     
   110     PEP_STATUS status = PEP_STATUS_OK;
   111     
   112     if (!session || !ident || !ident->fpr || !ident->fpr[0])
   113         return PEP_ILLEGAL_VALUE;    
   114         
   115     char* fpr = ident->fpr;
   116     
   117     bool has_private = false;
   118     
   119     if (ident->me) {
   120         status = contains_priv_key(session, fpr, &has_private);
   121         if (status != PEP_STATUS_OK || !has_private)
   122             return PEP_KEY_UNSUITABLE;
   123     }
   124     
   125     status = get_trust(session, ident);
   126     if (status != PEP_STATUS_OK)
   127         ident->comm_type = PEP_ct_unknown;
   128             
   129     PEP_comm_type ct = ident->comm_type;
   130 
   131     if (ct == PEP_ct_unknown) {
   132         // If status is bad, it's ok, we get the rating
   133         // we should use then (PEP_ct_unknown)
   134         get_key_rating(session, fpr, &ct);
   135         ident->comm_type = ct;
   136     }
   137     
   138     bool pep_user = false;
   139     
   140     is_pep_user(session, ident, &pep_user);
   141 
   142     if (pep_user) {
   143         switch (ct) {
   144             case PEP_ct_OpenPGP:
   145             case PEP_ct_OpenPGP_unconfirmed:
   146                 ct += 0x47; // difference between PEP and OpenPGP values;
   147                 ident->comm_type = ct;
   148                 break;
   149             default:
   150                 break;
   151         }
   152     }
   153     
   154     bool revoked, expired;
   155     bool blacklisted = false;
   156     
   157     status = key_revoked(session, fpr, &revoked);    
   158         
   159     if (status != PEP_STATUS_OK) {
   160         return status;
   161     }
   162     
   163     if (!revoked) {
   164         time_t exp_time = (ident->me ? 
   165                            time(NULL) + (7*24*3600) : time(NULL));
   166                            
   167         status = key_expired(session, fpr, 
   168                              exp_time,
   169                              &expired);
   170                              
   171         assert(status == PEP_STATUS_OK);
   172         if (status != PEP_STATUS_OK)
   173             return status;
   174 
   175         if (check_blacklist && IS_PGP_CT(ct) &&
   176             !ident->me) {
   177             status = blacklist_is_listed(session, 
   178                                          fpr, 
   179                                          &blacklisted);
   180                                          
   181             if (status != PEP_STATUS_OK)
   182                 return status;
   183         }
   184     }
   185             
   186     if (ident->me && (ct >= PEP_ct_strong_but_unconfirmed) && !revoked && expired) {
   187         // extend key
   188         timestamp *ts = new_timestamp(time(NULL) + KEY_EXPIRE_DELTA);
   189         status = renew_key(session, fpr, ts);
   190         free_timestamp(ts);
   191 
   192         if (status == PEP_STATUS_OK) {
   193             // if key is valid (second check because pEp key might be extended above)
   194             //      Return fpr        
   195             status = key_expired(session, fpr, time(NULL), &expired);            
   196             if (status != PEP_STATUS_OK) {
   197                  ident->comm_type = PEP_ct_key_expired;
   198                  return status;
   199              }
   200             // communicate key(?)
   201         }        
   202     }
   203      
   204     if (revoked) 
   205         ct = PEP_ct_key_revoked;
   206     else if (expired)
   207         ct = PEP_ct_key_expired;        
   208     else if (blacklisted) { // never true for .me
   209         ident->comm_type = ct = PEP_ct_key_not_found;
   210         free(ident->fpr);
   211             ident->fpr = strdup("");
   212         status = PEP_KEY_BLACKLISTED;
   213     }
   214     
   215     switch (ct) {
   216         case PEP_ct_key_expired:
   217         case PEP_ct_key_revoked:
   218         case PEP_ct_key_b0rken:
   219             // delete key from being default key for all users/identities
   220             status = remove_fpr_as_default(session, fpr);
   221             status = update_trust_for_fpr(session, 
   222                                           fpr, 
   223                                           ct);
   224         case PEP_ct_mistrusted:                                  
   225             free(ident->fpr);
   226             ident->fpr = NULL;
   227             ident->comm_type = ct;            
   228             status = PEP_KEY_UNSUITABLE;
   229         default:
   230             break;
   231     }            
   232 
   233     return status;
   234 }
   235 
   236 PEP_STATUS get_user_default_key(PEP_SESSION session, const char* user_id,
   237                                 char** default_key) {
   238     assert(session);
   239     assert(user_id);
   240     
   241     if (!session || !user_id)
   242         return PEP_ILLEGAL_VALUE;
   243 
   244     PEP_STATUS status = PEP_STATUS_OK;
   245             
   246     // try to get default key for user_data
   247     sqlite3_reset(session->get_user_default_key);
   248     sqlite3_bind_text(session->get_user_default_key, 1, user_id, 
   249                       -1, SQLITE_STATIC);
   250     
   251     const int result = sqlite3_step(session->get_user_default_key);
   252     char* user_fpr = NULL;
   253     if (result == SQLITE_ROW) {
   254         const char* u_fpr =
   255             (char *) sqlite3_column_text(session->get_user_default_key, 0);
   256         if (u_fpr)
   257             user_fpr = strdup(u_fpr);
   258     }
   259     else
   260         status = PEP_GET_KEY_FAILED;
   261         
   262     sqlite3_reset(session->get_user_default_key);
   263     
   264     *default_key = user_fpr;
   265     return status;     
   266 }
   267 
   268 // Only call on retrieval of previously stored identity!
   269 // Also, we presume that if the stored_identity was sent in
   270 // without an fpr, there wasn't one in the trust DB for this
   271 // identity.
   272 PEP_STATUS get_valid_pubkey(PEP_SESSION session,
   273                          pEp_identity* stored_identity,
   274                          bool* is_identity_default,
   275                          bool* is_user_default,
   276                          bool* is_address_default,
   277                          bool check_blacklist) {
   278     
   279     PEP_STATUS status = PEP_STATUS_OK;
   280 
   281     if (!stored_identity || EMPTYSTR(stored_identity->user_id)
   282         || !is_identity_default || !is_user_default || !is_address_default)
   283         return PEP_ILLEGAL_VALUE;
   284         
   285     *is_identity_default = *is_user_default = *is_address_default = false;
   286 
   287     PEP_comm_type first_reject_comm_type = PEP_ct_key_not_found;
   288     PEP_STATUS first_reject_status = PEP_KEY_NOT_FOUND;
   289     
   290     char* stored_fpr = stored_identity->fpr;
   291     // Input: stored identity retrieved from database
   292     // if stored identity contains a default key
   293     if (!EMPTYSTR(stored_fpr)) {
   294         status = validate_fpr(session, stored_identity, check_blacklist);    
   295         if (status == PEP_STATUS_OK && !EMPTYSTR(stored_identity->fpr)) {
   296             *is_identity_default = *is_address_default = true;
   297             return status;
   298         }
   299         else if (status != PEP_KEY_NOT_FOUND) {
   300             first_reject_status = status;
   301             first_reject_comm_type = stored_identity->comm_type;
   302         }
   303     }
   304     // if no valid default stored identity key found
   305     free(stored_identity->fpr);
   306     stored_identity->fpr = NULL;
   307     
   308     char* user_fpr = NULL;
   309     status = get_user_default_key(session, stored_identity->user_id, &user_fpr);
   310     
   311     if (!EMPTYSTR(user_fpr)) {             
   312         // There exists a default key for user, so validate
   313         stored_identity->fpr = user_fpr;
   314         status = validate_fpr(session, stored_identity, check_blacklist);
   315         if (status == PEP_STATUS_OK && stored_identity->fpr) {
   316             *is_user_default = true;
   317             *is_address_default = key_matches_address(session, 
   318                                                       stored_identity->address,
   319                                                       stored_identity->fpr);
   320             return status;
   321         }        
   322         else if (status != PEP_KEY_NOT_FOUND && first_reject_status != PEP_KEY_NOT_FOUND) {
   323             first_reject_status = status;
   324             first_reject_comm_type = stored_identity->comm_type;
   325         }
   326     }
   327     
   328     status = elect_pubkey(session, stored_identity, check_blacklist);
   329     if (status == PEP_STATUS_OK) {
   330         if (!EMPTYSTR(stored_identity->fpr))
   331             validate_fpr(session, stored_identity, false); // blacklist already filtered of needed
   332     }    
   333     else if (status != PEP_KEY_NOT_FOUND && first_reject_status != PEP_KEY_NOT_FOUND) {
   334         first_reject_status = status;
   335         first_reject_comm_type = stored_identity->comm_type;
   336     }
   337     
   338     switch (stored_identity->comm_type) {
   339         case PEP_ct_key_revoked:
   340         case PEP_ct_key_b0rken:
   341         case PEP_ct_key_expired:
   342         case PEP_ct_compromised:
   343         case PEP_ct_mistrusted:
   344             // this only happens when it's all there is
   345             status = first_reject_status;
   346             free(stored_identity->fpr);
   347             stored_identity->fpr = NULL;
   348             stored_identity->comm_type = first_reject_comm_type;
   349             break;    
   350         default:
   351             if (check_blacklist && status == PEP_KEY_BLACKLISTED) {
   352                 free(stored_identity->fpr);
   353                 stored_identity->fpr = NULL;
   354                 stored_identity->comm_type = PEP_ct_key_not_found;
   355             }
   356             break;
   357     }
   358     return status;
   359 }
   360 
   361 static void transfer_ident_lang_and_flags(pEp_identity* new_ident,
   362                                           pEp_identity* stored_ident) {
   363     if (new_ident->lang[0] == 0) {
   364       new_ident->lang[0] = stored_ident->lang[0];
   365       new_ident->lang[1] = stored_ident->lang[1];
   366       new_ident->lang[2] = 0;
   367     }
   368 
   369     new_ident->flags = stored_ident->flags;
   370     new_ident->me = new_ident->me || stored_ident->me;
   371 }
   372 
   373 static void adjust_pep_trust_status(PEP_SESSION session, pEp_identity* identity) {
   374     assert(session);
   375     assert(identity);
   376     
   377     if (identity->comm_type < PEP_ct_strong_but_unconfirmed ||
   378         (identity->comm_type | PEP_ct_confirmed) == PEP_ct_pEp)
   379         return;
   380     
   381     bool pep_user;
   382     
   383     is_pep_user(session, identity, &pep_user);
   384     
   385     if (pep_user) {
   386         PEP_comm_type confirmation_status = identity->comm_type & PEP_ct_confirmed;
   387         identity->comm_type = PEP_ct_pEp_unconfirmed | confirmation_status;    
   388     }
   389 }
   390 
   391 
   392 static PEP_STATUS prepare_updated_identity(PEP_SESSION session,
   393                                                  pEp_identity* return_id,
   394                                                  pEp_identity* stored_ident,
   395                                                  bool store) {
   396     
   397     if (!session || !return_id || !stored_ident)
   398         return PEP_ILLEGAL_VALUE;
   399     
   400     PEP_STATUS status;
   401     
   402     bool is_identity_default, is_user_default, is_address_default;
   403     status = get_valid_pubkey(session, stored_ident,
   404                                 &is_identity_default,
   405                                 &is_user_default,
   406                                 &is_address_default,
   407                               false);
   408                                 
   409     if (status == PEP_STATUS_OK && stored_ident->fpr && *(stored_ident->fpr) != '\0') {
   410     // set identity comm_type from trust db (user_id, FPR)
   411         status = get_trust(session, stored_ident);
   412         if (status == PEP_CANNOT_FIND_IDENTITY || stored_ident->comm_type == PEP_ct_unknown) {
   413             // This is OK - there is no trust DB entry, but we
   414             // found a key. We won't store this, but we'll
   415             // use it.
   416             PEP_comm_type ct = PEP_ct_unknown;
   417             status = get_key_rating(session, stored_ident->fpr, &ct);
   418             stored_ident->comm_type = ct;
   419         }
   420     }
   421     else {
   422         if (stored_ident->comm_type == PEP_ct_unknown)
   423             stored_ident->comm_type = PEP_ct_key_not_found;
   424     }
   425     free(return_id->fpr);
   426     return_id->fpr = NULL;
   427     if (status == PEP_STATUS_OK && !EMPTYSTR(stored_ident->fpr))
   428         return_id->fpr = strdup(stored_ident->fpr);
   429         
   430     return_id->comm_type = stored_ident->comm_type;
   431                     
   432     // We patch the DB with the input username, but if we didn't have
   433     // one, we pull it out of storage if available.
   434     // (also, if the input username is "anonymous" and there exists
   435     //  a DB username, we replace)
   436     if (!EMPTYSTR(stored_ident->username)) {
   437         if (!EMPTYSTR(return_id->username) && 
   438             (strcasecmp(return_id->username, return_id->address) == 0)) {
   439             free(return_id->username);
   440             return_id->username = NULL;
   441         }
   442         if (EMPTYSTR(return_id->username)) {
   443             free(return_id->username);
   444             return_id->username = strdup(stored_ident->username);
   445         }
   446     }
   447     else {
   448         if (EMPTYSTR(return_id->username))
   449             return_id->username = strdup(return_id->address);
   450     }
   451     
   452     return_id->me = stored_ident->me;
   453     
   454     // FIXME: Do we ALWAYS do this? We probably should...
   455     if (EMPTYSTR(return_id->user_id)) {
   456         free(return_id->user_id);
   457         return_id->user_id = strdup(stored_ident->user_id);
   458     } 
   459     
   460     adjust_pep_trust_status(session, return_id);
   461    
   462     // Call set_identity() to store
   463     if ((is_identity_default || is_user_default) &&
   464          is_address_default) {                 
   465          // if we got an fpr which is default for either user
   466          // or identity AND is valid for this address, set in DB
   467          // as default
   468          status = set_identity(session, return_id);
   469     }
   470     else {
   471         // Store without default fpr/ct, but return the fpr and ct 
   472         // for current use
   473         char* save_fpr = return_id->fpr;
   474         PEP_comm_type save_ct = return_id->comm_type;
   475         return_id->fpr = NULL;
   476         return_id->comm_type = PEP_ct_unknown;
   477         PEP_STATUS save_status = status;
   478         status = set_identity(session, return_id);
   479         if (save_status != PEP_STATUS_OK)
   480             status = save_status;
   481         return_id->fpr = save_fpr;
   482         return_id->comm_type = save_ct;
   483     }
   484     
   485     transfer_ident_lang_and_flags(return_id, stored_ident);
   486     
   487     if (return_id->comm_type == PEP_ct_unknown)
   488         return_id->comm_type = PEP_ct_key_not_found;
   489     
   490     return status;
   491 }
   492 
   493 DYNAMIC_API PEP_STATUS update_identity(
   494         PEP_SESSION session, pEp_identity * identity
   495     )
   496 {
   497     PEP_STATUS status;
   498 
   499     assert(session);
   500     assert(identity);
   501     assert(!EMPTYSTR(identity->address));
   502 
   503     if (!(session && identity && !EMPTYSTR(identity->address)))
   504         return PEP_ILLEGAL_VALUE;
   505 
   506     char* default_own_id = NULL;
   507     status = get_default_own_userid(session, &default_own_id);    
   508 
   509     // Is this me, temporary or not? If so, BAIL.
   510     if (identity->me || 
   511        (default_own_id && identity->user_id && (strcmp(default_own_id, identity->user_id) == 0))) 
   512     {
   513         free(default_own_id);
   514         return PEP_ILLEGAL_VALUE;
   515     }
   516 
   517     // We have, at least, an address.
   518     // Retrieve stored identity information!    
   519     pEp_identity* stored_ident = NULL;
   520 
   521     if (!EMPTYSTR(identity->user_id)) {            
   522         // (we're gonna update the trust/fpr anyway, so we use the no-fpr-from-trust-db variant)
   523         //      * do get_identity() to retrieve stored identity information
   524         status = get_identity_without_trust_check(session, identity->address, identity->user_id, &stored_ident);
   525 
   526         // Before we start - if there was no stored identity, we should check to make sure we don't
   527         // have a stored identity with a temporary user_id that differs from the input user_id. This
   528         // happens in multithreaded environments sometimes.
   529         if (!stored_ident) {
   530             identity_list* id_list = NULL;
   531             status = get_identities_by_address(session, identity->address, &id_list);
   532 
   533             if (id_list) {
   534                 identity_list* id_curr = id_list;
   535                 while (id_curr) {
   536                     pEp_identity* this_id = id_curr->ident;
   537                     if (this_id) {
   538                         char* this_uid = this_id->user_id;
   539                         if (this_uid && (strstr(this_uid, "TOFU_") == this_uid)) {
   540                             // FIXME: should we also be fixing pEp_own_userId in this
   541                             // function here?
   542                             
   543                             // if usernames match, we replace the userid. Or if the temp username
   544                             // is anonymous.
   545                             // FIXME: do we need to create an address match function which
   546                             // matches the whole dot-and-case rigamarole from 
   547                             if (EMPTYSTR(this_id->username) ||
   548                                 strcasecmp(this_id->username, this_id->address) == 0 ||
   549                                 (identity->username && 
   550                                  strcasecmp(identity->username, 
   551                                             this_id->username) == 0)) {
   552                                 
   553                                 // Ok, we have a temp ID. We have to replace this
   554                                 // with the real ID.
   555                                 status = replace_userid(session, 
   556                                                         this_uid, 
   557                                                         identity->user_id);
   558                                 if (status != PEP_STATUS_OK) {
   559                                     free_identity_list(id_list);
   560                                     free(default_own_id);
   561                                     return status;
   562                                 }
   563                                     
   564                                 free(this_uid);
   565                                 this_uid = NULL;
   566                                 
   567                                 // Reflect the change we just made to the DB
   568                                 this_id->user_id = strdup(identity->user_id);
   569                                 stored_ident = this_id;
   570                                 // FIXME: free list.
   571                                 break;                                
   572                             }                            
   573                         } 
   574                     }
   575                     id_curr = id_curr->next;
   576                 }
   577             }
   578         } 
   579                 
   580         if (status == PEP_STATUS_OK && stored_ident) { 
   581             //  * if identity available
   582             //      * patch it with username
   583             //          (note: this will happen when 
   584             //           setting automatically below...)
   585             //      * elect valid key for identity
   586             //    * if valid key exists
   587             //        * set return value's fpr
   588             status = prepare_updated_identity(session,
   589                                               identity,
   590                                               stored_ident, true);
   591         }
   592         //  * else (identity unavailable)
   593         else {
   594             status = PEP_STATUS_OK;
   595 
   596             // FIXME: We may need to roll this back.
   597             // FIXME: change docs if we don't
   598             //  if we only have user_id and address and identity not available
   599             //      * return error status (identity not found)
   600             if (EMPTYSTR(identity->username)) {
   601                 free(identity->username);
   602                 identity->username = strdup(identity->address);
   603             }
   604             
   605             // Otherwise, if we had user_id, address, and username:
   606             //    * create identity with user_id, address, username
   607             //      (this is the input id without the fpr + comm type!)
   608 
   609             if (status == PEP_STATUS_OK) {
   610                 elect_pubkey(session, identity, false);
   611             }
   612                         
   613             //    * We've already checked and retrieved
   614             //      any applicable temporary identities above. If we're 
   615             //      here, none of them fit.
   616             //    * call set_identity() to store
   617             if (status == PEP_STATUS_OK) {
   618                 // FIXME: Do we set if we had to copy in the address?
   619                 adjust_pep_trust_status(session, identity);
   620                 status = set_identity(session, identity);
   621             }
   622             //  * Return: created identity
   623         }        
   624     }
   625     else if (!EMPTYSTR(identity->username)) {
   626         /*
   627          * Temporary identity information with username supplied
   628             * Input: address, username (no others)
   629          */
   630          
   631         //  * See if there is an own identity that uses this address. If so, we'll
   632         //    prefer that
   633         stored_ident = NULL;
   634         
   635         if (default_own_id) {
   636             status = get_identity(session, 
   637                                   identity->address, 
   638                                   default_own_id, 
   639                                   &stored_ident);
   640         }
   641         // If there isn't an own identity, search for a non-temp stored ident
   642         // with this address.                      
   643         if (status == PEP_CANNOT_FIND_IDENTITY || !stored_ident) { 
   644  
   645             identity_list* id_list = NULL;
   646             status = get_identities_by_address(session, identity->address, &id_list);
   647 
   648             if (id_list) {
   649                 identity_list* id_curr = id_list;
   650                 while (id_curr) {
   651                     pEp_identity* this_id = id_curr->ident;
   652                     if (this_id) {
   653                         char* this_uid = this_id->user_id;
   654                         if (this_uid && (strstr(this_uid, "TOFU_") != this_uid)) {
   655                             // if usernames match, we replace the userid.
   656                             if (identity->username && 
   657                                 strcasecmp(identity->username, 
   658                                            this_id->username) == 0) {
   659                                 
   660                                 // Ok, we have a real ID. Copy it!
   661                                 identity->user_id = strdup(this_uid);
   662                                 assert(identity->user_id);
   663                                 if (!identity->user_id)
   664                                     goto enomem;
   665 
   666                                 stored_ident = this_id;
   667                                 
   668                                 break;                                
   669                             }                            
   670                         } 
   671                     }
   672                     id_curr = id_curr->next;
   673                 }
   674             }
   675         }
   676         
   677         if (stored_ident) {
   678             status = prepare_updated_identity(session,
   679                                               identity,
   680                                               stored_ident, true);
   681         }
   682         else {
   683             identity->user_id = calloc(1, strlen(identity->address) + 6);
   684             if (!identity->user_id)
   685                 goto enomem;
   686 
   687             snprintf(identity->user_id, strlen(identity->address) + 6,
   688                      "TOFU_%s", identity->address);        
   689 
   690             status = get_identity(session, 
   691                                   identity->address, 
   692                                   identity->user_id, 
   693                                   &stored_ident);
   694 
   695             if (status == PEP_STATUS_OK && stored_ident) {
   696                 status = prepare_updated_identity(session,
   697                                                   identity,
   698                                                   stored_ident, true);
   699             }
   700             else {
   701                          
   702                 //    * We've already checked and retrieved
   703                 //      any applicable temporary identities above. If we're 
   704                 //      here, none of them fit.
   705                 
   706                 status = elect_pubkey(session, identity, false);
   707                              
   708                 //    * call set_identity() to store
   709                 if (identity->fpr)
   710                     status = get_key_rating(session, identity->fpr, &identity->comm_type);
   711             
   712                 //    * call set_identity() to store
   713                 adjust_pep_trust_status(session, identity);            
   714                 status = set_identity(session, identity);
   715             }
   716         }
   717     }
   718     else {
   719         /*
   720         * Input: address (no others)
   721          * Temporary identity information without username suplied
   722          */
   723          
   724         //  * Again, see if there is an own identity that uses this address. If so, we'll
   725         //    prefer that
   726         stored_ident = NULL;
   727          
   728         if (default_own_id) {
   729             status = get_identity(session, 
   730                                   identity->address, 
   731                                   default_own_id, 
   732                                   &stored_ident);
   733         }
   734         // If there isn't an own identity, search for a non-temp stored ident
   735         // with this address.                      
   736         if (status == PEP_CANNOT_FIND_IDENTITY || !stored_ident) { 
   737  
   738             identity_list* id_list = NULL;
   739             //    * Search for identity with this address
   740             status = get_identities_by_address(session, identity->address, &id_list);
   741 
   742             // Results are ordered by timestamp descending, so this covers
   743             // both the one-result and multi-result cases
   744             if (id_list) {
   745                 if (stored_ident) // unlikely
   746                     free_identity(stored_ident);
   747                 stored_ident = id_list->ident;
   748             }
   749         }
   750         if (stored_ident)
   751             status = prepare_updated_identity(session, identity,
   752                                               stored_ident, false);
   753         else  {            
   754             // too little info. BUT. We see if we can find a key; if so, we create a
   755             // temp identity, look for a key, and store.
   756                          
   757             // create temporary identity, store it, and Return this
   758             // This means TOFU_ user_id
   759             identity->user_id = calloc(1, strlen(identity->address) + 6);
   760             if (!identity->user_id)
   761                 goto enomem;
   762 
   763             snprintf(identity->user_id, strlen(identity->address) + 6,
   764                      "TOFU_%s", identity->address);        
   765         
   766             identity->username = strdup(identity->address);
   767             if (!identity->address)
   768                 goto enomem;
   769             
   770             free(identity->fpr);
   771             identity->fpr = NULL;
   772             identity->comm_type = PEP_ct_unknown;
   773 
   774             status = elect_pubkey(session, identity, false);
   775                          
   776             if (identity->fpr)
   777                 status = get_key_rating(session, identity->fpr, &identity->comm_type);
   778         
   779             //    * call set_identity() to store
   780             adjust_pep_trust_status(session, identity);            
   781             status = set_identity(session, identity);
   782 
   783         }
   784     }
   785     
   786     // FIXME: This is legacy. I presume it's a notification for the caller...
   787     // Revisit once I can talk to Volker
   788     if (identity->comm_type != PEP_ct_compromised &&
   789         identity->comm_type < PEP_ct_strong_but_unconfirmed)
   790         if (session->examine_identity)
   791             session->examine_identity(identity, session->examine_management);
   792 
   793     goto pep_free;
   794 
   795 enomem:
   796     status = PEP_OUT_OF_MEMORY;
   797 
   798 pep_free:
   799     free(default_own_id);
   800     free_identity(stored_ident);
   801     return status;
   802 }
   803 
   804 PEP_STATUS elect_ownkey(
   805         PEP_SESSION session, pEp_identity * identity
   806     )
   807 {
   808     PEP_STATUS status;
   809     stringlist_t *keylist = NULL;
   810 
   811     free(identity->fpr);
   812     identity->fpr = NULL;
   813 
   814     status = find_private_keys(session, identity->address, &keylist);
   815     assert(status != PEP_OUT_OF_MEMORY);
   816     if (status == PEP_OUT_OF_MEMORY)
   817         return PEP_OUT_OF_MEMORY;
   818     
   819     if (keylist != NULL && keylist->value != NULL)
   820     {
   821         char *_fpr = NULL;
   822         identity->comm_type = PEP_ct_unknown;
   823 
   824         stringlist_t *_keylist;
   825         for (_keylist = keylist; _keylist && _keylist->value; _keylist = _keylist->next) {
   826             bool is_own = false;
   827             
   828             status = own_key_is_listed(session, _keylist->value, &is_own);
   829             assert(status == PEP_STATUS_OK);
   830             if (status != PEP_STATUS_OK) {
   831                 free_stringlist(keylist);
   832                 return status;
   833             }
   834             
   835             if (is_own)
   836             {
   837                 PEP_comm_type _comm_type_key;
   838                 
   839                 status = get_key_rating(session, _keylist->value, &_comm_type_key);
   840                 assert(status != PEP_OUT_OF_MEMORY);
   841                 if (status == PEP_OUT_OF_MEMORY) {
   842                     free_stringlist(keylist);
   843                     return PEP_OUT_OF_MEMORY;
   844                 }
   845                 
   846                 if (_comm_type_key != PEP_ct_compromised &&
   847                     _comm_type_key != PEP_ct_unknown)
   848                 {
   849                     if (identity->comm_type == PEP_ct_unknown ||
   850                         _comm_type_key > identity->comm_type)
   851                     {
   852                         identity->comm_type = _comm_type_key;
   853                         _fpr = _keylist->value;
   854                     }
   855                 }
   856             }
   857         }
   858         
   859         if (_fpr)
   860         {
   861             identity->fpr = strdup(_fpr);
   862             assert(identity->fpr);
   863             if (identity->fpr == NULL)
   864             {
   865                 free_stringlist(keylist);
   866                 return PEP_OUT_OF_MEMORY;
   867             }
   868         }
   869         free_stringlist(keylist);
   870     }
   871     return PEP_STATUS_OK;
   872 }
   873 
   874 PEP_STATUS _has_usable_priv_key(PEP_SESSION session, char* fpr,
   875                                 bool* is_usable) {
   876     
   877     bool has_private = false;
   878     PEP_STATUS status = contains_priv_key(session, fpr, &has_private);
   879     
   880     *is_usable = has_private;
   881     
   882     return status;
   883 }
   884 
   885 PEP_STATUS _myself(PEP_SESSION session, pEp_identity * identity, bool do_keygen, bool ignore_flags)
   886 {
   887 
   888     PEP_STATUS status;
   889 
   890     assert(session);
   891     assert(identity);
   892     assert(!EMPTYSTR(identity->address));
   893     assert(!EMPTYSTR(identity->user_id));
   894 
   895     if (!session || !identity || EMPTYSTR(identity->address) ||
   896         EMPTYSTR(identity->user_id))
   897         return PEP_ILLEGAL_VALUE;
   898 
   899     pEp_identity *stored_identity = NULL;
   900     char* revoked_fpr = NULL; 
   901     bool valid_key_found = false;
   902         
   903     char* default_own_id = NULL;
   904     status = get_default_own_userid(session, &default_own_id);
   905 
   906     // Deal with non-default user_ids.
   907     if (default_own_id && strcmp(default_own_id, identity->user_id) != 0) {
   908         
   909         status = set_userid_alias(session, default_own_id, identity->user_id);
   910         // Do we want this to be fatal? For now, we'll do it...
   911         if (status != PEP_STATUS_OK)
   912             goto pep_free;
   913             
   914         free(identity->user_id);
   915         identity->user_id = strdup(default_own_id);
   916         if (identity->user_id == NULL) {
   917             status = PEP_OUT_OF_MEMORY;
   918             goto pep_free;
   919         }
   920     }
   921 
   922     // NOTE: IF WE DON'T YET HAVE AN OWN_ID, WE IGNORE REFERENCES TO THIS ADDRESS IN THE
   923     // DB (WHICH MAY HAVE BEEN SET BEFORE MYSELF WAS CALLED BY RECEIVING AN EMAIL FROM
   924     // THIS ADDRESS), AS IT IS NOT AN OWN_IDENTITY AND HAS NO INFORMATION WE NEED OR WHAT TO
   925     // SET FOR MYSELF
   926     
   927     // Ok, so now, set up the own_identity:
   928     identity->comm_type = PEP_ct_pEp;
   929     identity->me = true;
   930     if(ignore_flags)
   931         identity->flags = 0;
   932     
   933     // Let's see if we have an identity record in the DB for 
   934     // this user_id + address
   935 //    DEBUG_LOG("myself", "debug", identity->address);
   936  
   937     status = get_identity(session,
   938                           identity->address,
   939                           identity->user_id,
   940                           &stored_identity);
   941 
   942     assert(status != PEP_OUT_OF_MEMORY);
   943     if (status == PEP_OUT_OF_MEMORY) {
   944         status = PEP_OUT_OF_MEMORY;
   945         goto pep_free;
   946     }
   947 
   948     // Set usernames - priority is input username > stored name > address
   949     // If there's an input username, we always patch the username with that
   950     // input.
   951     if (EMPTYSTR(identity->username)) {
   952         bool stored_uname = (stored_identity && !EMPTYSTR(stored_identity->username));
   953         char* uname = (stored_uname ? stored_identity->username : identity->address);
   954         free(identity->username);
   955         identity->username = strdup(uname);
   956         if (identity->username == NULL) {
   957             status = PEP_OUT_OF_MEMORY;
   958             goto pep_free;
   959         }
   960     }
   961 
   962     // ignore input fpr
   963 
   964     if (identity->fpr) {
   965         free(identity->fpr);
   966         identity->fpr = NULL;
   967     }
   968 
   969     // check stored identity
   970     if (stored_identity && !EMPTYSTR(stored_identity->fpr)) {
   971         // Fall back / retrieve
   972         status = validate_fpr(session, stored_identity, false);
   973         if (status == PEP_OUT_OF_MEMORY)
   974             goto pep_free;
   975         if (status == PEP_STATUS_OK) {
   976             if (stored_identity->comm_type >= PEP_ct_strong_but_unconfirmed) {
   977                 identity->fpr = strdup(stored_identity->fpr);
   978                 assert(identity->fpr);
   979                 if (!identity->fpr) {
   980                     status = PEP_OUT_OF_MEMORY;
   981                     goto pep_free;
   982                 }
   983                 valid_key_found = true;            
   984             }
   985             else {
   986                 bool revoked = false;
   987                 status = key_revoked(session, stored_identity->fpr, &revoked);
   988                 if (status)
   989                     goto pep_free;
   990                 if (revoked) {
   991                     revoked_fpr = strdup(stored_identity->fpr);
   992                     assert(revoked_fpr);
   993                     if (!revoked_fpr) {
   994                         status = PEP_OUT_OF_MEMORY;
   995                         goto pep_free;
   996                     }
   997                 }
   998             }
   999         }
  1000     }
  1001     
  1002     // Nothing left to do but generate a key
  1003     if (!valid_key_found) {
  1004         if (!do_keygen)
  1005             status = PEP_GET_KEY_FAILED;
  1006         else {
  1007 // /            DEBUG_LOG("Generating key pair", "debug", identity->address);
  1008 
  1009             free(identity->fpr);
  1010             identity->fpr = NULL;
  1011             status = generate_keypair(session, identity);
  1012             assert(status != PEP_OUT_OF_MEMORY);
  1013 
  1014             if (status != PEP_STATUS_OK) {
  1015                 char buf[11];
  1016                 snprintf(buf, 11, "%d", status); // uh, this is kludgey. FIXME
  1017 //                DEBUG_LOG("Generating key pair failed", "debug", buf);
  1018             }        
  1019             else {
  1020                 valid_key_found = true;
  1021                 if (revoked_fpr) {
  1022                     status = set_revoked(session, revoked_fpr,
  1023                                          stored_identity->fpr, time(NULL));
  1024                 }
  1025             }
  1026         }
  1027     }
  1028 
  1029     if (valid_key_found) {
  1030         identity->comm_type = PEP_ct_pEp;
  1031         status = PEP_STATUS_OK;
  1032     }
  1033     else {
  1034         free(identity->fpr);
  1035         identity->fpr = NULL;
  1036         identity->comm_type = PEP_ct_unknown;
  1037     }
  1038     
  1039     status = set_identity(session, identity);
  1040     if (status == PEP_STATUS_OK)
  1041         status = set_as_pep_user(session, identity);
  1042 
  1043 pep_free:    
  1044     free(default_own_id);
  1045     free(revoked_fpr);                     
  1046     free_identity(stored_identity);
  1047     return status;
  1048 }
  1049 
  1050 // DYNAMIC_API PEP_STATUS initialise_own_identities(PEP_SESSION session,
  1051 //                                                  identity_list* my_idents) {
  1052 //     PEP_STATUS status = PEP_STATUS_OK;
  1053 //     if (!session)
  1054 //         return PEP_ILLEGAL_VALUE;
  1055 //         
  1056 //     if (!my_idents)
  1057 //         return PEP_STATUS_OK;
  1058 //             
  1059 //     identity_list* ident_curr = my_idents;
  1060 //     while (ident_curr) {
  1061 //         pEp_identity* ident = ident_curr->ident;
  1062 //         if (!ident || !ident->address) {
  1063 //             status = PEP_ILLEGAL_VALUE;
  1064 //             goto pep_error;
  1065 //         }
  1066 // 
  1067 //         status = _myself(session, ident, false, false);
  1068 //         
  1069 //         ident_curr = ident_curr->next;
  1070 //     }
  1071 //     
  1072 // pep_error:
  1073 //     return status;
  1074 // }
  1075 
  1076 DYNAMIC_API PEP_STATUS myself(PEP_SESSION session, pEp_identity * identity)
  1077 {
  1078     return _myself(session, identity, true, false);
  1079 }
  1080 
  1081 DYNAMIC_API PEP_STATUS register_examine_function(
  1082         PEP_SESSION session, 
  1083         examine_identity_t examine_identity,
  1084         void *management
  1085     )
  1086 {
  1087     assert(session);
  1088     if (!session)
  1089         return PEP_ILLEGAL_VALUE;
  1090 
  1091     session->examine_management = management;
  1092     session->examine_identity = examine_identity;
  1093 
  1094     return PEP_STATUS_OK;
  1095 }
  1096 
  1097 DYNAMIC_API PEP_STATUS do_keymanagement(
  1098         retrieve_next_identity_t retrieve_next_identity,
  1099         void *management
  1100     )
  1101 {
  1102     PEP_SESSION session;
  1103     pEp_identity *identity;
  1104     PEP_STATUS status;
  1105 
  1106     assert(retrieve_next_identity);
  1107     assert(management);
  1108 
  1109     if (!retrieve_next_identity || !management)
  1110         return PEP_ILLEGAL_VALUE;
  1111 
  1112     status = init(&session);
  1113     assert(status == PEP_STATUS_OK);
  1114     if (status != PEP_STATUS_OK)
  1115         return status;
  1116 
  1117     log_event(session, "keymanagement thread started", "pEp engine", NULL, NULL);
  1118 
  1119     while ((identity = retrieve_next_identity(management))) 
  1120     {
  1121         assert(identity->address);
  1122         if(identity->address)
  1123         {
  1124             DEBUG_LOG("do_keymanagement", "retrieve_next_identity", identity->address);
  1125 
  1126             if (identity->me) {
  1127                 status = myself(session, identity);
  1128             } else {
  1129                 status = recv_key(session, identity->address);
  1130             }
  1131 
  1132             assert(status != PEP_OUT_OF_MEMORY);
  1133             if(status == PEP_OUT_OF_MEMORY)
  1134                 return PEP_OUT_OF_MEMORY;
  1135         }
  1136         free_identity(identity);
  1137     }
  1138 
  1139     log_event(session, "keymanagement thread shutdown", "pEp engine", NULL, NULL);
  1140 
  1141     release(session);
  1142     return PEP_STATUS_OK;
  1143 }
  1144 
  1145 DYNAMIC_API PEP_STATUS key_mistrusted(
  1146         PEP_SESSION session,
  1147         pEp_identity *ident
  1148     )
  1149 {
  1150     PEP_STATUS status = PEP_STATUS_OK;
  1151 
  1152     assert(session);
  1153     assert(ident);
  1154     assert(!EMPTYSTR(ident->fpr));
  1155 
  1156     if (!(session && ident && ident->fpr))
  1157         return PEP_ILLEGAL_VALUE;
  1158 
  1159     if (ident->me)
  1160     {
  1161         revoke_key(session, ident->fpr, NULL);
  1162         myself(session, ident);
  1163     }
  1164     else
  1165     {
  1166         // for undo
  1167         if (session->cached_mistrusted)
  1168             free(session->cached_mistrusted);
  1169         session->cached_mistrusted = identity_dup(ident);
  1170         
  1171         // set mistrust for this user_id/keypair (even if there's not an
  1172         // identity set yet, this is important, as we need to record the mistrust
  1173         // action)
  1174         
  1175         // double-check to be sure key is even in the DB
  1176         if (ident->fpr)
  1177             status = set_pgp_keypair(session, ident->fpr);
  1178 
  1179         // We set this temporarily but will grab it back from the cache afterwards
  1180         ident->comm_type = PEP_ct_mistrusted;
  1181         status = set_trust(session, ident);
  1182         ident->comm_type = session->cached_mistrusted->comm_type;
  1183         
  1184         if (status == PEP_STATUS_OK)
  1185             // cascade that mistrust for anyone using this key
  1186             status = mark_as_compromised(session, ident->fpr);
  1187         if (status == PEP_STATUS_OK)
  1188             status = remove_fpr_as_default(session, ident->fpr);
  1189         if (status == PEP_STATUS_OK)
  1190             status = add_mistrusted_key(session, ident->fpr);
  1191     }
  1192 
  1193     return status;
  1194 }
  1195 
  1196 DYNAMIC_API PEP_STATUS undo_last_mistrust(PEP_SESSION session) {
  1197     assert(session);
  1198     
  1199     if (!session)
  1200         return PEP_ILLEGAL_VALUE;
  1201     
  1202     PEP_STATUS status = PEP_STATUS_OK;
  1203         
  1204     pEp_identity* cached_ident = session->cached_mistrusted;
  1205     
  1206     if (!cached_ident)
  1207         status = PEP_CANNOT_FIND_IDENTITY;
  1208     else {
  1209         status = delete_mistrusted_key(session, cached_ident->fpr);
  1210         if (status == PEP_STATUS_OK) {
  1211             status = set_identity(session, cached_ident);
  1212             // THIS SHOULDN'T BE NECESSARY - PREVIOUS VALUE WAS IN THE DB
  1213             // if (status == PEP_STATUS_OK) {
  1214             //     if ((cached_ident->comm_type | PEP_ct_confirmed) == PEP_ct_pEp)
  1215             //         status = set_as_pep_user(session, cached_ident);
  1216             // }            
  1217             free_identity(session->cached_mistrusted);
  1218         }
  1219     }
  1220     
  1221     session->cached_mistrusted = NULL;
  1222     
  1223     return status;
  1224 }
  1225 
  1226 DYNAMIC_API PEP_STATUS key_reset_trust(
  1227         PEP_SESSION session,
  1228         pEp_identity *ident
  1229     )
  1230 {
  1231     PEP_STATUS status = PEP_STATUS_OK;
  1232 
  1233     assert(session);
  1234     assert(ident);
  1235     assert(!EMPTYSTR(ident->fpr));
  1236     assert(!EMPTYSTR(ident->address));
  1237     assert(!EMPTYSTR(ident->user_id));
  1238 
  1239     if (!(session && ident && ident->fpr && ident->fpr[0] != '\0' && ident->address &&
  1240             ident->user_id))
  1241         return PEP_ILLEGAL_VALUE;
  1242 
  1243     // we do not change the input struct at ALL.
  1244     pEp_identity* input_copy = identity_dup(ident);
  1245     
  1246     pEp_identity* tmp_ident = NULL;
  1247     
  1248     status = get_trust(session, input_copy);
  1249     
  1250     if (status != PEP_STATUS_OK)
  1251         goto pep_free;
  1252         
  1253     PEP_comm_type new_trust = PEP_ct_unknown;
  1254     status = get_key_rating(session, ident->fpr, &new_trust);
  1255     if (status != PEP_STATUS_OK)
  1256         goto pep_free;
  1257 
  1258     bool pep_user = false;
  1259     
  1260     status = is_pep_user(session, ident, &pep_user);
  1261     
  1262     if (pep_user && new_trust >= PEP_ct_unconfirmed_encryption)
  1263         input_copy->comm_type = PEP_ct_pEp_unconfirmed;
  1264     else
  1265         input_copy->comm_type = new_trust;
  1266         
  1267     status = set_trust(session, input_copy);
  1268     
  1269     if (status != PEP_STATUS_OK)
  1270         goto pep_free;
  1271 
  1272     bool mistrusted_key = false;
  1273         
  1274     status = is_mistrusted_key(session, ident->fpr, &mistrusted_key);
  1275 
  1276     if (status != PEP_STATUS_OK)
  1277         goto pep_free;
  1278     
  1279     if (mistrusted_key)
  1280         status = delete_mistrusted_key(session, ident->fpr);
  1281 
  1282     if (status != PEP_STATUS_OK)
  1283         goto pep_free;
  1284         
  1285     tmp_ident = new_identity(ident->address, NULL, ident->user_id, NULL);
  1286 
  1287     if (!tmp_ident)
  1288         return PEP_OUT_OF_MEMORY;
  1289     
  1290     if (is_me(session, tmp_ident))
  1291         status = myself(session, tmp_ident);
  1292     else
  1293         status = update_identity(session, tmp_ident);
  1294     
  1295     if (status != PEP_STATUS_OK)
  1296         goto pep_free;
  1297     
  1298     // remove as default if necessary
  1299     if (!EMPTYSTR(tmp_ident->fpr) && strcmp(tmp_ident->fpr, ident->fpr) == 0) {
  1300         free(tmp_ident->fpr);
  1301         tmp_ident->fpr = NULL;
  1302         tmp_ident->comm_type = PEP_ct_unknown;
  1303         status = set_identity(session, tmp_ident);
  1304         if (status != PEP_STATUS_OK)
  1305             goto pep_free;
  1306     }
  1307     
  1308     char* user_default = NULL;
  1309     get_main_user_fpr(session, tmp_ident->user_id, &user_default);
  1310     
  1311     if (!EMPTYSTR(user_default)) {
  1312         if (strcmp(user_default, ident->fpr) == 0)
  1313             status = refresh_userid_default_key(session, ident->user_id);
  1314         if (status != PEP_STATUS_OK)
  1315             goto pep_free;    
  1316     }
  1317             
  1318 pep_free:
  1319     free_identity(tmp_ident);
  1320     free_identity(input_copy);
  1321     return status;
  1322 }
  1323 
  1324 DYNAMIC_API PEP_STATUS trust_personal_key(
  1325         PEP_SESSION session,
  1326         pEp_identity *ident
  1327     )
  1328 {
  1329     PEP_STATUS status = PEP_STATUS_OK;
  1330 
  1331     assert(session);
  1332     assert(ident);
  1333     assert(!EMPTYSTR(ident->address));
  1334     assert(!EMPTYSTR(ident->user_id));
  1335     assert(!EMPTYSTR(ident->fpr));
  1336 
  1337     if (!ident || EMPTYSTR(ident->address) || EMPTYSTR(ident->user_id) ||
  1338             EMPTYSTR(ident->fpr))
  1339         return PEP_ILLEGAL_VALUE;
  1340 
  1341     //bool ident_has_trusted_default = false;
  1342     char* ident_default_fpr = NULL;
  1343 
  1344     // Before we do anything, be sure the input fpr is even eligible to be trusted
  1345     PEP_comm_type input_default_ct = PEP_ct_unknown;
  1346     status = get_key_rating(session, ident->fpr, &input_default_ct);
  1347     if (input_default_ct < PEP_ct_strong_but_unconfirmed)
  1348         return PEP_KEY_UNSUITABLE;
  1349 
  1350     status = set_pgp_keypair(session, ident->fpr);
  1351     if (status != PEP_STATUS_OK)
  1352         return status;
  1353 
  1354     bool me = is_me(session, ident);
  1355 
  1356     pEp_identity* ident_copy = identity_dup(ident);
  1357     char* cached_fpr = NULL;
  1358 
  1359     // for setting up a temp trusted identity for the input fpr
  1360     pEp_identity* tmp_id = NULL;
  1361 
  1362     // For later, in case we need to check the user default key
  1363     pEp_identity* tmp_user_ident = NULL;
  1364 
  1365     if (me) {
  1366         bool has_private = false;
  1367         // first of all, does this key even have a private component.
  1368         status = contains_priv_key(session, ident->fpr, &has_private);
  1369         if (status != PEP_STATUS_OK && status != PEP_KEY_NOT_FOUND)
  1370             goto pep_free;
  1371             
  1372         if (has_private) {
  1373             status = set_own_key(session, ident_copy, ident->fpr); 
  1374             goto pep_free;
  1375         }
  1376     }
  1377     
  1378     // Either it's not me, or it's me but the key has no private key. 
  1379     // We're only talking about pub keys here. Moving on.
  1380     
  1381     // Save the input fpr, which we already tested as non-NULL
  1382     cached_fpr = strdup(ident->fpr);
  1383 
  1384     // Set up a temp trusted identity for the input fpr without a comm type;
  1385     tmp_id = new_identity(ident->address, ident->fpr, ident->user_id, NULL);
  1386     
  1387     // ->me isn't set, even if this is an own identity, so this will work.
  1388     status = validate_fpr(session, tmp_id, false);
  1389         
  1390     if (status == PEP_STATUS_OK) {
  1391         // Validate fpr gets trust DB or, when that fails, key comm type. we checked
  1392         // above that the key was ok. (not revoked or expired), but we want the max.
  1393         tmp_id->comm_type = _MAX(tmp_id->comm_type, input_default_ct) | PEP_ct_confirmed;
  1394 
  1395         // Get the default identity without setting the fpr                                       
  1396         if (me)
  1397             status = _myself(session, ident_copy, false, true);
  1398         else    
  1399             status = update_identity(session, ident_copy);
  1400             
  1401         ident_default_fpr = (EMPTYSTR(ident_copy->fpr) ? NULL : strdup(ident_copy->fpr));
  1402 
  1403         if (status == PEP_STATUS_OK) {
  1404             bool trusted_default = false;
  1405 
  1406             // If there's no default, or the default is different from the input...
  1407             if (me || EMPTYSTR(ident_default_fpr) || strcmp(cached_fpr, ident_default_fpr) != 0) {
  1408                 
  1409                 // If the default fpr (if there is one) is trusted and key is strong enough,
  1410                 // don't replace, we just set the trusted bit on this key for this user_id...
  1411                 // (If there's no default fpr, this won't be true anyway.)
  1412                 if (me || (ident_copy->comm_type >= PEP_ct_strong_but_unconfirmed && 
  1413                           (ident_copy->comm_type & PEP_ct_confirmed))) {                        
  1414 
  1415                     trusted_default = true;
  1416                                     
  1417                     status = set_trust(session, tmp_id);
  1418                     input_default_ct = tmp_id->comm_type;                    
  1419                 }
  1420                 else {
  1421                     free(ident_copy->fpr);
  1422                     ident_copy->fpr = strdup(cached_fpr);
  1423                     ident_copy->comm_type = tmp_id->comm_type;
  1424                     status = set_identity(session, ident_copy); // replace identity default
  1425                     if (status == PEP_STATUS_OK) {
  1426                         if ((ident_copy->comm_type | PEP_ct_confirmed) == PEP_ct_pEp)
  1427                             status = set_as_pep_user(session, ident_copy);
  1428                     }            
  1429                 }
  1430             }
  1431             else { // we're setting this on the default fpr
  1432                 ident->comm_type = tmp_id->comm_type;
  1433                 status = set_identity(session, ident);
  1434                 trusted_default = true;
  1435             }
  1436             if (status == PEP_STATUS_OK && !trusted_default) {
  1437                 // Ok, there wasn't a trusted default, so we replaced. Thus, we also
  1438                 // make sure there's a trusted default on the user_id. If there
  1439                 // is not, we make this the default.
  1440                 char* user_default = NULL;
  1441                 status = get_main_user_fpr(session, ident->user_id, &user_default);
  1442             
  1443                 if (status == PEP_STATUS_OK && user_default) {
  1444                     tmp_user_ident = new_identity(ident->address, 
  1445                                                   user_default, 
  1446                                                   ident->user_id, 
  1447                                                   NULL);
  1448                     if (!tmp_user_ident)
  1449                         status = PEP_OUT_OF_MEMORY;
  1450                     else {
  1451                         status = validate_fpr(session, tmp_user_ident, false);
  1452                         
  1453                         if (status != PEP_STATUS_OK ||
  1454                             tmp_user_ident->comm_type < PEP_ct_strong_but_unconfirmed ||
  1455                             !(tmp_user_ident->comm_type & PEP_ct_confirmed)) 
  1456                         {
  1457                             char* trusted_fpr = (trusted_default ? ident_default_fpr : cached_fpr);
  1458                             status = replace_main_user_fpr(session, ident->user_id, trusted_fpr);
  1459                         } 
  1460                     }
  1461                 }
  1462             }
  1463         }
  1464     }    
  1465 
  1466 pep_free:
  1467     free(ident_default_fpr);
  1468     free(cached_fpr);
  1469     free_identity(tmp_id);
  1470     free_identity(ident_copy);
  1471     free_identity(tmp_user_ident);
  1472     return status;
  1473 }
  1474 
  1475 DYNAMIC_API PEP_STATUS own_key_is_listed(
  1476         PEP_SESSION session,
  1477         const char *fpr,
  1478         bool *listed
  1479     )
  1480 {
  1481     PEP_STATUS status = PEP_STATUS_OK;
  1482     int count;
  1483     
  1484     assert(session && fpr && fpr[0] && listed);
  1485     
  1486     if (!(session && fpr && fpr[0] && listed))
  1487         return PEP_ILLEGAL_VALUE;
  1488     
  1489     *listed = false;
  1490     
  1491     sqlite3_reset(session->own_key_is_listed);
  1492     sqlite3_bind_text(session->own_key_is_listed, 1, fpr, -1, SQLITE_STATIC);
  1493     
  1494     int result;
  1495     
  1496     result = sqlite3_step(session->own_key_is_listed);
  1497     switch (result) {
  1498         case SQLITE_ROW:
  1499             count = sqlite3_column_int(session->own_key_is_listed, 0);
  1500             *listed = count > 0;
  1501             status = PEP_STATUS_OK;
  1502             break;
  1503             
  1504         default:
  1505             status = PEP_UNKNOWN_ERROR;
  1506     }
  1507     
  1508     sqlite3_reset(session->own_key_is_listed);
  1509     return status;
  1510 }
  1511 
  1512 PEP_STATUS _own_identities_retrieve(
  1513         PEP_SESSION session,
  1514         identity_list **own_identities,
  1515         identity_flags_t excluded_flags
  1516       )
  1517 {
  1518     PEP_STATUS status = PEP_STATUS_OK;
  1519     
  1520     assert(session && own_identities);
  1521     if (!(session && own_identities))
  1522         return PEP_ILLEGAL_VALUE;
  1523     
  1524     *own_identities = NULL;
  1525     identity_list *_own_identities = new_identity_list(NULL);
  1526     if (_own_identities == NULL)
  1527         goto enomem;
  1528     
  1529     sqlite3_reset(session->own_identities_retrieve);
  1530     
  1531     int result;
  1532     // address, fpr, username, user_id, comm_type, lang, flags
  1533     const char *address = NULL;
  1534     const char *fpr = NULL;
  1535     const char *username = NULL;
  1536     const char *user_id = NULL;
  1537     PEP_comm_type comm_type = PEP_ct_unknown;
  1538     const char *lang = NULL;
  1539     unsigned int flags = 0;
  1540     
  1541     identity_list *_bl = _own_identities;
  1542     do {
  1543         sqlite3_bind_int(session->own_identities_retrieve, 1, excluded_flags);
  1544         result = sqlite3_step(session->own_identities_retrieve);
  1545         switch (result) {
  1546             case SQLITE_ROW:
  1547                 address = (const char *)
  1548                     sqlite3_column_text(session->own_identities_retrieve, 0);
  1549                 fpr = (const char *)
  1550                     sqlite3_column_text(session->own_identities_retrieve, 1);
  1551                 user_id = (const char *)
  1552                     sqlite3_column_text(session->own_identities_retrieve, 2);
  1553                 username = (const char *)
  1554                     sqlite3_column_text(session->own_identities_retrieve, 3);
  1555                 comm_type = PEP_ct_pEp;
  1556                 lang = (const char *)
  1557                     sqlite3_column_text(session->own_identities_retrieve, 4);
  1558                 flags = (unsigned int)
  1559                     sqlite3_column_int(session->own_identities_retrieve, 5);
  1560 
  1561                 pEp_identity *ident = new_identity(address, fpr, user_id, username);
  1562                 if (!ident)
  1563                     goto enomem;
  1564                 ident->comm_type = comm_type;
  1565                 if (lang && lang[0]) {
  1566                     ident->lang[0] = lang[0];
  1567                     ident->lang[1] = lang[1];
  1568                     ident->lang[2] = 0;
  1569                 }
  1570                 ident->me = true;
  1571                 ident->flags = flags;
  1572 
  1573                 _bl = identity_list_add(_bl, ident);
  1574                 if (_bl == NULL) {
  1575                     free_identity(ident);
  1576                     goto enomem;
  1577                 }
  1578                 
  1579                 break;
  1580                 
  1581             case SQLITE_DONE:
  1582                 break;
  1583                 
  1584             default:
  1585                 status = PEP_UNKNOWN_ERROR;
  1586                 result = SQLITE_DONE;
  1587         }
  1588     } while (result != SQLITE_DONE);
  1589     
  1590     sqlite3_reset(session->own_identities_retrieve);
  1591     if (status == PEP_STATUS_OK)
  1592         *own_identities = _own_identities;
  1593     else
  1594         free_identity_list(_own_identities);
  1595     
  1596     goto the_end;
  1597     
  1598 enomem:
  1599     free_identity_list(_own_identities);
  1600     status = PEP_OUT_OF_MEMORY;
  1601     
  1602 the_end:
  1603     return status;
  1604 }
  1605 
  1606 DYNAMIC_API PEP_STATUS own_identities_retrieve(
  1607         PEP_SESSION session,
  1608         identity_list **own_identities
  1609       )
  1610 {
  1611     return _own_identities_retrieve(session, own_identities, 0);
  1612 }
  1613 
  1614 PEP_STATUS _own_keys_retrieve(
  1615         PEP_SESSION session,
  1616         stringlist_t **keylist,
  1617         identity_flags_t excluded_flags
  1618       )
  1619 {
  1620     PEP_STATUS status = PEP_STATUS_OK;
  1621     
  1622     assert(session && keylist);
  1623     if (!(session && keylist))
  1624         return PEP_ILLEGAL_VALUE;
  1625     
  1626     *keylist = NULL;
  1627     stringlist_t *_keylist = NULL;
  1628     
  1629     sqlite3_reset(session->own_keys_retrieve);
  1630     
  1631     int result;
  1632     char *fpr = NULL;
  1633     
  1634     stringlist_t *_bl = _keylist;
  1635     do {
  1636         sqlite3_bind_int(session->own_keys_retrieve, 1, excluded_flags);
  1637         result = sqlite3_step(session->own_keys_retrieve);
  1638         switch (result) {
  1639             case SQLITE_ROW:
  1640                 fpr = strdup((const char *) sqlite3_column_text(session->own_keys_retrieve, 0));
  1641                 if(fpr == NULL)
  1642                     goto enomem;
  1643 
  1644                 _bl = stringlist_add(_bl, fpr);
  1645                 if (_bl == NULL) {
  1646                     free(fpr);
  1647                     goto enomem;
  1648                 }
  1649                 if (_keylist == NULL)
  1650                     _keylist = _bl;
  1651                 
  1652                 break;
  1653                 
  1654             case SQLITE_DONE:
  1655                 break;
  1656                 
  1657             default:
  1658                 status = PEP_UNKNOWN_ERROR;
  1659                 result = SQLITE_DONE;
  1660         }
  1661     } while (result != SQLITE_DONE);
  1662     
  1663     sqlite3_reset(session->own_keys_retrieve);
  1664     if (status == PEP_STATUS_OK)
  1665         *keylist = _keylist;
  1666     else
  1667         free_stringlist(_keylist);
  1668     
  1669     goto the_end;
  1670     
  1671 enomem:
  1672     free_stringlist(_keylist);
  1673     status = PEP_OUT_OF_MEMORY;
  1674     
  1675 the_end:
  1676     return status;
  1677 }
  1678 
  1679 DYNAMIC_API PEP_STATUS own_keys_retrieve(PEP_SESSION session, stringlist_t **keylist)
  1680 {
  1681     return _own_keys_retrieve(session, keylist, 0);
  1682 }
  1683 
  1684 DYNAMIC_API PEP_STATUS set_own_key(
  1685        PEP_SESSION session,
  1686        pEp_identity *me,
  1687        const char *fpr
  1688     )
  1689 {
  1690     PEP_STATUS status = PEP_STATUS_OK;
  1691     
  1692     assert(session && me);
  1693     assert(!EMPTYSTR(fpr));
  1694     assert(!EMPTYSTR(me->address));
  1695     assert(!EMPTYSTR(me->user_id));
  1696     assert(!EMPTYSTR(me->username));
  1697 
  1698     if (!session || !me || EMPTYSTR(fpr) || EMPTYSTR(me->address) ||
  1699             EMPTYSTR(me->user_id) || EMPTYSTR(me->username))
  1700         return PEP_ILLEGAL_VALUE;
  1701 
  1702     status = _myself(session, me, false, true);
  1703     // we do not need a valid key but dislike other errors
  1704     if (status != PEP_STATUS_OK && status != PEP_GET_KEY_FAILED && status != PEP_KEY_UNSUITABLE)
  1705         return status;
  1706     status = PEP_STATUS_OK;
  1707  
  1708     if (me->fpr)
  1709         free(me->fpr);
  1710     me->fpr = strdup(fpr);
  1711     assert(me->fpr);
  1712     if (!me->fpr)
  1713         return PEP_OUT_OF_MEMORY;
  1714 
  1715     status = validate_fpr(session, me, false);
  1716     if (status)
  1717         return status;
  1718 
  1719     me->comm_type = PEP_ct_pEp;
  1720     status = set_identity(session, me);
  1721     return status;
  1722 }
  1723 
  1724 PEP_STATUS contains_priv_key(PEP_SESSION session, const char *fpr,
  1725                              bool *has_private) {
  1726 
  1727     assert(session);
  1728     assert(fpr);
  1729     assert(has_private);
  1730     
  1731     if (!(session && fpr && has_private))
  1732         return PEP_ILLEGAL_VALUE;
  1733 
  1734     return session->cryptotech[PEP_crypt_OpenPGP].contains_priv_key(session, fpr, has_private);
  1735 }
  1736 
  1737 PEP_STATUS add_mistrusted_key(PEP_SESSION session, const char* fpr)
  1738 {
  1739     int result;
  1740 
  1741     assert(!EMPTYSTR(fpr));
  1742     
  1743     if (!(session) || EMPTYSTR(fpr))
  1744         return PEP_ILLEGAL_VALUE;
  1745 
  1746     sqlite3_reset(session->add_mistrusted_key);
  1747     sqlite3_bind_text(session->add_mistrusted_key, 1, fpr, -1,
  1748             SQLITE_STATIC);
  1749 
  1750     result = sqlite3_step(session->add_mistrusted_key);
  1751     sqlite3_reset(session->add_mistrusted_key);
  1752 
  1753     if (result != SQLITE_DONE)
  1754         return PEP_CANNOT_SET_PGP_KEYPAIR; // FIXME: Better status?
  1755 
  1756     return PEP_STATUS_OK;
  1757 }
  1758 
  1759 PEP_STATUS delete_mistrusted_key(PEP_SESSION session, const char* fpr)
  1760 {
  1761     int result;
  1762 
  1763     assert(!EMPTYSTR(fpr));
  1764     
  1765     if (!(session) || EMPTYSTR(fpr))
  1766         return PEP_ILLEGAL_VALUE;
  1767 
  1768     sqlite3_reset(session->delete_mistrusted_key);
  1769     sqlite3_bind_text(session->delete_mistrusted_key, 1, fpr, -1,
  1770             SQLITE_STATIC);
  1771 
  1772     result = sqlite3_step(session->delete_mistrusted_key);
  1773     sqlite3_reset(session->delete_mistrusted_key);
  1774 
  1775     if (result != SQLITE_DONE)
  1776         return PEP_UNKNOWN_ERROR; // FIXME: Better status?
  1777 
  1778     return PEP_STATUS_OK;
  1779 }
  1780 
  1781 PEP_STATUS is_mistrusted_key(PEP_SESSION session, const char* fpr,
  1782                              bool* mistrusted)
  1783 {
  1784     PEP_STATUS status = PEP_STATUS_OK;
  1785 
  1786     assert(session);
  1787     assert(!EMPTYSTR(fpr));
  1788 
  1789     if (!(session && fpr))
  1790         return PEP_ILLEGAL_VALUE;
  1791 
  1792     *mistrusted = false;
  1793 
  1794     sqlite3_reset(session->is_mistrusted_key);
  1795     sqlite3_bind_text(session->is_mistrusted_key, 1, fpr, -1, SQLITE_STATIC);
  1796 
  1797     int result;
  1798 
  1799     result = sqlite3_step(session->is_mistrusted_key);
  1800     switch (result) {
  1801     case SQLITE_ROW:
  1802         *mistrusted = sqlite3_column_int(session->is_mistrusted_key, 0);
  1803         status = PEP_STATUS_OK;
  1804         break;
  1805 
  1806     default:
  1807         status = PEP_UNKNOWN_ERROR;
  1808     }
  1809 
  1810     sqlite3_reset(session->is_mistrusted_key);
  1811     return status;
  1812 }
  1813 
  1814 #ifdef USE_GPG
  1815 PEP_STATUS pgp_find_trusted_private_keys(
  1816         PEP_SESSION session, stringlist_t **keylist
  1817     );
  1818 
  1819 enum _pgp_thing {
  1820     _pgp_none = 0,
  1821     _pgp_fpr,
  1822     _pgp_email,
  1823     _pgp_name
  1824 };
  1825 
  1826 static enum _pgp_thing _pgp_thing_next(enum _pgp_thing thing)
  1827 {
  1828     switch (thing) {
  1829         case _pgp_fpr:
  1830             return _pgp_email;
  1831         case _pgp_email:
  1832             return _pgp_name;
  1833         case _pgp_name:
  1834             return _pgp_fpr;
  1835         default:
  1836             return _pgp_fpr;
  1837     }
  1838 }
  1839 
  1840 PEP_STATUS pgp_import_ultimately_trusted_keypairs(PEP_SESSION session) {
  1841     assert(session);
  1842     if (!session)
  1843         return PEP_ILLEGAL_VALUE;
  1844 
  1845     stringlist_t* priv_keylist = NULL;
  1846     PEP_STATUS status = PEP_STATUS_OK;
  1847 
  1848     // 1. get keys
  1849     status = pgp_find_trusted_private_keys(session, &priv_keylist);
  1850     if (status)
  1851         return status;
  1852 
  1853     pEp_identity *identity = NULL;
  1854     stringlist_t *_sl;
  1855 	
  1856     char *fpr = NULL;
  1857     enum _pgp_thing thing = _pgp_none;
  1858     for (_sl = priv_keylist; _sl && _sl->value; _sl = _sl->next) {
  1859         thing = _pgp_thing_next(thing);
  1860         switch (thing) {
  1861             case _pgp_fpr:
  1862                 identity = new_identity(NULL, NULL, PEP_OWN_USERID, NULL);
  1863                 if (!identity)
  1864                     status = PEP_OUT_OF_MEMORY;
  1865                 identity->me = true;
  1866                 fpr = strdup(_sl->value);
  1867                 assert(fpr);
  1868                 if (!fpr) {
  1869                     status = PEP_OUT_OF_MEMORY;
  1870                     free_identity(identity);
  1871                 }
  1872                 break;
  1873             case _pgp_email:
  1874                 assert(identity);
  1875                 identity->address = strdup(_sl->value);
  1876                 assert(identity->address);
  1877                 if (!identity->address) {
  1878                     status = PEP_OUT_OF_MEMORY;
  1879                     free_identity(identity);
  1880                 }
  1881                 break;
  1882             case _pgp_name:
  1883                 assert(identity);
  1884                 identity->username = strdup(_sl->value);
  1885                 assert(identity->username);
  1886                 if (!identity->username)
  1887                     status = PEP_OUT_OF_MEMORY;
  1888                 else
  1889                     status = set_own_key(session, identity, fpr);
  1890                 free_identity(identity);
  1891                 identity = NULL;
  1892                 break;
  1893             default:
  1894                 assert(0);
  1895                 free_identity(identity);
  1896                 status = PEP_UNKNOWN_ERROR;
  1897         }
  1898         if (status)
  1899             break;
  1900     }
  1901     
  1902     free_stringlist(priv_keylist);
  1903     return status;
  1904 }
  1905 #endif // USE_GPG