LCOV - code coverage report
Current view: top level - g10 - tofu.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 607 1228 49.4 %
Date: 2016-09-12 13:01:59 Functions: 34 45 75.6 %

          Line data    Source code
       1             : /* tofu.c - TOFU trust model.
       2             :  * Copyright (C) 2015, 2016 g10 Code GmbH
       3             :  *
       4             :  * This file is part of GnuPG.
       5             :  *
       6             :  * GnuPG is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation; either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * GnuPG is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : /* TODO:
      21             : 
      22             :    - Format the fingerprints nicely when printing (similar to gpg
      23             :      --list-keys)
      24             :  */
      25             : 
      26             : #include <config.h>
      27             : #include <stdio.h>
      28             : #include <sys/stat.h>
      29             : #include <stdarg.h>
      30             : #include <sqlite3.h>
      31             : 
      32             : #include "gpg.h"
      33             : #include "types.h"
      34             : #include "logging.h"
      35             : #include "stringhelp.h"
      36             : #include "options.h"
      37             : #include "mbox-util.h"
      38             : #include "i18n.h"
      39             : #include "ttyio.h"
      40             : #include "trustdb.h"
      41             : #include "mkdir_p.h"
      42             : #include "gpgsql.h"
      43             : #include "status.h"
      44             : #include "sqrtu32.h"
      45             : 
      46             : #include "tofu.h"
      47             : 
      48             : 
      49             : #define CONTROL_L ('L' - 'A' + 1)
      50             : 
      51             : /* Number of signed messages required to indicate that enough history
      52             :  * is available for basic trust.  */
      53             : #define BASIC_TRUST_THRESHOLD  10
      54             : /* Number of signed messages required to indicate that a lot of
      55             :  * history is available.  */
      56             : #define FULL_TRUST_THRESHOLD  100
      57             : 
      58             : 
      59             : /* An struct with data pertaining to the tofu DB.
      60             : 
      61             :    To initialize this data structure, call opendbs().  Cleanup is done
      62             :    when the CTRL object is released.  To get a handle to a database,
      63             :    use the getdb() function.  This will either return an existing
      64             :    handle or open a new DB connection, as appropriate.  */
      65             : struct tofu_dbs_s
      66             : {
      67             :   sqlite3 *db;
      68             : 
      69             :   struct
      70             :   {
      71             :     sqlite3_stmt *savepoint_batch;
      72             :     sqlite3_stmt *savepoint_batch_commit;
      73             : 
      74             :     sqlite3_stmt *record_binding_get_old_policy;
      75             :     sqlite3_stmt *record_binding_update;
      76             :     sqlite3_stmt *record_binding_update2;
      77             :     sqlite3_stmt *get_policy_select_policy_and_conflict;
      78             :     sqlite3_stmt *get_trust_bindings_with_this_email;
      79             :     sqlite3_stmt *get_trust_gather_other_user_ids;
      80             :     sqlite3_stmt *get_trust_gather_signature_stats;
      81             :     sqlite3_stmt *get_trust_gather_encryption_stats;
      82             :     sqlite3_stmt *register_already_seen;
      83             :     sqlite3_stmt *register_insert;
      84             :   } s;
      85             : 
      86             :   int in_batch_transaction;
      87             :   int in_transaction;
      88             :   time_t batch_update_started;
      89             : };
      90             : 
      91             : 
      92             : #define STRINGIFY(s) STRINGIFY2(s)
      93             : #define STRINGIFY2(s) #s
      94             : 
      95             : /* The grouping parameters when collecting signature statistics.  */
      96             : 
      97             : /* If a message is signed a couple of hours in the future, just assume
      98             :    some clock skew.  */
      99             : #define TIME_AGO_FUTURE_IGNORE (2 * 60 * 60)
     100             : /* Days.  */
     101             : #define TIME_AGO_UNIT_SMALL (24 * 60 * 60)
     102             : #define TIME_AGO_SMALL_THRESHOLD (7 * TIME_AGO_UNIT_SMALL)
     103             : /* Months.  */
     104             : #define TIME_AGO_UNIT_MEDIUM (30 * 24 * 60 * 60)
     105             : #define TIME_AGO_MEDIUM_THRESHOLD (2 * TIME_AGO_UNIT_MEDIUM)
     106             : /* Years.  */
     107             : #define TIME_AGO_UNIT_LARGE (365 * 24 * 60 * 60)
     108             : #define TIME_AGO_LARGE_THRESHOLD (2 * TIME_AGO_UNIT_LARGE)
     109             : 
     110             : /* Local prototypes.  */
     111             : static gpg_error_t end_transaction (ctrl_t ctrl, int only_batch);
     112             : static char *email_from_user_id (const char *user_id);
     113             : 
     114             : 
     115             : 
     116             : const char *
     117          33 : tofu_policy_str (enum tofu_policy policy)
     118             : {
     119          33 :   switch (policy)
     120             :     {
     121           0 :     case TOFU_POLICY_NONE: return "none";
     122           5 :     case TOFU_POLICY_AUTO: return "auto";
     123           7 :     case TOFU_POLICY_GOOD: return "good";
     124           7 :     case TOFU_POLICY_UNKNOWN: return "unknown";
     125           8 :     case TOFU_POLICY_BAD: return "bad";
     126           6 :     case TOFU_POLICY_ASK: return "ask";
     127           0 :     default: return "???";
     128             :     }
     129             : }
     130             : 
     131             : /* Convert a binding policy (e.g., TOFU_POLICY_BAD) to a trust level
     132             :    (e.g., TRUST_BAD) in light of the current configuration.  */
     133             : int
     134          80 : tofu_policy_to_trust_level (enum tofu_policy policy)
     135             : {
     136          80 :   if (policy == TOFU_POLICY_AUTO)
     137             :     /* If POLICY is AUTO, fallback to OPT.TOFU_DEFAULT_POLICY.  */
     138          10 :     policy = opt.tofu_default_policy;
     139             : 
     140          80 :   switch (policy)
     141             :     {
     142             :     case TOFU_POLICY_AUTO:
     143             :       /* If POLICY and OPT.TOFU_DEFAULT_POLICY are both AUTO, default
     144             :          to marginal trust.  */
     145          10 :       return TRUST_MARGINAL;
     146             :     case TOFU_POLICY_GOOD:
     147          22 :       return TRUST_FULLY;
     148             :     case TOFU_POLICY_UNKNOWN:
     149          22 :       return TRUST_UNKNOWN;
     150             :     case TOFU_POLICY_BAD:
     151          26 :       return TRUST_NEVER;
     152             :     case TOFU_POLICY_ASK:
     153           0 :       return TRUST_UNKNOWN;
     154             :     default:
     155           0 :       log_bug ("Bad value for trust policy: %d\n",
     156           0 :                opt.tofu_default_policy);
     157             :       return 0;
     158             :     }
     159             : }
     160             : 
     161             : 
     162             : 
     163             : /* Start a transaction on DB.  If ONLY_BATCH is set, then this will
     164             :    start a batch transaction if we haven't started a batch transaction
     165             :    and one has been requested.  */
     166             : static gpg_error_t
     167         192 : begin_transaction (ctrl_t ctrl, int only_batch)
     168             : {
     169         192 :   tofu_dbs_t dbs = ctrl->tofu.dbs;
     170             :   int rc;
     171         192 :   char *err = NULL;
     172             : 
     173         192 :   log_assert (dbs);
     174             : 
     175             :   /* If we've been in batch update mode for a while (on average, more
     176             :    * than 500 ms), to prevent starving other gpg processes, we drop
     177             :    * and retake the batch lock.
     178             :    *
     179             :    * Note: if we wanted higher resolution, we could use
     180             :    * npth_clock_gettime.  */
     181         192 :   if (/* No real transactions.  */
     182         192 :       dbs->in_transaction == 0
     183             :       /* There is an open batch transaction.  */
     184         186 :       && dbs->in_batch_transaction
     185             :       /* And some time has gone by since it was started.  */
     186         129 :       && dbs->batch_update_started != gnupg_get_time ())
     187             :     {
     188             :       /* If we are in a batch update, then batch updates better have
     189             :          been enabled.  */
     190           0 :       log_assert (ctrl->tofu.batch_updated_wanted);
     191             : 
     192           0 :       end_transaction (ctrl, 2);
     193             : 
     194             :       /* Yield to allow another process a chance to run.  */
     195           0 :       gpgrt_yield ();
     196             :     }
     197             : 
     198         192 :   if (/* Batch mode is enabled.  */
     199         192 :       ctrl->tofu.batch_updated_wanted
     200             :       /* But we don't have an open batch transaction.  */
     201         180 :       && !dbs->in_batch_transaction)
     202             :     {
     203             :       /* We are in batch mode, but we don't have an open batch
     204             :        * transaction.  Since the batch save point must be the outer
     205             :        * save point, it must be taken before the inner save point.  */
     206          51 :       log_assert (dbs->in_transaction == 0);
     207             : 
     208          51 :       rc = gpgsql_stepx (dbs->db, &dbs->s.savepoint_batch,
     209             :                           NULL, NULL, &err,
     210             :                           "savepoint batch;", GPGSQL_ARG_END);
     211          51 :       if (rc)
     212             :         {
     213           0 :           log_error (_("error beginning transaction on TOFU database: %s\n"),
     214             :                      err);
     215           0 :           sqlite3_free (err);
     216           0 :           return gpg_error (GPG_ERR_GENERAL);
     217             :         }
     218             : 
     219          51 :       dbs->in_batch_transaction = 1;
     220          51 :       dbs->batch_update_started = gnupg_get_time ();
     221             :     }
     222             : 
     223         192 :   if (only_batch)
     224          88 :     return 0;
     225             : 
     226         104 :   log_assert(dbs->in_transaction >= 0);
     227         104 :   dbs->in_transaction ++;
     228             : 
     229         104 :   rc = gpgsql_exec_printf (dbs->db, NULL, NULL, &err,
     230             :                            "savepoint inner%d;",
     231             :                            dbs->in_transaction);
     232         104 :   if (rc)
     233             :     {
     234           0 :       log_error (_("error beginning transaction on TOFU database: %s\n"),
     235             :                  err);
     236           0 :       sqlite3_free (err);
     237           0 :       return gpg_error (GPG_ERR_GENERAL);
     238             :     }
     239             : 
     240         104 :   return 0;
     241             : }
     242             : 
     243             : 
     244             : /* Commit a transaction.  If ONLY_BATCH is 1, then this only ends the
     245             :  * batch transaction if we have left batch mode.  If ONLY_BATCH is 2,
     246             :  * this ends any open batch transaction even if we are still in batch
     247             :  * mode.  */
     248             : static gpg_error_t
     249         291 : end_transaction (ctrl_t ctrl, int only_batch)
     250             : {
     251         291 :   tofu_dbs_t dbs = ctrl->tofu.dbs;
     252             :   int rc;
     253         291 :   char *err = NULL;
     254             : 
     255         291 :   if (only_batch)
     256             :     {
     257         187 :       if (!dbs)
     258           6 :         return 0;  /* Shortcut to allow for easier cleanup code.  */
     259             : 
     260             :       /* If we are releasing the batch transaction, then we better not
     261             :          be in a normal transaction.  */
     262         181 :       log_assert (dbs->in_transaction == 0);
     263             : 
     264         181 :       if (/* Batch mode disabled?  */
     265         263 :           (!ctrl->tofu.batch_updated_wanted || only_batch == 2)
     266             :           /* But, we still have an open batch transaction?  */
     267          99 :           && dbs->in_batch_transaction)
     268             :         {
     269             :           /* The batch transaction is still in open, but we've left
     270             :            * batch mode.  */
     271          51 :           dbs->in_batch_transaction = 0;
     272             : 
     273          51 :           rc = gpgsql_stepx (dbs->db, &dbs->s.savepoint_batch_commit,
     274             :                              NULL, NULL, &err,
     275             :                              "release batch;", GPGSQL_ARG_END);
     276          51 :           if (rc)
     277             :             {
     278           0 :               log_error (_("error committing transaction on TOFU database: %s\n"),
     279             :                          err);
     280           0 :               sqlite3_free (err);
     281           0 :               return gpg_error (GPG_ERR_GENERAL);
     282             :             }
     283             : 
     284          51 :           return 0;
     285             :         }
     286             : 
     287         130 :       return 0;
     288             :     }
     289             : 
     290         104 :   log_assert (dbs);
     291         104 :   log_assert (dbs->in_transaction > 0);
     292             : 
     293         104 :   rc = gpgsql_exec_printf (dbs->db, NULL, NULL, &err,
     294             :                            "release inner%d;", dbs->in_transaction);
     295             : 
     296         104 :   dbs->in_transaction --;
     297             : 
     298         104 :   if (rc)
     299             :     {
     300           0 :       log_error (_("error committing transaction on TOFU database: %s\n"),
     301             :                  err);
     302           0 :       sqlite3_free (err);
     303           0 :       return gpg_error (GPG_ERR_GENERAL);
     304             :     }
     305             : 
     306         104 :   return 0;
     307             : }
     308             : 
     309             : 
     310             : static gpg_error_t
     311           0 : rollback_transaction (ctrl_t ctrl)
     312             : {
     313           0 :   tofu_dbs_t dbs = ctrl->tofu.dbs;
     314             :   int rc;
     315           0 :   char *err = NULL;
     316             : 
     317           0 :   log_assert (dbs);
     318           0 :   log_assert (dbs->in_transaction > 0);
     319             : 
     320             :   /* Be careful to not any progress made by closed transactions in
     321             :      batch mode.  */
     322           0 :   rc = gpgsql_exec_printf (dbs->db, NULL, NULL, &err,
     323             :                            "rollback to inner%d;",
     324             :                            dbs->in_transaction);
     325             : 
     326           0 :   dbs->in_transaction --;
     327             : 
     328           0 :   if (rc)
     329             :     {
     330           0 :       log_error (_("error rolling back transaction on TOFU database: %s\n"),
     331             :                  err);
     332           0 :       sqlite3_free (err);
     333           0 :       return gpg_error (GPG_ERR_GENERAL);
     334             :     }
     335             : 
     336           0 :   return 0;
     337             : }
     338             : 
     339             : void
     340         139 : tofu_begin_batch_update (ctrl_t ctrl)
     341             : {
     342         139 :   ctrl->tofu.batch_updated_wanted ++;
     343         139 : }
     344             : 
     345             : void
     346         139 : tofu_end_batch_update (ctrl_t ctrl)
     347             : {
     348         139 :   log_assert (ctrl->tofu.batch_updated_wanted > 0);
     349         139 :   ctrl->tofu.batch_updated_wanted --;
     350         139 :   end_transaction (ctrl, 1);
     351         139 : }
     352             : 
     353             : /* Suspend any extant batch transaction (it is safe to call this even
     354             :    no batch transaction has been started).  Note: you cannot suspend a
     355             :    batch transaction if you are in a normal transaction.  The batch
     356             :    transaction can be resumed explicitly by calling
     357             :    tofu_resume_batch_transaction or implicitly by starting a normal
     358             :    transaction.  */
     359             : static void
     360           0 : tofu_suspend_batch_transaction (ctrl_t ctrl)
     361             : {
     362           0 :   end_transaction (ctrl, 2);
     363           0 : }
     364             : 
     365             : /* Resume a batch transaction if there is no extant batch transaction
     366             :    and one has been requested using tofu_begin_batch_transaction.  */
     367             : static void
     368          88 : tofu_resume_batch_transaction (ctrl_t ctrl)
     369             : {
     370          88 :   begin_transaction (ctrl, 1);
     371          88 : }
     372             : 
     373             : 
     374             : 
     375             : /* Wrapper around strtol which prints a warning in case of a
     376             :  * conversion error.  On success the converted value is stored at
     377             :  * R_VALUE and 0 is returned; on error FALLBACK is stored at R_VALUE
     378             :  * and an error code is returned.  */
     379             : static gpg_error_t
     380         120 : string_to_long (long *r_value, const char *string, long fallback, int line)
     381             : {
     382             :   gpg_error_t err;
     383         120 :   char *tail = NULL;
     384             : 
     385         120 :   gpg_err_set_errno (0);
     386         120 :   *r_value = strtol (string, &tail, 0);
     387         120 :   if (errno || !(!strcmp (tail, ".0") || !*tail))
     388             :     {
     389           0 :       err = errno? gpg_error_from_errno (errno) : gpg_error (GPG_ERR_BAD_DATA);
     390           0 :       log_debug ("%s:%d: "
     391             :                  "strtol failed for DB returned string (tail=%.10s): %s\n",
     392             :                  __FILE__, line, tail, gpg_strerror (err));
     393           0 :       *r_value = fallback;
     394             :     }
     395             :   else
     396         120 :     err = 0;
     397             : 
     398         120 :   return err;
     399             : }
     400             : 
     401             : 
     402             : /* Wrapper around strtoul which prints a warning in case of a
     403             :  * conversion error.  On success the converted value is stored at
     404             :  * R_VALUE and 0 is returned; on error FALLBACK is stored at R_VALUE
     405             :  * and an error code is returned.  */
     406             : static gpg_error_t
     407         204 : string_to_ulong (unsigned long *r_value, const char *string,
     408             :                  unsigned long fallback, int line)
     409             : {
     410             :   gpg_error_t err;
     411         204 :   char *tail = NULL;
     412             : 
     413         204 :   gpg_err_set_errno (0);
     414         204 :   *r_value = strtoul (string, &tail, 0);
     415         204 :   if (errno || !(!strcmp (tail, ".0") || !*tail))
     416             :     {
     417           0 :       err = errno? gpg_error_from_errno (errno) : gpg_error (GPG_ERR_BAD_DATA);
     418           0 :       log_debug ("%s:%d: "
     419             :                  "strtoul failed for DB returned string (tail=%.10s): %s\n",
     420             :                  __FILE__, line, tail, gpg_strerror (err));
     421           0 :       *r_value = fallback;
     422             :     }
     423             :   else
     424         204 :     err = 0;
     425             : 
     426         204 :   return err;
     427             : }
     428             : 
     429             : 
     430             : 
     431             : /* Collect results of a select count (*) ...; style query.  Aborts if
     432             :    the argument is not a valid integer (or real of the form X.0).  */
     433             : static int
     434          54 : get_single_unsigned_long_cb (void *cookie, int argc, char **argv,
     435             :                              char **azColName)
     436             : {
     437          54 :   unsigned long int *count = cookie;
     438             : 
     439             :   (void) azColName;
     440             : 
     441          54 :   log_assert (argc == 1);
     442             : 
     443          54 :   if (string_to_ulong (count, argv[0], 0, __LINE__))
     444           0 :     return 1; /* Abort.  */
     445          54 :   return 0;
     446             : }
     447             : 
     448             : static int
     449           6 : get_single_unsigned_long_cb2 (void *cookie, int argc, char **argv,
     450             :                              char **azColName, sqlite3_stmt *stmt)
     451             : {
     452             :   (void) stmt;
     453           6 :   return get_single_unsigned_long_cb (cookie, argc, argv, azColName);
     454             : }
     455             : 
     456             : /* We expect a single integer column whose name is "version".  COOKIE
     457             :    must point to an int.  This function always aborts.  On error or a
     458             :    if the version is bad, sets *VERSION to -1.  */
     459             : static int
     460          47 : version_check_cb (void *cookie, int argc, char **argv, char **azColName)
     461             : {
     462          47 :   int *version = cookie;
     463             : 
     464          47 :   if (argc != 1 || strcmp (azColName[0], "version") != 0)
     465             :     {
     466           0 :       *version = -1;
     467           0 :       return 1;
     468             :     }
     469             : 
     470          47 :   if (strcmp (argv[0], "1") == 0)
     471          47 :     *version = 1;
     472             :   else
     473             :     {
     474           0 :       log_error (_("unsupported TOFU database version: %s\n"), argv[0]);
     475           0 :       *version = -1;
     476             :     }
     477             : 
     478             :   /* Don't run again.  */
     479          47 :   return 1;
     480             : }
     481             : 
     482             : 
     483             : /* If the DB is new, initialize it.  Otherwise, check the DB's
     484             :    version.
     485             : 
     486             :    Return 0 if the database is okay and 1 otherwise.  */
     487             : static int
     488          48 : initdb (sqlite3 *db)
     489             : {
     490          48 :   char *err = NULL;
     491             :   int rc;
     492             :   unsigned long int count;
     493          48 :   int version = -1;
     494             : 
     495          48 :   rc = sqlite3_exec (db, "begin transaction;", NULL, NULL, &err);
     496          48 :   if (rc)
     497             :     {
     498           0 :       log_error (_("error beginning transaction on TOFU database: %s\n"),
     499             :                  err);
     500           0 :       sqlite3_free (err);
     501           0 :       return 1;
     502             :     }
     503             : 
     504             :   /* If the DB has no tables, then assume this is a new DB that needs
     505             :      to be initialized.  */
     506          48 :   rc = sqlite3_exec (db,
     507             :                      "select count(*) from sqlite_master where type='table';",
     508             :                      get_single_unsigned_long_cb, &count, &err);
     509          48 :   if (rc)
     510             :     {
     511           0 :       log_error (_("error reading TOFU database: %s\n"), err);
     512           0 :       print_further_info ("query available tables");
     513           0 :       sqlite3_free (err);
     514           0 :       goto out;
     515             :     }
     516          48 :   else if (count != 0)
     517             :     /* Assume that the DB is already initialized.  Make sure the
     518             :        version is okay.  */
     519             :     {
     520          47 :       rc = sqlite3_exec (db, "select version from version;", version_check_cb,
     521             :                          &version, &err);
     522          47 :       if (rc == SQLITE_ABORT && version == 1)
     523             :         /* Happy, happy, joy, joy.  */
     524             :         {
     525          47 :           sqlite3_free (err);
     526          47 :           rc = 0;
     527          47 :           goto out;
     528             :         }
     529           0 :       else if (rc == SQLITE_ABORT && version == -1)
     530             :         /* Unsupported version.  */
     531             :         {
     532             :           /* An error message was already displayed.  */
     533           0 :           sqlite3_free (err);
     534           0 :           goto out;
     535             :         }
     536           0 :       else if (rc)
     537             :         /* Some error.  */
     538             :         {
     539           0 :           log_error (_("error determining TOFU database's version: %s\n"), err);
     540           0 :           sqlite3_free (err);
     541           0 :           goto out;
     542             :         }
     543             :       else
     544             :         {
     545             :           /* Unexpected success.  This can only happen if there are no
     546             :              rows.  (select returned 0, but expected ABORT.)  */
     547           0 :           log_error (_("error determining TOFU database's version: %s\n"),
     548             :                      gpg_strerror (GPG_ERR_NO_DATA));
     549           0 :           rc = 1;
     550           0 :           goto out;
     551             :         }
     552             :     }
     553             : 
     554             :   /* Create the version table.  */
     555           1 :   rc = sqlite3_exec (db,
     556             :                      "create table version (version INTEGER);",
     557             :                      NULL, NULL, &err);
     558           1 :   if (rc)
     559             :     {
     560           0 :       log_error (_("error initializing TOFU database: %s\n"), err);
     561           0 :       print_further_info ("create version");
     562           0 :       sqlite3_free (err);
     563           0 :       goto out;
     564             :     }
     565             : 
     566             :   /* Initialize the version table, which contains a single integer
     567             :      value.  */
     568           1 :   rc = sqlite3_exec (db,
     569             :                      "insert into version values (1);",
     570             :                      NULL, NULL, &err);
     571           1 :   if (rc)
     572             :     {
     573           0 :       log_error (_("error initializing TOFU database: %s\n"), err);
     574           0 :       print_further_info ("insert version");
     575           0 :       sqlite3_free (err);
     576           0 :       goto out;
     577             :     }
     578             : 
     579             :   /* The list of <fingerprint, email> bindings and auxiliary data.
     580             :    *
     581             :    *  OID is a unique ID identifying this binding (and used by the
     582             :    *    signatures table, see below).  Note: OIDs will never be
     583             :    *    reused.
     584             :    *
     585             :    *  FINGERPRINT: The key's fingerprint.
     586             :    *
     587             :    *  EMAIL: The normalized email address.
     588             :    *
     589             :    *  USER_ID: The unmodified user id from which EMAIL was extracted.
     590             :    *
     591             :    *  TIME: The time this binding was first observed.
     592             :    *
     593             :    *  POLICY: The trust policy (TOFU_POLICY_BAD, etc. as an integer).
     594             :    *
     595             :    *  CONFLICT is either NULL or a fingerprint.  Assume that we have
     596             :    *    a binding <0xdeadbeef, foo@example.com> and then we observe
     597             :    *    <0xbaddecaf, foo@example.com>.  There two bindings conflict
     598             :    *    (they have the same email address).  When we observe the
     599             :    *    latter binding, we warn the user about the conflict and ask
     600             :    *    for a policy decision about the new binding.  We also change
     601             :    *    the old binding's policy to ask if it was auto.  So that we
     602             :    *     know why this occurred, we also set conflict to 0xbaddecaf.
     603             :    */
     604           1 :   rc = gpgsql_exec_printf
     605             :       (db, NULL, NULL, &err,
     606             :        "create table bindings\n"
     607             :        " (oid INTEGER PRIMARY KEY AUTOINCREMENT,\n"
     608             :        "  fingerprint TEXT, email TEXT, user_id TEXT, time INTEGER,\n"
     609             :        "  policy BOOLEAN CHECK (policy in (%d, %d, %d, %d, %d)),\n"
     610             :        "  conflict STRING,\n"
     611             :        "  unique (fingerprint, email));\n"
     612             :        "create index bindings_fingerprint_email\n"
     613             :        " on bindings (fingerprint, email);\n"
     614             :        "create index bindings_email on bindings (email);\n",
     615             :        TOFU_POLICY_AUTO, TOFU_POLICY_GOOD, TOFU_POLICY_UNKNOWN,
     616             :        TOFU_POLICY_BAD, TOFU_POLICY_ASK);
     617           1 :   if (rc)
     618             :     {
     619           0 :       log_error (_("error initializing TOFU database: %s\n"), err);
     620           0 :       print_further_info ("create bindings");
     621           0 :       sqlite3_free (err);
     622           0 :       goto out;
     623             :     }
     624             : 
     625             :   /* The signatures that we have observed.
     626             :    *
     627             :    * BINDING refers to a record in the bindings table, which
     628             :    * describes the binding (i.e., this is a foreign key that
     629             :    * references bindings.oid).
     630             :    *
     631             :    * SIG_DIGEST is the digest stored in the signature.
     632             :    *
     633             :    * SIG_TIME is the timestamp stored in the signature.
     634             :    *
     635             :    * ORIGIN is a free-form string that describes who fed this
     636             :    * signature to GnuPG (e.g., email:claws).
     637             :    *
     638             :    * TIME is the time this signature was registered.  */
     639           1 :   rc = sqlite3_exec (db,
     640             :                          "create table signatures "
     641             :                          " (binding INTEGER NOT NULL, sig_digest TEXT,"
     642             :                          "  origin TEXT, sig_time INTEGER, time INTEGER,"
     643             :                          "  primary key (binding, sig_digest, origin));",
     644             :                          NULL, NULL, &err);
     645           1 :   if (rc)
     646             :     {
     647           0 :       log_error (_("error initializing TOFU database: %s\n"), err);
     648           0 :       print_further_info ("create signatures");
     649           0 :       sqlite3_free (err);
     650           0 :       goto out;
     651             :     }
     652             : 
     653             :  out:
     654          48 :   if (! rc)
     655             :     {
     656             :       /* Early version of the v1 format did not include the encryption
     657             :          table.  Add it.  */
     658          48 :       sqlite3_exec (db,
     659             :                     "create table if not exists encryptions"
     660             :                     " (binding INTEGER NOT NULL,"
     661             :                     "  time INTEGER);"
     662             :                     "create index if not exists encryptions_binding"
     663             :                     " on encryptions (binding);\n",
     664             :                     NULL, NULL, &err);
     665             :     }
     666             : 
     667          48 :   if (rc)
     668             :     {
     669           0 :       rc = sqlite3_exec (db, "rollback;", NULL, NULL, &err);
     670           0 :       if (rc)
     671             :         {
     672           0 :           log_error (_("error rolling back transaction on TOFU database: %s\n"),
     673             :                      err);
     674           0 :           sqlite3_free (err);
     675             :         }
     676           0 :       return 1;
     677             :     }
     678             :   else
     679             :     {
     680          48 :       rc = sqlite3_exec (db, "end transaction;", NULL, NULL, &err);
     681          48 :       if (rc)
     682             :         {
     683           0 :           log_error (_("error committing transaction on TOFU database: %s\n"),
     684             :                      err);
     685           0 :           sqlite3_free (err);
     686           0 :           return 1;
     687             :         }
     688          48 :       return 0;
     689             :     }
     690             : }
     691             : 
     692             : 
     693             : /* Create a new DB handle.  Returns NULL on error.  */
     694             : /* FIXME: Change to return an error code for better reporting by the
     695             :    caller.  */
     696             : static tofu_dbs_t
     697         120 : opendbs (ctrl_t ctrl)
     698             : {
     699             :   char *filename;
     700             :   sqlite3 *db;
     701             :   int rc;
     702             : 
     703         120 :   if (!ctrl->tofu.dbs)
     704             :     {
     705          48 :       filename = make_filename (gnupg_homedir (), "tofu.db", NULL);
     706             : 
     707          48 :       rc = sqlite3_open (filename, &db);
     708          48 :       if (rc)
     709             :         {
     710           0 :           log_error (_("error opening TOFU database '%s': %s\n"),
     711             :                      filename, sqlite3_errmsg (db));
     712             :           /* Even if an error occurs, DB is guaranteed to be valid.  */
     713           0 :           sqlite3_close (db);
     714           0 :           db = NULL;
     715             :         }
     716          48 :       xfree (filename);
     717             : 
     718             :       /* If a DB is locked wait up to 5 seconds for the lock to be cleared
     719             :          before failing.  */
     720          48 :       if (db)
     721          48 :         sqlite3_busy_timeout (db, 5 * 1000);
     722             : 
     723          48 :       if (db && initdb (db))
     724             :         {
     725           0 :           sqlite3_close (db);
     726           0 :           db = NULL;
     727             :         }
     728             : 
     729          48 :       if (db)
     730             :         {
     731          48 :           ctrl->tofu.dbs = xmalloc_clear (sizeof *ctrl->tofu.dbs);
     732          48 :           ctrl->tofu.dbs->db = db;
     733             :         }
     734             :     }
     735             :   else
     736          72 :     log_assert (ctrl->tofu.dbs->db);
     737             : 
     738         120 :   return ctrl->tofu.dbs;
     739             : }
     740             : 
     741             : 
     742             : /* Release all of the resources associated with the DB handle.  */
     743             : void
     744        1699 : tofu_closedbs (ctrl_t ctrl)
     745             : {
     746             :   tofu_dbs_t dbs;
     747             :   sqlite3_stmt **statements;
     748             : 
     749        1699 :   dbs = ctrl->tofu.dbs;
     750        1699 :   if (!dbs)
     751        3350 :     return;  /* Not initialized.  */
     752             : 
     753          48 :   log_assert (dbs->in_transaction == 0);
     754             : 
     755          48 :   end_transaction (ctrl, 2);
     756             : 
     757             :   /* Arghh, that is a surprising use of the struct.  */
     758         672 :   for (statements = (void *) &dbs->s;
     759         624 :        (void *) statements < (void *) &(&dbs->s)[1];
     760         576 :        statements ++)
     761         576 :     sqlite3_finalize (*statements);
     762             : 
     763          48 :   sqlite3_close (dbs->db);
     764          48 :   xfree (dbs);
     765          48 :   ctrl->tofu.dbs = NULL;
     766             : }
     767             : 
     768             : 
     769             : /* Collect results of a select min (foo) ...; style query.  Aborts if
     770             :    the argument is not a valid integer (or real of the form X.0).  */
     771             : static int
     772           4 : get_single_long_cb (void *cookie, int argc, char **argv, char **azColName)
     773             : {
     774           4 :   long *count = cookie;
     775             : 
     776             :   (void) azColName;
     777             : 
     778           4 :   log_assert (argc == 1);
     779             : 
     780           4 :   if (string_to_long (count, argv[0], 0, __LINE__))
     781           0 :     return 1; /* Abort.  */
     782             : 
     783           4 :   return 0;
     784             : }
     785             : 
     786             : static int
     787           4 : get_single_long_cb2 (void *cookie, int argc, char **argv, char **azColName,
     788             :                      sqlite3_stmt *stmt)
     789             : {
     790             :   (void) stmt;
     791           4 :   return get_single_long_cb (cookie, argc, argv, azColName);
     792             : }
     793             : 
     794             : /* Record (or update) a trust policy about a (possibly new)
     795             :    binding.
     796             : 
     797             :    If SHOW_OLD is set, the binding's old policy is displayed.  */
     798             : static gpg_error_t
     799           7 : record_binding (tofu_dbs_t dbs, const char *fingerprint, const char *email,
     800             :                 const char *user_id, enum tofu_policy policy, int show_old,
     801             :                 time_t now)
     802             : {
     803           7 :   char *fingerprint_pp = format_hexfingerprint (fingerprint, NULL, 0);
     804             :   gpg_error_t rc;
     805           7 :   char *err = NULL;
     806             : 
     807           9 :   if (! (policy == TOFU_POLICY_AUTO
     808           5 :          || policy == TOFU_POLICY_GOOD
     809           4 :          || policy == TOFU_POLICY_UNKNOWN
     810           3 :          || policy == TOFU_POLICY_BAD
     811             :          || policy == TOFU_POLICY_ASK))
     812           0 :     log_bug ("%s: Bad value for policy (%d)!\n", __func__, policy);
     813             : 
     814             : 
     815           7 :   if (DBG_TRUST || show_old)
     816             :     {
     817             :       /* Get the old policy.  Since this is just for informational
     818             :        * purposes, there is no need to start a transaction or to die
     819             :        * if there is a failure.  */
     820             : 
     821             :       /* policy_old needs to be a long and not an enum tofu_policy,
     822             :          because we pass it by reference to get_single_long_cb2, which
     823             :          expects a long.  */
     824           4 :       long policy_old = TOFU_POLICY_NONE;
     825             : 
     826           4 :       rc = gpgsql_stepx
     827             :         (dbs->db, &dbs->s.record_binding_get_old_policy,
     828             :          get_single_long_cb2, &policy_old, &err,
     829             :          "select policy from bindings where fingerprint = ? and email = ?",
     830             :          GPGSQL_ARG_STRING, fingerprint, GPGSQL_ARG_STRING, email,
     831             :          GPGSQL_ARG_END);
     832           4 :       if (rc)
     833             :         {
     834           0 :           log_debug ("TOFU: Error reading from binding database"
     835             :                      " (reading policy for <key: %s, user id: %s>): %s\n",
     836             :                      fingerprint, email, err);
     837           0 :           sqlite3_free (err);
     838             :         }
     839             : 
     840           4 :       if (policy_old != TOFU_POLICY_NONE)
     841           4 :         (show_old ? log_info : log_debug)
     842             :           ("Changing TOFU trust policy for binding"
     843             :            " <key: %s, user id: %s> from %s to %s.\n",
     844             :            fingerprint, show_old ? user_id : email,
     845             :            tofu_policy_str (policy_old),
     846             :            tofu_policy_str (policy));
     847             :       else
     848           0 :         (show_old ? log_info : log_debug)
     849             :           ("Setting TOFU trust policy for new binding"
     850             :            " <key: %s, user id: %s> to %s.\n",
     851             :            fingerprint, show_old ? user_id : email,
     852             :            tofu_policy_str (policy));
     853             : 
     854           4 :       if (policy_old == policy)
     855             :         {
     856           0 :           rc = 0;
     857           0 :           goto leave; /* Nothing to do.  */
     858             :         }
     859             :     }
     860             : 
     861           7 :   if (opt.dry_run)
     862             :     {
     863           0 :       log_info ("TOFU database update skipped due to --dry-run\n");
     864           0 :       rc = 0;
     865           0 :       goto leave;
     866             :     }
     867             : 
     868           7 :   rc = gpgsql_stepx
     869             :     (dbs->db, &dbs->s.record_binding_update, NULL, NULL, &err,
     870             :      "insert or replace into bindings\n"
     871             :      " (oid, fingerprint, email, user_id, time, policy)\n"
     872             :      " values (\n"
     873             :      /* If we don't explicitly reuse the OID, then SQLite will
     874             :         reallocate a new one.  We just need to search for the OID
     875             :         based on the fingerprint and email since they are unique.  */
     876             :      "  (select oid from bindings where fingerprint = ? and email = ?),\n"
     877             :      "  ?, ?, ?, ?, ?);",
     878             :      GPGSQL_ARG_STRING, fingerprint, GPGSQL_ARG_STRING, email,
     879             :      GPGSQL_ARG_STRING, fingerprint, GPGSQL_ARG_STRING, email,
     880             :      GPGSQL_ARG_STRING, user_id,
     881             :      GPGSQL_ARG_LONG_LONG, (long long) now,
     882             :      GPGSQL_ARG_INT, (int) policy,
     883             :      GPGSQL_ARG_END);
     884           7 :   if (rc)
     885             :     {
     886           0 :       log_error (_("error updating TOFU database: %s\n"), err);
     887           0 :       print_further_info (" insert bindings <key: %s, user id: %s> = %s",
     888             :                           fingerprint, email, tofu_policy_str (policy));
     889           0 :       sqlite3_free (err);
     890           0 :       goto leave;
     891             :     }
     892             : 
     893             :  leave:
     894           7 :   xfree (fingerprint_pp);
     895           7 :   return rc;
     896             : }
     897             : 
     898             : 
     899             : /* Collect the strings returned by a query in a simply string list.
     900             :    Any NULL values are converted to the empty string.
     901             : 
     902             :    If a result has 3 rows and each row contains two columns, then the
     903             :    results are added to the list as follows (the value is parentheses
     904             :    is the 1-based index in the final list):
     905             : 
     906             :      row 1, col 2 (6)
     907             :      row 1, col 1 (5)
     908             :      row 2, col 2 (4)
     909             :      row 2, col 1 (3)
     910             :      row 3, col 2 (2)
     911             :      row 3, col 1 (1)
     912             : 
     913             :    This is because add_to_strlist pushes the results onto the front of
     914             :    the list.  The end result is that the rows are backwards, but the
     915             :    columns are in the expected order.  */
     916             : static int
     917         169 : strings_collect_cb (void *cookie, int argc, char **argv, char **azColName)
     918             : {
     919             :   int i;
     920         169 :   strlist_t *strlist = cookie;
     921             : 
     922             :   (void) azColName;
     923             : 
     924         554 :   for (i = argc - 1; i >= 0; i --)
     925         385 :     add_to_strlist (strlist, argv[i] ? argv[i] : "");
     926             : 
     927         169 :   return 0;
     928             : }
     929             : 
     930             : static int
     931         119 : strings_collect_cb2 (void *cookie, int argc, char **argv, char **azColName,
     932             :                      sqlite3_stmt *stmt)
     933             : {
     934             :   (void) stmt;
     935         119 :   return strings_collect_cb (cookie, argc, argv, azColName);
     936             : 
     937             : }
     938             : 
     939             : /* Auxiliary data structure to collect statistics about
     940             :    signatures.  */
     941             : struct signature_stats
     942             : {
     943             :   struct signature_stats *next;
     944             : 
     945             :   /* The user-assigned policy for this binding.  */
     946             :   enum tofu_policy policy;
     947             : 
     948             :   /* How long ago the signature was created (rounded to a multiple of
     949             :      TIME_AGO_UNIT_SMALL, etc.).  */
     950             :   long time_ago;
     951             :   /* Number of signatures during this time.  */
     952             :   unsigned long count;
     953             : 
     954             :   /* If the corresponding key/user id has been expired / revoked.  */
     955             :   int is_expired;
     956             :   int is_revoked;
     957             : 
     958             :   /* The key that generated this signature.  */
     959             :   char fingerprint[1];
     960             : };
     961             : 
     962             : static void
     963           0 : signature_stats_free (struct signature_stats *stats)
     964             : {
     965           0 :   while (stats)
     966             :     {
     967           0 :       struct signature_stats *next = stats->next;
     968           0 :       xfree (stats);
     969           0 :       stats = next;
     970             :     }
     971           0 : }
     972             : 
     973             : static void
     974           0 : signature_stats_prepend (struct signature_stats **statsp,
     975             :                          const char *fingerprint,
     976             :                          enum tofu_policy policy,
     977             :                          long time_ago,
     978             :                          unsigned long count)
     979             : {
     980           0 :   struct signature_stats *stats =
     981           0 :     xmalloc_clear (sizeof (*stats) + strlen (fingerprint));
     982             : 
     983           0 :   stats->next = *statsp;
     984           0 :   *statsp = stats;
     985             : 
     986           0 :   strcpy (stats->fingerprint, fingerprint);
     987           0 :   stats->policy = policy;
     988           0 :   stats->time_ago = time_ago;
     989           0 :   stats->count = count;
     990           0 : }
     991             : 
     992             : 
     993             : /* Process rows that contain the four columns:
     994             : 
     995             :      <fingerprint, policy, time ago, count>.  */
     996             : static int
     997           0 : signature_stats_collect_cb (void *cookie, int argc, char **argv,
     998             :                             char **azColName, sqlite3_stmt *stmt)
     999             : {
    1000           0 :   struct signature_stats **statsp = cookie;
    1001           0 :   int i = 0;
    1002             :   enum tofu_policy policy;
    1003             :   long time_ago;
    1004             :   unsigned long count;
    1005             :   long along;
    1006             : 
    1007             :   (void) azColName;
    1008             :   (void) stmt;
    1009             : 
    1010           0 :   i ++;
    1011             : 
    1012           0 :   if (string_to_long (&along, argv[i], 0, __LINE__))
    1013           0 :     return 1;  /* Abort */
    1014           0 :   policy = along;
    1015           0 :   i ++;
    1016             : 
    1017           0 :   if (! argv[i])
    1018           0 :     time_ago = 0;
    1019             :   else
    1020             :     {
    1021           0 :       if (string_to_long (&time_ago, argv[i], 0, __LINE__))
    1022           0 :         return 1; /* Abort.  */
    1023             :     }
    1024           0 :   i ++;
    1025             : 
    1026             :   /* If time_ago is NULL, then we had no messages, but we still have a
    1027             :      single row, which count(*) turns into 1.  */
    1028           0 :   if (! argv[i - 1])
    1029           0 :     count = 0;
    1030             :   else
    1031             :     {
    1032           0 :       if (string_to_ulong (&count, argv[i], 0, __LINE__))
    1033           0 :         return 1; /* Abort */
    1034             :     }
    1035           0 :   i ++;
    1036             : 
    1037           0 :   log_assert (argc == i);
    1038             : 
    1039           0 :   signature_stats_prepend (statsp, argv[0], policy, time_ago, count);
    1040             : 
    1041           0 :   return 0;
    1042             : }
    1043             : 
    1044             : /* Convert from seconds to time units.
    1045             : 
    1046             :    Note: T should already be a multiple of TIME_AGO_UNIT_SMALL or
    1047             :    TIME_AGO_UNIT_MEDIUM or TIME_AGO_UNIT_LARGE.  */
    1048             : signed long
    1049           0 : time_ago_scale (signed long t)
    1050             : {
    1051           0 :   if (t < TIME_AGO_UNIT_MEDIUM)
    1052           0 :     return t / TIME_AGO_UNIT_SMALL;
    1053           0 :   if (t < TIME_AGO_UNIT_LARGE)
    1054           0 :     return t / TIME_AGO_UNIT_MEDIUM;
    1055           0 :   return t / TIME_AGO_UNIT_LARGE;
    1056             : }
    1057             : 
    1058             : 
    1059             : /* Return the policy for the binding <FINGERPRINT, EMAIL> (email has
    1060             :    already been normalized) and any conflict information in *CONFLICT
    1061             :    if CONFLICT is not NULL.  Returns _tofu_GET_POLICY_ERROR if an error
    1062             :    occurs.  */
    1063             : static enum tofu_policy
    1064         119 : get_policy (tofu_dbs_t dbs, const char *fingerprint, const char *email,
    1065             :             char **conflict)
    1066             : {
    1067             :   int rc;
    1068         119 :   char *err = NULL;
    1069         119 :   strlist_t strlist = NULL;
    1070         119 :   enum tofu_policy policy = _tofu_GET_POLICY_ERROR;
    1071             :   long along;
    1072             : 
    1073             :   /* Check if the <FINGERPRINT, EMAIL> binding is known
    1074             :      (TOFU_POLICY_NONE cannot appear in the DB.  Thus, if POLICY is
    1075             :      still TOFU_POLICY_NONE after executing the query, then the
    1076             :      result set was empty.)  */
    1077         119 :   rc = gpgsql_stepx (dbs->db, &dbs->s.get_policy_select_policy_and_conflict,
    1078             :                       strings_collect_cb2, &strlist, &err,
    1079             :                       "select policy, conflict from bindings\n"
    1080             :                       " where fingerprint = ? and email = ?",
    1081             :                       GPGSQL_ARG_STRING, fingerprint,
    1082             :                       GPGSQL_ARG_STRING, email,
    1083             :                       GPGSQL_ARG_END);
    1084         119 :   if (rc)
    1085             :     {
    1086           0 :       log_error (_("error reading TOFU database: %s\n"), err);
    1087           0 :       print_further_info ("checking for existing bad bindings");
    1088           0 :       sqlite3_free (err);
    1089           0 :       goto out;
    1090             :     }
    1091             : 
    1092         119 :   if (strlist_length (strlist) == 0)
    1093             :     /* No results.  */
    1094             :     {
    1095           3 :       policy = TOFU_POLICY_NONE;
    1096           3 :       goto out;
    1097             :     }
    1098         116 :   else if (strlist_length (strlist) != 2)
    1099             :     /* The result has the wrong form.  */
    1100             :     {
    1101           0 :       log_error (_("error reading TOFU database: %s\n"),
    1102             :                  gpg_strerror (GPG_ERR_BAD_DATA));
    1103           0 :       print_further_info ("checking for existing bad bindings:"
    1104             :                           " expected 2 results, got %d\n",
    1105             :                           strlist_length (strlist));
    1106           0 :       goto out;
    1107             :     }
    1108             : 
    1109             :   /* The result has the right form.  */
    1110             : 
    1111         116 :   if (string_to_long (&along, strlist->d, 0, __LINE__))
    1112             :     {
    1113           0 :       log_error (_("error reading TOFU database: %s\n"),
    1114             :                  gpg_strerror (GPG_ERR_BAD_DATA));
    1115           0 :       print_further_info ("bad value for policy: %s", strlist->d);
    1116           0 :       goto out;
    1117             :     }
    1118         116 :   policy = along;
    1119             : 
    1120         133 :   if (! (policy == TOFU_POLICY_AUTO
    1121          98 :          || policy == TOFU_POLICY_GOOD
    1122          73 :          || policy == TOFU_POLICY_UNKNOWN
    1123          48 :          || policy == TOFU_POLICY_BAD
    1124             :          || policy == TOFU_POLICY_ASK))
    1125             :     {
    1126           0 :       log_error (_("error reading TOFU database: %s\n"),
    1127             :                  gpg_strerror (GPG_ERR_DB_CORRUPTED));
    1128           0 :       print_further_info ("invalid value for policy (%d)", policy);
    1129           0 :       policy = _tofu_GET_POLICY_ERROR;
    1130           0 :       goto out;
    1131             :     }
    1132             : 
    1133             : 
    1134             :   /* If CONFLICT is set, then policy should be TOFU_POLICY_ASK.  But,
    1135             :      just in case, we do the check again here and ignore the conflict
    1136             :      if POLICY is not TOFU_POLICY_ASK.  */
    1137         116 :   if (conflict)
    1138             :     {
    1139           0 :       if (policy == TOFU_POLICY_ASK && *strlist->next->d)
    1140           0 :         *conflict = xstrdup (strlist->next->d);
    1141             :       else
    1142           0 :         *conflict = NULL;
    1143             :     }
    1144             : 
    1145             :  out:
    1146         119 :   log_assert (policy == _tofu_GET_POLICY_ERROR
    1147             :               || policy == TOFU_POLICY_NONE
    1148             :               || policy == TOFU_POLICY_AUTO
    1149             :               || policy == TOFU_POLICY_GOOD
    1150             :               || policy == TOFU_POLICY_UNKNOWN
    1151             :               || policy == TOFU_POLICY_BAD
    1152             :               || policy == TOFU_POLICY_ASK);
    1153             : 
    1154         119 :   free_strlist (strlist);
    1155             : 
    1156         119 :   return policy;
    1157             : }
    1158             : 
    1159             : 
    1160             : /* Format the first part of a conflict message and return that as a
    1161             :  * malloced string.  */
    1162             : static char *
    1163           0 : format_conflict_msg_part1 (int policy, strlist_t conflict_set,
    1164             :                            const char *email)
    1165             : {
    1166             :   estream_t fp;
    1167             :   char *fingerprint;
    1168             :   char *tmpstr, *text;
    1169             : 
    1170           0 :   log_assert (conflict_set);
    1171           0 :   fingerprint = conflict_set->d;
    1172             : 
    1173           0 :   fp = es_fopenmem (0, "rw,samethread");
    1174           0 :   if (!fp)
    1175           0 :     log_fatal ("error creating memory stream: %s\n",
    1176             :                gpg_strerror (gpg_error_from_syserror()));
    1177             : 
    1178           0 :   if (policy == TOFU_POLICY_NONE)
    1179             :     {
    1180           0 :       es_fprintf (fp,
    1181           0 :                   _("This is the first time the email address \"%s\" is "
    1182             :                     "being used with key %s."),
    1183             :                   email, fingerprint);
    1184           0 :       es_fputs ("  ", fp);
    1185             :     }
    1186           0 :   else if (policy == TOFU_POLICY_ASK && conflict_set->next)
    1187             :     {
    1188           0 :       int conflicts = strlist_length (conflict_set);
    1189           0 :       es_fprintf (fp, _("The email address \"%s\" is associated with %d keys!"),
    1190             :                   email, conflicts);
    1191           0 :       if (opt.verbose)
    1192           0 :         es_fprintf (fp,
    1193           0 :                     _("  Since this binding's policy was 'auto', it has been "
    1194             :                       "changed to 'ask'."));
    1195           0 :       es_fputs ("  ", fp);
    1196             :     }
    1197             : 
    1198           0 :   es_fprintf (fp,
    1199           0 :               _("Please indicate whether this email address should"
    1200             :                 " be associated with key %s or whether you think someone"
    1201             :                 " is impersonating \"%s\"."),
    1202             :               fingerprint, email);
    1203           0 :   es_fputc ('\n', fp);
    1204             : 
    1205           0 :   es_fputc (0, fp);
    1206           0 :   if (es_fclose_snatch (fp, (void **)&tmpstr, NULL))
    1207           0 :     log_fatal ("error snatching memory stream\n");
    1208           0 :   text = format_text (tmpstr, 0, 72, 80);
    1209           0 :   es_free (tmpstr);
    1210             : 
    1211           0 :   return text;
    1212             : }
    1213             : 
    1214             : 
    1215             : /* Return 1 if A signed B and B signed A.  */
    1216             : int
    1217           3 : cross_sigs (kbnode_t a, kbnode_t b)
    1218             : {
    1219             :   int i;
    1220             : 
    1221           3 :   PKT_public_key *a_pk = a->pkt->pkt.public_key;
    1222           3 :   PKT_public_key *b_pk = b->pkt->pkt.public_key;
    1223             : 
    1224             :   char a_keyid[33];
    1225             :   char b_keyid[33];
    1226             : 
    1227           3 :   if (DBG_TRUST)
    1228             :     {
    1229           0 :       format_keyid (pk_main_keyid (a_pk),
    1230             :                     KF_LONG, a_keyid, sizeof (a_keyid));
    1231           0 :       format_keyid (pk_main_keyid (b_pk),
    1232             :                     KF_LONG, b_keyid, sizeof (b_keyid));
    1233             :     }
    1234             : 
    1235           3 :   for (i = 0; i < 2; i ++)
    1236             :     {
    1237             :       /* See if SIGNER signed SIGNEE.  */
    1238             : 
    1239           3 :       kbnode_t signer = i == 0 ? a : b;
    1240           3 :       kbnode_t signee = i == 0 ? b : a;
    1241             : 
    1242           3 :       PKT_public_key *signer_pk = signer->pkt->pkt.public_key;
    1243           3 :       u32 *signer_kid = pk_main_keyid (signer_pk);
    1244             :       kbnode_t n;
    1245             : 
    1246             :       /* Iterate over SIGNEE's keyblock and see if there is a valid
    1247             :          signature from SIGNER.  */
    1248          18 :       for (n = signee; n; n = n->next)
    1249             :         {
    1250             :           PKT_signature *sig;
    1251             : 
    1252          15 :           if (n->pkt->pkttype != PKT_SIGNATURE)
    1253           9 :             continue;
    1254             : 
    1255           6 :           sig = n->pkt->pkt.signature;
    1256             : 
    1257          12 :           if (! (sig->sig_class == 0x10
    1258           6 :                  || sig->sig_class == 0x11
    1259           6 :                  || sig->sig_class == 0x12
    1260           6 :                  || sig->sig_class == 0x13))
    1261             :             /* Not a signature over a user id.  */
    1262           3 :             continue;
    1263             : 
    1264             :           /* SIG is on SIGNEE's keyblock.  If SIG was generated by the
    1265             :              signer, then it's a match.  */
    1266           3 :           if (keyid_cmp (sig->keyid, signer_kid) == 0)
    1267             :             /* Match!  */
    1268           0 :             break;
    1269             :         }
    1270           3 :       if (! n)
    1271             :         /* We didn't find a signature from signer over signee.  */
    1272             :         {
    1273           3 :           if (DBG_TRUST)
    1274           0 :             log_debug ("No cross sig between %s and %s\n",
    1275             :                        a_keyid, b_keyid);
    1276           3 :           return 0;
    1277             :         }
    1278             :     }
    1279             : 
    1280             :   /* A signed B and B signed A.  */
    1281           0 :   if (DBG_TRUST)
    1282           0 :     log_debug ("Cross sig between %s and %s\n",
    1283             :                a_keyid, b_keyid);
    1284             : 
    1285           0 :   return 1;
    1286             : }
    1287             : 
    1288             : 
    1289             : enum
    1290             :   {
    1291             :     BINDING_NEW = 1 << 0,
    1292             :     BINDING_CONFLICT = 1 << 1,
    1293             :     BINDING_EXPIRED = 1 << 2,
    1294             :     BINDING_REVOKED = 1 << 3
    1295             :   };
    1296             : 
    1297             : 
    1298             : /* Ask the user about the binding.  There are three ways we could end
    1299             :  * up here:
    1300             :  *
    1301             :  *   - This is a new binding and there is a conflict
    1302             :  *     (policy == TOFU_POLICY_NONE && conflict_set_count > 1),
    1303             :  *
    1304             :  *   - This is a new binding and opt.tofu_default_policy is set to
    1305             :  *     ask.  (policy == TOFU_POLICY_NONE && opt.tofu_default_policy ==
    1306             :  *     TOFU_POLICY_ASK), or,
    1307             :  *
    1308             :  *   - The policy is ask (the user deferred last time) (policy ==
    1309             :  *     TOFU_POLICY_ASK).
    1310             :  *
    1311             :  * Note: this function must not be called while in a transaction!
    1312             :  *
    1313             :  * CONFLICT_SET includes all of the conflicting bindings
    1314             :  * with FINGERPRINT first.  FLAGS is a bit-wise or of
    1315             :  * BINDING_NEW, etc.
    1316             :  */
    1317             : static void
    1318           0 : ask_about_binding (ctrl_t ctrl,
    1319             :                    enum tofu_policy *policy,
    1320             :                    int *trust_level,
    1321             :                    strlist_t conflict_set,
    1322             :                    const char *fingerprint,
    1323             :                    const char *email,
    1324             :                    const char *user_id,
    1325             :                    time_t now)
    1326             : {
    1327             :   tofu_dbs_t dbs;
    1328             :   strlist_t iter;
    1329           0 :   int conflict_set_count = strlist_length (conflict_set);
    1330           0 :   char *sqerr = NULL;
    1331             :   int rc;
    1332             :   estream_t fp;
    1333           0 :   strlist_t other_user_ids = NULL;
    1334           0 :   struct signature_stats *stats = NULL;
    1335           0 :   struct signature_stats *stats_iter = NULL;
    1336           0 :   char *prompt = NULL;
    1337             :   char *choices;
    1338             : 
    1339           0 :   dbs = ctrl->tofu.dbs;
    1340           0 :   log_assert (dbs);
    1341           0 :   log_assert (dbs->in_transaction == 0);
    1342             : 
    1343           0 :   fp = es_fopenmem (0, "rw,samethread");
    1344           0 :   if (!fp)
    1345           0 :     log_fatal ("error creating memory stream: %s\n",
    1346             :                gpg_strerror (gpg_error_from_syserror()));
    1347             : 
    1348             :   {
    1349           0 :     char *text = format_conflict_msg_part1 (*policy, conflict_set, email);
    1350           0 :     es_fputs (text, fp);
    1351           0 :     es_fputc ('\n', fp);
    1352           0 :     xfree (text);
    1353             :   }
    1354             : 
    1355           0 :   begin_transaction (ctrl, 0);
    1356             : 
    1357             :   /* Find other user ids associated with this key and whether the
    1358             :    * bindings are marked as good or bad.  */
    1359           0 :   rc = gpgsql_stepx
    1360             :     (dbs->db, &dbs->s.get_trust_gather_other_user_ids,
    1361             :      strings_collect_cb2, &other_user_ids, &sqerr,
    1362             :      "select user_id, policy from bindings where fingerprint = ?;",
    1363             :      GPGSQL_ARG_STRING, fingerprint, GPGSQL_ARG_END);
    1364           0 :   if (rc)
    1365             :     {
    1366           0 :       log_error (_("error gathering other user IDs: %s\n"), sqerr);
    1367           0 :       sqlite3_free (sqerr);
    1368           0 :       sqerr = NULL;
    1369             :     }
    1370             : 
    1371           0 :   if (other_user_ids)
    1372             :     {
    1373             :       strlist_t strlist_iter;
    1374             : 
    1375           0 :       es_fprintf (fp, _("This key's user IDs:\n"));
    1376           0 :       for (strlist_iter = other_user_ids;
    1377             :            strlist_iter;
    1378           0 :            strlist_iter = strlist_iter->next)
    1379             :         {
    1380           0 :           char *other_user_id = strlist_iter->d;
    1381             :           char *other_thing;
    1382             :           enum tofu_policy other_policy;
    1383             : 
    1384           0 :           log_assert (strlist_iter->next);
    1385           0 :           strlist_iter = strlist_iter->next;
    1386           0 :           other_thing = strlist_iter->d;
    1387             : 
    1388           0 :           other_policy = atoi (other_thing);
    1389             : 
    1390           0 :           es_fprintf (fp, "  %s (", other_user_id);
    1391           0 :           es_fprintf (fp, _("policy: %s"), tofu_policy_str (other_policy));
    1392           0 :           es_fprintf (fp, ")\n");
    1393             :         }
    1394           0 :       es_fprintf (fp, "\n");
    1395             : 
    1396           0 :       free_strlist (other_user_ids);
    1397             :     }
    1398             : 
    1399             :   /* Get the stats for all the keys in CONFLICT_SET.  */
    1400           0 :   strlist_rev (&conflict_set);
    1401           0 :   for (iter = conflict_set; iter && ! rc; iter = iter->next)
    1402             :     {
    1403             : #define STATS_SQL(table, time, sign)                         \
    1404             :          "select fingerprint, policy, time_ago, count(*)\n" \
    1405             :          " from\n" \
    1406             :          "  (select bindings.*,\n" \
    1407             :          "     "sign" case\n" \
    1408             :          "       when delta ISNULL then 1\n" \
    1409             :          /* From the future (but if its just a couple of hours in the \
    1410             :           * future don't turn it into a warning)?  Or should we use \
    1411             :           * small, medium or large units?  (Note: whatever we do, we \
    1412             :           * keep the value in seconds.  Then when we group, everything \
    1413             :           * that rounds to the same number of seconds is grouped.)  */ \
    1414             :          "      when delta < -("STRINGIFY (TIME_AGO_FUTURE_IGNORE)") then 2\n" \
    1415             :          "      when delta < ("STRINGIFY (TIME_AGO_SMALL_THRESHOLD)")\n" \
    1416             :          "       then 3\n" \
    1417             :          "      when delta < ("STRINGIFY (TIME_AGO_MEDIUM_THRESHOLD)")\n" \
    1418             :          "       then 4\n" \
    1419             :          "      when delta < ("STRINGIFY (TIME_AGO_LARGE_THRESHOLD)")\n" \
    1420             :          "       then 5\n" \
    1421             :          "      else 6\n" \
    1422             :          "     end time_ago,\n" \
    1423             :          "    delta time_ago_raw\n" \
    1424             :          "   from bindings\n" \
    1425             :          "   left join\n" \
    1426             :          "     (select *,\n" \
    1427             :          "        cast(? - " time " as real) delta\n" \
    1428             :          "       from " table ") ss\n" \
    1429             :          "    on ss.binding = bindings.oid)\n" \
    1430             :          " where email = ? and fingerprint = ?\n" \
    1431             :          " group by time_ago\n" \
    1432             :          /* Make sure the current key is first.  */ \
    1433             :          " order by time_ago desc;\n"
    1434             : 
    1435             :       /* Use the time when we saw the signature, not when the
    1436             :          signature was created as that can be forged.  */
    1437           0 :       rc = gpgsql_stepx
    1438             :         (dbs->db, &dbs->s.get_trust_gather_signature_stats,
    1439             :          signature_stats_collect_cb, &stats, &sqerr,
    1440             :          STATS_SQL ("signatures", "time", ""),
    1441             :          GPGSQL_ARG_LONG_LONG, (long long) now,
    1442             :          GPGSQL_ARG_STRING, email,
    1443           0 :          GPGSQL_ARG_STRING, iter->d,
    1444             :          GPGSQL_ARG_END);
    1445           0 :       if (rc)
    1446           0 :         break;
    1447             : 
    1448           0 :       if (!stats || strcmp (iter->d, stats->fingerprint) != 0)
    1449             :         /* No stats for this binding.  Add a dummy entry.  */
    1450           0 :         signature_stats_prepend (&stats, iter->d, TOFU_POLICY_AUTO, 1, 1);
    1451             : 
    1452           0 :       rc = gpgsql_stepx
    1453             :         (dbs->db, &dbs->s.get_trust_gather_encryption_stats,
    1454             :          signature_stats_collect_cb, &stats, &sqerr,
    1455             :          STATS_SQL ("encryptions", "time", "-"),
    1456             :          GPGSQL_ARG_LONG_LONG, (long long) now,
    1457             :          GPGSQL_ARG_STRING, email,
    1458           0 :          GPGSQL_ARG_STRING, iter->d,
    1459             :          GPGSQL_ARG_END);
    1460           0 :       if (rc)
    1461           0 :         break;
    1462             : 
    1463             : #undef STATS_SQL
    1464             : 
    1465           0 :       if (!stats || strcmp (iter->d, stats->fingerprint) != 0
    1466           0 :           || stats->time_ago > 0)
    1467             :         /* No stats for this binding.  Add a dummy entry.  */
    1468           0 :         signature_stats_prepend (&stats, iter->d, TOFU_POLICY_AUTO, -1, 1);
    1469             :     }
    1470           0 :   end_transaction (ctrl, 0);
    1471           0 :   strlist_rev (&conflict_set);
    1472           0 :   if (rc)
    1473             :     {
    1474             :       strlist_t strlist_iter;
    1475             : 
    1476           0 :       log_error (_("error gathering signature stats: %s\n"), sqerr);
    1477           0 :       sqlite3_free (sqerr);
    1478           0 :       sqerr = NULL;
    1479             : 
    1480           0 :       es_fprintf (fp, ngettext("The email address \"%s\" is"
    1481             :                                " associated with %d key:\n",
    1482             :                                "The email address \"%s\" is"
    1483             :                                " associated with %d keys:\n",
    1484             :                                conflict_set_count),
    1485             :                   email, conflict_set_count);
    1486           0 :       for (strlist_iter = conflict_set;
    1487             :            strlist_iter;
    1488           0 :            strlist_iter = strlist_iter->next)
    1489           0 :         es_fprintf (fp, "  %s\n", strlist_iter->d);
    1490             :     }
    1491             :   else
    1492             :     {
    1493           0 :       char *key = NULL;
    1494             :       strlist_t binding;
    1495           0 :       int seen_in_past = 0;
    1496             : 
    1497           0 :       es_fprintf (fp, _("Statistics for keys"
    1498             :                         " with the email address \"%s\":\n"),
    1499             :                   email);
    1500           0 :       for (stats_iter = stats; stats_iter; stats_iter = stats_iter->next)
    1501             :         {
    1502             : #if 0
    1503             :           log_debug ("%s: time_ago: %ld; count: %ld\n",
    1504             :                      stats_iter->fingerprint,
    1505             :                      stats_iter->time_ago,
    1506             :                      stats_iter->count);
    1507             : #endif
    1508             : 
    1509           0 :           if (! key || strcmp (key, stats_iter->fingerprint))
    1510             :             {
    1511             :               int this_key;
    1512             :               char *key_pp;
    1513             : 
    1514           0 :               key = stats_iter->fingerprint;
    1515           0 :               this_key = strcmp (key, fingerprint) == 0;
    1516           0 :               key_pp = format_hexfingerprint (key, NULL, 0);
    1517           0 :               es_fprintf (fp, "  %s (", key_pp);
    1518             : 
    1519             :               /* Find the associated binding.  */
    1520           0 :               for (binding = conflict_set;
    1521             :                    binding;
    1522           0 :                    binding = binding->next)
    1523           0 :                 if (strcmp (key, binding->d) == 0)
    1524           0 :                   break;
    1525           0 :               log_assert (binding);
    1526             : 
    1527           0 :               if ((binding->flags & BINDING_REVOKED))
    1528             :                 {
    1529           0 :                   es_fprintf (fp, _("revoked"));
    1530           0 :                   es_fprintf (fp, _(", "));
    1531             :                 }
    1532           0 :               else if ((binding->flags & BINDING_EXPIRED))
    1533             :                 {
    1534           0 :                   es_fprintf (fp, _("expired"));
    1535           0 :                   es_fprintf (fp, _(", "));
    1536             :                 }
    1537             : 
    1538           0 :               if (this_key)
    1539           0 :                 es_fprintf (fp, _("this key"));
    1540             :               else
    1541           0 :                 es_fprintf (fp, _("policy: %s"),
    1542             :                             tofu_policy_str (stats_iter->policy));
    1543           0 :               es_fputs ("):\n", fp);
    1544           0 :               xfree (key_pp);
    1545             : 
    1546           0 :               seen_in_past = 0;
    1547             :             }
    1548             : 
    1549           0 :           if (abs(stats_iter->time_ago) == 1)
    1550             :             {
    1551             :               /* The 1 in this case is the NULL entry.  */
    1552           0 :               log_assert (stats_iter->count == 1);
    1553           0 :               stats_iter->count = 0;
    1554             :             }
    1555           0 :           seen_in_past += stats_iter->count;
    1556             : 
    1557           0 :           es_fputs ("    ", fp);
    1558             :           /* TANSLATORS: This string is concatenated with one of
    1559             :            * the day/week/month strings to form one sentence.  */
    1560           0 :           if (stats_iter->time_ago > 0)
    1561           0 :             es_fprintf (fp, ngettext("Verified %d message",
    1562             :                                      "Verified %d messages",
    1563             :                                      seen_in_past), seen_in_past);
    1564             :           else
    1565           0 :             es_fprintf (fp, ngettext("Encrypted %d message",
    1566             :                                      "Encrypted %d messages",
    1567             :                                      seen_in_past), seen_in_past);
    1568             : 
    1569           0 :           if (!stats_iter->count)
    1570           0 :             es_fputs (".", fp);
    1571           0 :           else if (abs(stats_iter->time_ago) == 2)
    1572             :             {
    1573           0 :               es_fprintf (fp, "in the future.");
    1574             :               /* Reset it.  */
    1575           0 :               seen_in_past = 0;
    1576             :             }
    1577             :           else
    1578             :             {
    1579           0 :               if (abs(stats_iter->time_ago) == 3)
    1580           0 :                 es_fprintf (fp, ngettext(" over the past days.",
    1581             :                                          " over the past %d days.",
    1582             :                                          seen_in_past),
    1583             :                             TIME_AGO_SMALL_THRESHOLD
    1584             :                             / TIME_AGO_UNIT_SMALL);
    1585           0 :               else if (abs(stats_iter->time_ago) == 4)
    1586           0 :                 es_fprintf (fp, ngettext(" over the past month.",
    1587             :                                          " over the past %d months.",
    1588             :                                          seen_in_past),
    1589             :                             TIME_AGO_MEDIUM_THRESHOLD
    1590             :                             / TIME_AGO_UNIT_MEDIUM);
    1591           0 :               else if (abs(stats_iter->time_ago) == 5)
    1592           0 :                 es_fprintf (fp, ngettext(" over the past year.",
    1593             :                                          " over the past %d years.",
    1594             :                                          seen_in_past),
    1595             :                             TIME_AGO_LARGE_THRESHOLD
    1596             :                             / TIME_AGO_UNIT_LARGE);
    1597           0 :               else if (abs(stats_iter->time_ago) == 6)
    1598           0 :                 es_fprintf (fp, _(" in the past."));
    1599             :               else
    1600           0 :                 log_assert (! "Broken SQL.\n");
    1601             :             }
    1602           0 :           es_fputs ("\n", fp);
    1603             :         }
    1604             :     }
    1605             : 
    1606           0 :   if (conflict_set_count > 1 || (conflict_set->flags & BINDING_CONFLICT))
    1607             :     {
    1608             :       /* This is a conflict.  */
    1609             : 
    1610             :       /* TRANSLATORS: Please translate the text found in the source
    1611             :        * file below.  We don't directly internationalize that text so
    1612             :        * that we can tweak it without breaking translations.  */
    1613           0 :       char *text = _("TOFU detected a binding conflict");
    1614             :       char *textbuf;
    1615           0 :       if (!strcmp (text, "TOFU detected a binding conflict"))
    1616             :         {
    1617             :           /* No translation.  Use the English text.  */
    1618           0 :           text =
    1619             :             "Normally, an email address is associated with a single key.  "
    1620             :             "However, people sometimes generate a new key if "
    1621             :             "their key is too old or they think it might be compromised.  "
    1622             :             "Alternatively, a new key may indicate a man-in-the-middle "
    1623             :             "attack!  Before accepting this association, you should talk to or "
    1624             :             "call the person to make sure this new key is legitimate.";
    1625             :         }
    1626           0 :       textbuf = format_text (text, 0, 72, 80);
    1627           0 :       es_fprintf (fp, "\n%s\n", textbuf);
    1628           0 :       xfree (textbuf);
    1629             :     }
    1630             : 
    1631           0 :   es_fputc ('\n', fp);
    1632             : 
    1633             :   /* Add a NUL terminator.  */
    1634           0 :   es_fputc (0, fp);
    1635           0 :   if (es_fclose_snatch (fp, (void **) &prompt, NULL))
    1636           0 :     log_fatal ("error snatching memory stream\n");
    1637             : 
    1638             :   /* I think showing the large message once is sufficient.  If we
    1639             :    * would move it right before the cpr_get many lines will scroll
    1640             :    * away and the user might not realize that he merely entered a
    1641             :    * wrong choise (because he does not see that either).  As a small
    1642             :    * benefit we allow C-L to redisplay everything.  */
    1643           0 :   tty_printf ("%s", prompt);
    1644             : 
    1645             :   /* Suspend any transaction: it could take a while until the user
    1646             :      responds.  */
    1647           0 :   tofu_suspend_batch_transaction (ctrl);
    1648             :   while (1)
    1649             :     {
    1650             :       char *response;
    1651             : 
    1652             :       /* TRANSLATORS: Two letters (normally the lower and upper case
    1653             :        * version of the hotkey) for each of the five choices.  If
    1654             :        * there is only one choice in your language, repeat it.  */
    1655           0 :       choices = _("gG" "aA" "uU" "rR" "bB");
    1656           0 :       if (strlen (choices) != 10)
    1657           0 :         log_bug ("Bad TOFU conflict translation!  Please report.");
    1658             : 
    1659           0 :       response = cpr_get
    1660             :         ("tofu.conflict",
    1661           0 :          _("(G)ood, (A)ccept once, (U)nknown, (R)eject once, (B)ad? "));
    1662           0 :       trim_spaces (response);
    1663           0 :       cpr_kill_prompt ();
    1664           0 :       if (*response == CONTROL_L)
    1665           0 :         tty_printf ("%s", prompt);
    1666           0 :       else if (!response[0])
    1667             :         /* Default to unknown.  Don't save it.  */
    1668             :         {
    1669           0 :           tty_printf (_("Defaulting to unknown."));
    1670           0 :           *policy = TOFU_POLICY_UNKNOWN;
    1671           0 :           break;
    1672             :         }
    1673           0 :       else if (!response[1])
    1674             :         {
    1675           0 :           char *choice = strchr (choices, *response);
    1676             : 
    1677           0 :           if (choice)
    1678             :             {
    1679           0 :               int c = ((size_t) choice - (size_t) choices) / 2;
    1680             : 
    1681           0 :               switch (c)
    1682             :                 {
    1683             :                 case 0: /* Good.  */
    1684           0 :                   *policy = TOFU_POLICY_GOOD;
    1685           0 :                   *trust_level = tofu_policy_to_trust_level (*policy);
    1686           0 :                   break;
    1687             :                 case 1: /* Accept once.  */
    1688           0 :                   *policy = TOFU_POLICY_ASK;
    1689           0 :                   *trust_level = tofu_policy_to_trust_level (TOFU_POLICY_GOOD);
    1690           0 :                   break;
    1691             :                 case 2: /* Unknown.  */
    1692           0 :                   *policy = TOFU_POLICY_UNKNOWN;
    1693           0 :                   *trust_level = tofu_policy_to_trust_level (*policy);
    1694           0 :                   break;
    1695             :                 case 3: /* Reject once.  */
    1696           0 :                   *policy = TOFU_POLICY_ASK;
    1697           0 :                   *trust_level = tofu_policy_to_trust_level (TOFU_POLICY_BAD);
    1698           0 :                   break;
    1699             :                 case 4: /* Bad.  */
    1700           0 :                   *policy = TOFU_POLICY_BAD;
    1701           0 :                   *trust_level = tofu_policy_to_trust_level (*policy);
    1702           0 :                   break;
    1703             :                 default:
    1704           0 :                   log_bug ("c should be between 0 and 4 but it is %d!", c);
    1705             :                 }
    1706             : 
    1707           0 :               if (record_binding (dbs, fingerprint, email, user_id,
    1708             :                                   *policy, 0, now))
    1709             :                 {
    1710             :                   /* If there's an error registering the
    1711             :                    * binding, don't save the signature.  */
    1712           0 :                   *trust_level = _tofu_GET_TRUST_ERROR;
    1713             :                 }
    1714           0 :               break;
    1715             :             }
    1716             :         }
    1717           0 :       xfree (response);
    1718           0 :     }
    1719             : 
    1720           0 :   tofu_resume_batch_transaction (ctrl);
    1721             : 
    1722           0 :   xfree (prompt);
    1723             : 
    1724           0 :   signature_stats_free (stats);
    1725           0 : }
    1726             : 
    1727             : /* Return the set of keys that conflict with the binding <fingerprint,
    1728             :    email> (including the binding itself, which will be first in the
    1729             :    list).  For each returned key also sets BINDING_NEW, etc.  */
    1730             : static strlist_t
    1731           3 : build_conflict_set (tofu_dbs_t dbs, const char *fingerprint, const char *email)
    1732             : {
    1733             :   gpg_error_t rc;
    1734             :   char *sqerr;
    1735           3 :   strlist_t conflict_set = NULL;
    1736             :   int conflict_set_count;
    1737             :   strlist_t iter;
    1738             :   kbnode_t *kb_all;
    1739             :   KEYDB_HANDLE hd;
    1740             :   int i;
    1741             : 
    1742             :   /* Get the fingerprints of any bindings that share the email address
    1743             :    * and whether the bindings have a known conflict.
    1744             :    *
    1745             :    * Note: if the binding in question is in the DB, it will also be
    1746             :    * returned.  Thus, if the result set is empty, then <email,
    1747             :    * fingerprint> is a new binding.  */
    1748           3 :   rc = gpgsql_stepx
    1749             :     (dbs->db, &dbs->s.get_trust_bindings_with_this_email,
    1750             :      strings_collect_cb2, &conflict_set, &sqerr,
    1751             :      "select"
    1752             :      /* A binding should only appear once, but try not to break in the
    1753             :       * case of corruption.  */
    1754             :      "  fingerprint || case sum(conflict ISNULL) when 0 then '' else '!' end"
    1755             :      " from bindings where email = ?"
    1756             :      "  group by fingerprint"
    1757             :      /* Make sure the current key comes first in the result list (if
    1758             :         it is present).  */
    1759             :      "  order by fingerprint = ? asc, fingerprint desc;",
    1760             :      GPGSQL_ARG_STRING, email,
    1761             :      GPGSQL_ARG_STRING, fingerprint,
    1762             :      GPGSQL_ARG_END);
    1763           3 :   if (rc)
    1764             :     {
    1765           0 :       log_error (_("error reading TOFU database: %s\n"), sqerr);
    1766           0 :       print_further_info ("listing fingerprints");
    1767           0 :       sqlite3_free (sqerr);
    1768           0 :       return NULL;
    1769             :     }
    1770             : 
    1771             :   /* Set BINDING_CONFLICT if the binding has a known conflict.  This
    1772             :    * allows us to distinguish between bindings where the user
    1773             :    * explicitly set the policy to ask and bindings where we set the
    1774             :    * policy to ask due to a conflict.  */
    1775           6 :   for (iter = conflict_set; iter; iter = iter->next)
    1776             :     {
    1777           3 :       int l = strlen (iter->d);
    1778           3 :       if (!(l == 2 * MAX_FINGERPRINT_LEN
    1779             :             || l == 2 * MAX_FINGERPRINT_LEN + 1))
    1780             :         {
    1781           0 :           log_error (_("TOFU db corruption detected.\n"));
    1782           0 :           print_further_info ("fingerprint '%s' is not %d characters long",
    1783           0 :                               iter->d, 2 * MAX_FINGERPRINT_LEN);
    1784             :         }
    1785             : 
    1786           3 :       if (l >= 1 && iter->d[l - 1] == '!')
    1787             :         {
    1788           3 :           iter->flags |= BINDING_CONFLICT;
    1789             :           /* Remove the !.  */
    1790           3 :           iter->d[l - 1] = 0;
    1791             :         }
    1792             :     }
    1793             : 
    1794             :   /* If the current binding has not yet been recorded, add it to the
    1795             :    * list.  (The order by above ensures that if it is present, it will
    1796             :    * be first.)  */
    1797           3 :   if (! (conflict_set && strcmp (conflict_set->d, fingerprint) == 0))
    1798             :     {
    1799           3 :       add_to_strlist (&conflict_set, fingerprint);
    1800           3 :       conflict_set->flags |= BINDING_NEW;
    1801             :     }
    1802             : 
    1803           3 :   conflict_set_count = strlist_length (conflict_set);
    1804             : 
    1805             :   /* Eliminate false conflicts.  */
    1806             : 
    1807             :   /* If two keys have cross signatures, then they are controlled by
    1808             :    * the same person and thus are not in conflict.  */
    1809           3 :   kb_all = xcalloc (sizeof (kb_all[0]), conflict_set_count);
    1810           3 :   hd = keydb_new ();
    1811          12 :   for (i = 0, iter = conflict_set;
    1812             :        i < conflict_set_count;
    1813           6 :        i ++, iter = iter->next)
    1814             :     {
    1815           6 :       char *fp = iter->d;
    1816             :       KEYDB_SEARCH_DESC desc;
    1817             :       kbnode_t kb;
    1818             :       PKT_public_key *binding_pk;
    1819             :       kbnode_t n;
    1820             :       int found_user_id;
    1821             : 
    1822           6 :       rc = keydb_search_reset (hd);
    1823           6 :       if (rc)
    1824             :         {
    1825           0 :           log_error (_("resetting keydb: %s\n"),
    1826             :                      gpg_strerror (rc));
    1827           0 :           continue;
    1828             :         }
    1829             : 
    1830           6 :       rc = classify_user_id (fp, &desc, 0);
    1831           6 :       if (rc)
    1832             :         {
    1833           0 :           log_error (_("error parsing key specification '%s': %s\n"),
    1834             :                      fp, gpg_strerror (rc));
    1835           0 :           continue;
    1836             :         }
    1837             : 
    1838           6 :       rc = keydb_search (hd, &desc, 1, NULL);
    1839           6 :       if (rc)
    1840             :         {
    1841             :           /* Note: it is entirely possible that we don't have the key
    1842             :              corresponding to an entry in the TOFU DB.  This can
    1843             :              happen if we merge two TOFU DBs, but not the key
    1844             :              rings.  */
    1845           0 :           log_info (_("key \"%s\" not found: %s\n"),
    1846             :                     fp, gpg_strerror (rc));
    1847           0 :           continue;
    1848             :         }
    1849             : 
    1850           6 :       rc = keydb_get_keyblock (hd, &kb);
    1851           6 :       if (rc)
    1852             :         {
    1853           0 :           log_error (_("error reading keyblock: %s\n"),
    1854             :                      gpg_strerror (rc));
    1855           0 :           print_further_info ("fingerprint: %s", fp);
    1856           0 :           continue;
    1857             :         }
    1858             : 
    1859           6 :       merge_keys_and_selfsig (kb);
    1860             : 
    1861           6 :       log_assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
    1862             : 
    1863           6 :       kb_all[i] = kb;
    1864             : 
    1865             :       /* Since we have the key block, use this opportunity to figure
    1866             :        * out if the binding is expired or revoked.  */
    1867           6 :       binding_pk = kb->pkt->pkt.public_key;
    1868             : 
    1869             :       /* The binding is always expired/revoked if the key is
    1870             :        * expired/revoked.  */
    1871           6 :       if (binding_pk->has_expired)
    1872           0 :         iter->flags &= BINDING_EXPIRED;
    1873           6 :       if (binding_pk->flags.revoked)
    1874           0 :         iter->flags &= BINDING_REVOKED;
    1875             : 
    1876             :       /* The binding is also expired/revoked if the user id is
    1877             :        * expired/revoked.  */
    1878           6 :       n = kb;
    1879           6 :       found_user_id = 0;
    1880          18 :       while ((n = find_next_kbnode (n, PKT_USER_ID)) && ! found_user_id)
    1881             :         {
    1882           6 :           PKT_user_id *user_id2 = n->pkt->pkt.user_id;
    1883             :           char *email2;
    1884             : 
    1885           6 :           if (user_id2->attrib_data)
    1886           0 :             continue;
    1887             : 
    1888           6 :           email2 = email_from_user_id (user_id2->name);
    1889             : 
    1890           6 :           if (strcmp (email, email2) == 0)
    1891             :             {
    1892           6 :               found_user_id = 1;
    1893             : 
    1894           6 :               if (user_id2->is_revoked)
    1895           0 :                 iter->flags &= BINDING_REVOKED;
    1896           6 :               if (user_id2->is_expired)
    1897           0 :                 iter->flags &= BINDING_EXPIRED;
    1898             :             }
    1899             : 
    1900           6 :           xfree (email2);
    1901             :         }
    1902             : 
    1903           6 :       if (! found_user_id)
    1904             :         {
    1905           0 :           log_info (_("TOFU db corruption detected.\n"));
    1906           0 :           print_further_info ("user id '%s' not on key block '%s'",
    1907             :                               email, fingerprint);
    1908             :         }
    1909             :     }
    1910           3 :   keydb_release (hd);
    1911             : 
    1912             :   /* Now that we have the key blocks, check for cross sigs.  */
    1913             :   {
    1914             :     int j;
    1915             :     strlist_t *prevp;
    1916             :     strlist_t iter_next;
    1917           3 :     int die[conflict_set_count];
    1918             : 
    1919           3 :     memset (die, 0, sizeof (die));
    1920             : 
    1921           9 :     for (i = 0; i < conflict_set_count; i ++)
    1922             :       {
    1923             :         /* Look for cross sigs between this key (i == 0) or a key
    1924             :          * that has cross sigs with i == 0 (i.e., transitively) */
    1925           6 :         if (! (i == 0 || die[i]))
    1926           3 :           continue;
    1927             : 
    1928           6 :         for (j = i + 1; j < conflict_set_count; j ++)
    1929             :           /* Be careful: we might not have a key block for a key.  */
    1930           3 :           if (kb_all[i] && kb_all[j] && cross_sigs (kb_all[i], kb_all[j]))
    1931           0 :             die[j] = 1;
    1932             :       }
    1933             : 
    1934             :     /* Free unconflicting bindings (and all of the key blocks).  */
    1935          12 :     for (iter = conflict_set, prevp = &conflict_set, i = 0;
    1936             :          iter;
    1937           6 :          iter = iter_next, i ++)
    1938             :       {
    1939           6 :         iter_next = iter->next;
    1940             : 
    1941           6 :         release_kbnode (kb_all[i]);
    1942             : 
    1943           6 :         if (die[i])
    1944             :           {
    1945           0 :             *prevp = iter_next;
    1946           0 :             iter->next = NULL;
    1947           0 :             free_strlist (iter);
    1948           0 :             conflict_set_count --;
    1949             :           }
    1950             :         else
    1951             :           {
    1952           6 :             prevp = &iter->next;
    1953             :           }
    1954             :       }
    1955             : 
    1956             :     /* We shouldn't have removed the head.  */
    1957           3 :     log_assert (conflict_set);
    1958           3 :     log_assert (conflict_set_count >= 1);
    1959             :   }
    1960             : 
    1961           3 :   if (DBG_TRUST)
    1962             :     {
    1963           0 :       log_debug ("binding <key: %s, email: %s> conflicts:\n",
    1964             :                  fingerprint, email);
    1965           0 :       for (iter = conflict_set; iter; iter = iter->next)
    1966             :         {
    1967           0 :           log_debug ("  %s:%s%s%s%s\n",
    1968           0 :                      iter->d,
    1969           0 :                      (iter->flags & BINDING_NEW) ? " new" : "",
    1970           0 :                      (iter->flags & BINDING_CONFLICT) ? " known_conflict" : "",
    1971           0 :                      (iter->flags & BINDING_EXPIRED) ? " expired" : "",
    1972           0 :                      (iter->flags & BINDING_REVOKED) ? " revoked" : "");
    1973             :         }
    1974             :     }
    1975             : 
    1976           3 :   return conflict_set;
    1977             : }
    1978             : 
    1979             : 
    1980             : /* Return the trust level (TRUST_NEVER, etc.) for the binding
    1981             :  * <FINGERPRINT, EMAIL> (email is already normalized).  If no policy
    1982             :  * is registered, returns TOFU_POLICY_NONE.  If an error occurs,
    1983             :  * returns _tofu_GET_TRUST_ERROR.
    1984             :  *
    1985             :  * PK is the public key object for FINGERPRINT.
    1986             :  *
    1987             :  * USER_ID is the unadulterated user id.
    1988             :  *
    1989             :  * If MAY_ASK is set, then we may interact with the user.  This is
    1990             :  * necessary if there is a conflict or the binding's policy is
    1991             :  * TOFU_POLICY_ASK.  In the case of a conflict, we set the new
    1992             :  * conflicting binding's policy to TOFU_POLICY_ASK.  In either case,
    1993             :  * we return TRUST_UNDEFINED.  Note: if MAY_ASK is set, then this
    1994             :  * function must not be called while in a transaction!  */
    1995             : static enum tofu_policy
    1996          94 : get_trust (ctrl_t ctrl, PKT_public_key *pk,
    1997             :            const char *fingerprint, const char *email,
    1998             :            const char *user_id, int may_ask, time_t now)
    1999             : {
    2000          94 :   tofu_dbs_t dbs = ctrl->tofu.dbs;
    2001          94 :   int in_transaction = 0;
    2002             :   enum tofu_policy policy;
    2003             :   int rc;
    2004          94 :   char *sqerr = NULL;
    2005          94 :   int change_conflicting_to_ask = 0;
    2006          94 :   strlist_t conflict_set = NULL;
    2007             :   int conflict_set_count;
    2008          94 :   int trust_level = TRUST_UNKNOWN;
    2009             :   strlist_t iter;
    2010             : 
    2011          94 :   log_assert (dbs);
    2012             : 
    2013          94 :   if (may_ask)
    2014           3 :     log_assert (dbs->in_transaction == 0);
    2015             : 
    2016          94 :   if (opt.batch)
    2017          94 :     may_ask = 0;
    2018             : 
    2019          94 :   log_assert (keyid_cmp (pk_keyid (pk), pk->main_keyid) == 0);
    2020             : 
    2021             :   /* Make sure _tofu_GET_TRUST_ERROR isn't equal to any of the trust
    2022             :      levels.  */
    2023             :   log_assert (_tofu_GET_TRUST_ERROR != TRUST_UNKNOWN
    2024             :               && _tofu_GET_TRUST_ERROR != TRUST_EXPIRED
    2025             :               && _tofu_GET_TRUST_ERROR != TRUST_UNDEFINED
    2026             :               && _tofu_GET_TRUST_ERROR != TRUST_NEVER
    2027             :               && _tofu_GET_TRUST_ERROR != TRUST_MARGINAL
    2028             :               && _tofu_GET_TRUST_ERROR != TRUST_FULLY
    2029             :               && _tofu_GET_TRUST_ERROR != TRUST_ULTIMATE);
    2030             : 
    2031          94 :   begin_transaction (ctrl, 0);
    2032          94 :   in_transaction = 1;
    2033             : 
    2034          94 :   policy = get_policy (dbs, fingerprint, email, NULL);
    2035             :   {
    2036             :     /* See if the key is ultimately trusted.  If so, we're done.  */
    2037             :     u32 kid[2];
    2038             : 
    2039          94 :     keyid_from_pk (pk, kid);
    2040             : 
    2041          94 :     if (tdb_keyid_is_utk (kid))
    2042             :       {
    2043           0 :         if (policy == TOFU_POLICY_NONE)
    2044             :           {
    2045           0 :             if (record_binding (dbs, fingerprint, email, user_id,
    2046             :                                 TOFU_POLICY_AUTO, 0, now) != 0)
    2047             :               {
    2048           0 :                 log_error (_("error setting TOFU binding's trust level"
    2049             :                              " to %s\n"), "auto");
    2050           0 :                 trust_level = _tofu_GET_TRUST_ERROR;
    2051           0 :                 goto out;
    2052             :               }
    2053             :           }
    2054             : 
    2055           0 :         trust_level = TRUST_ULTIMATE;
    2056           0 :         goto out;
    2057             :       }
    2058             :   }
    2059             : 
    2060          94 :   if (policy == TOFU_POLICY_AUTO)
    2061             :     {
    2062          15 :       policy = opt.tofu_default_policy;
    2063          15 :       if (DBG_TRUST)
    2064           0 :         log_debug ("TOFU: binding <key: %s, user id: %s>'s policy is"
    2065             :                    " auto (default: %s).\n",
    2066             :                    fingerprint, email,
    2067             :                    tofu_policy_str (opt.tofu_default_policy));
    2068             :     }
    2069          94 :   switch (policy)
    2070             :     {
    2071             :     case TOFU_POLICY_AUTO:
    2072             :     case TOFU_POLICY_GOOD:
    2073             :     case TOFU_POLICY_UNKNOWN:
    2074             :     case TOFU_POLICY_BAD:
    2075             :       /* The saved judgement is auto -> auto, good, unknown or bad.
    2076             :        * We don't need to ask the user anything.  */
    2077          79 :       if (DBG_TRUST)
    2078           0 :         log_debug ("TOFU: Known binding <key: %s, user id: %s>'s policy: %s\n",
    2079             :                    fingerprint, email, tofu_policy_str (policy));
    2080          79 :       trust_level = tofu_policy_to_trust_level (policy);
    2081          79 :       goto out;
    2082             : 
    2083             :     case TOFU_POLICY_ASK:
    2084             :       /* We need to ask the user what to do.  Case #1 or #2 below.  */
    2085          12 :       if (! may_ask)
    2086             :         {
    2087          12 :           trust_level = TRUST_UNDEFINED;
    2088          12 :           goto out;
    2089             :         }
    2090             : 
    2091           0 :       break;
    2092             : 
    2093             :     case TOFU_POLICY_NONE:
    2094             :       /* The binding is new, we need to check for conflicts.  Case #3
    2095             :        * below.  */
    2096           3 :       break;
    2097             : 
    2098             :     case _tofu_GET_POLICY_ERROR:
    2099           0 :       trust_level = _tofu_GET_TRUST_ERROR;
    2100           0 :       goto out;
    2101             : 
    2102             :     default:
    2103           0 :       log_bug ("%s: Impossible value for policy (%d)\n", __func__, policy);
    2104             :     }
    2105             : 
    2106             : 
    2107             :   /* We get here if:
    2108             :    *
    2109             :    *   1. The saved policy is auto and the default policy is ask
    2110             :    *      (get_policy() == TOFU_POLICY_AUTO
    2111             :    *       && opt.tofu_default_policy == TOFU_POLICY_ASK)
    2112             :    *
    2113             :    *   2. The saved policy is ask (either last time the user selected
    2114             :    *      accept once or reject once or there was a conflict and this
    2115             :    *      binding's policy was changed from auto to ask)
    2116             :    *      (policy == TOFU_POLICY_ASK), or,
    2117             :    *
    2118             :    *   3. We don't have a saved policy (policy == TOFU_POLICY_NONE)
    2119             :    *      (need to check for a conflict).
    2120             :    *
    2121             :    * In summary: POLICY is ask or none.
    2122             :    */
    2123             : 
    2124             :   /* Look for conflicts.  This is needed in all 3 cases.  */
    2125           3 :   conflict_set = build_conflict_set (dbs, fingerprint, email);
    2126           3 :   conflict_set_count = strlist_length (conflict_set);
    2127           3 :   if (conflict_set_count == 0)
    2128             :     {
    2129             :       /* We should always at least have the current binding.  */
    2130           0 :       trust_level = _tofu_GET_TRUST_ERROR;
    2131           0 :       goto out;
    2132             :     }
    2133             : 
    2134           3 :   if (conflict_set_count == 1
    2135           1 :       && (conflict_set->flags & BINDING_NEW)
    2136           1 :       && opt.tofu_default_policy != TOFU_POLICY_ASK)
    2137             :     {
    2138             :       /* We've never observed a binding with this email address and we
    2139             :        * have a default policy, which is not to ask the user.  */
    2140             : 
    2141             :       /* If we've seen this binding, then we've seen this email and
    2142             :        * policy couldn't possibly be TOFU_POLICY_NONE.  */
    2143           1 :       log_assert (policy == TOFU_POLICY_NONE);
    2144             : 
    2145           1 :       if (DBG_TRUST)
    2146           0 :         log_debug ("TOFU: New binding <key: %s, user id: %s>, no conflict.\n",
    2147             :                    fingerprint, email);
    2148             : 
    2149           1 :       if (record_binding (dbs, fingerprint, email, user_id,
    2150             :                           TOFU_POLICY_AUTO, 0, now) != 0)
    2151             :         {
    2152           0 :           log_error (_("error setting TOFU binding's trust level to %s\n"),
    2153             :                        "auto");
    2154           0 :           trust_level = _tofu_GET_TRUST_ERROR;
    2155           0 :           goto out;
    2156             :         }
    2157             : 
    2158           1 :       trust_level = tofu_policy_to_trust_level (TOFU_POLICY_AUTO);
    2159           1 :       goto out;
    2160             :     }
    2161             : 
    2162           2 :   if (conflict_set_count == 1
    2163           0 :       && (conflict_set->flags & BINDING_CONFLICT))
    2164             :     {
    2165             :       /* No known conflicts now, but there was a conflict.  This means
    2166             :        * at somepoint, there was a conflict and we changed this
    2167             :        * binding's policy to ask and set the conflicting key.  The
    2168             :        * conflict can go away if there is not a cross sig between the
    2169             :        * two keys.  In this case, just silently clear the conflict and
    2170             :        * reset the policy to auto.  */
    2171             : 
    2172           0 :       log_assert (policy == TOFU_POLICY_ASK);
    2173             : 
    2174           0 :       if (DBG_TRUST)
    2175           0 :         log_debug ("TOFU: binding <key: %s, user id: %s> had a conflict, but it's been resolved (probably via  cross sig).\n",
    2176             :                    fingerprint, email);
    2177             : 
    2178           0 :       if (record_binding (dbs, fingerprint, email, user_id,
    2179             :                           TOFU_POLICY_AUTO, 0, now) != 0)
    2180           0 :         log_error (_("error setting TOFU binding's trust level to %s\n"),
    2181             :                    "auto");
    2182             : 
    2183           0 :       trust_level = tofu_policy_to_trust_level (TOFU_POLICY_AUTO);
    2184           0 :       goto out;
    2185             :     }
    2186             : 
    2187             :   /* We have a conflict.  Mark any conflicting bindings that have an
    2188             :    * automatic policy as now requiring confirmation.  Note: we delay
    2189             :    * this until after we ask for confirmation so that when the current
    2190             :    * policy is printed, it is correct.  */
    2191           2 :   change_conflicting_to_ask = 1;
    2192             : 
    2193           2 :   if (! may_ask)
    2194             :     {
    2195             :       /* We can only get here in the third case (no saved policy) and
    2196             :        * if there is a conflict.  (If the policy was ask (cases #1 and
    2197             :        * #2) and we weren't allowed to ask, we'd have already exited).  */
    2198           2 :       log_assert (policy == TOFU_POLICY_NONE);
    2199             : 
    2200           2 :       if (record_binding (dbs, fingerprint, email, user_id,
    2201             :                           TOFU_POLICY_ASK, 0, now) != 0)
    2202           0 :         log_error (_("error setting TOFU binding's trust level to %s\n"),
    2203             :                    "ask");
    2204             : 
    2205           2 :       trust_level = TRUST_UNDEFINED;
    2206           2 :       goto out;
    2207             :     }
    2208             : 
    2209             :   /* We can't be in a normal transaction in ask_about_binding.  */
    2210           0 :   end_transaction (ctrl, 0);
    2211           0 :   in_transaction = 0;
    2212             : 
    2213             :   /* If we get here, we need to ask the user about the binding.  */
    2214           0 :   ask_about_binding (ctrl,
    2215             :                      &policy,
    2216             :                      &trust_level,
    2217             :                      conflict_set,
    2218             :                      fingerprint,
    2219             :                      email,
    2220             :                      user_id,
    2221             :                      now);
    2222             : 
    2223             :  out:
    2224             : 
    2225          94 :   if (change_conflicting_to_ask)
    2226             :     {
    2227             :       /* Mark any conflicting bindings that have an automatic policy as
    2228             :        * now requiring confirmation.  */
    2229             : 
    2230           2 :       if (! in_transaction)
    2231             :         {
    2232           0 :           begin_transaction (ctrl, 0);
    2233           0 :           in_transaction = 1;
    2234             :         }
    2235             : 
    2236             :       /* If we weren't allowed to ask, also update this key as
    2237             :        * conflicting with itself.  */
    2238           9 :       for (iter = may_ask ? conflict_set->next : conflict_set;
    2239           5 :            iter; iter = iter->next)
    2240             :         {
    2241           5 :           rc = gpgsql_exec_printf
    2242             :             (dbs->db, NULL, NULL, &sqerr,
    2243             :              "update bindings set policy = %d, conflict = %Q"
    2244             :              " where email = %Q and fingerprint = %Q and policy = %d;",
    2245             :              TOFU_POLICY_ASK, fingerprint,
    2246           5 :              email, iter->d, TOFU_POLICY_AUTO);
    2247           5 :           if (rc)
    2248             :             {
    2249           0 :               log_error (_("error changing TOFU policy: %s\n"), sqerr);
    2250           0 :               print_further_info ("binding: <key: %s, user id: %s>",
    2251             :                                   fingerprint, user_id);
    2252           0 :               sqlite3_free (sqerr);
    2253           0 :               sqerr = NULL;
    2254             :             }
    2255           5 :           else if (DBG_TRUST)
    2256           0 :             log_debug ("Set %s to conflict with %s\n",
    2257           0 :                        iter->d, fingerprint);
    2258             :         }
    2259             :     }
    2260             : 
    2261          94 :   if (in_transaction)
    2262          94 :     end_transaction (ctrl, 0);
    2263             : 
    2264          94 :   free_strlist (conflict_set);
    2265             : 
    2266          94 :   return trust_level;
    2267             : }
    2268             : 
    2269             : 
    2270             : /* Return a malloced string of the form
    2271             :  *    "7 months, 1 day, 5 minutes, 0 seconds"
    2272             :  * The caller should replace all '~' in the returned string by a space
    2273             :  * and also free the returned string.
    2274             :  *
    2275             :  * This is actually a bad hack which may not work correctly with all
    2276             :  * languages.
    2277             :  */
    2278             : static char *
    2279           3 : time_ago_str (long long int t)
    2280             : {
    2281             :   estream_t fp;
    2282           3 :   int years = 0;
    2283           3 :   int months = 0;
    2284           3 :   int days = 0;
    2285           3 :   int hours = 0;
    2286           3 :   int minutes = 0;
    2287           3 :   int seconds = 0;
    2288             : 
    2289             :   /* The number of units that we've printed so far.  */
    2290           3 :   int count = 0;
    2291             :   /* The first unit that we printed (year = 0, month = 1,
    2292             :      etc.).  */
    2293           3 :   int first = -1;
    2294             :   /* The current unit.  */
    2295           3 :   int i = 0;
    2296             : 
    2297             :   char *str;
    2298             : 
    2299             :   /* It would be nice to use a macro to do this, but gettext
    2300             :      works on the unpreprocessed code.  */
    2301             : #define MIN_SECS (60)
    2302             : #define HOUR_SECS (60 * MIN_SECS)
    2303             : #define DAY_SECS (24 * HOUR_SECS)
    2304             : #define MONTH_SECS (30 * DAY_SECS)
    2305             : #define YEAR_SECS (365 * DAY_SECS)
    2306             : 
    2307           3 :   if (t > YEAR_SECS)
    2308             :     {
    2309           0 :       years = t / YEAR_SECS;
    2310           0 :       t -= years * YEAR_SECS;
    2311             :     }
    2312           3 :   if (t > MONTH_SECS)
    2313             :     {
    2314           0 :       months = t / MONTH_SECS;
    2315           0 :       t -= months * MONTH_SECS;
    2316             :     }
    2317           3 :   if (t > DAY_SECS)
    2318             :     {
    2319           0 :       days = t / DAY_SECS;
    2320           0 :       t -= days * DAY_SECS;
    2321             :     }
    2322           3 :   if (t > HOUR_SECS)
    2323             :     {
    2324           0 :       hours = t / HOUR_SECS;
    2325           0 :       t -= hours * HOUR_SECS;
    2326             :     }
    2327           3 :   if (t > MIN_SECS)
    2328             :     {
    2329           0 :       minutes = t / MIN_SECS;
    2330           0 :       t -= minutes * MIN_SECS;
    2331             :     }
    2332           3 :   seconds = t;
    2333             : 
    2334             : #undef MIN_SECS
    2335             : #undef HOUR_SECS
    2336             : #undef DAY_SECS
    2337             : #undef MONTH_SECS
    2338             : #undef YEAR_SECS
    2339             : 
    2340           3 :   fp = es_fopenmem (0, "rw,samethread");
    2341           3 :   if (! fp)
    2342           0 :     log_fatal ("error creating memory stream: %s\n",
    2343             :                gpg_strerror (gpg_error_from_syserror()));
    2344             : 
    2345           3 :   if (years)
    2346             :     {
    2347             :       /* TRANSLATORS: The tilde ('~') is used here to indicate a
    2348             :        * non-breakable space  */
    2349           0 :       es_fprintf (fp, ngettext("%d~year", "%d~years", years), years);
    2350           0 :       count ++;
    2351           0 :       first = i;
    2352             :     }
    2353           3 :   i ++;
    2354           3 :   if ((first == -1 || i - first <= 3) && count <= 0 && months)
    2355             :     {
    2356           0 :       if (count)
    2357           0 :         es_fprintf (fp, ", ");
    2358           0 :       es_fprintf (fp, ngettext("%d~month", "%d~months", months), months);
    2359           0 :       count ++;
    2360           0 :       first = i;
    2361             :     }
    2362           3 :   i ++;
    2363           3 :   if ((first == -1 || i - first <= 3) && count <= 0 && days)
    2364             :     {
    2365           0 :       if (count)
    2366           0 :         es_fprintf (fp, ", ");
    2367           0 :       es_fprintf (fp, ngettext("%d~day", "%d~days", days), days);
    2368           0 :       count ++;
    2369           0 :       first = i;
    2370             :     }
    2371           3 :   i ++;
    2372           3 :   if ((first == -1 || i - first <= 3) && count <= 0 && hours)
    2373             :     {
    2374           0 :       if (count)
    2375           0 :         es_fprintf (fp, ", ");
    2376           0 :       es_fprintf (fp, ngettext("%d~hour", "%d~hours", hours), hours);
    2377           0 :       count ++;
    2378           0 :       first = i;
    2379             :     }
    2380           3 :   i ++;
    2381           3 :   if ((first == -1 || i - first <= 3) && count <= 0 && minutes)
    2382             :     {
    2383           0 :       if (count)
    2384           0 :         es_fprintf (fp, ", ");
    2385           0 :       es_fprintf (fp, ngettext("%d~minute", "%d~minutes", minutes), minutes);
    2386           0 :       count ++;
    2387           0 :       first = i;
    2388             :     }
    2389           3 :   i ++;
    2390           3 :   if ((first == -1 || i - first <= 3) && count <= 0)
    2391             :     {
    2392           3 :       if (count)
    2393           0 :         es_fprintf (fp, ", ");
    2394           3 :       es_fprintf (fp, ngettext("%d~second", "%d~seconds", seconds), seconds);
    2395             :     }
    2396             : 
    2397           3 :   es_fputc (0, fp);
    2398           3 :   if (es_fclose_snatch (fp, (void **) &str, NULL))
    2399           0 :     log_fatal ("error snatching memory stream\n");
    2400             : 
    2401           3 :   return str;
    2402             : }
    2403             : 
    2404             : 
    2405             : /* If FP is NULL, write TOFU_STATS status line.  If FP is not NULL
    2406             :  * write a "tfs" record to that stream. */
    2407             : static void
    2408          25 : write_stats_status (estream_t fp,
    2409             :                     enum tofu_policy policy,
    2410             :                     unsigned long signature_count,
    2411             :                     unsigned long signature_first_seen,
    2412             :                     unsigned long signature_most_recent,
    2413             :                     unsigned long encryption_count,
    2414             :                     unsigned long encryption_first_done,
    2415             :                     unsigned long encryption_most_recent)
    2416             : {
    2417             :   const char *validity;
    2418             :   unsigned long messages;
    2419             : 
    2420             :   /* Use the euclidean distance rather then the sum of the magnitudes
    2421             :      to ensure a balance between verified signatures and encrypted
    2422             :      messages.  */
    2423          25 :   messages = sqrtu32 (signature_count) + sqrtu32 (encryption_count);
    2424             : 
    2425          25 :   if (messages < 1)
    2426           0 :     validity = "1"; /* Key without history.  */
    2427          25 :   else if (messages < sqrtu32 (2 * BASIC_TRUST_THRESHOLD))
    2428          25 :     validity = "2"; /* Key with too little history.  */
    2429           0 :   else if (messages < sqrtu32 (2 * FULL_TRUST_THRESHOLD))
    2430           0 :     validity = "3"; /* Key with enough history for basic trust.  */
    2431             :   else
    2432           0 :     validity = "4"; /* Key with a lot of history.  */
    2433             : 
    2434          25 :   if (fp)
    2435             :     {
    2436          22 :       es_fprintf (fp, "tfs:1:%s:%lu:%lu:%s:%lu:%lu:%lu:%lu:\n",
    2437             :                   validity, signature_count, encryption_count,
    2438             :                   tofu_policy_str (policy),
    2439             :                   signature_first_seen, signature_most_recent,
    2440             :                   encryption_first_done, encryption_most_recent);
    2441             :     }
    2442             :   else
    2443             :     {
    2444           3 :       write_status_printf (STATUS_TOFU_STATS,
    2445             :                            "%s %lu %lu %s %lu %lu %lu %lu",
    2446             :                            validity,
    2447             :                            signature_count,
    2448             :                            encryption_count,
    2449             :                            tofu_policy_str (policy),
    2450             :                            signature_first_seen,
    2451             :                            signature_most_recent,
    2452             :                            encryption_first_done,
    2453             :                            encryption_most_recent);
    2454             :     }
    2455          25 : }
    2456             : 
    2457             : /* Note: If OUTFP is not NULL, this function merely prints a "tfs" record
    2458             :  * to OUTFP.  In this case USER_ID is not required.
    2459             :  *
    2460             :  * Returns whether the caller should call show_warning after iterating
    2461             :  * over all user ids.
    2462             :  */
    2463             : static int
    2464          25 : show_statistics (tofu_dbs_t dbs, const char *fingerprint,
    2465             :                  const char *email, const char *user_id,
    2466             :                  estream_t outfp, time_t now)
    2467             : {
    2468          25 :   enum tofu_policy policy = get_policy (dbs, fingerprint, email, NULL);
    2469             : 
    2470             :   char *fingerprint_pp;
    2471             :   int rc;
    2472          25 :   strlist_t strlist = NULL;
    2473          25 :   char *err = NULL;
    2474             : 
    2475          25 :   unsigned long signature_first_seen = 0;
    2476          25 :   unsigned long signature_most_recent = 0;
    2477          25 :   unsigned long signature_count = 0;
    2478          25 :   unsigned long encryption_first_done = 0;
    2479          25 :   unsigned long encryption_most_recent = 0;
    2480          25 :   unsigned long encryption_count = 0;
    2481             : 
    2482          25 :   int show_warning = 0;
    2483             : 
    2484             :   (void) user_id;
    2485             : 
    2486          25 :   fingerprint_pp = format_hexfingerprint (fingerprint, NULL, 0);
    2487             : 
    2488             :   /* Get the signature stats.  */
    2489          25 :   rc = gpgsql_exec_printf
    2490             :     (dbs->db, strings_collect_cb, &strlist, &err,
    2491             :      "select count (*), min (signatures.time), max (signatures.time)\n"
    2492             :      " from signatures\n"
    2493             :      " left join bindings on signatures.binding = bindings.oid\n"
    2494             :      " where fingerprint = %Q and email = %Q;",
    2495             :      fingerprint, email);
    2496          25 :   if (rc)
    2497             :     {
    2498           0 :       log_error (_("error reading TOFU database: %s\n"), err);
    2499           0 :       print_further_info ("getting statistics");
    2500           0 :       sqlite3_free (err);
    2501           0 :       goto out;
    2502             :     }
    2503             : 
    2504          25 :   if (strlist)
    2505             :     {
    2506          25 :       log_assert (strlist->next);
    2507          25 :       log_assert (strlist->next->next);
    2508          25 :       log_assert (! strlist->next->next->next);
    2509             : 
    2510          25 :       string_to_ulong (&signature_count, strlist->d, -1, __LINE__);
    2511          25 :       string_to_ulong (&signature_first_seen, strlist->next->d, -1, __LINE__);
    2512          25 :       string_to_ulong (&signature_most_recent,
    2513          25 :                        strlist->next->next->d, -1, __LINE__);
    2514             : 
    2515          25 :       free_strlist (strlist);
    2516          25 :       strlist = NULL;
    2517             :     }
    2518             : 
    2519             :   /* Get the encryption stats.  */
    2520          25 :   rc = gpgsql_exec_printf
    2521             :     (dbs->db, strings_collect_cb, &strlist, &err,
    2522             :      "select count (*), min (encryptions.time), max (encryptions.time)\n"
    2523             :      " from encryptions\n"
    2524             :      " left join bindings on encryptions.binding = bindings.oid\n"
    2525             :      " where fingerprint = %Q and email = %Q;",
    2526             :      fingerprint, email);
    2527          25 :   if (rc)
    2528             :     {
    2529           0 :       log_error (_("error reading TOFU database: %s\n"), err);
    2530           0 :       print_further_info ("getting statistics");
    2531           0 :       sqlite3_free (err);
    2532           0 :       goto out;
    2533             :     }
    2534             : 
    2535          25 :   if (strlist)
    2536             :     {
    2537          25 :       log_assert (strlist->next);
    2538          25 :       log_assert (strlist->next->next);
    2539          25 :       log_assert (! strlist->next->next->next);
    2540             : 
    2541          25 :       string_to_ulong (&encryption_count, strlist->d, -1, __LINE__);
    2542          25 :       string_to_ulong (&encryption_first_done, strlist->next->d, -1, __LINE__);
    2543          25 :       string_to_ulong (&encryption_most_recent,
    2544          25 :                        strlist->next->next->d, -1, __LINE__);
    2545             : 
    2546          25 :       free_strlist (strlist);
    2547          25 :       strlist = NULL;
    2548             :     }
    2549             : 
    2550          25 :   if (!outfp)
    2551           3 :     write_status_text_and_buffer (STATUS_TOFU_USER, fingerprint,
    2552             :                                   email, strlen (email), 0);
    2553             : 
    2554          25 :   write_stats_status (outfp, policy,
    2555             :                       signature_count,
    2556             :                       signature_first_seen,
    2557             :                       signature_most_recent,
    2558             :                       encryption_count,
    2559             :                       encryption_first_done,
    2560             :                       encryption_most_recent);
    2561             : 
    2562          25 :   if (!outfp)
    2563             :     {
    2564             :       estream_t fp;
    2565             :       char *msg;
    2566             : 
    2567           3 :       fp = es_fopenmem (0, "rw,samethread");
    2568           3 :       if (! fp)
    2569           0 :         log_fatal ("error creating memory stream: %s\n",
    2570             :                    gpg_strerror (gpg_error_from_syserror()));
    2571             : 
    2572           3 :       es_fprintf (fp, _("%s: "), email);
    2573             : 
    2574           3 :       if (signature_count == 0)
    2575             :         {
    2576           0 :           es_fprintf (fp, _("Verified %ld signatures"), 0L);
    2577           0 :           es_fputc ('\n', fp);
    2578             :         }
    2579             :       else
    2580             :         {
    2581           3 :           char *first_seen_ago_str = time_ago_str (now - signature_first_seen);
    2582             : 
    2583             :           /* TRANSLATORS: The final %s is replaced by a string like
    2584             :              "7 months, 1 day, 5 minutes, 0 seconds". */
    2585           6 :           es_fprintf (fp,
    2586           3 :                       ngettext("Verified %ld signature in the past %s",
    2587             :                                "Verified %ld signatures in the past %s",
    2588             :                                signature_count),
    2589             :                       signature_count, first_seen_ago_str);
    2590             : 
    2591           3 :           xfree (first_seen_ago_str);
    2592             :         }
    2593             : 
    2594           3 :       if (encryption_count == 0)
    2595             :         {
    2596           3 :           es_fprintf (fp, _(", and encrypted %ld messages"), 0L);
    2597             :         }
    2598             :       else
    2599             :         {
    2600           0 :           char *first_done_ago_str = time_ago_str (now - encryption_first_done);
    2601             : 
    2602             :           /* TRANSLATORS: The final %s is replaced by a string like
    2603             :              "7 months, 1 day, 5 minutes, 0 seconds". */
    2604           0 :           es_fprintf (fp,
    2605           0 :                       ngettext(", and encrypted %ld message in the past %s",
    2606             :                                ", and encrypted %ld messages in the past %s",
    2607             :                                encryption_count),
    2608             :                       encryption_count, first_done_ago_str);
    2609             : 
    2610           0 :           xfree (first_done_ago_str);
    2611             :         }
    2612             : 
    2613           3 :       if (opt.verbose)
    2614             :         {
    2615           0 :           es_fputs ("  ", fp);
    2616           0 :           es_fputc ('(', fp);
    2617           0 :           es_fprintf (fp, _("policy: %s"), tofu_policy_str (policy));
    2618           0 :           es_fputs (").\n", fp);
    2619             :         }
    2620             :       else
    2621           3 :         es_fputs (".\n", fp);
    2622             : 
    2623             : 
    2624             :       {
    2625             :         char *tmpmsg, *p;
    2626           3 :         es_fputc (0, fp);
    2627           3 :         if (es_fclose_snatch (fp, (void **) &tmpmsg, NULL))
    2628           0 :           log_fatal ("error snatching memory stream\n");
    2629           3 :         msg = format_text (tmpmsg, 0, 72, 80);
    2630           3 :         es_free (tmpmsg);
    2631             : 
    2632             :         /* Print a status line but suppress the trailing LF.
    2633             :          * Spaces are not percent escaped. */
    2634           3 :         if (*msg)
    2635           3 :           write_status_buffer (STATUS_TOFU_STATS_LONG,
    2636           3 :                                msg, strlen (msg)-1, -1);
    2637             : 
    2638             :         /* Remove the non-breaking space markers.  */
    2639         276 :         for (p=msg; *p; p++)
    2640         273 :           if (*p == '~')
    2641           3 :             *p = ' ';
    2642             :       }
    2643             : 
    2644           3 :       log_string (GPGRT_LOG_INFO, msg);
    2645           3 :       xfree (msg);
    2646             : 
    2647           3 :       if (policy == TOFU_POLICY_AUTO)
    2648             :         {
    2649           1 :           if (signature_count == 0)
    2650           0 :             log_info (_("Warning: we have yet to see"
    2651             :                         " a message signed using this key and user id!\n"));
    2652           1 :           else if (signature_count == 1)
    2653           1 :             log_info (_("Warning: we've only seen one message"
    2654             :                         " signed using this key and user id!\n"));
    2655             : 
    2656           1 :           if (encryption_count == 0)
    2657           1 :             log_info (_("Warning: you have yet to encrypt"
    2658             :                         " a message to this key and user id!\n"));
    2659           0 :           else if (encryption_count == 1)
    2660           0 :             log_info (_("Warning: you have only encrypted"
    2661             :                         "  one message to this key and user id!\n"));
    2662             : 
    2663             :           /* Cf. write_stats_status  */
    2664           2 :           if (sqrtu32 (encryption_count) + sqrtu32 (signature_count)
    2665           1 :               < sqrtu32 (2 * BASIC_TRUST_THRESHOLD))
    2666           1 :             show_warning = 1;
    2667             :         }
    2668             :     }
    2669             : 
    2670             :  out:
    2671          25 :   xfree (fingerprint_pp);
    2672             : 
    2673          25 :   return show_warning;
    2674             : }
    2675             : 
    2676             : static void
    2677           1 : show_warning (const char *fingerprint, strlist_t user_id_list)
    2678             : {
    2679             :   char *set_policy_command;
    2680             :   char *text;
    2681             :   char *tmpmsg;
    2682             : 
    2683           1 :   set_policy_command =
    2684             :     xasprintf ("gpg --tofu-policy bad %s", fingerprint);
    2685             : 
    2686           1 :   tmpmsg = xasprintf
    2687           1 :     (ngettext
    2688             :      ("Warning: if you think you've seen more signatures "
    2689             :       "by this key and user id, then this key might be a "
    2690             :       "forgery!  Carefully examine the email address for small "
    2691             :       "variations.  If the key is suspect, then use\n"
    2692             :       "  %s\n"
    2693             :       "to mark it as being bad.\n",
    2694             :       "Warning: if you think you've seen more signatures "
    2695             :       "by this key and these user ids, then this key might be a "
    2696             :       "forgery!  Carefully examine the email addresses for small "
    2697             :       "variations.  If the key is suspect, then use\n"
    2698             :       "  %s\n"
    2699             :       "to mark it as being bad.\n",
    2700           1 :       strlist_length (user_id_list)),
    2701             :      set_policy_command);
    2702             : 
    2703           1 :   text = format_text (tmpmsg, 0, 72, 80);
    2704           1 :   xfree (tmpmsg);
    2705           1 :   log_string (GPGRT_LOG_INFO, text);
    2706           1 :   xfree (text);
    2707             : 
    2708           1 :   es_free (set_policy_command);
    2709           1 : }
    2710             : 
    2711             : 
    2712             : /* Extract the email address from a user id and normalize it.  If the
    2713             :    user id doesn't contain an email address, then we use the whole
    2714             :    user_id and normalize that.  The returned string must be freed.  */
    2715             : static char *
    2716         126 : email_from_user_id (const char *user_id)
    2717             : {
    2718         126 :   char *email = mailbox_from_userid (user_id);
    2719         126 :   if (! email)
    2720             :     {
    2721             :       /* Hmm, no email address was provided or we are out of core.  Just
    2722             :          take the lower-case version of the whole user id.  It could be
    2723             :          a hostname, for instance.  */
    2724         126 :       email = ascii_strlwr (xstrdup (user_id));
    2725             :     }
    2726             : 
    2727         126 :   return email;
    2728             : }
    2729             : 
    2730             : /* Register the signature with the bindings <fingerprint, USER_ID>,
    2731             :    for each USER_ID in USER_ID_LIST.  The fingerprint is taken from
    2732             :    the primary key packet PK.
    2733             : 
    2734             :    SIG_DIGEST_BIN is the binary representation of the message's
    2735             :    digest.  SIG_DIGEST_BIN_LEN is its length.
    2736             : 
    2737             :    SIG_TIME is the time that the signature was generated.
    2738             : 
    2739             :    ORIGIN is a free-formed string describing the origin of the
    2740             :    signature.  If this was from an email and the Claws MUA was used,
    2741             :    then this should be something like: "email:claws".  If this is
    2742             :    NULL, the default is simply "unknown".
    2743             : 
    2744             :    If MAY_ASK is 1, then this function may interact with the user.
    2745             :    This is necessary if there is a conflict or the binding's policy is
    2746             :    TOFU_POLICY_ASK.
    2747             : 
    2748             :    This function returns 0 on success and an error code if an error
    2749             :    occured.  */
    2750             : gpg_error_t
    2751           6 : tofu_register_signature (ctrl_t ctrl,
    2752             :                          PKT_public_key *pk, strlist_t user_id_list,
    2753             :                          const byte *sig_digest_bin, int sig_digest_bin_len,
    2754             :                          time_t sig_time, const char *origin)
    2755             : {
    2756           6 :   time_t now = gnupg_get_time ();
    2757             :   gpg_error_t rc;
    2758             :   tofu_dbs_t dbs;
    2759           6 :   char *fingerprint = NULL;
    2760             :   strlist_t user_id;
    2761           6 :   char *email = NULL;
    2762           6 :   char *err = NULL;
    2763             :   char *sig_digest;
    2764             :   unsigned long c;
    2765             : 
    2766           6 :   dbs = opendbs (ctrl);
    2767           6 :   if (! dbs)
    2768             :     {
    2769           0 :       rc = gpg_error (GPG_ERR_GENERAL);
    2770           0 :       log_error (_("error opening TOFU database: %s\n"),
    2771             :                  gpg_strerror (rc));
    2772           0 :       return rc;
    2773             :     }
    2774             : 
    2775             :   /* We do a query and then an insert.  Make sure they are atomic
    2776             :      by wrapping them in a transaction.  */
    2777           6 :   rc = begin_transaction (ctrl, 0);
    2778           6 :   if (rc)
    2779           0 :     return rc;
    2780             : 
    2781           6 :   log_assert (keyid_cmp (pk_keyid (pk), pk->main_keyid) == 0);
    2782             : 
    2783           6 :   sig_digest = make_radix64_string (sig_digest_bin, sig_digest_bin_len);
    2784           6 :   fingerprint = hexfingerprint (pk, NULL, 0);
    2785             : 
    2786           6 :   if (! origin)
    2787             :     /* The default origin is simply "unknown".  */
    2788           0 :     origin = "unknown";
    2789             : 
    2790          12 :   for (user_id = user_id_list; user_id; user_id = user_id->next)
    2791             :     {
    2792           6 :       email = email_from_user_id (user_id->d);
    2793             : 
    2794           6 :       if (DBG_TRUST)
    2795           0 :         log_debug ("TOFU: Registering signature %s with binding"
    2796             :                    " <key: %s, user id: %s>\n",
    2797             :                    sig_digest, fingerprint, email);
    2798             : 
    2799             :       /* Make sure the binding exists and record any TOFU
    2800             :          conflicts.  */
    2801           6 :       if (get_trust (ctrl, pk, fingerprint, email, user_id->d, 0, now)
    2802             :           == _tofu_GET_TRUST_ERROR)
    2803             :         {
    2804           0 :           rc = gpg_error (GPG_ERR_GENERAL);
    2805           0 :           xfree (email);
    2806           0 :           break;
    2807             :         }
    2808             : 
    2809             :       /* If we've already seen this signature before, then don't add
    2810             :          it again.  */
    2811           6 :       rc = gpgsql_stepx
    2812             :         (dbs->db, &dbs->s.register_already_seen,
    2813             :          get_single_unsigned_long_cb2, &c, &err,
    2814             :          "select count (*)\n"
    2815             :          " from signatures left join bindings\n"
    2816             :          "  on signatures.binding = bindings.oid\n"
    2817             :          " where fingerprint = ? and email = ? and sig_time = ?\n"
    2818             :          "  and sig_digest = ?",
    2819             :          GPGSQL_ARG_STRING, fingerprint, GPGSQL_ARG_STRING, email,
    2820             :          GPGSQL_ARG_LONG_LONG, (long long) sig_time,
    2821             :          GPGSQL_ARG_STRING, sig_digest,
    2822             :          GPGSQL_ARG_END);
    2823           6 :       if (rc)
    2824             :         {
    2825           0 :           log_error (_("error reading TOFU database: %s\n"), err);
    2826           0 :           print_further_info ("checking existence");
    2827           0 :           sqlite3_free (err);
    2828             :         }
    2829           6 :       else if (c > 1)
    2830             :         /* Duplicates!  This should not happen.  In particular,
    2831             :            because <fingerprint, email, sig_time, sig_digest> is the
    2832             :            primary key!  */
    2833           0 :         log_debug ("SIGNATURES DB contains duplicate records"
    2834             :                    " <key: %s, fingerprint: %s, time: 0x%lx, sig: %s,"
    2835             :                    " origin: %s>."
    2836             :                    "  Please report.\n",
    2837             :                    fingerprint, email, (unsigned long) sig_time,
    2838             :                    sig_digest, origin);
    2839           6 :       else if (c == 1)
    2840             :         {
    2841           3 :           if (DBG_TRUST)
    2842           0 :             log_debug ("Already observed the signature and binding"
    2843             :                        " <key: %s, user id: %s, time: 0x%lx, sig: %s,"
    2844             :                        " origin: %s>\n",
    2845             :                        fingerprint, email, (unsigned long) sig_time,
    2846             :                        sig_digest, origin);
    2847             :         }
    2848           3 :       else if (opt.dry_run)
    2849             :         {
    2850           0 :           log_info ("TOFU database update skipped due to --dry-run\n");
    2851             :         }
    2852             :       else
    2853             :         /* This is the first time that we've seen this signature and
    2854             :            binding.  Record it.  */
    2855             :         {
    2856           3 :           if (DBG_TRUST)
    2857           0 :             log_debug ("TOFU: Saving signature"
    2858             :                        " <key: %s, user id: %s, sig: %s>\n",
    2859             :                        fingerprint, email, sig_digest);
    2860             : 
    2861           3 :           log_assert (c == 0);
    2862             : 
    2863           3 :           rc = gpgsql_stepx
    2864             :             (dbs->db, &dbs->s.register_insert, NULL, NULL, &err,
    2865             :              "insert into signatures\n"
    2866             :              " (binding, sig_digest, origin, sig_time, time)\n"
    2867             :              " values\n"
    2868             :              " ((select oid from bindings\n"
    2869             :              "    where fingerprint = ? and email = ?),\n"
    2870             :              "  ?, ?, ?, ?);",
    2871             :              GPGSQL_ARG_STRING, fingerprint, GPGSQL_ARG_STRING, email,
    2872             :              GPGSQL_ARG_STRING, sig_digest, GPGSQL_ARG_STRING, origin,
    2873             :              GPGSQL_ARG_LONG_LONG, (long long) sig_time,
    2874             :              GPGSQL_ARG_LONG_LONG, (long long) now,
    2875             :              GPGSQL_ARG_END);
    2876           3 :           if (rc)
    2877             :             {
    2878           0 :               log_error (_("error updating TOFU database: %s\n"), err);
    2879           0 :               print_further_info ("insert signatures");
    2880           0 :               sqlite3_free (err);
    2881             :             }
    2882             :         }
    2883             : 
    2884           6 :       xfree (email);
    2885             : 
    2886           6 :       if (rc)
    2887           0 :         break;
    2888             :     }
    2889             : 
    2890           6 :   if (rc)
    2891           0 :     rollback_transaction (ctrl);
    2892             :   else
    2893           6 :     rc = end_transaction (ctrl, 0);
    2894             : 
    2895           6 :   xfree (fingerprint);
    2896           6 :   xfree (sig_digest);
    2897             : 
    2898           6 :   return rc;
    2899             : }
    2900             : 
    2901             : gpg_error_t
    2902           0 : tofu_register_encryption (ctrl_t ctrl,
    2903             :                           PKT_public_key *pk, strlist_t user_id_list,
    2904             :                           int may_ask)
    2905             : {
    2906           0 :   time_t now = gnupg_get_time ();
    2907           0 :   gpg_error_t rc = 0;
    2908             :   tofu_dbs_t dbs;
    2909           0 :   kbnode_t kb = NULL;
    2910           0 :   int free_user_id_list = 0;
    2911           0 :   char *fingerprint = NULL;
    2912             :   strlist_t user_id;
    2913           0 :   char *err = NULL;
    2914             : 
    2915           0 :   dbs = opendbs (ctrl);
    2916           0 :   if (! dbs)
    2917             :     {
    2918           0 :       rc = gpg_error (GPG_ERR_GENERAL);
    2919           0 :       log_error (_("error opening TOFU database: %s\n"),
    2920             :                  gpg_strerror (rc));
    2921           0 :       return rc;
    2922             :     }
    2923             : 
    2924             :   /* Make sure PK is a primary key.  */
    2925           0 :   if (keyid_cmp (pk_keyid (pk), pk->main_keyid) != 0
    2926           0 :       || user_id_list)
    2927           0 :     kb = get_pubkeyblock (pk->keyid);
    2928             : 
    2929           0 :   if (keyid_cmp (pk_keyid (pk), pk->main_keyid) != 0)
    2930           0 :     pk = kb->pkt->pkt.public_key;
    2931             : 
    2932           0 :   if (! user_id_list)
    2933             :     {
    2934             :       /* Use all non-revoked user ids.  Do use expired user ids.  */
    2935           0 :       kbnode_t n = kb;
    2936             : 
    2937           0 :       while ((n = find_next_kbnode (n, PKT_USER_ID)))
    2938             :         {
    2939           0 :           PKT_user_id *uid = n->pkt->pkt.user_id;
    2940             : 
    2941           0 :           if (uid->is_revoked)
    2942           0 :             continue;
    2943             : 
    2944           0 :           add_to_strlist (&user_id_list, uid->name);
    2945             :         }
    2946             : 
    2947           0 :       free_user_id_list = 1;
    2948             : 
    2949           0 :       if (! user_id_list)
    2950           0 :         log_info ("WARNING: Encrypting to %s, which has no"
    2951             :                   "non-revoked user ids.\n",
    2952           0 :                   keystr (pk->keyid));
    2953             :     }
    2954             : 
    2955           0 :   fingerprint = hexfingerprint (pk, NULL, 0);
    2956             : 
    2957           0 :   tofu_begin_batch_update (ctrl);
    2958           0 :   tofu_resume_batch_transaction (ctrl);
    2959             : 
    2960           0 :   for (user_id = user_id_list; user_id; user_id = user_id->next)
    2961             :     {
    2962           0 :       char *email = email_from_user_id (user_id->d);
    2963             : 
    2964             :       /* Make sure the binding exists and that we recognize any
    2965             :          conflicts.  */
    2966           0 :       int tl = get_trust (ctrl, pk, fingerprint, email, user_id->d,
    2967             :                           may_ask, now);
    2968           0 :       if (tl == _tofu_GET_TRUST_ERROR)
    2969             :         {
    2970             :           /* An error.  */
    2971           0 :           xfree (email);
    2972           0 :           goto die;
    2973             :         }
    2974             : 
    2975           0 :       rc = gpgsql_stepx
    2976             :         (dbs->db, &dbs->s.register_insert, NULL, NULL, &err,
    2977             :          "insert into encryptions\n"
    2978             :          " (binding, time)\n"
    2979             :          " values\n"
    2980             :          " ((select oid from bindings\n"
    2981             :          "    where fingerprint = ? and email = ?),\n"
    2982             :          "  ?);",
    2983             :          GPGSQL_ARG_STRING, fingerprint, GPGSQL_ARG_STRING, email,
    2984             :          GPGSQL_ARG_LONG_LONG, (long long) now,
    2985             :          GPGSQL_ARG_END);
    2986           0 :       if (rc)
    2987             :         {
    2988           0 :           log_error (_("error updating TOFU database: %s\n"), err);
    2989           0 :           print_further_info ("insert encryption");
    2990           0 :           sqlite3_free (err);
    2991             :         }
    2992             : 
    2993           0 :       xfree (email);
    2994             :     }
    2995             : 
    2996             :  die:
    2997           0 :   tofu_end_batch_update (ctrl);
    2998             : 
    2999           0 :   if (kb)
    3000           0 :     release_kbnode (kb);
    3001             : 
    3002           0 :   if (free_user_id_list)
    3003           0 :     free_strlist (user_id_list);
    3004             : 
    3005           0 :   xfree (fingerprint);
    3006             : 
    3007           0 :   return rc;
    3008             : }
    3009             : 
    3010             : 
    3011             : /* Combine a trust level returned from the TOFU trust model with a
    3012             :    trust level returned by the PGP trust model.  This is primarily of
    3013             :    interest when the trust model is tofu+pgp (TM_TOFU_PGP).
    3014             : 
    3015             :    This function ors together the upper bits (the values not covered
    3016             :    by TRUST_MASK, i.e., TRUST_FLAG_REVOKED, etc.).  */
    3017             : int
    3018         191 : tofu_wot_trust_combine (int tofu_base, int wot_base)
    3019             : {
    3020         191 :   int tofu = tofu_base & TRUST_MASK;
    3021         191 :   int wot = wot_base & TRUST_MASK;
    3022         191 :   int upper = (tofu_base & ~TRUST_MASK) | (wot_base & ~TRUST_MASK);
    3023             : 
    3024         191 :   log_assert (tofu == TRUST_UNKNOWN
    3025             :               || tofu == TRUST_EXPIRED
    3026             :               || tofu == TRUST_UNDEFINED
    3027             :               || tofu == TRUST_NEVER
    3028             :               || tofu == TRUST_MARGINAL
    3029             :               || tofu == TRUST_FULLY
    3030             :               || tofu == TRUST_ULTIMATE);
    3031         191 :   log_assert (wot == TRUST_UNKNOWN
    3032             :               || wot == TRUST_EXPIRED
    3033             :               || wot == TRUST_UNDEFINED
    3034             :               || wot == TRUST_NEVER
    3035             :               || wot == TRUST_MARGINAL
    3036             :               || wot == TRUST_FULLY
    3037             :               || wot == TRUST_ULTIMATE);
    3038             : 
    3039             :   /* We first consider negative trust policys.  These trump positive
    3040             :      trust policies.  */
    3041         191 :   if (tofu == TRUST_NEVER || wot == TRUST_NEVER)
    3042             :     /* TRUST_NEVER trumps everything else.  */
    3043          26 :     return upper | TRUST_NEVER;
    3044         165 :   if (tofu == TRUST_EXPIRED || wot == TRUST_EXPIRED)
    3045             :     /* TRUST_EXPIRED trumps everything but TRUST_NEVER.  */
    3046           0 :     return upper | TRUST_EXPIRED;
    3047             : 
    3048             :   /* Now we only have positive or neutral trust policies.  We take
    3049             :      the max.  */
    3050         165 :   if (tofu == TRUST_ULTIMATE)
    3051           0 :     return upper | TRUST_ULTIMATE | TRUST_FLAG_TOFU_BASED;
    3052         165 :   if (wot == TRUST_ULTIMATE)
    3053           0 :     return upper | TRUST_ULTIMATE;
    3054             : 
    3055         165 :   if (tofu == TRUST_FULLY)
    3056          22 :     return upper | TRUST_FULLY | TRUST_FLAG_TOFU_BASED;
    3057         143 :   if (wot == TRUST_FULLY)
    3058           0 :     return upper | TRUST_FULLY;
    3059             : 
    3060         143 :   if (tofu == TRUST_MARGINAL)
    3061           8 :     return upper | TRUST_MARGINAL | TRUST_FLAG_TOFU_BASED;
    3062         135 :   if (wot == TRUST_MARGINAL)
    3063           0 :     return upper | TRUST_MARGINAL;
    3064             : 
    3065         135 :   if (tofu == TRUST_UNDEFINED)
    3066          10 :     return upper | TRUST_UNDEFINED | TRUST_FLAG_TOFU_BASED;
    3067         125 :   if (wot == TRUST_UNDEFINED)
    3068           0 :     return upper | TRUST_UNDEFINED;
    3069             : 
    3070         125 :   return upper | TRUST_UNKNOWN;
    3071             : }
    3072             : 
    3073             : 
    3074             : /* Write a "tfs" record for a --with-colons listing.  */
    3075             : gpg_error_t
    3076          22 : tofu_write_tfs_record (ctrl_t ctrl, estream_t fp,
    3077             :                        PKT_public_key *pk, const char *user_id)
    3078             : {
    3079          22 :   time_t now = gnupg_get_time ();
    3080             :   gpg_error_t err;
    3081             :   tofu_dbs_t dbs;
    3082             :   char *fingerprint;
    3083             :   char *email;
    3084             : 
    3085          22 :   if (!*user_id)
    3086           0 :     return 0;  /* No TOFU stats possible for an empty ID.  */
    3087             : 
    3088          22 :   dbs = opendbs (ctrl);
    3089          22 :   if (!dbs)
    3090             :     {
    3091           0 :       err = gpg_error (GPG_ERR_GENERAL);
    3092           0 :       log_error (_("error opening TOFU database: %s\n"), gpg_strerror (err));
    3093           0 :       return err;
    3094             :     }
    3095             : 
    3096          22 :   fingerprint = hexfingerprint (pk, NULL, 0);
    3097          22 :   email = email_from_user_id (user_id);
    3098             : 
    3099          22 :   show_statistics (dbs, fingerprint, email, user_id, fp, now);
    3100             : 
    3101          22 :   xfree (email);
    3102          22 :   xfree (fingerprint);
    3103          22 :   return 0;
    3104             : }
    3105             : 
    3106             : 
    3107             : /* Return the validity (TRUST_NEVER, etc.) of the bindings
    3108             :    <FINGERPRINT, USER_ID>, for each USER_ID in USER_ID_LIST.  If
    3109             :    USER_ID_LIST->FLAG is set, then the id is considered to be expired.
    3110             : 
    3111             :    PK is the primary key packet.
    3112             : 
    3113             :    If MAY_ASK is 1 and the policy is TOFU_POLICY_ASK, then the user
    3114             :    will be prompted to choose a policy.  If MAY_ASK is 0 and the
    3115             :    policy is TOFU_POLICY_ASK, then TRUST_UNKNOWN is returned.
    3116             : 
    3117             :    Returns TRUST_UNDEFINED if an error occurs.  */
    3118             : int
    3119          88 : tofu_get_validity (ctrl_t ctrl, PKT_public_key *pk, strlist_t user_id_list,
    3120             :                    int may_ask)
    3121             : {
    3122          88 :   time_t now = gnupg_get_time ();
    3123             :   tofu_dbs_t dbs;
    3124          88 :   char *fingerprint = NULL;
    3125             :   strlist_t user_id;
    3126          88 :   int trust_level = TRUST_UNKNOWN;
    3127          88 :   int bindings = 0;
    3128          88 :   int bindings_valid = 0;
    3129          88 :   int need_warning = 0;
    3130             : 
    3131          88 :   dbs = opendbs (ctrl);
    3132          88 :   if (! dbs)
    3133             :     {
    3134           0 :       log_error (_("error opening TOFU database: %s\n"),
    3135             :                  gpg_strerror (GPG_ERR_GENERAL));
    3136           0 :       return TRUST_UNDEFINED;
    3137             :     }
    3138             : 
    3139          88 :   fingerprint = hexfingerprint (pk, NULL, 0);
    3140             : 
    3141          88 :   tofu_begin_batch_update (ctrl);
    3142          88 :   tofu_resume_batch_transaction (ctrl);
    3143             : 
    3144         176 :   for (user_id = user_id_list; user_id; user_id = user_id->next, bindings ++)
    3145             :     {
    3146          88 :       char *email = email_from_user_id (user_id->d);
    3147             : 
    3148             :       /* Always call get_trust to make sure the binding is
    3149             :          registered.  */
    3150          88 :       int tl = get_trust (ctrl, pk, fingerprint, email, user_id->d,
    3151             :                           may_ask, now);
    3152          88 :       if (tl == _tofu_GET_TRUST_ERROR)
    3153             :         {
    3154             :           /* An error.  */
    3155           0 :           trust_level = TRUST_UNDEFINED;
    3156           0 :           xfree (email);
    3157           0 :           goto die;
    3158             :         }
    3159             : 
    3160          88 :       if (DBG_TRUST)
    3161           0 :         log_debug ("TOFU: validity for <key: %s, user id: %s>: %s%s.\n",
    3162             :                    fingerprint, email,
    3163             :                    trust_value_to_string (tl),
    3164           0 :                    user_id->flags ? " (but expired)" : "");
    3165             : 
    3166          88 :       if (user_id->flags)
    3167           0 :         tl = TRUST_EXPIRED;
    3168             : 
    3169          88 :       if (tl != TRUST_EXPIRED)
    3170          88 :         bindings_valid ++;
    3171             : 
    3172          88 :       if (may_ask && tl != TRUST_ULTIMATE && tl != TRUST_EXPIRED)
    3173           3 :         need_warning |=
    3174           3 :           show_statistics (dbs, fingerprint, email, user_id->d, NULL, now);
    3175             : 
    3176          88 :       if (tl == TRUST_NEVER)
    3177          26 :         trust_level = TRUST_NEVER;
    3178          62 :       else if (tl == TRUST_EXPIRED)
    3179             :         /* Ignore expired bindings in the trust calculation.  */
    3180             :         ;
    3181          62 :       else if (tl > trust_level)
    3182             :         {
    3183             :           /* The expected values: */
    3184          40 :           log_assert (tl == TRUST_UNKNOWN || tl == TRUST_UNDEFINED
    3185             :                       || tl == TRUST_MARGINAL || tl == TRUST_FULLY
    3186             :                       || tl == TRUST_ULTIMATE);
    3187             : 
    3188             :           /* We assume the following ordering:  */
    3189             :           log_assert (TRUST_UNKNOWN < TRUST_UNDEFINED);
    3190             :           log_assert (TRUST_UNDEFINED < TRUST_MARGINAL);
    3191             :           log_assert (TRUST_MARGINAL < TRUST_FULLY);
    3192             :           log_assert (TRUST_FULLY < TRUST_ULTIMATE);
    3193             : 
    3194          40 :           trust_level = tl;
    3195             :         }
    3196             : 
    3197          88 :       xfree (email);
    3198             :     }
    3199             : 
    3200          88 :   if (need_warning)
    3201           1 :     show_warning (fingerprint, user_id_list);
    3202             : 
    3203             :  die:
    3204          88 :   tofu_end_batch_update (ctrl);
    3205             : 
    3206          88 :   xfree (fingerprint);
    3207             : 
    3208          88 :   if (bindings_valid == 0)
    3209             :     {
    3210           0 :       if (DBG_TRUST)
    3211           0 :         log_debug ("no (of %d) valid bindings."
    3212             :                    "  Can't get TOFU validity for this set of user ids.\n",
    3213             :                    bindings);
    3214           0 :       return TRUST_NEVER;
    3215             :     }
    3216             : 
    3217          88 :   return trust_level;
    3218             : }
    3219             : 
    3220             : /* Set the policy for all non-revoked user ids in the keyblock KB to
    3221             :    POLICY.
    3222             : 
    3223             :    If no key is available with the specified key id, then this
    3224             :    function returns GPG_ERR_NO_PUBKEY.
    3225             : 
    3226             :    Returns 0 on success and an error code otherwise.  */
    3227             : gpg_error_t
    3228           4 : tofu_set_policy (ctrl_t ctrl, kbnode_t kb, enum tofu_policy policy)
    3229             : {
    3230           4 :   time_t now = gnupg_get_time ();
    3231             :   tofu_dbs_t dbs;
    3232             :   PKT_public_key *pk;
    3233           4 :   char *fingerprint = NULL;
    3234             : 
    3235           4 :   log_assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
    3236           4 :   pk = kb->pkt->pkt.public_key;
    3237             : 
    3238           4 :   dbs = opendbs (ctrl);
    3239           4 :   if (! dbs)
    3240             :     {
    3241           0 :       log_error (_("error opening TOFU database: %s\n"),
    3242             :                  gpg_strerror (GPG_ERR_GENERAL));
    3243           0 :       return gpg_error (GPG_ERR_GENERAL);
    3244             :     }
    3245             : 
    3246           4 :   if (DBG_TRUST)
    3247           0 :     log_debug ("Setting TOFU policy for %s to %s\n",
    3248           0 :                keystr (pk->keyid), tofu_policy_str (policy));
    3249           8 :   if (! (pk->main_keyid[0] == pk->keyid[0]
    3250           4 :          && pk->main_keyid[1] == pk->keyid[1]))
    3251           0 :     log_bug ("%s: Passed a subkey, but expecting a primary key.\n", __func__);
    3252             : 
    3253           4 :   fingerprint = hexfingerprint (pk, NULL, 0);
    3254             : 
    3255           4 :   begin_transaction (ctrl, 0);
    3256             : 
    3257          24 :   for (; kb; kb = kb->next)
    3258             :     {
    3259             :       PKT_user_id *user_id;
    3260             :       char *email;
    3261             : 
    3262          20 :       if (kb->pkt->pkttype != PKT_USER_ID)
    3263          16 :         continue;
    3264             : 
    3265           4 :       user_id = kb->pkt->pkt.user_id;
    3266           4 :       if (user_id->is_revoked)
    3267             :         /* Skip revoked user ids.  (Don't skip expired user ids, the
    3268             :            expiry can be changed.)  */
    3269           0 :         continue;
    3270             : 
    3271           4 :       email = email_from_user_id (user_id->name);
    3272             : 
    3273           4 :       record_binding (dbs, fingerprint, email, user_id->name, policy, 1, now);
    3274             : 
    3275           4 :       xfree (email);
    3276             :     }
    3277             : 
    3278           4 :   end_transaction (ctrl, 0);
    3279             : 
    3280           4 :   xfree (fingerprint);
    3281           4 :   return 0;
    3282             : }
    3283             : 
    3284             : /* Set the TOFU policy for all non-revoked user ids in the KEY with
    3285             :    the key id KEYID to POLICY.
    3286             : 
    3287             :    If no key is available with the specified key id, then this
    3288             :    function returns GPG_ERR_NO_PUBKEY.
    3289             : 
    3290             :    Returns 0 on success and an error code otherwise.  */
    3291             : gpg_error_t
    3292           0 : tofu_set_policy_by_keyid (ctrl_t ctrl, u32 *keyid, enum tofu_policy policy)
    3293             : {
    3294           0 :   kbnode_t keyblock = get_pubkeyblock (keyid);
    3295           0 :   if (! keyblock)
    3296           0 :     return gpg_error (GPG_ERR_NO_PUBKEY);
    3297             : 
    3298           0 :   return tofu_set_policy (ctrl, keyblock, policy);
    3299             : }
    3300             : 
    3301             : /* Return the TOFU policy for the specified binding in *POLICY.  If no
    3302             :    policy has been set for the binding, sets *POLICY to
    3303             :    TOFU_POLICY_NONE.
    3304             : 
    3305             :    PK is a primary public key and USER_ID is a user id.
    3306             : 
    3307             :    Returns 0 on success and an error code otherwise.  */
    3308             : gpg_error_t
    3309           0 : tofu_get_policy (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *user_id,
    3310             :                  enum tofu_policy *policy)
    3311             : {
    3312             :   tofu_dbs_t dbs;
    3313             :   char *fingerprint;
    3314             :   char *email;
    3315             : 
    3316             :   /* Make sure PK is a primary key.  */
    3317           0 :   log_assert (pk->main_keyid[0] == pk->keyid[0]
    3318             :               && pk->main_keyid[1] == pk->keyid[1]);
    3319             : 
    3320           0 :   dbs = opendbs (ctrl);
    3321           0 :   if (! dbs)
    3322             :     {
    3323           0 :       log_error (_("error opening TOFU database: %s\n"),
    3324             :                  gpg_strerror (GPG_ERR_GENERAL));
    3325           0 :       return gpg_error (GPG_ERR_GENERAL);
    3326             :     }
    3327             : 
    3328           0 :   fingerprint = hexfingerprint (pk, NULL, 0);
    3329             : 
    3330           0 :   email = email_from_user_id (user_id->name);
    3331             : 
    3332           0 :   *policy = get_policy (dbs, fingerprint, email, NULL);
    3333             : 
    3334           0 :   xfree (email);
    3335           0 :   xfree (fingerprint);
    3336           0 :   if (*policy == _tofu_GET_POLICY_ERROR)
    3337           0 :     return gpg_error (GPG_ERR_GENERAL);
    3338           0 :   return 0;
    3339             : }

Generated by: LCOV version 1.11