Merged in ENGINE-352 database_change_branch
authorKrista Bennett <krista@pep-project.org>
Sun, 04 Feb 2018 03:52:27 +0100
branchdatabase_change_branch
changeset 24736ca62f99148e
parent 2472 ebe750121b3d
parent 2470 8ee0981369bb
child 2476 5a4da2a7f99b
child 2714 cd909fb137d4
Merged in ENGINE-352
src/message_api.c
src/pEpEngine.c
src/pEp_internal.h
     1.1 --- a/src/message_api.c	Sun Feb 04 03:38:28 2018 +0100
     1.2 +++ b/src/message_api.c	Sun Feb 04 03:52:27 2018 +0100
     1.3 @@ -1501,6 +1501,8 @@
     1.4      }
     1.5  
     1.6      bool dest_keys_found = true;
     1.7 +    bool has_pep_user = false;
     1.8 +    
     1.9      PEP_comm_type max_comm_type = PEP_ct_pEp;
    1.10  
    1.11      identity_list * _il;
    1.12 @@ -1524,6 +1526,8 @@
    1.13                  _il->ident->comm_type = PEP_ct_key_not_found;
    1.14                  _status = PEP_STATUS_OK;
    1.15              }
    1.16 +            if (!has_pep_user)
    1.17 +                is_pep_user(session, _il->ident, &has_pep_user);
    1.18          }
    1.19          else
    1.20              _status = myself(session, _il->ident);
    1.21 @@ -1554,6 +1558,8 @@
    1.22                      _il->ident->comm_type = PEP_ct_key_not_found;
    1.23                      _status = PEP_STATUS_OK;
    1.24                  }
    1.25 +                if (!has_pep_user)
    1.26 +                    is_pep_user(session, _il->ident, &has_pep_user);
    1.27              }
    1.28              else
    1.29                  _status = myself(session, _il->ident);
    1.30 @@ -1583,6 +1589,8 @@
    1.31                      _il->ident->comm_type = PEP_ct_key_not_found;
    1.32                      _status = PEP_STATUS_OK;
    1.33                  }
    1.34 +                if (!has_pep_user)
    1.35 +                    is_pep_user(session, _il->ident, &has_pep_user);
    1.36              }
    1.37              else
    1.38                  _status = myself(session, _il->ident);
    1.39 @@ -1612,7 +1620,7 @@
    1.40                  PEP_rating_undefined) < PEP_rating_reliable)
    1.41      {
    1.42          free_stringlist(keys);
    1.43 -        if (!session->passive_mode && 
    1.44 +        if ((has_pep_user || !session->passive_mode) && 
    1.45              !(flags & PEP_encrypt_flag_force_no_attached_key)) {
    1.46              attach_own_key(session, src);
    1.47              decorate_message(src, PEP_rating_undefined, NULL, true);
    1.48 @@ -1829,31 +1837,31 @@
    1.49      return ADD_TO_LOG(status);
    1.50  }
    1.51  
    1.52 -static PEP_STATUS _update_identity_for_incoming_message(
    1.53 -        PEP_SESSION session,
    1.54 -        const message *src
    1.55 -    )
    1.56 -{
    1.57 -    PEP_STATUS status;
    1.58 -
    1.59 -    if (src->from && src->from->address) {
    1.60 -        if (!is_me(session, src->from))
    1.61 -            status = update_identity(session, src->from);
    1.62 -        else
    1.63 -            status = myself(session, src->from);
    1.64 -        if (status == PEP_STATUS_OK
    1.65 -                && is_a_pEpmessage(src)
    1.66 -                && src->from->comm_type >= PEP_ct_OpenPGP_unconfirmed
    1.67 -                && src->from->comm_type != PEP_ct_pEp_unconfirmed
    1.68 -                && src->from->comm_type != PEP_ct_pEp)
    1.69 -        {
    1.70 -            src->from->comm_type |= PEP_ct_pEp_unconfirmed;
    1.71 -            status = set_identity(session, src->from);
    1.72 -        }
    1.73 -        return status;
    1.74 -    }
    1.75 -    return PEP_ILLEGAL_VALUE;
    1.76 -}
    1.77 +// static PEP_STATUS _update_identity_for_incoming_message(
    1.78 +//         PEP_SESSION session,
    1.79 +//         const message *src
    1.80 +//     )
    1.81 +// {
    1.82 +//     PEP_STATUS status;
    1.83 +// 
    1.84 +//     if (src->from && src->from->address) {
    1.85 +//         if (!is_me(session, src->from))
    1.86 +//             status = update_identity(session, src->from);
    1.87 +//         else
    1.88 +//             status = myself(session, src->from);
    1.89 +//         if (status == PEP_STATUS_OK
    1.90 +//                 && is_a_pEpmessage(src)
    1.91 +//                 && src->from->comm_type >= PEP_ct_OpenPGP_unconfirmed
    1.92 +//                 && src->from->comm_type != PEP_ct_pEp_unconfirmed
    1.93 +//                 && src->from->comm_type != PEP_ct_pEp)
    1.94 +//         {
    1.95 +//             src->from->comm_type |= PEP_ct_pEp_unconfirmed;
    1.96 +//             status = set_identity(session, src->from);
    1.97 +//         }
    1.98 +//         return status;
    1.99 +//     }
   1.100 +//     return PEP_ILLEGAL_VALUE;
   1.101 +// }
   1.102  
   1.103  
   1.104  static PEP_STATUS _get_detached_signature(message* msg, 
   1.105 @@ -2043,7 +2051,7 @@
   1.106          }
   1.107          else {
   1.108              pEp_identity *_sender = new_identity(sender->address, fpr,
   1.109 -                                               sender->user_id, sender->username);
   1.110 +                                                 sender->user_id, sender->username);
   1.111              if (_sender == NULL)
   1.112                  return PEP_OUT_OF_MEMORY;
   1.113  
   1.114 @@ -2432,6 +2440,58 @@
   1.115      return status;
   1.116  }
   1.117  
   1.118 +static PEP_STATUS update_sender_to_pep_trust(
   1.119 +        PEP_SESSION session, 
   1.120 +        pEp_identity* sender, 
   1.121 +        stringlist_t* keylist) 
   1.122 +{
   1.123 +    assert(session);
   1.124 +    assert(sender);
   1.125 +    assert(keylist && !EMPTYSTR(keylist->value));
   1.126 +    
   1.127 +    if (!session || !sender || !keylist || EMPTYSTR(keylist->value))
   1.128 +        return PEP_ILLEGAL_VALUE;
   1.129 +        
   1.130 +    free(sender->fpr);
   1.131 +    sender->fpr = NULL;
   1.132 +    
   1.133 +    PEP_STATUS status = 
   1.134 +            is_me(session, sender) ? myself(session, sender) : update_identity(session, sender);
   1.135 +    
   1.136 +    if (EMPTYSTR(sender->fpr) || strcmp(sender->fpr, keylist->value) != 0) {
   1.137 +        free(sender->fpr);
   1.138 +        sender->fpr = strdup(keylist->value);
   1.139 +        if (!sender->fpr)
   1.140 +            return PEP_OUT_OF_MEMORY;
   1.141 +        status = get_trust(session, sender);
   1.142 +        
   1.143 +        if (status == PEP_CANNOT_FIND_IDENTITY || sender->comm_type == PEP_ct_unknown) {
   1.144 +            PEP_comm_type ct = PEP_ct_unknown;
   1.145 +            status = get_key_rating(session, sender->fpr, &ct);
   1.146 +            if (status != PEP_STATUS_OK)
   1.147 +                return status;
   1.148 +                
   1.149 +            sender->comm_type = ct;    
   1.150 +        }
   1.151 +    }
   1.152 +    
   1.153 +    // Could be done elegantly, but we do this explicitly here for readability.
   1.154 +    // This file's code is difficult enough to parse. But change at will.
   1.155 +    switch (sender->comm_type) {
   1.156 +        case PEP_ct_OpenPGP_unconfirmed:
   1.157 +            status = set_trust(session, sender->user_id, sender->fpr, PEP_ct_pEp_unconfirmed);
   1.158 +            break;
   1.159 +        case PEP_ct_OpenPGP:
   1.160 +            status = set_trust(session, sender->user_id, sender->fpr, PEP_ct_pEp);
   1.161 +            break;
   1.162 +        default:
   1.163 +            break;
   1.164 +    }
   1.165 +    
   1.166 +    return status;
   1.167 +}
   1.168 +
   1.169 +
   1.170  DYNAMIC_API PEP_STATUS _decrypt_message(
   1.171          PEP_SESSION session,
   1.172          message *src,
   1.173 @@ -2462,36 +2522,58 @@
   1.174      char *ptext = NULL;
   1.175      size_t psize;
   1.176      stringlist_t *_keylist = NULL;
   1.177 +    char* signer_fpr = NULL;
   1.178 +    bool is_pep_msg = is_a_pEpmessage(src);
   1.179  
   1.180      *dst = NULL;
   1.181      *keylist = NULL;
   1.182      *rating = PEP_rating_undefined;
   1.183  
   1.184      *flags = 0;
   1.185 +    
   1.186      /*** End init ***/
   1.187  
   1.188 +    // Ok, before we do anything, if it's a pEp message, regardless of whether it's
   1.189 +    // encrypted or not, we set the sender as a pEp user. This has NOTHING to do
   1.190 +    // with the key.
   1.191 +    if (src->from && !(is_me(session, src->from))) {
   1.192 +        if (is_pep_msg) {
   1.193 +            pEp_identity* tmp_from = src->from;
   1.194 +            
   1.195 +            // Ensure there's a user id
   1.196 +            if (EMPTYSTR(tmp_from->user_id) && tmp_from->address) {
   1.197 +                status = update_identity(session, tmp_from);
   1.198 +                if (status == PEP_CANNOT_FIND_IDENTITY) {
   1.199 +                    tmp_from->user_id = calloc(1, strlen(tmp_from->address) + 6);
   1.200 +                    if (!tmp_from->user_id)
   1.201 +                        return PEP_OUT_OF_MEMORY;
   1.202 +                    snprintf(tmp_from->user_id, strlen(tmp_from->address) + 6,
   1.203 +                             "TOFU_%s", tmp_from->address);        
   1.204 +                    status = PEP_STATUS_OK;
   1.205 +                }
   1.206 +            }
   1.207 +            if (status == PEP_STATUS_OK) {
   1.208 +                // Now set user as PEP (may also create an identity if none existed yet)
   1.209 +                status = set_as_pep_user(session, tmp_from);
   1.210 +            }
   1.211 +        }
   1.212 +    }
   1.213 +    // We really need key used in signing to do anything further on the pEp comm_type.
   1.214 +    // So we can't adjust the rating of the sender just yet.
   1.215 +
   1.216      /*** Begin Import any attached public keys and update identities accordingly ***/
   1.217 -
   1.218      // Private key in unencrypted mail are ignored -> NULL
   1.219      bool imported_keys = import_attached_keys(session, src, NULL);
   1.220  
   1.221 -    // Update src->from in case we just imported a key
   1.222 -    // we would need to check signature
   1.223 -    status = _update_identity_for_incoming_message(session, src);
   1.224 -    
   1.225 -    if (status == PEP_ILLEGAL_VALUE && src->from && is_me(session, src->from)) {
   1.226 -        // the above function should fail if it's us.
   1.227 -        // We don't need to update, as any revocations or expirations
   1.228 -        // of our own key imported above, which are all that we 
   1.229 -        // would care about for anything imported,
   1.230 -        // SHOULD get caught when they matter later.
   1.231 -        // (Private keys imported above are not stored in the trust DB)
   1.232 -        status = PEP_STATUS_OK;
   1.233 -    }
   1.234 +    // FIXME: is this really necessary here?
   1.235 +    if (!is_me(session, src->from))
   1.236 +        status = update_identity(session, src->from);
   1.237 +    else
   1.238 +        status = myself(session, src->from);
   1.239          
   1.240      if (status != PEP_STATUS_OK)
   1.241          return ADD_TO_LOG(status);
   1.242 -
   1.243 +    
   1.244      /*** End Import any attached public keys and update identities accordingly ***/
   1.245      
   1.246      /*** Begin get detached signatures that are attached to the encrypted message ***/
   1.247 @@ -2525,7 +2607,7 @@
   1.248      status = get_crypto_text(src, &ctext, &csize);
   1.249      if (status != PEP_STATUS_OK)
   1.250          return status;
   1.251 -    
   1.252 +        
   1.253      /** Ok, we should be ready to decrypt. Try decrypt and verify first! **/
   1.254      status = cryptotech[crypto].decrypt_and_verify(session, ctext,
   1.255                                                     csize, dsig_text, dsig_size,
   1.256 @@ -2683,12 +2765,17 @@
   1.257          }
   1.258          
   1.259          *rating = decrypt_rating(decrypt_status);
   1.260 +        
   1.261 +        // Ok, so if it was signed and it's all verified, we can update
   1.262 +        // eligible signer comm_types to PEP_ct_pEp_*
   1.263 +        if (decrypt_status == PEP_DECRYPTED_AND_VERIFIED && is_pep_msg)
   1.264 +            status = update_sender_to_pep_trust(session, src->from, _keylist);
   1.265  
   1.266          /* Ok, now we have a keylist used for decryption/verification.
   1.267             now we need to update the message rating with the 
   1.268             sender and recipients in mind */
   1.269          status = amend_rating_according_to_sender_and_recipients(session,
   1.270 -                rating, src->from, _keylist);
   1.271 +                 rating, src->from, _keylist);
   1.272  
   1.273          if (status != PEP_STATUS_OK)
   1.274              GOTO(pep_error);
   1.275 @@ -2747,6 +2834,7 @@
   1.276  
   1.277  pep_error:
   1.278      free(ptext);
   1.279 +    free(signer_fpr);
   1.280      free_message(msg);
   1.281      free_stringlist(_keylist);
   1.282  
     2.1 --- a/src/pEpEngine.c	Sun Feb 04 03:38:28 2018 +0100
     2.2 +++ b/src/pEpEngine.c	Sun Feb 04 03:52:27 2018 +0100
     2.3 @@ -104,14 +104,26 @@
     2.4      "      where id = ?1), upper(replace(?4,' ','')))),"
     2.5      "    (select device_group from person where id = ?1)) ;";
     2.6  
     2.7 +static const char *sql_set_as_pep_user =
     2.8 +    "update person set is_pep_user = 1 "
     2.9 +    "   where id = ?1 ; ";
    2.10 +
    2.11 +static const char *sql_is_pep_user =
    2.12 +    "select is_pep_user from person "
    2.13 +    "   where id = ?1 ; ";
    2.14 +
    2.15 +static const char* sql_exists_person = 
    2.16 +    "select count(*) from person "
    2.17 +    "   where id = ?1 ;";
    2.18 +
    2.19  static const char *sql_set_device_group = 
    2.20      "update person set device_group = ?1 "
    2.21 -    "where id = ?2;";
    2.22 +    "   where id = ?2;";
    2.23  
    2.24  // This will cascade to identity and trust
    2.25  static const char* sql_replace_userid =
    2.26      "update person set id = ?1 " 
    2.27 -    "where id = ?2;";
    2.28 +    "   where id = ?2;";
    2.29  
    2.30  static const char *sql_replace_main_user_fpr =  
    2.31      "update person "
    2.32 @@ -526,7 +538,8 @@
    2.33                  "       on delete set null,\n"
    2.34                  "   lang text,\n"
    2.35                  "   comment text,\n"
    2.36 -                "   device_group text\n"
    2.37 +                "   device_group text,\n"
    2.38 +                "   is_pep_user integer default 0\n"
    2.39                  ");\n"
    2.40                  "create table if not exists identity (\n"
    2.41                  "   address text,\n"
    2.42 @@ -615,8 +628,11 @@
    2.43          // is really necessary...
    2.44          if (version == 1) {
    2.45              bool version_changed = true;
    2.46 -            
    2.47 -            if (table_contains_column(_session, "identity", "is_own") > 0) {
    2.48 +
    2.49 +            if (table_contains_column(_session, "person", "is_pep_user") > 0) {
    2.50 +                version = 7;
    2.51 +            }            
    2.52 +            else if (table_contains_column(_session, "identity", "is_own") > 0) {
    2.53                  version = 6;
    2.54              }
    2.55              else if (table_contains_column(_session, "sequences", "own") > 0) {
    2.56 @@ -795,6 +811,32 @@
    2.57              if (version < 7) {
    2.58                  int_result = sqlite3_exec(
    2.59                      _session->db,
    2.60 +                    "alter table person\n"
    2.61 +                    "   add column is_pep_user integer default 0;\n",
    2.62 +                    NULL,
    2.63 +                    NULL,
    2.64 +                    NULL
    2.65 +                );
    2.66 +                assert(int_result == SQLITE_OK);
    2.67 +                int_result = sqlite3_exec(
    2.68 +                    _session->db,
    2.69 +                    "update person\n"
    2.70 +                    "   set is_pep_user = 1\n"
    2.71 +                    "   where id = "
    2.72 +                    "       (select distinct id from person "
    2.73 +                    "               join trust on id = user_id "
    2.74 +                    "               where (case when (comm_type = 127) then (id) "
    2.75 +                    "                           when (comm_type = 255) then (id) "
    2.76 +                    "                           else 0"
    2.77 +                    "                      end) = id );\n",
    2.78 +                    NULL,
    2.79 +                    NULL,
    2.80 +                    NULL
    2.81 +                );
    2.82 +                assert(int_result == SQLITE_OK);
    2.83 +                
    2.84 +                int_result = sqlite3_exec(
    2.85 +                    _session->db,
    2.86                      "create table if not exists mistrusted_keys (\n"
    2.87                      "    fpr text primary key\n"
    2.88                      ");\n",            
    2.89 @@ -802,8 +844,9 @@
    2.90                      NULL,
    2.91                      NULL
    2.92                  );
    2.93 +                assert(int_result == SQLITE_OK);    
    2.94              }
    2.95 -        }
    2.96 +        }        
    2.97          else { 
    2.98              // Version from DB was 0, it means this is initial setup.
    2.99              // DB has just been created, and all tables are empty.
   2.100 @@ -896,6 +939,18 @@
   2.101              (int)strlen(sql_set_person), &_session->set_person, NULL);
   2.102      assert(int_result == SQLITE_OK);
   2.103  
   2.104 +    int_result = sqlite3_prepare_v2(_session->db, sql_set_as_pep_user,
   2.105 +            (int)strlen(sql_set_as_pep_user), &_session->set_as_pep_user, NULL);
   2.106 +    assert(int_result == SQLITE_OK);
   2.107 +    
   2.108 +    int_result = sqlite3_prepare_v2(_session->db, sql_is_pep_user,
   2.109 +            (int)strlen(sql_is_pep_user), &_session->is_pep_user, NULL);
   2.110 +    assert(int_result == SQLITE_OK);
   2.111 +
   2.112 +    int_result = sqlite3_prepare_v2(_session->db, sql_exists_person,
   2.113 +            (int)strlen(sql_exists_person), &_session->exists_person, NULL);
   2.114 +    assert(int_result == SQLITE_OK);
   2.115 +
   2.116      int_result = sqlite3_prepare_v2(_session->db, sql_set_device_group,
   2.117              (int)strlen(sql_set_device_group), &_session->set_device_group, NULL);
   2.118      assert(int_result == SQLITE_OK);
   2.119 @@ -1134,6 +1189,12 @@
   2.120                  sqlite3_finalize(session->remove_fpr_as_default);            
   2.121              if (session->set_person)
   2.122                  sqlite3_finalize(session->set_person);
   2.123 +            if (session->set_as_pep_user)
   2.124 +                sqlite3_finalize(session->set_as_pep_user);
   2.125 +            if (session->is_pep_user)
   2.126 +                sqlite3_finalize(session->is_pep_user);
   2.127 +            if (session->exists_person)
   2.128 +                sqlite3_finalize(session->exists_person);                        
   2.129              if (session->set_device_group)
   2.130                  sqlite3_finalize(session->set_device_group);
   2.131              if (session->get_device_group)
   2.132 @@ -1869,6 +1930,18 @@
   2.133          assert(identity->lang[2] == 0);
   2.134      }
   2.135  
   2.136 +    if (has_fpr) {
   2.137 +        sqlite3_reset(session->set_pgp_keypair);
   2.138 +        sqlite3_bind_text(session->set_pgp_keypair, 1, identity->fpr, -1,
   2.139 +                SQLITE_STATIC);
   2.140 +        result = sqlite3_step(session->set_pgp_keypair);
   2.141 +        sqlite3_reset(session->set_pgp_keypair);
   2.142 +        if (result != SQLITE_DONE) {
   2.143 +            sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
   2.144 +            return PEP_CANNOT_SET_PGP_KEYPAIR;
   2.145 +        }
   2.146 +    }
   2.147 +
   2.148      sqlite3_reset(session->set_person);
   2.149      sqlite3_bind_text(session->set_person, 1, identity->user_id, -1,
   2.150              SQLITE_STATIC);
   2.151 @@ -1888,18 +1961,6 @@
   2.152          return PEP_CANNOT_SET_PERSON;
   2.153      }
   2.154  
   2.155 -    if (has_fpr) {
   2.156 -        sqlite3_reset(session->set_pgp_keypair);
   2.157 -        sqlite3_bind_text(session->set_pgp_keypair, 1, identity->fpr, -1,
   2.158 -                SQLITE_STATIC);
   2.159 -        result = sqlite3_step(session->set_pgp_keypair);
   2.160 -        sqlite3_reset(session->set_pgp_keypair);
   2.161 -        if (result != SQLITE_DONE) {
   2.162 -            sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
   2.163 -            return PEP_CANNOT_SET_PGP_KEYPAIR;
   2.164 -        }
   2.165 -    }
   2.166 -
   2.167      sqlite3_reset(session->set_identity);
   2.168      sqlite3_bind_text(session->set_identity, 1, identity->address, -1,
   2.169              SQLITE_STATIC);
   2.170 @@ -1938,6 +1999,146 @@
   2.171          return PEP_COMMIT_FAILED;
   2.172  }
   2.173  
   2.174 +// This ONLY sets the user flag, and creates a shell identity if necessary.
   2.175 +PEP_STATUS set_as_pep_user(PEP_SESSION session, pEp_identity* user) {
   2.176 +
   2.177 +    assert(session);
   2.178 +    assert(user);
   2.179 +    assert(user->address);
   2.180 +    assert(!EMPTYSTR(user->user_id));
   2.181 +    
   2.182 +    char* user_id = user->user_id;
   2.183 +    
   2.184 +    if (!session || !user || user->address || EMPTYSTR(user_id))
   2.185 +        return PEP_ILLEGAL_VALUE;
   2.186 +            
   2.187 +    PEP_STATUS status = PEP_STATUS_OK;
   2.188 +    
   2.189 +    char* alias_default = NULL;
   2.190 +    
   2.191 +    bool person_exists = false;
   2.192 +    
   2.193 +    status = exists_person(session, user_id, &alias_default, &person_exists);
   2.194 +    
   2.195 +    if (status != PEP_STATUS_OK)
   2.196 +        return status;
   2.197 +        
   2.198 +    if (!person_exists) {
   2.199 +        if (!user->address)
   2.200 +            return PEP_ILLEGAL_VALUE;
   2.201 +            
   2.202 +        // create shell identity
   2.203 +        pEp_identity* tmp_id = new_identity(user->address, NULL, user->user_id, user->username);
   2.204 +        status = set_identity(session, tmp_id); // this creates the person
   2.205 +        free_identity(tmp_id);
   2.206 +        if (status != PEP_STATUS_OK)
   2.207 +            return status;
   2.208 +        alias_default = strdup(user->user_id);
   2.209 +    }
   2.210 +        
   2.211 +    // Ok, let's set it.
   2.212 +    sqlite3_reset(session->set_as_pep_user);
   2.213 +    sqlite3_bind_text(session->set_as_pep_user, 1, alias_default, -1,
   2.214 +            SQLITE_STATIC);
   2.215 +    int result = sqlite3_step(session->set_as_pep_user);
   2.216 +    sqlite3_reset(session->set_as_pep_user);
   2.217 +    
   2.218 +    if (result != SQLITE_DONE)
   2.219 +        return PEP_CANNOT_SET_PERSON;
   2.220 +        
   2.221 +    return PEP_STATUS_OK;    
   2.222 +}
   2.223 +
   2.224 +PEP_STATUS exists_person(PEP_SESSION session, const char* user_id,
   2.225 +                         char** default_id, bool* exists) {
   2.226 +    assert(session);
   2.227 +    assert(exists);
   2.228 +    assert(!EMPTYSTR(user_id));
   2.229 +        
   2.230 +    if (!session || !exists || EMPTYSTR(user_id))
   2.231 +        return PEP_ILLEGAL_VALUE;
   2.232 +    
   2.233 +    *exists = false;
   2.234 +    
   2.235 +    char* alias_default = NULL;
   2.236 +    
   2.237 +    PEP_STATUS status = get_userid_alias_default(session, user_id, &alias_default);
   2.238 +    
   2.239 +    if (status == PEP_CANNOT_FIND_ALIAS || EMPTYSTR(alias_default)) {
   2.240 +        free(alias_default);
   2.241 +        alias_default = NULL;
   2.242 +        sqlite3_reset(session->exists_person);
   2.243 +        sqlite3_bind_text(session->exists_person, 1, user_id, -1,
   2.244 +                SQLITE_STATIC);
   2.245 +        int result = sqlite3_step(session->exists_person);
   2.246 +        switch (result) {
   2.247 +            case SQLITE_ROW: {
   2.248 +                // yeah yeah, I know, we could be lazy here, but it looks bad.
   2.249 +                *exists = (sqlite3_column_int(session->exists_person, 0) != 0);
   2.250 +                break;
   2.251 +            }
   2.252 +            default:
   2.253 +                return PEP_UNKNOWN_ERROR;
   2.254 +        }
   2.255 +        if (*exists)
   2.256 +            alias_default = strdup(user_id);
   2.257 +    }
   2.258 +    else
   2.259 +        *exists = true; // thank you, delete on cascade!
   2.260 +
   2.261 +    if (!default_id)
   2.262 +        free(alias_default);
   2.263 +    else    
   2.264 +        *default_id = alias_default;
   2.265 +    
   2.266 +    return PEP_STATUS_OK;
   2.267 +}
   2.268 +
   2.269 +PEP_STATUS is_pep_user(PEP_SESSION session, pEp_identity *identity, bool* is_pep)
   2.270 +{
   2.271 +    assert(session);
   2.272 +    assert(is_pep);
   2.273 +    assert(identity);
   2.274 +    assert(!EMPTYSTR(identity->user_id));
   2.275 +
   2.276 +    if (!session || !is_pep || !identity || EMPTYSTR(identity->user_id))
   2.277 +        return PEP_ILLEGAL_VALUE;
   2.278 +    
   2.279 +    *is_pep = false;
   2.280 +    
   2.281 +    const char* user_id = identity->user_id;
   2.282 +    
   2.283 +    if (!session || EMPTYSTR(user_id))
   2.284 +        return PEP_ILLEGAL_VALUE;
   2.285 +        
   2.286 +    char* alias_default = NULL;
   2.287 +    
   2.288 +    PEP_STATUS status = get_userid_alias_default(session, user_id, &alias_default);
   2.289 +    
   2.290 +    if (status == PEP_CANNOT_FIND_ALIAS || EMPTYSTR(alias_default)) {
   2.291 +        free(alias_default);
   2.292 +        alias_default = strdup(user_id);
   2.293 +    }
   2.294 +    
   2.295 +    sqlite3_reset(session->is_pep_user);
   2.296 +    sqlite3_bind_text(session->is_pep_user, 1, user_id, -1,
   2.297 +            SQLITE_STATIC);
   2.298 +    int result = sqlite3_step(session->is_pep_user);
   2.299 +    switch (result) {
   2.300 +        case SQLITE_ROW: {
   2.301 +            // yeah yeah, I know, we could be lazy here, but it looks bad.
   2.302 +            *is_pep = (sqlite3_column_int(session->is_pep_user, 0) != 0);
   2.303 +            break;
   2.304 +        }
   2.305 +        default:
   2.306 +            free(alias_default);
   2.307 +            return PEP_CANNOT_FIND_PERSON;
   2.308 +    }
   2.309 +
   2.310 +    return PEP_STATUS_OK;
   2.311 +}
   2.312 +
   2.313 +
   2.314  PEP_STATUS remove_fpr_as_default(PEP_SESSION session, 
   2.315                                   const char* fpr) 
   2.316  {
     3.1 --- a/src/pEpEngine.h	Sun Feb 04 03:38:28 2018 +0100
     3.2 +++ b/src/pEpEngine.h	Sun Feb 04 03:52:27 2018 +0100
     3.3 @@ -1231,6 +1231,21 @@
     3.4  
     3.5  PEP_STATUS import_trusted_own_keys(PEP_SESSION session);
     3.6  
     3.7 +// This ONLY sets the *user* flag, and creates a shell identity if necessary.
     3.8 +PEP_STATUS set_as_pep_user(PEP_SESSION session, pEp_identity* user);
     3.9 +
    3.10 +// returns true (by reference) if a person with this user_id exists; if default_id != NULL,
    3.11 +// function will also return by reference a copy of the default id which
    3.12 +// is this user_id is aliased to (which will usually, but not always, 
    3.13 +// string equivalent to the user_id)
    3.14 +PEP_STATUS exists_person(PEP_SESSION session, const char* user_id,
    3.15 +                         char** default_id, bool* exists);
    3.16 +
    3.17 +// returns true if the USER corresponding to this identity has been listed in
    3.18 +// the *person* table as a pEp user. This *does not check comm_type*                         
    3.19 +PEP_STATUS is_pep_user(PEP_SESSION session, pEp_identity *identity, bool* is_pep);
    3.20 +
    3.21 +
    3.22  #ifdef __cplusplus
    3.23  }
    3.24  #endif
     4.1 --- a/src/pEp_internal.h	Sun Feb 04 03:38:28 2018 +0100
     4.2 +++ b/src/pEp_internal.h	Sun Feb 04 03:52:27 2018 +0100
     4.3 @@ -131,6 +131,9 @@
     4.4      sqlite3_stmt *refresh_userid_default_key;
     4.5      sqlite3_stmt *remove_fpr_as_default;
     4.6      sqlite3_stmt *set_person;
     4.7 +    sqlite3_stmt *set_as_pep_user;
     4.8 +    sqlite3_stmt *is_pep_user;
     4.9 +    sqlite3_stmt *exists_person;
    4.10      sqlite3_stmt *set_device_group;
    4.11      sqlite3_stmt *get_device_group;
    4.12      sqlite3_stmt *set_pgp_keypair;
     5.1 --- a/test/pEpEngineTest.cc	Sun Feb 04 03:38:28 2018 +0100
     5.2 +++ b/test/pEpEngineTest.cc	Sun Feb 04 03:52:27 2018 +0100
     5.3 @@ -32,7 +32,7 @@
     5.4          return sstr.str();
     5.5  }
     5.6  
     5.7 -// no C++11, yet? So do our own implementation:
     5.8 +// no C++11, yet? So do our own implementation:1G
     5.9  namespace{
    5.10      std::string to_string(unsigned long u)
    5.11      {
    5.12 @@ -270,6 +270,7 @@
    5.13  
    5.14      cout << "\nsetting identity...\n";
    5.15      PEP_STATUS pep_set_result = set_identity(session, identity);
    5.16 +    cout << pep_set_result << endl;
    5.17      assert(pep_set_result == PEP_STATUS_OK);
    5.18      free_identity(identity);
    5.19      get_identity(session, "leon.schumacher@digitalekho.com", "23", &identity);