src/pEpEngine.c
author Edouard Tisserant <edouard@pep-project.org>
Fri, 18 Nov 2016 00:13:40 +0100
branchENGINE-140_exclude_identity_from_sync
changeset 1406 8d8ae9657388
parent 1401 ed3616afb3fb
child 1407 10c67fc4e3a7
permissions -rw-r--r--
ENGINE-140 changed identities flags update policy
     1 #include "pEp_internal.h"
     2 #include "dynamic_api.h"
     3 #include "cryptotech.h"
     4 #include "transport.h"
     5 #include "blacklist.h"
     6 #include "sync_fsm.h"
     7 
     8 static int init_count = -1;
     9 
    10 static int user_version(void *_version, int count, char **text, char **name)
    11 {
    12     assert(_version);
    13     assert(count == 1);
    14     assert(text && text[0]);
    15     if (!(_version && count == 1 && text && text[0]))
    16         return -1;
    17 
    18     int *version = (int *) _version;
    19     *version = atoi(text[0]);
    20     return 0;
    21 }
    22 
    23 DYNAMIC_API PEP_STATUS init(PEP_SESSION *session)
    24 {
    25     PEP_STATUS status = PEP_STATUS_OK;
    26     int int_result;
    27     static const char *sql_log;
    28     static const char *sql_trustword;
    29     static const char *sql_get_identity;
    30     static const char *sql_set_person;
    31     static const char *sql_set_device_group;
    32     static const char *sql_get_device_group;
    33     static const char *sql_set_pgp_keypair;
    34     static const char *sql_set_identity;
    35     static const char *sql_set_identity_flags;
    36     static const char *sql_unset_identity_flags;
    37     static const char *sql_set_trust;
    38     static const char *sql_get_trust;
    39     static const char *sql_least_trust;
    40     static const char *sql_mark_as_compromized;
    41     static const char *sql_crashdump;
    42     static const char *sql_languagelist;
    43     static const char *sql_i18n_token;
    44 
    45     // blacklist
    46     static const char *sql_blacklist_add;
    47     static const char *sql_blacklist_delete;
    48     static const char *sql_blacklist_is_listed;
    49     static const char *sql_blacklist_retrieve;
    50     
    51     // Own keys
    52     static const char *sql_own_key_is_listed;
    53     static const char *sql_own_identities_retrieve;
    54     static const char *sql_own_keys_retrieve;
    55     static const char *sql_set_own_key;
    56 
    57     // Sequence
    58     static const char *sql_sequence_value1;
    59     static const char *sql_sequence_value2;
    60     static const char *sql_sequence_value3;
    61 
    62     // Revocation tracking
    63     static const char *sql_set_revoked;
    64     static const char *sql_get_revoked;
    65     
    66     bool in_first = false;
    67 
    68     assert(sqlite3_threadsafe());
    69     if (!sqlite3_threadsafe())
    70         return PEP_INIT_SQLITE3_WITHOUT_MUTEX;
    71 
    72     // a little race condition - but still a race condition
    73     // mitigated by calling caveat (see documentation)
    74 
    75     ++init_count;
    76     if (init_count == 0)
    77         in_first = true;
    78 
    79     assert(session);
    80     if (session == NULL)
    81         return PEP_ILLEGAL_VALUE;
    82 
    83     *session = NULL;
    84 
    85     pEpSession *_session = calloc(1, sizeof(pEpSession));
    86     assert(_session);
    87     if (_session == NULL)
    88         goto enomem;
    89 
    90     _session->version = PEP_ENGINE_VERSION;
    91 
    92     assert(LOCAL_DB);
    93     if (LOCAL_DB == NULL) {
    94         status = PEP_INIT_CANNOT_OPEN_DB;
    95         goto pep_error;
    96     }
    97 
    98     int_result = sqlite3_open_v2(
    99             LOCAL_DB,
   100             &_session->db,
   101             SQLITE_OPEN_READWRITE
   102                 | SQLITE_OPEN_CREATE
   103                 | SQLITE_OPEN_FULLMUTEX
   104                 | SQLITE_OPEN_PRIVATECACHE,
   105             NULL 
   106         );
   107 
   108     if (int_result != SQLITE_OK) {
   109         status = PEP_INIT_CANNOT_OPEN_DB;
   110         goto pep_error;
   111     }
   112 
   113     sqlite3_busy_timeout(_session->db, BUSY_WAIT_TIME);
   114 
   115     assert(SYSTEM_DB);
   116     if (SYSTEM_DB == NULL) {
   117         status = PEP_INIT_CANNOT_OPEN_SYSTEM_DB;
   118         goto pep_error;
   119     }
   120 
   121     int_result = sqlite3_open_v2(
   122             SYSTEM_DB, &_session->system_db,
   123             SQLITE_OPEN_READONLY
   124                 | SQLITE_OPEN_FULLMUTEX
   125                 | SQLITE_OPEN_SHAREDCACHE,
   126             NULL
   127         );
   128 
   129     if (int_result != SQLITE_OK) {
   130         status = PEP_INIT_CANNOT_OPEN_SYSTEM_DB;
   131         goto pep_error;
   132     }
   133 
   134     sqlite3_busy_timeout(_session->system_db, 1000);
   135 
   136 // increment this when patching DDL
   137 #define _DDL_USER_VERSION "4"
   138 
   139     if (in_first) {
   140 
   141         int_result = sqlite3_exec(
   142             _session->db,
   143                 "create table if not exists version_info (\n"
   144                 "   id integer primary key,\n"
   145                 "   timestamp integer default (datetime('now')),\n"
   146                 "   version text,\n"
   147                 "   comment text\n"
   148                 ");\n",
   149                 NULL,
   150                 NULL,
   151                 NULL
   152         );
   153         int_result = sqlite3_exec(
   154             _session->db,
   155                 "PRAGMA application_id = 0x23423423;\n"
   156                 "create table if not exists log (\n"
   157                 "   timestamp integer default (datetime('now')),\n"
   158                 "   title text not null,\n"
   159                 "   entity text not null,\n"
   160                 "   description text,\n"
   161                 "   comment text\n"
   162                 ");\n"
   163                 "create index if not exists log_timestamp on log (\n"
   164                 "   timestamp\n"
   165                 ");\n"
   166                 "create table if not exists pgp_keypair (\n"
   167                 "   fpr text primary key,\n"
   168                 "   created integer,\n"
   169                 "   expires integer,\n"
   170                 "   comment text,\n"
   171                 "   flags integer default 0\n"
   172                 ");\n"
   173                 "create index if not exists pgp_keypair_expires on pgp_keypair (\n"
   174                 "   expires\n"
   175                 ");\n"
   176                 "create table if not exists person (\n"
   177                 "   id text primary key,\n"
   178                 "   username text not null,\n"
   179                 "   main_key_id text\n"
   180                 "       references pgp_keypair (fpr)\n"
   181                 "       on delete set null,\n"
   182                 "   lang text,\n"
   183                 "   comment text,\n"
   184                 "   device_group text\n"
   185                 ");\n"
   186                 "create table if not exists identity (\n"
   187                 "   address text,\n"
   188                 "   user_id text\n"
   189                 "       references person (id)\n"
   190                 "       on delete cascade,\n"
   191                 "   main_key_id text\n"
   192                 "       references pgp_keypair (fpr)\n"
   193                 "       on delete set null,\n"
   194                 "   comment text,\n"
   195                 "   flags integer default 0,"
   196                 "   primary key (address, user_id)\n"
   197                 ");\n"
   198                 "create table if not exists trust (\n"
   199                 "   user_id text not null\n"
   200                 "       references person (id)\n"
   201                 "       on delete cascade,\n"
   202                 "   pgp_keypair_fpr text not null\n"
   203                 "       references pgp_keypair (fpr)\n"
   204                 "       on delete cascade,\n"
   205                 "   comm_type integer not null,\n"
   206                 "   comment text,\n"
   207                 "   primary key (user_id, pgp_keypair_fpr)\n"
   208                 ");\n"
   209                 // blacklist
   210                 "create table if not exists blacklist_keys (\n"
   211                 "   fpr text primary key\n"
   212                 ");\n"
   213                 // sequences
   214                 "create table if not exists sequences(\n"
   215                 "   name text primary key,\n"
   216                 "   value integer default 0,\n"
   217                 "   own integer default 0\n"
   218                 ");\n"
   219                 "create table if not exists revoked_keys (\n"
   220                 "   revoked_fpr text primary key,\n"
   221                 "   replacement_fpr text not null\n"
   222                 "       references pgp_keypair (fpr)\n"
   223                 "       on delete cascade,\n"
   224                 "   revocation_date integer\n"
   225                 ");\n"
   226                 "create table if not exists own_keys (\n"
   227                 "   address text,\n"
   228                 "   user_id text,\n"
   229                 "   fpr text not null\n"
   230                 "       references pgp_keypair (fpr)\n"
   231                 "       on delete cascade,\n"
   232                 "   foreign key (address, user_id)\n"
   233                 "       references identity\n"
   234                 "       on delete cascade,\n"
   235                 "   check (user_id = '" PEP_OWN_USERID "')\n"
   236                 "   primary key (address, fpr)\n"
   237                 ");\n" 
   238                 ,
   239             NULL,
   240             NULL,
   241             NULL
   242         );
   243         assert(int_result == SQLITE_OK);
   244 
   245         int version;
   246         int_result = sqlite3_exec(
   247             _session->db,
   248             "pragma user_version;",
   249             user_version,
   250             &version,
   251             NULL
   252         );
   253         assert(int_result == SQLITE_OK);
   254 
   255         if (version < 1) {
   256             int_result = sqlite3_exec(
   257                 _session->db,
   258                 "alter table identity\n"
   259                 "   add column flags integer default 0;\n",
   260                 NULL,
   261                 NULL,
   262                 NULL
   263             );
   264         }
   265 
   266         if (version < 2) {
   267             int_result = sqlite3_exec(
   268                 _session->db,
   269                 "alter table pgp_keypair\n"
   270                 "   add column flags integer default 0;\n"
   271                 "alter table person\n"
   272                 "   add column device_group text;\n",
   273                 NULL,
   274                 NULL,
   275                 NULL
   276             );
   277         }
   278 
   279         if (version < 3) {
   280             int_result = sqlite3_exec(
   281                 _session->db,
   282                 "alter table sequences\n"
   283                 "   add column own integer default 0;\n",
   284                 NULL,
   285                 NULL,
   286                 NULL
   287             );
   288         }
   289 
   290         if (version < atoi(_DDL_USER_VERSION)) {
   291             int_result = sqlite3_exec(
   292                 _session->db,
   293                 "pragma user_version = "_DDL_USER_VERSION";\n"
   294                 "insert or replace into version_info (id, version)"
   295                     "values (1, '" PEP_ENGINE_VERSION "');",
   296                 NULL,
   297                 NULL,
   298                 NULL
   299             );
   300             assert(int_result == SQLITE_OK);
   301         }
   302 
   303         sql_log = "insert into log (title, entity, description, comment)"
   304                   "values (?1, ?2, ?3, ?4);";
   305 
   306         sql_get_identity =  "select fpr, username, comm_type, lang,"
   307                             "   identity.flags | pgp_keypair.flags"
   308                             "   from identity"
   309                             "   join person on id = identity.user_id"
   310                             "   join pgp_keypair on fpr = identity.main_key_id"
   311                             "   join trust on id = trust.user_id"
   312                             "       and pgp_keypair_fpr = identity.main_key_id"
   313                             "   where address = ?1 and identity.user_id = ?2;";
   314 
   315         sql_trustword = "select id, word from wordlist where lang = lower(?1) "
   316                        "and id = ?2 ;";
   317 
   318         // Set person, but if already exist, only update.
   319         // if main_key_id already set, don't touch.
   320         sql_set_person = "insert or replace into person (id, username, lang, main_key_id, device_group)"
   321                          "  values (?1, ?2, ?3,"
   322                          "    (select coalesce((select main_key_id from person "
   323                          "      where id = ?1), upper(replace(?4,' ','')))),"
   324                          "    (select device_group from person where id = ?1)) ;";
   325 
   326         sql_set_device_group = "update person set device_group = ?1 "
   327                                "where id = '" PEP_OWN_USERID "';";
   328 
   329         sql_get_device_group = "select device_group from person "
   330                                "where id = '" PEP_OWN_USERID "';";
   331 
   332         sql_set_pgp_keypair = "insert or replace into pgp_keypair (fpr) "
   333                               "values (upper(replace(?1,' ',''))) ;";
   334 
   335         sql_set_identity = "insert or replace into identity ("
   336                            " address, main_key_id, "
   337                            " user_id, flags"
   338                            ") values ("
   339                            " ?1,"
   340                            " upper(replace(?2,' ','')),"
   341                            " ?3,"
   342                            // " (select"
   343                            // "   coalesce("
   344                            // "    (select flags from identity"
   345                            // "     where address = ?1 and"
   346                            // "           user_id = ?3),"
   347                            // "    0)"
   348                            // " ) | (?4 & 255)"
   349                            /* set_identity ignores previous flags, and doesn't filter machine flags */
   350                            " ?4"
   351                            ");";
   352         
   353         sql_set_identity_flags = "update identity set flags = "
   354                                  "    ((?1 & 255) | (select flags from identity"
   355                                  "                   where address = ?2 and user_id = ?3)) "
   356                                  "where address = ?2 and user_id = ?3 ;";
   357 
   358         sql_unset_identity_flags = 
   359                                  "update identity set flags = "
   360                                  "    ( ~(?1 & 255) & (select flags from identity"
   361                                  "                   where address = ?2 and user_id = ?3)) "
   362                                  "where address = ?2 and user_id = ?3 ;";
   363 
   364         sql_set_trust = "insert or replace into trust (user_id, pgp_keypair_fpr, comm_type) "
   365                         "values (?1, upper(replace(?2,' ','')), ?3) ;";
   366 
   367         sql_get_trust = "select comm_type from trust where user_id = ?1 "
   368                         "and pgp_keypair_fpr = upper(replace(?2,' ','')) ;";
   369 
   370         sql_least_trust = "select min(comm_type) from trust where pgp_keypair_fpr = upper(replace(?1,' ','')) ;";
   371 
   372         sql_mark_as_compromized = "update trust not indexed set comm_type = 15"
   373                                   " where pgp_keypair_fpr = upper(replace(?1,' ','')) ;";
   374 
   375         sql_crashdump = "select timestamp, title, entity, description, comment"
   376                         " from log order by timestamp desc limit ?1 ;";
   377 
   378         sql_languagelist = "select i18n_language.lang, name, phrase from i18n_language join i18n_token using (lang) where i18n_token.id = 1000;" ;
   379 
   380         sql_i18n_token = "select phrase from i18n_token where lang = lower(?1) and id = ?2 ;";
   381 
   382         // blacklist
   383 
   384         sql_blacklist_add = "insert or replace into blacklist_keys (fpr) values (upper(replace(?1,' ',''))) ;"
   385                             "delete from identity where main_key_id = upper(replace(?1,' ','')) ;"
   386                             "delete from pgp_keypair where fpr = upper(replace(?1,' ','')) ;";
   387 
   388         sql_blacklist_delete = "delete from blacklist_keys where fpr = upper(replace(?1,' ','')) ;";
   389 
   390         sql_blacklist_is_listed = "select count(*) from blacklist_keys where fpr = upper(replace(?1,' ','')) ;";
   391 
   392         sql_blacklist_retrieve = "select * from blacklist_keys ;";
   393                 
   394         // Own keys
   395         
   396         sql_own_key_is_listed = "select count(*) from ("
   397                                 " select main_key_id from person "
   398                                 "   where main_key_id = upper(replace(?1,' ',''))"
   399                                 "    and id = '" PEP_OWN_USERID "' "
   400                                 " union "
   401                                 "  select main_key_id from identity "
   402                                 "   where main_key_id = upper(replace(?1,' ',''))"
   403                                 "    and user_id = '" PEP_OWN_USERID "' );";
   404 
   405         sql_own_identities_retrieve =  
   406                             "select address, fpr, username, "
   407                             "   lang, identity.flags | pgp_keypair.flags"
   408                             "   from identity"
   409                             "   join person on id = identity.user_id"
   410                             "   join pgp_keypair on fpr = identity.main_key_id"
   411                             "   join trust on id = trust.user_id"
   412                             "       and pgp_keypair_fpr = identity.main_key_id"
   413                             "   where identity.user_id = '" PEP_OWN_USERID "';";
   414         
   415         sql_own_keys_retrieve =  
   416                             "select fpr from own_keys"
   417                             "   join identity"
   418                             "   where identity.flags & 1 = 0;"; // PEP_idf_not_for_sync
   419 
   420         sql_set_own_key = "insert or replace into own_keys (address, user_id, fpr)"
   421                           " values (?1, '" PEP_OWN_USERID "', upper(replace(?2,' ','')));";
   422 
   423         sql_sequence_value1 = "insert or replace into sequences (name, value, own) "
   424                               "values (?1, "
   425                               "(select coalesce((select value + 1 from sequences "
   426                               "where name = ?1), 1 )), ?2) ; ";
   427         sql_sequence_value2 = "select value, own from sequences where name = ?1 ;";
   428         sql_sequence_value3 = "update sequences set value = ?2, own = ?3 where name = ?1 ;";
   429         
   430         sql_set_revoked =     "insert or replace into revoked_keys ("
   431                               "    revoked_fpr, replacement_fpr, revocation_date) "
   432                               "values (upper(replace(?1,' ','')),"
   433                               "        upper(replace(?2,' ','')),"
   434                               "        ?3) ;";
   435         
   436         sql_get_revoked =     "select revoked_fpr, revocation_date from revoked_keys"
   437                               "    where replacement_fpr = upper(replace(?1,' ','')) ;";
   438     }
   439 
   440     int_result = sqlite3_prepare_v2(_session->db, sql_log,
   441             (int)strlen(sql_log), &_session->log, NULL);
   442     assert(int_result == SQLITE_OK);
   443 
   444     int_result = sqlite3_prepare_v2(_session->system_db, sql_trustword,
   445             (int)strlen(sql_trustword), &_session->trustword, NULL);
   446     assert(int_result == SQLITE_OK);
   447 
   448     int_result = sqlite3_prepare_v2(_session->db, sql_get_identity,
   449             (int)strlen(sql_get_identity), &_session->get_identity, NULL);
   450     assert(int_result == SQLITE_OK);
   451 
   452     int_result = sqlite3_prepare_v2(_session->db, sql_set_person,
   453             (int)strlen(sql_set_person), &_session->set_person, NULL);
   454     assert(int_result == SQLITE_OK);
   455 
   456     int_result = sqlite3_prepare_v2(_session->db, sql_set_device_group,
   457             (int)strlen(sql_set_device_group), &_session->set_device_group, NULL);
   458     assert(int_result == SQLITE_OK);
   459 
   460     int_result = sqlite3_prepare_v2(_session->db, sql_get_device_group,
   461             (int)strlen(sql_get_device_group), &_session->get_device_group, NULL);
   462     assert(int_result == SQLITE_OK);
   463 
   464     int_result = sqlite3_prepare_v2(_session->db, sql_set_pgp_keypair,
   465             (int)strlen(sql_set_pgp_keypair), &_session->set_pgp_keypair,
   466             NULL);
   467     assert(int_result == SQLITE_OK);
   468 
   469     int_result = sqlite3_prepare_v2(_session->db, sql_set_identity,
   470             (int)strlen(sql_set_identity), &_session->set_identity, NULL);
   471     assert(int_result == SQLITE_OK);
   472 
   473     int_result = sqlite3_prepare_v2(_session->db, sql_set_identity_flags,
   474             (int)strlen(sql_set_identity_flags), &_session->set_identity_flags,
   475             NULL);
   476     assert(int_result == SQLITE_OK);
   477 
   478     int_result = sqlite3_prepare_v2(_session->db, sql_unset_identity_flags,
   479             (int)strlen(sql_unset_identity_flags), &_session->unset_identity_flags,
   480             NULL);
   481     assert(int_result == SQLITE_OK);
   482 
   483     int_result = sqlite3_prepare_v2(_session->db, sql_set_trust,
   484             (int)strlen(sql_set_trust), &_session->set_trust, NULL);
   485     assert(int_result == SQLITE_OK);
   486 
   487     int_result = sqlite3_prepare_v2(_session->db, sql_get_trust,
   488             (int)strlen(sql_get_trust), &_session->get_trust, NULL);
   489     assert(int_result == SQLITE_OK);
   490 
   491     int_result = sqlite3_prepare_v2(_session->db, sql_least_trust,
   492             (int)strlen(sql_least_trust), &_session->least_trust, NULL);
   493     assert(int_result == SQLITE_OK);
   494 
   495     int_result = sqlite3_prepare_v2(_session->db, sql_mark_as_compromized,
   496             (int)strlen(sql_mark_as_compromized), &_session->mark_compromized,
   497             NULL);
   498     assert(int_result == SQLITE_OK);
   499 
   500     int_result = sqlite3_prepare_v2(_session->db, sql_crashdump,
   501             (int)strlen(sql_crashdump), &_session->crashdump, NULL);
   502     assert(int_result == SQLITE_OK);
   503 
   504     int_result = sqlite3_prepare_v2(_session->system_db, sql_languagelist,
   505             (int)strlen(sql_languagelist), &_session->languagelist, NULL);
   506     assert(int_result == SQLITE_OK);
   507 
   508     int_result = sqlite3_prepare_v2(_session->system_db, sql_i18n_token,
   509             (int)strlen(sql_i18n_token), &_session->i18n_token, NULL);
   510     assert(int_result == SQLITE_OK);
   511 
   512     // blacklist
   513 
   514     int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_add,
   515             (int)strlen(sql_blacklist_add), &_session->blacklist_add, NULL);
   516     assert(int_result == SQLITE_OK);
   517 
   518     int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_delete,
   519             (int)strlen(sql_blacklist_delete), &_session->blacklist_delete,
   520             NULL);
   521     assert(int_result == SQLITE_OK);
   522 
   523     int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_is_listed,
   524             (int)strlen(sql_blacklist_is_listed),
   525             &_session->blacklist_is_listed, NULL);
   526     assert(int_result == SQLITE_OK);
   527 
   528     int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_retrieve,
   529             (int)strlen(sql_blacklist_retrieve), &_session->blacklist_retrieve,
   530             NULL);
   531     assert(int_result == SQLITE_OK);
   532     
   533     // Own keys
   534     
   535     int_result = sqlite3_prepare_v2(_session->db, sql_own_key_is_listed,
   536             (int)strlen(sql_own_key_is_listed), &_session->own_key_is_listed,
   537             NULL);
   538     assert(int_result == SQLITE_OK);
   539     
   540     int_result = sqlite3_prepare_v2(_session->db, sql_own_identities_retrieve,
   541             (int)strlen(sql_own_identities_retrieve),
   542             &_session->own_identities_retrieve, NULL);
   543     assert(int_result == SQLITE_OK);
   544  
   545     int_result = sqlite3_prepare_v2(_session->db, sql_own_keys_retrieve,
   546             (int)strlen(sql_own_keys_retrieve),
   547             &_session->own_keys_retrieve, NULL);
   548     assert(int_result == SQLITE_OK);
   549  
   550     int_result = sqlite3_prepare_v2(_session->db, sql_set_own_key,
   551             (int)strlen(sql_set_own_key),
   552             &_session->set_own_key, NULL);
   553     assert(int_result == SQLITE_OK);
   554  
   555     // Sequence
   556 
   557     int_result = sqlite3_prepare_v2(_session->db, sql_sequence_value1,
   558             (int)strlen(sql_sequence_value1), &_session->sequence_value1,
   559             NULL);
   560     assert(int_result == SQLITE_OK);
   561 
   562     int_result = sqlite3_prepare_v2(_session->db, sql_sequence_value2,
   563             (int)strlen(sql_sequence_value2), &_session->sequence_value2,
   564             NULL);
   565     assert(int_result == SQLITE_OK);
   566 
   567     int_result = sqlite3_prepare_v2(_session->db, sql_sequence_value3,
   568             (int)strlen(sql_sequence_value3), &_session->sequence_value3,
   569             NULL);
   570     assert(int_result == SQLITE_OK);
   571 
   572     // Revocation tracking
   573     
   574     int_result = sqlite3_prepare_v2(_session->db, sql_set_revoked,
   575             (int)strlen(sql_set_revoked), &_session->set_revoked, NULL);
   576     assert(int_result == SQLITE_OK);
   577     
   578     int_result = sqlite3_prepare_v2(_session->db, sql_get_revoked,
   579             (int)strlen(sql_get_revoked), &_session->get_revoked, NULL);
   580     assert(int_result == SQLITE_OK);
   581     
   582     status = init_cryptotech(_session, in_first);
   583     if (status != PEP_STATUS_OK)
   584         goto pep_error;
   585 
   586     status = init_transport_system(_session, in_first);
   587     if (status != PEP_STATUS_OK)
   588         goto pep_error;
   589 
   590     status = log_event(_session, "init", "pEp " PEP_ENGINE_VERSION, NULL, NULL);
   591     if (status != PEP_STATUS_OK)
   592         goto pep_error;
   593 
   594     // runtime config
   595 
   596 #ifdef ANDROID
   597     _session->use_only_own_private_keys = true;
   598 #elif TARGET_OS_IPHONE
   599     _session->use_only_own_private_keys = true;
   600 #else
   601     _session->use_only_own_private_keys = false;
   602 #endif
   603 
   604     *session = _session;
   605     return PEP_STATUS_OK;
   606 
   607 enomem:
   608     status = PEP_OUT_OF_MEMORY;
   609 
   610 pep_error:
   611     release(_session);
   612     return status;
   613 }
   614 
   615 DYNAMIC_API void release(PEP_SESSION session)
   616 {
   617     bool out_last = false;
   618 
   619     assert(init_count >= 0);
   620     assert(session);
   621 
   622     if (!((init_count >= 0) && session))
   623         return;
   624 
   625     // a small race condition but still a race condition
   626     // mitigated by calling caveat (see documentation)
   627 
   628     if (init_count == 0)
   629         out_last = true;
   630     --init_count;
   631 
   632     if (session) {
   633         if (session->sync_state != DeviceState_state_NONE)
   634             unregister_sync_callbacks(session);
   635 
   636         if (session->db) {
   637             if (session->log)
   638                 sqlite3_finalize(session->log);
   639             if (session->trustword)
   640                 sqlite3_finalize(session->trustword);
   641             if (session->get_identity)
   642                 sqlite3_finalize(session->get_identity);
   643             if (session->set_person)
   644                 sqlite3_finalize(session->set_person);
   645             if (session->set_device_group)
   646                 sqlite3_finalize(session->set_device_group);
   647             if (session->get_device_group)
   648                 sqlite3_finalize(session->get_device_group);
   649             if (session->set_pgp_keypair)
   650                 sqlite3_finalize(session->set_pgp_keypair);
   651             if (session->set_identity)
   652                 sqlite3_finalize(session->set_identity);
   653             if (session->set_identity_flags)
   654                 sqlite3_finalize(session->set_identity_flags);
   655             if (session->unset_identity_flags)
   656                 sqlite3_finalize(session->unset_identity_flags);
   657             if (session->set_trust)
   658                 sqlite3_finalize(session->set_trust);
   659             if (session->get_trust)
   660                 sqlite3_finalize(session->get_trust);
   661             if (session->least_trust)
   662                 sqlite3_finalize(session->least_trust);
   663             if (session->mark_compromized)
   664                 sqlite3_finalize(session->mark_compromized);
   665             if (session->crashdump)
   666                 sqlite3_finalize(session->crashdump);
   667             if (session->languagelist)
   668                 sqlite3_finalize(session->languagelist);
   669             if (session->i18n_token)
   670                 sqlite3_finalize(session->i18n_token);
   671             if (session->blacklist_add)
   672                 sqlite3_finalize(session->blacklist_add);
   673             if (session->blacklist_delete)
   674                 sqlite3_finalize(session->blacklist_delete);
   675             if (session->blacklist_is_listed)
   676                 sqlite3_finalize(session->blacklist_is_listed);
   677             if (session->blacklist_retrieve)
   678                 sqlite3_finalize(session->blacklist_retrieve);
   679             if (session->own_key_is_listed)
   680                 sqlite3_finalize(session->own_key_is_listed);
   681             if (session->own_identities_retrieve)
   682                 sqlite3_finalize(session->own_identities_retrieve);
   683             if (session->own_keys_retrieve)
   684                 sqlite3_finalize(session->own_keys_retrieve);
   685             if (session->set_own_key)
   686                 sqlite3_finalize(session->set_own_key);
   687             if (session->sequence_value1)
   688                 sqlite3_finalize(session->sequence_value1);
   689             if (session->sequence_value2)
   690                 sqlite3_finalize(session->sequence_value2);
   691             if (session->sequence_value3)
   692                 sqlite3_finalize(session->sequence_value3);
   693             if (session->set_revoked)
   694                 sqlite3_finalize(session->set_revoked);
   695             if (session->get_revoked)
   696                 sqlite3_finalize(session->get_revoked);
   697 
   698             if (session->db)
   699                 sqlite3_close_v2(session->db);
   700             if (session->system_db)
   701                 sqlite3_close_v2(session->system_db);
   702         }
   703 
   704         release_transport_system(session, out_last);
   705         release_cryptotech(session, out_last);
   706 
   707         free(session);
   708     }
   709 }
   710 
   711 DYNAMIC_API void config_passive_mode(PEP_SESSION session, bool enable)
   712 {
   713     assert(session);
   714     session->passive_mode = enable;
   715 }
   716 
   717 DYNAMIC_API void config_unencrypted_subject(PEP_SESSION session, bool enable)
   718 {
   719     assert(session);
   720     session->unencrypted_subject = enable;
   721 }
   722 
   723 DYNAMIC_API void config_use_only_own_private_keys(PEP_SESSION session,
   724         bool enable)
   725 {
   726     assert(session);
   727     session->use_only_own_private_keys = enable;
   728 }
   729 
   730 DYNAMIC_API void config_keep_sync_msg(PEP_SESSION session, bool enable)
   731 {
   732     assert(session);
   733     session->keep_sync_msg = enable;
   734 }
   735 
   736 DYNAMIC_API PEP_STATUS log_event(
   737         PEP_SESSION session,
   738         const char *title,
   739         const char *entity,
   740         const char *description,
   741         const char *comment
   742     )
   743 {
   744     PEP_STATUS status = PEP_STATUS_OK;
   745     int result;
   746 
   747     assert(session);
   748     assert(title);
   749     assert(entity);
   750 
   751     if (!(session && title && entity))
   752         return PEP_ILLEGAL_VALUE;
   753 
   754     sqlite3_reset(session->log);
   755     sqlite3_bind_text(session->log, 1, title, -1, SQLITE_STATIC);
   756     sqlite3_bind_text(session->log, 2, entity, -1, SQLITE_STATIC);
   757     if (description)
   758         sqlite3_bind_text(session->log, 3, description, -1, SQLITE_STATIC);
   759     else
   760         sqlite3_bind_null(session->log, 3);
   761     if (comment)
   762         sqlite3_bind_text(session->log, 4, comment, -1, SQLITE_STATIC);
   763     else
   764         sqlite3_bind_null(session->log, 4);
   765     do {
   766         result = sqlite3_step(session->log);
   767         assert(result == SQLITE_DONE || result == SQLITE_BUSY);
   768         if (result != SQLITE_DONE && result != SQLITE_BUSY)
   769             status = PEP_UNKNOWN_ERROR;
   770     } while (result == SQLITE_BUSY);
   771     sqlite3_reset(session->log);
   772 
   773     return status;
   774 }
   775 
   776 DYNAMIC_API PEP_STATUS trustword(
   777             PEP_SESSION session, uint16_t value, const char *lang,
   778             char **word, size_t *wsize
   779         )
   780 {
   781     PEP_STATUS status = PEP_STATUS_OK;
   782 
   783     assert(session);
   784     assert(word);
   785     assert(wsize);
   786 
   787     if (!(session && word && wsize))
   788         return PEP_ILLEGAL_VALUE;
   789 
   790     *word = NULL;
   791     *wsize = 0;
   792 
   793     if (lang == NULL)
   794         lang = "en";
   795 
   796     assert((lang[0] >= 'A' && lang[0] <= 'Z')
   797             || (lang[0] >= 'a' && lang[0] <= 'z'));
   798     assert((lang[1] >= 'A' && lang[1] <= 'Z')
   799             || (lang[1] >= 'a' && lang[1] <= 'z'));
   800     assert(lang[2] == 0);
   801 
   802     sqlite3_reset(session->trustword);
   803     sqlite3_bind_text(session->trustword, 1, lang, -1, SQLITE_STATIC);
   804     sqlite3_bind_int(session->trustword, 2, value);
   805 
   806     const int result = sqlite3_step(session->trustword);
   807     if (result == SQLITE_ROW) {
   808         *word = strdup((const char *) sqlite3_column_text(session->trustword,
   809                     1));
   810         if (*word)
   811             *wsize = sqlite3_column_bytes(session->trustword, 1);
   812         else
   813             status = PEP_OUT_OF_MEMORY;
   814     } else
   815         status = PEP_TRUSTWORD_NOT_FOUND;
   816 
   817     sqlite3_reset(session->trustword);
   818     return status;
   819 }
   820 
   821 DYNAMIC_API PEP_STATUS trustwords(
   822         PEP_SESSION session, const char *fingerprint, const char *lang,
   823         char **words, size_t *wsize, int max_words
   824     )
   825 {
   826     const char *source = fingerprint;
   827     char *buffer;
   828     char *dest;
   829     size_t fsize;
   830 
   831     assert(session);
   832     assert(fingerprint);
   833     assert(words);
   834     assert(wsize);
   835     assert(max_words >= 0);
   836 
   837     if (!(session && fingerprint && words && wsize && max_words >= 0))
   838         return PEP_ILLEGAL_VALUE;
   839 
   840     *words = NULL;
   841     *wsize = 0;
   842 
   843     buffer = calloc(1, MAX_TRUSTWORDS_SPACE);
   844     assert(buffer);
   845     if (buffer == NULL)
   846         return PEP_OUT_OF_MEMORY;
   847     dest = buffer;
   848 
   849     fsize = strlen(fingerprint);
   850 
   851     if (!lang || !lang[0])
   852         lang = "en";
   853 
   854     assert((lang[0] >= 'A' && lang[0] <= 'Z')
   855             || (lang[0] >= 'a' && lang[0] <= 'z'));
   856     assert((lang[1] >= 'A' && lang[1] <= 'Z')
   857             || (lang[1] >= 'a' && lang[1] <= 'z'));
   858     assert(lang[2] == 0);
   859 
   860     int n_words = 0;
   861     while (source < fingerprint + fsize) {
   862         PEP_STATUS _status;
   863         uint16_t value;
   864         char *word;
   865         size_t _wsize;
   866         int j;
   867 
   868         for (value=0, j=0; j < 4 && source < fingerprint + fsize; ) {
   869             if (*source >= 'a' && *source <= 'f')
   870                 value += (*source - 'a' + 10) << (3 - j++) * 4;
   871             else if (*source >= 'A' && *source <= 'F')
   872                 value += (*source - 'A' + 10) << (3 - j++) * 4;
   873             else if (*source >= '0' && *source <= '9')
   874                 value += (*source - '0') << (3 - j++) * 4;
   875             
   876             source++;
   877         }
   878 
   879         _status = trustword(session, value, lang, &word, &_wsize);
   880         if (_status == PEP_OUT_OF_MEMORY) {
   881             free(buffer);
   882             return PEP_OUT_OF_MEMORY;
   883         }
   884         if (word == NULL) {
   885             free(buffer);
   886             return PEP_TRUSTWORD_NOT_FOUND;
   887         }
   888 
   889         if (dest + _wsize < buffer + MAX_TRUSTWORDS_SPACE - 1) {
   890             strncpy(dest, word, _wsize);
   891             free(word);
   892             dest += _wsize;
   893         }
   894         else {
   895             free(word);
   896             break; // buffer full
   897         }
   898 
   899         if (source < fingerprint + fsize
   900                 && dest + _wsize < buffer + MAX_TRUSTWORDS_SPACE - 1)
   901             *dest++ = ' ';
   902 
   903         ++n_words;
   904         if (max_words && n_words >= max_words)
   905             break;
   906     }
   907 
   908     *words = buffer;
   909     *wsize = dest - buffer;
   910     return PEP_STATUS_OK;
   911 }
   912 
   913 pEp_identity *new_identity(
   914         const char *address, const char *fpr, const char *user_id,
   915         const char *username
   916     )
   917 {
   918     pEp_identity *result = calloc(1, sizeof(pEp_identity));
   919     assert(result);
   920     if (result) {
   921         if (address) {
   922             result->address = strdup(address);
   923             assert(result->address);
   924             if (result->address == NULL) {
   925                 free(result);
   926                 return NULL;
   927             }
   928         }
   929         if (fpr) {
   930             result->fpr = strdup(fpr);
   931             assert(result->fpr);
   932             if (result->fpr == NULL) {
   933                 free_identity(result);
   934                 return NULL;
   935             }
   936         }
   937         if (user_id) {
   938             result->user_id = strdup(user_id);
   939             assert(result->user_id);
   940             if (result->user_id == NULL) {
   941                 free_identity(result);
   942                 return NULL;
   943             }
   944         }
   945         if (username) {
   946             result->username = strdup(username);
   947             assert(result->username);
   948             if (result->username == NULL) {
   949                 free_identity(result);
   950                 return NULL;
   951             }
   952         }
   953     }
   954     return result;
   955 }
   956 
   957 pEp_identity *identity_dup(const pEp_identity *src)
   958 {
   959     assert(src);
   960 
   961     pEp_identity *dup = new_identity(src->address, src->fpr, src->user_id,
   962             src->username);
   963     assert(dup);
   964     if (dup == NULL)
   965         return NULL;
   966     
   967     dup->comm_type = src->comm_type;
   968     dup->lang[0] = src->lang[0];
   969     dup->lang[1] = src->lang[1];
   970     dup->lang[2] = 0;
   971     dup->me = src->me;
   972     dup->flags = src->flags;
   973 
   974     return dup;
   975 }
   976 
   977 void free_identity(pEp_identity *identity)
   978 {
   979     if (identity) {
   980         free(identity->address);
   981         free(identity->fpr);
   982         free(identity->user_id);
   983         free(identity->username);
   984         free(identity);
   985     }
   986 }
   987 
   988 DYNAMIC_API PEP_STATUS get_identity(
   989         PEP_SESSION session,
   990         const char *address,
   991         const char *user_id,
   992         pEp_identity **identity
   993     )
   994 {
   995     PEP_STATUS status = PEP_STATUS_OK;
   996     static pEp_identity *_identity;
   997 
   998     assert(session);
   999     assert(address);
  1000     assert(address[0]);
  1001     assert(identity);
  1002 
  1003     if (!(session && address && address[0] && identity))
  1004         return PEP_ILLEGAL_VALUE;
  1005 
  1006     *identity = NULL;
  1007 
  1008     sqlite3_reset(session->get_identity);
  1009     sqlite3_bind_text(session->get_identity, 1, address, -1, SQLITE_STATIC);
  1010     sqlite3_bind_text(session->get_identity, 2, user_id, -1, SQLITE_STATIC);
  1011 
  1012     const int result = sqlite3_step(session->get_identity);
  1013     switch (result) {
  1014     case SQLITE_ROW:
  1015         _identity = new_identity(
  1016                 address,
  1017                 (const char *) sqlite3_column_text(session->get_identity, 0),
  1018                 user_id,
  1019                 (const char *) sqlite3_column_text(session->get_identity, 1)
  1020                 );
  1021         assert(_identity);
  1022         if (_identity == NULL)
  1023             return PEP_OUT_OF_MEMORY;
  1024 
  1025         _identity->comm_type = (PEP_comm_type)
  1026             sqlite3_column_int(session->get_identity, 2);
  1027         const char* const _lang = (const char *)
  1028             sqlite3_column_text(session->get_identity, 3);
  1029         if (_lang && _lang[0]) {
  1030             assert(_lang[0] >= 'a' && _lang[0] <= 'z');
  1031             assert(_lang[1] >= 'a' && _lang[1] <= 'z');
  1032             assert(_lang[2] == 0);
  1033             _identity->lang[0] = _lang[0];
  1034             _identity->lang[1] = _lang[1];
  1035             _identity->lang[2] = 0;
  1036         }
  1037         _identity->flags = (unsigned int)
  1038             sqlite3_column_int(session->get_identity, 4);
  1039         *identity = _identity;
  1040         break;
  1041     default:
  1042         status = PEP_CANNOT_FIND_IDENTITY;
  1043         *identity = NULL;
  1044     }
  1045 
  1046     sqlite3_reset(session->get_identity);
  1047     return status;
  1048 }
  1049 
  1050 DYNAMIC_API PEP_STATUS set_identity(
  1051         PEP_SESSION session, const pEp_identity *identity
  1052     )
  1053 {
  1054     int result;
  1055 
  1056     assert(session);
  1057     assert(identity);
  1058     assert(identity->address);
  1059     assert(identity->user_id);
  1060     assert(identity->username);
  1061 
  1062     if (!(session && identity && identity->address &&
  1063                 identity->user_id && identity->username))
  1064         return PEP_ILLEGAL_VALUE;
  1065 
  1066     bool listed;
  1067     
  1068     if (identity->fpr && identity->fpr[0] != '\0') {
  1069         
  1070         // blacklist check
  1071         PEP_STATUS status = blacklist_is_listed(session, identity->fpr, &listed);
  1072         assert(status == PEP_STATUS_OK);
  1073         if (status != PEP_STATUS_OK)
  1074             return status;
  1075 
  1076         if (listed)
  1077             return PEP_KEY_BLACKLISTED;
  1078         
  1079     }
  1080 
  1081     sqlite3_exec(session->db, "BEGIN ;", NULL, NULL, NULL);
  1082 
  1083     if (identity->lang[0]) {
  1084         assert(identity->lang[0] >= 'a' && identity->lang[0] <= 'z');
  1085         assert(identity->lang[1] >= 'a' && identity->lang[1] <= 'z');
  1086         assert(identity->lang[2] == 0);
  1087     }
  1088 
  1089     sqlite3_reset(session->set_person);
  1090     sqlite3_bind_text(session->set_person, 1, identity->user_id, -1,
  1091             SQLITE_STATIC);
  1092     sqlite3_bind_text(session->set_person, 2, identity->username, -1,
  1093             SQLITE_STATIC);
  1094     if (identity->lang[0])
  1095         sqlite3_bind_text(session->set_person, 3, identity->lang, 2,
  1096                 SQLITE_STATIC);
  1097     else
  1098         sqlite3_bind_null(session->set_person, 3);
  1099     sqlite3_bind_text(session->set_person, 4, identity->fpr, -1,
  1100                       SQLITE_STATIC);
  1101     result = sqlite3_step(session->set_person);
  1102     sqlite3_reset(session->set_person);
  1103     if (result != SQLITE_DONE) {
  1104         sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
  1105         return PEP_CANNOT_SET_PERSON;
  1106     }
  1107 
  1108     sqlite3_reset(session->set_pgp_keypair);
  1109     sqlite3_bind_text(session->set_pgp_keypair, 1, identity->fpr, -1,
  1110             SQLITE_STATIC);
  1111     result = sqlite3_step(session->set_pgp_keypair);
  1112     sqlite3_reset(session->set_pgp_keypair);
  1113     if (result != SQLITE_DONE) {
  1114         sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
  1115         return PEP_CANNOT_SET_PGP_KEYPAIR;
  1116     }
  1117 
  1118 
  1119     sqlite3_reset(session->set_identity);
  1120     sqlite3_bind_text(session->set_identity, 1, identity->address, -1,
  1121             SQLITE_STATIC);
  1122     sqlite3_bind_text(session->set_identity, 2, identity->fpr, -1,
  1123             SQLITE_STATIC);
  1124     sqlite3_bind_text(session->set_identity, 3, identity->user_id, -1,
  1125             SQLITE_STATIC);
  1126     sqlite3_bind_int(session->set_identity, 4, identity->flags);
  1127     result = sqlite3_step(session->set_identity);
  1128     sqlite3_reset(session->set_identity);
  1129     if (result != SQLITE_DONE) {
  1130         sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
  1131         return PEP_CANNOT_SET_IDENTITY;
  1132     }
  1133 
  1134     if(strcmp(identity->user_id, PEP_OWN_USERID) == 0 &&
  1135        identity->fpr && identity->fpr[0] != '\0') {
  1136         sqlite3_reset(session->set_own_key);
  1137         sqlite3_bind_text(session->set_own_key, 1, identity->address, -1,
  1138             SQLITE_STATIC);
  1139         sqlite3_bind_text(session->set_own_key, 2, identity->fpr, -1,
  1140             SQLITE_STATIC);
  1141         result = sqlite3_step(session->set_own_key);
  1142         sqlite3_reset(session->set_own_key);
  1143         if (result != SQLITE_DONE) {
  1144             sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
  1145             return PEP_CANNOT_SET_PGP_KEYPAIR;
  1146         }
  1147     }
  1148 
  1149     sqlite3_reset(session->set_trust);
  1150     sqlite3_bind_text(session->set_trust, 1, identity->user_id, -1,
  1151             SQLITE_STATIC);
  1152     sqlite3_bind_text(session->set_trust, 2, identity->fpr, -1,
  1153             SQLITE_STATIC);
  1154     sqlite3_bind_int(session->set_trust, 3, identity->comm_type);
  1155     result = sqlite3_step(session->set_trust);
  1156     sqlite3_reset(session->set_trust);
  1157     if (result != SQLITE_DONE) {
  1158         sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
  1159         return PEP_CANNOT_SET_TRUST;
  1160     }
  1161 
  1162     result = sqlite3_exec(session->db, "COMMIT ;", NULL, NULL, NULL);
  1163     if (result == SQLITE_OK)
  1164         return PEP_STATUS_OK;
  1165     else
  1166         return PEP_COMMIT_FAILED;
  1167 }
  1168 
  1169 DYNAMIC_API PEP_STATUS set_device_group(
  1170         PEP_SESSION session,
  1171         const char *group_name
  1172     )
  1173 {
  1174     int result;
  1175 
  1176     assert(session);
  1177     assert(group_name);
  1178 
  1179     if (!(session && group_name))
  1180         return PEP_ILLEGAL_VALUE;
  1181 
  1182     sqlite3_reset(session->set_device_group);
  1183     sqlite3_bind_text(session->set_device_group, 1, group_name, -1,
  1184             SQLITE_STATIC);
  1185     result = sqlite3_step(session->set_device_group);
  1186     sqlite3_reset(session->set_device_group);
  1187     if (result != SQLITE_DONE)
  1188         return PEP_CANNOT_SET_PERSON;
  1189 
  1190     return PEP_STATUS_OK;
  1191 }
  1192 
  1193 DYNAMIC_API PEP_STATUS get_device_group(PEP_SESSION session, char **group_name)
  1194 {
  1195     PEP_STATUS status = PEP_STATUS_OK;
  1196     int result;
  1197 
  1198     assert(session);
  1199     assert(group_name);
  1200 
  1201     if (!(session && group_name))
  1202         return PEP_ILLEGAL_VALUE;
  1203 
  1204     sqlite3_reset(session->get_device_group);
  1205 
  1206     result = sqlite3_step(session->get_device_group);
  1207     switch (result) {
  1208     case SQLITE_ROW: {
  1209         *group_name = strdup(
  1210             (const char *) sqlite3_column_text(session->get_device_group, 0));
  1211             if(*group_name == NULL)
  1212                 status = PEP_OUT_OF_MEMORY;
  1213         break;
  1214     }
  1215  
  1216     default:
  1217         status = PEP_RECORD_NOT_FOUND;
  1218     }
  1219 
  1220     sqlite3_reset(session->get_device_group);
  1221     return status;
  1222 }
  1223 
  1224 DYNAMIC_API PEP_STATUS set_identity_flags(
  1225         PEP_SESSION session,
  1226         pEp_identity *identity,
  1227         unsigned int flags
  1228     )
  1229 {
  1230     int result;
  1231 
  1232     assert(session);
  1233     assert(identity);
  1234     assert(identity->address);
  1235     assert(identity->user_id);
  1236 
  1237     if (!(session && identity && identity->address && identity->user_id))
  1238         return PEP_ILLEGAL_VALUE;
  1239 
  1240     sqlite3_reset(session->set_identity_flags);
  1241     sqlite3_bind_int(session->set_identity_flags, 1, flags);
  1242     sqlite3_bind_text(session->set_identity_flags, 2, identity->address, -1,
  1243             SQLITE_STATIC);
  1244     sqlite3_bind_text(session->set_identity_flags, 3, identity->user_id, -1,
  1245             SQLITE_STATIC);
  1246     result = sqlite3_step(session->set_identity_flags);
  1247     sqlite3_reset(session->set_identity_flags);
  1248     if (result != SQLITE_DONE)
  1249         return PEP_CANNOT_SET_IDENTITY;
  1250 
  1251     identity->flags |= flags;
  1252     return PEP_STATUS_OK;
  1253 }
  1254 
  1255 DYNAMIC_API PEP_STATUS unset_identity_flags(
  1256         PEP_SESSION session,
  1257         pEp_identity *identity,
  1258         unsigned int flags
  1259     )
  1260 {
  1261     int result;
  1262 
  1263     assert(session);
  1264     assert(identity);
  1265     assert(identity->address);
  1266     assert(identity->user_id);
  1267 
  1268     if (!(session && identity && identity->address && identity->user_id))
  1269         return PEP_ILLEGAL_VALUE;
  1270 
  1271     sqlite3_reset(session->unset_identity_flags);
  1272     sqlite3_bind_int(session->unset_identity_flags, 1, flags);
  1273     sqlite3_bind_text(session->unset_identity_flags, 2, identity->address, -1,
  1274             SQLITE_STATIC);
  1275     sqlite3_bind_text(session->unset_identity_flags, 3, identity->user_id, -1,
  1276             SQLITE_STATIC);
  1277     result = sqlite3_step(session->unset_identity_flags);
  1278     sqlite3_reset(session->unset_identity_flags);
  1279     if (result != SQLITE_DONE)
  1280         return PEP_CANNOT_SET_IDENTITY;
  1281 
  1282     identity->flags &= ~flags;
  1283     return PEP_STATUS_OK;
  1284 }
  1285 
  1286 DYNAMIC_API PEP_STATUS mark_as_compromized(
  1287         PEP_SESSION session,
  1288         const char *fpr
  1289     )
  1290 {
  1291     int result;
  1292 
  1293     assert(session);
  1294     assert(fpr && fpr[0]);
  1295 
  1296     if (!(session && fpr && fpr[0]))
  1297         return PEP_ILLEGAL_VALUE;
  1298 
  1299     sqlite3_reset(session->mark_compromized);
  1300     sqlite3_bind_text(session->mark_compromized, 1, fpr, -1,
  1301             SQLITE_STATIC);
  1302     result = sqlite3_step(session->mark_compromized);
  1303     sqlite3_reset(session->mark_compromized);
  1304 
  1305     if (result != SQLITE_DONE)
  1306         return PEP_CANNOT_SET_TRUST;
  1307 
  1308     return PEP_STATUS_OK;
  1309 }
  1310 
  1311 void pEp_free(void *p)
  1312 {
  1313     free(p);
  1314 }
  1315 
  1316 DYNAMIC_API PEP_STATUS get_trust(PEP_SESSION session, pEp_identity *identity)
  1317 {
  1318     PEP_STATUS status = PEP_STATUS_OK;
  1319     int result;
  1320 
  1321     assert(session);
  1322     assert(identity);
  1323     assert(identity->user_id);
  1324     assert(identity->user_id[0]);
  1325     assert(identity->fpr);
  1326     assert(identity->fpr[0]);
  1327 
  1328     if (!(session && identity && identity->user_id && identity->user_id[0] &&
  1329                 identity->fpr && identity->fpr[0]))
  1330         return PEP_ILLEGAL_VALUE;
  1331 
  1332     identity->comm_type = PEP_ct_unknown;
  1333 
  1334     sqlite3_reset(session->get_trust);
  1335     sqlite3_bind_text(session->get_trust, 1, identity->user_id, -1,
  1336             SQLITE_STATIC);
  1337     sqlite3_bind_text(session->get_trust, 2, identity->fpr, -1, SQLITE_STATIC);
  1338 
  1339     result = sqlite3_step(session->get_trust);
  1340     switch (result) {
  1341     case SQLITE_ROW: {
  1342         int comm_type = (PEP_comm_type) sqlite3_column_int(session->get_trust,
  1343                 0);
  1344         identity->comm_type = comm_type;
  1345         break;
  1346     }
  1347  
  1348     default:
  1349         status = PEP_CANNOT_FIND_IDENTITY;
  1350     }
  1351 
  1352     sqlite3_reset(session->get_trust);
  1353     return status;
  1354 }
  1355 
  1356 DYNAMIC_API PEP_STATUS least_trust(
  1357         PEP_SESSION session,
  1358         const char *fpr,
  1359         PEP_comm_type *comm_type
  1360     )
  1361 {
  1362     PEP_STATUS status = PEP_STATUS_OK;
  1363     int result;
  1364 
  1365     assert(session);
  1366     assert(fpr);
  1367     assert(comm_type);
  1368 
  1369     if (!(session && fpr && comm_type))
  1370         return PEP_ILLEGAL_VALUE;
  1371 
  1372     *comm_type = PEP_ct_unknown;
  1373 
  1374     sqlite3_reset(session->least_trust);
  1375     sqlite3_bind_text(session->least_trust, 1, fpr, -1, SQLITE_STATIC);
  1376 
  1377     result = sqlite3_step(session->least_trust);
  1378     switch (result) {
  1379         case SQLITE_ROW: {
  1380             int _comm_type = sqlite3_column_int(session->least_trust, 0);
  1381             *comm_type = (PEP_comm_type) _comm_type;
  1382             break;
  1383         }
  1384         default:
  1385             status = PEP_CANNOT_FIND_IDENTITY;
  1386     }
  1387 
  1388     sqlite3_reset(session->least_trust);
  1389     return status;
  1390 }
  1391 
  1392 DYNAMIC_API PEP_STATUS decrypt_and_verify(
  1393     PEP_SESSION session, const char *ctext, size_t csize,
  1394     char **ptext, size_t *psize, stringlist_t **keylist
  1395     )
  1396 {
  1397     assert(session);
  1398     assert(ctext);
  1399     assert(csize);
  1400     assert(ptext);
  1401     assert(psize);
  1402     assert(keylist);
  1403 
  1404     if (!(session && ctext && csize && ptext && psize && keylist))
  1405         return PEP_ILLEGAL_VALUE;
  1406 
  1407     return session->cryptotech[PEP_crypt_OpenPGP].decrypt_and_verify(
  1408             session, ctext, csize, ptext, psize, keylist);
  1409 }
  1410 
  1411 DYNAMIC_API PEP_STATUS encrypt_and_sign(
  1412     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  1413     size_t psize, char **ctext, size_t *csize
  1414     )
  1415 {
  1416     assert(session);
  1417     assert(keylist);
  1418     assert(ptext);
  1419     assert(psize);
  1420     assert(ctext);
  1421     assert(csize);
  1422 
  1423     if (!(session && keylist && ptext && psize && ctext && csize))
  1424         return PEP_ILLEGAL_VALUE;
  1425 
  1426     return session->cryptotech[PEP_crypt_OpenPGP].encrypt_and_sign(session,
  1427             keylist, ptext, psize, ctext, csize);
  1428 }
  1429 
  1430 DYNAMIC_API PEP_STATUS verify_text(
  1431     PEP_SESSION session, const char *text, size_t size,
  1432     const char *signature, size_t sig_size, stringlist_t **keylist
  1433     )
  1434 {
  1435     assert(session);
  1436     assert(text);
  1437     assert(size);
  1438     assert(signature);
  1439     assert(sig_size);
  1440     assert(keylist);
  1441 
  1442     if (!(session && text && size && signature && sig_size && keylist))
  1443         return PEP_ILLEGAL_VALUE;
  1444 
  1445     return session->cryptotech[PEP_crypt_OpenPGP].verify_text(session, text,
  1446             size, signature, sig_size, keylist);
  1447 }
  1448 
  1449 DYNAMIC_API PEP_STATUS delete_keypair(PEP_SESSION session, const char *fpr)
  1450 {
  1451     assert(session);
  1452     assert(fpr);
  1453 
  1454     if (!(session && fpr))
  1455         return PEP_ILLEGAL_VALUE;
  1456 
  1457     return session->cryptotech[PEP_crypt_OpenPGP].delete_keypair(session, fpr);
  1458 }
  1459 
  1460 DYNAMIC_API PEP_STATUS export_key(
  1461         PEP_SESSION session, const char *fpr, char **key_data, size_t *size
  1462     )
  1463 {
  1464     assert(session);
  1465     assert(fpr);
  1466     assert(key_data);
  1467     assert(size);
  1468 
  1469     if (!(session && fpr && key_data && size))
  1470         return PEP_ILLEGAL_VALUE;
  1471 
  1472     return session->cryptotech[PEP_crypt_OpenPGP].export_key(session, fpr,
  1473             key_data, size, false);
  1474 }
  1475 
  1476 DYNAMIC_API PEP_STATUS export_secrect_key(
  1477         PEP_SESSION session, const char *fpr, char **key_data, size_t *size
  1478     )
  1479 {
  1480     assert(session);
  1481     assert(fpr);
  1482     assert(key_data);
  1483     assert(size);
  1484 
  1485     if (!(session && fpr && key_data && size))
  1486         return PEP_ILLEGAL_VALUE;
  1487 
  1488     // don't accept key IDs but full fingerprints only
  1489     if (strlen(fpr) < 16)
  1490         return PEP_ILLEGAL_VALUE;
  1491 
  1492     return session->cryptotech[PEP_crypt_OpenPGP].export_key(session, fpr,
  1493             key_data, size, true);
  1494 }
  1495 
  1496 DYNAMIC_API PEP_STATUS find_keys(
  1497         PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1498     )
  1499 {
  1500     assert(session);
  1501     assert(pattern);
  1502     assert(keylist);
  1503 
  1504     if (!(session && pattern && keylist))
  1505         return PEP_ILLEGAL_VALUE;
  1506 
  1507     return session->cryptotech[PEP_crypt_OpenPGP].find_keys(session, pattern,
  1508             keylist);
  1509 }
  1510 
  1511 
  1512 DYNAMIC_API PEP_STATUS generate_keypair(
  1513         PEP_SESSION session, pEp_identity *identity
  1514     )
  1515 {
  1516     assert(session);
  1517     assert(identity);
  1518     assert(identity->address);
  1519     assert(identity->fpr == NULL || identity->fpr[0] == 0);
  1520     assert(identity->username);
  1521 
  1522     if (!(session && identity && identity->address &&
  1523             (identity->fpr == NULL || identity->fpr[0] == 0) &&
  1524             identity->username))
  1525         return PEP_ILLEGAL_VALUE;
  1526 
  1527     PEP_STATUS status =
  1528         session->cryptotech[PEP_crypt_OpenPGP].generate_keypair(session,
  1529                 identity);
  1530     if (status != PEP_STATUS_OK)
  1531         return status;
  1532 
  1533     return status;
  1534 }
  1535 
  1536 DYNAMIC_API PEP_STATUS get_key_rating(
  1537         PEP_SESSION session,
  1538         const char *fpr,
  1539         PEP_comm_type *comm_type
  1540     )
  1541 {
  1542     assert(session);
  1543     assert(fpr);
  1544     assert(comm_type);
  1545 
  1546     if (!(session && fpr && comm_type))
  1547         return PEP_ILLEGAL_VALUE;
  1548 
  1549     return session->cryptotech[PEP_crypt_OpenPGP].get_key_rating(session, fpr,
  1550             comm_type);
  1551 }
  1552 
  1553 DYNAMIC_API PEP_STATUS import_key(
  1554         PEP_SESSION session,
  1555         const char *key_data,
  1556         size_t size,
  1557         identity_list **private_keys
  1558     )
  1559 {
  1560     assert(session);
  1561     assert(key_data);
  1562 
  1563     if (!(session && key_data))
  1564         return PEP_ILLEGAL_VALUE;
  1565 
  1566     return session->cryptotech[PEP_crypt_OpenPGP].import_key(session, key_data,
  1567             size, private_keys);
  1568 }
  1569 
  1570 DYNAMIC_API PEP_STATUS recv_key(PEP_SESSION session, const char *pattern)
  1571 {
  1572     assert(session);
  1573     assert(pattern);
  1574 
  1575     if (!(session && pattern))
  1576         return PEP_ILLEGAL_VALUE;
  1577 
  1578     return session->cryptotech[PEP_crypt_OpenPGP].recv_key(session, pattern);
  1579 }
  1580 
  1581 DYNAMIC_API PEP_STATUS send_key(PEP_SESSION session, const char *pattern)
  1582 {
  1583     assert(session);
  1584     assert(pattern);
  1585 
  1586     if (!(session && pattern))
  1587         return PEP_ILLEGAL_VALUE;
  1588 
  1589     return session->cryptotech[PEP_crypt_OpenPGP].send_key(session, pattern);
  1590 }
  1591 
  1592 DYNAMIC_API PEP_STATUS renew_key(
  1593         PEP_SESSION session,
  1594         const char *fpr,
  1595         const timestamp *ts
  1596     )
  1597 {
  1598     assert(session);
  1599     assert(fpr);
  1600 
  1601     if (!(session && fpr))
  1602         return PEP_ILLEGAL_VALUE;
  1603 
  1604     return session->cryptotech[PEP_crypt_OpenPGP].renew_key(session, fpr, ts);
  1605 }
  1606 
  1607 DYNAMIC_API PEP_STATUS revoke_key(
  1608         PEP_SESSION session,
  1609         const char *fpr,
  1610         const char *reason
  1611     )
  1612 {
  1613     assert(session);
  1614     assert(fpr);
  1615 
  1616     if (!(session && fpr))
  1617         return PEP_ILLEGAL_VALUE;
  1618 
  1619     return session->cryptotech[PEP_crypt_OpenPGP].revoke_key(session, fpr,
  1620             reason);
  1621 }
  1622 
  1623 DYNAMIC_API PEP_STATUS key_expired(
  1624         PEP_SESSION session,
  1625         const char *fpr,
  1626         const time_t when,
  1627         bool *expired
  1628     )
  1629 {
  1630     assert(session);
  1631     assert(fpr);
  1632     assert(expired);
  1633 
  1634     if (!(session && fpr && expired))
  1635         return PEP_ILLEGAL_VALUE;
  1636 
  1637     return session->cryptotech[PEP_crypt_OpenPGP].key_expired(session, fpr,
  1638             when, expired);
  1639 }
  1640 
  1641 DYNAMIC_API PEP_STATUS key_revoked(
  1642        PEP_SESSION session,
  1643        const char *fpr,
  1644        bool *revoked
  1645    )
  1646 {
  1647     assert(session);
  1648     assert(fpr);
  1649     assert(revoked);
  1650     
  1651     if (!(session && fpr && revoked))
  1652         return PEP_ILLEGAL_VALUE;
  1653     
  1654     return session->cryptotech[PEP_crypt_OpenPGP].key_revoked(session, fpr,
  1655             revoked);
  1656 }
  1657 
  1658 static void _clean_log_value(char *text)
  1659 {
  1660     if (text) {
  1661         for (char *c = text; *c; c++) {
  1662             if (*c < 32 && *c != '\n')
  1663                 *c = 32;
  1664             else if (*c == '"')
  1665                 *c = '\'';
  1666         }
  1667     }
  1668 }
  1669 
  1670 static char *_concat_string(char *str1, const char *str2, char delim)
  1671 {
  1672     str2 = str2 ? str2 : "";
  1673     size_t len1 = str1 ? strlen(str1) : 0;
  1674     size_t len2 = strlen(str2);
  1675     size_t len = len1 + len2 + 3;
  1676     char * result = realloc(str1, len + 1);
  1677 
  1678     if (result) {
  1679         result[len1] = '"';
  1680         strcpy(result + len1 + 1, str2);
  1681         result[len - 2] = '"';
  1682         result[len - 1] = delim;
  1683         result[len] = 0;
  1684     }
  1685     else {
  1686         free(str1);
  1687     }
  1688 
  1689     return result;
  1690 }
  1691 
  1692 DYNAMIC_API PEP_STATUS get_crashdump_log(
  1693         PEP_SESSION session,
  1694         int maxlines,
  1695         char **logdata
  1696     )
  1697 {
  1698     PEP_STATUS status = PEP_STATUS_OK;
  1699     char *_logdata= NULL;
  1700 
  1701     assert(session);
  1702     assert(maxlines >= 0 && maxlines <= CRASHDUMP_MAX_LINES);
  1703     assert(logdata);
  1704 
  1705     if (!(session && logdata && maxlines >= 0 && maxlines <=
  1706             CRASHDUMP_MAX_LINES))
  1707         return PEP_ILLEGAL_VALUE;
  1708 
  1709     *logdata = NULL;
  1710 
  1711     int limit = maxlines ? maxlines : CRASHDUMP_DEFAULT_LINES;
  1712     const char *timestamp = NULL;
  1713     const char *title = NULL;
  1714     const char *entity = NULL;
  1715     const char *desc = NULL;
  1716     const char *comment = NULL;
  1717 
  1718     sqlite3_reset(session->crashdump);
  1719     sqlite3_bind_int(session->crashdump, 1, limit);
  1720 
  1721     int result;
  1722 
  1723     do {
  1724         result = sqlite3_step(session->crashdump);
  1725         switch (result) {
  1726         case SQLITE_ROW:
  1727             timestamp = (const char *) sqlite3_column_text(session->crashdump,
  1728                     0);
  1729             title   = (const char *) sqlite3_column_text(session->crashdump,
  1730                     1);
  1731             entity  = (const char *) sqlite3_column_text(session->crashdump,
  1732                     2);
  1733             desc    = (const char *) sqlite3_column_text(session->crashdump,
  1734                     3);
  1735             comment = (const char *) sqlite3_column_text(session->crashdump,
  1736                     4);
  1737 
  1738             _logdata = _concat_string(_logdata, timestamp, ',');
  1739             if (_logdata == NULL)
  1740                 goto enomem;
  1741 
  1742             _logdata = _concat_string(_logdata, title, ',');
  1743             if (_logdata == NULL)
  1744                 goto enomem;
  1745 
  1746             _logdata = _concat_string(_logdata, entity, ',');
  1747             if (_logdata == NULL)
  1748                 goto enomem;
  1749 
  1750             _logdata = _concat_string(_logdata, desc, ',');
  1751             if (_logdata == NULL)
  1752                 goto enomem;
  1753 
  1754             _logdata = _concat_string(_logdata, comment, '\n');
  1755             if (_logdata == NULL)
  1756                 goto enomem;
  1757 
  1758             _clean_log_value(_logdata);
  1759             break;
  1760 
  1761         case SQLITE_DONE:
  1762             break;
  1763 
  1764         default:
  1765             status = PEP_UNKNOWN_ERROR;
  1766             result = SQLITE_DONE;
  1767         }
  1768     } while (result != SQLITE_DONE);
  1769 
  1770     sqlite3_reset(session->crashdump);
  1771     if (status == PEP_STATUS_OK)
  1772         *logdata = _logdata;
  1773 
  1774     goto the_end;
  1775 
  1776 enomem:
  1777     status = PEP_OUT_OF_MEMORY;
  1778 
  1779 the_end:
  1780     return status;
  1781 }
  1782 
  1783 DYNAMIC_API PEP_STATUS get_languagelist(
  1784         PEP_SESSION session,
  1785         char **languages
  1786     )
  1787 {
  1788     PEP_STATUS status = PEP_STATUS_OK;
  1789     char *_languages= NULL;
  1790 
  1791     assert(session);
  1792     assert(languages);
  1793 
  1794     if (!(session && languages))
  1795         return PEP_ILLEGAL_VALUE;
  1796 
  1797     *languages = NULL;
  1798 
  1799     const char *lang = NULL;
  1800     const char *name = NULL;
  1801     const char *phrase = NULL;
  1802 
  1803     sqlite3_reset(session->languagelist);
  1804 
  1805     int result;
  1806 
  1807     do {
  1808         result = sqlite3_step(session->languagelist);
  1809         switch (result) {
  1810         case SQLITE_ROW:
  1811             lang = (const char *) sqlite3_column_text(session->languagelist,
  1812                     0);
  1813             name = (const char *) sqlite3_column_text(session->languagelist,
  1814                     1);
  1815             phrase = (const char *) sqlite3_column_text(session->languagelist,
  1816                     2);
  1817 
  1818             _languages = _concat_string(_languages, lang, ',');
  1819             if (_languages == NULL)
  1820                 goto enomem;
  1821 
  1822             _languages = _concat_string(_languages, name, ',');
  1823             if (_languages == NULL)
  1824                 goto enomem;
  1825 
  1826             _languages = _concat_string(_languages, phrase, '\n');
  1827             if (_languages == NULL)
  1828                 goto enomem;
  1829 
  1830             break;
  1831 
  1832         case SQLITE_DONE:
  1833             break;
  1834 
  1835         default:
  1836             status = PEP_UNKNOWN_ERROR;
  1837             result = SQLITE_DONE;
  1838         }
  1839     } while (result != SQLITE_DONE);
  1840 
  1841     sqlite3_reset(session->languagelist);
  1842     if (status == PEP_STATUS_OK)
  1843         *languages = _languages;
  1844 
  1845     goto the_end;
  1846 
  1847 enomem:
  1848     status = PEP_OUT_OF_MEMORY;
  1849 
  1850 the_end:
  1851     return status;
  1852 }
  1853 
  1854 DYNAMIC_API PEP_STATUS get_phrase(
  1855         PEP_SESSION session,
  1856         const char *lang,
  1857         int phrase_id,
  1858         char **phrase
  1859     )
  1860 {
  1861     PEP_STATUS status = PEP_STATUS_OK;
  1862 
  1863     assert(session && lang && lang[0] && lang[1] && lang[2] == 0 && phrase);
  1864     if (!(session && lang && lang[0] && lang[1] && lang[2] == 0 && phrase))
  1865         return PEP_ILLEGAL_VALUE;
  1866 
  1867     *phrase = NULL;
  1868 
  1869     sqlite3_reset(session->i18n_token);
  1870     sqlite3_bind_text(session->i18n_token, 1, lang, -1, SQLITE_STATIC);
  1871     sqlite3_bind_int(session->i18n_token, 2, phrase_id);
  1872 
  1873     const char *_phrase = NULL;
  1874     int result;
  1875 
  1876     result = sqlite3_step(session->i18n_token);
  1877     switch (result) {
  1878     case SQLITE_ROW:
  1879         _phrase = (const char *) sqlite3_column_text(session->i18n_token, 0);
  1880         break;
  1881 
  1882     case SQLITE_DONE:
  1883         status = PEP_PHRASE_NOT_FOUND;
  1884         break;
  1885 
  1886     default:
  1887         status = PEP_UNKNOWN_ERROR;
  1888     }
  1889 
  1890     if (status == PEP_STATUS_OK) {
  1891         *phrase = strdup(_phrase);
  1892         if (*phrase == NULL)
  1893             goto enomem;
  1894     }
  1895 
  1896     sqlite3_reset(session->i18n_token);
  1897     goto the_end;
  1898 
  1899 enomem:
  1900     status = PEP_OUT_OF_MEMORY;
  1901 
  1902 the_end:
  1903     return status;
  1904 }
  1905 
  1906 static PEP_STATUS _get_sequence_value(PEP_SESSION session, const char *name,
  1907         int32_t *value)
  1908 {
  1909     assert(session && name && value);
  1910     if (!(session && name && value))
  1911         return PEP_ILLEGAL_VALUE;
  1912 
  1913     PEP_STATUS status = PEP_STATUS_OK;
  1914 
  1915     sqlite3_reset(session->sequence_value2);
  1916     sqlite3_bind_text(session->sequence_value2, 1, name, -1,
  1917             SQLITE_STATIC);
  1918     int result = sqlite3_step(session->sequence_value2);
  1919     switch (result) {
  1920         case SQLITE_ROW: {
  1921             int32_t _value = (int32_t)
  1922                     sqlite3_column_int(session->sequence_value2, 0);
  1923             int _own = (int)
  1924                     sqlite3_column_int(session->sequence_value2, 1);
  1925             *value = _value;
  1926             if (_own)
  1927                 status = PEP_OWN_SEQUENCE;
  1928             break;
  1929         }
  1930         case SQLITE_DONE:
  1931             status = PEP_RECORD_NOT_FOUND;
  1932             break;
  1933         default:
  1934             status = PEP_UNKNOWN_ERROR;
  1935     }
  1936     sqlite3_reset(session->sequence_value2);
  1937 
  1938     return status;
  1939 }
  1940 
  1941 static PEP_STATUS _increment_sequence_value(PEP_SESSION session,
  1942         const char *name, int own)
  1943 {
  1944     assert(session && name);
  1945     if (!(session && name))
  1946         return PEP_ILLEGAL_VALUE;
  1947 
  1948     sqlite3_reset(session->sequence_value1);
  1949     sqlite3_bind_text(session->sequence_value1, 1, name, -1, SQLITE_STATIC);
  1950     sqlite3_bind_int(session->sequence_value1, 2, own);
  1951     int result = sqlite3_step(session->sequence_value1);
  1952     assert(result == SQLITE_DONE);
  1953     sqlite3_reset(session->sequence_value1);
  1954     if (result == SQLITE_DONE)
  1955         return PEP_STATUS_OK;
  1956     else
  1957         return PEP_CANNOT_INCREASE_SEQUENCE;
  1958 }
  1959 
  1960 static PEP_STATUS _set_sequence_value(PEP_SESSION session,
  1961         const char *name, int32_t value, int own)
  1962 {
  1963     assert(session && name && value > 0);
  1964     if (!(session && name && value > 0))
  1965         return PEP_ILLEGAL_VALUE;
  1966 
  1967     sqlite3_reset(session->sequence_value3);
  1968     sqlite3_bind_text(session->sequence_value3, 1, name, -1, SQLITE_STATIC);
  1969     sqlite3_bind_int(session->sequence_value3, 2, value);
  1970     sqlite3_bind_int(session->sequence_value3, 3, own);
  1971     int result = sqlite3_step(session->sequence_value3);
  1972     assert(result == SQLITE_DONE);
  1973     sqlite3_reset(session->sequence_value3);
  1974     if (result == SQLITE_DONE)
  1975         return PEP_STATUS_OK;
  1976     else
  1977         return PEP_CANNOT_SET_SEQUENCE_VALUE;
  1978 }
  1979 
  1980 DYNAMIC_API PEP_STATUS sequence_value(
  1981         PEP_SESSION session,
  1982         char *name,
  1983         int32_t *value
  1984     )
  1985 {
  1986     PEP_STATUS status = PEP_STATUS_OK;
  1987 
  1988     assert(session);
  1989     assert(name && value && *value >= 0);
  1990 
  1991     if (!(session && name && value && *value >= 0))
  1992         return PEP_ILLEGAL_VALUE;
  1993 
  1994     int own = 0;
  1995     if (!name[0]) {
  1996         pEpUUID uuid;
  1997         uuid_generate_random(uuid);
  1998         uuid_unparse_upper(uuid, name);
  1999         own = 1;
  2000     }
  2001     else {
  2002         if (name == session->sync_uuid || strcmp(name, session->sync_uuid) == 0)
  2003             own = 1;
  2004     }
  2005 
  2006     if (*value) {
  2007         int32_t old_value = 0;
  2008         status = _get_sequence_value(session, name, &old_value);
  2009         if (status != PEP_STATUS_OK && status != PEP_RECORD_NOT_FOUND)
  2010             return status;
  2011 
  2012         if (old_value >= *value) {
  2013             return PEP_SEQUENCE_VIOLATED;
  2014         }
  2015         else {
  2016             status = _set_sequence_value(session, name, *value, own);
  2017             return status;
  2018         }
  2019     }
  2020 
  2021     assert(*value == 0);
  2022     status = _increment_sequence_value(session, name, own);
  2023     if (status == PEP_STATUS_OK) {
  2024         status = _get_sequence_value(session, name, value);
  2025         assert(*value < INT32_MAX);
  2026         if (*value == INT32_MAX)
  2027             return PEP_CANNOT_INCREASE_SEQUENCE;
  2028     }
  2029     return status;
  2030 }
  2031 
  2032 DYNAMIC_API PEP_STATUS set_revoked(
  2033        PEP_SESSION session,
  2034        const char *revoked_fpr,
  2035        const char *replacement_fpr,
  2036        const uint64_t revocation_date
  2037     )
  2038 {
  2039     PEP_STATUS status = PEP_STATUS_OK;
  2040     
  2041     assert(session &&
  2042            revoked_fpr && revoked_fpr[0] &&
  2043            replacement_fpr && replacement_fpr[0]
  2044           );
  2045     
  2046     if (!(session &&
  2047           revoked_fpr && revoked_fpr[0] &&
  2048           replacement_fpr && replacement_fpr[0]
  2049          ))
  2050         return PEP_ILLEGAL_VALUE;
  2051     
  2052     sqlite3_reset(session->set_revoked);
  2053     sqlite3_bind_text(session->set_revoked, 1, revoked_fpr, -1, SQLITE_STATIC);
  2054     sqlite3_bind_text(session->set_revoked, 2, replacement_fpr, -1,
  2055             SQLITE_STATIC);
  2056     sqlite3_bind_int64(session->set_revoked, 3, revocation_date);
  2057 
  2058     int result;
  2059     
  2060     result = sqlite3_step(session->set_revoked);
  2061     switch (result) {
  2062         case SQLITE_DONE:
  2063             status = PEP_STATUS_OK;
  2064             break;
  2065             
  2066         default:
  2067             status = PEP_UNKNOWN_ERROR;
  2068     }
  2069     
  2070     sqlite3_reset(session->set_revoked);
  2071     return status;
  2072 }
  2073 
  2074 DYNAMIC_API PEP_STATUS get_revoked(
  2075         PEP_SESSION session,
  2076         const char *fpr,
  2077         char **revoked_fpr,
  2078         uint64_t *revocation_date
  2079     )
  2080 {
  2081     PEP_STATUS status = PEP_STATUS_OK;
  2082 
  2083     assert(session &&
  2084            revoked_fpr &&
  2085            fpr && fpr[0]
  2086           );
  2087     
  2088     if (!(session &&
  2089            revoked_fpr &&
  2090            fpr && fpr[0]
  2091           ))
  2092         return PEP_ILLEGAL_VALUE;
  2093 
  2094     *revoked_fpr = NULL;
  2095     *revocation_date = 0;
  2096 
  2097     sqlite3_reset(session->get_revoked);
  2098     sqlite3_bind_text(session->get_revoked, 1, fpr, -1, SQLITE_STATIC);
  2099 
  2100     int result;
  2101     
  2102     result = sqlite3_step(session->get_revoked);
  2103     switch (result) {
  2104         case SQLITE_ROW: {
  2105             *revoked_fpr = strdup((const char *)
  2106                     sqlite3_column_text(session->get_revoked, 0));
  2107             if(*revoked_fpr)
  2108                 *revocation_date = sqlite3_column_int64(session->get_revoked,
  2109                         1);
  2110             else
  2111                 status = PEP_OUT_OF_MEMORY;
  2112 
  2113             break;
  2114         }
  2115         default:
  2116             status = PEP_CANNOT_FIND_IDENTITY;
  2117     }
  2118 
  2119     sqlite3_reset(session->get_revoked);
  2120 
  2121     return status;
  2122 }
  2123 
  2124 PEP_STATUS key_created(
  2125         PEP_SESSION session,
  2126         const char *fpr,
  2127         time_t *created
  2128     )
  2129 {
  2130     assert(session && fpr && created);
  2131     if (!(session && fpr && created))
  2132         return PEP_ILLEGAL_VALUE;
  2133 
  2134     return session->cryptotech[PEP_crypt_OpenPGP].key_created(session, fpr,
  2135             created);
  2136 }
  2137 
  2138 PEP_STATUS find_private_keys(PEP_SESSION session, const char* pattern,
  2139                              stringlist_t **keylist) {
  2140     assert(session && pattern && keylist);
  2141     if (!(session && pattern && keylist))
  2142         return PEP_ILLEGAL_VALUE;
  2143     
  2144     return session->cryptotech[PEP_crypt_OpenPGP].find_private_keys(session, pattern,
  2145                                                                     keylist);
  2146 }
  2147 
  2148 DYNAMIC_API const char* get_engine_version() {
  2149     return PEP_ENGINE_VERSION;
  2150 }
  2151 
  2152 
  2153 DYNAMIC_API PEP_STATUS reset_peptest_hack(PEP_SESSION session)
  2154 {
  2155     assert(session);
  2156 
  2157     if (!session)
  2158         return PEP_ILLEGAL_VALUE;
  2159 
  2160     int int_result = sqlite3_exec(
  2161         session->db,
  2162         "delete from identity where address like '%@peptest.ch' ;",
  2163         NULL,
  2164         NULL,
  2165         NULL
  2166     );
  2167     assert(int_result == SQLITE_OK);
  2168 
  2169     return PEP_STATUS_OK;
  2170 }
  2171