* gpg.sgml: Clarify new notation delete feature.
[gnupg.git] / g10 / cardglue.c
index ae4d37a..d850b56 100644 (file)
@@ -1,5 +1,5 @@
 /* cardglue.c - mainly dispatcher for card related functions.
- * Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+ * Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -29,7 +29,6 @@
 #include <errno.h>
 #include <stdarg.h>
 #include <assert.h>
-
 #include "options.h"
 #include "packet.h"
 #include "errors.h"
 #include "apdu.h"
 #include "app-common.h"
 
-/* If we build w/o agent support, assuan.h won't be included and thus
-   we need to define a repalcement for the assuan error type. */
-#ifndef ENABLE_AGENT_SUPPORT
-typedef int assuan_error_t;
-#endif
 
 
 struct ctrl_ctx_s 
@@ -81,6 +75,48 @@ static app_t current_app;
 static assuan_error_t learn_status_cb (void *opaque, const char *line);
 
 
+/* To avoid cluttering the code with bunches of ifdefs we use a few
+   dummy functions instead and defines. */
+#ifndef ENABLE_AGENT_SUPPORT
+
+#define ASSUAN_LINELENGTH 100
+
+static assuan_context_t 
+agent_open (int try, const char *orig_codeset)
+{
+  return NULL;
+}
+
+void 
+agent_close (assuan_context_t ctx)
+{
+}
+
+const char *
+assuan_strerror (assuan_error_t err)
+{
+  return "no Assuan support";
+}
+
+assuan_error_t 
+assuan_transact (assuan_context_t ctx,
+                 const char *command,
+                 assuan_error_t (*data_cb)(void *, const void *, size_t),
+                 void *data_cb_arg,
+                 assuan_error_t (*inquire_cb)(void*, const char *),
+                 void *inquire_cb_arg,
+                 assuan_error_t (*status_cb)(void*, const char *),
+                 void *status_cb_arg)
+{
+  return 100; /* ASSUAN_NOT_IMPLEMENTED */
+}
+assuan_error_t 
+assuan_send_data (assuan_context_t ctx, const void *buffer, size_t length)
+{
+  return 100; /* ASSUAN_NOT_IMPLEMENTED */
+}  
+#endif /*!ENABLE_AGENT_SUPPORT*/
+
 \f
 /* Create a serialno/fpr string from the serial number and the secret
    key.  caller must free the returned string.  There is no error
@@ -253,9 +289,6 @@ app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp)
 
 
 
-
-
-
 /* Release the card info structure. */
 void 
 agent_release_card_info (struct agent_card_info_s *info)
@@ -280,7 +313,7 @@ agent_release_card_info (struct agent_card_info_s *info)
 }
 
 
-/* Print an error message for a failed assuan-Transact and return a
+/* Print an error message for a failed assuan_transact and return a
    gpg error code. No error is printed if RC is 0. */
 static gpg_error_t
 test_transact (int rc, const char *command)
@@ -304,7 +337,7 @@ open_card_via_agent (int *scd_available)
   int rc;
 
   *scd_available = 0;
-  ctx = agent_open (1);
+  ctx = agent_open (1, NULL);
   if (!ctx)
     return NULL;
 
@@ -351,6 +384,7 @@ open_card (void)
   int rc;
   app_t app;
   int did_shutdown = 0;
+  int retry_count = 0;
 
   /* First check whether we can contact a gpg-agent and divert all
      operation to it. This is required because gpg as well as the
@@ -378,6 +412,7 @@ open_card (void)
       slot = apdu_open_reader (default_reader_port);
       if (slot == -1)
         {
+          write_status_text (STATUS_CARDCTRL, "5");
           log_error ("card reader not available\n");
           return NULL;
         }
@@ -386,7 +421,10 @@ open_card (void)
   app = xcalloc (1, sizeof *app);
   app->slot = slot;
   rc = app_select_openpgp (app);
-  if (rc && !opt.batch)
+  if (opt.limit_card_insert_tries 
+      && ++retry_count >= opt.limit_card_insert_tries)
+    ;
+  else if (rc && !opt.batch)
     {
       write_status_text (STATUS_CARDCTRL, "1");
       
@@ -481,10 +519,24 @@ format_cacheid (const char *sn)
   return cacheid;
 }
 
+
+/* If RC is not 0, write an appropriate status message. */
+static void
+status_sc_op_failure (int rc)
+{
+  if (rc == G10ERR_CANCELED)
+    write_status_text (STATUS_SC_OP_FAILURE, "1");
+  else if (rc == G10ERR_BAD_PASS)
+    write_status_text (STATUS_SC_OP_FAILURE, "2");
+  else if (rc)
+    write_status (STATUS_SC_OP_FAILURE);
+}  
+
+
 /* Check that the serial number of the current card (as described by
    APP) matches SERIALNO.  If there is no match and we are not in
    batch mode, present a prompt to insert the desired card.  The
-   function return 0 is the present card is okay, -1 if the user
+   function returnd 0 if the present card is okay, -1 if the user
    selected to insert a new card or an error value.  Note that the
    card context will be closed in all cases except for 0 as return
    value and if it was possible to merely shutdown the reader. */
@@ -494,7 +546,7 @@ check_card_serialno (app_t app, const char *serialno)
   const char *s;
   int ask = 0;
   int n;
-  
+
   for (s = serialno, n=0; *s != '/' && hexdigitp (s); s++, n++)
     ;
   if (n != 32)
@@ -516,17 +568,20 @@ check_card_serialno (app_t app, const char *serialno)
         did_shutdown = 1;
       else
         card_close ();
-      tty_printf (_("Please remove the current card and "
-                    "insert the one with serial number:\n"
-                    "   %.*s\n"), 32, serialno);
+
+      if (!opt.batch)
+        tty_printf (_("Please remove the current card and "
+                      "insert the one with serial number:\n"
+                      "   %.*s\n"), 32, serialno);
 
       sprintf (buf, "1 %.32s", serialno);
       write_status_text (STATUS_CARDCTRL, buf);
 
-      if ( cpr_get_answer_okay_cancel ("cardctrl.change_card.okay",
-                          _("Hit return when ready "
-                            "or enter 'c' to cancel: "),
-                                       1) )
+      if ( !opt.batch
+           && cpr_get_answer_okay_cancel ("cardctrl.change_card.okay",
+                                          _("Hit return when ready "
+                                            "or enter 'c' to cancel: "),
+                                          1) )
         {
           card_close ();
           return -1;
@@ -841,8 +896,18 @@ pin_cb (void *opaque, const char *info, char **retstr)
 
  again:
   if (is_status_enabled())
-    write_status_text (STATUS_NEED_PASSPHRASE_PIN,
-                       isadmin? "OPENPGP 3" : "OPENPGP 1");
+    {
+      if (parm && parm->sn && *parm->sn)
+        {
+          char *buf = xmalloc ( 10 + strlen (parm->sn) + 1);
+          strcpy (stpcpy (buf, isadmin? "OPENPGP 3 ":"OPENPGP 1 "), parm->sn);
+          write_status_text (STATUS_NEED_PASSPHRASE_PIN, buf);
+          xfree (buf);
+        }
+      else  
+        write_status_text (STATUS_NEED_PASSPHRASE_PIN,
+                           isadmin? "OPENPGP 3" : "OPENPGP 1");
+    }
 
   value = ask_passphrase (info, again_text,
                           newpin && isadmin? "passphrase.adminpin.new.ask" :
@@ -859,7 +924,7 @@ pin_cb (void *opaque, const char *info, char **retstr)
   cacheid = NULL;
   again_text = NULL;
   if (!value && canceled)
-    return -1;
+    return G10ERR_CANCELED;
   else if (!value)
     return G10ERR_GENERAL;
 
@@ -867,16 +932,17 @@ pin_cb (void *opaque, const char *info, char **retstr)
     {
       char *value2;
 
-      value2 = ask_passphrase (info, NULL, NULL,
+      value2 = ask_passphrase (info, NULL,
                                "passphrase.pin.repeat", 
                                _("Repeat this PIN: "),
-                              &canceled);
-      if (!value && canceled)
+                               NULL,
+                               &canceled);
+      if (!value2 && canceled)
         {
           xfree (value);
-          return -1;
+          return G10ERR_CANCELED;
         }
-      else if (!value)
+      else if (!value2)
         {
           xfree (value);
           return G10ERR_GENERAL;
@@ -901,10 +967,15 @@ pin_cb (void *opaque, const char *info, char **retstr)
 /* Send a SETATTR command to the SCdaemon. */
 int 
 agent_scd_setattr (const char *name,
-                   const unsigned char *value, size_t valuelen)
+                   const unsigned char *value, size_t valuelen,
+                   const char *serialno)
 {
   app_t app;
   int rc;
+  struct pincb_parm_s parm;
+
+  memset (&parm, 0, sizeof parm);
+  parm.sn = serialno;
 
   app = current_app? current_app : open_card ();
   if (!app)
@@ -942,11 +1013,10 @@ agent_scd_setattr (const char *name,
     }
   else
     {
-      rc = app->fnc.setattr (app, name, pin_cb, NULL, value, valuelen);
+      rc = app->fnc.setattr (app, name, pin_cb, &parm, value, valuelen);
     }
 
-  if (rc)
-    write_status (STATUS_SC_OP_FAILURE);
+  status_sc_op_failure (rc);
   return rc;
 }
 
@@ -964,11 +1034,17 @@ inq_writekey_parms (void *opaque, const char *keyword)
 
 /* Send a WRITEKEY command to the SCdaemon. */
 int 
-agent_scd_writekey (int keyno, const unsigned char *keydata, size_t keydatalen)
+agent_scd_writekey (int keyno, const char *serialno,
+                    const unsigned char *keydata, size_t keydatalen)
 {
   app_t app;
   int rc;
   char line[ASSUAN_LINELENGTH];
+  struct pincb_parm_s parm;
+
+  memset (&parm, 0, sizeof parm);
+  parm.sn = serialno;
+
   app = current_app? current_app : open_card ();
   if (!app)
     return gpg_error (GPG_ERR_CARD);
@@ -993,12 +1069,11 @@ agent_scd_writekey (int keyno, const unsigned char *keydata, size_t keydatalen)
       snprintf (line, DIM(line)-1, "OPENPGP.%d", keyno);
       line[DIM(line)-1] = 0;
       rc = app->fnc.writekey (app, NULL, line, 0x0001,
-                              pin_cb, NULL,
+                              pin_cb, &parm,
                               keydata, keydatalen);
     }
 
-  if (rc)
-    write_status (STATUS_SC_OP_FAILURE);
+  status_sc_op_failure (rc);
   return rc;
 }
 
@@ -1058,12 +1133,17 @@ genkey_status_cb (void *opaque, const char *line)
 
 /* Send a GENKEY command to the SCdaemon. */
 int 
-agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force)
+agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
+                  const char *serialno)
 {
   app_t app;
   char line[ASSUAN_LINELENGTH];
   struct ctrl_ctx_s ctrl;
   int rc;
+  struct pincb_parm_s parm;
+
+  memset (&parm, 0, sizeof parm);
+  parm.sn = serialno;
 
   app = current_app? current_app : open_card ();
   if (!app)
@@ -1088,11 +1168,10 @@ agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force)
       ctrl.status_cb_arg = info;
       rc = app->fnc.genkey (app, &ctrl, line,
                             force? 1:0,
-                            pin_cb, NULL);
+                            pin_cb, &parm);
     }
 
-  if (rc)
-    write_status (STATUS_SC_OP_FAILURE);
+  status_sc_op_failure (rc);
   return rc;
 }
 
@@ -1174,7 +1253,7 @@ agent_scd_pksign (const char *serialno, int hashalgo,
 
   if (rc)
     {
-      write_status (STATUS_SC_OP_FAILURE);
+      status_sc_op_failure (rc);
       if (!app->assuan_ctx)
         agent_clear_pin_cache (serialno);
     }
@@ -1248,20 +1327,26 @@ agent_scd_pkdecrypt (const char *serialno,
 
   if (rc)
     {
-      write_status (STATUS_SC_OP_FAILURE);
+      status_sc_op_failure (rc);
       if (!app->assuan_ctx)
         agent_clear_pin_cache (serialno);
     }
   return rc;
 }
 
-/* Change the PIN of an OpenPGP card or reset the retry counter. */
+/* Change the PIN of an OpenPGP card or reset the retry
+   counter. SERIALNO may be NULL or a hex string finally passed to the
+   passphrase callback. */
 int 
-agent_scd_change_pin (int chvno)
+agent_scd_change_pin (int chvno, const char *serialno)
 {
   app_t app;
   int reset = 0;
   int rc;
+  struct pincb_parm_s parm;
+
+  memset (&parm, 0, sizeof parm);
+  parm.sn = serialno;
 
   reset = (chvno >= 100);
   chvno %= 100;
@@ -1287,11 +1372,10 @@ agent_scd_change_pin (int chvno)
 
       sprintf (chvnostr, "%d", chvno);
       rc = app->fnc.change_pin (app, NULL, chvnostr, reset,
-                                pin_cb, NULL);
+                                pin_cb, &parm);
     }
 
-  if (rc)
-    write_status (STATUS_SC_OP_FAILURE);
+  status_sc_op_failure (rc);
   return rc;
 }
 
@@ -1303,6 +1387,10 @@ agent_scd_checkpin (const char *serialnobuf)
 {
   app_t app;
   int rc;
+  struct pincb_parm_s parm;
+
+  memset (&parm, 0, sizeof parm);
+  parm.sn = serialnobuf;
 
   app = current_app? current_app : open_card ();
   if (!app)
@@ -1321,11 +1409,10 @@ agent_scd_checkpin (const char *serialnobuf)
     }
   else
     {
-      rc = app->fnc.check_pin (app, serialnobuf, pin_cb, NULL);
+      rc = app->fnc.check_pin (app, serialnobuf, pin_cb, &parm);
     }
 
-  if (rc)
-    write_status (STATUS_SC_OP_FAILURE);
+  status_sc_op_failure (rc);
   return rc;
 }