* agent.h (server_control_s): Add connection_fd field.
authorWerner Koch <wk@gnupg.org>
Thu, 29 Jan 2004 20:17:27 +0000 (20:17 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 29 Jan 2004 20:17:27 +0000 (20:17 +0000)
* command.c (start_command_handler): Init it here.
* gpg-agent.c (agent_init_default_ctrl): and here.
* call-scd.c: Add the CTRL arg to all functions calling start_scd
and pass it to start_scd.  Changed all callers
(start_scd): Keep track of the current active connection.
(agent_reset_scd): New.
* command.c (start_command_handler): Call it here.
* learncard.c (agent_handle_learn): Add arg CTRL; changed caller.
(send_cert_back): Ditto.

agent/ChangeLog
agent/agent.h
agent/call-scd.c
agent/command.c
agent/divert-scd.c
agent/gpg-agent.c
agent/learncard.c

index 73b9c45..4cdaade 100644 (file)
@@ -1,3 +1,16 @@
+2004-01-29  Werner Koch  <wk@gnupg.org>
+
+       * agent.h (server_control_s): Add connection_fd field.
+       * command.c (start_command_handler): Init it here.
+       * gpg-agent.c (agent_init_default_ctrl): and here.
+       * call-scd.c: Add the CTRL arg to all functions calling start_scd
+       and pass it to start_scd.  Changed all callers
+       (start_scd): Keep track of the current active connection.
+       (agent_reset_scd): New.
+       * command.c (start_command_handler): Call it here.
+       * learncard.c (agent_handle_learn): Add arg CTRL; changed caller.
+       (send_cert_back): Ditto.
+
 2004-01-28  Werner Koch  <wk@gnupg.org>
 
        * trustlist.c (agent_marktrusted): Check whether the trustlist is
@@ -18,7 +31,7 @@
 
        * findkey.c (agent_key_from_file): Now return an error code so
        that we have more detailed error messages in the upper layers.
-       This fixes the handling pinentry's cancel button. 
+       This fixes the handling of pinentry's cancel button. 
        * pksign.c (agent_pksign): Changed accordingly.
        * pkdecrypt.c (agent_pkdecrypt): Ditto.
        * command.c (cmd_passwd): Ditto.
index 95b0ba4..b70a4ae 100644 (file)
@@ -83,6 +83,7 @@ struct server_local_s;
 
 struct server_control_s {
   struct server_local_s *server_local;
+  int   connection_fd; /* -1 or an identifier for the current connection. */
   char *display;
   char *ttyname;
   char *ttytype;
@@ -98,6 +99,7 @@ struct server_control_s {
 
 };
 typedef struct server_control_s *CTRL;
+typedef struct server_control_s *ctrl_t;
 
 
 struct pin_entry_info_s {
@@ -194,33 +196,38 @@ int divert_generic_cmd (CTRL ctrl, const char *cmdline, void *assuan_context);
 
 
 /*-- call-scd.c --*/
-int agent_card_learn (void (*kpinfo_cb)(void*, const char *),
+int agent_reset_scd (ctrl_t ctrl);
+int agent_card_learn (ctrl_t ctrl,
+                      void (*kpinfo_cb)(void*, const char *),
                       void *kpinfo_cb_arg,
                       void (*certinfo_cb)(void*, const char *),
                       void *certinfo_cb_arg,
                       void (*sinfo_cb)(void*, const char *,
                                        size_t, const char *),
                       void *sinfo_cb_arg);
-int agent_card_serialno (char **r_serialno);
-int agent_card_pksign (const char *keyid,
+int agent_card_serialno (ctrl_t ctrl, char **r_serialno);
+int agent_card_pksign (ctrl_t ctrl,
+                       const char *keyid,
                        int (*getpin_cb)(void *, const char *, char*, size_t),
                        void *getpin_cb_arg,
                        const unsigned char *indata, size_t indatalen,
                        char **r_buf, size_t *r_buflen);
-int agent_card_pkdecrypt (const char *keyid,
+int agent_card_pkdecrypt (ctrl_t ctrl,
+                          const char *keyid,
                           int (*getpin_cb)(void *, const char *, char*,size_t),
                           void *getpin_cb_arg,
                           const unsigned char *indata, size_t indatalen,
                           char **r_buf, size_t *r_buflen);
-int agent_card_readcert (const char *id, char **r_buf, size_t *r_buflen);
-int agent_card_readkey (const char *id, unsigned char **r_buf);
-int agent_card_scd (const char *cmdline,
+int agent_card_readcert (ctrl_t ctrl,
+                         const char *id, char **r_buf, size_t *r_buflen);
+int agent_card_readkey (ctrl_t ctrl, const char *id, unsigned char **r_buf);
+int agent_card_scd (ctrl_t ctrl, const char *cmdline,
                     int (*getpin_cb)(void *, const char *, char*, size_t),
                     void *getpin_cb_arg, void *assuan_context);
 
 
 /*-- learncard.c --*/
-int agent_handle_learn (void *assuan_context);
+int agent_handle_learn (ctrl_t ctrl, void *assuan_context);
 
 
 #endif /*AGENT_H*/
index f205fb0..0bb365c 100644 (file)
@@ -50,6 +50,17 @@ static ASSUAN_CONTEXT scd_ctx = NULL;
 #ifdef USE_GNU_PTH
 static pth_mutex_t scd_lock = PTH_MUTEX_INIT;
 #endif
+/* We need to keep track of the connection currently using the SCD.
+   For a pipe server this is all a NOP becuase the connection will
+   always have the conenction indicator -1.  agent_reset_scd releases
+   the active connection; i.e. sets it back to -1, so that a new
+   connection can start using the SCD.  If we eventually allow
+   multiple SCD session we will either make scdaemon multi-threaded or
+   fork of a new scdaemon and let it see how it can get access to a
+   reader. 
+*/
+static int active_connection_fd = -1;
+static int active_connection = 0;
 
 /* callback parameter for learn card */
 struct learn_parm_s {
@@ -162,9 +173,10 @@ atfork_cb (void *opaque, int where)
 }
 
 
-/* Fork off the SCdaemon if this has not already been done */
+/* Fork off the SCdaemon if this has not already been done.  Note that
+   this fucntion alos locks the daemon.  */
 static int
-start_scd (void)
+start_scd (ctrl_t ctrl)
 {
   int rc;
   const char *pgmname;
@@ -182,9 +194,20 @@ start_scd (void)
 #endif
 
   if (scd_ctx)
-    return 0; /* No need to serialize things because the agent is
-                 expected to tun as a single-thread (or may be in
-                 future using libpth) */
+    {
+      /* If we are not the connection currently using the SCD, return
+         an error. */
+      if (!active_connection)
+        {
+          active_connection_fd = ctrl->connection_fd;
+          active_connection = 1;
+        }
+      else if (ctrl->connection_fd != active_connection_fd)
+        return unlock_scd (gpg_error (GPG_ERR_CONFLICT));
+      
+      /* Okay, we scdaemon already started and used by us. */
+      return 0; 
+    }
 
   if (opt.verbose)
     log_info ("no running SCdaemon - starting it\n");
@@ -226,13 +249,45 @@ start_scd (void)
       return unlock_scd (gpg_error (GPG_ERR_NO_SCDAEMON));
     }
   scd_ctx = ctx;
-  
+  active_connection_fd = ctrl->connection_fd;
+  active_connection = 1;
+
   if (DBG_ASSUAN)
     log_debug ("connection to SCdaemon established\n");
+
   return 0;
 }
 
 
+
+/* Reset the SCD if it has been used. */
+int
+agent_reset_scd (ctrl_t ctrl)
+{
+  int rc = 0;
+
+#ifdef USE_GNU_PTH
+  if (!pth_mutex_acquire (&scd_lock, 0, NULL))
+    {
+      log_error ("failed to acquire the SCD lock for reset\n");
+      return gpg_error (GPG_ERR_INTERNAL);
+    }
+#endif
+  if (active_connection && active_connection_fd == ctrl->connection_fd)
+    {
+      if (scd_ctx)
+        rc = assuan_transact (scd_ctx, "RESET", NULL, NULL,
+                              NULL, NULL, NULL, NULL);
+      active_connection_fd = -1;
+      active_connection = 0;
+    }
+
+  return unlock_scd (map_assuan_err (rc));
+}
+
+
+
+
 \f
 static AssuanError
 learn_status_cb (void *opaque, const char *line)
@@ -264,7 +319,8 @@ learn_status_cb (void *opaque, const char *line)
 /* Perform the learn command and return a list of all private keys
    stored on the card. */
 int
-agent_card_learn (void (*kpinfo_cb)(void*, const char *),
+agent_card_learn (ctrl_t ctrl,
+                  void (*kpinfo_cb)(void*, const char *),
                   void *kpinfo_cb_arg,
                   void (*certinfo_cb)(void*, const char *),
                   void *certinfo_cb_arg,
@@ -274,7 +330,7 @@ agent_card_learn (void (*kpinfo_cb)(void*, const char *),
   int rc;
   struct learn_parm_s parm;
 
-  rc = start_scd ();
+  rc = start_scd (ctrl);
   if (rc)
     return rc;
 
@@ -330,12 +386,12 @@ get_serialno_cb (void *opaque, const char *line)
 /* Return the serial number of the card or an appropriate error.  The
    serial number is returned as a hexstring. */
 int
-agent_card_serialno (char **r_serialno)
+agent_card_serialno (ctrl_t ctrl, char **r_serialno)
 {
   int rc;
   char *serialno = NULL;
 
-  rc = start_scd ();
+  rc = start_scd (ctrl);
   if (rc)
     return rc;
 
@@ -405,7 +461,8 @@ inq_needpin (void *opaque, const char *line)
 
 /* Create a signature using the current card */
 int
-agent_card_pksign (const char *keyid,
+agent_card_pksign (ctrl_t ctrl,
+                   const char *keyid,
                    int (*getpin_cb)(void *, const char *, char*, size_t),
                    void *getpin_cb_arg,
                    const unsigned char *indata, size_t indatalen,
@@ -420,7 +477,7 @@ agent_card_pksign (const char *keyid,
   size_t sigbuflen;
 
   *r_buf = NULL;
-  rc = start_scd ();
+  rc = start_scd (ctrl);
   if (rc)
     return rc;
 
@@ -476,11 +533,12 @@ agent_card_pksign (const char *keyid,
 
 /* Decipher INDATA using the current card. Note that the returned value is */
 int
-agent_card_pkdecrypt (const char *keyid,
-                   int (*getpin_cb)(void *, const char *, char*, size_t),
-                   void *getpin_cb_arg,
-                   const unsigned char *indata, size_t indatalen,
-                   char **r_buf, size_t *r_buflen)
+agent_card_pkdecrypt (ctrl_t ctrl,
+                      const char *keyid,
+                      int (*getpin_cb)(void *, const char *, char*, size_t),
+                      void *getpin_cb_arg,
+                      const unsigned char *indata, size_t indatalen,
+                      char **r_buf, size_t *r_buflen)
 {
   int rc, i;
   char *p, line[ASSUAN_LINELENGTH];
@@ -489,7 +547,7 @@ agent_card_pkdecrypt (const char *keyid,
   size_t len;
 
   *r_buf = NULL;
-  rc = start_scd ();
+  rc = start_scd (ctrl);
   if (rc)
     return rc;
 
@@ -531,7 +589,8 @@ agent_card_pkdecrypt (const char *keyid,
 \f
 /* Read a certificate with ID into R_BUF and R_BUFLEN. */
 int
-agent_card_readcert (const char *id, char **r_buf, size_t *r_buflen)
+agent_card_readcert (ctrl_t ctrl,
+                     const char *id, char **r_buf, size_t *r_buflen)
 {
   int rc;
   char line[ASSUAN_LINELENGTH];
@@ -539,7 +598,7 @@ agent_card_readcert (const char *id, char **r_buf, size_t *r_buflen)
   size_t len;
 
   *r_buf = NULL;
-  rc = start_scd ();
+  rc = start_scd (ctrl);
   if (rc)
     return rc;
 
@@ -567,7 +626,7 @@ agent_card_readcert (const char *id, char **r_buf, size_t *r_buflen)
 /* Read a key with ID and return it in an allocate buffer pointed to
    by r_BUF as a valid S-expression. */
 int
-agent_card_readkey (const char *id, unsigned char **r_buf)
+agent_card_readkey (ctrl_t ctrl, const char *id, unsigned char **r_buf)
 {
   int rc;
   char line[ASSUAN_LINELENGTH];
@@ -575,7 +634,7 @@ agent_card_readkey (const char *id, unsigned char **r_buf)
   size_t len, buflen;
 
   *r_buf = NULL;
-  rc = start_scd ();
+  rc = start_scd (ctrl);
   if (rc)
     return rc;
 
@@ -642,14 +701,14 @@ pass_data_thru (void *opaque, const void *buffer, size_t length)
    mechanism to pass everything verbatim to SCDAEMOPN.  The PIN
    inquirey is handled inside gpg-agent. */
 int
-agent_card_scd (const char *cmdline,
+agent_card_scd (ctrl_t ctrl, const char *cmdline,
                 int (*getpin_cb)(void *, const char *, char*, size_t),
                 void *getpin_cb_arg, void *assuan_context)
 {
   int rc;
   struct inq_needpin_s inqparm;
 
-  rc = start_scd ();
+  rc = start_scd (ctrl);
   if (rc)
     return rc;
 
index 0406ea4..aec48e1 100644 (file)
@@ -579,9 +579,10 @@ cmd_get_confirmation (ASSUAN_CONTEXT ctx, char *line)
 static int
 cmd_learn (ASSUAN_CONTEXT ctx, char *line)
 {
+  ctrl_t ctrl = assuan_get_pointer (ctx);
   int rc;
 
-  rc = agent_handle_learn (has_option (line, "--send")? ctx : NULL);
+  rc = agent_handle_learn (ctrl, has_option (line, "--send")? ctx : NULL);
   if (rc)
     log_error ("command learn failed: %s\n", gpg_strerror (rc));
   return map_to_assuan_status (rc);
@@ -771,6 +772,7 @@ start_command_handler (int listen_fd, int fd)
   else 
     {
       rc = assuan_init_connected_socket_server (&ctx, fd);
+      ctrl.connection_fd = fd;
     }
   if (rc)
     {
@@ -816,6 +818,8 @@ start_command_handler (int listen_fd, int fd)
         }
     }
 
+  /* Reset the SCD if needed. */
+  agent_reset_scd (&ctrl);
 
   assuan_deinit_server (ctx);
   if (ctrl.display)
index 283150a..455d230 100644 (file)
@@ -81,7 +81,7 @@ ask_for_card (CTRL ctrl, const unsigned char *shadow_info, char **r_kid)
 
   for (;;)
     {
-      rc = agent_card_serialno (&serialno);
+      rc = agent_card_serialno (ctrl, &serialno);
       if (!rc)
         {
           log_debug ("detected card with S/N %s\n", serialno);
@@ -108,6 +108,13 @@ ask_for_card (CTRL ctrl, const unsigned char *shadow_info, char **r_kid)
 
       if (!rc)
         {
+          /* We better reset the SCD now.  This is kludge requred
+             because the scdaemon is currently not always able to
+             detect the presence of a card.  With a fully working
+             scdaemon this would not be required; i.e. the pkcs#15
+             support does not require it becuase OpenSC correclty
+             detects a present card. */
+          agent_reset_scd (ctrl);
           if (asprintf (&desc,
                     "%s:%%0A%%0A"
                     "  \"%.*s\"",
@@ -230,7 +237,7 @@ divert_pksign (CTRL ctrl,
   if (rc)
     return rc;
 
-  rc = agent_card_pksign (kid, getpin_cb, ctrl,
+  rc = agent_card_pksign (ctrl, kid, getpin_cb, ctrl,
                           data, ndata, &sigval, &siglen);
   if (!rc)
     *r_sig = sigval;
@@ -294,7 +301,7 @@ divert_pkdecrypt (CTRL ctrl,
   if (rc)
     return rc;
 
-  rc = agent_card_pkdecrypt (kid, getpin_cb, ctrl,
+  rc = agent_card_pkdecrypt (ctrl, kid, getpin_cb, ctrl,
                              ciphertext, ciphertextlen,
                              &plaintext, &plaintextlen);
   if (!rc)
@@ -310,7 +317,7 @@ divert_pkdecrypt (CTRL ctrl,
 int  
 divert_generic_cmd (CTRL ctrl, const char *cmdline, void *assuan_context)
 {
-  return agent_card_scd (cmdline, getpin_cb, ctrl, assuan_context);
+  return agent_card_scd (ctrl, cmdline, getpin_cb, ctrl, assuan_context);
 }
 
 
index 4742011..22537aa 100644 (file)
@@ -784,6 +784,8 @@ agent_exit (int rc)
 void
 agent_init_default_ctrl (struct server_control_s *ctrl)
 {
+  ctrl->connection_fd = -1;
+
   /* Note we ignore malloc errors because we can't do much about it
      and the request will fail anyway shortly after this
      initialization. */
index a76f265..76e8986 100644 (file)
@@ -255,13 +255,13 @@ make_shadow_info (const char *serialno, const char *idstring)
 }
 
 static int
-send_cert_back (const char *id, void *assuan_context)
+send_cert_back (ctrl_t ctrl, const char *id, void *assuan_context)
 {
   int rc;
   char *derbuf;
   size_t derbuflen;
   
-  rc = agent_card_readcert (id, &derbuf, &derbuflen);
+  rc = agent_card_readcert (ctrl, id, &derbuf, &derbuflen);
   if (rc)
     {
       log_error ("error reading certificate: %s\n",
@@ -287,7 +287,7 @@ send_cert_back (const char *id, void *assuan_context)
 /* Perform the learn operation.  If ASSUAN_CONTEXT is not NULL all new
    certificates are send via Assuan */
 int
-agent_handle_learn (void *assuan_context)
+agent_handle_learn (ctrl_t ctrl, void *assuan_context)
 {
   int rc;
   struct kpinfo_cb_parm_s parm;
@@ -313,12 +313,12 @@ agent_handle_learn (void *assuan_context)
   memset (&sparm, 0, sizeof sparm);
 
   /* Check whether a card is present and get the serial number */
-  rc = agent_card_serialno (&serialno);
+  rc = agent_card_serialno (ctrl, &serialno);
   if (rc)
     goto leave;
 
   /* now gather all the available info */
-  rc = agent_card_learn (kpinfo_cb, &parm, certinfo_cb, &cparm,
+  rc = agent_card_learn (ctrl, kpinfo_cb, &parm, certinfo_cb, &cparm,
                          sinfo_cb, &sparm);
   if (!rc && (parm.error || cparm.error || sparm.error))
     rc = parm.error? parm.error : cparm.error? cparm.error : sparm.error;
@@ -354,7 +354,7 @@ agent_handle_learn (void *assuan_context)
           
           if (assuan_context)
             {
-              rc = send_cert_back (citem->id, assuan_context);
+              rc = send_cert_back (ctrl, citem->id, assuan_context);
               if (rc)
                 goto leave;
               citem->done = 1;
@@ -380,7 +380,7 @@ agent_handle_learn (void *assuan_context)
         continue;
       
       /* unknown - store it */
-      rc = agent_card_readkey (item->id, &pubkey);
+      rc = agent_card_readkey (ctrl, item->id, &pubkey);
       if (rc)
         {
           log_debug ("agent_card_readkey failed: %s\n", gpg_strerror (rc));
@@ -430,7 +430,7 @@ agent_handle_learn (void *assuan_context)
             }
           if (!citem)
             {
-              rc = send_cert_back (item->id, assuan_context);
+              rc = send_cert_back (ctrl, item->id, assuan_context);
               if (rc)
                 goto leave;
             }