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