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