/* Return the effective policy for the binding <FINGERPRINT, EMAIL>
- * (email has already been normalized) and any conflict information in
- * *CONFLICT_SETP, if CONFLICT_SETP is not NULL. Returns
- * _tofu_GET_POLICY_ERROR if an error occurs. */
+ * (email has already been normalized). Returns
+ * _tofu_GET_POLICY_ERROR if an error occurs. Returns any conflict
+ * information in *CONFLICT_SETP if CONFLICT_SETP is not NULL and the
+ * returned policy is TOFU_POLICY_ASK (consequently, if there is a
+ * conflict, but the user set the policy to good *CONFLICT_SETP will
+ * empty). Note: as per build_conflict_set, which is used to build
+ * the conflict information, the conflict information includes the
+ * current user id as the first element of the linked list.
+ *
+ * This function registers the binding in the bindings table if it has
+ * not yet been registered.
+ */
static enum tofu_policy
get_policy (tofu_dbs_t dbs, PKT_public_key *pk,
const char *fingerprint, const char *user_id, const char *email,
static enum tofu_policy
get_trust (ctrl_t ctrl, PKT_public_key *pk,
const char *fingerprint, const char *email,
- const char *user_id, int may_ask, time_t now)
+ const char *user_id, int may_ask,
+ enum tofu_policy *policyp, strlist_t *conflict_setp,
+ time_t now)
{
tofu_dbs_t dbs = ctrl->tofu.dbs;
int in_transaction = 0;
&& _tofu_GET_TRUST_ERROR != TRUST_FULLY
&& _tofu_GET_TRUST_ERROR != TRUST_ULTIMATE);
+ begin_transaction (ctrl, 0);
+ in_transaction = 1;
+
+ /* We need to call get_policy even if the key is ultimately trusted
+ * to make sure the binding has been registered. */
+ policy = get_policy (dbs, pk, fingerprint, user_id, email,
+ &conflict_set, now);
+
+ if (policy == TOFU_POLICY_ASK)
+ /* The conflict set should always contain at least one element:
+ * the current key. */
+ log_assert (conflict_set);
+ else
+ /* If the policy is not TOFU_POLICY_ASK, then conflict_set will be
+ * NULL. */
+ log_assert (! conflict_set);
+
/* If the key is ultimately trusted, there is nothing to do. */
{
u32 kid[2];
if (tdb_keyid_is_utk (kid))
{
trust_level = TRUST_ULTIMATE;
+ policy = TOFU_POLICY_GOOD;
goto out;
}
}
- begin_transaction (ctrl, 0);
- in_transaction = 1;
-
- policy = get_policy (dbs, pk, fingerprint, user_id, email, &conflict_set, now);
if (policy == TOFU_POLICY_AUTO)
{
policy = opt.tofu_default_policy;
" auto (default: %s).\n",
fingerprint, email,
tofu_policy_str (opt.tofu_default_policy));
+
+ if (policy == TOFU_POLICY_ASK)
+ /* The default policy is ASK, but there is no conflict (policy
+ * was 'auto'). In this case, we need to make sure the
+ * conflict set includes at least the current user id. */
+ {
+ add_to_strlist (&conflict_set, fingerprint);
+ }
}
switch (policy)
{
}
else
{
- for (iter = conflict_set; iter; iter = iter->next)
- show_statistics (dbs, iter->d, email,
- TOFU_POLICY_ASK, NULL, 1, now);
-
trust_level = TRUST_UNDEFINED;
}
if (in_transaction)
end_transaction (ctrl, 0);
- free_strlist (conflict_set);
+ if (policyp)
+ *policyp = policy;
+
+ if (conflict_setp)
+ *conflict_setp = conflict_set;
+ else
+ free_strlist (conflict_set);
return trust_level;
}
/* Get the signature stats. */
rc = gpgsql_exec_printf
(dbs->db, strings_collect_cb, &strlist, &err,
- "select count (*), min (signatures.time), max (signatures.time)\n"
+ "select count (*), coalesce (min (signatures.time), 0),\n"
+ " coalesce (max (signatures.time), 0)\n"
" from signatures\n"
" left join bindings on signatures.binding = bindings.oid\n"
" where fingerprint = %Q and email = %Q;",
/* Get the encryption stats. */
rc = gpgsql_exec_printf
(dbs->db, strings_collect_cb, &strlist, &err,
- "select count (*), min (encryptions.time), max (encryptions.time)\n"
+ "select count (*), coalesce (min (encryptions.time), 0),\n"
+ " coalesce (max (encryptions.time), 0)\n"
" from encryptions\n"
" left join bindings on encryptions.binding = bindings.oid\n"
" where fingerprint = %Q and email = %Q;",
/* Make sure the binding exists and record any TOFU
conflicts. */
- if (get_trust (ctrl, pk, fingerprint, email, user_id->d, 0, now)
+ if (get_trust (ctrl, pk, fingerprint, email, user_id->d,
+ 0, NULL, NULL, now)
== _tofu_GET_TRUST_ERROR)
{
rc = gpg_error (GPG_ERR_GENERAL);
for (user_id = user_id_list; user_id; user_id = user_id->next)
{
char *email = email_from_user_id (user_id->d);
+ strlist_t conflict_set = NULL;
+ enum tofu_policy policy;
/* Make sure the binding exists and that we recognize any
conflicts. */
int tl = get_trust (ctrl, pk, fingerprint, email, user_id->d,
- may_ask, now);
+ may_ask, &policy, &conflict_set, now);
if (tl == _tofu_GET_TRUST_ERROR)
{
/* An error. */
goto die;
}
+
+ /* If there is a conflict and MAY_ASK is true, we need to show
+ * the TOFU statistics for the current binding and the
+ * conflicting bindings. But, if we are not in batch mode, then
+ * they have already been printed (this is required to make sure
+ * the information is available to the caller before cpr_get is
+ * called). */
+ if (policy == TOFU_POLICY_ASK && may_ask && opt.batch)
+ {
+ strlist_t iter;
+
+ /* The conflict set should contain at least the current
+ * key. */
+ log_assert (conflict_set);
+
+ for (iter = conflict_set; iter; iter = iter->next)
+ show_statistics (dbs, iter->d, email,
+ TOFU_POLICY_ASK, NULL, 1, now);
+ }
+
+ free_strlist (conflict_set);
+
rc = gpgsql_stepx
(dbs->db, &dbs->s.register_encryption, NULL, NULL, &err,
"insert into encryptions\n"
int bindings = 0;
int bindings_valid = 0;
int need_warning = 0;
+ int had_conflict = 0;
dbs = opendbs (ctrl);
if (! dbs)
for (user_id = user_id_list; user_id; user_id = user_id->next, bindings ++)
{
char *email = email_from_user_id (user_id->d);
+ strlist_t conflict_set = NULL;
+ enum tofu_policy policy;
/* Always call get_trust to make sure the binding is
registered. */
int tl = get_trust (ctrl, pk, fingerprint, email, user_id->d,
- may_ask, now);
+ may_ask, &policy, &conflict_set, now);
if (tl == _tofu_GET_TRUST_ERROR)
{
/* An error. */
if (may_ask && tl != TRUST_ULTIMATE && tl != TRUST_EXPIRED)
{
- enum tofu_policy policy =
- get_policy (dbs, pk, fingerprint, user_id->d, email, NULL, now);
+ /* If policy is ask, then we already printed out the
+ * conflict information in ask_about_binding or will do so
+ * in a moment. */
+ if (policy != TOFU_POLICY_ASK)
+ need_warning |=
+ show_statistics (dbs, fingerprint, email, policy, NULL, 0, now);
+
+ /* If there is a conflict and MAY_ASK is true, we need to
+ * show the TOFU statistics for the current binding and the
+ * conflicting bindings. But, if we are not in batch mode,
+ * then they have already been printed (this is required to
+ * make sure the information is available to the caller
+ * before cpr_get is called). */
+ if (policy == TOFU_POLICY_ASK && opt.batch)
+ {
+ strlist_t iter;
- need_warning |=
- show_statistics (dbs, fingerprint, email, policy, NULL, 0, now);
+ /* The conflict set should contain at least the current
+ * key. */
+ log_assert (conflict_set);
+
+ had_conflict = 1;
+ for (iter = conflict_set; iter; iter = iter->next)
+ show_statistics (dbs, iter->d, email,
+ TOFU_POLICY_ASK, NULL, 1, now);
+ }
}
+ free_strlist (conflict_set);
+
if (tl == TRUST_NEVER)
trust_level = TRUST_NEVER;
else if (tl == TRUST_EXPIRED)
xfree (email);
}
- if (need_warning)
+ if (need_warning && ! had_conflict)
show_warning (fingerprint, user_id_list);
die: