mirror of
git://git.gnupg.org/gnupg.git
synced 2025-04-17 15:44:34 +02:00
g10: Be careful to not be in a transaction during long operations
* g10/tofu.c (begin_transaction): New parameter only_batch. If set, only start a batch transaction if there is none and one has been requested. Update callers. (tofu_suspend_batch_transaction): New function. (tofu_resume_batch_transaction): Likewise. (ask_about_binding): Take a ctrl_t, not a tofu_dbs_t. Update callers. Gather statistics within a transaction. Suspend any batch transaction when getting user input. (get_trust): Take a ctrl_t, not a tofu_dbs_t. Update callers. Enclose in a transaction. (tofu_get_validity): Use a batch transaction, not a normal transaction. -- Signed-off-by: Neal H. Walfield <neal@g10code.com>
This commit is contained in:
parent
babeb6f8a9
commit
4cbd2a690c
95
g10/tofu.c
95
g10/tofu.c
@ -162,9 +162,11 @@ tofu_policy_to_trust_level (enum tofu_policy policy)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Start a transaction on DB. */
|
/* Start a transaction on DB. If ONLY_BATCH is set, then this will
|
||||||
|
start a batch transaction if we haven't started a batch transaction
|
||||||
|
and one has been requested. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
begin_transaction (ctrl_t ctrl)
|
begin_transaction (ctrl_t ctrl, int only_batch)
|
||||||
{
|
{
|
||||||
tofu_dbs_t dbs = ctrl->tofu.dbs;
|
tofu_dbs_t dbs = ctrl->tofu.dbs;
|
||||||
int rc;
|
int rc;
|
||||||
@ -220,6 +222,9 @@ begin_transaction (ctrl_t ctrl)
|
|||||||
dbs->batch_update_started = gnupg_get_time ();
|
dbs->batch_update_started = gnupg_get_time ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (only_batch)
|
||||||
|
return 0;
|
||||||
|
|
||||||
log_assert(dbs->in_transaction >= 0);
|
log_assert(dbs->in_transaction >= 0);
|
||||||
dbs->in_transaction ++;
|
dbs->in_transaction ++;
|
||||||
|
|
||||||
@ -289,6 +294,9 @@ end_transaction (ctrl_t ctrl, int only_batch)
|
|||||||
|
|
||||||
rc = gpgsql_exec_printf (dbs->db, NULL, NULL, &err,
|
rc = gpgsql_exec_printf (dbs->db, NULL, NULL, &err,
|
||||||
"release inner%d;", dbs->in_transaction);
|
"release inner%d;", dbs->in_transaction);
|
||||||
|
|
||||||
|
dbs->in_transaction --;
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
log_error (_("error committing transaction on TOFU database: %s\n"),
|
log_error (_("error committing transaction on TOFU database: %s\n"),
|
||||||
@ -297,8 +305,6 @@ end_transaction (ctrl_t ctrl, int only_batch)
|
|||||||
return gpg_error (GPG_ERR_GENERAL);
|
return gpg_error (GPG_ERR_GENERAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
dbs->in_transaction --;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,11 +349,28 @@ tofu_end_batch_update (ctrl_t ctrl)
|
|||||||
{
|
{
|
||||||
log_assert (ctrl->tofu.batch_updated_wanted > 0);
|
log_assert (ctrl->tofu.batch_updated_wanted > 0);
|
||||||
ctrl->tofu.batch_updated_wanted --;
|
ctrl->tofu.batch_updated_wanted --;
|
||||||
|
end_transaction (ctrl, 1);
|
||||||
if (!ctrl->tofu.batch_updated_wanted)
|
|
||||||
end_transaction (ctrl, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Suspend any extant batch transaction (it is safe to call this even
|
||||||
|
no batch transaction has been started). Note: you cannot suspend a
|
||||||
|
batch transaction if you are in a normal transaction. The batch
|
||||||
|
transaction can be resumed explicitly by calling
|
||||||
|
tofu_resume_batch_transaction or implicitly by starting a normal
|
||||||
|
transaction. */
|
||||||
|
static void
|
||||||
|
tofu_suspend_batch_transaction (ctrl_t ctrl)
|
||||||
|
{
|
||||||
|
end_transaction (ctrl, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resume a batch transaction if there is no extant batch transaction
|
||||||
|
and one has been requested using tofu_begin_batch_transaction. */
|
||||||
|
static void
|
||||||
|
tofu_resume_batch_transaction (ctrl_t ctrl)
|
||||||
|
{
|
||||||
|
begin_transaction (ctrl, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1193,9 +1216,11 @@ format_conflict_msg_part1 (int policy, const char *conflict,
|
|||||||
*
|
*
|
||||||
* - The policy is ask (the user deferred last time) (policy ==
|
* - The policy is ask (the user deferred last time) (policy ==
|
||||||
* TOFU_POLICY_ASK).
|
* TOFU_POLICY_ASK).
|
||||||
|
*
|
||||||
|
* Note: this function must not be called while in a transaction!
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
ask_about_binding (tofu_dbs_t dbs,
|
ask_about_binding (ctrl_t ctrl,
|
||||||
enum tofu_policy *policy,
|
enum tofu_policy *policy,
|
||||||
int *trust_level,
|
int *trust_level,
|
||||||
int bindings_with_this_email_count,
|
int bindings_with_this_email_count,
|
||||||
@ -1205,6 +1230,7 @@ ask_about_binding (tofu_dbs_t dbs,
|
|||||||
const char *email,
|
const char *email,
|
||||||
const char *user_id)
|
const char *user_id)
|
||||||
{
|
{
|
||||||
|
tofu_dbs_t dbs;
|
||||||
char *sqerr = NULL;
|
char *sqerr = NULL;
|
||||||
int rc;
|
int rc;
|
||||||
estream_t fp;
|
estream_t fp;
|
||||||
@ -1214,6 +1240,10 @@ ask_about_binding (tofu_dbs_t dbs,
|
|||||||
char *prompt;
|
char *prompt;
|
||||||
char *choices;
|
char *choices;
|
||||||
|
|
||||||
|
dbs = ctrl->tofu.dbs;
|
||||||
|
log_assert (dbs);
|
||||||
|
log_assert (dbs->in_transaction == 0);
|
||||||
|
|
||||||
fp = es_fopenmem (0, "rw,samethread");
|
fp = es_fopenmem (0, "rw,samethread");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
log_fatal ("error creating memory stream: %s\n",
|
log_fatal ("error creating memory stream: %s\n",
|
||||||
@ -1227,6 +1257,8 @@ ask_about_binding (tofu_dbs_t dbs,
|
|||||||
xfree (text);
|
xfree (text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
begin_transaction (ctrl, 0);
|
||||||
|
|
||||||
/* Find other user ids associated with this key and whether the
|
/* Find other user ids associated with this key and whether the
|
||||||
* bindings are marked as good or bad. */
|
* bindings are marked as good or bad. */
|
||||||
rc = gpgsql_stepx
|
rc = gpgsql_stepx
|
||||||
@ -1495,6 +1527,7 @@ ask_about_binding (tofu_dbs_t dbs,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
end_transaction (ctrl, 0);
|
||||||
|
|
||||||
if ((*policy == TOFU_POLICY_NONE && bindings_with_this_email_count > 0)
|
if ((*policy == TOFU_POLICY_NONE && bindings_with_this_email_count > 0)
|
||||||
|| (*policy == TOFU_POLICY_ASK
|
|| (*policy == TOFU_POLICY_ASK
|
||||||
@ -1536,6 +1569,10 @@ ask_about_binding (tofu_dbs_t dbs,
|
|||||||
* wrong choise (because he does not see that either). As a small
|
* wrong choise (because he does not see that either). As a small
|
||||||
* benefit we allow C-L to redisplay everything. */
|
* benefit we allow C-L to redisplay everything. */
|
||||||
tty_printf ("%s", prompt);
|
tty_printf ("%s", prompt);
|
||||||
|
|
||||||
|
/* Suspend any transaction: it could take a while until the user
|
||||||
|
responds. */
|
||||||
|
tofu_suspend_batch_transaction (ctrl);
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
char *response;
|
char *response;
|
||||||
@ -1599,6 +1636,7 @@ ask_about_binding (tofu_dbs_t dbs,
|
|||||||
}
|
}
|
||||||
xfree (response);
|
xfree (response);
|
||||||
}
|
}
|
||||||
|
tofu_resume_batch_transaction (ctrl);
|
||||||
|
|
||||||
xfree (prompt);
|
xfree (prompt);
|
||||||
|
|
||||||
@ -1619,12 +1657,15 @@ ask_about_binding (tofu_dbs_t dbs,
|
|||||||
* necessary if there is a conflict or the binding's policy is
|
* necessary if there is a conflict or the binding's policy is
|
||||||
* TOFU_POLICY_ASK. In the case of a conflict, we set the new
|
* TOFU_POLICY_ASK. In the case of a conflict, we set the new
|
||||||
* conflicting binding's policy to TOFU_POLICY_ASK. In either case,
|
* conflicting binding's policy to TOFU_POLICY_ASK. In either case,
|
||||||
* we return TRUST_UNDEFINED. */
|
* we return TRUST_UNDEFINED. Note: if MAY_ASK is set, then this
|
||||||
|
* function must not be called while in a transaction! */
|
||||||
static enum tofu_policy
|
static enum tofu_policy
|
||||||
get_trust (tofu_dbs_t dbs, PKT_public_key *pk,
|
get_trust (ctrl_t ctrl, PKT_public_key *pk,
|
||||||
const char *fingerprint, const char *email,
|
const char *fingerprint, const char *email,
|
||||||
const char *user_id, int may_ask)
|
const char *user_id, int may_ask)
|
||||||
{
|
{
|
||||||
|
tofu_dbs_t dbs = ctrl->tofu.dbs;
|
||||||
|
int in_transaction = 0;
|
||||||
enum tofu_policy policy;
|
enum tofu_policy policy;
|
||||||
char *conflict = NULL;
|
char *conflict = NULL;
|
||||||
int rc;
|
int rc;
|
||||||
@ -1634,6 +1675,11 @@ get_trust (tofu_dbs_t dbs, PKT_public_key *pk,
|
|||||||
int change_conflicting_to_ask = 0;
|
int change_conflicting_to_ask = 0;
|
||||||
int trust_level = TRUST_UNKNOWN;
|
int trust_level = TRUST_UNKNOWN;
|
||||||
|
|
||||||
|
log_assert (dbs);
|
||||||
|
|
||||||
|
if (may_ask)
|
||||||
|
log_assert (dbs->in_transaction == 0);
|
||||||
|
|
||||||
if (opt.batch)
|
if (opt.batch)
|
||||||
may_ask = 0;
|
may_ask = 0;
|
||||||
|
|
||||||
@ -1647,6 +1693,9 @@ get_trust (tofu_dbs_t dbs, PKT_public_key *pk,
|
|||||||
&& _tofu_GET_TRUST_ERROR != TRUST_FULLY
|
&& _tofu_GET_TRUST_ERROR != TRUST_FULLY
|
||||||
&& _tofu_GET_TRUST_ERROR != TRUST_ULTIMATE);
|
&& _tofu_GET_TRUST_ERROR != TRUST_ULTIMATE);
|
||||||
|
|
||||||
|
begin_transaction (ctrl, 0);
|
||||||
|
in_transaction = 1;
|
||||||
|
|
||||||
policy = get_policy (dbs, fingerprint, email, &conflict);
|
policy = get_policy (dbs, fingerprint, email, &conflict);
|
||||||
{
|
{
|
||||||
/* See if the key is ultimately trusted. If so, we're done. */
|
/* See if the key is ultimately trusted. If so, we're done. */
|
||||||
@ -1813,8 +1862,12 @@ get_trust (tofu_dbs_t dbs, PKT_public_key *pk,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We can't be in a normal transaction in ask_about_binding. */
|
||||||
|
end_transaction (ctrl, 0);
|
||||||
|
in_transaction = 0;
|
||||||
|
|
||||||
/* If we get here, we need to ask the user about the binding. */
|
/* If we get here, we need to ask the user about the binding. */
|
||||||
ask_about_binding (dbs,
|
ask_about_binding (ctrl,
|
||||||
&policy,
|
&policy,
|
||||||
&trust_level,
|
&trust_level,
|
||||||
bindings_with_this_email_count,
|
bindings_with_this_email_count,
|
||||||
@ -1825,6 +1878,9 @@ get_trust (tofu_dbs_t dbs, PKT_public_key *pk,
|
|||||||
user_id);
|
user_id);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
if (in_transaction)
|
||||||
|
end_transaction (ctrl, 0);
|
||||||
|
|
||||||
if (change_conflicting_to_ask)
|
if (change_conflicting_to_ask)
|
||||||
{
|
{
|
||||||
if (! may_ask)
|
if (! may_ask)
|
||||||
@ -2334,7 +2390,7 @@ tofu_register (ctrl_t ctrl, PKT_public_key *pk, strlist_t user_id_list,
|
|||||||
|
|
||||||
/* We do a query and then an insert. Make sure they are atomic
|
/* We do a query and then an insert. Make sure they are atomic
|
||||||
by wrapping them in a transaction. */
|
by wrapping them in a transaction. */
|
||||||
rc = begin_transaction (ctrl);
|
rc = begin_transaction (ctrl, 0);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@ -2356,7 +2412,7 @@ tofu_register (ctrl_t ctrl, PKT_public_key *pk, strlist_t user_id_list,
|
|||||||
|
|
||||||
/* Make sure the binding exists and record any TOFU
|
/* Make sure the binding exists and record any TOFU
|
||||||
conflicts. */
|
conflicts. */
|
||||||
if (get_trust (dbs, pk, fingerprint, email, user_id->d, 0)
|
if (get_trust (ctrl, pk, fingerprint, email, user_id->d, 0)
|
||||||
== _tofu_GET_TRUST_ERROR)
|
== _tofu_GET_TRUST_ERROR)
|
||||||
{
|
{
|
||||||
rc = gpg_error (GPG_ERR_GENERAL);
|
rc = gpg_error (GPG_ERR_GENERAL);
|
||||||
@ -2557,8 +2613,8 @@ tofu_write_tfs_record (ctrl_t ctrl, estream_t fp,
|
|||||||
PK is the primary key packet.
|
PK is the primary key packet.
|
||||||
|
|
||||||
If MAY_ASK is 1 and the policy is TOFU_POLICY_ASK, then the user
|
If MAY_ASK is 1 and the policy is TOFU_POLICY_ASK, then the user
|
||||||
will be prompted to choose a different policy. If MAY_ASK is 0 and
|
will be prompted to choose a policy. If MAY_ASK is 0 and the
|
||||||
the policy is TOFU_POLICY_ASK, then TRUST_UNKNOWN is returned.
|
policy is TOFU_POLICY_ASK, then TRUST_UNKNOWN is returned.
|
||||||
|
|
||||||
Returns TRUST_UNDEFINED if an error occurs. */
|
Returns TRUST_UNDEFINED if an error occurs. */
|
||||||
int
|
int
|
||||||
@ -2582,7 +2638,8 @@ tofu_get_validity (ctrl_t ctrl, PKT_public_key *pk, strlist_t user_id_list,
|
|||||||
|
|
||||||
fingerprint = hexfingerprint (pk, NULL, 0);
|
fingerprint = hexfingerprint (pk, NULL, 0);
|
||||||
|
|
||||||
begin_transaction (ctrl);
|
tofu_begin_batch_update (ctrl);
|
||||||
|
tofu_resume_batch_transaction (ctrl);
|
||||||
|
|
||||||
for (user_id = user_id_list; user_id; user_id = user_id->next, bindings ++)
|
for (user_id = user_id_list; user_id; user_id = user_id->next, bindings ++)
|
||||||
{
|
{
|
||||||
@ -2590,7 +2647,7 @@ tofu_get_validity (ctrl_t ctrl, PKT_public_key *pk, strlist_t user_id_list,
|
|||||||
|
|
||||||
/* Always call get_trust to make sure the binding is
|
/* Always call get_trust to make sure the binding is
|
||||||
registered. */
|
registered. */
|
||||||
int tl = get_trust (dbs, pk, fingerprint, email, user_id->d, may_ask);
|
int tl = get_trust (ctrl, pk, fingerprint, email, user_id->d, may_ask);
|
||||||
if (tl == _tofu_GET_TRUST_ERROR)
|
if (tl == _tofu_GET_TRUST_ERROR)
|
||||||
{
|
{
|
||||||
/* An error. */
|
/* An error. */
|
||||||
@ -2639,7 +2696,7 @@ tofu_get_validity (ctrl_t ctrl, PKT_public_key *pk, strlist_t user_id_list,
|
|||||||
}
|
}
|
||||||
|
|
||||||
die:
|
die:
|
||||||
end_transaction (ctrl, 0);
|
tofu_end_batch_update (ctrl);
|
||||||
|
|
||||||
xfree (fingerprint);
|
xfree (fingerprint);
|
||||||
|
|
||||||
@ -2689,7 +2746,7 @@ tofu_set_policy (ctrl_t ctrl, kbnode_t kb, enum tofu_policy policy)
|
|||||||
|
|
||||||
fingerprint = hexfingerprint (pk, NULL, 0);
|
fingerprint = hexfingerprint (pk, NULL, 0);
|
||||||
|
|
||||||
begin_transaction (ctrl);
|
begin_transaction (ctrl, 0);
|
||||||
|
|
||||||
for (; kb; kb = kb->next)
|
for (; kb; kb = kb->next)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user