Imported Upstream version 2.4.3
[platform/upstream/gpg2.git] / g10 / keylist.c
index 76eed6a..8b7c597 100644 (file)
@@ -44,6 +44,8 @@
 #include "../common/mbox-util.h"
 #include "../common/zb32.h"
 #include "tofu.h"
+#include "../common/init.h"
+#include "../common/recsel.h"
 #include "../common/compliance.h"
 #include "../common/pkscreening.h"
 
@@ -64,16 +66,26 @@ struct keylist_context
   int no_validity; /* Do not show validity.  */
 };
 
-
-static void list_keyblock (ctrl_t ctrl,
-                           kbnode_t keyblock, int secret, int has_secret,
-                           int fpr, struct keylist_context *listctx);
+/* An object and a global instance to store selectors created from
+ * --list-filter select=EXPR.
+ */
+struct list_filter_s
+{
+  recsel_expr_t selkey;
+};
+struct list_filter_s list_filter;
 
 
 /* The stream used to write attribute packets to.  */
 static estream_t attrib_fp;
 
 
+
+\f
+static void list_keyblock (ctrl_t ctrl,
+                           kbnode_t keyblock, int secret, int has_secret,
+                           int fpr, struct keylist_context *listctx);
+
 /* Release resources from a keylist context.  */
 static void
 keylist_context_release (struct keylist_context *listctx)
@@ -82,6 +94,49 @@ keylist_context_release (struct keylist_context *listctx)
 }
 
 
+static void
+release_list_filter (struct list_filter_s *filt)
+{
+  recsel_release (filt->selkey);
+  filt->selkey = NULL;
+}
+
+
+static void
+cleanup_keylist_globals (void)
+{
+  release_list_filter (&list_filter);
+}
+
+
+/* Parse and set an list filter from string.  STRING has the format
+ * "NAME=EXPR" with NAME being the name of the filter.  Spaces before
+ * and after NAME are not allowed.  If this function is all called
+ * several times all expressions for the same NAME are concatenated.
+ * Supported filter names are:
+ *
+ *  - select :: If the expression evaluates to true for a certain key
+ *              this key will be listed.  The expression may use any
+ *              variable defined for the export and import filters.
+ *
+ */
+gpg_error_t
+parse_and_set_list_filter (const char *string)
+{
+  gpg_error_t err;
+
+  /* Auto register the cleanup function.  */
+  register_mem_cleanup_func (cleanup_keylist_globals);
+
+  if (!strncmp (string, "select=", 7))
+    err = recsel_parse_expr (&list_filter.selkey, string+7);
+  else
+    err = gpg_error (GPG_ERR_INV_NAME);
+
+  return err;
+}
+
+
 /* List the keys.  If list is NULL, all available keys are listed.
  * With LOCATE_MODE set the locate algorithm is used to find a key; if
  * in addition NO_LOCAL is set the locate does not look into the local
@@ -306,6 +361,173 @@ print_card_key_info (estream_t fp, kbnode_t keyblock)
 #endif /*ENABLE_CARD_SUPPORT*/
 
 
+/* Print the preferences line.  Allowed values for MODE are:
+ *  -1 - print to the TTY
+ *   0 - print to stdout.
+ *   1 - use log_info
+ */
+void
+show_preferences (PKT_user_id *uid, int indent, int mode, int verbose)
+{
+  estream_t fp = mode < 0? NULL : mode ? log_get_stream () : es_stdout;
+  const prefitem_t fake = { 0, 0 };
+  const prefitem_t *prefs;
+  int i;
+
+  if (!uid)
+    return;
+
+  if (uid->prefs)
+    prefs = uid->prefs;
+  else if (verbose)
+    prefs = &fake;
+  else
+    return;
+
+  if (verbose)
+    {
+      int any, des_seen = 0, sha1_seen = 0, uncomp_seen = 0;
+
+      tty_fprintf (fp, "%*s %s", indent, "", _("Cipher: "));
+      for (i = any = 0; prefs[i].type; i++)
+       {
+         if (prefs[i].type == PREFTYPE_SYM)
+           {
+             if (any)
+               tty_fprintf (fp, ", ");
+             any = 1;
+             /* We don't want to display strings for experimental algos */
+             if (!openpgp_cipher_test_algo (prefs[i].value)
+                 && prefs[i].value < 100)
+               tty_fprintf (fp, "%s", openpgp_cipher_algo_name (prefs[i].value));
+             else
+               tty_fprintf (fp, "[%d]", prefs[i].value);
+             if (prefs[i].value == CIPHER_ALGO_3DES)
+               des_seen = 1;
+           }
+       }
+      if (!des_seen)
+       {
+         if (any)
+           tty_fprintf (fp, ", ");
+         tty_fprintf (fp, "%s", openpgp_cipher_algo_name (CIPHER_ALGO_3DES));
+       }
+      tty_fprintf (fp, "\n%*s %s", indent, "", _("AEAD: "));
+      for (i = any = 0; prefs[i].type; i++)
+       {
+         if (prefs[i].type == PREFTYPE_AEAD)
+           {
+             if (any)
+               tty_fprintf (fp, ", ");
+             any = 1;
+             /* We don't want to display strings for experimental algos */
+             if (!openpgp_aead_test_algo (prefs[i].value)
+                 && prefs[i].value < 100)
+               tty_fprintf (fp, "%s", openpgp_aead_algo_name (prefs[i].value));
+             else
+               tty_fprintf (fp, "[%d]", prefs[i].value);
+           }
+       }
+      tty_fprintf (fp, "\n%*s %s", indent, "", _("Digest: "));
+      for (i = any = 0; prefs[i].type; i++)
+       {
+         if (prefs[i].type == PREFTYPE_HASH)
+           {
+             if (any)
+               tty_fprintf (fp, ", ");
+             any = 1;
+             /* We don't want to display strings for experimental algos */
+             if (!gcry_md_test_algo (prefs[i].value) && prefs[i].value < 100)
+               tty_fprintf (fp, "%s", gcry_md_algo_name (prefs[i].value));
+             else
+               tty_fprintf (fp, "[%d]", prefs[i].value);
+             if (prefs[i].value == DIGEST_ALGO_SHA1)
+               sha1_seen = 1;
+           }
+       }
+      if (!sha1_seen)
+       {
+         if (any)
+           tty_fprintf (fp, ", ");
+         tty_fprintf (fp, "%s", gcry_md_algo_name (DIGEST_ALGO_SHA1));
+       }
+      tty_fprintf (fp, "\n%*s %s", indent, "", _("Compression: "));
+      for (i = any = 0; prefs[i].type; i++)
+       {
+         if (prefs[i].type == PREFTYPE_ZIP)
+           {
+             const char *s = compress_algo_to_string (prefs[i].value);
+
+             if (any)
+               tty_fprintf (fp, ", ");
+             any = 1;
+             /* We don't want to display strings for experimental algos */
+             if (s && prefs[i].value < 100)
+               tty_fprintf (fp, "%s", s);
+             else
+               tty_fprintf (fp, "[%d]", prefs[i].value);
+             if (prefs[i].value == COMPRESS_ALGO_NONE)
+               uncomp_seen = 1;
+           }
+       }
+      if (!uncomp_seen)
+       {
+         if (any)
+           tty_fprintf (fp, ", ");
+         else
+           {
+             tty_fprintf (fp, "%s",
+                           compress_algo_to_string (COMPRESS_ALGO_ZIP));
+             tty_fprintf (fp, ", ");
+           }
+         tty_fprintf (fp, "%s", compress_algo_to_string (COMPRESS_ALGO_NONE));
+       }
+      if (uid->flags.mdc || uid->flags.aead || !uid->flags.ks_modify)
+       {
+          tty_fprintf (fp, "\n%*s %s", indent, "", _("Features: "));
+         any = 0;
+         if (uid->flags.mdc)
+           {
+             tty_fprintf (fp, "MDC");
+             any = 1;
+           }
+         if (uid->flags.aead)
+           {
+             if (any)
+               tty_fprintf (fp, ", ");
+             tty_fprintf (fp, "AEAD");
+           }
+         if (!uid->flags.ks_modify)
+           {
+             if (any)
+               tty_fprintf (fp, ", ");
+             tty_fprintf (fp, _("Keyserver no-modify"));
+           }
+       }
+      tty_fprintf (fp, "\n");
+    }
+  else
+    {
+      tty_fprintf (fp, "%*s", indent, "");
+      for (i = 0; prefs[i].type; i++)
+        {
+          tty_fprintf (fp, " %c%d", prefs[i].type == PREFTYPE_SYM ? 'S' :
+                       prefs[i].type == PREFTYPE_AEAD ? 'A' :
+                       prefs[i].type == PREFTYPE_HASH ? 'H' :
+                       prefs[i].type == PREFTYPE_ZIP ? 'Z' : '?',
+                       prefs[i].value);
+        }
+      if (uid->flags.mdc)
+        tty_fprintf (fp, " [mdc]");
+      if (uid->flags.aead)
+        tty_fprintf (fp, " [aead]");
+      if (!uid->flags.ks_modify)
+        tty_fprintf (fp, " [no-ks-modify]");
+      tty_fprintf (fp, "\n");
+    }
+}
+
+
 /* Flags = 0x01 hashed 0x02 critical.  */
 static void
 status_one_subpacket (sigsubpkttype_t type, size_t len, int flags,
@@ -802,6 +1024,13 @@ print_capabilities (ctrl_t ctrl, PKT_public_key *pk, KBNODE keyblock)
   if ((use & PUBKEY_USAGE_AUTH))
     es_putc ('a', es_stdout);
 
+  if (use & PUBKEY_USAGE_RENC)
+    es_putc ('r', es_stdout);
+  if ((use & PUBKEY_USAGE_TIME))
+    es_putc ('t', es_stdout);
+  if ((use & PUBKEY_USAGE_GROUP))
+    es_putc ('g', es_stdout);
+
   if ((use & PUBKEY_USAGE_UNKNOWN))
     es_putc ('?', es_stdout);
 
@@ -987,7 +1216,8 @@ cmp_signodes (const void *av, const void *bv)
 }
 
 
-/* Helper for list_keyblock_print.  */
+/* Helper for list_keyblock_print.  The caller must have set
+ * NODFLG_MARK_B to indicate self-signatures.  */
 static void
 list_signature_print (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
                       struct keylist_context *listctx)
@@ -1018,6 +1248,11 @@ list_signature_print (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
                case GPG_ERR_UNUSABLE_PUBKEY:
                  listctx->no_key++;
                  return;
+                case GPG_ERR_DIGEST_ALGO:
+                case GPG_ERR_PUBKEY_ALGO:
+                  if (!(opt.list_options & LIST_SHOW_UNUSABLE_SIGS))
+                    return;
+                  /* fallthru. */
                default:
                  listctx->oth_err++;
                  sigrc = '%';
@@ -1030,6 +1265,15 @@ list_signature_print (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
            }
          else
            {
+              if (!(opt.list_options & LIST_SHOW_UNUSABLE_SIGS)
+                  && (gpg_err_code (openpgp_pk_test_algo (sig->pubkey_algo)
+                                    == GPG_ERR_PUBKEY_ALGO)
+                      || gpg_err_code (openpgp_md_test_algo (sig->digest_algo)
+                                       == GPG_ERR_DIGEST_ALGO)
+                      || (sig->digest_algo == DIGEST_ALGO_SHA1
+                          && !(node->flag & NODFLG_MARK_B) /*no selfsig*/
+                          && !opt.flags.allow_weak_key_signatures)))
+                return;
              rc = 0;
              sigrc = ' ';
            }
@@ -1077,7 +1321,9 @@ list_signature_print (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
            es_fprintf (es_stdout, "[%s] ", gpg_strerror (rc));
          else if (sigrc == '?')
            ;
-         else if (!opt.fast_list_mode)
+         else if ((node->flag & NODFLG_MARK_B))
+            es_fputs (_("[self-signature]"), es_stdout);
+          else if (!opt.fast_list_mode )
            {
              size_t n;
              char *p = get_user_id (ctrl, sig->keyid, &n, NULL);
@@ -1262,6 +1508,11 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
          print_utf8_buffer (es_stdout, uid->name, uid->len);
          es_putc ('\n', es_stdout);
 
+          if ((opt.list_options & LIST_SHOW_PREF_VERBOSE))
+            show_preferences (uid, indent+2, 0, 1);
+          else if ((opt.list_options & LIST_SHOW_PREF))
+            show_preferences (uid, indent+2, 0, 0);
+
           if (opt.with_wkd_hash)
             {
               char *mbox, *hash, *p;
@@ -1351,37 +1602,33 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
       else if (opt.list_sigs
               && node->pkt->pkttype == PKT_SIGNATURE && !skip_sigs)
        {
-          if ((opt.list_options & LIST_SORT_SIGS))
-            {
-              kbnode_t n;
-              unsigned int sigcount = 0;
-              kbnode_t *sigarray;
-              unsigned int idx;
+          kbnode_t n;
+          unsigned int sigcount = 0;
+          kbnode_t *sigarray;
+          unsigned int idx;
 
-              for (n=node; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
-                sigcount++;
-              sigarray = xcalloc (sigcount, sizeof *sigarray);
+          for (n=node; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
+            sigcount++;
+          sigarray = xcalloc (sigcount, sizeof *sigarray);
 
-              sigcount = 0;
-              for (n=node; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
-                {
-                  if (!keyid_cmp (mainkid, n->pkt->pkt.signature->keyid))
-                    n->flag |= NODFLG_MARK_B;  /* Is a self-sig.  */
-                  else
-                    n->flag &= ~NODFLG_MARK_B;
+          sigcount = 0;
+          for (n=node; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
+            {
+              if (keyid_eq (mainkid, n->pkt->pkt.signature->keyid))
+                n->flag |= NODFLG_MARK_B;  /* Is a self-sig.  */
+              else
+                n->flag &= ~NODFLG_MARK_B;
 
-                  sigarray[sigcount++] = node = n;
-                }
-              /* Note that NODE is now at the last signature.  */
+              sigarray[sigcount++] = node = n;
+            }
+          /* Note that NODE is now at the last signature.  */
 
-              qsort (sigarray, sigcount, sizeof *sigarray, cmp_signodes);
+          if ((opt.list_options & LIST_SORT_SIGS))
+            qsort (sigarray, sigcount, sizeof *sigarray, cmp_signodes);
 
-              for (idx=0; idx < sigcount; idx++)
-                list_signature_print (ctrl, keyblock, sigarray[idx], listctx);
-              xfree (sigarray);
-            }
-          else
-            list_signature_print (ctrl, keyblock, node, listctx);
+          for (idx=0; idx < sigcount; idx++)
+            list_signature_print (ctrl, keyblock, sigarray[idx], listctx);
+          xfree (sigarray);
        }
     }
   es_putc ('\n', es_stdout);
@@ -1984,6 +2231,7 @@ reorder_keyblock (KBNODE keyblock)
   do_reorder_keyblock (keyblock, 0);
 }
 
+
 static void
 list_keyblock (ctrl_t ctrl,
                KBNODE keyblock, int secret, int has_secret, int fpr,
@@ -1991,6 +2239,24 @@ list_keyblock (ctrl_t ctrl,
 {
   reorder_keyblock (keyblock);
 
+  if (list_filter.selkey)
+    {
+      int selected = 0;
+      struct impex_filter_parm_s parm;
+      parm.ctrl = ctrl;
+
+      for (parm.node = keyblock; parm.node; parm.node = parm.node->next)
+        {
+          if (recsel_select (list_filter.selkey, impex_filter_getval, &parm))
+            {
+              selected = 1;
+              break;
+            }
+        }
+      if (!selected)
+        return;  /* Skip this one.  */
+    }
+
   if (opt.with_colons)
     list_keyblock_colon (ctrl, keyblock, secret, has_secret);
   else if ((opt.list_options & LIST_SHOW_ONLY_FPR_MBOX))