g10: Fix testing for debug flag.
[gnupg.git] / g10 / pkclist.c
index c865660..823d670 100644 (file)
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <assert.h>
 
 #include "gpg.h"
 #include "options.h"
@@ -179,7 +178,7 @@ show_revocation_reason( PKT_public_key *pk, int mode )
  */
 #ifndef NO_TRUST_MODELS
 static int
-do_edit_ownertrust (PKT_public_key *pk, int mode,
+do_edit_ownertrust (ctrl_t ctrl, PKT_public_key *pk, int mode,
                     unsigned *new_trust, int defer_help )
 {
   char *p;
@@ -190,7 +189,6 @@ do_edit_ownertrust (PKT_public_key *pk, int mode,
   int min_num;
   int did_help=defer_help;
   unsigned int minimum = tdb_get_min_ownertrust (pk);
-  char pkstrbuf[PUBKEY_STRING_SIZE];
 
   switch(minimum)
     {
@@ -223,13 +221,12 @@ do_edit_ownertrust (PKT_public_key *pk, int mode,
           {
             KBNODE keyblock, un;
 
-            tty_printf(_("No trust value assigned to:\n"));
-           tty_printf("%s/%s %s\n",
-                       pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
-                       keystr(keyid), datestr_from_pk( pk ) );
-           p=get_user_id_native(keyid);
-           tty_printf(_("      \"%s\"\n"),p);
-           xfree(p);
+            tty_printf (_("No trust value assigned to:\n"));
+            print_key_line (NULL, pk, 0);
+
+           p = get_user_id_native(keyid);
+           tty_printf (_("      \"%s\"\n"),p);
+           xfree (p);
 
             keyblock = get_pubkeyblock (keyid);
             if (!keyblock)
@@ -249,7 +246,8 @@ do_edit_ownertrust (PKT_public_key *pk, int mode,
 
                if((opt.verify_options&VERIFY_SHOW_PHOTOS)
                   && un->pkt->pkt.user_id->attrib_data)
-                 show_photos (un->pkt->pkt.user_id->attribs,
+                 show_photos (ctrl,
+                               un->pkt->pkt.user_id->attribs,
                                un->pkt->pkt.user_id->numattribs, pk,
                                un->pkt->pkt.user_id);
 
@@ -377,14 +375,14 @@ do_edit_ownertrust (PKT_public_key *pk, int mode,
  */
 #ifndef NO_TRUST_MODELS
 int
-edit_ownertrust (PKT_public_key *pk, int mode )
+edit_ownertrust (ctrl_t ctrl, PKT_public_key *pk, int mode )
 {
   unsigned int trust = 0;
   int no_help = 0;
 
   for(;;)
     {
-      switch ( do_edit_ownertrust (pk, mode, &trust, no_help ) )
+      switch ( do_edit_ownertrust (ctrl, pk, mode, &trust, no_help ) )
         {
         case -1: /* quit */
           return -1;
@@ -430,7 +428,7 @@ do_we_trust( PKT_public_key *pk, unsigned int trustlevel )
     default:
       log_error ("invalid trustlevel %u returned from validation layer\n",
                 trustlevel);
-      /* fall thru */
+      /* fall through */
     case TRUST_UNKNOWN:
     case TRUST_UNDEFINED:
       log_info(_("%s: There is no assurance this key belongs"
@@ -451,6 +449,13 @@ do_we_trust( PKT_public_key *pk, unsigned int trustlevel )
       if( opt.verbose )
        log_info(_("This key belongs to us\n"));
       return 1; /* yes */
+
+    case TRUST_NEVER:
+      /* This is retruned can be returned by TOFU, which can return
+         negative assertions.  */
+      log_info(_("%s: This key is bad!  It has been marked as untrusted!\n"),
+               keystr_from_pk(pk));
+      return 0; /* no */
     }
 
   return 1; /*NOTREACHED*/
@@ -474,10 +479,16 @@ do_we_trust_pre( PKT_public_key *pk, unsigned int trustlevel )
       print_fingerprint (NULL, pk, 2);
       tty_printf("\n");
 
-      tty_printf(
-              _("It is NOT certain that the key belongs to the person named\n"
-                "in the user ID.  If you *really* know what you are doing,\n"
-                "you may answer the next question with yes.\n"));
+      if ((trustlevel & TRUST_MASK) == TRUST_NEVER)
+        tty_printf(
+          _("This key has is bad!  It has been marked as untrusted!  If you\n"
+            "*really* know what you are doing, you may answer the next\n"
+            "question with yes.\n"));
+      else
+        tty_printf(
+          _("It is NOT certain that the key belongs to the person named\n"
+            "in the user ID.  If you *really* know what you are doing,\n"
+            "you may answer the next question with yes.\n"));
 
       tty_printf("\n");
 
@@ -506,12 +517,32 @@ do_we_trust_pre( PKT_public_key *pk, unsigned int trustlevel )
 }
 
 
+/* Write a TRUST_foo status line inclduing the validation model.  */
+static void
+write_trust_status (int statuscode, int trustlevel)
+{
+#ifdef NO_TRUST_MODELS
+  write_status (statuscode);
+#else /* NO_TRUST_MODELS */
+  int tm;
+
+  /* For the combined tofu+pgp method, we return the trust model which
+   * was responsible for the trustlevel.  */
+  if (opt.trust_model == TM_TOFU_PGP)
+    tm = (trustlevel & TRUST_FLAG_TOFU_BASED)? TM_TOFU : TM_PGP;
+  else
+    tm = opt.trust_model;
+  write_status_strings (statuscode, "0 ", trust_model_string (tm), NULL);
+#endif /* NO_TRUST_MODELS */
+}
+
+
 /****************
  * Check whether we can trust this signature.
  * Returns an error code if we should not trust this signature.
  */
 int
-check_signatures_trust( PKT_signature *sig )
+check_signatures_trust (ctrl_t ctrl, PKT_signature *sig)
 {
   PKT_public_key *pk = xmalloc_clear( sizeof *pk );
   unsigned int trustlevel = TRUST_UNKNOWN;
@@ -538,7 +569,7 @@ check_signatures_trust( PKT_signature *sig )
     log_info(_("WARNING: this key might be revoked (revocation key"
               " not present)\n"));
 
-  trustlevel = get_validity (pk, NULL, sig, 1);
+  trustlevel = get_validity (ctrl, pk, NULL, sig, 1);
 
   if ( (trustlevel & TRUST_FLAG_REVOKED) )
     {
@@ -624,10 +655,10 @@ check_signatures_trust( PKT_signature *sig )
     default:
       log_error ("invalid trustlevel %u returned from validation layer\n",
                  trustlevel);
-      /* fall thru */
+      /* fall through */
     case TRUST_UNKNOWN:
     case TRUST_UNDEFINED:
-      write_status( STATUS_TRUST_UNDEFINED );
+      write_trust_status (STATUS_TRUST_UNDEFINED, trustlevel);
       log_info(_("WARNING: This key is not certified with"
                  " a trusted signature!\n"));
       log_info(_("         There is no indication that the "
@@ -636,8 +667,9 @@ check_signatures_trust( PKT_signature *sig )
       break;
 
     case TRUST_NEVER:
-      /* currently we won't get that status */
-      write_status( STATUS_TRUST_NEVER );
+      /* This level can be returned by TOFU, which supports negative
+       * assertions.  */
+      write_trust_status (STATUS_TRUST_NEVER, trustlevel);
       log_info(_("WARNING: We do NOT trust this key!\n"));
       log_info(_("         The signature is probably a FORGERY.\n"));
       if (opt.with_fingerprint)
@@ -646,7 +678,7 @@ check_signatures_trust( PKT_signature *sig )
       break;
 
     case TRUST_MARGINAL:
-      write_status( STATUS_TRUST_MARGINAL );
+      write_trust_status (STATUS_TRUST_MARGINAL, trustlevel);
       log_info(_("WARNING: This key is not certified with"
                  " sufficiently trusted signatures!\n"));
       log_info(_("         It is not certain that the"
@@ -655,13 +687,13 @@ check_signatures_trust( PKT_signature *sig )
       break;
 
     case TRUST_FULLY:
-      write_status( STATUS_TRUST_FULLY );
+      write_trust_status (STATUS_TRUST_FULLY, trustlevel);
       if (opt.with_fingerprint)
         print_fingerprint (NULL, pk, 1);
       break;
 
     case TRUST_ULTIMATE:
-      write_status( STATUS_TRUST_ULTIMATE );
+      write_trust_status (STATUS_TRUST_ULTIMATE, trustlevel);
       if (opt.with_fingerprint)
         print_fingerprint (NULL, pk, 1);
       break;
@@ -761,14 +793,16 @@ expand_id(const char *id,strlist_t *into,unsigned int flags)
 }
 
 /* For simplicity, and to avoid potential loops, we only expand once -
  you can't make an alias that points to an alias. */
* you can't make an alias that points to an alias.  */
 static strlist_t
-expand_group(strlist_t input)
+expand_group (strlist_t input)
 {
-  strlist_t sl,output=NULL,rover;
+  strlist_t output = NULL;
+  strlist_t sl, rover;
 
-  for(rover=input;rover;rover=rover->next)
-    if(expand_id(rover->d,&output,rover->flags)==0)
+  for (rover = input; rover; rover = rover->next)
+    if (!(rover->flags & PK_LIST_FROM_FILE)
+        && !expand_id(rover->d,&output,rover->flags))
       {
        /* Didn't find any groups, so use the existing string */
        sl=add_to_strlist(&output,rover->d);
@@ -780,17 +814,18 @@ expand_group(strlist_t input)
 
 
 /* Helper for build_pk_list to find and check one key.  This helper is
-   also used directly in server mode by the RECIPIENTS command.  On
-   success the new key is added to PK_LIST_ADDR.  NAME is the user id
-   of the key. USE the requested usage and a set MARK_HIDDEN will mark
-   the key in the updated list as a hidden recipient. */
+ * also used directly in server mode by the RECIPIENTS command.  On
+ * success the new key is added to PK_LIST_ADDR.  NAME is the user id
+ * of the key.  USE the requested usage and a set MARK_HIDDEN will
+ * mark the key in the updated list as a hidden recipient.  If
+ * FROM_FILE is true, NAME is is not a user ID but the name of a file
+ * holding a key. */
 gpg_error_t
 find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
-                    int mark_hidden, pk_list_t *pk_list_addr)
+                    int mark_hidden, int from_file, pk_list_t *pk_list_addr)
 {
   int rc;
   PKT_public_key *pk;
-  int trustlevel;
 
   if (!name || !*name)
     return gpg_error (GPG_ERR_INV_USER_ID);
@@ -800,7 +835,10 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
     return gpg_error_from_syserror ();
   pk->req_usage = use;
 
-  rc = get_pubkey_byname (ctrl, NULL, pk, name, NULL, NULL, 0, 0);
+  if (from_file)
+    rc = get_pubkey_fromfile (ctrl, pk, name);
+  else
+    rc = get_pubkey_byname (ctrl, NULL, pk, name, NULL, NULL, 0, 0);
   if (rc)
     {
       int code;
@@ -830,24 +868,28 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
     }
 
   /* Key found and usable.  Check validity. */
-  trustlevel = get_validity (pk, pk->user_id, NULL, 1);
-  if ( (trustlevel & TRUST_FLAG_DISABLED) )
+  if (!from_file)
     {
-      /* Key has been disabled. */
-      send_status_inv_recp (13, name);
-      log_info (_("%s: skipped: public key is disabled\n"), name);
-      free_public_key (pk);
-      return GPG_ERR_UNUSABLE_PUBKEY;
-    }
+      int trustlevel;
 
-  if ( !do_we_trust_pre (pk, trustlevel) )
-    {
-      /* We don't trust this key.  */
-      send_status_inv_recp (10, name);
-      free_public_key (pk);
-      return GPG_ERR_UNUSABLE_PUBKEY;
+      trustlevel = get_validity (ctrl, pk, pk->user_id, NULL, 1);
+      if ( (trustlevel & TRUST_FLAG_DISABLED) )
+        {
+          /* Key has been disabled. */
+          send_status_inv_recp (13, name);
+          log_info (_("%s: skipped: public key is disabled\n"), name);
+          free_public_key (pk);
+          return GPG_ERR_UNUSABLE_PUBKEY;
+        }
+
+      if ( !do_we_trust_pre (pk, trustlevel) )
+        {
+          /* We don't trust this key.  */
+          send_status_inv_recp (10, name);
+          free_public_key (pk);
+          return GPG_ERR_UNUSABLE_PUBKEY;
+        }
     }
-  /* Note: do_we_trust may have changed the trustlevel. */
 
   /* Skip the actual key if the key is already present in the
      list.  */
@@ -880,28 +922,27 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
 
 
 /* This is the central function to collect the keys for recipients.
  It is thus used to prepare a public key encryption. encrypt-to
  keys, default keys and the keys for the actual recipients are all
  collected here.  When not in batch mode and no recipient has been
  passed on the commandline, the function will also ask for
  recipients.
-
  RCPTS is a string list with the recipients; NULL is an allowed
  value but not very useful.  Group expansion is done on these names;
  they may be in any of the user Id formats we can handle.  The flags
  bits for each string in the string list are used for:
-     Bit 0 (PK_LIST_ENCRYPT_TO): This is an encrypt-to recipient.
    Bit 1 (PK_LIST_HIDDEN)    : This is a hidden recipient.
-
  USE is the desired use for the key - usually PUBKEY_USAGE_ENC.
-
  On success a list of keys is stored at the address RET_PK_LIST; the
  caller must free this list.  On error the value at this address is
  not changed.
* It is thus used to prepare a public key encryption. encrypt-to
* keys, default keys and the keys for the actual recipients are all
* collected here.  When not in batch mode and no recipient has been
* passed on the commandline, the function will also ask for
* recipients.
+ *
* RCPTS is a string list with the recipients; NULL is an allowed
* value but not very useful.  Group expansion is done on these names;
* they may be in any of the user Id formats we can handle.  The flags
* bits for each string in the string list are used for:
+ *
* - PK_LIST_ENCRYPT_TO :: This is an encrypt-to recipient.
+ * - PK_LIST_HIDDEN     :: This is a hidden recipient.
* - PK_LIST_FROM_FILE  :: The argument is a file with a key.
+ *
* On success a list of keys is stored at the address RET_PK_LIST; the
* caller must free this list.  On error the value at this address is
* not changed.
  */
 int
-build_pk_list (ctrl_t ctrl,
-               strlist_t rcpts, PK_LIST *ret_pk_list, unsigned int use )
+build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
 {
   PK_LIST pk_list = NULL;
   PKT_public_key *pk=NULL;
@@ -917,6 +958,60 @@ build_pk_list (ctrl_t ctrl,
   else
     remusr = rcpts;
 
+  /* XXX: Change this function to use get_pubkeys instead of
+     get_pubkey_byname to detect ambiguous key specifications and warn
+     about duplicate keyblocks.  For ambiguous key specifications on
+     the command line or provided interactively, prompt the user to
+     select the best key.  If a key specification is ambiguous and we
+     are in batch mode, die.  */
+
+  if (opt.encrypt_to_default_key)
+    {
+      static int warned;
+
+      const char *default_key = parse_def_secret_key (ctrl);
+      if (default_key)
+        {
+          PK_LIST r = xmalloc_clear (sizeof *r);
+
+          r->pk = xmalloc_clear (sizeof *r->pk);
+          r->pk->req_usage = PUBKEY_USAGE_ENC;
+
+          rc = get_pubkey_byname (ctrl, NULL, r->pk, default_key,
+                                   NULL, NULL, 0, 1);
+          if (rc)
+            {
+              xfree (r->pk);
+              xfree (r);
+
+              log_error (_("can't encrypt to '%s'\n"), default_key);
+              if (!opt.quiet)
+                log_info (_("(check argument of option '%s')\n"),
+                          "--default-key");
+            }
+          else
+            {
+              r->next = pk_list;
+              r->flags = 0;
+              pk_list = r;
+            }
+        }
+      else if (opt.def_secret_key)
+        {
+          if (! warned)
+            log_info (_("option '%s' given, but no valid default keys given\n"),
+                      "--encrypt-to-default-key");
+          warned = 1;
+        }
+      else
+        {
+          if (! warned)
+            log_info (_("option '%s' given, but option '%s' not given\n"),
+                      "--encrypt-to-default-key", "--default-key");
+          warned = 1;
+        }
+    }
+
   /* Check whether there are any recipients in the list and build the
    * list of the encrypt-to ones (we always trust them). */
   for ( rov = remusr; rov; rov = rov->next )
@@ -938,12 +1033,12 @@ build_pk_list (ctrl_t ctrl,
               compliance_failure();
             }
         }
-      else if ( (use & PUBKEY_USAGE_ENC) && !opt.no_encrypt_to )
+      else if (!opt.no_encrypt_to)
         {
-          /* Encryption has been requested and --encrypt-to has not
-             been disabled.  Check this encrypt-to key. */
+          /* --encrypt-to has not been disabled.  Check this
+             encrypt-to key. */
           pk = xmalloc_clear( sizeof *pk );
-          pk->req_usage = use;
+          pk->req_usage = PUBKEY_USAGE_ENC;
 
           /* We explicitly allow encrypt-to to an disabled key; thus
              we pass 1 for the second last argument and 1 as the last
@@ -956,7 +1051,8 @@ build_pk_list (ctrl_t ctrl,
               send_status_inv_recp (0, rov->d);
               goto fail;
             }
-          else if ( !(rc=openpgp_pk_test_algo2 (pk->pubkey_algo, use)) )
+          else if ( !(rc=openpgp_pk_test_algo2 (pk->pubkey_algo,
+                                                PUBKEY_USAGE_ENC)) )
             {
               /* Skip the actual key if the key is already present
                * in the list.  Add it to our list if not. */
@@ -1084,11 +1180,12 @@ build_pk_list (ctrl_t ctrl,
           /* Get and check key for the current name. */
           free_public_key (pk);
           pk = xmalloc_clear( sizeof *pk );
-          pk->req_usage = use;
+          pk->req_usage = PUBKEY_USAGE_ENC;
           rc = get_pubkey_byname (ctrl, NULL, pk, answer, NULL, NULL, 0, 0 );
           if (rc)
             tty_printf(_("No such user ID.\n"));
-          else if ( !(rc=openpgp_pk_test_algo2 (pk->pubkey_algo, use)) )
+          else if ( !(rc=openpgp_pk_test_algo2 (pk->pubkey_algo,
+                                                PUBKEY_USAGE_ENC)) )
             {
               if ( have_def_rec )
                 {
@@ -1115,7 +1212,7 @@ build_pk_list (ctrl_t ctrl,
                 { /* Check validity of this key. */
                   int trustlevel;
 
-                  trustlevel = get_validity (pk, pk->user_id, NULL, 1);
+                  trustlevel = get_validity (ctrl, pk, pk->user_id, NULL, 1);
                   if ( (trustlevel & TRUST_FLAG_DISABLED) )
                     {
                       tty_printf (_("Public key is disabled.\n") );
@@ -1157,14 +1254,15 @@ build_pk_list (ctrl_t ctrl,
     {
       /* We are in batch mode and have only a default recipient. */
       pk = xmalloc_clear( sizeof *pk );
-      pk->req_usage = use;
+      pk->req_usage = PUBKEY_USAGE_ENC;
 
       /* The default recipient is allowed to be disabled; thus pass 1
          as second last argument.  We also don't want an AKL. */
       rc = get_pubkey_byname (ctrl, NULL, pk, def_rec, NULL, NULL, 1, 1);
       if (rc)
         log_error(_("unknown default recipient \"%s\"\n"), def_rec );
-      else if ( !(rc=openpgp_pk_test_algo2(pk->pubkey_algo, use)) )
+      else if ( !(rc=openpgp_pk_test_algo2(pk->pubkey_algo,
+                                           PUBKEY_USAGE_ENC)) )
         {
           /* Mark any_recipients here since the default recipient
              would have been used if it wasn't already there.  It
@@ -1199,8 +1297,9 @@ build_pk_list (ctrl_t ctrl,
           if ( (remusr->flags & PK_LIST_ENCRYPT_TO) )
             continue; /* encrypt-to keys are already handled. */
 
-          rc = find_and_check_key (ctrl, remusr->d, use,
+          rc = find_and_check_key (ctrl, remusr->d, PUBKEY_USAGE_ENC,
                                    !!(remusr->flags&PK_LIST_HIDDEN),
+                                   !!(remusr->flags&PK_LIST_FROM_FILE),
                                    &pk_list);
           if (rc)
             goto fail;
@@ -1215,6 +1314,29 @@ build_pk_list (ctrl_t ctrl,
       rc = GPG_ERR_NO_USER_ID;
     }
 
+#ifdef USE_TOFU
+  if (! rc && (opt.trust_model == TM_TOFU_PGP || opt.trust_model == TM_TOFU))
+    {
+      PK_LIST iter;
+      for (iter = pk_list; iter; iter = iter->next)
+        {
+          int rc2;
+
+          /* Note: we already resolved any conflict when looking up
+             the key.  Don't annoy the user again if she selected
+             accept once.  */
+          rc2 = tofu_register_encryption (ctrl, iter->pk, NULL, 0);
+          if (rc2)
+            log_info ("WARNING: Failed to register encryption to %s"
+                      " with TOFU engine\n",
+                      keystr (pk_main_keyid (iter->pk)));
+          else if (DBG_TRUST)
+            log_debug ("Registered encryption to %s with TOFU DB.\n",
+                      keystr (pk_main_keyid (iter->pk)));
+        }
+    }
+#endif /*USE_TOFU*/
+
  fail:
 
   if ( rc )