diff --git a/src/blacklist.c b/src/blacklist.c index e8eb8c71..d15080dc 100644 --- a/src/blacklist.c +++ b/src/blacklist.c @@ -13,6 +13,8 @@ DYNAMIC_API PEP_STATUS blacklist_add(PEP_SESSION session, const char *fpr) if (!(session && fpr && fpr[0])) return PEP_ILLEGAL_VALUE; + sqlite3_exec(session->db, "BEGIN ;", NULL, NULL, NULL); + sqlite3_reset(session->blacklist_add); sqlite3_bind_text(session->blacklist_add, 1, fpr, -1, SQLITE_STATIC); @@ -22,9 +24,11 @@ DYNAMIC_API PEP_STATUS blacklist_add(PEP_SESSION session, const char *fpr) switch (result) { case SQLITE_DONE: status = PEP_STATUS_OK; + sqlite3_exec(session->db, "COMMIT ;", NULL, NULL, NULL); break; default: + sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL); status = PEP_UNKNOWN_ERROR; } @@ -157,4 +161,3 @@ enomem: the_end: return status; } - diff --git a/src/keymanagement.c b/src/keymanagement.c index 922091b2..0d8ffa66 100644 --- a/src/keymanagement.c +++ b/src/keymanagement.c @@ -1070,7 +1070,12 @@ DYNAMIC_API PEP_STATUS key_mistrusted( // set mistrust for this user_id/keypair (even if there's not an // identity set yet, this is important, as we need to record the mistrust // action) - status = set_trust(session, ident->user_id, ident->fpr, PEP_ct_mistrusted); + + // We set this temporarily but will grab it back from the cache afterwards + ident->comm_type = PEP_ct_mistrusted; + status = set_trust(session, ident); + ident->comm_type = session->cached_mistrusted->comm_type; + if (status == PEP_STATUS_OK) // cascade that mistrust for anyone using this key status = mark_as_compromized(session, ident->fpr); @@ -1140,7 +1145,9 @@ DYNAMIC_API PEP_STATUS key_reset_trust( if (input_copy->comm_type != PEP_ct_mistrusted) new_trust = input_copy->comm_type & ~PEP_ct_confirmed; - status = set_trust(session, ident->user_id, ident->fpr, new_trust); + // We'll return the status from the input_copy cache afterward + input_copy->comm_type = new_trust; + status = set_trust(session, input_copy); if (status != PEP_STATUS_OK) goto pep_free; @@ -1157,8 +1164,6 @@ DYNAMIC_API PEP_STATUS key_reset_trust( if (status != PEP_STATUS_OK) goto pep_free; - - input_copy->comm_type = new_trust; tmp_ident = new_identity(ident->address, NULL, ident->user_id, NULL); @@ -1263,7 +1268,7 @@ DYNAMIC_API PEP_STATUS trust_personal_key( trusted_default = true; - status = set_trust(session, tmp_id->user_id, cached_fpr, tmp_id->comm_type); + status = set_trust(session, tmp_id); input_default_ct = tmp_id->comm_type; } else { diff --git a/src/message_api.c b/src/message_api.c index a93bbd4a..a98a6304 100644 --- a/src/message_api.c +++ b/src/message_api.c @@ -2478,12 +2478,12 @@ static PEP_STATUS update_sender_to_pep_trust( // This file's code is difficult enough to parse. But change at will. switch (sender->comm_type) { case PEP_ct_OpenPGP_unconfirmed: - status = set_trust(session, sender->user_id, sender->fpr, PEP_ct_pEp_unconfirmed); - break; case PEP_ct_OpenPGP: - status = set_trust(session, sender->user_id, sender->fpr, PEP_ct_pEp); + sender->comm_type = PEP_ct_pEp_unconfirmed | (sender->comm_type & PEP_ct_confirmed); + status = set_trust(session, sender); break; default: + status = PEP_CANNOT_SET_TRUST; break; } diff --git a/src/pEpEngine.c b/src/pEpEngine.c index aff6f794..c9973e7e 100644 --- a/src/pEpEngine.c +++ b/src/pEpEngine.c @@ -98,12 +98,15 @@ static const char *sql_remove_fpr_as_default = // Set person, but if already exist, only update. // if main_key_id already set, don't touch. static const char *sql_set_person = - "insert or ignore into person (id, username, lang, main_key_id, device_group)" + "insert or replace into person (id, username, lang, main_key_id, device_group)" " values (?1, ?2, ?3," - " (select coalesce( " - " (select main_key_id from person where id = ?1), " - " upper(replace(?4,' ',''))))," - " (select device_group from person where id = ?1)) ;" +// " (select coalesce( " +// " (select main_key_id from person where id = ?1), " +// " upper(replace(?4,' ',''))))," + " ?4," + " (select device_group from person where id = ?1)) ;"; + +static const char *sql_update_person = "update person " " set username = ?2, " " lang = ?3, " @@ -165,8 +168,8 @@ static const char *sql_set_pgp_keypair = "insert or ignore into pgp_keypair (fpr) " "values (upper(replace(?1,' ',''))) ;"; -static const char *sql_set_identity = - "insert or ignore into identity (" +static const char *sql_set_identity_entry = + "insert or replace into identity (" " address, main_key_id, " " user_id, flags, is_own" " ) values (" @@ -175,7 +178,9 @@ static const char *sql_set_identity = " ?3," " ?4," " ?5" - " );" + " );"; + +static const char* sql_update_identity_entry = "update identity " " set main_key_id = upper(replace(?2,' ','')), " " flags = ?4, " @@ -190,8 +195,6 @@ static const char *sql_set_identity = // " 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 = " @@ -206,8 +209,10 @@ static const char *sql_unset_identity_flags = "where address = ?2 and user_id = ?3 ;"; static const char *sql_set_trust = - "insert or ignore into trust (user_id, pgp_keypair_fpr, comm_type) " - "values (?1, upper(replace(?2,' ','')), ?3) ;" + "insert or replace 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,' ',''));"; @@ -329,7 +334,7 @@ static const char *sql_get_userid_alias_default = // Revocation tracking static const char *sql_add_mistrusted_key = - "insert or ignore into mistrusted_keys (fpr) " + "insert or replace into mistrusted_keys (fpr) " " values (upper(replace(?1,' ',''))) ;"; static const char *sql_delete_mistrusted_key = @@ -339,7 +344,7 @@ 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 ignore into alternate_user_id (default_id, alternate_id) " + "insert or replace into alternate_user_id (default_id, alternate_id) " "values (?1, ?2) ;"; static int user_version(void *_version, int count, char **text, char **name) @@ -611,8 +616,8 @@ DYNAMIC_API PEP_STATUS init(PEP_SESSION *session) ");\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" + " default_id text references person (id)\n" + " on delete cascade on update cascade,\n" " alternate_id text primary key\n" ");\n" // mistrusted keys @@ -835,8 +840,8 @@ DYNAMIC_API PEP_STATUS init(PEP_SESSION *session) "\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" + " default_id text references person (id)\n" + " on delete cascade on update cascade,\n" " alternate_id text primary key\n" ");\n" , @@ -977,6 +982,10 @@ DYNAMIC_API PEP_STATUS init(PEP_SESSION *session) (int)strlen(sql_set_person), &_session->set_person, NULL); assert(int_result == SQLITE_OK); + int_result = sqlite3_prepare_v2(_session->db, sql_update_person, + (int)strlen(sql_update_person), &_session->update_person, NULL); + assert(int_result == SQLITE_OK); + 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); @@ -1002,8 +1011,12 @@ DYNAMIC_API PEP_STATUS init(PEP_SESSION *session) NULL); assert(int_result == SQLITE_OK); - int_result = sqlite3_prepare_v2(_session->db, sql_set_identity, - (int)strlen(sql_set_identity), &_session->set_identity, NULL); + 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); + + 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); int_result = sqlite3_prepare_v2(_session->db, sql_set_identity_flags, @@ -1020,6 +1033,10 @@ DYNAMIC_API PEP_STATUS init(PEP_SESSION *session) (int)strlen(sql_set_trust), &_session->set_trust, NULL); assert(int_result == SQLITE_OK); + int_result = sqlite3_prepare_v2(_session->db, sql_update_trust, + (int)strlen(sql_update_trust), &_session->update_trust, NULL); + assert(int_result == SQLITE_OK); + 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); @@ -1159,7 +1176,7 @@ DYNAMIC_API PEP_STATUS init(PEP_SESSION *session) // private keys have an 'unknown' trust designation in PGP). // We don't really worry about the status here. - status = import_trusted_own_keys(_session); +// status = import_trusted_own_keys(_session); } // sync_session set to own session by default @@ -1239,14 +1256,18 @@ DYNAMIC_API void release(PEP_SESSION session) sqlite3_finalize(session->get_device_group); if (session->set_pgp_keypair) sqlite3_finalize(session->set_pgp_keypair); - if (session->set_identity) - sqlite3_finalize(session->set_identity); + 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_trust) sqlite3_finalize(session->set_trust); + if (session->update_trust) + sqlite3_finalize(session->update_trust); if (session->update_trust_for_fpr) sqlite3_finalize(session->update_trust_for_fpr); if (session->get_trust) @@ -1712,6 +1733,8 @@ DYNAMIC_API PEP_STATUS set_userid_alias ( if (!(session && default_id && alias_id && default_id[0] != '\0' && alias_id[0] != '\0')) return PEP_ILLEGAL_VALUE; + + sqlite3_exec(session->db, "BEGIN ;", NULL, NULL, NULL); sqlite3_reset(session->add_userid_alias); sqlite3_bind_text(session->add_userid_alias, 1, default_id, -1, @@ -1722,9 +1745,13 @@ DYNAMIC_API PEP_STATUS set_userid_alias ( result = sqlite3_step(session->add_userid_alias); sqlite3_reset(session->add_userid_alias); - if (result != SQLITE_DONE) + if (result != SQLITE_DONE) { + sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL); return PEP_CANNOT_SET_ALIAS; - + } + sqlite3_exec(session->db, "COMMIT ;", NULL, NULL, NULL); + + return PEP_STATUS_OK; } @@ -1946,6 +1973,155 @@ PEP_STATUS set_pgp_keypair(PEP_SESSION session, const char* fpr) { return PEP_STATUS_OK; } +static PEP_STATUS _set_or_update_trust(PEP_SESSION session, + const pEp_identity* identity, + sqlite3_stmt* set_or_update) { + + assert(session); + assert(identity); + assert(identity->user_id); + assert(identity->fpr); + + if (!session || !identity || EMPTYSTR(identity->user_id) || EMPTYSTR(identity->fpr)) + return PEP_ILLEGAL_VALUE; + + int result; + + sqlite3_reset(set_or_update); + sqlite3_bind_text(set_or_update, 1, identity->user_id, -1, + SQLITE_STATIC); + sqlite3_bind_text(set_or_update, 2, identity->fpr, -1, + SQLITE_STATIC); + sqlite3_bind_int(set_or_update, 3, identity->comm_type); + result = sqlite3_step(set_or_update); + assert(result == SQLITE_DONE); + sqlite3_reset(set_or_update); + if (result != SQLITE_DONE) + return PEP_CANNOT_SET_TRUST; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _set_or_update_identity_entry(PEP_SESSION session, + const pEp_identity* identity, + sqlite3_stmt* set_or_update) { + assert(session); + assert(identity); + assert(set_or_update); + + if (!session || !identity || !identity->user_id || !identity->address) + return PEP_ILLEGAL_VALUE; + + sqlite3_reset(set_or_update); + sqlite3_bind_text(set_or_update, 1, identity->address, -1, + SQLITE_STATIC); + sqlite3_bind_text(set_or_update, 2, identity->fpr, -1, + SQLITE_STATIC); + sqlite3_bind_text(set_or_update, 3, identity->user_id, -1, + SQLITE_STATIC); + sqlite3_bind_int(set_or_update, 4, identity->flags); + sqlite3_bind_int(set_or_update, 5, identity->me); + int result = sqlite3_step(set_or_update); + sqlite3_reset(set_or_update); + if (result != SQLITE_DONE) + return PEP_CANNOT_SET_IDENTITY; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _set_or_update_person(PEP_SESSION session, + const pEp_identity* identity, + sqlite3_stmt* set_or_update) { + assert(session); + assert(identity); + assert(set_or_update); + + if (!session || !identity || !identity->user_id || !identity->username) + return PEP_ILLEGAL_VALUE; + + sqlite3_reset(set_or_update); + sqlite3_bind_text(set_or_update, 1, identity->user_id, -1, + SQLITE_STATIC); + sqlite3_bind_text(set_or_update, 2, identity->username, -1, + SQLITE_STATIC); + if (identity->lang[0]) + sqlite3_bind_text(set_or_update, 3, identity->lang, 2, + SQLITE_STATIC); + else + sqlite3_bind_null(set_or_update, 3); + sqlite3_bind_text(set_or_update, 4, identity->fpr, -1, + SQLITE_STATIC); + int result = sqlite3_step(set_or_update); + sqlite3_reset(set_or_update); + + if (result != SQLITE_DONE) + return PEP_CANNOT_SET_PERSON; + + return PEP_STATUS_OK; +} + +PEP_STATUS set_or_update_with_identity(PEP_SESSION session, + const pEp_identity* identity, + PEP_STATUS (* set_function)(PEP_SESSION, const pEp_identity*, sqlite3_stmt*), + sqlite3_stmt* set_query, + sqlite3_stmt* update_query, + bool guard_transaction) { + + if (guard_transaction) { + sqlite3_exec(session->db, "BEGIN ;", NULL, NULL, NULL); + } + PEP_STATUS status = set_function(session, identity, update_query); + if (status != PEP_STATUS_OK) { + if (guard_transaction) + sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL); + return status; + } + else { + if (sqlite3_changes(session->db) == 0) { + status = set_function(session, identity, set_query); + if (status != PEP_STATUS_OK) { + if (guard_transaction) + sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL); + return status; + } + } + } + if (guard_transaction) { + sqlite3_exec(session->db, "COMMIT ;", NULL, NULL, NULL); + } + return status; +} + +PEP_STATUS _set_trust_internal(PEP_SESSION session, const pEp_identity* identity, + bool guard_transaction) { + return set_or_update_with_identity(session, identity, + _set_or_update_trust, + session->update_trust, + session->set_trust, + guard_transaction); +} +PEP_STATUS set_trust(PEP_SESSION session, const pEp_identity* identity) { + return _set_trust_internal(session, identity, true); +} + +PEP_STATUS set_person(PEP_SESSION session, const pEp_identity* identity, + bool guard_transaction) { + return set_or_update_with_identity(session, identity, + _set_or_update_person, + session->update_person, + session->set_person, + guard_transaction); +} + +PEP_STATUS set_identity_entry(PEP_SESSION session, const pEp_identity* identity, + bool guard_transaction) { + return set_or_update_with_identity(session, identity, + _set_or_update_identity_entry, + session->update_identity_entry, + session->set_identity_entry, + guard_transaction); +} + DYNAMIC_API PEP_STATUS set_identity( PEP_SESSION session, const pEp_identity *identity ) @@ -1999,53 +2175,23 @@ DYNAMIC_API PEP_STATUS set_identity( } } - sqlite3_reset(session->set_person); - sqlite3_bind_text(session->set_person, 1, identity->user_id, -1, - SQLITE_STATIC); - sqlite3_bind_text(session->set_person, 2, identity->username, -1, - SQLITE_STATIC); - if (identity->lang[0]) - sqlite3_bind_text(session->set_person, 3, identity->lang, 2, - SQLITE_STATIC); - else - sqlite3_bind_null(session->set_person, 3); - sqlite3_bind_text(session->set_person, 4, identity->fpr, -1, - SQLITE_STATIC); - result = sqlite3_step(session->set_person); - sqlite3_reset(session->set_person); - if (result != SQLITE_DONE) { + status = set_person(session, identity, false); + if (status != PEP_STATUS_OK) { sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL); - return PEP_CANNOT_SET_PERSON; + return status; } - sqlite3_reset(session->set_identity); - sqlite3_bind_text(session->set_identity, 1, identity->address, -1, - SQLITE_STATIC); - sqlite3_bind_text(session->set_identity, 2, identity->fpr, -1, - SQLITE_STATIC); - sqlite3_bind_text(session->set_identity, 3, identity->user_id, -1, - SQLITE_STATIC); - sqlite3_bind_int(session->set_identity, 4, identity->flags); - sqlite3_bind_int(session->set_identity, 5, identity->me); - result = sqlite3_step(session->set_identity); - sqlite3_reset(session->set_identity); - if (result != SQLITE_DONE) { + status = set_identity_entry(session, identity, false); + if (status != PEP_STATUS_OK) { sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL); - return PEP_CANNOT_SET_IDENTITY; + return status; } if (has_fpr) { - sqlite3_reset(session->set_trust); - sqlite3_bind_text(session->set_trust, 1, identity->user_id, -1, - SQLITE_STATIC); - sqlite3_bind_text(session->set_trust, 2, identity->fpr, -1, - SQLITE_STATIC); - sqlite3_bind_int(session->set_trust, 3, identity->comm_type); - result = sqlite3_step(session->set_trust); - sqlite3_reset(session->set_trust); - if (result != SQLITE_DONE) { + status = _set_trust_internal(session, identity, false); + if (status != PEP_STATUS_OK) { sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL); - return PEP_CANNOT_SET_TRUST; + return status; } } @@ -2554,35 +2700,6 @@ void pEp_free(void *p) free(p); } -PEP_STATUS set_trust(PEP_SESSION session, - const char* user_id, - const char* fpr, - PEP_comm_type comm_type) -{ - assert(session); - assert(user_id); - assert(fpr); - - if (!session || !user_id || user_id[0] == '\0' || !fpr || fpr[0] == '\0') - return PEP_ILLEGAL_VALUE; - - int result; - - sqlite3_reset(session->set_trust); - sqlite3_bind_text(session->set_trust, 1, user_id, -1, - SQLITE_STATIC); - sqlite3_bind_text(session->set_trust, 2, fpr, -1, - SQLITE_STATIC); - sqlite3_bind_int(session->set_trust, 3, comm_type); - result = sqlite3_step(session->set_trust); - assert(result == SQLITE_DONE); - sqlite3_reset(session->set_trust); - if (result != SQLITE_DONE) - return PEP_CANNOT_SET_TRUST; - - return PEP_STATUS_OK; -} - DYNAMIC_API PEP_STATUS get_trust(PEP_SESSION session, pEp_identity *identity) { diff --git a/src/pEpEngine.h b/src/pEpEngine.h index fd520eec..e647c8aa 100644 --- a/src/pEpEngine.h +++ b/src/pEpEngine.h @@ -934,9 +934,7 @@ DYNAMIC_API PEP_STATUS get_trust(PEP_SESSION session, pEp_identity *identity); PEP_STATUS set_trust(PEP_SESSION session, - const char* user_id, - const char* fpr, - PEP_comm_type comm_type); + const pEp_identity* identity); PEP_STATUS update_trust_for_fpr(PEP_SESSION session, const char* fpr, diff --git a/src/pEp_internal.h b/src/pEp_internal.h index 86ba4b0a..00a5680d 100644 --- a/src/pEp_internal.h +++ b/src/pEp_internal.h @@ -131,16 +131,19 @@ struct _pEpSession { sqlite3_stmt *refresh_userid_default_key; sqlite3_stmt *remove_fpr_as_default; sqlite3_stmt *set_person; + sqlite3_stmt *update_person; sqlite3_stmt *set_as_pep_user; sqlite3_stmt *is_pep_user; sqlite3_stmt *exists_person; sqlite3_stmt *set_device_group; sqlite3_stmt *get_device_group; sqlite3_stmt *set_pgp_keypair; - sqlite3_stmt *set_identity; + sqlite3_stmt *set_identity_entry; + sqlite3_stmt *update_identity_entry; sqlite3_stmt *set_identity_flags; sqlite3_stmt *unset_identity_flags; sqlite3_stmt *set_trust; + sqlite3_stmt *update_trust; sqlite3_stmt *update_trust_for_fpr; sqlite3_stmt *get_trust; sqlite3_stmt *least_trust; diff --git a/test/Makefile b/test/Makefile index c325e091..9de971ad 100644 --- a/test/Makefile +++ b/test/Makefile @@ -55,7 +55,7 @@ TEST_CMD_PFX=$(LIBPATH)=$(EXTRA_LIB_PATHS) HOME=$(TEST_HOME) GNUPGHOME=$(TEST_GN UNIT_TESTS_SOURCE=$(wildcard *_test.cc) UNIT_TESTS=$(subst .cc,,$(UNIT_TESTS_SOURCE)) -UNIT_TESTS_RUN=$(subst .cc,_gdb,$(UNIT_TESTS_SOURCE)) +UNIT_TESTS_RUN=$(subst .cc,_run,$(UNIT_TESTS_SOURCE)) CFLAGS:=$(filter-out -DNDEBUG,$(CFLAGS)) ifneq ($(MAKECMDGOALS),clean)