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