diff --git a/src/engine_sql.c b/src/engine_sql.c new file mode 100644 index 000000000..2dbe91281 --- /dev/null +++ b/src/engine_sql.c @@ -0,0 +1,2642 @@ +#include "pEp_internal.h" +#include "engine_sql.h" + +// sql overloaded functions - modified from sqlite3.c +/** + * @internal + * + * + * + * @brief TODO + * + * @param[in] *ctx sqlite3_context + * @param[in] argc int + * @param[in] **argv sqlite3_value + * + */ +static void _sql_lower(sqlite3_context* ctx, int argc, sqlite3_value** argv) { + const char *z2; + int n; + z2 = (char*)sqlite3_value_text(argv[0]); + n = sqlite3_value_bytes(argv[0]); + /* Verify that the call to _bytes() does not invalidate the _text() pointer */ + assert( z2==(char*)sqlite3_value_text(argv[0]) ); + if( z2 ){ + char *z1 = (char*)sqlite3_malloc(n+1); + if( z1 ){ + for(int i=0; i 0x7a) + c_mod = c; + z1[i] = c_mod; + } + z1[n] = '\0'; + sqlite3_result_text(ctx, z1, n, sqlite3_free); + } + } +} + +#ifdef _PEP_SQLITE_DEBUG +/** + * @internal + * + * + * + * @brief TODO + * + * @param[in] trace_constant unsigned + * @param[in] *context_ptr void + * @param[in] *P void + * @param[in] *X void + * + */ +int sql_trace_callback (unsigned trace_constant, + void* context_ptr, + void* P, + void* X) { + switch (trace_constant) { + case SQLITE_TRACE_STMT: + fprintf(stderr, "SQL_DEBUG: STMT - "); + const char* X_str = (const char*) X; + if (!EMPTYSTR(X_str) && X_str[0] == '-' && X_str[1] == '-') + fprintf(stderr, "%s\n", X_str); + else + fprintf(stderr, "%s\n", sqlite3_expanded_sql((sqlite3_stmt*)P)); + break; + case SQLITE_TRACE_ROW: + fprintf(stderr, "SQL_DEBUG: ROW - "); + fprintf(stderr, "%s\n", sqlite3_expanded_sql((sqlite3_stmt*)P)); + break; + case SQLITE_TRACE_CLOSE: + fprintf(stderr, "SQL_DEBUG: CLOSE - "); + break; + default: + break; + } + return 0; +} +#endif + +/** + * @internal + * + * + * + * @brief TODO + * + * @param[in] *pArg void + * @param[in] iErrCode int + * @param[in] *zMsg constchar + * + */ +void errorLogCallback(void *pArg, int iErrCode, const char *zMsg){ + fprintf(stderr, "(%d) %s\n", iErrCode, zMsg); +} + +// TODO: refactor and generalise these two functions if possible. +/** + * @internal + * + * + * + * @brief TODO + * + * @param[in] session PEP_SESSION + * @param[in] *table_name constchar + * + */ +static int db_contains_table(PEP_SESSION session, const char* table_name) { + if (!session || !table_name) + return -1; + + // Table names can't be SQL parameters, so we do it this way. + + // these two must be the same number. + char sql_buf[500]; + const size_t max_q_len = 500; + + size_t t_size, q_size; + + const char* q1 = "SELECT name FROM sqlite_master WHERE type='table' AND name='{"; // 61 + const char* q2 = "}';"; // 3 + + q_size = 64; + t_size = strlen(table_name); + + size_t query_len = q_size + t_size + 1; + + if (query_len > max_q_len) + return -1; + + strlcpy(sql_buf, q1, max_q_len); + strlcat(sql_buf, table_name, max_q_len); + strlcat(sql_buf, q2, max_q_len); + + sqlite3_stmt *stmt; + + sqlite3_prepare_v2(session->db, sql_buf, -1, &stmt, NULL); + + int retval = 0; + + int rc = sqlite3_step(stmt); + if (rc == SQLITE_DONE || rc == SQLITE_OK || rc == SQLITE_ROW) { + retval = 1; + } + + sqlite3_finalize(stmt); + + return retval; + +} + +/** + * @internal + * + * + * + * @brief TODO + * + * @param[in] session PEP_SESSION + * @param[in] *table_name constchar + * @param[in] *col_name constchar + * + */ +static int table_contains_column(PEP_SESSION session, const char* table_name, + const char* col_name) { + + + if (!session || !table_name || !col_name) + return -1; + + // Table names can't be SQL parameters, so we do it this way. + + // these two must be the same number. + char sql_buf[500]; + const size_t max_q_len = 500; + + size_t t_size, c_size, q_size; + + const char* q1 = "SELECT "; // 7 + const char* q2 = " from "; // 6 + const char* q3 = ";"; // 1 + + q_size = 14; + t_size = strlen(table_name); + c_size = strlen(col_name); + + size_t query_len = q_size + c_size + t_size + 1; + + if (query_len > max_q_len) + return -1; + + strlcpy(sql_buf, q1, max_q_len); + strlcat(sql_buf, col_name, max_q_len); + strlcat(sql_buf, q2, max_q_len); + strlcat(sql_buf, table_name, max_q_len); + strlcat(sql_buf, q3, max_q_len); + + sqlite3_stmt *stmt; + + sqlite3_prepare_v2(session->db, sql_buf, -1, &stmt, NULL); + + int retval = 0; + + int rc = sqlite3_step(stmt); + if (rc == SQLITE_DONE || rc == SQLITE_OK || rc == SQLITE_ROW) { + retval = 1; + } + + sqlite3_finalize(stmt); + + return retval; +} + +/** + * @internal + * + * + * + * @brief TODO + * + * @param[in] session PEP_SESSION + * + */ +#define _PEP_MAX_AFFECTED 5 +PEP_STATUS repair_altered_tables(PEP_SESSION session) { + PEP_STATUS status = PEP_STATUS_OK; + + char* table_names[_PEP_MAX_AFFECTED] = {0}; + + const char* sql_query = "select tbl_name from sqlite_master WHERE sql LIKE '%REFERENCES%' AND sql LIKE '%_old%';"; + sqlite3_stmt *stmt; + sqlite3_prepare_v2(session->db, sql_query, -1, &stmt, NULL); + int i = 0; + int int_result = 0; + while ((int_result = sqlite3_step(stmt)) == SQLITE_ROW && i < _PEP_MAX_AFFECTED) { + table_names[i++] = strdup((const char*)(sqlite3_column_text(stmt, 0))); + } + + sqlite3_finalize(stmt); + + if ((int_result != SQLITE_DONE && int_result != SQLITE_OK) || i > (_PEP_MAX_AFFECTED + 1)) { + status = PEP_UNKNOWN_DB_ERROR; + goto pEp_free; + } + + for (i = 0; i < _PEP_MAX_AFFECTED; i++) { + const char* table_name = table_names[i]; + if (!table_name) + break; + + if (strcmp(table_name, "identity") == 0) { + int_result = sqlite3_exec(session->db, + "PRAGMA foreign_keys=off;\n" + "BEGIN TRANSACTION;\n" + "create table _identity_new (\n" + " address text,\n" + " user_id text\n" + " references person (id)\n" + " on delete cascade on update cascade,\n" + " main_key_id text\n" + " references pgp_keypair (fpr)\n" + " on delete set null,\n" + " comment text,\n" + " flags integer default 0,\n" + " is_own integer default 0,\n" + " timestamp integer default (datetime('now')),\n" + " primary key (address, user_id)\n" + ");\n" + "INSERT INTO _identity_new SELECT * from identity;\n" + "DROP TABLE identity;\n" + "ALTER TABLE _identity_new RENAME TO identity;\n" + "COMMIT;\n" + "PRAGMA foreign_keys=on;" + , + NULL, + NULL, + NULL + ); + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + } + else if (strcmp(table_name, "trust") == 0) { + int_result = sqlite3_exec(session->db, + "PRAGMA foreign_keys=off;\n" + "BEGIN TRANSACTION;\n" + "create table _trust_new (\n" + " user_id text not null\n" + " references person (id)\n" + " on delete cascade on update cascade,\n" + " pgp_keypair_fpr text not null\n" + " references pgp_keypair (fpr)\n" + " on delete cascade,\n" + " comm_type integer not null,\n" + " comment text,\n" + " primary key (user_id, pgp_keypair_fpr)\n" + ");\n" + "INSERT INTO _trust_new SELECT * from trust;\n" + "DROP TABLE trust;\n" + "ALTER TABLE _trust_new RENAME TO trust;\n" + "COMMIT;\n" + "PRAGMA foreign_keys=on;" + , + NULL, + NULL, + NULL + ); + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + } + else if (strcmp(table_name, "alternate_user_id") == 0) { + int_result = sqlite3_exec(session->db, + "PRAGMA foreign_keys=off;\n" + "BEGIN TRANSACTION;\n" + "create table _alternate_user_id_new (\n" + " default_id text references person (id)\n" + " on delete cascade on update cascade,\n" + " alternate_id text primary key\n" + ");\n" + "INSERT INTO _alternate_user_id_new SELECT * from alternate_user_id;\n" + "DROP TABLE alternate_user_id;\n" + "ALTER TABLE _alternate_user_id_new RENAME TO alternate_user_id;\n" + "COMMIT;\n" + "PRAGMA foreign_keys=on;" + , + NULL, + NULL, + NULL + ); + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + } + else if (strcmp(table_name, "revocation_contact_list") == 0) { + int_result = sqlite3_exec(session->db, + "PRAGMA foreign_keys=off;\n" + "BEGIN TRANSACTION;\n" + "create table _revocation_contact_list_new (\n" + " fpr text not null references pgp_keypair (fpr)\n" + " on delete cascade,\n" + " contact_id text not null references person (id)\n" + " on delete cascade on update cascade,\n" + " timestamp integer default (datetime('now')),\n" + " PRIMARY KEY(fpr, contact_id)\n" + ");\n" + "INSERT INTO _revocation_contact_list_new SELECT * from revocation_contact_list;\n" + "DROP TABLE revocation_contact_list;\n" + "ALTER TABLE _revocation_contact_list_new RENAME TO revocation_contact_list;\n" + "COMMIT;\n" + "PRAGMA foreign_keys=on;" + , + NULL, + NULL, + NULL + ); + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + } + else if (strcmp(table_name, "social_graph")) { + int_result = sqlite3_exec(session->db, + "PRAGMA foreign_keys=off;\n" + "BEGIN TRANSACTION;\n" + "create table _social_new (\n" + " own_userid text,\n" + " own_address text,\n" + " contact_userid text,\n" + " CONSTRAINT fk_own_identity\n" + " FOREIGN KEY(own_address, own_userid)\n" + " REFERENCES identity(address, user_id)\n" + " ON DELETE CASCADE ON UPDATE CASCADE\n" + ");\n" + "INSERT INTO _social_graph_new SELECT * from social_graph;\n" + "DROP TABLE social_graph;\n" + "ALTER TABLE _social_graph_new RENAME TO social_graph;\n" + "COMMIT;\n" + "PRAGMA foreign_keys=on;" + , + NULL, + NULL, + NULL + ); + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + } + } + + int_result = sqlite3_exec( + session->db, + "PRAGMA foreign_key_check;\n" + , + NULL, + NULL, + NULL + ); + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + pEp_free: + for (i = 0; i < _PEP_MAX_AFFECTED; i++) { + free(table_names[i]); + } + return status; +} + +/** + * @internal + * + * + * + * @brief TODO + * + * @param[in] session PEP_SESSION + * + */ +static PEP_STATUS upgrade_revoc_contact_to_13(PEP_SESSION session) { + // I HATE SQLITE. + PEP_STATUS status = PEP_STATUS_OK; + int int_result = 0; + + // Ok, first we ADD the column so we can USE it. + // We will end up propagating the "error" this first time + // (one-to-one revoke-replace relationships), but since key reset + // hasn't been used in production, this is not a customer-facing + // issue. + + // Note: the check upfront is to deal with partially-upgraded DB issues + if (!table_contains_column(session, "revocation_contact_list", "own_address")) { + int_result = sqlite3_exec( + session->db, + "alter table revocation_contact_list\n" + " add column own_address text;\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + } + + // the best we can do here is search per address, since these + // are no longer associated with an identity. For now, if we find + // something we can't add an address to, we'll delete the record. + // this should not, in the current environment, ever happen, but + // since we need to make the address part of the primary key, it's + // the right thing to do. sqlite does support null fields in a primary + // key for a weird version compatibility reason, but that doesn't + // mean we should use it, and we should be *safe*, not relying + // on an implementation-specific quirk which might be sanely removed + // in a future sqlite version. + + identity_list* id_list = NULL; + + sqlite3_stmt* tmp_own_id_retrieve = NULL; + sqlite3_prepare_v2(session->db, sql_own_identities_retrieve, -1, &tmp_own_id_retrieve, NULL); + + // Kludgey - put the stmt in temporarily, and then remove again, so less code dup. + // FIXME LATER: refactor if possible, but... chicken and egg, and thiis case rarely happens. + session->own_identities_retrieve = tmp_own_id_retrieve; + status = own_identities_retrieve(session, &id_list); + sqlite3_finalize(tmp_own_id_retrieve); + session->own_identities_retrieve = NULL; + + if (!status || !id_list) + return PEP_STATUS_OK; // it's empty AFAIK (FIXME) + + identity_list* curr_own = id_list; + + sqlite3_stmt* update_revoked_w_addr_stmt = NULL; + const char* sql_query = "update revocation_contact_list set own_address = ?1 where fpr = ?2;"; + sqlite3_prepare_v2(session->db, sql_query, -1, &update_revoked_w_addr_stmt, NULL); + + // Ok, go through and find any keys associated with this address + for ( ; curr_own && curr_own->ident; curr_own = curr_own->next) { + if (EMPTYSTR(curr_own->ident->address)) // shouldn't happen + continue; + stringlist_t* keylist = NULL; + status = find_keys(session, curr_own->ident->address, &keylist); + stringlist_t* curr_key = keylist; + for ( ; curr_key && curr_key->value; curr_key = curr_key->next) { + if (EMPTYSTR(curr_key->value)) + continue; + + // We just do this lazily - if this isn't a revoked key, it + // won't do anything. + sqlite3_bind_text(update_revoked_w_addr_stmt, 1, curr_own->ident->address, -1, + SQLITE_STATIC); + sqlite3_bind_text(update_revoked_w_addr_stmt, 2, curr_key->value, -1, + SQLITE_STATIC); + + int_result = sqlite3_step(update_revoked_w_addr_stmt); + assert(int_result == SQLITE_DONE); + + sqlite3_reset(update_revoked_w_addr_stmt); + + if (int_result != SQLITE_DONE) + return PEP_UNKNOWN_DB_ERROR; + + } + } + sqlite3_finalize(update_revoked_w_addr_stmt); + + int_result = sqlite3_exec( + session->db, + "delete from revocation_contact_list where own_address is NULL;\n" + "PRAGMA foreign_keys=off;\n" + "BEGIN TRANSACTION;\n" + "create table if not exists _revocation_contact_list_new (\n" + " fpr text not null references pgp_keypair (fpr)\n" + " on delete cascade,\n" + " own_address text,\n" + " contact_id text not null references person (id)\n" + " on delete cascade on update cascade,\n" + " timestamp integer default (datetime('now')),\n" + " PRIMARY KEY(fpr, own_address, contact_id)\n" + ");\n" + "INSERT INTO _revocation_contact_list_new (fpr, " + " own_address, " + " contact_id) " + " SELECT revocation_contact_list.fpr, " + " revocation_contact_list.own_address, " + " revocation_contact_list.contact_id " + " FROM revocation_contact_list " + " WHERE 1;\n" + "DROP TABLE revocation_contact_list;\n" + "ALTER TABLE _revocation_contact_list_new RENAME TO revocation_contact_list;\n" + "COMMIT;\n" + "\n" + "PRAGMA foreign_keys=on;\n" + , + NULL, + NULL, + NULL + ); + + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return status; +} + + +/** + * @internal + * + * + * + * @brief TODO + * + * @param[in] *_version void + * @param[in] count int + * @param[in] **text char + * @param[in] **name char + * + */ +static int user_version(void *_version, int count, char **text, char **name) +{ + if (!(_version && count == 1 && text && text[0])) + return -1; + + int *version = (int *) _version; + *version = atoi(text[0]); + return 0; +} + +PEP_STATUS init_databases(PEP_SESSION session) { + assert(LOCAL_DB); + if (LOCAL_DB == NULL) + return PEP_INIT_CANNOT_OPEN_DB; + +#ifdef _PEP_SQLITE_DEBUG + sqlite3_config(SQLITE_CONFIG_LOG, errorLogCallback, NULL); +#endif + + int int_result = sqlite3_open_v2( + LOCAL_DB, + &session->db, + SQLITE_OPEN_READWRITE + | SQLITE_OPEN_CREATE + | SQLITE_OPEN_FULLMUTEX + | SQLITE_OPEN_PRIVATECACHE, + NULL + ); + + if (int_result != SQLITE_OK) + return PEP_INIT_CANNOT_OPEN_DB; + + int_result = sqlite3_exec( + session->db, + "PRAGMA locking_mode=NORMAL;\n" + "PRAGMA journal_mode=WAL;\n", + NULL, + NULL, + NULL + ); + + sqlite3_busy_timeout(session->db, BUSY_WAIT_TIME); + +#ifdef _PEP_SQLITE_DEBUG + sqlite3_trace_v2(session->db, + SQLITE_TRACE_STMT | SQLITE_TRACE_ROW | SQLITE_TRACE_CLOSE, + sql_trace_callback, + NULL); +#endif + + assert(SYSTEM_DB); + if (SYSTEM_DB == NULL) + return PEP_INIT_CANNOT_OPEN_SYSTEM_DB; + + int_result = sqlite3_open_v2( + SYSTEM_DB, &session->system_db, + SQLITE_OPEN_READONLY + | SQLITE_OPEN_FULLMUTEX + | SQLITE_OPEN_SHAREDCACHE, + NULL + ); + + if (int_result != SQLITE_OK) + return PEP_INIT_CANNOT_OPEN_SYSTEM_DB; + + sqlite3_busy_timeout(session->system_db, 1000); + return PEP_STATUS_OK; +} + +static PEP_STATUS _create_initial_tables(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + "create table if not exists version_info (\n" + " id integer primary key,\n" + " timestamp integer default (datetime('now')),\n" + " version text,\n" + " comment text\n" + ");\n", + NULL, + NULL, + NULL + ); + + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + // This string is now too large for the C standard, so we're going to break it up some. + // I presume we use the enormous string for performance purposes... terrible for debugging purposes, but OK. + int_result = sqlite3_exec( + session->db, + "PRAGMA application_id = 0x23423423;\n" + "create table if not exists log (\n" + " timestamp integer default (datetime('now')),\n" + " title text not null,\n" + " description text,\n" + " entity text not null,\n" + " comment text\n" + ");\n" + "create index if not exists log_timestamp on log (\n" + " timestamp\n" + ");\n" + , + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _create_core_tables(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + "create table if not exists pgp_keypair (\n" + " fpr text primary key,\n" + " created integer,\n" + " expires integer,\n" + " comment text,\n" + " flags integer default 0,\n" + " manually_set integer default 0\n" + ");\n" + "create index if not exists pgp_keypair_expires on pgp_keypair (\n" + " expires\n" + ");\n" + "create table if not exists person (\n" + " id text primary key,\n" + " username text not null,\n" + " main_key_id text\n" + " references pgp_keypair (fpr)\n" + " on delete set null,\n" + " lang text,\n" + " comment text,\n" + // " device_group text,\n" + " is_pEp_user integer default 0\n" + ");\n" + "create table if not exists identity (\n" + " address text,\n" + " user_id text\n" + " references person (id)\n" + " on delete cascade on update cascade,\n" + " main_key_id text\n" + " references pgp_keypair (fpr)\n" + " on delete set null,\n" + " comment text,\n" + " flags integer default 0,\n" + " is_own integer default 0,\n" + " pEp_version_major integer default 0,\n" + " pEp_version_minor integer default 0,\n" + " enc_format integer default 0,\n" + " timestamp integer default (datetime('now')),\n" + " primary key (address, user_id)\n" + ");\n" + "create index if not exists identity_userid_addr on identity(address, user_id);\n" + "create table if not exists trust (\n" + " user_id text not null\n" + " references person (id)\n" + " on delete cascade on update cascade,\n" + " pgp_keypair_fpr text not null\n" + " references pgp_keypair (fpr)\n" + " on delete cascade,\n" + " comm_type integer not null,\n" + " comment text,\n" + " primary key (user_id, pgp_keypair_fpr)\n" + ");\n" + , + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _create_group_tables(PEP_SESSION session) { + if (!session) + return PEP_ILLEGAL_VALUE; + + int int_result = sqlite3_exec( + session->db, + // group information + "create table if not exists groups (\n" + " group_id text,\n" + " group_address text,\n" + " manager_userid text,\n" + " manager_address text,\n" + " active integer default 0,\n" + " constraint groups_pk\n" + " primary key (group_address, group_id),\n" + " constraint group_identity_fk\n" + " foreign key (group_address, group_id) references identity\n" + " on update cascade on delete cascade,\n" + " constraint manager_identity_fk\n" + " foreign key (manager_address, manager_userid) references identity\n" + " on update cascade on delete cascade\n" + ");\n" + "create table if not exists own_memberships (\n" + " group_id text,\n" + " group_address text,\n" + " own_id text,\n" + " own_address text,\n" + " have_joined int default 0,\n" + " constraint own_memberships_pk\n" + " primary key (group_address, group_id),\n" + " constraint own_memberships_own_id_fk\n" + " foreign key (own_address, own_id) references identity\n" + " on update cascade on delete cascade,\n" + " constraint own_memberships_group_fk\n" + " foreign key (group_address, group_id) references groups\n" + " on update cascade on delete cascade\n" + ");\n" + "create table if not exists own_groups_members (\n" + " group_id text,\n" + " group_address text,\n" + " member_id text,\n" + " member_address text,\n" + " active_member int default 0,\n" + " constraint own_groups_members_pk\n" + " primary key (group_address, group_id, member_address, member_id),\n" + " constraint group_ident_fk\n" + " foreign key (group_address, group_id) references groups\n" + " on update cascade on delete cascade,\n" + " constraint member_ident_fk\n" + " foreign key (member_address, member_id) references identity\n" + " on update cascade on delete cascade\n" + ");\n" + , + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _create_supplementary_key_tables(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + // blacklist + "create table if not exists blacklist_keys (\n" + " fpr text primary key\n" + ");\n" + "create table if not exists revoked_keys (\n" + " revoked_fpr text primary key,\n" + " replacement_fpr text not null\n" + " references pgp_keypair (fpr)\n" + " on delete cascade,\n" + " revocation_date integer\n" + ");\n" + // mistrusted keys + "create table if not exists mistrusted_keys (\n" + " fpr text primary key\n" + ");\n" + // social graph for key resets + "create table if not exists social_graph (\n" + " own_userid text,\n" + " own_address text,\n" + " contact_userid text,\n" + " CONSTRAINT fk_own_identity\n" + " FOREIGN KEY(own_address, own_userid)\n" + " REFERENCES identity(address, user_id)\n" + " ON DELETE CASCADE ON UPDATE CASCADE\n" + ");\n" + // list of user_ids sent revocation + "create table if not exists revocation_contact_list (\n" + " fpr text not null references pgp_keypair (fpr)\n" + " on delete cascade,\n" + " own_address text,\n" + " contact_id text not null references person (id)\n" + " on delete cascade on update cascade,\n" + " timestamp integer default (datetime('now')),\n" + " PRIMARY KEY(fpr, own_address, contact_id)\n" + ");\n" + , + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _create_misc_admin_tables(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + // sequences + "create table if not exists sequences(\n" + " name text primary key,\n" + " value integer default 0\n" + ");\n" + // user id aliases + "create table if not exists alternate_user_id (\n" + " default_id text references person (id)\n" + " on delete cascade on update cascade,\n" + " alternate_id text primary key\n" + ");\n" + , + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + + +// The create tables string is now too large for the C standard, so we're going to break it up some. +// I presume we use the enormous string for performance purposes... terrible for debugging purposes, but OK. +PEP_STATUS create_tables(PEP_SESSION session) { + + if (!session) + return PEP_ILLEGAL_VALUE; + + PEP_STATUS status = PEP_STATUS_OK; + + status = _create_initial_tables(session); + if (status != PEP_STATUS_OK) + return status; + + status = _create_core_tables(session); + if (status != PEP_STATUS_OK) + return status; + + status = _create_group_tables(session); + if (status != PEP_STATUS_OK) + return status; + + status = _create_supplementary_key_tables(session); + if (status != PEP_STATUS_OK) + return status; + + status = _create_misc_admin_tables(session); + + return status; +} + +PEP_STATUS get_db_user_version(PEP_SESSION session, int* version) { + int int_result = sqlite3_exec( + session->db, + "pragma user_version;", + user_version, + version, + NULL + ); + + assert(int_result == SQLITE_OK); + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _verify_version(PEP_SESSION session, int* version) { + // Sometimes the user_version wasn't set correctly. + bool version_changed = true; + int int_result; + if (table_contains_column(session, "pgp_keypair", "manually_set")) { + *version = 16; + } + else if (table_contains_column(session, "groups", "group_identity")) { + *version = 15; + } + else if (table_contains_column(session, "identity", "enc_format")) { + *version = 14; + } else if (table_contains_column(session, "revocation_contact_list", "own_address")) { + *version = 13; + } else if (table_contains_column(session, "identity", "pEp_version_major")) { + *version = 12; + } else if (db_contains_table(session, "social_graph") > 0) { + if (!table_contains_column(session, "person", "device_group")) + *version = 10; + else + *version = 9; + } else if (table_contains_column(session, "identity", "timestamp") > 0) { + *version = 8; + } else if (table_contains_column(session, "person", "is_pEp_user") > 0) { + *version = 7; + } else if (table_contains_column(session, "identity", "is_own") > 0) { + *version = 6; + } else if (table_contains_column(session, "pgp_keypair", "flags") > 0) { + *version = 2; + } else { + version_changed = false; + } + + if (version_changed) { + // set it in the DB, finally. Yeesh. + char verbuf[21]; // enough digits for a max-sized 64 bit int, cmon. + sprintf(verbuf, "%d", *version); + + size_t query_size = strlen(verbuf) + 25; + char *query = calloc(query_size, 1); + + strlcpy(query, "pragma user_version = ", query_size); + strlcat(query, verbuf, query_size); + strlcat(query, ";", query_size); + + int_result = sqlite3_exec( + session->db, + query, + user_version, + &*version, + NULL + ); + free(query); + } + + // FIXME: status + return PEP_STATUS_OK; +} + +static PEP_STATUS _upgrade_DB_to_ver_2(PEP_SESSION session) { + // N.B. addition of device_group column removed in DDL v10 + int int_result = sqlite3_exec( + session->db, + "alter table pgp_keypair\n" + " add column flags integer default 0;\n", + // "alter table person\n" + // " add column device_group text;\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _upgrade_DB_to_ver_5(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + "delete from pgp_keypair where fpr = '';", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_exec( + session->db, + "delete from trust where pgp_keypair_fpr = '';", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _upgrade_DB_to_ver_6(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + "alter table identity\n" + " add column is_own integer default 0;\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_exec( + session->db, + "update identity\n" + " set is_own = 1\n" + " where (user_id = '" PEP_OWN_USERID "');\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + // Turns out that just adding "on update cascade" in + // sqlite is a PITA. We need to be able to cascade + // person->id replacements (for temp ids like "TOFU_") + // so here we go... + int_result = sqlite3_exec( + session->db, + "PRAGMA foreign_keys=off;\n" + "BEGIN TRANSACTION;\n" + "create table _identity_new (\n" + " address text,\n" + " user_id text\n" + " references person (id)\n" + " on delete cascade on update cascade,\n" + " main_key_id text\n" + " references pgp_keypair (fpr)\n" + " on delete set null,\n" + " comment text,\n" + " flags integer default 0,\n" + " is_own integer default 0,\n" + " primary key (address, user_id)\n" + ");\n" + "INSERT INTO _identity_new SELECT * FROM identity;\n" + "DROP TABLE identity;\n" + "ALTER TABLE _identity_new RENAME TO identity;\n" + "COMMIT;\n" + "\n" + "BEGIN TRANSACTION;\n" + "create table _trust_new (\n" + " user_id text not null\n" + " references person (id)\n" + " on delete cascade on update cascade,\n" + " pgp_keypair_fpr text not null\n" + " references pgp_keypair (fpr)\n" + " on delete cascade,\n" + " comm_type integer not null,\n" + " comment text,\n" + " primary key (user_id, pgp_keypair_fpr)\n" + ");\n" + "INSERT INTO _trust_new SELECT * FROM trust;\n" + "DROP TABLE trust;\n" + "ALTER TABLE _trust_new RENAME TO trust;\n" + "COMMIT;\n" + "\n" + "PRAGMA foreign_keys=on;\n" + "create table if not exists alternate_user_id (\n" + " default_id text references person (id)\n" + " on delete cascade on update cascade,\n" + " alternate_id text primary key\n" + ");\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_exec( + session->db, + "PRAGMA foreign_key_check;\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + // FIXME: foreign key check here + + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + return PEP_STATUS_OK; +} + +static PEP_STATUS _upgrade_DB_to_ver_7(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + "alter table person\n" + " add column is_pEp_user integer default 0;\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_exec( + session->db, + "update person\n" + " set is_pEp_user = 1\n" + " where id = " + " (select distinct id from person " + " join trust on id = user_id " + " where (case when (comm_type = 127) then (id) " + " when (comm_type = 255) then (id) " + " else 0" + " end) = id );\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_exec( + session->db, + "create table if not exists mistrusted_keys (\n" + " fpr text primary key\n" + ");\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + return PEP_STATUS_OK; +} + +static PEP_STATUS _upgrade_DB_to_ver_8(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + "PRAGMA foreign_keys=off;\n" + "BEGIN TRANSACTION;\n" + "create table _identity_new (\n" + " address text,\n" + " user_id text\n" + " references person (id)\n" + " on delete cascade on update cascade,\n" + " main_key_id text\n" + " references pgp_keypair (fpr)\n" + " on delete set null,\n" + " comment text,\n" + " flags integer default 0,\n" + " is_own integer default 0,\n" + " timestamp integer default (datetime('now')),\n" + " primary key (address, user_id)\n" + ");\n" + "INSERT INTO _identity_new (address, user_id, main_key_id, " + " comment, flags, is_own) " + " SELECT identity.address, identity.user_id, " + " identity.main_key_id, identity.comment, " + " identity.flags, identity.is_own " + " FROM identity " + " WHERE 1;\n" + "DROP TABLE identity;\n" + "ALTER TABLE _identity_new RENAME TO identity;\n" + "COMMIT;\n" + "\n" + "PRAGMA foreign_keys=on;\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_exec( + session->db, + "PRAGMA foreign_key_check;\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + // FIXME: foreign key check + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + + +static PEP_STATUS _upgrade_DB_to_ver_9(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + "create table if not exists social_graph (\n" + " own_userid text,\n" + " own_address text,\n" + " contact_userid text,\n" + " CONSTRAINT fk_own_identity\n" + " FOREIGN KEY(own_address, own_userid)\n" + " REFERENCES identity(address, user_id)\n" + " ON DELETE CASCADE ON UPDATE CASCADE\n" + ");\n" + "create table if not exists revocation_contact_list (\n" + " fpr text not null references pgp_keypair (fpr)\n" + " on delete cascade,\n" + " contact_id text not null references person (id)\n" + " on delete cascade on update cascade,\n" + " timestamp integer default (datetime('now')),\n" + " PRIMARY KEY(fpr, contact_id)\n" + ");\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _upgrade_DB_to_ver_10(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + "PRAGMA foreign_keys=off;\n" + "BEGIN TRANSACTION;\n" + "create table _person_new (\n" + " id text primary key,\n" + " username text not null,\n" + " main_key_id text\n" + " references pgp_keypair (fpr)\n" + " on delete set null,\n" + " lang text,\n" + " comment text,\n" + " is_pEp_user integer default 0\n" + ");\n" + "INSERT INTO _person_new (id, username, main_key_id, " + " lang, comment, is_pEp_user) " + " SELECT person.id, person.username, " + " person.main_key_id, person.lang, " + " person.comment, person.is_pEp_user " + " FROM person " + " WHERE 1;\n" + "DROP TABLE person;\n" + "ALTER TABLE _person_new RENAME TO person;\n" + "COMMIT;\n" + "\n" + "PRAGMA foreign_keys=on;\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_exec( + session->db, + "PRAGMA foreign_key_check;\n", + NULL, + NULL, + NULL + ); + + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _upgrade_DB_to_ver_12(PEP_SESSION session) { + PEP_STATUS status = PEP_STATUS_OK; + + int int_result = sqlite3_exec( + session->db, + "create index if not exists identity_userid_addr on identity(address, user_id);\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_exec( + session->db, + "alter table identity\n" + " add column pEp_version_major integer default 0;\n" + "alter table identity\n" + " add column pEp_version_minor integer default 0;\n", + NULL, + NULL, + NULL + ); + if (status != PEP_STATUS_OK) + return status; + + int_result = sqlite3_exec( + session->db, + "update identity\n" + " set pEp_version_major = 2\n" + " where exists (select * from person\n" + " where identity.user_id = person.id\n" + " and identity.is_own = 0\n" + " and person.is_pEp_user = 1);\n", + NULL, + NULL, + NULL + ); + if (status != PEP_STATUS_OK) + return status; + + // N.B. WE DEFINE PEP_VERSION - IF WE'RE AT 9-DIGIT MAJOR OR MINOR VERSIONS, ER, BAD. + char major_buf[10]; + char minor_buf[10]; + + // Guess we were abusing sscanf here, so we'll do it this way: + const char *cptr = PEP_VERSION; + size_t major_len = 0; + size_t minor_len = 0; + + char *bufptr = major_buf; + while (*cptr != '.' && *cptr != '\0') { + *bufptr++ = *cptr++; + major_len++; + } + *bufptr = '\0'; + bufptr = minor_buf; + + if (*cptr == '.') { + cptr++; + while (*cptr != '\0') { + *bufptr++ = *cptr++; + minor_len++; + } + } else { + *bufptr++ = '0'; + } + *bufptr = '\0'; + + const char *_ver_12_startstr = + "update identity\n" + " set pEp_version_major = "; + const char *_ver_12_midstr = ",\n" + " pEp_version_minor = "; + const char *_ver_12_endstr = + "\n" + " where identity.is_own = 1;\n"; + + size_t new_stringlen = strlen(_ver_12_startstr) + major_len + + strlen(_ver_12_midstr) + minor_len + + strlen(_ver_12_endstr); + + char *_ver_12_stmt = calloc(new_stringlen + 1, 1); + snprintf(_ver_12_stmt, new_stringlen + 1, "%s%s%s%s%s", + _ver_12_startstr, major_buf, _ver_12_midstr, minor_buf, _ver_12_endstr); + + int_result = sqlite3_exec( + session->db, + _ver_12_stmt, + NULL, + NULL, + NULL + ); + free(_ver_12_stmt); + if (status != PEP_STATUS_OK) + return status; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _upgrade_DB_to_ver_14(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + "alter table identity\n" + " add column enc_format integer default 0;\n", + NULL, + NULL, + NULL + ); + + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _upgrade_DB_to_ver_15(PEP_SESSION session) { +// int int_result = sqlite3_exec( +// session->db, +// "alter table pgp_keypair\n" +// " add column manually_set integer default 0;\n", +// NULL, +// NULL, +// NULL +// ); +// +// assert(int_result == SQLITE_OK); +// +// if (int_result != SQLITE_OK) +// return PEP_UNKNOWN_DB_ERROR; + + // FIXME! DO THIS! + return PEP_STATUS_OK; +} + +static PEP_STATUS _upgrade_DB_to_ver_16(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + "alter table pgp_keypair\n" + " add column manually_set integer default 0;\n", + NULL, + NULL, + NULL + ); + + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _check_and_execute_upgrades(PEP_SESSION session, int version) { + PEP_STATUS status = PEP_STATUS_OK; + + switch(version) { + case 1: + status = _upgrade_DB_to_ver_2(session); + if (status != PEP_STATUS_OK) + return status; + case 2: + case 3: + case 4: + status = _upgrade_DB_to_ver_5(session); + if (status != PEP_STATUS_OK) + return status; + case 5: + status = _upgrade_DB_to_ver_6(session); + if (status != PEP_STATUS_OK) + return status; + case 6: + status = _upgrade_DB_to_ver_7(session); + if (status != PEP_STATUS_OK) + return status; + case 7: + status = _upgrade_DB_to_ver_8(session); + if (status != PEP_STATUS_OK) + return status; + case 8: + status = _upgrade_DB_to_ver_9(session); + if (status != PEP_STATUS_OK) + return status; + case 9: + if (version > 1) { + status = _upgrade_DB_to_ver_10(session); + if (status != PEP_STATUS_OK) + return status; + } + case 10: + status = repair_altered_tables(session); + assert(status == PEP_STATUS_OK); + if (status != PEP_STATUS_OK) + return status; + case 11: + status = _upgrade_DB_to_ver_12(session); + if (status != PEP_STATUS_OK) + return status; + case 12: + status = upgrade_revoc_contact_to_13(session); + assert(status == PEP_STATUS_OK); + if (status != PEP_STATUS_OK) + return status; + case 13: + status = _upgrade_DB_to_ver_14(session); + if (status != PEP_STATUS_OK) + return status; + case 14: + status = _upgrade_DB_to_ver_15(session); + if (status != PEP_STATUS_OK) + return status; + case 15: + status = _upgrade_DB_to_ver_16(session); + if (status != PEP_STATUS_OK) + return status; + case 16: + break; + default: + return PEP_ILLEGAL_VALUE; + } + return PEP_STATUS_OK; +} + + +PEP_STATUS pEp_sql_init(PEP_SESSION session) { + bool very_first = false; + PEP_STATUS status = create_tables(session); + if (status != PEP_STATUS_OK) + return status; + + int version = 0; + status = get_db_user_version(session, &version); + if (status != PEP_STATUS_OK) + return status; + + void (*xFunc_lower)(sqlite3_context *, int, sqlite3_value **) = &_sql_lower; + + int int_result = sqlite3_create_function_v2( + session->db, + "lower", + 1, + SQLITE_UTF8 | SQLITE_DETERMINISTIC, + NULL, + xFunc_lower, + NULL, + NULL, + NULL); + + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_exec( + session->db, + "pragma foreign_keys=ON;\n", + NULL, + NULL, + NULL + ); + + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + if (version > atoi(_DDL_USER_VERSION)) { + // This is *explicitly* not allowed. + return PEP_INIT_DB_DOWNGRADE_VIOLATION; + } + + if (version == 1) { + // Sometimes the user_version wasn't set correctly. + status = _verify_version(session, &version); + if (status != PEP_STATUS_OK) + return PEP_ILLEGAL_VALUE; + } + + + if (version != 0) { + // Version has been already set + + // Early mistake : version 0 shouldn't have existed. + // Numbering should have started at 1 to detect newly created DB. + // Version 0 DBs are not anymore compatible. + status = _check_and_execute_upgrades(session, version); + if (status != PEP_STATUS_OK) + return PEP_ILLEGAL_VALUE; + } else { + // Version from DB was 0, it means this is initial setup. + // DB has just been created, and all tables are empty. + very_first = true; + } + + if (version < atoi(_DDL_USER_VERSION)) { + int_result = sqlite3_exec( + session->db, + "pragma user_version = "_DDL_USER_VERSION";\n" + "insert or replace into version_info (id, version)" + "values (1, '" PEP_ENGINE_VERSION "');", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + } + return PEP_STATUS_OK; +} + + +// This whole mess really does need to be generated somewhere. +PEP_STATUS pEp_prepare_sql_stmts(PEP_SESSION session) { + + int int_result = sqlite3_prepare_v2(session->system_db, sql_trustword, + (int)strlen(sql_trustword), &session->trustword, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_get_identity, + (int)strlen(sql_get_identity), &session->get_identity, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_get_identity_without_trust_check, + (int)strlen(sql_get_identity_without_trust_check), + &session->get_identity_without_trust_check, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_identities_by_address, + (int)strlen(sql_get_identities_by_address), + &session->get_identities_by_address, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_identities_by_userid, + (int)strlen(sql_get_identities_by_userid), + &session->get_identities_by_userid, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_identities_by_main_key_id, + (int)strlen(sql_get_identities_by_main_key_id), + &session->get_identities_by_main_key_id, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_user_default_key, + (int)strlen(sql_get_user_default_key), &session->get_user_default_key, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_all_keys_for_user, + (int)strlen(sql_get_all_keys_for_user), &session->get_all_keys_for_user, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_default_own_userid, + (int)strlen(sql_get_default_own_userid), &session->get_default_own_userid, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_userid_alias_default, + (int)strlen(sql_get_userid_alias_default), &session->get_userid_alias_default, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_add_userid_alias, + (int)strlen(sql_add_userid_alias), &session->add_userid_alias, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_replace_userid, + (int)strlen(sql_replace_userid), &session->replace_userid, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_delete_key, + (int)strlen(sql_delete_key), &session->delete_key, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_replace_main_user_fpr, + (int)strlen(sql_replace_main_user_fpr), &session->replace_main_user_fpr, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_replace_main_user_fpr_if_equal, + (int)strlen(sql_replace_main_user_fpr_if_equal), &session->replace_main_user_fpr_if_equal, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_main_user_fpr, + (int)strlen(sql_get_main_user_fpr), &session->get_main_user_fpr, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_refresh_userid_default_key, + (int)strlen(sql_refresh_userid_default_key), &session->refresh_userid_default_key, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_replace_identities_fpr, + (int)strlen(sql_replace_identities_fpr), + &session->replace_identities_fpr, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_remove_fpr_as_identity_default, + (int)strlen(sql_remove_fpr_as_identity_default), + &session->remove_fpr_as_identity_default, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_remove_fpr_as_user_default, + (int)strlen(sql_remove_fpr_as_user_default), + &session->remove_fpr_as_user_default, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_set_person, + (int)strlen(sql_set_person), &session->set_person, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_update_person, + (int)strlen(sql_update_person), &session->update_person, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_delete_person, + (int)strlen(sql_delete_person), &session->delete_person, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_exists_person, + (int)strlen(sql_exists_person), &session->exists_person, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_set_as_pEp_user, + (int)strlen(sql_set_as_pEp_user), &session->set_as_pEp_user, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_is_pEp_user, + (int)strlen(sql_is_pEp_user), &session->is_pEp_user, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_add_into_social_graph, + (int)strlen(sql_add_into_social_graph), &session->add_into_social_graph, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, + sql_get_own_address_binding_from_contact, + (int)strlen(sql_get_own_address_binding_from_contact), + &session->get_own_address_binding_from_contact, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, + sql_set_revoke_contact_as_notified, + (int)strlen(sql_set_revoke_contact_as_notified), + &session->set_revoke_contact_as_notified, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, + sql_get_contacted_ids_from_revoke_fpr, + (int)strlen(sql_get_contacted_ids_from_revoke_fpr), + &session->get_contacted_ids_from_revoke_fpr, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, + sql_was_id_for_revoke_contacted, + (int)strlen(sql_was_id_for_revoke_contacted), + &session->was_id_for_revoke_contacted, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, + sql_has_id_contacted_address, + (int)strlen(sql_has_id_contacted_address), + &session->has_id_contacted_address, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, + sql_get_last_contacted, + (int)strlen(sql_get_last_contacted), + &session->get_last_contacted, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, + sql_get_own_address_binding_from_contact, + (int)strlen(sql_get_own_address_binding_from_contact), + &session->get_own_address_binding_from_contact, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_set_pgp_keypair, + (int)strlen(sql_set_pgp_keypair), &session->set_pgp_keypair, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_set_identity_entry, + (int)strlen(sql_set_identity_entry), &session->set_identity_entry, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_update_identity_entry, + (int)strlen(sql_update_identity_entry), &session->update_identity_entry, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_exists_identity_entry, + (int)strlen(sql_exists_identity_entry), &session->exists_identity_entry, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_set_identity_flags, + (int)strlen(sql_set_identity_flags), &session->set_identity_flags, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_unset_identity_flags, + (int)strlen(sql_unset_identity_flags), &session->unset_identity_flags, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_set_ident_enc_format, + (int)strlen(sql_set_ident_enc_format), &session->set_ident_enc_format, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_set_pEp_version, + (int)strlen(sql_set_pEp_version), &session->set_pEp_version, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_upgrade_pEp_version_by_user_id, + (int)strlen(sql_upgrade_pEp_version_by_user_id), &session->upgrade_pEp_version_by_user_id, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_clear_trust_info, + (int)strlen(sql_clear_trust_info), &session->clear_trust_info, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_set_trust, + (int)strlen(sql_set_trust), &session->set_trust, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_update_trust, + (int)strlen(sql_update_trust), &session->update_trust, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_update_trust_to_pEp, + (int)strlen(sql_update_trust_to_pEp), &session->update_trust_to_pEp, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_exists_trust_entry, + (int)strlen(sql_exists_trust_entry), &session->exists_trust_entry, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_update_trust_for_fpr, + (int)strlen(sql_update_trust_for_fpr), &session->update_trust_for_fpr, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_trust, + (int)strlen(sql_get_trust), &session->get_trust, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_trust_by_userid, + (int)strlen(sql_get_trust_by_userid), &session->get_trust_by_userid, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_least_trust, + (int)strlen(sql_least_trust), &session->least_trust, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_mark_as_compromised, + (int)strlen(sql_mark_as_compromised), &session->mark_compromised, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_crashdump, + (int)strlen(sql_crashdump), &session->crashdump, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->system_db, sql_languagelist, + (int)strlen(sql_languagelist), &session->languagelist, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->system_db, sql_i18n_token, + (int)strlen(sql_i18n_token), &session->i18n_token, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + // blacklist + + int_result = sqlite3_prepare_v2(session->db, sql_blacklist_add, + (int)strlen(sql_blacklist_add), &session->blacklist_add, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_blacklist_delete, + (int)strlen(sql_blacklist_delete), &session->blacklist_delete, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_blacklist_is_listed, + (int)strlen(sql_blacklist_is_listed), + &session->blacklist_is_listed, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_blacklist_retrieve, + (int)strlen(sql_blacklist_retrieve), &session->blacklist_retrieve, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + // Own keys + + int_result = sqlite3_prepare_v2(session->db, sql_own_key_is_listed, + (int)strlen(sql_own_key_is_listed), &session->own_key_is_listed, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_is_own_address, + (int)strlen(sql_is_own_address), &session->is_own_address, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_own_identities_retrieve, + (int)strlen(sql_own_identities_retrieve), + &session->own_identities_retrieve, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_own_keys_retrieve, + (int)strlen(sql_own_keys_retrieve), + &session->own_keys_retrieve, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + // int_result = sqlite3_prepare_v2(session->db, sql_set_own_key, + // (int)strlen(sql_set_own_key), + // &session->set_own_key, NULL); + // assert(int_result == SQLITE_OK); + + + // Sequence + + int_result = sqlite3_prepare_v2(session->db, sql_sequence_value1, + (int)strlen(sql_sequence_value1), &session->sequence_value1, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_sequence_value2, + (int)strlen(sql_sequence_value2), &session->sequence_value2, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + // Revocation tracking + + int_result = sqlite3_prepare_v2(session->db, sql_set_revoked, + (int)strlen(sql_set_revoked), &session->set_revoked, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_revoked, + (int)strlen(sql_get_revoked), &session->get_revoked, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_replacement_fpr, + (int)strlen(sql_get_replacement_fpr), &session->get_replacement_fpr, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_add_mistrusted_key, + (int)strlen(sql_add_mistrusted_key), &session->add_mistrusted_key, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_delete_mistrusted_key, + (int)strlen(sql_delete_mistrusted_key), &session->delete_mistrusted_key, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_is_mistrusted_key, + (int)strlen(sql_is_mistrusted_key), &session->is_mistrusted_key, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + /* Groups */ + int_result = sqlite3_prepare_v2(session->db, sql_create_group, + (int)strlen(sql_create_group), &session->create_group, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_enable_group, + (int)strlen(sql_enable_group), &session->enable_group, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_disable_group, + (int)strlen(sql_disable_group), &session->disable_group, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_exists_group_entry, + (int)strlen(sql_exists_group_entry), &session->exists_group_entry, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_group_add_member, + (int)strlen(sql_group_add_member), &session->group_add_member, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_set_group_member_status, + (int)strlen(sql_set_group_member_status), &session->set_group_member_status, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_join_group, + (int)strlen(sql_join_group), &session->join_group, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_leave_group, + (int)strlen(sql_leave_group), &session->leave_group, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_all_members, + (int)strlen(sql_get_all_members), &session->get_all_members, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + + int_result = sqlite3_prepare_v2(session->db, sql_get_active_members, + (int)strlen(sql_get_active_members), &session->get_active_members, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_all_groups, + (int)strlen(sql_get_all_groups), &session->get_all_groups, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_active_groups, + (int)strlen(sql_get_active_groups), &session->get_active_groups, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_add_own_membership_entry, + (int)strlen(sql_add_own_membership_entry), &session->add_own_membership_entry, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_get_own_membership_status, + (int)strlen(sql_get_own_membership_status), &session->get_own_membership_status, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_retrieve_own_membership_info_for_group_and_ident, + (int)strlen(sql_retrieve_own_membership_info_for_group_and_ident), &session->retrieve_own_membership_info_for_group_and_ident, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_retrieve_own_membership_info_for_group, + (int)strlen(sql_retrieve_own_membership_info_for_group), &session->retrieve_own_membership_info_for_group, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_get_group_manager, + (int)strlen(sql_get_group_manager), &session->get_group_manager, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_is_invited_group_member, + (int)strlen(sql_is_invited_group_member), &session->is_invited_group_member, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_is_group_active, + (int)strlen(sql_is_group_active), &session->is_group_active, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + +// int_result = sqlite3_prepare_v2(session->db, sql_group_invite_exists, +// (int)strlen(sql_group_invite_exists), &session->group_invite_exists, NULL); +// assert(int_result == SQLITE_OK); +// +// if (int_result != SQLITE_OK) +// return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_log, + (int)strlen(sql_log), &session->log, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + /* End groups */ + return PEP_STATUS_OK; +} + +PEP_STATUS pEp_finalize_sql_stmts(PEP_SESSION session) { + if (session->log) + sqlite3_finalize(session->log); + if (session->trustword) + sqlite3_finalize(session->trustword); + if (session->get_identity) + sqlite3_finalize(session->get_identity); + if (session->get_identity_without_trust_check) + sqlite3_finalize(session->get_identity_without_trust_check); + if (session->get_identities_by_address) + sqlite3_finalize(session->get_identities_by_address); + if (session->get_identities_by_userid) + sqlite3_finalize(session->get_identities_by_userid); + if (session->get_identities_by_main_key_id) + sqlite3_finalize(session->get_identities_by_main_key_id); + if (session->get_user_default_key) + sqlite3_finalize(session->get_user_default_key); + if (session->get_all_keys_for_user) + sqlite3_finalize(session->get_all_keys_for_user); + if (session->get_default_own_userid) + sqlite3_finalize(session->get_default_own_userid); + if (session->get_userid_alias_default) + sqlite3_finalize(session->get_userid_alias_default); + if (session->add_userid_alias) + sqlite3_finalize(session->add_userid_alias); + if (session->replace_identities_fpr) + sqlite3_finalize(session->replace_identities_fpr); + if (session->remove_fpr_as_identity_default) + sqlite3_finalize(session->remove_fpr_as_identity_default); + if (session->remove_fpr_as_user_default) + sqlite3_finalize(session->remove_fpr_as_user_default); + if (session->set_person) + sqlite3_finalize(session->set_person); + if (session->delete_person) + sqlite3_finalize(session->delete_person); + if (session->set_as_pEp_user) + sqlite3_finalize(session->set_as_pEp_user); + if (session->upgrade_pEp_version_by_user_id) + sqlite3_finalize(session->upgrade_pEp_version_by_user_id); + if (session->is_pEp_user) + sqlite3_finalize(session->is_pEp_user); + if (session->exists_person) + sqlite3_finalize(session->exists_person); + if (session->add_into_social_graph) + sqlite3_finalize(session->add_into_social_graph); + if (session->get_own_address_binding_from_contact) + sqlite3_finalize(session->get_own_address_binding_from_contact); + if (session->set_revoke_contact_as_notified) + sqlite3_finalize(session->set_revoke_contact_as_notified); + if (session->get_contacted_ids_from_revoke_fpr) + sqlite3_finalize(session->get_contacted_ids_from_revoke_fpr); + if (session->was_id_for_revoke_contacted) + sqlite3_finalize(session->was_id_for_revoke_contacted); + if (session->has_id_contacted_address) + sqlite3_finalize(session->has_id_contacted_address); + if (session->get_last_contacted) + sqlite3_finalize(session->get_last_contacted); + if (session->set_pgp_keypair) + sqlite3_finalize(session->set_pgp_keypair); + if (session->exists_identity_entry) + sqlite3_finalize(session->exists_identity_entry); + if (session->set_identity_entry) + sqlite3_finalize(session->set_identity_entry); + if (session->update_identity_entry) + sqlite3_finalize(session->update_identity_entry); + if (session->set_identity_flags) + sqlite3_finalize(session->set_identity_flags); + if (session->unset_identity_flags) + sqlite3_finalize(session->unset_identity_flags); + if (session->set_ident_enc_format) + sqlite3_finalize(session->set_ident_enc_format); + if (session->set_pEp_version) + sqlite3_finalize(session->set_pEp_version); + if (session->exists_trust_entry) + sqlite3_finalize(session->exists_trust_entry); + if (session->clear_trust_info) + sqlite3_finalize(session->clear_trust_info); + if (session->set_trust) + sqlite3_finalize(session->set_trust); + if (session->update_trust) + sqlite3_finalize(session->update_trust); + if (session->update_trust_to_pEp) + sqlite3_finalize(session->update_trust_to_pEp); + if (session->update_trust_for_fpr) + sqlite3_finalize(session->update_trust_for_fpr); + if (session->get_trust) + sqlite3_finalize(session->get_trust); + if (session->get_trust_by_userid) + sqlite3_finalize(session->get_trust_by_userid); + if (session->least_trust) + sqlite3_finalize(session->least_trust); + if (session->mark_compromised) + sqlite3_finalize(session->mark_compromised); + if (session->crashdump) + sqlite3_finalize(session->crashdump); + if (session->languagelist) + sqlite3_finalize(session->languagelist); + if (session->i18n_token) + sqlite3_finalize(session->i18n_token); + if (session->replace_userid) + sqlite3_finalize(session->replace_userid); + if (session->delete_key) + sqlite3_finalize(session->delete_key); + if (session->replace_main_user_fpr) + sqlite3_finalize(session->replace_main_user_fpr); + if (session->replace_main_user_fpr_if_equal) + sqlite3_finalize(session->replace_main_user_fpr_if_equal); + if (session->get_main_user_fpr) + sqlite3_finalize(session->get_main_user_fpr); + if (session->refresh_userid_default_key) + sqlite3_finalize(session->refresh_userid_default_key); + if (session->blacklist_add) + sqlite3_finalize(session->blacklist_add); + if (session->blacklist_delete) + sqlite3_finalize(session->blacklist_delete); + if (session->blacklist_is_listed) + sqlite3_finalize(session->blacklist_is_listed); + if (session->blacklist_retrieve) + sqlite3_finalize(session->blacklist_retrieve); + if (session->own_key_is_listed) + sqlite3_finalize(session->own_key_is_listed); + if (session->is_own_address) + sqlite3_finalize(session->is_own_address); + if (session->own_identities_retrieve) + sqlite3_finalize(session->own_identities_retrieve); + if (session->own_keys_retrieve) + sqlite3_finalize(session->own_keys_retrieve); + // if (session->set_own_key) + // sqlite3_finalize(session->set_own_key); + if (session->sequence_value1) + sqlite3_finalize(session->sequence_value1); + if (session->sequence_value2) + sqlite3_finalize(session->sequence_value2); + if (session->set_revoked) + sqlite3_finalize(session->set_revoked); + if (session->get_revoked) + sqlite3_finalize(session->get_revoked); + if (session->get_replacement_fpr) + sqlite3_finalize(session->get_replacement_fpr); + if (session->add_mistrusted_key) + sqlite3_finalize(session->add_mistrusted_key); + if (session->delete_mistrusted_key) + sqlite3_finalize(session->delete_mistrusted_key); + if (session->is_mistrusted_key) + sqlite3_finalize(session->is_mistrusted_key); + if (session->create_group) + sqlite3_finalize(session->create_group); + if (session->enable_group) + sqlite3_finalize(session->enable_group); + if (session->disable_group) + sqlite3_finalize(session->disable_group); + if (session->exists_group_entry) + sqlite3_finalize(session->exists_group_entry); + if (session->group_add_member) + sqlite3_finalize(session->group_add_member); + if (session->set_group_member_status) + sqlite3_finalize(session->set_group_member_status); + if (session->join_group) + sqlite3_finalize(session->join_group); + if (session->leave_group) + sqlite3_finalize(session->leave_group); + if (session->get_all_members) + sqlite3_finalize(session->get_all_members); + if (session->get_active_members) + sqlite3_finalize(session->get_active_members); + if (session->get_active_groups) + sqlite3_finalize(session->get_active_groups); + if (session->get_all_groups) + sqlite3_finalize(session->get_all_groups); + if (session->add_own_membership_entry) + sqlite3_finalize(session->add_own_membership_entry); + if (session->get_own_membership_status) + sqlite3_finalize(session->get_own_membership_status); + if (session->retrieve_own_membership_info_for_group_and_ident) + sqlite3_finalize(session->retrieve_own_membership_info_for_group_and_ident); + if (session->retrieve_own_membership_info_for_group) + sqlite3_finalize(session->retrieve_own_membership_info_for_group); + if (session->get_group_manager) + sqlite3_finalize(session->get_group_manager); + if (session->is_invited_group_member) + sqlite3_finalize(session->is_invited_group_member); + if (session->is_group_active) + sqlite3_finalize(session->is_group_active); + // retrieve_own_membership_info_for_group_and_ident + // if (session->group_invite_exists) +// sqlite3_finalize(session->group_invite_exists); + return PEP_STATUS_OK; +} diff --git a/src/engine_sql.h b/src/engine_sql.h new file mode 100644 index 000000000..2ca72e042 --- /dev/null +++ b/src/engine_sql.h @@ -0,0 +1,560 @@ +#pragma once + +#include "pEp_internal.h" + +// increment this when patching DDL +#define _DDL_USER_VERSION "16" + +PEP_STATUS init_databases(PEP_SESSION session); +PEP_STATUS pEp_sql_init(PEP_SESSION session); +PEP_STATUS pEp_prepare_sql_stmts(PEP_SESSION session); +PEP_STATUS pEp_finalize_sql_stmts(PEP_SESSION session); + +/** + * Strings to feed into prepared statements + */ +static const char *sql_log = + "insert into log (title, entity, description, comment)" + "values (?1, ?2, ?3, ?4);"; + +static const char *sql_trustword = + "select id, word from wordlist where lang = lower(?1) " + "and id = ?2 ;"; + +// FIXME?: problems if we don't have a key for the user - we get nothing +static const char *sql_get_identity = + "select identity.main_key_id, username, comm_type, lang," + " identity.flags | pgp_keypair.flags," + " is_own, pEp_version_major, pEp_version_minor, enc_format" + " from identity" + " join person on id = identity.user_id" + " left join pgp_keypair on fpr = identity.main_key_id" + " left join trust on id = trust.user_id" + " and pgp_keypair_fpr = identity.main_key_id" + " where (case when (address = ?1) then (1)" + " when (lower(address) = lower(?1)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)" + " else 0" + " end) = 1" + " and identity.user_id = ?2" + " order by is_own desc, " + " timestamp desc; "; + +static const char *sql_get_identities_by_main_key_id = + "select address, identity.user_id, username, comm_type, lang," + " identity.flags | pgp_keypair.flags," + " is_own, pEp_version_major, pEp_version_minor, enc_format" + " from identity" + " join person on id = identity.user_id" + " left join pgp_keypair on fpr = identity.main_key_id" + " left join trust on id = trust.user_id" + " and pgp_keypair_fpr = identity.main_key_id" + " where identity.main_key_id = ?1" + " order by is_own desc, " + " timestamp desc; "; + +static const char *sql_get_identity_without_trust_check = + "select identity.main_key_id, username, lang," + " identity.flags, is_own, pEp_version_major, pEp_version_minor, enc_format" + " from identity" + " join person on id = identity.user_id" + " where (case when (address = ?1) then (1)" + " when (lower(address) = lower(?1)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)" + " else 0" + " end) = 1" + " and identity.user_id = ?2 " + " order by is_own desc, " + " timestamp desc; "; + +static const char *sql_get_identities_by_address = + "select user_id, identity.main_key_id, username, lang," + " identity.flags, is_own, pEp_version_major, pEp_version_minor, enc_format" + " from identity" + " join person on id = identity.user_id" + " where (case when (address = ?1) then (1)" + " when (lower(address) = lower(?1)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)" + " else 0" + " end) = 1 " + " order by is_own desc, " + " timestamp desc; "; + +static const char *sql_get_identities_by_userid = + "select address, identity.main_key_id, username, comm_type, lang," + " identity.flags | pgp_keypair.flags," + " is_own, pEp_version_major, pEp_version_minor, enc_format" + " from identity" + " join person on id = identity.user_id" + " left join pgp_keypair on fpr = identity.main_key_id" + " left join trust on id = trust.user_id" + " and pgp_keypair_fpr = identity.main_key_id" + " where identity.user_id = ?1" + " order by is_own desc, " + " timestamp desc; "; + +static const char *sql_replace_identities_fpr = + "update identity" + " set main_key_id = ?1 " + " where main_key_id = ?2 ;"; + +static const char *sql_remove_fpr_as_identity_default = + "update identity set main_key_id = NULL where main_key_id = ?1 ;"; + +static const char *sql_remove_fpr_as_user_default = + "update person set main_key_id = NULL where main_key_id = ?1 ;"; + +// Set person, but if already exist, only update. +// if main_key_id already set, don't touch. +static const char *sql_set_person = + "insert into person (id, username, lang, main_key_id)" + " values (?1, ?2, ?3, ?4) ;"; + +static const char *sql_update_person = + "update person " + " set username = ?2, " + " lang = ?3, " + " main_key_id = " + " (select coalesce( " + " (select main_key_id from person where id = ?1), " + " upper(replace(?4,' ',''))))" + " where id = ?1 ;"; + +// Will cascade. +static const char *sql_delete_person = + "delete from person where id = ?1 ;"; + +static const char *sql_set_as_pEp_user = + "update person set is_pEp_user = 1 " + " where id = ?1 ; "; + +static const char *sql_is_pEp_user = + "select is_pEp_user from person " + " where id = ?1 ; "; + +static const char* sql_exists_person = + "select count(*) from person " + " where id = ?1 ;"; + +// This will cascade to identity and trust +static const char* sql_replace_userid = + "update person set id = ?1 " + " where id = ?2;"; + +// Hopefully this cascades and removes trust entries... +static const char *sql_delete_key = + "delete from pgp_keypair " + " where fpr = ?1 ; "; + +static const char *sql_replace_main_user_fpr = + "update person " + " set main_key_id = ?1 " + " where id = ?2 ;"; + +static const char *sql_get_main_user_fpr = + "select main_key_id from person" + " where id = ?1 ;"; + +static const char *sql_replace_main_user_fpr_if_equal = + "update person " + " set main_key_id = ?1 " + " where id = ?2 and main_key_id = ?3;"; + +static const char *sql_refresh_userid_default_key = + "update person " + " set main_key_id = " + " (select identity.main_key_id from identity " + " join trust on trust.user_id = identity.user_id " + " and trust.pgp_keypair_fpr = identity.main_key_id " + " join person on person.id = identity.user_id " + " where identity.user_id = ?1 " + " order by trust.comm_type desc " + " limit 1) " + "where id = ?1 ; "; + +static const char *sql_set_pgp_keypair = + "insert or ignore into pgp_keypair (fpr) " + "values (upper(replace(?1,' ',''))) ;"; + + + +static const char* sql_exists_identity_entry = + "select count(*) from identity " + " where (case when (address = ?1) then (1)" + " when (lower(address) = lower(?1)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)" + " else 0" + " end) = 1" + " and user_id = ?2;"; + +static const char *sql_set_identity_entry = + "insert into identity (" + " address, main_key_id, " + " user_id, flags, is_own," + " pEp_version_major, pEp_version_minor" + " ) values (" + " ?1," + " upper(replace(?2,' ',''))," + " ?3," + " ?4," + " ?5," + " ?6," + " ?7" + " );"; + +static const char* sql_update_identity_entry = + "update identity " + " set main_key_id = upper(replace(?2,' ','')), " + " flags = ?4, " + " is_own = ?5, " + " pEp_version_major = ?6, " + " pEp_version_minor = ?7 " + " where (case when (address = ?1) then (1)" + " when (lower(address) = lower(?1)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1) " + " else 0 " + " end) = 1 " + " and user_id = ?3 ;"; + +// " (select" +// " coalesce(" +// " (select flags from identity" +// " where address = ?1 and" +// " user_id = ?3)," +// " 0)" +// " ) | (?4 & 255)" +/* set_identity ignores previous flags, and doesn't filter machine flags */ + +static const char *sql_set_identity_flags = + "update identity set flags = " + " ((?1 & 65535) | (select flags from identity" + " where (case when (address = ?2) then (1)" + " when (lower(address) = lower(?2)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?2),'.','')) then (1)" + " else 0 " + " end) = 1 " + " and user_id = ?3)) " + " where (case when (address = ?2) then (1)" + " when (lower(address) = lower(?2)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?2),'.','')) then (1)" + " else 0" + " end) = 1" + " and user_id = ?3 ;"; + +static const char *sql_unset_identity_flags = + "update identity set flags = " + " ( ~(?1 & 65535) & (select flags from identity" + " where (case when (address = ?2) then (1)" + " when (lower(address) = lower(?2)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?2),'.','')) then (1)" + " else 0 " + " end) = 1 " + " and user_id = ?3)) " + " where (case when (address = ?2) then (1)" + " when (lower(address) = lower(?2)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?2),'.','')) then (1)" + " else 0" + " end) = 1" + " and user_id = ?3 ;"; + +static const char *sql_set_ident_enc_format = + "update identity " + " set enc_format = ?1 " + " where (case when (address = ?2) then (1)" + " when (lower(address) = lower(?2)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?2),'.','')) then (1) " + " else 0 " + " end) = 1 " + " and user_id = ?3 ;"; + +static const char *sql_set_pEp_version = + "update identity " + " set pEp_version_major = ?1, " + " pEp_version_minor = ?2 " + " where (case when (address = ?3) then (1)" + " when (lower(address) = lower(?3)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?3),'.','')) then (1) " + " else 0 " + " end) = 1 " + " and user_id = ?4 ;"; + +static const char *sql_upgrade_pEp_version_by_user_id = + "update identity " + " set pEp_version_major = ?1, " + " pEp_version_minor = ?2 " + " where user_id = ?3 " + " and (case when (pEp_version_major < ?1) then (1)" + " when (pEp_version_major > ?1) then (0)" + " when (pEp_version_minor < ?2) then (1)" + " else 0 " + " end) = 1 ;"; + +static const char *sql_set_trust = + "insert into trust (user_id, pgp_keypair_fpr, comm_type) " + "values (?1, upper(replace(?2,' ','')), ?3) ;"; + +static const char *sql_update_trust = + "update trust set comm_type = ?3 " + " where user_id = ?1 and pgp_keypair_fpr = upper(replace(?2,' ',''));"; + +static const char *sql_clear_trust_info = + "delete from trust " + " where user_id = ?1 and pgp_keypair_fpr = upper(replace(?2,' ',''));"; + +static const char *sql_update_trust_to_pEp = + "update trust set comm_type = comm_type + 71 " + " where (user_id = ?1 " + " and (case when (comm_type = 56) then (1) " + " when (comm_type = 184) then (1) " + " else 0" + " end) = 1); "; + +static const char* sql_exists_trust_entry = + "select count(*) from trust " + " where user_id = ?1 and pgp_keypair_fpr = upper(replace(?2,' ',''));"; + +static const char *sql_update_trust_for_fpr = + "update trust " + "set comm_type = ?1 " + "where pgp_keypair_fpr = upper(replace(?2,' ','')) ;"; + +static const char *sql_get_trust = + "select comm_type from trust where user_id = ?1 " + "and pgp_keypair_fpr = upper(replace(?2,' ','')) ;"; + +static const char *sql_get_trust_by_userid = + "select pgp_keypair_fpr, comm_type from trust where user_id = ?1 "; + +static const char *sql_least_trust = + "select min(comm_type) from trust where" + " pgp_keypair_fpr = upper(replace(?1,' ',''))" + " and comm_type != 0;"; // ignores PEP_ct_unknown +// returns PEP_ct_unknown only when no known trust is recorded + +static const char *sql_mark_as_compromised = + "update trust not indexed set comm_type = 15" + " where pgp_keypair_fpr = upper(replace(?1,' ','')) ;"; + +static const char *sql_crashdump = + "select timestamp, title, entity, description, comment" + " from log order by timestamp desc limit ?1 ;"; + +static const char *sql_languagelist = + "select i18n_language.lang, name, phrase" + " from i18n_language join i18n_token using (lang) where i18n_token.id = 1000;" ; + +static const char *sql_i18n_token = + "select phrase from i18n_token where lang = lower(?1) and id = ?2 ;"; + +// blacklist +static const char *sql_blacklist_add = + "insert or ignore into blacklist_keys (fpr) values (upper(replace(?1,' ',''))) ;" + "delete from identity where main_key_id = upper(replace(?1,' ','')) ;" + "delete from pgp_keypair where fpr = upper(replace(?1,' ','')) ;"; + +static const char *sql_blacklist_delete = + "delete from blacklist_keys where fpr = upper(replace(?1,' ','')) ;"; + +static const char *sql_blacklist_is_listed = + "select count(*) from blacklist_keys where fpr = upper(replace(?1,' ','')) ;"; + +static const char *sql_blacklist_retrieve = + "select * from blacklist_keys ;"; + + +// Own keys +// We only care if it's 0 or non-zero +static const char *sql_own_key_is_listed = + "select count(*) from (" + " select pgp_keypair_fpr from trust" + " join identity on trust.user_id = identity.user_id" + " where pgp_keypair_fpr = upper(replace(?1,' ',''))" + " and identity.is_own = 1" + ");"; + +static const char *sql_is_own_address = + "select count(*) from (" + " select address from identity" + " where (case when (address = ?1) then (1)" + " when (lower(address) = lower(?1)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)" + " else 0" + " end) = 1 " + " and identity.is_own = 1" + ");"; + +static const char *sql_own_identities_retrieve = + "select address, identity.main_key_id, identity.user_id, username," + " lang, identity.flags | pgp_keypair.flags, pEp_version_major, pEp_version_minor" + " from identity" + " join person on id = identity.user_id" + " left join pgp_keypair on fpr = identity.main_key_id" + " left join trust on id = trust.user_id" + " and pgp_keypair_fpr = identity.main_key_id" + " where identity.is_own = 1" + " and (identity.flags & ?1) = 0;"; + +static const char *sql_own_keys_retrieve = + "select distinct pgp_keypair_fpr from trust" + " join identity on trust.user_id = identity.user_id" + " where identity.is_own = 1"; + +static const char* sql_get_user_default_key = + "select main_key_id from person" + " where id = ?1;"; + +static const char* sql_get_all_keys_for_user = + "select pgp_keypair_fpr from trust" + " where user_id = ?1; "; + +static const char* sql_get_default_own_userid = + "select id from person" + " join identity on id = identity.user_id" + " where identity.is_own = 1"; + +// Sequence +static const char *sql_sequence_value1 = + "insert or replace into sequences (name, value) " + "values (?1, " + " (select coalesce((select value + 1 from sequences " + " where name = ?1), 1 ))); "; + +static const char *sql_sequence_value2 = + "select value from sequences where name = ?1 ;"; + +// Revocation tracking +static const char *sql_set_revoked = + "insert or replace into revoked_keys (" + " revoked_fpr, replacement_fpr, revocation_date) " + "values (upper(replace(?1,' ',''))," + " upper(replace(?2,' ',''))," + " ?3) ;"; + +static const char *sql_get_revoked = + "select revoked_fpr, revocation_date from revoked_keys" + " where replacement_fpr = upper(replace(?1,' ','')) ;"; + +static const char *sql_get_replacement_fpr = + "select replacement_fpr, revocation_date from revoked_keys" + " where revoked_fpr = upper(replace(?1,' ','')) ;"; + +static const char *sql_get_userid_alias_default = + "select default_id from alternate_user_id " + " where alternate_id = ?1 ; "; + +// Revocation tracking +static const char *sql_add_mistrusted_key = + "insert or replace into mistrusted_keys (fpr) " + " values (upper(replace(?1,' ',''))) ;"; + +static const char *sql_delete_mistrusted_key = + "delete from mistrusted_keys where fpr = upper(replace(?1,' ','')) ;"; + +static const char *sql_is_mistrusted_key = + "select count(*) from mistrusted_keys where fpr = upper(replace(?1,' ','')) ;"; + +static const char *sql_add_userid_alias = + "insert or replace into alternate_user_id (alternate_id, default_id) " + "values (?2, ?1) ;"; + +static const char *sql_add_into_social_graph = + "insert or replace into social_graph(own_userid, own_address, contact_userid) " + "values (?1, ?2, ?3) ;"; + +static const char *sql_get_own_address_binding_from_contact = + "select own_address from social_graph where own_userid = ?1 and contact_userid = ?2 ;"; + +static const char *sql_set_revoke_contact_as_notified = + "insert or replace into revocation_contact_list(fpr, own_address, contact_id) values (?1, ?2, ?3) ;"; + +static const char *sql_get_contacted_ids_from_revoke_fpr = + "select * from revocation_contact_list where fpr = ?1 ;"; + +static const char *sql_was_id_for_revoke_contacted = + "select count(*) from revocation_contact_list where fpr = ?1 and own_address = ?2 and contact_id = ?3 ;"; + +static const char *sql_has_id_contacted_address = + "select count(*) from social_graph where own_address = ?1 and contact_userid = ?2 ;"; + +// We only need user_id and address, since in the main usage, we'll call update_identity +// on this anyway when sending out messages. +static const char *sql_get_last_contacted = + "select user_id, address from identity where datetime('now') < datetime(timestamp, '+14 days') ; "; + +static const char *sql_create_group = + "insert into groups (group_id, group_address, manager_userid, manager_address) " + "VALUES (?1, ?2, ?3, ?4) ;"; + +static const char *sql_enable_group = + "update groups set active = 1 " + " where group_id = ?1 and group_address = ?2 ;"; + +static const char *sql_disable_group = + "update groups set active = 0 " + " where group_id = ?1 and group_address = ?2 ;"; + +static const char *sql_exists_group_entry = + "select count(*) from groups " + " where group_id = ?1 and group_address = ?2;"; +static const char *sql_group_add_member = + "insert or ignore into own_groups_members (group_id, group_address, member_id, member_address) " + " values (?1, ?2, ?3, ?4) ;"; +static const char *sql_set_group_member_status = + "update own_groups_members set active_member = ?1 " + " where group_id = ?2 and group_address = ?3 and " + " member_id = ?4 and member_address = ?5; "; +static const char *sql_join_group = + "update own_memberships set have_joined = 1 " + " where group_id = ?1 and group_address = ?2 and " + " own_id = ?3 and own_address = ?4; "; +static const char *sql_leave_group = + "update own_memberships set have_joined = 0 " + " where group_id = ?1 and group_address = ?2 and " + " own_id = ?3 and own_address = ?4; "; +static const char *sql_get_all_members = + "select member_id, member_address, active_member from own_groups_members " + " where group_id = ?1 and group_address = ?2; "; +static const char *sql_get_active_members = + "select member_id, member_address from own_groups_members " + " where group_id = ?1 and group_address = ?2 and active_member = 1; "; +static const char *sql_get_group_manager = + "select manager_userid, manager_address from groups " + " where group_id = ?1 and group_address = ?2; "; +static const char *sql_is_invited_group_member = + "select count(*) from own_groups_members " + " where group_id = ?1 and group_address = ?2 and member_id = ?3 and member_address = ?4; "; +static const char *sql_get_all_groups = + "select group_id, group_address from own_memberships; "; +static const char *sql_get_active_groups = + "select group_id, group_address from own_memberships where have_joined = 1; "; +static const char *sql_add_own_membership_entry = + "insert or replace into own_memberships (group_id, group_address, own_id, own_address, have_joined) " + " values (?1, ?2, ?3, ?4, 0) ; "; +static const char *sql_is_group_active = + "select count(*) from groups " + " where group_id = ?1 and group_address = ?2 and active = 1; "; + +// This below can return multiple entries for multiple idents in same group +// FIXME: decide what we really need here +static const char *sql_retrieve_own_membership_info_for_group = + "select own_id, own_address, have_joined " + " from own_memberships " + " inner join groups using (group_id, group_address) " + " where group_id = ?1 and group_address = ?2; "; + +static const char *sql_retrieve_own_membership_info_for_group_and_ident = + "select have_joined, manager_userid, manager_address, active " + " from own_memberships " + " inner join groups using (group_id, group_address) " + " where group_id = ?1 and group_address = ?2 and own_id = ?3 and own_address = ?4; "; + +// This will return all membership info for all identities +static const char *sql_retrieve_all_own_membership_info = + "select group_id, group_address, own_id, own_address, have_joined, manager_id, manager_address, active " + " from own_memberships " + " inner join using (group_id, group_address); "; + +static const char* sql_get_own_membership_status = + "select have_joined from own_memberships " + " where group_id = ?1 and group_address = ?2 and " + " own_id = ?3 and own_address = ?4; "; diff --git a/src/key_reset.c b/src/key_reset.c index d1a673438..e517958c9 100644 --- a/src/key_reset.c +++ b/src/key_reset.c @@ -23,21 +23,6 @@ #define KEY_RESET_MAJOR_VERSION 1L #define KEY_RESET_MINOR_VERSION 0L -/** - * @internal - * - * - * - * @brief TODO - * - * @param[in] *msg message - * - */ -static void _add_auto_consume(message* msg) { - add_opt_field(msg, "pEp-auto-consume", "yes"); - msg->in_reply_to = stringlist_add(msg->in_reply_to, "pEp-auto-consume@pEp.foundation"); -} - /** * @internal * diff --git a/src/pEpEngine.c b/src/pEpEngine.c index 7bf7afa55..4610d759a 100644 --- a/src/pEpEngine.c +++ b/src/pEpEngine.c @@ -10,6 +10,7 @@ #include "transport.h" #include "blacklist.h" #include "KeySync_fsm.h" +#include "engine_sql.h" #include #include @@ -20,2553 +21,75 @@ static volatile int init_count = -1; -// sql overloaded functions - modified from sqlite3.c -/** - * @internal - * - * - * - * @brief TODO - * - * @param[in] *ctx sqlite3_context - * @param[in] argc int - * @param[in] **argv sqlite3_value - * - */ -static void _sql_lower(sqlite3_context* ctx, int argc, sqlite3_value** argv) { - const char *z2; - int n; - z2 = (char*)sqlite3_value_text(argv[0]); - n = sqlite3_value_bytes(argv[0]); - /* Verify that the call to _bytes() does not invalidate the _text() pointer */ - assert( z2==(char*)sqlite3_value_text(argv[0]) ); - if( z2 ){ - char *z1 = (char*)sqlite3_malloc(n+1); - if( z1 ){ - for(int i=0; i 0x7a) - c_mod = c; - z1[i] = c_mod; - } - z1[n] = '\0'; - sqlite3_result_text(ctx, z1, n, sqlite3_free); - } - } -} - -#ifdef _PEP_SQLITE_DEBUG -/** - * @internal - * - * - * - * @brief TODO - * - * @param[in] trace_constant unsigned - * @param[in] *context_ptr void - * @param[in] *P void - * @param[in] *X void - * - */ -int sql_trace_callback (unsigned trace_constant, - void* context_ptr, - void* P, - void* X) { - switch (trace_constant) { - case SQLITE_TRACE_STMT: - fprintf(stderr, "SQL_DEBUG: STMT - "); - const char* X_str = (const char*) X; - if (!EMPTYSTR(X_str) && X_str[0] == '-' && X_str[1] == '-') - fprintf(stderr, "%s\n", X_str); - else - fprintf(stderr, "%s\n", sqlite3_expanded_sql((sqlite3_stmt*)P)); - break; - case SQLITE_TRACE_ROW: - fprintf(stderr, "SQL_DEBUG: ROW - "); - fprintf(stderr, "%s\n", sqlite3_expanded_sql((sqlite3_stmt*)P)); - break; - case SQLITE_TRACE_CLOSE: - fprintf(stderr, "SQL_DEBUG: CLOSE - "); - break; - default: - break; - } - return 0; -} -#endif - -// sql manipulation statements -static const char *sql_log = - "insert into log (title, entity, description, comment)" - "values (?1, ?2, ?3, ?4);"; - -static const char *sql_trustword = - "select id, word from wordlist where lang = lower(?1) " - "and id = ?2 ;"; - -// FIXME?: problems if we don't have a key for the user - we get nothing -static const char *sql_get_identity = - "select identity.main_key_id, username, comm_type, lang," - " identity.flags | pgp_keypair.flags," - " is_own, pEp_version_major, pEp_version_minor, enc_format" - " from identity" - " join person on id = identity.user_id" - " left join pgp_keypair on fpr = identity.main_key_id" - " left join trust on id = trust.user_id" - " and pgp_keypair_fpr = identity.main_key_id" - " where (case when (address = ?1) then (1)" - " when (lower(address) = lower(?1)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)" - " else 0" - " end) = 1" - " and identity.user_id = ?2" - " order by is_own desc, " - " timestamp desc; "; - -static const char *sql_get_identities_by_main_key_id = - "select address, identity.user_id, username, comm_type, lang," - " identity.flags | pgp_keypair.flags," - " is_own, pEp_version_major, pEp_version_minor, enc_format" - " from identity" - " join person on id = identity.user_id" - " left join pgp_keypair on fpr = identity.main_key_id" - " left join trust on id = trust.user_id" - " and pgp_keypair_fpr = identity.main_key_id" - " where identity.main_key_id = ?1" - " order by is_own desc, " - " timestamp desc; "; - -static const char *sql_get_identity_without_trust_check = - "select identity.main_key_id, username, lang," - " identity.flags, is_own, pEp_version_major, pEp_version_minor, enc_format" - " from identity" - " join person on id = identity.user_id" - " where (case when (address = ?1) then (1)" - " when (lower(address) = lower(?1)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)" - " else 0" - " end) = 1" - " and identity.user_id = ?2 " - " order by is_own desc, " - " timestamp desc; "; - -static const char *sql_get_identities_by_address = - "select user_id, identity.main_key_id, username, lang," - " identity.flags, is_own, pEp_version_major, pEp_version_minor, enc_format" - " from identity" - " join person on id = identity.user_id" - " where (case when (address = ?1) then (1)" - " when (lower(address) = lower(?1)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)" - " else 0" - " end) = 1 " - " order by is_own desc, " - " timestamp desc; "; - -static const char *sql_get_identities_by_userid = - "select address, identity.main_key_id, username, comm_type, lang," - " identity.flags | pgp_keypair.flags," - " is_own, pEp_version_major, pEp_version_minor, enc_format" - " from identity" - " join person on id = identity.user_id" - " left join pgp_keypair on fpr = identity.main_key_id" - " left join trust on id = trust.user_id" - " and pgp_keypair_fpr = identity.main_key_id" - " where identity.user_id = ?1" - " order by is_own desc, " - " timestamp desc; "; - -static const char *sql_replace_identities_fpr = - "update identity" - " set main_key_id = ?1 " - " where main_key_id = ?2 ;"; - -static const char *sql_remove_fpr_as_identity_default = - "update identity set main_key_id = NULL where main_key_id = ?1 ;"; - -static const char *sql_remove_fpr_as_user_default = - "update person set main_key_id = NULL where main_key_id = ?1 ;"; - -// Set person, but if already exist, only update. -// if main_key_id already set, don't touch. -static const char *sql_set_person = - "insert into person (id, username, lang, main_key_id)" - " values (?1, ?2, ?3, ?4) ;"; - -static const char *sql_update_person = - "update person " - " set username = ?2, " - " lang = ?3, " - " main_key_id = " - " (select coalesce( " - " (select main_key_id from person where id = ?1), " - " upper(replace(?4,' ',''))))" - " where id = ?1 ;"; - -// Will cascade. -static const char *sql_delete_person = - "delete from person where id = ?1 ;"; - -static const char *sql_set_as_pEp_user = - "update person set is_pEp_user = 1 " - " where id = ?1 ; "; - -static const char *sql_is_pEp_user = - "select is_pEp_user from person " - " where id = ?1 ; "; - -static const char* sql_exists_person = - "select count(*) from person " - " where id = ?1 ;"; - -// This will cascade to identity and trust -static const char* sql_replace_userid = - "update person set id = ?1 " - " where id = ?2;"; - -// Hopefully this cascades and removes trust entries... -static const char *sql_delete_key = - "delete from pgp_keypair " - " where fpr = ?1 ; "; - -static const char *sql_replace_main_user_fpr = - "update person " - " set main_key_id = ?1 " - " where id = ?2 ;"; - -static const char *sql_get_main_user_fpr = - "select main_key_id from person" - " where id = ?1 ;"; - -static const char *sql_replace_main_user_fpr_if_equal = - "update person " - " set main_key_id = ?1 " - " where id = ?2 and main_key_id = ?3;"; - -static const char *sql_refresh_userid_default_key = - "update person " - " set main_key_id = " - " (select identity.main_key_id from identity " - " join trust on trust.user_id = identity.user_id " - " and trust.pgp_keypair_fpr = identity.main_key_id " - " join person on person.id = identity.user_id " - " where identity.user_id = ?1 " - " order by trust.comm_type desc " - " limit 1) " - "where id = ?1 ; "; - -static const char *sql_set_pgp_keypair = - "insert or ignore into pgp_keypair (fpr) " - "values (upper(replace(?1,' ',''))) ;"; - -static const char* sql_exists_identity_entry = - "select count(*) from identity " - " where (case when (address = ?1) then (1)" - " when (lower(address) = lower(?1)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)" - " else 0" - " end) = 1" - " and user_id = ?2;"; - -static const char *sql_set_identity_entry = - "insert into identity (" - " address, main_key_id, " - " user_id, flags, is_own," - " pEp_version_major, pEp_version_minor" - " ) values (" - " ?1," - " upper(replace(?2,' ',''))," - " ?3," - " ?4," - " ?5," - " ?6," - " ?7" - " );"; - -static const char* sql_update_identity_entry = - "update identity " - " set main_key_id = upper(replace(?2,' ','')), " - " flags = ?4, " - " is_own = ?5, " - " pEp_version_major = ?6, " - " pEp_version_minor = ?7 " - " where (case when (address = ?1) then (1)" - " when (lower(address) = lower(?1)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1) " - " else 0 " - " end) = 1 " - " and user_id = ?3 ;"; - - // " (select" - // " coalesce(" - // " (select flags from identity" - // " where address = ?1 and" - // " user_id = ?3)," - // " 0)" - // " ) | (?4 & 255)" - /* set_identity ignores previous flags, and doesn't filter machine flags */ - -static const char *sql_set_identity_flags = - "update identity set flags = " - " ((?1 & 65535) | (select flags from identity" - " where (case when (address = ?2) then (1)" - " when (lower(address) = lower(?2)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?2),'.','')) then (1)" - " else 0 " - " end) = 1 " - " and user_id = ?3)) " - " where (case when (address = ?2) then (1)" - " when (lower(address) = lower(?2)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?2),'.','')) then (1)" - " else 0" - " end) = 1" - " and user_id = ?3 ;"; - -static const char *sql_unset_identity_flags = - "update identity set flags = " - " ( ~(?1 & 65535) & (select flags from identity" - " where (case when (address = ?2) then (1)" - " when (lower(address) = lower(?2)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?2),'.','')) then (1)" - " else 0 " - " end) = 1 " - " and user_id = ?3)) " - " where (case when (address = ?2) then (1)" - " when (lower(address) = lower(?2)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?2),'.','')) then (1)" - " else 0" - " end) = 1" - " and user_id = ?3 ;"; - -static const char *sql_set_ident_enc_format = - "update identity " - " set enc_format = ?1 " - " where (case when (address = ?2) then (1)" - " when (lower(address) = lower(?2)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?2),'.','')) then (1) " - " else 0 " - " end) = 1 " - " and user_id = ?3 ;"; - -static const char *sql_set_pEp_version = - "update identity " - " set pEp_version_major = ?1, " - " pEp_version_minor = ?2 " - " where (case when (address = ?3) then (1)" - " when (lower(address) = lower(?3)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?3),'.','')) then (1) " - " else 0 " - " end) = 1 " - " and user_id = ?4 ;"; - -static const char *sql_upgrade_pEp_version_by_user_id = - "update identity " - " set pEp_version_major = ?1, " - " pEp_version_minor = ?2 " - " where user_id = ?3 " - " and (case when (pEp_version_major < ?1) then (1)" - " when (pEp_version_major > ?1) then (0)" - " when (pEp_version_minor < ?2) then (1)" - " else 0 " - " end) = 1 ;"; - -static const char *sql_set_trust = - "insert into trust (user_id, pgp_keypair_fpr, comm_type) " - "values (?1, upper(replace(?2,' ','')), ?3) ;"; - -static const char *sql_update_trust = - "update trust set comm_type = ?3 " - " where user_id = ?1 and pgp_keypair_fpr = upper(replace(?2,' ',''));"; - -static const char *sql_clear_trust_info = - "delete from trust " - " where user_id = ?1 and pgp_keypair_fpr = upper(replace(?2,' ',''));"; - -static const char *sql_update_trust_to_pEp = - "update trust set comm_type = comm_type + 71 " - " where (user_id = ?1 " - " and (case when (comm_type = 56) then (1) " - " when (comm_type = 184) then (1) " - " else 0" - " end) = 1); "; - -static const char* sql_exists_trust_entry = - "select count(*) from trust " - " where user_id = ?1 and pgp_keypair_fpr = upper(replace(?2,' ',''));"; - -static const char *sql_update_trust_for_fpr = - "update trust " - "set comm_type = ?1 " - "where pgp_keypair_fpr = upper(replace(?2,' ','')) ;"; - -static const char *sql_get_trust = - "select comm_type from trust where user_id = ?1 " - "and pgp_keypair_fpr = upper(replace(?2,' ','')) ;"; - -static const char *sql_get_trust_by_userid = - "select pgp_keypair_fpr, comm_type from trust where user_id = ?1 "; - -static const char *sql_least_trust = - "select min(comm_type) from trust where" - " pgp_keypair_fpr = upper(replace(?1,' ',''))" - " and comm_type != 0;"; // ignores PEP_ct_unknown - // returns PEP_ct_unknown only when no known trust is recorded - -static const char *sql_mark_as_compromised = - "update trust not indexed set comm_type = 15" - " where pgp_keypair_fpr = upper(replace(?1,' ','')) ;"; - -static const char *sql_crashdump = - "select timestamp, title, entity, description, comment" - " from log order by timestamp desc limit ?1 ;"; - -static const char *sql_languagelist = - "select i18n_language.lang, name, phrase" - " from i18n_language join i18n_token using (lang) where i18n_token.id = 1000;" ; - -static const char *sql_i18n_token = - "select phrase from i18n_token where lang = lower(?1) and id = ?2 ;"; - -// blacklist -static const char *sql_blacklist_add = - "insert or ignore into blacklist_keys (fpr) values (upper(replace(?1,' ',''))) ;" - "delete from identity where main_key_id = upper(replace(?1,' ','')) ;" - "delete from pgp_keypair where fpr = upper(replace(?1,' ','')) ;"; - -static const char *sql_blacklist_delete = - "delete from blacklist_keys where fpr = upper(replace(?1,' ','')) ;"; - -static const char *sql_blacklist_is_listed = - "select count(*) from blacklist_keys where fpr = upper(replace(?1,' ','')) ;"; - -static const char *sql_blacklist_retrieve = - "select * from blacklist_keys ;"; - - -// Own keys -// We only care if it's 0 or non-zero -static const char *sql_own_key_is_listed = - "select count(*) from (" - " select pgp_keypair_fpr from trust" - " join identity on trust.user_id = identity.user_id" - " where pgp_keypair_fpr = upper(replace(?1,' ',''))" - " and identity.is_own = 1" - ");"; - -static const char *sql_is_own_address = - "select count(*) from (" - " select address from identity" - " where (case when (address = ?1) then (1)" - " when (lower(address) = lower(?1)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)" - " else 0" - " end) = 1 " - " and identity.is_own = 1" - ");"; - -static const char *sql_own_identities_retrieve = - "select address, identity.main_key_id, identity.user_id, username," - " lang, identity.flags | pgp_keypair.flags, pEp_version_major, pEp_version_minor" - " from identity" - " join person on id = identity.user_id" - " left join pgp_keypair on fpr = identity.main_key_id" - " left join trust on id = trust.user_id" - " and pgp_keypair_fpr = identity.main_key_id" - " where identity.is_own = 1" - " and (identity.flags & ?1) = 0;"; - -static const char *sql_own_keys_retrieve = - "select distinct pgp_keypair_fpr from trust" - " join identity on trust.user_id = identity.user_id" - " where identity.is_own = 1"; - -static const char* sql_get_user_default_key = - "select main_key_id from person" - " where id = ?1;"; - -static const char* sql_get_all_keys_for_user = - "select pgp_keypair_fpr from trust" - " where user_id = ?1; "; - -static const char* sql_get_default_own_userid = - "select id from person" - " join identity on id = identity.user_id" - " where identity.is_own = 1"; - -// Sequence -static const char *sql_sequence_value1 = - "insert or replace into sequences (name, value) " - "values (?1, " - " (select coalesce((select value + 1 from sequences " - " where name = ?1), 1 ))); "; - -static const char *sql_sequence_value2 = - "select value from sequences where name = ?1 ;"; - -// Revocation tracking -static const char *sql_set_revoked = - "insert or replace into revoked_keys (" - " revoked_fpr, replacement_fpr, revocation_date) " - "values (upper(replace(?1,' ',''))," - " upper(replace(?2,' ',''))," - " ?3) ;"; - -static const char *sql_get_revoked = - "select revoked_fpr, revocation_date from revoked_keys" - " where replacement_fpr = upper(replace(?1,' ','')) ;"; - -static const char *sql_get_replacement_fpr = - "select replacement_fpr, revocation_date from revoked_keys" - " where revoked_fpr = upper(replace(?1,' ','')) ;"; - -static const char *sql_get_userid_alias_default = - "select default_id from alternate_user_id " - " where alternate_id = ?1 ; "; - -// Revocation tracking -static const char *sql_add_mistrusted_key = - "insert or replace into mistrusted_keys (fpr) " - " values (upper(replace(?1,' ',''))) ;"; - -static const char *sql_delete_mistrusted_key = - "delete from mistrusted_keys where fpr = upper(replace(?1,' ','')) ;"; - -static const char *sql_is_mistrusted_key = - "select count(*) from mistrusted_keys where fpr = upper(replace(?1,' ','')) ;"; - -static const char *sql_add_userid_alias = - "insert or replace into alternate_user_id (alternate_id, default_id) " - "values (?2, ?1) ;"; - -static const char *sql_add_into_social_graph = - "insert or replace into social_graph(own_userid, own_address, contact_userid) " - "values (?1, ?2, ?3) ;"; - -static const char *sql_get_own_address_binding_from_contact = - "select own_address from social_graph where own_userid = ?1 and contact_userid = ?2 ;"; - -static const char *sql_set_revoke_contact_as_notified = - "insert or replace into revocation_contact_list(fpr, own_address, contact_id) values (?1, ?2, ?3) ;"; - -static const char *sql_get_contacted_ids_from_revoke_fpr = - "select * from revocation_contact_list where fpr = ?1 ;"; - -static const char *sql_was_id_for_revoke_contacted = - "select count(*) from revocation_contact_list where fpr = ?1 and own_address = ?2 and contact_id = ?3 ;"; - -static const char *sql_has_id_contacted_address = - "select count(*) from social_graph where own_address = ?1 and contact_userid = ?2 ;"; - -// We only need user_id and address, since in the main usage, we'll call update_identity -// on this anyway when sending out messages. -static const char *sql_get_last_contacted = - "select user_id, address from identity where datetime('now') < datetime(timestamp, '+14 days') ; "; - -/** - * @internal - * - * - * - * @brief TODO - * - * @param[in] *_version void - * @param[in] count int - * @param[in] **text char - * @param[in] **name char - * - */ -static int user_version(void *_version, int count, char **text, char **name) -{ - if (!(_version && count == 1 && text && text[0])) - return -1; - - int *version = (int *) _version; - *version = atoi(text[0]); - return 0; -} - -// TODO: refactor and generalise these two functions if possible. -/** - * @internal - * - * - * - * @brief TODO - * - * @param[in] session PEP_SESSION - * @param[in] *table_name constchar - * - */ -static int db_contains_table(PEP_SESSION session, const char* table_name) { - if (!session || !table_name) - return -1; - - // Table names can't be SQL parameters, so we do it this way. - - // these two must be the same number. - char sql_buf[500]; - const size_t max_q_len = 500; - - size_t t_size, q_size; - - const char* q1 = "SELECT name FROM sqlite_master WHERE type='table' AND name='{"; // 61 - const char* q2 = "}';"; // 3 - - q_size = 64; - t_size = strlen(table_name); - - size_t query_len = q_size + t_size + 1; - - if (query_len > max_q_len) - return -1; - - strlcpy(sql_buf, q1, max_q_len); - strlcat(sql_buf, table_name, max_q_len); - strlcat(sql_buf, q2, max_q_len); - - sqlite3_stmt *stmt; - - sqlite3_prepare_v2(session->db, sql_buf, -1, &stmt, NULL); - - int retval = 0; - - int rc = sqlite3_step(stmt); - if (rc == SQLITE_DONE || rc == SQLITE_OK || rc == SQLITE_ROW) { - retval = 1; - } - - sqlite3_finalize(stmt); - - return retval; - -} - -/** - * @internal - * - * - * - * @brief TODO - * - * @param[in] session PEP_SESSION - * @param[in] *table_name constchar - * @param[in] *col_name constchar - * - */ -static int table_contains_column(PEP_SESSION session, const char* table_name, - const char* col_name) { - - - if (!session || !table_name || !col_name) - return -1; - - // Table names can't be SQL parameters, so we do it this way. - - // these two must be the same number. - char sql_buf[500]; - const size_t max_q_len = 500; - - size_t t_size, c_size, q_size; - - const char* q1 = "SELECT "; // 7 - const char* q2 = " from "; // 6 - const char* q3 = ";"; // 1 - - q_size = 14; - t_size = strlen(table_name); - c_size = strlen(col_name); - - size_t query_len = q_size + c_size + t_size + 1; - - if (query_len > max_q_len) - return -1; - - strlcpy(sql_buf, q1, max_q_len); - strlcat(sql_buf, col_name, max_q_len); - strlcat(sql_buf, q2, max_q_len); - strlcat(sql_buf, table_name, max_q_len); - strlcat(sql_buf, q3, max_q_len); - - sqlite3_stmt *stmt; - - sqlite3_prepare_v2(session->db, sql_buf, -1, &stmt, NULL); - - int retval = 0; - - int rc = sqlite3_step(stmt); - if (rc == SQLITE_DONE || rc == SQLITE_OK || rc == SQLITE_ROW) { - retval = 1; - } - - sqlite3_finalize(stmt); - - return retval; -} - -/** - * @internal - * - * - * - * @brief TODO - * - * @param[in] session PEP_SESSION - * - */ -#define _PEP_MAX_AFFECTED 5 -PEP_STATUS repair_altered_tables(PEP_SESSION session) { - PEP_STATUS status = PEP_STATUS_OK; - - char* table_names[_PEP_MAX_AFFECTED] = {0}; - - const char* sql_query = "select tbl_name from sqlite_master WHERE sql LIKE '%REFERENCES%' AND sql LIKE '%_old%';"; - sqlite3_stmt *stmt; - sqlite3_prepare_v2(session->db, sql_query, -1, &stmt, NULL); - int i = 0; - int int_result = 0; - while ((int_result = sqlite3_step(stmt)) == SQLITE_ROW && i < _PEP_MAX_AFFECTED) { - table_names[i++] = strdup((const char*)(sqlite3_column_text(stmt, 0))); - } - - sqlite3_finalize(stmt); - - if ((int_result != SQLITE_DONE && int_result != SQLITE_OK) || i > (_PEP_MAX_AFFECTED + 1)) { - status = PEP_UNKNOWN_DB_ERROR; - goto pEp_free; - } - - for (i = 0; i < _PEP_MAX_AFFECTED; i++) { - const char* table_name = table_names[i]; - if (!table_name) - break; - - if (strcmp(table_name, "identity") == 0) { - int_result = sqlite3_exec(session->db, - "PRAGMA foreign_keys=off;\n" - "BEGIN TRANSACTION;\n" - "create table _identity_new (\n" - " address text,\n" - " user_id text\n" - " references person (id)\n" - " on delete cascade on update cascade,\n" - " main_key_id text\n" - " references pgp_keypair (fpr)\n" - " on delete set null,\n" - " comment text,\n" - " flags integer default 0,\n" - " is_own integer default 0,\n" - " timestamp integer default (datetime('now')),\n" - " primary key (address, user_id)\n" - ");\n" - "INSERT INTO _identity_new SELECT * from identity;\n" - "DROP TABLE identity;\n" - "ALTER TABLE _identity_new RENAME TO identity;\n" - "COMMIT;\n" - "PRAGMA foreign_keys=on;" - , - NULL, - NULL, - NULL - ); - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - } - else if (strcmp(table_name, "trust") == 0) { - int_result = sqlite3_exec(session->db, - "PRAGMA foreign_keys=off;\n" - "BEGIN TRANSACTION;\n" - "create table _trust_new (\n" - " user_id text not null\n" - " references person (id)\n" - " on delete cascade on update cascade,\n" - " pgp_keypair_fpr text not null\n" - " references pgp_keypair (fpr)\n" - " on delete cascade,\n" - " comm_type integer not null,\n" - " comment text,\n" - " primary key (user_id, pgp_keypair_fpr)\n" - ");\n" - "INSERT INTO _trust_new SELECT * from trust;\n" - "DROP TABLE trust;\n" - "ALTER TABLE _trust_new RENAME TO trust;\n" - "COMMIT;\n" - "PRAGMA foreign_keys=on;" - , - NULL, - NULL, - NULL - ); - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - } - else if (strcmp(table_name, "alternate_user_id") == 0) { - int_result = sqlite3_exec(session->db, - "PRAGMA foreign_keys=off;\n" - "BEGIN TRANSACTION;\n" - "create table _alternate_user_id_new (\n" - " default_id text references person (id)\n" - " on delete cascade on update cascade,\n" - " alternate_id text primary key\n" - ");\n" - "INSERT INTO _alternate_user_id_new SELECT * from alternate_user_id;\n" - "DROP TABLE alternate_user_id;\n" - "ALTER TABLE _alternate_user_id_new RENAME TO alternate_user_id;\n" - "COMMIT;\n" - "PRAGMA foreign_keys=on;" - , - NULL, - NULL, - NULL - ); - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - } - else if (strcmp(table_name, "revocation_contact_list") == 0) { - int_result = sqlite3_exec(session->db, - "PRAGMA foreign_keys=off;\n" - "BEGIN TRANSACTION;\n" - "create table _revocation_contact_list_new (\n" - " fpr text not null references pgp_keypair (fpr)\n" - " on delete cascade,\n" - " contact_id text not null references person (id)\n" - " on delete cascade on update cascade,\n" - " timestamp integer default (datetime('now')),\n" - " PRIMARY KEY(fpr, contact_id)\n" - ");\n" - "INSERT INTO _revocation_contact_list_new SELECT * from revocation_contact_list;\n" - "DROP TABLE revocation_contact_list;\n" - "ALTER TABLE _revocation_contact_list_new RENAME TO revocation_contact_list;\n" - "COMMIT;\n" - "PRAGMA foreign_keys=on;" - , - NULL, - NULL, - NULL - ); - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - } - else if (strcmp(table_name, "social_graph")) { - int_result = sqlite3_exec(session->db, - "PRAGMA foreign_keys=off;\n" - "BEGIN TRANSACTION;\n" - "create table _social_new (\n" - " own_userid text,\n" - " own_address text,\n" - " contact_userid text,\n" - " CONSTRAINT fk_own_identity\n" - " FOREIGN KEY(own_address, own_userid)\n" - " REFERENCES identity(address, user_id)\n" - " ON DELETE CASCADE ON UPDATE CASCADE\n" - ");\n" - "INSERT INTO _social_graph_new SELECT * from social_graph;\n" - "DROP TABLE social_graph;\n" - "ALTER TABLE _social_graph_new RENAME TO social_graph;\n" - "COMMIT;\n" - "PRAGMA foreign_keys=on;" - , - NULL, - NULL, - NULL - ); - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - } - } - - int_result = sqlite3_exec( - session->db, - "PRAGMA foreign_key_check;\n" - , - NULL, - NULL, - NULL - ); - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - -pEp_free: - for (i = 0; i < _PEP_MAX_AFFECTED; i++) { - free(table_names[i]); - } - return status; -} -/** - * @internal - * - * - * - * @brief TODO - * - * @param[in] *pArg void - * @param[in] iErrCode int - * @param[in] *zMsg constchar - * - */ -void errorLogCallback(void *pArg, int iErrCode, const char *zMsg){ - fprintf(stderr, "(%d) %s\n", iErrCode, zMsg); -} - -/** - * @internal - * - * - * - * @brief TODO - * - * @param[in] session PEP_SESSION - * - */ -static PEP_STATUS upgrade_revoc_contact_to_13(PEP_SESSION session) { - // I HATE SQLITE. - PEP_STATUS status = PEP_STATUS_OK; - int int_result = 0; - - // Ok, first we ADD the column so we can USE it. - // We will end up propagating the "error" this first time - // (one-to-one revoke-replace relationships), but since key reset - // hasn't been used in production, this is not a customer-facing - // issue. - - // Note: the check upfront is to deal with partially-upgraded DB issues - if (!table_contains_column(session, "revocation_contact_list", "own_address")) { - int_result = sqlite3_exec( - session->db, - "alter table revocation_contact_list\n" - " add column own_address text;\n", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - } - - // the best we can do here is search per address, since these - // are no longer associated with an identity. For now, if we find - // something we can't add an address to, we'll delete the record. - // this should not, in the current environment, ever happen, but - // since we need to make the address part of the primary key, it's - // the right thing to do. sqlite does support null fields in a primary - // key for a weird version compatibility reason, but that doesn't - // mean we should use it, and we should be *safe*, not relying - // on an implementation-specific quirk which might be sanely removed - // in a future sqlite version. - - identity_list* id_list = NULL; - - sqlite3_stmt* tmp_own_id_retrieve = NULL; - sqlite3_prepare_v2(session->db, sql_own_identities_retrieve, -1, &tmp_own_id_retrieve, NULL); - - // Kludgey - put the stmt in temporarily, and then remove again, so less code dup. - // FIXME LATER: refactor if possible, but... chicken and egg, and thiis case rarely happens. - session->own_identities_retrieve = tmp_own_id_retrieve; - status = own_identities_retrieve(session, &id_list); - sqlite3_finalize(tmp_own_id_retrieve); - session->own_identities_retrieve = NULL; - - if (!status || !id_list) - return PEP_STATUS_OK; // it's empty AFAIK (FIXME) - - identity_list* curr_own = id_list; - - sqlite3_stmt* update_revoked_w_addr_stmt = NULL; - const char* sql_query = "update revocation_contact_list set own_address = ?1 where fpr = ?2;"; - sqlite3_prepare_v2(session->db, sql_query, -1, &update_revoked_w_addr_stmt, NULL); - - // Ok, go through and find any keys associated with this address - for ( ; curr_own && curr_own->ident; curr_own = curr_own->next) { - if (EMPTYSTR(curr_own->ident->address)) // shouldn't happen - continue; - stringlist_t* keylist = NULL; - status = find_keys(session, curr_own->ident->address, &keylist); - stringlist_t* curr_key = keylist; - for ( ; curr_key && curr_key->value; curr_key = curr_key->next) { - if (EMPTYSTR(curr_key->value)) - continue; - - // We just do this lazily - if this isn't a revoked key, it - // won't do anything. - sqlite3_bind_text(update_revoked_w_addr_stmt, 1, curr_own->ident->address, -1, - SQLITE_STATIC); - sqlite3_bind_text(update_revoked_w_addr_stmt, 2, curr_key->value, -1, - SQLITE_STATIC); - - int_result = sqlite3_step(update_revoked_w_addr_stmt); - assert(int_result == SQLITE_DONE); - - sqlite3_reset(update_revoked_w_addr_stmt); - - if (int_result != SQLITE_DONE) - return PEP_UNKNOWN_DB_ERROR; - - } - } - sqlite3_finalize(update_revoked_w_addr_stmt); - - int_result = sqlite3_exec( - session->db, - "delete from revocation_contact_list where own_address is NULL;\n" - "PRAGMA foreign_keys=off;\n" - "BEGIN TRANSACTION;\n" - "create table if not exists _revocation_contact_list_new (\n" - " fpr text not null references pgp_keypair (fpr)\n" - " on delete cascade,\n" - " own_address text,\n" - " contact_id text not null references person (id)\n" - " on delete cascade on update cascade,\n" - " timestamp integer default (datetime('now')),\n" - " PRIMARY KEY(fpr, own_address, contact_id)\n" - ");\n" - "INSERT INTO _revocation_contact_list_new (fpr, " - " own_address, " - " contact_id) " - " SELECT revocation_contact_list.fpr, " - " revocation_contact_list.own_address, " - " revocation_contact_list.contact_id " - " FROM revocation_contact_list " - " WHERE 1;\n" - "DROP TABLE revocation_contact_list;\n" - "ALTER TABLE _revocation_contact_list_new RENAME TO revocation_contact_list;\n" - "COMMIT;\n" - "\n" - "PRAGMA foreign_keys=on;\n" - , - NULL, - NULL, - NULL - ); - - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - return status; -} - -DYNAMIC_API PEP_STATUS init( - PEP_SESSION *session, - messageToSend_t messageToSend, - inject_sync_event_t inject_sync_event, - ensure_passphrase_t ensure_passphrase - ) -{ - PEP_STATUS status = PEP_STATUS_OK; - int int_result; - - bool in_first = false; - bool very_first = false; - - assert(sqlite3_threadsafe()); - if (!sqlite3_threadsafe()) - return PEP_INIT_SQLITE3_WITHOUT_MUTEX; - - // a little race condition - but still a race condition - // mitigated by calling caveat (see documentation) - - // this increment is made atomic IN THE ADAPTERS by - // guarding the call to init with the appropriate mutex. - int _count = ++init_count; - if (_count == 0) - in_first = true; - - // Race condition mitigated by calling caveat starts here : - // If another call to init() preempts right now, then preemptive call - // will have in_first false, will not create SQL tables, and following - // calls relying on those tables will fail. - // - // Therefore, as above, adapters MUST guard init() with a mutex. - // - // Therefore, first session - // is to be created and last session to be deleted alone, and not - // concurently to other sessions creation or deletion. - // We expect adapters to enforce this either by implicitely creating a - // client session, or by using synchronization primitive to protect - // creation/deletion of first/last session from the app. - - if (session == NULL) - return PEP_ILLEGAL_VALUE; - - *session = NULL; - - pEpSession *_session = calloc(1, sizeof(pEpSession)); - assert(_session); - if (_session == NULL) - goto enomem; - - _session->version = PEP_ENGINE_VERSION; - _session->messageToSend = messageToSend; - _session->inject_sync_event = inject_sync_event; - _session->ensure_passphrase = ensure_passphrase; - - assert(LOCAL_DB); - if (LOCAL_DB == NULL) { - status = PEP_INIT_CANNOT_OPEN_DB; - goto pEp_error; - } - -#ifdef _PEP_SQLITE_DEBUG - sqlite3_config(SQLITE_CONFIG_LOG, errorLogCallback, NULL); -#endif - - int_result = sqlite3_open_v2( - LOCAL_DB, - &_session->db, - SQLITE_OPEN_READWRITE - | SQLITE_OPEN_CREATE - | SQLITE_OPEN_FULLMUTEX - | SQLITE_OPEN_PRIVATECACHE, - NULL - ); - - if (int_result != SQLITE_OK) { - status = PEP_INIT_CANNOT_OPEN_DB; - goto pEp_error; - } - - int_result = sqlite3_exec( - _session->db, - "PRAGMA locking_mode=NORMAL;\n" - "PRAGMA journal_mode=WAL;\n", - NULL, - NULL, - NULL - ); - - - sqlite3_busy_timeout(_session->db, BUSY_WAIT_TIME); - -#ifdef _PEP_SQLITE_DEBUG - sqlite3_trace_v2(_session->db, - SQLITE_TRACE_STMT | SQLITE_TRACE_ROW | SQLITE_TRACE_CLOSE, - sql_trace_callback, - NULL); -#endif - - assert(SYSTEM_DB); - if (SYSTEM_DB == NULL) { - status = PEP_INIT_CANNOT_OPEN_SYSTEM_DB; - goto pEp_error; - } - - int_result = sqlite3_open_v2( - SYSTEM_DB, &_session->system_db, - SQLITE_OPEN_READONLY - | SQLITE_OPEN_FULLMUTEX - | SQLITE_OPEN_SHAREDCACHE, - NULL - ); - - if (int_result != SQLITE_OK) { - status = PEP_INIT_CANNOT_OPEN_SYSTEM_DB; - goto pEp_error; - } - - sqlite3_busy_timeout(_session->system_db, 1000); - -// increment this when patching DDL -#define _DDL_USER_VERSION "14" - - if (in_first) { - - int_result = sqlite3_exec( - _session->db, - "create table if not exists version_info (\n" - " id integer primary key,\n" - " timestamp integer default (datetime('now')),\n" - " version text,\n" - " comment text\n" - ");\n", - NULL, - NULL, - NULL - ); - int_result = sqlite3_exec( - _session->db, - "PRAGMA application_id = 0x23423423;\n" - "create table if not exists log (\n" - " timestamp integer default (datetime('now')),\n" - " title text not null,\n" - " description text,\n" - " entity text not null,\n" - " comment text\n" - ");\n" - "create index if not exists log_timestamp on log (\n" - " timestamp\n" - ");\n" - "create table if not exists pgp_keypair (\n" - " fpr text primary key,\n" - " created integer,\n" - " expires integer,\n" - " comment text,\n" - " flags integer default 0\n" - ");\n" - "create index if not exists pgp_keypair_expires on pgp_keypair (\n" - " expires\n" - ");\n" - "create table if not exists person (\n" - " id text primary key,\n" - " username text not null,\n" - " main_key_id text\n" - " references pgp_keypair (fpr)\n" - " on delete set null,\n" - " lang text,\n" - " comment text,\n" -// " device_group text,\n" - " is_pEp_user integer default 0\n" - ");\n" - "create table if not exists identity (\n" - " address text,\n" - " user_id text\n" - " references person (id)\n" - " on delete cascade on update cascade,\n" - " main_key_id text\n" - " references pgp_keypair (fpr)\n" - " on delete set null,\n" - " comment text,\n" - " flags integer default 0,\n" - " is_own integer default 0,\n" - " pEp_version_major integer default 0,\n" - " pEp_version_minor integer default 0,\n" - " enc_format integer default 0,\n" - " timestamp integer default (datetime('now')),\n" - " primary key (address, user_id)\n" - ");\n" - "create index if not exists identity_userid_addr on identity(address, user_id);\n" - "create table if not exists trust (\n" - " user_id text not null\n" - " references person (id)\n" - " on delete cascade on update cascade,\n" - " pgp_keypair_fpr text not null\n" - " references pgp_keypair (fpr)\n" - " on delete cascade,\n" - " comm_type integer not null,\n" - " comment text,\n" - " primary key (user_id, pgp_keypair_fpr)\n" - ");\n" - // blacklist - "create table if not exists blacklist_keys (\n" - " fpr text primary key\n" - ");\n" - // sequences - "create table if not exists sequences(\n" - " name text primary key,\n" - " value integer default 0\n" - ");\n" - "create table if not exists revoked_keys (\n" - " revoked_fpr text primary key,\n" - " replacement_fpr text not null\n" - " references pgp_keypair (fpr)\n" - " on delete cascade,\n" - " revocation_date integer\n" - ");\n" - // user id aliases - "create table if not exists alternate_user_id (\n" - " default_id text references person (id)\n" - " on delete cascade on update cascade,\n" - " alternate_id text primary key\n" - ");\n" - // mistrusted keys - "create table if not exists mistrusted_keys (\n" - " fpr text primary key\n" - ");\n" - // social graph for key resets - "create table if not exists social_graph (\n" - " own_userid text,\n" - " own_address text,\n" - " contact_userid text,\n" - " CONSTRAINT fk_own_identity\n" - " FOREIGN KEY(own_address, own_userid)\n" - " REFERENCES identity(address, user_id)\n" - " ON DELETE CASCADE ON UPDATE CASCADE\n" - ");\n" - // list of user_ids sent revocation - "create table if not exists revocation_contact_list (\n" - " fpr text not null references pgp_keypair (fpr)\n" - " on delete cascade,\n" - " own_address text,\n" - " contact_id text not null references person (id)\n" - " on delete cascade on update cascade,\n" - " timestamp integer default (datetime('now')),\n" - " PRIMARY KEY(fpr, own_address, contact_id)\n" - ");\n" - , - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int version; - int_result = sqlite3_exec( - _session->db, - "pragma user_version;", - user_version, - &version, - NULL - ); - - assert(int_result == SQLITE_OK); - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - void (*xFunc_lower)(sqlite3_context*,int,sqlite3_value**) = &_sql_lower; - - int_result = sqlite3_create_function_v2( - _session->db, - "lower", - 1, - SQLITE_UTF8 | SQLITE_DETERMINISTIC, - NULL, - xFunc_lower, - NULL, - NULL, - NULL); - - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_exec( - _session->db, - "pragma foreign_keys=ON;\n", - NULL, - NULL, - NULL - ); - - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - if (version > atoi(_DDL_USER_VERSION)) { - // This is *explicitly* not allowed. - return PEP_INIT_DB_DOWNGRADE_VIOLATION; - } - - // Sometimes the user_version wasn't set correctly. - if (version == 1) { - bool version_changed = true; - if (table_contains_column(_session, "identity", "enc_format")) { - version = 14; - } - else if (table_contains_column(_session, "revocation_contact_list", "own_address")) { - version = 13; - } - else if (table_contains_column(_session, "identity", "pEp_version_major")) { - version = 12; - } - else if (db_contains_table(_session, "social_graph") > 0) { - if (!table_contains_column(_session, "person", "device_group")) - version = 10; - else - version = 9; - } - else if (table_contains_column(_session, "identity", "timestamp") > 0) { - version = 8; - } - else if (table_contains_column(_session, "person", "is_pEp_user") > 0) { - version = 7; - } - else if (table_contains_column(_session, "identity", "is_own") > 0) { - version = 6; - } - else if (table_contains_column(_session, "pgp_keypair", "flags") > 0) { - version = 2; - } - else { - version_changed = false; - } - - if (version_changed) { - // set it in the DB, finally. Yeesh. - char verbuf[21]; // enough digits for a max-sized 64 bit int, cmon. - sprintf(verbuf,"%d",version); - - size_t query_size = strlen(verbuf) + 25; - char* query = calloc(query_size, 1); - - strlcpy(query, "pragma user_version = ", query_size); - strlcat(query, verbuf, query_size); - strlcat(query, ";", query_size); - - int_result = sqlite3_exec( - _session->db, - query, - user_version, - &version, - NULL - ); - free(query); - } - } - - - if(version != 0) { - // Version has been already set - - // Early mistake : version 0 shouldn't have existed. - // Numbering should have started at 1 to detect newly created DB. - // Version 0 DBs are not anymore compatible. - - // // Was version 0 compat code. - // if (version < 1) { - // int_result = sqlite3_exec( - // _session->db, - // "alter table identity\n" - // " add column flags integer default 0;\n", - // NULL, - // NULL, - // NULL - // ); - // assert(int_result == SQLITE_OK); - // } - - if (version < 2) { - // N.B. addition of device_group column removed in DDL v10 - int_result = sqlite3_exec( - _session->db, - "alter table pgp_keypair\n" - " add column flags integer default 0;\n", - // "alter table person\n" - // " add column device_group text;\n", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - } - - if (version < 5) { - int_result = sqlite3_exec( - _session->db, - "delete from pgp_keypair where fpr = '';", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - int_result = sqlite3_exec( - _session->db, - "delete from trust where pgp_keypair_fpr = '';", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - } - - if (version < 6) { - int_result = sqlite3_exec( - _session->db, - "alter table identity\n" - " add column is_own integer default 0;\n", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - int_result = sqlite3_exec( - _session->db, - "update identity\n" - " set is_own = 1\n" - " where (user_id = '" PEP_OWN_USERID "');\n", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - // Turns out that just adding "on update cascade" in - // sqlite is a PITA. We need to be able to cascade - // person->id replacements (for temp ids like "TOFU_") - // so here we go... - int_result = sqlite3_exec( - _session->db, - "PRAGMA foreign_keys=off;\n" - "BEGIN TRANSACTION;\n" - "create table _identity_new (\n" - " address text,\n" - " user_id text\n" - " references person (id)\n" - " on delete cascade on update cascade,\n" - " main_key_id text\n" - " references pgp_keypair (fpr)\n" - " on delete set null,\n" - " comment text,\n" - " flags integer default 0,\n" - " is_own integer default 0,\n" - " primary key (address, user_id)\n" - ");\n" - "INSERT INTO _identity_new SELECT * FROM identity;\n" - "DROP TABLE identity;\n" - "ALTER TABLE _identity_new RENAME TO identity;\n" - "COMMIT;\n" - "\n" - "BEGIN TRANSACTION;\n" - "create table _trust_new (\n" - " user_id text not null\n" - " references person (id)\n" - " on delete cascade on update cascade,\n" - " pgp_keypair_fpr text not null\n" - " references pgp_keypair (fpr)\n" - " on delete cascade,\n" - " comm_type integer not null,\n" - " comment text,\n" - " primary key (user_id, pgp_keypair_fpr)\n" - ");\n" - "INSERT INTO _trust_new SELECT * FROM trust;\n" - "DROP TABLE trust;\n" - "ALTER TABLE _trust_new RENAME TO trust;\n" - "COMMIT;\n" - "\n" - "PRAGMA foreign_keys=on;\n" - "create table if not exists alternate_user_id (\n" - " default_id text references person (id)\n" - " on delete cascade on update cascade,\n" - " alternate_id text primary key\n" - ");\n" - , - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_exec( - _session->db, - "PRAGMA foreign_key_check;\n" - , - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - // FIXME: foreign key check here - } - if (version < 7) { - int_result = sqlite3_exec( - _session->db, - "alter table person\n" - " add column is_pEp_user integer default 0;\n", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - int_result = sqlite3_exec( - _session->db, - "update person\n" - " set is_pEp_user = 1\n" - " where id = " - " (select distinct id from person " - " join trust on id = user_id " - " where (case when (comm_type = 127) then (id) " - " when (comm_type = 255) then (id) " - " else 0" - " end) = id );\n", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_exec( - _session->db, - "create table if not exists mistrusted_keys (\n" - " fpr text primary key\n" - ");\n", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - } - if (version < 8) { - int_result = sqlite3_exec( - _session->db, - "PRAGMA foreign_keys=off;\n" - "BEGIN TRANSACTION;\n" - "create table _identity_new (\n" - " address text,\n" - " user_id text\n" - " references person (id)\n" - " on delete cascade on update cascade,\n" - " main_key_id text\n" - " references pgp_keypair (fpr)\n" - " on delete set null,\n" - " comment text,\n" - " flags integer default 0,\n" - " is_own integer default 0,\n" - " timestamp integer default (datetime('now')),\n" - " primary key (address, user_id)\n" - ");\n" - "INSERT INTO _identity_new (address, user_id, main_key_id, " - " comment, flags, is_own) " - " SELECT identity.address, identity.user_id, " - " identity.main_key_id, identity.comment, " - " identity.flags, identity.is_own " - " FROM identity " - " WHERE 1;\n" - "DROP TABLE identity;\n" - "ALTER TABLE _identity_new RENAME TO identity;\n" - "COMMIT;\n" - "\n" - "PRAGMA foreign_keys=on;\n" - , - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_exec( - _session->db, - "PRAGMA foreign_key_check;\n" - , - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - // FIXME: foreign key check - } - if (version < 9) { - int_result = sqlite3_exec( - _session->db, - "create table if not exists social_graph (\n" - " own_userid text,\n" - " own_address text,\n" - " contact_userid text,\n" - " CONSTRAINT fk_own_identity\n" - " FOREIGN KEY(own_address, own_userid)\n" - " REFERENCES identity(address, user_id)\n" - " ON DELETE CASCADE ON UPDATE CASCADE\n" - ");\n" - "create table if not exists revocation_contact_list (\n" - " fpr text not null references pgp_keypair (fpr)\n" - " on delete cascade,\n" - " contact_id text not null references person (id)\n" - " on delete cascade on update cascade,\n" - " timestamp integer default (datetime('now')),\n" - " PRIMARY KEY(fpr, contact_id)\n" - ");\n" - , - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - } - if (version < 10 && version > 1) { - int_result = sqlite3_exec( - _session->db, - "PRAGMA foreign_keys=off;\n" - "BEGIN TRANSACTION;\n" - "create table _person_new (\n" - " id text primary key,\n" - " username text not null,\n" - " main_key_id text\n" - " references pgp_keypair (fpr)\n" - " on delete set null,\n" - " lang text,\n" - " comment text,\n" - " is_pEp_user integer default 0\n" - ");\n" - "INSERT INTO _person_new (id, username, main_key_id, " - " lang, comment, is_pEp_user) " - " SELECT person.id, person.username, " - " person.main_key_id, person.lang, " - " person.comment, person.is_pEp_user " - " FROM person " - " WHERE 1;\n" - "DROP TABLE person;\n" - "ALTER TABLE _person_new RENAME TO person;\n" - "COMMIT;\n" - "\n" - "PRAGMA foreign_keys=on;\n" - , - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - int_result = sqlite3_exec( - _session->db, - "PRAGMA foreign_key_check;\n" - , - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - } - if (version < 11) { - status = repair_altered_tables(_session); - assert(status == PEP_STATUS_OK); - if (status != PEP_STATUS_OK) - return status; - } - if (version < 12) { - int_result = sqlite3_exec( - _session->db, - "create index if not exists identity_userid_addr on identity(address, user_id);\n" - , - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_exec( - _session->db, - "alter table identity\n" - " add column pEp_version_major integer default 0;\n" - "alter table identity\n" - " add column pEp_version_minor integer default 0;\n", - NULL, - NULL, - NULL - ); - if (status != PEP_STATUS_OK) - return status; - - int_result = sqlite3_exec( - _session->db, - "update identity\n" - " set pEp_version_major = 2\n" - " where exists (select * from person\n" - " where identity.user_id = person.id\n" - " and identity.is_own = 0\n" - " and person.is_pEp_user = 1);\n", - NULL, - NULL, - NULL - ); - if (status != PEP_STATUS_OK) - return status; - - // N.B. WE DEFINE PEP_VERSION - IF WE'RE AT 9-DIGIT MAJOR OR MINOR VERSIONS, ER, BAD. - char major_buf[10]; - char minor_buf[10]; - - // Guess we were abusing sscanf here, so we'll do it this way: - const char* cptr = PEP_VERSION; - size_t major_len = 0; - size_t minor_len = 0; - - char* bufptr = major_buf; - while (*cptr != '.' && *cptr != '\0') { - *bufptr++ = *cptr++; - major_len++; - } - *bufptr = '\0'; - bufptr = minor_buf; - - if (*cptr == '.') { - cptr++; - while (*cptr != '\0') { - *bufptr++ = *cptr++; - minor_len++; - } - } - else { - *bufptr++ = '0'; - } - *bufptr = '\0'; - - const char* _ver_12_startstr = - "update identity\n" - " set pEp_version_major = "; - const char* _ver_12_midstr = ",\n" - " pEp_version_minor = "; - const char* _ver_12_endstr = - "\n" - " where identity.is_own = 1;\n"; - - size_t new_stringlen = strlen(_ver_12_startstr) + major_len + - strlen(_ver_12_midstr) + minor_len + - strlen(_ver_12_endstr); - - char* _ver_12_stmt = calloc(new_stringlen + 1, 1); - snprintf(_ver_12_stmt, new_stringlen + 1, "%s%s%s%s%s", - _ver_12_startstr, major_buf, _ver_12_midstr, minor_buf, _ver_12_endstr); - - int_result = sqlite3_exec( - _session->db, - _ver_12_stmt, - NULL, - NULL, - NULL - ); - free(_ver_12_stmt); - if (status != PEP_STATUS_OK) - return status; - } - if (version < 13) { - status = upgrade_revoc_contact_to_13(_session); - assert(status == PEP_STATUS_OK); - if (status != PEP_STATUS_OK) - return status; - } - if (version < 14) { - int_result = sqlite3_exec( - _session->db, - "alter table identity\n" - " add column enc_format integer default 0;\n", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - } - - } - else { - // Version from DB was 0, it means this is initial setup. - // DB has just been created, and all tables are empty. - very_first = true; - } - - if (version < atoi(_DDL_USER_VERSION)) { - int_result = sqlite3_exec( - _session->db, - "pragma user_version = "_DDL_USER_VERSION";\n" - "insert or replace into version_info (id, version)" - "values (1, '" PEP_ENGINE_VERSION "');", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - } - - // We need to init a few globals for message id that we'd rather not - // calculate more than once. - _init_globals(); - } - - int_result = sqlite3_prepare_v2(_session->db, sql_log, - (int)strlen(sql_log), &_session->log, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->system_db, sql_trustword, - (int)strlen(sql_trustword), &_session->trustword, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_identity, - (int)strlen(sql_get_identity), &_session->get_identity, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_identity_without_trust_check, - (int)strlen(sql_get_identity_without_trust_check), - &_session->get_identity_without_trust_check, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_identities_by_address, - (int)strlen(sql_get_identities_by_address), - &_session->get_identities_by_address, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_identities_by_userid, - (int)strlen(sql_get_identities_by_userid), - &_session->get_identities_by_userid, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_identities_by_main_key_id, - (int)strlen(sql_get_identities_by_main_key_id), - &_session->get_identities_by_main_key_id, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_user_default_key, - (int)strlen(sql_get_user_default_key), &_session->get_user_default_key, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_all_keys_for_user, - (int)strlen(sql_get_all_keys_for_user), &_session->get_all_keys_for_user, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_default_own_userid, - (int)strlen(sql_get_default_own_userid), &_session->get_default_own_userid, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_userid_alias_default, - (int)strlen(sql_get_userid_alias_default), &_session->get_userid_alias_default, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_add_userid_alias, - (int)strlen(sql_add_userid_alias), &_session->add_userid_alias, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_replace_userid, - (int)strlen(sql_replace_userid), &_session->replace_userid, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_delete_key, - (int)strlen(sql_delete_key), &_session->delete_key, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_replace_main_user_fpr, - (int)strlen(sql_replace_main_user_fpr), &_session->replace_main_user_fpr, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_replace_main_user_fpr_if_equal, - (int)strlen(sql_replace_main_user_fpr_if_equal), &_session->replace_main_user_fpr_if_equal, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_main_user_fpr, - (int)strlen(sql_get_main_user_fpr), &_session->get_main_user_fpr, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_refresh_userid_default_key, - (int)strlen(sql_refresh_userid_default_key), &_session->refresh_userid_default_key, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_replace_identities_fpr, - (int)strlen(sql_replace_identities_fpr), - &_session->replace_identities_fpr, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_remove_fpr_as_identity_default, - (int)strlen(sql_remove_fpr_as_identity_default), - &_session->remove_fpr_as_identity_default, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_remove_fpr_as_user_default, - (int)strlen(sql_remove_fpr_as_user_default), - &_session->remove_fpr_as_user_default, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_set_person, - (int)strlen(sql_set_person), &_session->set_person, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_update_person, - (int)strlen(sql_update_person), &_session->update_person, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_delete_person, - (int)strlen(sql_delete_person), &_session->delete_person, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_exists_person, - (int)strlen(sql_exists_person), &_session->exists_person, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_set_as_pEp_user, - (int)strlen(sql_set_as_pEp_user), &_session->set_as_pEp_user, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_is_pEp_user, - (int)strlen(sql_is_pEp_user), &_session->is_pEp_user, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_add_into_social_graph, - (int)strlen(sql_add_into_social_graph), &_session->add_into_social_graph, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, - sql_get_own_address_binding_from_contact, - (int)strlen(sql_get_own_address_binding_from_contact), - &_session->get_own_address_binding_from_contact, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, - sql_set_revoke_contact_as_notified, - (int)strlen(sql_set_revoke_contact_as_notified), - &_session->set_revoke_contact_as_notified, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, - sql_get_contacted_ids_from_revoke_fpr, - (int)strlen(sql_get_contacted_ids_from_revoke_fpr), - &_session->get_contacted_ids_from_revoke_fpr, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, - sql_was_id_for_revoke_contacted, - (int)strlen(sql_was_id_for_revoke_contacted), - &_session->was_id_for_revoke_contacted, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, - sql_has_id_contacted_address, - (int)strlen(sql_has_id_contacted_address), - &_session->has_id_contacted_address, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, - sql_get_last_contacted, - (int)strlen(sql_get_last_contacted), - &_session->get_last_contacted, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, - sql_get_own_address_binding_from_contact, - (int)strlen(sql_get_own_address_binding_from_contact), - &_session->get_own_address_binding_from_contact, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_set_pgp_keypair, - (int)strlen(sql_set_pgp_keypair), &_session->set_pgp_keypair, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_set_identity_entry, - (int)strlen(sql_set_identity_entry), &_session->set_identity_entry, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_update_identity_entry, - (int)strlen(sql_update_identity_entry), &_session->update_identity_entry, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_exists_identity_entry, - (int)strlen(sql_exists_identity_entry), &_session->exists_identity_entry, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_set_identity_flags, - (int)strlen(sql_set_identity_flags), &_session->set_identity_flags, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_unset_identity_flags, - (int)strlen(sql_unset_identity_flags), &_session->unset_identity_flags, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_set_ident_enc_format, - (int)strlen(sql_set_ident_enc_format), &_session->set_ident_enc_format, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_set_pEp_version, - (int)strlen(sql_set_pEp_version), &_session->set_pEp_version, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_upgrade_pEp_version_by_user_id, - (int)strlen(sql_upgrade_pEp_version_by_user_id), &_session->upgrade_pEp_version_by_user_id, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_clear_trust_info, - (int)strlen(sql_clear_trust_info), &_session->clear_trust_info, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_set_trust, - (int)strlen(sql_set_trust), &_session->set_trust, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_update_trust, - (int)strlen(sql_update_trust), &_session->update_trust, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_update_trust_to_pEp, - (int)strlen(sql_update_trust_to_pEp), &_session->update_trust_to_pEp, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_exists_trust_entry, - (int)strlen(sql_exists_trust_entry), &_session->exists_trust_entry, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_update_trust_for_fpr, - (int)strlen(sql_update_trust_for_fpr), &_session->update_trust_for_fpr, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_trust, - (int)strlen(sql_get_trust), &_session->get_trust, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_trust_by_userid, - (int)strlen(sql_get_trust_by_userid), &_session->get_trust_by_userid, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_least_trust, - (int)strlen(sql_least_trust), &_session->least_trust, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_mark_as_compromised, - (int)strlen(sql_mark_as_compromised), &_session->mark_compromised, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_crashdump, - (int)strlen(sql_crashdump), &_session->crashdump, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->system_db, sql_languagelist, - (int)strlen(sql_languagelist), &_session->languagelist, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->system_db, sql_i18n_token, - (int)strlen(sql_i18n_token), &_session->i18n_token, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - // blacklist - - int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_add, - (int)strlen(sql_blacklist_add), &_session->blacklist_add, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_delete, - (int)strlen(sql_blacklist_delete), &_session->blacklist_delete, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_is_listed, - (int)strlen(sql_blacklist_is_listed), - &_session->blacklist_is_listed, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - +DYNAMIC_API PEP_STATUS init( + PEP_SESSION *session, + messageToSend_t messageToSend, + inject_sync_event_t inject_sync_event, + ensure_passphrase_t ensure_passphrase + ) +{ + PEP_STATUS status = PEP_STATUS_OK; - int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_retrieve, - (int)strlen(sql_blacklist_retrieve), &_session->blacklist_retrieve, - NULL); - assert(int_result == SQLITE_OK); + bool in_first = false; - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; + assert(sqlite3_threadsafe()); + if (!sqlite3_threadsafe()) + return PEP_INIT_SQLITE3_WITHOUT_MUTEX; + // a little race condition - but still a race condition + // mitigated by calling caveat (see documentation) - // Own keys + // this increment is made atomic IN THE ADAPTERS by + // guarding the call to init with the appropriate mutex. + int _count = ++init_count; + if (_count == 0) + in_first = true; - int_result = sqlite3_prepare_v2(_session->db, sql_own_key_is_listed, - (int)strlen(sql_own_key_is_listed), &_session->own_key_is_listed, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_is_own_address, - (int)strlen(sql_is_own_address), &_session->is_own_address, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_own_identities_retrieve, - (int)strlen(sql_own_identities_retrieve), - &_session->own_identities_retrieve, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_own_keys_retrieve, - (int)strlen(sql_own_keys_retrieve), - &_session->own_keys_retrieve, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - // int_result = sqlite3_prepare_v2(_session->db, sql_set_own_key, - // (int)strlen(sql_set_own_key), - // &_session->set_own_key, NULL); - // assert(int_result == SQLITE_OK); - - - // Sequence - - int_result = sqlite3_prepare_v2(_session->db, sql_sequence_value1, - (int)strlen(sql_sequence_value1), &_session->sequence_value1, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - + // Race condition mitigated by calling caveat starts here : + // If another call to init() preempts right now, then preemptive call + // will have in_first false, will not create SQL tables, and following + // calls relying on those tables will fail. + // + // Therefore, as above, adapters MUST guard init() with a mutex. + // + // Therefore, first session + // is to be created and last session to be deleted alone, and not + // concurently to other sessions creation or deletion. + // We expect adapters to enforce this either by implicitely creating a + // client session, or by using synchronization primitive to protect + // creation/deletion of first/last session from the app. - int_result = sqlite3_prepare_v2(_session->db, sql_sequence_value2, - (int)strlen(sql_sequence_value2), &_session->sequence_value2, - NULL); - assert(int_result == SQLITE_OK); + if (session == NULL) + return PEP_ILLEGAL_VALUE; - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; + *session = NULL; + pEpSession *_session = calloc(1, sizeof(pEpSession)); + assert(_session); + if (_session == NULL) + goto enomem; - // Revocation tracking + _session->version = PEP_ENGINE_VERSION; + _session->messageToSend = messageToSend; + _session->inject_sync_event = inject_sync_event; + _session->ensure_passphrase = ensure_passphrase; - int_result = sqlite3_prepare_v2(_session->db, sql_set_revoked, - (int)strlen(sql_set_revoked), &_session->set_revoked, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_revoked, - (int)strlen(sql_get_revoked), &_session->get_revoked, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_replacement_fpr, - (int)strlen(sql_get_replacement_fpr), &_session->get_replacement_fpr, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_add_mistrusted_key, - (int)strlen(sql_add_mistrusted_key), &_session->add_mistrusted_key, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_delete_mistrusted_key, - (int)strlen(sql_delete_mistrusted_key), &_session->delete_mistrusted_key, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; + status = init_databases(_session); + if (status != PEP_STATUS_OK) + return status; + if (in_first) { - int_result = sqlite3_prepare_v2(_session->db, sql_is_mistrusted_key, - (int)strlen(sql_is_mistrusted_key), &_session->is_mistrusted_key, NULL); - assert(int_result == SQLITE_OK); + status = pEp_sql_init(_session); - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; + // We need to init a few globals for message id that we'd rather not + // calculate more than once. + _init_globals(); + } + status = pEp_prepare_sql_stmts(_session); + if (status != PEP_STATUS_OK) + goto pEp_error; status = init_cryptotech(_session, in_first); if (status != PEP_STATUS_OK) @@ -2623,151 +146,7 @@ DYNAMIC_API void release(PEP_SESSION session) free_Sync_state(session); if (session->db) { - if (session->log) - sqlite3_finalize(session->log); - if (session->trustword) - sqlite3_finalize(session->trustword); - if (session->get_identity) - sqlite3_finalize(session->get_identity); - if (session->get_identity_without_trust_check) - sqlite3_finalize(session->get_identity_without_trust_check); - if (session->get_identities_by_address) - sqlite3_finalize(session->get_identities_by_address); - if (session->get_identities_by_userid) - sqlite3_finalize(session->get_identities_by_userid); - if (session->get_identities_by_main_key_id) - sqlite3_finalize(session->get_identities_by_main_key_id); - if (session->get_user_default_key) - sqlite3_finalize(session->get_user_default_key); - if (session->get_all_keys_for_user) - sqlite3_finalize(session->get_all_keys_for_user); - if (session->get_default_own_userid) - sqlite3_finalize(session->get_default_own_userid); - if (session->get_userid_alias_default) - sqlite3_finalize(session->get_userid_alias_default); - if (session->add_userid_alias) - sqlite3_finalize(session->add_userid_alias); - if (session->replace_identities_fpr) - sqlite3_finalize(session->replace_identities_fpr); - if (session->remove_fpr_as_identity_default) - sqlite3_finalize(session->remove_fpr_as_identity_default); - if (session->remove_fpr_as_user_default) - sqlite3_finalize(session->remove_fpr_as_user_default); - if (session->set_person) - sqlite3_finalize(session->set_person); - if (session->delete_person) - sqlite3_finalize(session->delete_person); - if (session->set_as_pEp_user) - sqlite3_finalize(session->set_as_pEp_user); - if (session->upgrade_pEp_version_by_user_id) - sqlite3_finalize(session->upgrade_pEp_version_by_user_id); - if (session->is_pEp_user) - sqlite3_finalize(session->is_pEp_user); - if (session->exists_person) - sqlite3_finalize(session->exists_person); - if (session->add_into_social_graph) - sqlite3_finalize(session->add_into_social_graph); - if (session->get_own_address_binding_from_contact) - sqlite3_finalize(session->get_own_address_binding_from_contact); - if (session->set_revoke_contact_as_notified) - sqlite3_finalize(session->set_revoke_contact_as_notified); - if (session->get_contacted_ids_from_revoke_fpr) - sqlite3_finalize(session->get_contacted_ids_from_revoke_fpr); - if (session->was_id_for_revoke_contacted) - sqlite3_finalize(session->was_id_for_revoke_contacted); - if (session->has_id_contacted_address) - sqlite3_finalize(session->has_id_contacted_address); - if (session->get_last_contacted) - sqlite3_finalize(session->get_last_contacted); - if (session->set_pgp_keypair) - sqlite3_finalize(session->set_pgp_keypair); - if (session->exists_identity_entry) - sqlite3_finalize(session->exists_identity_entry); - if (session->set_identity_entry) - sqlite3_finalize(session->set_identity_entry); - if (session->update_identity_entry) - sqlite3_finalize(session->update_identity_entry); - if (session->set_identity_flags) - sqlite3_finalize(session->set_identity_flags); - if (session->unset_identity_flags) - sqlite3_finalize(session->unset_identity_flags); - if (session->set_ident_enc_format) - sqlite3_finalize(session->set_ident_enc_format); - if (session->set_pEp_version) - sqlite3_finalize(session->set_pEp_version); - if (session->exists_trust_entry) - sqlite3_finalize(session->exists_trust_entry); - if (session->clear_trust_info) - sqlite3_finalize(session->clear_trust_info); - if (session->set_trust) - sqlite3_finalize(session->set_trust); - if (session->update_trust) - sqlite3_finalize(session->update_trust); - if (session->update_trust_to_pEp) - sqlite3_finalize(session->update_trust_to_pEp); - if (session->update_trust_for_fpr) - sqlite3_finalize(session->update_trust_for_fpr); - if (session->get_trust) - sqlite3_finalize(session->get_trust); - if (session->get_trust_by_userid) - sqlite3_finalize(session->get_trust_by_userid); - if (session->least_trust) - sqlite3_finalize(session->least_trust); - if (session->mark_compromised) - sqlite3_finalize(session->mark_compromised); - if (session->crashdump) - sqlite3_finalize(session->crashdump); - if (session->languagelist) - sqlite3_finalize(session->languagelist); - if (session->i18n_token) - sqlite3_finalize(session->i18n_token); - if (session->replace_userid) - sqlite3_finalize(session->replace_userid); - if (session->delete_key) - sqlite3_finalize(session->delete_key); - if (session->replace_main_user_fpr) - sqlite3_finalize(session->replace_main_user_fpr); - if (session->replace_main_user_fpr_if_equal) - sqlite3_finalize(session->replace_main_user_fpr_if_equal); - if (session->get_main_user_fpr) - sqlite3_finalize(session->get_main_user_fpr); - if (session->refresh_userid_default_key) - sqlite3_finalize(session->refresh_userid_default_key); - if (session->blacklist_add) - sqlite3_finalize(session->blacklist_add); - if (session->blacklist_delete) - sqlite3_finalize(session->blacklist_delete); - if (session->blacklist_is_listed) - sqlite3_finalize(session->blacklist_is_listed); - if (session->blacklist_retrieve) - sqlite3_finalize(session->blacklist_retrieve); - if (session->own_key_is_listed) - sqlite3_finalize(session->own_key_is_listed); - if (session->is_own_address) - sqlite3_finalize(session->is_own_address); - if (session->own_identities_retrieve) - sqlite3_finalize(session->own_identities_retrieve); - if (session->own_keys_retrieve) - sqlite3_finalize(session->own_keys_retrieve); - // if (session->set_own_key) - // sqlite3_finalize(session->set_own_key); - if (session->sequence_value1) - sqlite3_finalize(session->sequence_value1); - if (session->sequence_value2) - sqlite3_finalize(session->sequence_value2); - if (session->set_revoked) - sqlite3_finalize(session->set_revoked); - if (session->get_revoked) - sqlite3_finalize(session->get_revoked); - if (session->get_replacement_fpr) - sqlite3_finalize(session->get_replacement_fpr); - if (session->add_mistrusted_key) - sqlite3_finalize(session->add_mistrusted_key); - if (session->delete_mistrusted_key) - sqlite3_finalize(session->delete_mistrusted_key); - if (session->is_mistrusted_key) - sqlite3_finalize(session->is_mistrusted_key); - + pEp_finalize_sql_stmts(session); if (session->db) { if (out_last) { sqlite3_exec( diff --git a/src/pEp_internal.h b/src/pEp_internal.h index 7be2446ac..8deb97898 100644 --- a/src/pEp_internal.h +++ b/src/pEp_internal.h @@ -22,6 +22,7 @@ #include "commit_hash.h" // We need this everywhere. So. + // maximum attachment size to import as key 25MB, maximum of 20 attachments #define MAX_KEY_SIZE (25 * 1024 * 1024) #define MAX_KEYS_TO_IMPORT 20 @@ -121,6 +122,9 @@ #include "pgp_sequoia_internal.h" #endif +#include "../asn.1/Distribution.h" +#include "../asn.1/Sync.h" + #include "keymanagement.h" #include "cryptotech.h" #include "transport.h" @@ -250,6 +254,26 @@ struct _pEpSession { sqlite3_stmt *get_default_own_userid; + // groups + sqlite3_stmt *create_group; + sqlite3_stmt *enable_group; + sqlite3_stmt *disable_group; + sqlite3_stmt *exists_group_entry; + sqlite3_stmt *group_add_member; + sqlite3_stmt *join_group; + sqlite3_stmt *leave_group; + sqlite3_stmt *set_group_member_status; + sqlite3_stmt *get_all_members; + sqlite3_stmt *get_active_members; + sqlite3_stmt *get_active_groups; + sqlite3_stmt *get_all_groups; + sqlite3_stmt *add_own_membership_entry; + sqlite3_stmt *get_own_membership_status; + sqlite3_stmt *retrieve_own_membership_info_for_group_and_ident; + sqlite3_stmt *retrieve_own_membership_info_for_group; + sqlite3_stmt *get_group_manager; + sqlite3_stmt *is_invited_group_member; + sqlite3_stmt *is_group_active; // sqlite3_stmt *set_own_key; @@ -749,16 +773,20 @@ extern double _pEp_log2_36; /** * - * + * + * @internal + * * @brief TODO * - * + * Please leave _patch_asn1_codec COMMENTED OUT unless you're working + * in a branch or patching the asn1 is a solution */ static inline void _init_globals() { _pEp_rand_max_bits = (int) ceil(log2((double) RAND_MAX)); _pEp_log2_36 = log2(36); } + // spinlock implementation /** @@ -778,4 +806,20 @@ static inline int Sqlite3_step(sqlite3_stmt* stmt) return rc; } +/** + * @internal + * + * + * + * @brief TODO + * + * @param[in] *msg message + * + */ +static inline void _add_auto_consume(message* msg) { + add_opt_field(msg, "pEp-auto-consume", "yes"); + msg->in_reply_to = stringlist_add(msg->in_reply_to, "pEp-auto-consume@pEp.foundation"); +} + + #endif