card: For passwd add a PIV menu and make the OpenPGP menu optional.
authorWerner Koch <wk@gnupg.org>
Thu, 28 Mar 2019 13:46:05 +0000 (14:46 +0100)
committerWerner Koch <wk@gnupg.org>
Thu, 28 Mar 2019 13:46:05 +0000 (14:46 +0100)
* tools/gpg-card.c (get_selection): New.
(cmd_passwd): Reworked.

Signed-off-by: Werner Koch <wk@gnupg.org>
tools/gpg-card.c

index a3113c9..7b3f8a3 100644 (file)
@@ -429,6 +429,24 @@ put_data_to_file (const char *fname, const void *buffer, size_t length)
 }
 
 
+/* Return a malloced string with the number opf the menu PROMPT.
+ * Control-D is mapped to "Q".  */
+static char *
+get_selection (const char *prompt)
+{
+  char *answer;
+
+  tty_printf ("\n");
+  tty_printf ("%s", prompt);
+  tty_printf ("\n");
+  answer = tty_get (_("Your selection? "));
+  tty_kill_prompt ();
+  if (*answer == CONTROL_D)
+    strcpy (answer, "q");
+  return answer;
+}
+
+
 \f
 /* Simply prints TEXT to the output.  Returns 0 as a convenience.
  * This is a separate fucntion so that it can be extended to run
@@ -2097,21 +2115,23 @@ cmd_generate (card_info_t info, char *argstr)
 
 
 \f
-/* Sub-menu to change a PIN.  */
+/* Change a PIN.  */
 static gpg_error_t
 cmd_passwd (card_info_t info, char *argstr)
 {
-  gpg_error_t err;
+  gpg_error_t err = 0;
   char *answer = NULL;
-  const char *pinref;
+  const char *pinref = NULL;
+  int reset_mode = 0;
+  int menu_used = 0;
 
   if (!info)
     return print_help
       ("PASSWD [PINREF]\n\n"
-       "Menu to change or unblock the PINs.  Note that the\n"
-       "presented menu options depend on the type of card\n"
-       "and whether the admin mode is enabled.  For OpenPGP\n"
-       "and PIV cards defaults for PINREF are available.",
+       "Change or unblock the PINs.  Note that in interactive mode\n"
+       "and without a PINREF a menu is presented for certain cards;\n"
+       "in non-interactive and without a PINREF a default value is\n"
+       "used for these cards.",
        0);
 
   if (opt.interactive || opt.verbose)
@@ -2119,92 +2139,93 @@ cmd_passwd (card_info_t info, char *argstr)
               app_type_string (info->apptype),
               info->dispserialno? info->dispserialno : info->serialno);
 
-  if (!*argstr && info->apptype == APP_TYPE_OPENPGP)
+  if (*argstr)
+    pinref = argstr;
+  else if (opt.interactive && info->apptype == APP_TYPE_OPENPGP)
     {
-      /* For an OpenPGP card we present the well known menu if no
-       * argument is given.  */
-      for (;;)
+      menu_used = 1;
+      while (!pinref)
         {
-          tty_printf ("\n");
-          tty_printf ("1 - change PIN\n"
-                      "2 - unblock and set new PIN\n"
-                      "3 - change Admin PIN\n"
-                      "4 - set the Reset Code\n"
-                      "Q - quit\n");
-          tty_printf ("\n");
-
-          err = 0;
           xfree (answer);
-          answer = tty_get (_("Your selection? "));
-          tty_kill_prompt ();
-          if (*answer == CONTROL_D)
-            break;  /* Quit.  */
+          answer = get_selection ("1 - change the PIN\n"
+                                  "2 - unblock and set new a PIN\n"
+                                  "3 - change the Admin PIN\n"
+                                  "4 - set the Reset Code\n"
+                                  "Q - quit\n");
           if (strlen (answer) != 1)
             continue;
-          if (*answer == 'q' || *answer == 'Q')
-            break;  /* Quit.  */
-
-          if (*answer == '1')
-            {
-              /* Change PIN (same as the direct thing in non-admin mode).  */
-              err = scd_change_pin ("OPENPGP.1", 0);
-              if (err)
-                log_error ("Error changing the PIN: %s\n", gpg_strerror (err));
-              else
-                log_info ("PIN changed.\n");
-            }
+          else if (*answer == 'q' || *answer == 'Q')
+            goto leave;
+          else if (*answer == '1')
+            pinref = "OPENPGP.1";
           else if (*answer == '2')
-            {
-              /* Unblock PIN by setting a new PIN.  */
-              err = scd_change_pin ("OPENPGP.1", 1);
-              if (err)
-                log_error ("Error unblocking the PIN: %s\n", gpg_strerror(err));
-              else
-                log_info ("PIN unblocked and new PIN set.\n");
-            }
+            { pinref = "OPENPGP.1"; reset_mode = 1; }
           else if (*answer == '3')
-            {
-              /* Change Admin PIN.  */
-              err = scd_change_pin ("OPENPGP.3", 0);
-              if (err)
-                log_error ("Error changing the PIN: %s\n", gpg_strerror (err));
-              else
-                log_info ("PIN changed.\n");
-         }
+            pinref = "OPENPGP.3";
           else if (*answer == '4')
-            {
-              /* Set a new Reset Code.  */
-              err = scd_change_pin ("OPENPGP.2", 1);
-              if (err)
-                log_error ("Error setting the Reset Code: %s\n",
-                           gpg_strerror (err));
-              else
-                log_info ("Reset Code set.\n");
-            }
-
-        } /*end for loop*/
+            { pinref = "OPENPGP.2"; reset_mode = 1; }
+        }
     }
-  else
+  else if (info->apptype == APP_TYPE_OPENPGP)
+    pinref = "OPENPGP.1";
+  else if (opt.interactive && info->apptype == APP_TYPE_PIV)
     {
-      if (*argstr)
-        pinref = argstr;
-      else if (info->apptype == APP_TYPE_PIV)
-        pinref = "PIV.80";
-      else
+      menu_used = 1;
+      while (!pinref)
         {
-          /* Note that we do not have a default value for OpenPGP
-           * because we want to be mostly compatible to "gpg
-           * --card-edit" and show a menu in that case (above).  */
-          err = gpg_error (GPG_ERR_MISSING_VALUE);
-          goto leave;
+          xfree (answer);
+          answer = get_selection ("1 - change the PIN\n"
+                                  "2 - change the PUK\n"
+                                  "3 - change the Global PIN\n"
+                                  "Q - quit\n");
+          if (strlen (answer) != 1)
+            ;
+          else if (*answer == 'q' || *answer == 'Q')
+            goto leave;
+          else if (*answer == '1')
+            pinref = "PIV.80";
+          else if (*answer == '2')
+            pinref = "PIV.81";
+          else if (*answer == '3')
+            pinref = "PIV.00";
         }
-      err = scd_change_pin (pinref, 0);
-      if (err)
-        goto leave;
+    }
+  else if (info->apptype == APP_TYPE_PIV)
+    pinref = "PIV.80";
+  else
+    {
+      err = gpg_error (GPG_ERR_MISSING_VALUE);
+      goto leave;
+    }
 
-      if (info->apptype == APP_TYPE_PIV
-          && !ascii_strcasecmp (pinref, "PIV.81"))
+  err = scd_change_pin (pinref, reset_mode);
+  if (err)
+    {
+      if (!opt.interactive && !menu_used && !opt.verbose)
+        ;
+      else if (!ascii_strcasecmp (pinref, "PIV.81"))
+        log_error ("Error changing the PUK.\n");
+      else if (!ascii_strcasecmp (pinref, "OPENPGP.1") && reset_mode)
+        log_error ("Error unblocking the PIN.\n");
+      else if (!ascii_strcasecmp (pinref, "OPENPGP.2") && reset_mode)
+        log_error ("Error setting the Reset Code.\n");
+      else if (!ascii_strcasecmp (pinref, "OPENPGP.3"))
+        log_error ("Error changing the Admin PIN.\n");
+      else
+        log_error ("Error changing the PIN.\n");
+    }
+  else
+    {
+      if (!opt.interactive && !opt.verbose)
+        ;
+      else if (!ascii_strcasecmp (pinref, "PIV.81"))
         log_info ("PUK changed.\n");
+      else if (!ascii_strcasecmp (pinref, "OPENPGP.1") && reset_mode)
+        log_info ("PIN unblocked and new PIN set.\n");
+      else if (!ascii_strcasecmp (pinref, "OPENPGP.2") && reset_mode)
+        log_info ("Reset Code set.\n");
+      else if (!ascii_strcasecmp (pinref, "OPENPGP.3"))
+        log_info ("Admin PIN changed.\n");
       else
         log_info ("PIN changed.\n");
     }
@@ -2261,7 +2282,7 @@ cmd_unblock (card_info_t info)
     }
   else
     {
-      log_info ("Unblocking not yet supported for '%s'\n",
+      log_info ("Unblocking not supported for '%s'.\n",
                 app_type_string (info->apptype));
       err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
     }