src/pEpEngine.c
author Edouard Tisserant
Sun, 12 Jun 2016 20:20:45 +0200
branchimport_own_key
changeset 734 bd9a3eb1d707
parent 728 80b966277620
parent 722 932c969958c8
child 876 7bb8baa0d4ee
permissions -rw-r--r--
merged remove_attached_keys
     1 #include "pEp_internal.h"
     2 #include "dynamic_api.h"
     3 #include "cryptotech.h"
     4 #include "transport.h"
     5 #include "blacklist.h"
     6 
     7 static int init_count = -1;
     8 
     9 DYNAMIC_API PEP_STATUS init(PEP_SESSION *session)
    10 {
    11     PEP_STATUS status = PEP_STATUS_OK;
    12     int int_result;
    13     static const char *sql_log;
    14     static const char *sql_trustword;
    15     static const char *sql_get_identity;
    16     static const char *sql_set_person;
    17     static const char *sql_set_pgp_keypair;
    18     static const char *sql_set_identity;
    19     static const char *sql_set_trust;
    20     static const char *sql_get_trust;
    21     static const char *sql_least_trust;
    22     static const char *sql_mark_as_compromized;
    23     static const char *sql_crashdump;
    24     static const char *sql_languagelist;
    25     static const char *sql_i18n_token;
    26 
    27     // blacklist
    28     static const char *sql_blacklist_add;
    29     static const char *sql_blacklist_delete;
    30     static const char *sql_blacklist_is_listed;
    31     static const char *sql_blacklist_retrieve;
    32 
    33     // Own keys
    34     static const char *sql_own_key_is_listed;
    35     static const char *sql_own_key_retrieve;
    36 
    37     // Sequence
    38     static const char *sql_sequence_value1;
    39     static const char *sql_sequence_value2;
    40 
    41     // Revocation tracking
    42     static const char *sql_set_revoked;
    43     static const char *sql_get_revoked;
    44     
    45     bool in_first = false;
    46 
    47     assert(sqlite3_threadsafe());
    48     if (!sqlite3_threadsafe())
    49         return PEP_INIT_SQLITE3_WITHOUT_MUTEX;
    50 
    51     // a little race condition - but still a race condition
    52     // mitigated by calling caveat (see documentation)
    53 
    54     ++init_count;
    55     if (init_count == 0)
    56         in_first = true;
    57 
    58     assert(session);
    59     if (session == NULL)
    60         return PEP_ILLEGAL_VALUE;
    61 
    62     *session = NULL;
    63 
    64     pEpSession *_session = calloc(1, sizeof(pEpSession));
    65     assert(_session);
    66     if (_session == NULL)
    67         goto enomem;
    68 
    69     _session->version = PEP_ENGINE_VERSION;
    70 
    71     assert(LOCAL_DB);
    72     if (LOCAL_DB == NULL) {
    73         status = PEP_INIT_CANNOT_OPEN_DB;
    74         goto pep_error;
    75     }
    76 
    77     int_result = sqlite3_open_v2(
    78             LOCAL_DB,
    79             &_session->db,
    80             SQLITE_OPEN_READWRITE
    81                 | SQLITE_OPEN_CREATE
    82                 | SQLITE_OPEN_FULLMUTEX
    83                 | SQLITE_OPEN_PRIVATECACHE,
    84             NULL 
    85         );
    86 
    87     if (int_result != SQLITE_OK) {
    88         status = PEP_INIT_CANNOT_OPEN_DB;
    89         goto pep_error;
    90     }
    91 
    92     sqlite3_busy_timeout(_session->db, BUSY_WAIT_TIME);
    93 
    94     assert(SYSTEM_DB);
    95     if (SYSTEM_DB == NULL) {
    96         status = PEP_INIT_CANNOT_OPEN_SYSTEM_DB;
    97         goto pep_error;
    98     }
    99 
   100     int_result = sqlite3_open_v2(
   101             SYSTEM_DB, &_session->system_db,
   102             SQLITE_OPEN_READONLY
   103                 | SQLITE_OPEN_FULLMUTEX
   104                 | SQLITE_OPEN_SHAREDCACHE,
   105             NULL
   106         );
   107 
   108     if (int_result != SQLITE_OK) {
   109         status = PEP_INIT_CANNOT_OPEN_SYSTEM_DB;
   110         goto pep_error;
   111     }
   112 
   113     sqlite3_busy_timeout(_session->system_db, 1000);
   114 
   115     if (in_first) {
   116         int_result = sqlite3_exec(
   117             _session->db,
   118                 "create table if not exists version_info (\n"
   119                 "   id integer primary key,\n"
   120                 "   timestamp integer default (datetime('now')) ,\n"
   121                 "   version text,\n"
   122                 "   comment text\n"
   123                 ");\n"
   124                 "create table if not exists log (\n"
   125                 "   timestamp integer default (datetime('now')) ,\n"
   126                 "   title text not null,\n"
   127                 "   entity text not null,\n"
   128                 "   description text,\n"
   129                 "   comment text\n"
   130                 ");\n"
   131                 "create index if not exists log_timestamp on log (\n"
   132                 "   timestamp\n"
   133                 ");\n"
   134                 "create table if not exists pgp_keypair (\n"
   135                 "   fpr text primary key,\n"
   136                 "   public_id text unique,\n"
   137                 "   private_id text,\n"
   138                 "   created integer,\n"
   139                 "   expires integer,\n"
   140                 "   comment text\n"
   141                 ");\n"
   142                 "create index if not exists pgp_keypair_expires on pgp_keypair (\n"
   143                 "   expires\n"
   144                 ");\n"
   145                 "create table if not exists person (\n"
   146                 "   id text primary key,\n"
   147                 "   username text not null,\n"
   148                 "   main_key_id text\n"
   149                 "       references pgp_keypair (fpr)\n"
   150                 "       on delete set null,\n"
   151                 "   lang text,\n"
   152                 "   comment text\n"
   153                 ");\n"
   154                 "create table if not exists identity (\n"
   155                 "   address text,\n"
   156                 "   user_id text\n"
   157                 "       references person (id)\n"
   158                 "       on delete cascade,\n"
   159                 "   main_key_id text\n"
   160                 "       references pgp_keypair (fpr)\n"
   161                 "       on delete set null,\n"
   162                 "   comment text,\n"
   163                 "   primary key (address, user_id)\n"
   164                 ");\n"
   165                 "create table if not exists trust (\n"
   166                 "   user_id text not null\n"
   167                 "       references person (id)\n"
   168                 "       on delete cascade,\n"
   169                 "   pgp_keypair_fpr text not null\n"
   170                 "       references pgp_keypair (fpr)\n"
   171                 "       on delete cascade,\n"
   172                 "   comm_type integer not null,\n"
   173                 "   comment text,\n"
   174                 "   primary key (user_id, pgp_keypair_fpr)\n"
   175                 ");\n"
   176                 // blacklist
   177                 "create table if not exists blacklist_keys (\n"
   178                 "   fpr text primary key\n"
   179                 ");\n"
   180                 // sequences
   181                 "create table if not exists sequences(\n"
   182                 "   name text primary key,\n"
   183                 "   value integer default 0\n"
   184                 ");\n"
   185                 "create table if not exists revoked_keys (\n"
   186                 "   revoked_fpr text primary key,\n"
   187                 "   replacement_fpr text not null\n"
   188                 "       references pgp_keypair (fpr)\n"
   189                 "       on delete cascade,\n"
   190                 "   revocation_date integer\n"
   191                 ");\n"
   192                 ,
   193             NULL,
   194             NULL,
   195             NULL
   196         );
   197         assert(int_result == SQLITE_OK);
   198 
   199         int_result = sqlite3_exec(
   200             _session->db,
   201             "insert or replace into version_info (id, version) values (1, '1.1');",
   202             NULL,
   203             NULL,
   204             NULL
   205         );
   206         assert(int_result == SQLITE_OK);
   207 
   208         sql_log = "insert into log (title, entity, description, comment)"
   209                   "values (?1, ?2, ?3, ?4);";
   210 
   211         sql_get_identity =  "select fpr, username, comm_type, lang"
   212                             "   from identity"
   213                             "   join person on id = identity.user_id"
   214                             "   join pgp_keypair on fpr = identity.main_key_id"
   215                             "   join trust on id = trust.user_id"
   216                             "       and pgp_keypair_fpr = identity.main_key_id"
   217                             "   where address = ?1 and identity.user_id = ?2;";
   218 
   219         sql_trustword = "select id, word from wordlist where lang = lower(?1) "
   220                        "and id = ?2 ;";
   221 
   222         // Set person, but if already exist, only update.
   223         // if main_key_id already set, don't touch.
   224         sql_set_person = "insert or replace into person (id, username, lang, main_key_id)"
   225                          "  values (?1, ?2, ?3,"
   226                          "    (select coalesce((select main_key_id from person "
   227                          "      where id = ?1), upper(replace(?4,' ',''))))) ;";
   228 
   229         sql_set_pgp_keypair = "insert or replace into pgp_keypair (fpr) "
   230                               "values (upper(replace(?1,' ',''))) ;";
   231 
   232         sql_set_identity = "insert or replace into identity (address, main_key_id, "
   233                            "user_id) values (?1, upper(replace(?2,' ','')), ?3) ;";
   234 
   235         sql_set_trust = "insert or replace into trust (user_id, pgp_keypair_fpr, comm_type) "
   236                         "values (?1, upper(replace(?2,' ','')), ?3) ;";
   237 
   238         sql_get_trust = "select comm_type from trust where user_id = ?1 "
   239                         "and pgp_keypair_fpr = upper(replace(?2,' ','')) ;";
   240 
   241         sql_least_trust = "select min(comm_type) from trust where pgp_keypair_fpr = upper(replace(?1,' ','')) ;";
   242 
   243         sql_mark_as_compromized = "update trust not indexed set comm_type = 15"
   244                                   " where pgp_keypair_fpr = upper(replace(?1,' ','')) ;";
   245 
   246         sql_crashdump = "select timestamp, title, entity, description, comment"
   247                         " from log order by timestamp desc limit ?1 ;";
   248 
   249         sql_languagelist = "select i18n_language.lang, name, phrase from i18n_language join i18n_token using (lang) where i18n_token.id = 1000;" ;
   250 
   251         sql_i18n_token = "select phrase from i18n_token where lang = lower(?1) and id = ?2 ;";
   252 
   253         // blacklist
   254 
   255         sql_blacklist_add = "insert or replace into blacklist_keys (fpr) values (upper(replace(?1,' ',''))) ;"
   256                             "delete from identity where main_key_id = upper(replace(?1,' ','')) ;"
   257                             "delete from pgp_keypair where fpr = upper(replace(?1,' ','')) ;";
   258 
   259         sql_blacklist_delete = "delete from blacklist_keys where fpr = upper(replace(?1,' ','')) ;";
   260 
   261         sql_blacklist_is_listed = "select count(*) from blacklist_keys where fpr = upper(replace(?1,' ','')) ;";
   262 
   263         sql_blacklist_retrieve = "select * from blacklist_keys ;";
   264         
   265         // Own keys
   266         
   267         sql_own_key_is_listed =
   268                                 "select count(*) from ("
   269                                 " select main_key_id from person "
   270                                 "   where main_key_id = upper(replace(?1,' ',''))"
   271                                 "    and id = '" PEP_OWN_USERID "' "
   272                                 " union "
   273                                 "  select main_key_id from identity "
   274                                 "   where main_key_id = upper(replace(?1,' ',''))"
   275                                 "    and user_id = '" PEP_OWN_USERID "' );";
   276 
   277         sql_own_key_retrieve = "select main_key_id from person "
   278                                "  where main_key_id is not null"
   279                                "   and id = '" PEP_OWN_USERID "' "
   280                                "union "
   281                                " select main_key_id from identity "
   282                                "  where main_key_id is not null"
   283                                "   and user_id = '" PEP_OWN_USERID "' ;";
   284         
   285         sql_sequence_value1 = "insert or replace into sequences (name, value) "
   286                               "values (?1, "
   287                               "(select coalesce((select value + 1 from sequences "
   288                               "where name = ?1), 1 ))) ; ";
   289         sql_sequence_value2 = "select value from sequences where name = ?1 ;";
   290         
   291         sql_set_revoked =     "insert or replace into revoked_keys ("
   292                               "    revoked_fpr, replacement_fpr, revocation_date) "
   293                               "values (upper(replace(?1,' ','')),"
   294                               "        upper(replace(?2,' ','')),"
   295                               "        ?3) ;";
   296         
   297         sql_get_revoked =     "select revoked_fpr, revocation_date from revoked_keys"
   298                               "    where replacement_fpr = upper(replace(?1,' ','')) ;";
   299     }
   300 
   301     int_result = sqlite3_prepare_v2(_session->db, sql_log, (int)strlen(sql_log),
   302             &_session->log, NULL);
   303     assert(int_result == SQLITE_OK);
   304 
   305     int_result = sqlite3_prepare_v2(_session->system_db, sql_trustword,
   306             (int)strlen(sql_trustword), &_session->trustword, NULL);
   307     assert(int_result == SQLITE_OK);
   308 
   309     int_result = sqlite3_prepare_v2(_session->db, sql_get_identity,
   310             (int)strlen(sql_get_identity), &_session->get_identity, NULL);
   311     assert(int_result == SQLITE_OK);
   312 
   313     int_result = sqlite3_prepare_v2(_session->db, sql_set_person,
   314             (int)strlen(sql_set_person), &_session->set_person, NULL);
   315     assert(int_result == SQLITE_OK);
   316 
   317     int_result = sqlite3_prepare_v2(_session->db, sql_set_pgp_keypair,
   318             (int)strlen(sql_set_pgp_keypair), &_session->set_pgp_keypair, NULL);
   319     assert(int_result == SQLITE_OK);
   320 
   321     int_result = sqlite3_prepare_v2(_session->db, sql_set_identity,
   322             (int)strlen(sql_set_identity), &_session->set_identity, NULL);
   323     assert(int_result == SQLITE_OK);
   324 
   325     int_result = sqlite3_prepare_v2(_session->db, sql_set_trust,
   326             (int)strlen(sql_set_trust), &_session->set_trust, NULL);
   327     assert(int_result == SQLITE_OK);
   328 
   329     int_result = sqlite3_prepare_v2(_session->db, sql_get_trust,
   330             (int)strlen(sql_get_trust), &_session->get_trust, NULL);
   331     assert(int_result == SQLITE_OK);
   332 
   333     int_result = sqlite3_prepare_v2(_session->db, sql_least_trust,
   334             (int)strlen(sql_least_trust), &_session->least_trust, NULL);
   335     assert(int_result == SQLITE_OK);
   336 
   337     int_result = sqlite3_prepare_v2(_session->db, sql_mark_as_compromized,
   338             (int)strlen(sql_mark_as_compromized), &_session->mark_compromized, NULL);
   339     assert(int_result == SQLITE_OK);
   340 
   341     int_result = sqlite3_prepare_v2(_session->db, sql_crashdump,
   342             (int)strlen(sql_crashdump), &_session->crashdump, NULL);
   343     assert(int_result == SQLITE_OK);
   344 
   345     int_result = sqlite3_prepare_v2(_session->system_db, sql_languagelist,
   346             (int)strlen(sql_languagelist), &_session->languagelist, NULL);
   347     assert(int_result == SQLITE_OK);
   348 
   349     int_result = sqlite3_prepare_v2(_session->system_db, sql_i18n_token,
   350             (int)strlen(sql_i18n_token), &_session->i18n_token, NULL);
   351     assert(int_result == SQLITE_OK);
   352 
   353     // blacklist
   354 
   355     int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_add,
   356             (int)strlen(sql_blacklist_add), &_session->blacklist_add, NULL);
   357     assert(int_result == SQLITE_OK);
   358 
   359     int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_delete,
   360             (int)strlen(sql_blacklist_delete), &_session->blacklist_delete, NULL);
   361     assert(int_result == SQLITE_OK);
   362 
   363     int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_is_listed,
   364             (int)strlen(sql_blacklist_is_listed), &_session->blacklist_is_listed, NULL);
   365     assert(int_result == SQLITE_OK);
   366 
   367     int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_retrieve,
   368             (int)strlen(sql_blacklist_retrieve), &_session->blacklist_retrieve, NULL);
   369     assert(int_result == SQLITE_OK);
   370 
   371     // Own keys
   372     
   373     int_result = sqlite3_prepare_v2(_session->db, sql_own_key_is_listed,
   374             (int)strlen(sql_own_key_is_listed), &_session->own_key_is_listed, NULL);
   375     assert(int_result == SQLITE_OK);
   376     
   377     int_result = sqlite3_prepare_v2(_session->db, sql_own_key_retrieve,
   378             (int)strlen(sql_own_key_retrieve), &_session->own_key_retrieve, NULL);
   379     assert(int_result == SQLITE_OK);
   380  
   381     // Sequence
   382 
   383     int_result = sqlite3_prepare_v2(_session->db, sql_sequence_value1,
   384             (int)strlen(sql_sequence_value1), &_session->sequence_value1, NULL);
   385     assert(int_result == SQLITE_OK);
   386 
   387     int_result = sqlite3_prepare_v2(_session->db, sql_sequence_value2,
   388             (int)strlen(sql_sequence_value2), &_session->sequence_value2, NULL);
   389     assert(int_result == SQLITE_OK);
   390 
   391     // Revocation tracking
   392     
   393     int_result = sqlite3_prepare_v2(_session->db, sql_set_revoked,
   394                                     (int)strlen(sql_set_revoked), &_session->set_revoked, NULL);
   395     assert(int_result == SQLITE_OK);
   396     
   397     int_result = sqlite3_prepare_v2(_session->db, sql_get_revoked,
   398                                     (int)strlen(sql_get_revoked), &_session->get_revoked, NULL);
   399     assert(int_result == SQLITE_OK);
   400     
   401     status = init_cryptotech(_session, in_first);
   402     if (status != PEP_STATUS_OK)
   403         goto pep_error;
   404 
   405     status = init_transport_system(_session, in_first);
   406     if (status != PEP_STATUS_OK)
   407         goto pep_error;
   408 
   409     status = log_event(_session, "init", "pEp " PEP_ENGINE_VERSION, NULL, NULL);
   410     if (status != PEP_STATUS_OK)
   411         goto pep_error;
   412 
   413     // runtime config
   414 
   415     _session->passive_mode = false;
   416     _session->unencrypted_subject = false;
   417 #ifdef ANDROID
   418     _session->use_only_own_private_keys = true;
   419 #elif TARGET_OS_IPHONE
   420     _session->use_only_own_private_keys = true;
   421 #else
   422     _session->use_only_own_private_keys = false;
   423 #endif
   424 
   425     *session = _session;
   426     return PEP_STATUS_OK;
   427 
   428 enomem:
   429     status = PEP_OUT_OF_MEMORY;
   430 
   431 pep_error:
   432     release(_session);
   433     return status;
   434 }
   435 
   436 DYNAMIC_API void release(PEP_SESSION session)
   437 {
   438     bool out_last = false;
   439 
   440     assert(init_count >= 0);
   441     assert(session);
   442 
   443     if (!((init_count >= 0) && session))
   444         return;
   445 
   446     // a small race condition but still a race condition
   447     // mitigated by calling caveat (see documentation)
   448 
   449     if (init_count == 0)
   450         out_last = true;
   451     --init_count;
   452 
   453     if (session) {
   454         if (session->db) {
   455             if (session->log)
   456                 sqlite3_finalize(session->log);
   457             if (session->trustword)
   458                 sqlite3_finalize(session->trustword);
   459             if (session->get_identity)
   460                 sqlite3_finalize(session->get_identity);
   461             if (session->set_person)
   462                 sqlite3_finalize(session->set_person);
   463             if (session->set_pgp_keypair)
   464                 sqlite3_finalize(session->set_pgp_keypair);
   465             if (session->set_identity)
   466                 sqlite3_finalize(session->set_identity);
   467             if (session->set_trust)
   468                 sqlite3_finalize(session->set_trust);
   469             if (session->get_trust)
   470                 sqlite3_finalize(session->get_trust);
   471             if (session->least_trust)
   472                 sqlite3_finalize(session->least_trust);
   473             if (session->mark_compromized)
   474                 sqlite3_finalize(session->mark_compromized);
   475             if (session->crashdump)
   476                 sqlite3_finalize(session->crashdump);
   477             if (session->languagelist)
   478                 sqlite3_finalize(session->languagelist);
   479             if (session->i18n_token)
   480                 sqlite3_finalize(session->i18n_token);
   481             if (session->blacklist_add)
   482                 sqlite3_finalize(session->blacklist_add);
   483             if (session->blacklist_delete)
   484                 sqlite3_finalize(session->blacklist_delete);
   485             if (session->blacklist_is_listed)
   486                 sqlite3_finalize(session->blacklist_is_listed);
   487             if (session->blacklist_retrieve)
   488                 sqlite3_finalize(session->blacklist_retrieve);
   489 
   490             if (session->db)
   491                 sqlite3_close_v2(session->db);
   492             if (session->system_db)
   493                 sqlite3_close_v2(session->system_db);
   494         }
   495 
   496         release_transport_system(session, out_last);
   497         release_cryptotech(session, out_last);
   498 
   499         free(session);
   500     }
   501 }
   502 
   503 DYNAMIC_API void config_passive_mode(PEP_SESSION session, bool enable)
   504 {
   505     assert(session);
   506     session->passive_mode = enable;
   507 }
   508 
   509 DYNAMIC_API void config_unencrypted_subject(PEP_SESSION session, bool enable)
   510 {
   511     assert(session);
   512     session->unencrypted_subject = enable;
   513 }
   514 
   515 DYNAMIC_API void config_use_only_own_private_keys(PEP_SESSION session, bool enable)
   516 {
   517     assert(session);
   518     session->use_only_own_private_keys = enable;
   519 }
   520 
   521 DYNAMIC_API PEP_STATUS log_event(
   522         PEP_SESSION session,
   523         const char *title,
   524         const char *entity,
   525         const char *description,
   526         const char *comment
   527     )
   528 {
   529     PEP_STATUS status = PEP_STATUS_OK;
   530     int result;
   531 
   532     assert(session);
   533     assert(title);
   534     assert(entity);
   535 
   536     if (!(session && title && entity))
   537         return PEP_ILLEGAL_VALUE;
   538 
   539     sqlite3_reset(session->log);
   540     sqlite3_bind_text(session->log, 1, title, -1, SQLITE_STATIC);
   541     sqlite3_bind_text(session->log, 2, entity, -1, SQLITE_STATIC);
   542     if (description)
   543         sqlite3_bind_text(session->log, 3, description, -1, SQLITE_STATIC);
   544     else
   545         sqlite3_bind_null(session->log, 3);
   546     if (comment)
   547         sqlite3_bind_text(session->log, 4, comment, -1, SQLITE_STATIC);
   548     else
   549         sqlite3_bind_null(session->log, 4);
   550     do {
   551         result = sqlite3_step(session->log);
   552         assert(result == SQLITE_DONE || result == SQLITE_BUSY);
   553         if (result != SQLITE_DONE && result != SQLITE_BUSY)
   554             status = PEP_UNKNOWN_ERROR;
   555     } while (result == SQLITE_BUSY);
   556     sqlite3_reset(session->log);
   557 
   558     return status;
   559 }
   560 
   561 DYNAMIC_API PEP_STATUS trustword(
   562             PEP_SESSION session, uint16_t value, const char *lang,
   563             char **word, size_t *wsize
   564         )
   565 {
   566     PEP_STATUS status = PEP_STATUS_OK;
   567     int result;
   568 
   569     assert(session);
   570     assert(word);
   571     assert(wsize);
   572 
   573     if (!(session && word && wsize))
   574         return PEP_ILLEGAL_VALUE;
   575 
   576     *word = NULL;
   577     *wsize = 0;
   578 
   579     if (lang == NULL)
   580         lang = "en";
   581 
   582     assert((lang[0] >= 'A' && lang[0] <= 'Z')
   583             || (lang[0] >= 'a' && lang[0] <= 'z'));
   584     assert((lang[1] >= 'A' && lang[1] <= 'Z')
   585             || (lang[1] >= 'a' && lang[1] <= 'z'));
   586     assert(lang[2] == 0);
   587 
   588     sqlite3_reset(session->trustword);
   589     sqlite3_bind_text(session->trustword, 1, lang, -1, SQLITE_STATIC);
   590     sqlite3_bind_int(session->trustword, 2, value);
   591 
   592     result = sqlite3_step(session->trustword);
   593     if (result == SQLITE_ROW) {
   594         *word = strdup((const char *) sqlite3_column_text(session->trustword,
   595                     1));
   596         if (*word)
   597             *wsize = sqlite3_column_bytes(session->trustword, 1);
   598         else
   599             status = PEP_OUT_OF_MEMORY;
   600     } else
   601         status = PEP_TRUSTWORD_NOT_FOUND;
   602 
   603     sqlite3_reset(session->trustword);
   604     return status;
   605 }
   606 
   607 DYNAMIC_API PEP_STATUS trustwords(
   608         PEP_SESSION session, const char *fingerprint, const char *lang,
   609         char **words, size_t *wsize, int max_words
   610     )
   611 {
   612     const char *source = fingerprint;
   613     char *buffer;
   614     char *dest;
   615     size_t fsize;
   616     PEP_STATUS _status;
   617 
   618     assert(session);
   619     assert(fingerprint);
   620     assert(words);
   621     assert(wsize);
   622     assert(max_words >= 0);
   623 
   624     if (!(session && fingerprint && words && wsize && max_words >= 0))
   625         return PEP_ILLEGAL_VALUE;
   626 
   627     *words = NULL;
   628     *wsize = 0;
   629 
   630     buffer = calloc(1, MAX_TRUSTWORDS_SPACE);
   631     assert(buffer);
   632     if (buffer == NULL)
   633         return PEP_OUT_OF_MEMORY;
   634     dest = buffer;
   635 
   636     fsize = strlen(fingerprint);
   637 
   638     if (!lang || !lang[0])
   639         lang = "en";
   640 
   641     assert((lang[0] >= 'A' && lang[0] <= 'Z')
   642             || (lang[0] >= 'a' && lang[0] <= 'z'));
   643     assert((lang[1] >= 'A' && lang[1] <= 'Z')
   644             || (lang[1] >= 'a' && lang[1] <= 'z'));
   645     assert(lang[2] == 0);
   646 
   647     int n_words = 0;
   648     while (source < fingerprint + fsize) {
   649         uint16_t value;
   650         char *word;
   651         size_t _wsize;
   652         int j;
   653 
   654         for (value=0, j=0; j < 4 && source < fingerprint + fsize; ) {
   655             if (*source >= 'a' && *source <= 'f')
   656                 value += (*source - 'a' + 10) << (3 - j++) * 4;
   657             else if (*source >= 'A' && *source <= 'F')
   658                 value += (*source - 'A' + 10) << (3 - j++) * 4;
   659             else if (*source >= '0' && *source <= '9')
   660                 value += (*source - '0') << (3 - j++) * 4;
   661             
   662             source++;
   663         }
   664 
   665         _status = trustword(session, value, lang, &word, &_wsize);
   666         if (_status == PEP_OUT_OF_MEMORY) {
   667             free(buffer);
   668             return PEP_OUT_OF_MEMORY;
   669         }
   670         if (word == NULL) {
   671             free(buffer);
   672             return PEP_TRUSTWORD_NOT_FOUND;
   673         }
   674 
   675         if (dest + _wsize < buffer + MAX_TRUSTWORDS_SPACE - 1) {
   676             strncpy(dest, word, _wsize);
   677             free(word);
   678             dest += _wsize;
   679         }
   680         else {
   681             free(word);
   682             break; // buffer full
   683         }
   684 
   685         if (source < fingerprint + fsize
   686                 && dest + _wsize < buffer + MAX_TRUSTWORDS_SPACE - 1)
   687             *dest++ = ' ';
   688 
   689         ++n_words;
   690         if (max_words && n_words >= max_words)
   691             break;
   692     }
   693 
   694     *words = buffer;
   695     *wsize = dest - buffer;
   696     return PEP_STATUS_OK;
   697 }
   698 
   699 pEp_identity *new_identity(
   700         const char *address, const char *fpr, const char *user_id,
   701         const char *username
   702     )
   703 {
   704     pEp_identity *result = calloc(1, sizeof(pEp_identity));
   705     assert(result);
   706     if (result) {
   707         if (address) {
   708             result->address = strdup(address);
   709             assert(result->address);
   710             if (result->address == NULL) {
   711                 free(result);
   712                 return NULL;
   713             }
   714         }
   715         if (fpr) {
   716             result->fpr = strdup(fpr);
   717             assert(result->fpr);
   718             if (result->fpr == NULL) {
   719                 free_identity(result);
   720                 return NULL;
   721             }
   722         }
   723         if (user_id) {
   724             result->user_id = strdup(user_id);
   725             assert(result->user_id);
   726             if (result->user_id == NULL) {
   727                 free_identity(result);
   728                 return NULL;
   729             }
   730         }
   731         if (username) {
   732             result->username = strdup(username);
   733             assert(result->username);
   734             if (result->username == NULL) {
   735                 free_identity(result);
   736                 return NULL;
   737             }
   738         }
   739     }
   740     return result;
   741 }
   742 
   743 pEp_identity *identity_dup(const pEp_identity *src)
   744 {
   745     assert(src);
   746 
   747     pEp_identity *dup = new_identity(src->address, src->fpr, src->user_id, src->username);
   748     assert(dup);
   749     if (dup == NULL)
   750         return NULL;
   751     
   752     dup->comm_type = src->comm_type;
   753     dup->lang[0] = src->lang[0];
   754     dup->lang[1] = src->lang[1];
   755     dup->lang[2] = 0;
   756     dup->me = src->me;
   757 
   758     return dup;
   759 }
   760 
   761 void free_identity(pEp_identity *identity)
   762 {
   763     if (identity) {
   764         free(identity->address);
   765         free(identity->fpr);
   766         free(identity->user_id);
   767         free(identity->username);
   768         free(identity);
   769     }
   770 }
   771 
   772 DYNAMIC_API PEP_STATUS get_identity(
   773         PEP_SESSION session,
   774         const char *address,
   775         const char *user_id,
   776         pEp_identity **identity
   777     )
   778 {
   779     PEP_STATUS status = PEP_STATUS_OK;
   780     static pEp_identity *_identity;
   781     int result;
   782     const char *_lang;
   783 
   784     assert(session);
   785     assert(address);
   786     assert(address[0]);
   787     assert(identity);
   788 
   789     if (!(session && address && address[0] && identity))
   790         return PEP_ILLEGAL_VALUE;
   791 
   792     *identity = NULL;
   793 
   794     sqlite3_reset(session->get_identity);
   795     sqlite3_bind_text(session->get_identity, 1, address, -1, SQLITE_STATIC);
   796     sqlite3_bind_text(session->get_identity, 2, user_id, -1, SQLITE_STATIC);
   797 
   798     result = sqlite3_step(session->get_identity);
   799     switch (result) {
   800     case SQLITE_ROW:
   801         _identity = new_identity(
   802                 address,
   803                 (const char *) sqlite3_column_text(session->get_identity, 0),
   804                 user_id,
   805                 (const char *) sqlite3_column_text(session->get_identity, 1)
   806                 );
   807         assert(_identity);
   808         if (_identity == NULL)
   809             return PEP_OUT_OF_MEMORY;
   810 
   811         _identity->comm_type = (PEP_comm_type) sqlite3_column_int(session->get_identity, 2);
   812         _lang = (const char *) sqlite3_column_text(session->get_identity, 3);
   813         if (_lang && _lang[0]) {
   814             assert(_lang[0] >= 'a' && _lang[0] <= 'z');
   815             assert(_lang[1] >= 'a' && _lang[1] <= 'z');
   816             assert(_lang[2] == 0);
   817             _identity->lang[0] = _lang[0];
   818             _identity->lang[1] = _lang[1];
   819             _identity->lang[2] = 0;
   820         }
   821         *identity = _identity;
   822         break;
   823     default:
   824         status = PEP_CANNOT_FIND_IDENTITY;
   825         *identity = NULL;
   826     }
   827 
   828     sqlite3_reset(session->get_identity);
   829     return status;
   830 }
   831 
   832 DYNAMIC_API PEP_STATUS set_identity(
   833         PEP_SESSION session, const pEp_identity *identity
   834     )
   835 {
   836     int result;
   837 
   838     assert(session);
   839     assert(identity);
   840     assert(identity->address);
   841     assert(identity->fpr);
   842     assert(identity->user_id);
   843     assert(identity->username);
   844 
   845     if (!(session && identity && identity->address && identity->fpr &&
   846                 identity->user_id && identity->username))
   847         return PEP_ILLEGAL_VALUE;
   848 
   849     bool listed;
   850     PEP_STATUS status = blacklist_is_listed(session, identity->fpr, &listed);
   851     assert(status == PEP_STATUS_OK);
   852     if (status != PEP_STATUS_OK)
   853         return status;
   854 
   855     if (listed)
   856         return PEP_KEY_BLACKLISTED;
   857 
   858     sqlite3_exec(session->db, "BEGIN ;", NULL, NULL, NULL);
   859 
   860     sqlite3_reset(session->set_person);
   861     sqlite3_bind_text(session->set_person, 1, identity->user_id, -1,
   862             SQLITE_STATIC);
   863     sqlite3_bind_text(session->set_person, 2, identity->username, -1,
   864             SQLITE_STATIC);
   865     if (identity->lang[0])
   866         sqlite3_bind_text(session->set_person, 3, identity->lang, 1,
   867                 SQLITE_STATIC);
   868     else
   869         sqlite3_bind_null(session->set_person, 3);
   870     sqlite3_bind_text(session->set_person, 4, identity->fpr, -1,
   871                       SQLITE_STATIC);
   872     result = sqlite3_step(session->set_person);
   873     sqlite3_reset(session->set_person);
   874     if (result != SQLITE_DONE) {
   875         sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
   876         return PEP_CANNOT_SET_PERSON;
   877     }
   878 
   879     sqlite3_reset(session->set_pgp_keypair);
   880     sqlite3_bind_text(session->set_pgp_keypair, 1, identity->fpr, -1,
   881             SQLITE_STATIC);
   882     result = sqlite3_step(session->set_pgp_keypair);
   883     sqlite3_reset(session->set_pgp_keypair);
   884     if (result != SQLITE_DONE) {
   885         sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
   886         return PEP_CANNOT_SET_PGP_KEYPAIR;
   887     }
   888 
   889     sqlite3_reset(session->set_identity);
   890     sqlite3_bind_text(session->set_identity, 1, identity->address, -1,
   891             SQLITE_STATIC);
   892     sqlite3_bind_text(session->set_identity, 2, identity->fpr, -1,
   893             SQLITE_STATIC);
   894     sqlite3_bind_text(session->set_identity, 3, identity->user_id, -1,
   895             SQLITE_STATIC);
   896     result = sqlite3_step(session->set_identity);
   897     sqlite3_reset(session->set_identity);
   898     if (result != SQLITE_DONE) {
   899         sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
   900         return PEP_CANNOT_SET_IDENTITY;
   901     }
   902 
   903     sqlite3_reset(session->set_trust);
   904     sqlite3_bind_text(session->set_trust, 1, identity->user_id, -1,
   905             SQLITE_STATIC);
   906     sqlite3_bind_text(session->set_trust, 2, identity->fpr, -1,
   907             SQLITE_STATIC);
   908     sqlite3_bind_int(session->set_trust, 3, identity->comm_type);
   909     result = sqlite3_step(session->set_trust);
   910     sqlite3_reset(session->set_trust);
   911     if (result != SQLITE_DONE) {
   912         sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
   913         return PEP_CANNOT_SET_TRUST;
   914     }
   915 
   916     result = sqlite3_exec(session->db, "COMMIT ;", NULL, NULL, NULL);
   917     if (result == SQLITE_OK)
   918         return PEP_STATUS_OK;
   919     else
   920         return PEP_COMMIT_FAILED;
   921 }
   922 
   923 DYNAMIC_API PEP_STATUS mark_as_compromized(
   924         PEP_SESSION session,
   925         const char *fpr
   926     )
   927 {
   928     int result;
   929 
   930     assert(session);
   931     assert(fpr && fpr[0]);
   932 
   933     if (!(session && fpr && fpr[0]))
   934         return PEP_ILLEGAL_VALUE;
   935 
   936     sqlite3_reset(session->mark_compromized);
   937     sqlite3_bind_text(session->mark_compromized, 1, fpr, -1,
   938             SQLITE_STATIC);
   939     result = sqlite3_step(session->mark_compromized);
   940     sqlite3_reset(session->mark_compromized);
   941 
   942     if (result != SQLITE_DONE)
   943         return PEP_CANNOT_SET_TRUST;
   944 
   945     return PEP_STATUS_OK;
   946 }
   947 
   948 void pEp_free(void *p)
   949 {
   950     free(p);
   951 }
   952 
   953 DYNAMIC_API PEP_STATUS get_trust(PEP_SESSION session, pEp_identity *identity)
   954 {
   955     PEP_STATUS status = PEP_STATUS_OK;
   956     int result;
   957 
   958     assert(session);
   959     assert(identity);
   960     assert(identity->user_id);
   961     assert(identity->user_id[0]);
   962     assert(identity->fpr);
   963     assert(identity->fpr[0]);
   964 
   965     if (!(session && identity && identity->user_id && identity->user_id[0] &&
   966                 identity->fpr && identity->fpr[0]))
   967         return PEP_ILLEGAL_VALUE;
   968 
   969     identity->comm_type = PEP_ct_unknown;
   970 
   971     sqlite3_reset(session->get_trust);
   972     sqlite3_bind_text(session->get_trust, 1, identity->user_id, -1, SQLITE_STATIC);
   973     sqlite3_bind_text(session->get_trust, 2, identity->fpr, -1, SQLITE_STATIC);
   974 
   975     result = sqlite3_step(session->get_trust);
   976     switch (result) {
   977     case SQLITE_ROW: {
   978         int comm_type = (PEP_comm_type) sqlite3_column_int(session->get_trust, 0);
   979         identity->comm_type = comm_type;
   980         break;
   981     }
   982  
   983     default:
   984         status = PEP_CANNOT_FIND_IDENTITY;
   985     }
   986 
   987     sqlite3_reset(session->get_trust);
   988     return status;
   989 }
   990 
   991 DYNAMIC_API PEP_STATUS least_trust(
   992         PEP_SESSION session,
   993         const char *fpr,
   994         PEP_comm_type *comm_type
   995     )
   996 {
   997     PEP_STATUS status = PEP_STATUS_OK;
   998     int result;
   999 
  1000     assert(session);
  1001     assert(fpr);
  1002     assert(comm_type);
  1003 
  1004     if (!(session && fpr && comm_type))
  1005         return PEP_ILLEGAL_VALUE;
  1006 
  1007     *comm_type = PEP_ct_unknown;
  1008 
  1009     sqlite3_reset(session->least_trust);
  1010     sqlite3_bind_text(session->least_trust, 1, fpr, -1, SQLITE_STATIC);
  1011 
  1012     result = sqlite3_step(session->least_trust);
  1013     switch (result) {
  1014         case SQLITE_ROW: {
  1015             int _comm_type = sqlite3_column_int(session->least_trust, 0);
  1016             *comm_type = (PEP_comm_type) _comm_type;
  1017             break;
  1018         }
  1019         default:
  1020             status = PEP_CANNOT_FIND_IDENTITY;
  1021     }
  1022 
  1023     sqlite3_reset(session->least_trust);
  1024     return status;
  1025 }
  1026 
  1027 DYNAMIC_API PEP_STATUS decrypt_and_verify(
  1028     PEP_SESSION session, const char *ctext, size_t csize,
  1029     char **ptext, size_t *psize, stringlist_t **keylist
  1030     )
  1031 {
  1032     assert(session);
  1033     assert(ctext);
  1034     assert(csize);
  1035     assert(ptext);
  1036     assert(psize);
  1037     assert(keylist);
  1038 
  1039     if (!(session && ctext && csize && ptext && psize && keylist && keylist))
  1040         return PEP_ILLEGAL_VALUE;
  1041 
  1042     return session->cryptotech[PEP_crypt_OpenPGP].decrypt_and_verify(session, ctext, csize, ptext, psize, keylist);
  1043 }
  1044 
  1045 DYNAMIC_API PEP_STATUS encrypt_and_sign(
  1046     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  1047     size_t psize, char **ctext, size_t *csize
  1048     )
  1049 {
  1050     assert(session);
  1051     assert(keylist);
  1052     assert(ptext);
  1053     assert(psize);
  1054     assert(ctext);
  1055     assert(csize);
  1056 
  1057     if (!(session && keylist && ptext && psize && ctext && csize))
  1058         return PEP_ILLEGAL_VALUE;
  1059 
  1060     return session->cryptotech[PEP_crypt_OpenPGP].encrypt_and_sign(session, keylist, ptext, psize, ctext, csize);
  1061 }
  1062 
  1063 DYNAMIC_API PEP_STATUS verify_text(
  1064     PEP_SESSION session, const char *text, size_t size,
  1065     const char *signature, size_t sig_size, stringlist_t **keylist
  1066     )
  1067 {
  1068     assert(session);
  1069     assert(text);
  1070     assert(size);
  1071     assert(signature);
  1072     assert(sig_size);
  1073     assert(keylist);
  1074 
  1075     if (!(session && text && size && signature && sig_size && keylist))
  1076         return PEP_ILLEGAL_VALUE;
  1077 
  1078     return session->cryptotech[PEP_crypt_OpenPGP].verify_text(session, text, size, signature, sig_size, keylist);
  1079 }
  1080 
  1081 DYNAMIC_API PEP_STATUS delete_keypair(PEP_SESSION session, const char *fpr)
  1082 {
  1083     assert(session);
  1084     assert(fpr);
  1085 
  1086     if (!(session && fpr))
  1087         return PEP_ILLEGAL_VALUE;
  1088 
  1089     return session->cryptotech[PEP_crypt_OpenPGP].delete_keypair(session, fpr);
  1090 }
  1091 
  1092 DYNAMIC_API PEP_STATUS export_key(
  1093         PEP_SESSION session, const char *fpr, char **key_data, size_t *size
  1094     )
  1095 {
  1096     assert(session);
  1097     assert(fpr);
  1098     assert(key_data);
  1099     assert(size);
  1100 
  1101     if (!(session && fpr && key_data && size))
  1102         return PEP_ILLEGAL_VALUE;
  1103 
  1104     return session->cryptotech[PEP_crypt_OpenPGP].export_key(session, fpr, key_data, size);
  1105 }
  1106 
  1107 DYNAMIC_API PEP_STATUS find_keys(
  1108         PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1109     )
  1110 {
  1111     assert(session);
  1112     assert(pattern);
  1113     assert(keylist);
  1114 
  1115     if (!(session && pattern && keylist))
  1116         return PEP_ILLEGAL_VALUE;
  1117 
  1118     return session->cryptotech[PEP_crypt_OpenPGP].find_keys(session, pattern, keylist);
  1119 }
  1120 
  1121 DYNAMIC_API PEP_STATUS generate_keypair(
  1122         PEP_SESSION session, pEp_identity *identity
  1123     )
  1124 {
  1125     assert(session);
  1126     assert(identity);
  1127     assert(identity->address);
  1128     assert(identity->fpr == NULL || identity->fpr[0] == 0);
  1129     assert(identity->username);
  1130 
  1131     if (!(session && identity && identity->address &&
  1132         (identity->fpr == NULL || identity->fpr[0] == 0) && identity->username))
  1133         return PEP_ILLEGAL_VALUE;
  1134 
  1135     return session->cryptotech[PEP_crypt_OpenPGP].generate_keypair(session, identity);
  1136 }
  1137 
  1138 DYNAMIC_API PEP_STATUS get_key_rating(
  1139         PEP_SESSION session,
  1140         const char *fpr,
  1141         PEP_comm_type *comm_type
  1142     )
  1143 {
  1144     assert(session);
  1145     assert(fpr);
  1146     assert(comm_type);
  1147 
  1148     if (!(session && fpr && comm_type))
  1149         return PEP_ILLEGAL_VALUE;
  1150 
  1151     return session->cryptotech[PEP_crypt_OpenPGP].get_key_rating(session, fpr, comm_type);
  1152 }
  1153 
  1154 DYNAMIC_API PEP_STATUS import_key(
  1155         PEP_SESSION session,
  1156         const char *key_data,
  1157         size_t size,
  1158         identity_list **private_keys
  1159     )
  1160 {
  1161     assert(session);
  1162     assert(key_data);
  1163 
  1164     if (!(session && key_data))
  1165         return PEP_ILLEGAL_VALUE;
  1166 
  1167     return session->cryptotech[PEP_crypt_OpenPGP].import_key(session, key_data, size, private_keys);
  1168 }
  1169 
  1170 DYNAMIC_API PEP_STATUS recv_key(PEP_SESSION session, const char *pattern)
  1171 {
  1172     assert(session);
  1173     assert(pattern);
  1174 
  1175     if (!(session && pattern))
  1176         return PEP_ILLEGAL_VALUE;
  1177 
  1178     return session->cryptotech[PEP_crypt_OpenPGP].recv_key(session, pattern);
  1179 }
  1180 
  1181 DYNAMIC_API PEP_STATUS send_key(PEP_SESSION session, const char *pattern)
  1182 {
  1183     assert(session);
  1184     assert(pattern);
  1185 
  1186     if (!(session && pattern))
  1187         return PEP_ILLEGAL_VALUE;
  1188 
  1189     return session->cryptotech[PEP_crypt_OpenPGP].send_key(session, pattern);
  1190 }
  1191 
  1192 DYNAMIC_API PEP_STATUS renew_key(
  1193         PEP_SESSION session,
  1194         const char *fpr,
  1195         const timestamp *ts
  1196     )
  1197 {
  1198     assert(session);
  1199     assert(fpr);
  1200 
  1201     if (!(session && fpr))
  1202         return PEP_ILLEGAL_VALUE;
  1203 
  1204     return session->cryptotech[PEP_crypt_OpenPGP].renew_key(session, fpr, ts);
  1205 }
  1206 
  1207 DYNAMIC_API PEP_STATUS revoke_key(
  1208         PEP_SESSION session,
  1209         const char *fpr,
  1210         const char *reason
  1211     )
  1212 {
  1213     assert(session);
  1214     assert(fpr);
  1215 
  1216     if (!(session && fpr))
  1217         return PEP_ILLEGAL_VALUE;
  1218 
  1219     return session->cryptotech[PEP_crypt_OpenPGP].revoke_key(session, fpr,
  1220             reason);
  1221 }
  1222 
  1223 DYNAMIC_API PEP_STATUS key_expired(
  1224         PEP_SESSION session,
  1225         const char *fpr,
  1226         const time_t when,
  1227         bool *expired
  1228     )
  1229 {
  1230     assert(session);
  1231     assert(fpr);
  1232     assert(expired);
  1233 
  1234     if (!(session && fpr && expired))
  1235         return PEP_ILLEGAL_VALUE;
  1236 
  1237     return session->cryptotech[PEP_crypt_OpenPGP].key_expired(session, fpr,
  1238             when, expired);
  1239 }
  1240 
  1241 DYNAMIC_API PEP_STATUS key_revoked(
  1242                                    PEP_SESSION session,
  1243                                    const char *fpr,
  1244                                    bool *revoked
  1245                                    )
  1246 {
  1247     assert(session);
  1248     assert(fpr);
  1249     assert(revoked);
  1250     
  1251     if (!(session && fpr && revoked))
  1252         return PEP_ILLEGAL_VALUE;
  1253     
  1254     return session->cryptotech[PEP_crypt_OpenPGP].key_revoked(session, fpr,
  1255                                                               revoked);
  1256 }
  1257 
  1258 static void _clean_log_value(char *text)
  1259 {
  1260     if (text) {
  1261         for (char *c = text; *c; c++) {
  1262             if (*c < 32 && *c != '\n')
  1263                 *c = 32;
  1264             else if (*c == '"')
  1265                 *c = '\'';
  1266         }
  1267     }
  1268 }
  1269 
  1270 static char *_concat_string(char *str1, const char *str2, char delim)
  1271 {
  1272     str2 = str2 ? str2 : "";
  1273     size_t len1 = str1 ? strlen(str1) : 0;
  1274     size_t len2 = strlen(str2);
  1275     size_t len = len1 + len2 + 3;
  1276     char * result = realloc(str1, len + 1);
  1277 
  1278     if (result) {
  1279         result[len1] = '"';
  1280         strcpy(result + len1 + 1, str2);
  1281         result[len - 2] = '"';
  1282         result[len - 1] = delim;
  1283         result[len] = 0;
  1284     }
  1285     else {
  1286         free(str1);
  1287     }
  1288 
  1289     return result;
  1290 }
  1291 
  1292 DYNAMIC_API PEP_STATUS get_crashdump_log(
  1293         PEP_SESSION session,
  1294         int maxlines,
  1295         char **logdata
  1296     )
  1297 {
  1298     PEP_STATUS status = PEP_STATUS_OK;
  1299     char *_logdata= NULL;
  1300 
  1301     assert(session);
  1302     assert(maxlines >= 0 && maxlines <= CRASHDUMP_MAX_LINES);
  1303     assert(logdata);
  1304 
  1305     if (!(session && logdata && maxlines >= 0 && maxlines <=
  1306             CRASHDUMP_MAX_LINES))
  1307         return PEP_ILLEGAL_VALUE;
  1308 
  1309     *logdata = NULL;
  1310 
  1311     int limit = maxlines ? maxlines : CRASHDUMP_DEFAULT_LINES;
  1312     const char *timestamp = NULL;
  1313     const char *title = NULL;
  1314     const char *entity = NULL;
  1315     const char *desc = NULL;
  1316     const char *comment = NULL;
  1317 
  1318     sqlite3_reset(session->crashdump);
  1319     sqlite3_bind_int(session->crashdump, 1, limit);
  1320 
  1321     int result;
  1322 
  1323     do {
  1324         result = sqlite3_step(session->crashdump);
  1325         switch (result) {
  1326         case SQLITE_ROW:
  1327             timestamp = (const char *) sqlite3_column_text(session->crashdump, 0);
  1328             title   = (const char *) sqlite3_column_text(session->crashdump, 1);
  1329             entity  = (const char *) sqlite3_column_text(session->crashdump, 2);
  1330             desc    = (const char *) sqlite3_column_text(session->crashdump, 3);
  1331             comment = (const char *) sqlite3_column_text(session->crashdump, 4);
  1332 
  1333             _logdata = _concat_string(_logdata, timestamp, ',');
  1334             if (_logdata == NULL)
  1335                 goto enomem;
  1336 
  1337             _logdata = _concat_string(_logdata, title, ',');
  1338             if (_logdata == NULL)
  1339                 goto enomem;
  1340 
  1341             _logdata = _concat_string(_logdata, entity, ',');
  1342             if (_logdata == NULL)
  1343                 goto enomem;
  1344 
  1345             _logdata = _concat_string(_logdata, desc, ',');
  1346             if (_logdata == NULL)
  1347                 goto enomem;
  1348 
  1349             _logdata = _concat_string(_logdata, comment, '\n');
  1350             if (_logdata == NULL)
  1351                 goto enomem;
  1352 
  1353             _clean_log_value(_logdata);
  1354             break;
  1355 
  1356         case SQLITE_DONE:
  1357             break;
  1358 
  1359         default:
  1360             status = PEP_UNKNOWN_ERROR;
  1361             result = SQLITE_DONE;
  1362         }
  1363     } while (result != SQLITE_DONE);
  1364 
  1365     sqlite3_reset(session->crashdump);
  1366     if (status == PEP_STATUS_OK)
  1367         *logdata = _logdata;
  1368 
  1369     goto the_end;
  1370 
  1371 enomem:
  1372     status = PEP_OUT_OF_MEMORY;
  1373 
  1374 the_end:
  1375     return status;
  1376 }
  1377 
  1378 DYNAMIC_API PEP_STATUS get_languagelist(
  1379         PEP_SESSION session,
  1380         char **languages
  1381     )
  1382 {
  1383     PEP_STATUS status = PEP_STATUS_OK;
  1384     char *_languages= NULL;
  1385 
  1386     assert(session);
  1387     assert(languages);
  1388 
  1389     if (!(session && languages))
  1390         return PEP_ILLEGAL_VALUE;
  1391 
  1392     *languages = NULL;
  1393 
  1394     const char *lang = NULL;
  1395     const char *name = NULL;
  1396     const char *phrase = NULL;
  1397 
  1398     sqlite3_reset(session->languagelist);
  1399 
  1400     int result;
  1401 
  1402     do {
  1403         result = sqlite3_step(session->languagelist);
  1404         switch (result) {
  1405         case SQLITE_ROW:
  1406             lang = (const char *) sqlite3_column_text(session->languagelist, 0);
  1407             name = (const char *) sqlite3_column_text(session->languagelist, 1);
  1408             phrase = (const char *) sqlite3_column_text(session->languagelist, 2);
  1409 
  1410             _languages = _concat_string(_languages, lang, ',');
  1411             if (_languages == NULL)
  1412                 goto enomem;
  1413 
  1414             _languages = _concat_string(_languages, name, ',');
  1415             if (_languages == NULL)
  1416                 goto enomem;
  1417 
  1418             _languages = _concat_string(_languages, phrase, '\n');
  1419             if (_languages == NULL)
  1420                 goto enomem;
  1421 
  1422             break;
  1423 
  1424         case SQLITE_DONE:
  1425             break;
  1426 
  1427         default:
  1428             status = PEP_UNKNOWN_ERROR;
  1429             result = SQLITE_DONE;
  1430         }
  1431     } while (result != SQLITE_DONE);
  1432 
  1433     sqlite3_reset(session->languagelist);
  1434     if (status == PEP_STATUS_OK)
  1435         *languages = _languages;
  1436 
  1437     goto the_end;
  1438 
  1439 enomem:
  1440     status = PEP_OUT_OF_MEMORY;
  1441 
  1442 the_end:
  1443     return status;
  1444 }
  1445 
  1446 DYNAMIC_API PEP_STATUS get_phrase(
  1447         PEP_SESSION session,
  1448         const char *lang,
  1449         int phrase_id,
  1450         char **phrase
  1451     )
  1452 {
  1453     PEP_STATUS status = PEP_STATUS_OK;
  1454 
  1455     assert(session && lang && lang[0] && lang[1] && lang[2] == 0 && phrase);
  1456     if (!(session && lang && lang[0] && lang[1] && lang[2] == 0 && phrase))
  1457         return PEP_ILLEGAL_VALUE;
  1458 
  1459     *phrase = NULL;
  1460 
  1461     sqlite3_reset(session->i18n_token);
  1462     sqlite3_bind_text(session->i18n_token, 1, lang, -1, SQLITE_STATIC);
  1463     sqlite3_bind_int(session->i18n_token, 2, phrase_id);
  1464 
  1465     const char *_phrase = NULL;
  1466     int result;
  1467 
  1468     result = sqlite3_step(session->i18n_token);
  1469     switch (result) {
  1470     case SQLITE_ROW:
  1471         _phrase = (const char *) sqlite3_column_text(session->i18n_token, 0);
  1472         break;
  1473 
  1474     case SQLITE_DONE:
  1475         status = PEP_PHRASE_NOT_FOUND;
  1476         break;
  1477 
  1478     default:
  1479         status = PEP_UNKNOWN_ERROR;
  1480     }
  1481 
  1482     if (status == PEP_STATUS_OK) {
  1483         *phrase = strdup(_phrase);
  1484         if (*phrase == NULL)
  1485             goto enomem;
  1486     }
  1487 
  1488     sqlite3_reset(session->i18n_token);
  1489     goto the_end;
  1490 
  1491 enomem:
  1492     status = PEP_OUT_OF_MEMORY;
  1493 
  1494 the_end:
  1495     return status;
  1496 }
  1497 
  1498 DYNAMIC_API PEP_STATUS sequence_value(
  1499         PEP_SESSION session,
  1500         const char *name,
  1501         int32_t *value
  1502     )
  1503 {
  1504     PEP_STATUS status = PEP_STATUS_OK;
  1505     int result;
  1506 
  1507     assert(session);
  1508     assert(name);
  1509     assert(value);
  1510 
  1511     if (!(session && name && value))
  1512         return PEP_ILLEGAL_VALUE;
  1513 
  1514     *value = 0;
  1515 
  1516     sqlite3_reset(session->sequence_value1);
  1517     sqlite3_bind_text(session->sequence_value1, 1, name, -1, SQLITE_STATIC);
  1518     result = sqlite3_step(session->sequence_value1);
  1519     assert(result == SQLITE_DONE);
  1520     sqlite3_reset(session->sequence_value1);
  1521     if (result != SQLITE_DONE) {
  1522         status = PEP_UNKNOWN_ERROR;
  1523     }
  1524     else {
  1525         sqlite3_reset(session->sequence_value2);
  1526         sqlite3_bind_text(session->sequence_value2, 1, name, -1, SQLITE_STATIC);
  1527         result = sqlite3_step(session->sequence_value2);
  1528         switch (result) {
  1529             case SQLITE_ROW: {
  1530                 int32_t _value = (int32_t)
  1531                         sqlite3_column_int64(session->sequence_value2, 0);
  1532                 *value = _value;
  1533                 break;
  1534             }
  1535             default:
  1536                 status = PEP_UNKNOWN_ERROR;
  1537         }
  1538         sqlite3_reset(session->sequence_value2);
  1539     }
  1540     return status;
  1541 }
  1542 
  1543 DYNAMIC_API PEP_STATUS set_revoked(
  1544        PEP_SESSION session,
  1545        const char *revoked_fpr,
  1546        const char *replacement_fpr,
  1547        const uint64_t revocation_date
  1548     )
  1549 {
  1550     PEP_STATUS status = PEP_STATUS_OK;
  1551     
  1552     assert(session &&
  1553            revoked_fpr && revoked_fpr[0] &&
  1554            replacement_fpr && replacement_fpr[0]
  1555           );
  1556     
  1557     if (!(session &&
  1558           revoked_fpr && revoked_fpr[0] &&
  1559           replacement_fpr && replacement_fpr[0]
  1560          ))
  1561         return PEP_ILLEGAL_VALUE;
  1562     
  1563     sqlite3_reset(session->set_revoked);
  1564     sqlite3_bind_text(session->set_revoked, 1, revoked_fpr, -1, SQLITE_STATIC);
  1565     sqlite3_bind_text(session->set_revoked, 2, replacement_fpr, -1, SQLITE_STATIC);
  1566     sqlite3_bind_int64(session->set_revoked, 3, revocation_date);
  1567 
  1568     int result;
  1569     
  1570     result = sqlite3_step(session->set_revoked);
  1571     switch (result) {
  1572         case SQLITE_DONE:
  1573             status = PEP_STATUS_OK;
  1574             break;
  1575             
  1576         default:
  1577             status = PEP_UNKNOWN_ERROR;
  1578     }
  1579     
  1580     sqlite3_reset(session->set_revoked);
  1581     return status;
  1582 }
  1583 
  1584 DYNAMIC_API PEP_STATUS get_revoked(
  1585         PEP_SESSION session,
  1586         const char *fpr,
  1587         char **revoked_fpr,
  1588         uint64_t *revocation_date
  1589     )
  1590 {
  1591     PEP_STATUS status = PEP_STATUS_OK;
  1592 
  1593     assert(session &&
  1594            revoked_fpr &&
  1595            fpr && fpr[0]
  1596           );
  1597     
  1598     if (!(session &&
  1599            revoked_fpr &&
  1600            fpr && fpr[0]
  1601           ))
  1602         return PEP_ILLEGAL_VALUE;
  1603 
  1604     *revoked_fpr = NULL;
  1605     *revocation_date = 0;
  1606 
  1607     sqlite3_reset(session->get_revoked);
  1608     sqlite3_bind_text(session->get_revoked, 1, fpr, -1, SQLITE_STATIC);
  1609 
  1610     int result;
  1611     
  1612     result = sqlite3_step(session->get_revoked);
  1613     switch (result) {
  1614         case SQLITE_ROW: {
  1615             *revoked_fpr = strdup((const char *) sqlite3_column_text(session->get_revoked, 0));
  1616             if(*revoked_fpr)
  1617                 *revocation_date = sqlite3_column_int64(session->get_revoked, 1);
  1618             else
  1619                 status = PEP_OUT_OF_MEMORY;
  1620 
  1621             break;
  1622         }
  1623         default:
  1624             status = PEP_CANNOT_FIND_IDENTITY;
  1625     }
  1626 
  1627     sqlite3_reset(session->get_revoked);
  1628 
  1629     return status;
  1630 }
  1631 
  1632 DYNAMIC_API PEP_STATUS reset_peptest_hack(PEP_SESSION session)
  1633 {
  1634     assert(session);
  1635 
  1636     if (!session)
  1637         return PEP_ILLEGAL_VALUE;
  1638 
  1639     int int_result = sqlite3_exec(
  1640         session->db,
  1641         "delete from identity where address like '%@peptest.ch' ;",
  1642         NULL,
  1643         NULL,
  1644         NULL
  1645     );
  1646     assert(int_result == SQLITE_OK);
  1647 
  1648     return PEP_STATUS_OK;
  1649 }
  1650