src/pEpEngine.c
branchgroup_key_reset
changeset 4286 471cebdff1c6
parent 4284 11da23e0fe0c
     1.1 --- a/src/pEpEngine.c	Sun Dec 15 21:21:19 2019 +0100
     1.2 +++ b/src/pEpEngine.c	Tue Dec 17 02:51:30 2019 +0100
     1.3 @@ -469,18 +469,26 @@
     1.4  // Revocation tracking
     1.5  static const char *sql_set_revoked =
     1.6      "insert or replace into revoked_keys ("
     1.7 -    "    revoked_fpr, replacement_fpr, revocation_date) "
     1.8 +    "    revoked_fpr, own_address, replacement_fpr, revocation_date) "
     1.9      "values (upper(replace(?1,' ','')),"
    1.10 -    "        upper(replace(?2,' ','')),"
    1.11 -    "        ?3) ;";
    1.12 -        
    1.13 +    "        ?2, "
    1.14 +    "        upper(replace(?3,' ','')),"
    1.15 +    "        ?4) ;";
    1.16 +
    1.17 +// FIXME: If we ever have more than one revoked fpr per replacement fpr, this 
    1.18 +// must change                
    1.19  static const char *sql_get_revoked = 
    1.20 -    "select revoked_fpr, revocation_date from revoked_keys"
    1.21 +    "select revoked_fpr, own_address, revocation_date from revoked_keys"
    1.22      "    where replacement_fpr = upper(replace(?1,' ','')) ;";
    1.23  
    1.24  static const char *sql_get_replacement_fpr = 
    1.25      "select replacement_fpr, revocation_date from revoked_keys"
    1.26 -    "    where revoked_fpr = upper(replace(?1,' ','')) ;";
    1.27 +    "    where revoked_fpr = upper(replace(?1,' ','')) "
    1.28 +    "        and own_address = ?2;";
    1.29 +
    1.30 +// static const char *sql_get_replacement_fprs = 
    1.31 +//     "select replacement_fpr, own_address, revocation_date from revoked_keys"
    1.32 +//     "    where revoked_fpr = upper(replace(?1,' ','')) ;";
    1.33  
    1.34  static const char *sql_get_userid_alias_default =
    1.35      "select default_id from alternate_user_id "
    1.36 @@ -630,6 +638,171 @@
    1.37      return retval;
    1.38  }
    1.39  
    1.40 +// To be used until we hit a steady state
    1.41 +static PEP_STATUS propagate_revocation_addresses(PEP_SESSION session) {
    1.42 +    PEP_STATUS status = PEP_STATUS_OK;
    1.43 +        
    1.44 +    // Apparently sqlite won't let you use this as part of the update 
    1.45 +    // statement? Which is fine, because honestly. too much. I'm 
    1.46 +    // a doctor, Jim, not a database analyst! XD
    1.47 +    const char* sql_query = 
    1.48 +        "SELECT T_NULL.revoked_fpr, T_ADDR.own_address "
    1.49 +        "    FROM (SELECT revoked_fpr, replacement_fpr FROM revoked_keys where own_address is NULL) as T_NULL "
    1.50 +        "    JOIN (SELECT revoked_fpr, own_address FROM revoked_keys where 1) as T_ADDR "            
    1.51 +        "    ON T_ADDR.revoked_fpr = T_NULL.replacement_fpr; ";
    1.52 +
    1.53 +    sqlite3_stmt *query_stmt; 
    1.54 +    sqlite3_prepare_v2(session->db, sql_query, -1, &query_stmt, NULL);
    1.55 +    sql_query = 
    1.56 +        "UPDATE revoked_keys SET own_address = ?1 WHERE revoked_fpr = ?2; ";
    1.57 +    sqlite3_stmt *update_stmt; 
    1.58 +    sqlite3_prepare_v2(session->db, sql_query, -1, &update_stmt, NULL);
    1.59 +
    1.60 +    bool changed = true;
    1.61 +    int result;
    1.62 +    
    1.63 +    while (changed) {
    1.64 +        stringpair_t* update_list = NULL;
    1.65 +        changed = false;
    1.66 +        do {
    1.67 +            result = sqlite3_step(query_stmt);
    1.68 +            switch (result) {
    1.69 +                case SQLITE_ROW:
    1.70 +                    const char* revfpr = sqlite3_column_text(query_stmt, 0);
    1.71 +                    const char* addr = sqlite3_column_text(query_stmt, 1);
    1.72 +                    if (revfpr && addr && *revfpr != '\0' && *attr != '\0') {
    1.73 +                        if (!update_list)
    1.74 +                            update_list = new stringpair_list(strdup(revfpr), strdup(addr));
    1.75 +                        else
    1.76 +                            stringpair_list_add(update_list, strdup(revfpr), strdup(addr));
    1.77 +                        changed = true;    
    1.78 +                    }
    1.79 +                    break;
    1.80 +                case SQLITE_DONE:
    1.81 +                    // done changing
    1.82 +                    break;
    1.83 +                default:
    1.84 +                    free_stringlist(update_list);
    1.85 +                    update_list = NULL;
    1.86 +                    status = PEP_UNKNOWN_DB_ERROR;
    1.87 +                    result = SQLITE_DONE;    
    1.88 +            }
    1.89 +        } while (result != SQLITE_DONE);
    1.90 +        sqlite3_reset(query_stmt);
    1.91 +        
    1.92 +        // Update all the stuff we've got
    1.93 +        if (!update_list)
    1.94 +            break;
    1.95 +        
    1.96 +        stringpair_list_t* curr_rev = update_list;
    1.97 +        for ( ; update_list && update_list->key && update_list->value; 
    1.98 +              update_list = update_list->next) {
    1.99 +            sqlite3_bind_text(update_stmt, 1, update_list->value, -1,
   1.100 +                                      SQLITE_STATIC);
   1.101 +            sqlite3_bind_text(update_stmt, 2, update_list->key, -1,
   1.102 +                                      SQLITE_STATIC);
   1.103 +            
   1.104 +            result = sqlite3_step(update_stmt);
   1.105 +            if (result != SQLITE_DONE)
   1.106 +                break; // FIXME
   1.107 +            
   1.108 +            sqlite3_reset(update_stmt);        
   1.109 +        }           
   1.110 +        // Ok, if nothing changed this time, we're done
   1.111 +    }
   1.112 +    sqlite3_finalize(query_stmt);
   1.113 +    sqlite3_finalize(update_stmt);
   1.114 +    return status;
   1.115 +}
   1.116 +
   1.117 +static PEP_STATUS modify_pre_v_13_revoked_key_db(PEP_SESSION session) {
   1.118 +    // I HATE SQLITE.
   1.119 +    
   1.120 +    PEP_STATUS status = PEP_STATUS_OK;
   1.121 +    int int_result = 0;
   1.122 +
   1.123 +    // Ok, first we ADD the column so we can USE it.
   1.124 +    int_result = sqlite3_exec(
   1.125 +        _session->db,
   1.126 +        "alter table revoked_keys\n"
   1.127 +        "   add column own_address text;\n",
   1.128 +        NULL,
   1.129 +        NULL,
   1.130 +        NULL
   1.131 +    );
   1.132 +    assert(int_result == SQLITE_OK);
   1.133 +            
   1.134 +    identity_list* id_list = NULL;
   1.135 +    status = own_identities_retrieve(session, &id_list);
   1.136 +
   1.137 +    if (!status || !id_list)
   1.138 +        return PEP_STATUS_OK; // it's empty AFAIK (FIXME)
   1.139 +    
   1.140 +    // the best we can do here is look at current keys and follow the 
   1.141 +    // chains back.    
   1.142 +    sqlite3_stmt* update_revoked_w_addr_stmt = NULL;
   1.143 +    const char* sql_query = "update revoked_keys set own_address = ?1 where replacement_fpr = ?2;";
   1.144 +    sqlite3_prepare_v2(session->db, sql_query, -1, &update_revoked_w_addr_stmt, NULL);
   1.145 +                                    
   1.146 +    pEp_identity* curr_own = NULL;
   1.147 +        
   1.148 +    // Because before DDL v. 13 there was only one mapping of fpr to 
   1.149 +    // revocation, we can do this    
   1.150 +    for (curr_own = id_list; curr_own && curr_own->ident; curr_own = curr_own->next) {            
   1.151 +        const char* curr_fpr = curr_own->ident->fpr;
   1.152 +        if (!curr_fpr)
   1.153 +            continue;
   1.154 +
   1.155 +        sqlite3_bind_text(update_revoked_w_addr_stmt, 1, curr_own->ident->address, -1,
   1.156 +                          SQLITE_STATIC);
   1.157 +        sqlite3_bind_text(update_revoked_w_addr_stmt, 2, curr_fpr, -1,
   1.158 +                          SQLITE_STATIC);
   1.159 +                
   1.160 +        int_result = sqlite3_step(stmt);
   1.161 +        assert(int_result == SQLITE_DONE);                  
   1.162 +        sqlite3_reset(stmt);                      
   1.163 +    }
   1.164 +    
   1.165 +    status = propagate_revocation_addresses(PEP_SESSION session);
   1.166 +    
   1.167 +    int_result = sqlite3_exec(
   1.168 +        _session->db,
   1.169 +        "PRAGMA foreign_keys=off;\n"
   1.170 +        "BEGIN TRANSACTION;\n"
   1.171 +        "create table if not exists _revoked_keys_new (\n"
   1.172 +        "   revoked_fpr text not null,\n"
   1.173 +        "   own_address text default 'UNKNOWN',"
   1.174 +        "   replacement_fpr text not null\n"
   1.175 +        "       references pgp_keypair (fpr)\n"
   1.176 +        "       on delete cascade,\n"
   1.177 +        "   revocation_date integer\n"
   1.178 +        "   primary key (revoked_fpr, own_address)\n"                
   1.179 +        ");\n"
   1.180 +        "INSERT INTO _revoked_keys_new (revoked_fpr, "
   1.181 +        "                               own_address, "
   1.182 +        "                               replacement_fpr, "
   1.183 +        "                               revocation_date) "
   1.184 +        "   SELECT revoked_keys.revoked_fpr, "
   1.185 +        "          revoked_keys.own_address, "
   1.186 +        "          revoked_keys.replacement_fpr, "
   1.187 +        "          revoked_keys.revocation_date "
   1.188 +        "   FROM revoked_keys "
   1.189 +        "   WHERE 1;\n"
   1.190 +        "DROP TABLE revoked_keys;\n"
   1.191 +        "ALTER TABLE _revoked_keys_new RENAME TO revoked_keys;\n"
   1.192 +        "COMMIT;\n"
   1.193 +        "\n"
   1.194 +        "PRAGMA foreign_keys=on;\n"
   1.195 +        ,
   1.196 +        NULL,
   1.197 +        NULL,
   1.198 +        NULL
   1.199 +    );
   1.200 +    assert(int_result == SQLITE_OK);    
   1.201 +    
   1.202 +    return status;
   1.203 +}
   1.204 +
   1.205  PEP_STATUS repair_altered_tables(PEP_SESSION session) {
   1.206      PEP_STATUS status = PEP_STATUS_OK;
   1.207      
   1.208 @@ -940,7 +1113,7 @@
   1.209      sqlite3_busy_timeout(_session->system_db, 1000);
   1.210  
   1.211  // increment this when patching DDL
   1.212 -#define _DDL_USER_VERSION "12"
   1.213 +#define _DDL_USER_VERSION "13"
   1.214  
   1.215      if (in_first) {
   1.216  
   1.217 @@ -1028,11 +1201,13 @@
   1.218                  "   value integer default 0\n"
   1.219                  ");\n"
   1.220                  "create table if not exists revoked_keys (\n"
   1.221 -                "   revoked_fpr text primary key,\n"
   1.222 +                "   revoked_fpr text,\n"
   1.223 +                "   own_address text,"
   1.224                  "   replacement_fpr text not null\n"
   1.225                  "       references pgp_keypair (fpr)\n"
   1.226                  "       on delete cascade,\n"
   1.227                  "   revocation_date integer\n"
   1.228 +                "   primary key (revoked_fpr, own_address)\n"                
   1.229                  ");\n"
   1.230                  // user id aliases
   1.231                  "create table if not exists alternate_user_id (\n"
   1.232 @@ -1109,7 +1284,10 @@
   1.233          // Sometimes the user_version wasn't set correctly. 
   1.234          if (version == 1) {
   1.235              bool version_changed = true;
   1.236 -            if (table_contains_column(_session, "identity", "pEp_version_major")) {
   1.237 +            if (table_contains_column(_session, "revoked_keys", "own_address")) {
   1.238 +                version = 13;
   1.239 +            }            
   1.240 +            else if (table_contains_column(_session, "identity", "pEp_version_major")) {
   1.241                  version = 12;
   1.242              }
   1.243              else if (db_contains_table(_session, "social_graph") > 0) {
   1.244 @@ -1159,6 +1337,10 @@
   1.245  
   1.246  
   1.247          if(version != 0) { 
   1.248 +            if (version > atoi(_DDL_USER_VERSION)) {
   1.249 +                status = PEP_INIT_DB_DOWNGRADE_NOT_POSSIBLE;
   1.250 +                goto pEp_error;
   1.251 +            }    
   1.252              // Version has been already set
   1.253  
   1.254              // Early mistake : version 0 shouldn't have existed.
   1.255 @@ -1561,6 +1743,10 @@
   1.256                  if (status != PEP_STATUS_OK)
   1.257                      return status;                      
   1.258              }
   1.259 +            if (version < 13) {
   1.260 +                status = modify_pre_v_13_revoked_key_db(session);
   1.261 +            }
   1.262 +            
   1.263          }        
   1.264          else { 
   1.265              // Version from DB was 0, it means this is initial setup.
   1.266 @@ -2646,6 +2832,110 @@
   1.267      return status;
   1.268  }
   1.269  
   1.270 +PEP_STATUS _own_identities_retrieve(
   1.271 +        PEP_SESSION session,
   1.272 +        identity_list **own_identities,
   1.273 +        identity_flags_t excluded_flags
   1.274 +      )
   1.275 +{
   1.276 +    PEP_STATUS status = PEP_STATUS_OK;
   1.277 +    
   1.278 +    assert(session && own_identities);
   1.279 +    if (!(session && own_identities))
   1.280 +        return PEP_ILLEGAL_VALUE;
   1.281 +    
   1.282 +    *own_identities = NULL;
   1.283 +    identity_list *_own_identities = new_identity_list(NULL);
   1.284 +    if (_own_identities == NULL)
   1.285 +        goto enomem;
   1.286 +    
   1.287 +    sqlite3_reset(session->own_identities_retrieve);
   1.288 +    
   1.289 +    int result;
   1.290 +    // address, fpr, username, user_id, comm_type, lang, flags
   1.291 +    const char *address = NULL;
   1.292 +    const char *fpr = NULL;
   1.293 +    const char *username = NULL;
   1.294 +    const char *user_id = NULL;
   1.295 +    PEP_comm_type comm_type = PEP_ct_unknown;
   1.296 +    const char *lang = NULL;
   1.297 +    unsigned int flags = 0;
   1.298 +    
   1.299 +    identity_list *_bl = _own_identities;
   1.300 +
   1.301 +    sqlite3_bind_int(session->own_identities_retrieve, 1, excluded_flags);
   1.302 +
   1.303 +    do {
   1.304 +        result = sqlite3_step(session->own_identities_retrieve);
   1.305 +        switch (result) {
   1.306 +            case SQLITE_ROW:
   1.307 +                address = (const char *)
   1.308 +                    sqlite3_column_text(session->own_identities_retrieve, 0);
   1.309 +                fpr = (const char *)
   1.310 +                    sqlite3_column_text(session->own_identities_retrieve, 1);
   1.311 +                user_id = (const char *)
   1.312 +                    sqlite3_column_text(session->own_identities_retrieve, 2);
   1.313 +                username = (const char *)
   1.314 +                    sqlite3_column_text(session->own_identities_retrieve, 3);
   1.315 +                comm_type = PEP_ct_pEp;
   1.316 +                lang = (const char *)
   1.317 +                    sqlite3_column_text(session->own_identities_retrieve, 4);
   1.318 +                flags = (unsigned int)
   1.319 +                    sqlite3_column_int(session->own_identities_retrieve, 5);
   1.320 +
   1.321 +                pEp_identity *ident = new_identity(address, fpr, user_id, username);
   1.322 +                if (!ident)
   1.323 +                    goto enomem;
   1.324 +                ident->comm_type = comm_type;
   1.325 +                if (lang && lang[0]) {
   1.326 +                    ident->lang[0] = lang[0];
   1.327 +                    ident->lang[1] = lang[1];
   1.328 +                    ident->lang[2] = 0;
   1.329 +                }
   1.330 +                ident->me = true;
   1.331 +                ident->flags = flags;
   1.332 +
   1.333 +                _bl = identity_list_add(_bl, ident);
   1.334 +                if (_bl == NULL) {
   1.335 +                    free_identity(ident);
   1.336 +                    goto enomem;
   1.337 +                }
   1.338 +                
   1.339 +                break;
   1.340 +                
   1.341 +            case SQLITE_DONE:
   1.342 +                break;
   1.343 +                
   1.344 +            default:
   1.345 +                status = PEP_UNKNOWN_ERROR;
   1.346 +                result = SQLITE_DONE;
   1.347 +        }
   1.348 +    } while (result != SQLITE_DONE);
   1.349 +    
   1.350 +    sqlite3_reset(session->own_identities_retrieve);
   1.351 +    if (status == PEP_STATUS_OK)
   1.352 +        *own_identities = _own_identities;
   1.353 +    else
   1.354 +        free_identity_list(_own_identities);
   1.355 +    
   1.356 +    goto the_end;
   1.357 +    
   1.358 +enomem:
   1.359 +    free_identity_list(_own_identities);
   1.360 +    status = PEP_OUT_OF_MEMORY;
   1.361 +    
   1.362 +the_end:
   1.363 +    return status;
   1.364 +}
   1.365 +
   1.366 +DYNAMIC_API PEP_STATUS own_identities_retrieve(
   1.367 +        PEP_SESSION session,
   1.368 +        identity_list **own_identities
   1.369 +      )
   1.370 +{
   1.371 +    return _own_identities_retrieve(session, own_identities, 0);
   1.372 +}
   1.373 +
   1.374  PEP_STATUS get_identities_by_userid(
   1.375          PEP_SESSION session,
   1.376          const char *user_id,
   1.377 @@ -5118,6 +5408,7 @@
   1.378  
   1.379  DYNAMIC_API PEP_STATUS set_revoked(
   1.380         PEP_SESSION session,
   1.381 +       const char *own_address,
   1.382         const char *revoked_fpr,
   1.383         const char *replacement_fpr,
   1.384         const uint64_t revocation_date
   1.385 @@ -5127,20 +5418,24 @@
   1.386      
   1.387      assert(session &&
   1.388             revoked_fpr && revoked_fpr[0] &&
   1.389 -           replacement_fpr && replacement_fpr[0]
   1.390 +           replacement_fpr && replacement_fpr[0] &&
   1.391 +           own_address && own_address[0]
   1.392            );
   1.393      
   1.394      if (!(session &&
   1.395            revoked_fpr && revoked_fpr[0] &&
   1.396 -          replacement_fpr && replacement_fpr[0]
   1.397 +          replacement_fpr && replacement_fpr[0] &&
   1.398 +          own_address && own_address[0] 
   1.399           ))
   1.400          return PEP_ILLEGAL_VALUE;
   1.401      
   1.402      sqlite3_reset(session->set_revoked);
   1.403      sqlite3_bind_text(session->set_revoked, 1, revoked_fpr, -1, SQLITE_STATIC);
   1.404 -    sqlite3_bind_text(session->set_revoked, 2, replacement_fpr, -1,
   1.405 +    sqlite3_bind_text(session->set_revoked, 2, own_address, -1,
   1.406 +            SQLITE_STATIC);    
   1.407 +    sqlite3_bind_text(session->set_revoked, 3, replacement_fpr, -1,
   1.408              SQLITE_STATIC);
   1.409 -    sqlite3_bind_int64(session->set_revoked, 3, revocation_date);
   1.410 +    sqlite3_bind_int64(session->set_revoked, 4, revocation_date);
   1.411  
   1.412      int result;
   1.413      
   1.414 @@ -5162,6 +5457,7 @@
   1.415          PEP_SESSION session,
   1.416          const char *fpr,
   1.417          char **revoked_fpr,
   1.418 +        char **own_address,        
   1.419          uint64_t *revocation_date
   1.420      )
   1.421  {
   1.422 @@ -5169,11 +5465,13 @@
   1.423  
   1.424      assert(session &&
   1.425             revoked_fpr &&
   1.426 +           own_address &&
   1.427             fpr && fpr[0]
   1.428            );
   1.429      
   1.430      if (!(session &&
   1.431             revoked_fpr &&
   1.432 +           own_address &&           
   1.433             fpr && fpr[0]
   1.434            ))
   1.435          return PEP_ILLEGAL_VALUE;
   1.436 @@ -5191,9 +5489,11 @@
   1.437          case SQLITE_ROW: {
   1.438              *revoked_fpr = strdup((const char *)
   1.439                      sqlite3_column_text(session->get_revoked, 0));
   1.440 +            *own_address = strdup((const char *)
   1.441 +                    sqlite3_column_text(session->get_revoked, 1));                    
   1.442              if(*revoked_fpr)
   1.443                  *revocation_date = sqlite3_column_int64(session->get_revoked,
   1.444 -                        1);
   1.445 +                        2);
   1.446              else
   1.447                  status = PEP_OUT_OF_MEMORY;
   1.448  
   1.449 @@ -5210,32 +5510,35 @@
   1.450  
   1.451  DYNAMIC_API PEP_STATUS get_replacement_fpr(
   1.452          PEP_SESSION session,
   1.453 -        const char *fpr,
   1.454 -        char **revoked_fpr,
   1.455 +        const char *revoked_fpr,
   1.456 +        const char *address,
   1.457 +        char **replacement_fpr,
   1.458          uint64_t *revocation_date
   1.459      )
   1.460  {
   1.461      PEP_STATUS status = PEP_STATUS_OK;
   1.462  
   1.463 -    assert(session && revoked_fpr && !EMPTYSTR(fpr) && revocation_date);
   1.464 -    
   1.465 -    if (!session || !revoked_fpr || EMPTYSTR(fpr) || !revocation_date)
   1.466 +    assert(session && replacement_fpr && !EMPTYSTR(revoked_fpr) && revocation_date);
   1.467 +    assert(!EMPTYSTR(address));
   1.468 +    
   1.469 +    if (!session || !replacement_fpr || EMPTYSTR(revoked_fpr) || EMPTYSTR(address) || !revocation_date)
   1.470          return PEP_ILLEGAL_VALUE;
   1.471  
   1.472 -    *revoked_fpr = NULL;
   1.473 +    *replacement_fpr = NULL;
   1.474      *revocation_date = 0;
   1.475  
   1.476      sqlite3_reset(session->get_replacement_fpr);
   1.477 -    sqlite3_bind_text(session->get_replacement_fpr, 1, fpr, -1, SQLITE_STATIC);
   1.478 +    sqlite3_bind_text(session->get_replacement_fpr, 1, revoked_fpr, -1, SQLITE_STATIC);
   1.479 +    sqlite3_bind_text(session->get_replacement_fpr, 2, address, -1, SQLITE_STATIC);
   1.480  
   1.481      int result;
   1.482      
   1.483      result = sqlite3_step(session->get_replacement_fpr);
   1.484      switch (result) {
   1.485          case SQLITE_ROW: {
   1.486 -            *revoked_fpr = strdup((const char *)
   1.487 +            *replacement_fpr = strdup((const char *)
   1.488                      sqlite3_column_text(session->get_replacement_fpr, 0));
   1.489 -            if(*revoked_fpr)
   1.490 +            if(*replacement_fpr)
   1.491                  *revocation_date = sqlite3_column_int64(session->get_replacement_fpr,
   1.492                          1);
   1.493              else
   1.494 @@ -5252,6 +5555,70 @@
   1.495      return status;
   1.496  }
   1.497  
   1.498 +
   1.499 +DYNAMIC_API PEP_STATUS get_replacement_fprs(
   1.500 +        PEP_SESSION session,
   1.501 +        const char *revoked_fpr,
   1.502 +        revocation_info_list_t** replacement_fprs_info
   1.503 +    )
   1.504 +{
   1.505 +    PEP_STATUS status = PEP_STATUS_OK;
   1.506 +
   1.507 +    assert(session && replacement_fpr && !EMPTYSTR(revoked_fpr) && revocation_date);
   1.508 +    assert(repl_fpr_for_addr);
   1.509 +    
   1.510 +    if (!session || !replacement_fpr || EMPTYSTR(revoked_fpr) || !repl_fpr_for_addr || !revocation_date)
   1.511 +        return PEP_ILLEGAL_VALUE;
   1.512 +
   1.513 +
   1.514 +    *replacement_fprs_info = new_revocation_info_list(NULL);
   1.515 +    
   1.516 +    sqlite3_reset(session->get_replacement_fprs);
   1.517 +    sqlite3_bind_text(session->get_replacement_fprs, 1, revoked_fpr, -1, SQLITE_STATIC);
   1.518 +    sqlite3_bind_text(session->get_replacement_fprs, 2, address, -1, SQLITE_STATIC);
   1.519 +
   1.520 +    int result;
   1.521 +    
   1.522 +    do {
   1.523 +        char* replacement_fpr = NULL;
   1.524 +        char* own_address = NULL;
   1.525 +        revocation_date = 0;
   1.526 +
   1.527 +        result = sqlite3_step(session->get_replacement_fprs);
   1.528 +        switch (result) {
   1.529 +            case SQLITE_ROW: {
   1.530 +                replacement_fpr = strdup((const char *)
   1.531 +                        sqlite3_column_text(session->get_replacement_fprs, 0));
   1.532 +                if (replacement_fpr) {        
   1.533 +                    own_address = strdup((const char *)
   1.534 +                                    sqlite3_column_text(session->get_replacement_fprs, 1));                        
   1.535 +                    revocation_date = sqlite3_column_int64(session->get_replacement_fprs, 2);
   1.536 +                    revocation_info* rev_info = new_revocation_info(strdup(revoked_fpr), own_address, replacement_fpr, revocation_date);
   1.537 +                    if (!rev_info) {
   1.538 +                        status = PEP_OUT_OF_MEMORY;
   1.539 +                        result = SQLITE_DONE;
   1.540 +                    }    
   1.541 +                    revocation_info_list_add(*replacement_fprs_info, rev_info);
   1.542 +                }    
   1.543 +                else {
   1.544 +                    status = PEP_OUT_OF_MEMORY;
   1.545 +                    result = SQLITE_DONE;
   1.546 +                }
   1.547 +                break;
   1.548 +            }
   1.549 +            case SQLITE_DONE:
   1.550 +                break;
   1.551 +            default:
   1.552 +                status = PEP_CANNOT_FIND_IDENTITY;
   1.553 +                result = SQLITE_DONE;
   1.554 +        }
   1.555 +    } while (result != SQLITE_DONE);
   1.556 +        
   1.557 +    sqlite3_reset(session->get_replacement_fprs);
   1.558 +
   1.559 +    return status;
   1.560 +}
   1.561 +
   1.562  PEP_STATUS get_last_contacted(
   1.563          PEP_SESSION session,
   1.564          identity_list** id_list