* command.c (cmd_updatestartuptty): New.
[gnupg.git] / agent / query.c
index a3a7733..d3b42a4 100644 (file)
@@ -1,5 +1,5 @@
 /* query.c - fork of the pinentry to query stuff from the user
- *     Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #define MAX_OPEN_FDS 20
 #endif
 
+
+/* Because access to the pinentry must be serialized (it is and shall
+   be a global mutual dialog) we should better timeout further
+   requests after some time.  2 minutes seem to be a reasonable
+   time. */
+#define LOCK_TIMEOUT  (1*60)
+
+
 static ASSUAN_CONTEXT entry_ctx = NULL;
 #ifdef USE_GNU_PTH
-static pth_mutex_t entry_lock = PTH_MUTEX_INIT;
+static pth_mutex_t entry_lock;
 #endif
 
 /* data to be passed to our callbacks */
@@ -56,10 +64,29 @@ struct entry_parm_s {
 
 
 \f
+/* This function must be called once to initialize this module.  This
+   has to be done before a second thread is spawned.  We can't do the
+   static initialization because Pth emulation code might not be able
+   to do a static init; in particualr, it is not possible for W32. */
+void
+initialize_module_query (void)
+{
+#ifdef USE_GNU_PTH
+  static int initialized;
+
+  if (!initialized)
+    if (pth_mutex_init (&entry_lock))
+      initialized = 1;
+#endif /*USE_GNU_PTH*/
+}
+
+
+
+
 /* Unlock the pinentry so that another thread can start one and
    disconnect that pinentry - we do this after the unlock so that a
    stalled pinentry does not block other threads.  Fixme: We should
-   have a timeout in Assuan for the disconnetc operation. */
+   have a timeout in Assuan for the disconnect operation. */
 static int 
 unlock_pinentry (int rc)
 {
@@ -104,11 +131,23 @@ start_pinentry (CTRL ctrl)
   int i;
 
 #ifdef USE_GNU_PTH
-  if (!pth_mutex_acquire (&entry_lock, 0, NULL))
+ {
+   pth_event_t evt;
+
+   evt = pth_event (PTH_EVENT_TIME, pth_timeout (LOCK_TIMEOUT, 0));
+   if (!pth_mutex_acquire (&entry_lock, 0, evt))
     {
-      log_error ("failed to acquire the entry lock\n");
-      return gpg_error (GPG_ERR_INTERNAL);
+      if (pth_event_occurred (evt))
+        rc = gpg_error (GPG_ERR_TIMEOUT);
+      else
+        rc = gpg_error (GPG_ERR_INTERNAL);
+      pth_event_free (evt, PTH_FREE_THIS);
+      log_error (_("failed to acquire the pinentry lock: %s\n"),
+                 gpg_strerror (rc));
+      return rc;
     }
+   pth_event_free (evt, PTH_FREE_THIS);
+ }
 #endif
 
   if (entry_ctx)
@@ -249,8 +288,10 @@ all_digitsp( const char *s)
    number here and repeat it as long as we have invalid formed
    numbers. */
 int
-agent_askpin (CTRL ctrl,
-              const char *desc_text, struct pin_entry_info_s *pininfo)
+agent_askpin (ctrl_t ctrl,
+              const char *desc_text, const char *prompt_text,
+              const char *initial_errtext,
+              struct pin_entry_info_s *pininfo)
 {
   int rc;
   char line[ASSUAN_LINELENGTH];
@@ -270,7 +311,10 @@ agent_askpin (CTRL ctrl,
     desc_text = _("Please enter your passphrase, so that the secret key "
                   "can be unlocked for this session");
 
-  is_pin = desc_text && strstr (desc_text, "PIN");
+  if (prompt_text)
+    is_pin = !!strstr (prompt_text, "PIN");
+  else
+    is_pin = desc_text && strstr (desc_text, "PIN");
 
   rc = start_pinentry (ctrl);
   if (rc)
@@ -282,13 +326,24 @@ agent_askpin (CTRL ctrl,
   if (rc)
     return unlock_pinentry (map_assuan_err (rc));
 
-  rc = assuan_transact (entry_ctx,
-                        is_pin? "SETPROMPT PIN:"
-                              : "SETPROMPT Passphrase:",
-                        NULL, NULL, NULL, NULL, NULL, NULL);
+  snprintf (line, DIM(line)-1, "SETPROMPT %s",
+            prompt_text? prompt_text : is_pin? "PIN:" : "Passphrase:");
+  line[DIM(line)-1] = 0;
+  rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return unlock_pinentry (map_assuan_err (rc));
 
+
+  if (initial_errtext)
+    { 
+      snprintf (line, DIM(line)-1, "SETERROR %s", initial_errtext);
+      line[DIM(line)-1] = 0;
+      rc = assuan_transact (entry_ctx, line,
+                            NULL, NULL, NULL, NULL, NULL, NULL);
+      if (rc)
+        return unlock_pinentry (map_assuan_err (rc));
+    }
+
   for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
     {
       memset (&parm, 0, sizeof parm);
@@ -301,7 +356,8 @@ agent_askpin (CTRL ctrl,
           snprintf (line, DIM(line)-1, "SETERROR %s (try %d of %d)",
                     errtext, pininfo->failed_tries+1, pininfo->max_tries);
           line[DIM(line)-1] = 0;
-          rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+          rc = assuan_transact (entry_ctx, line,
+                                NULL, NULL, NULL, NULL, NULL, NULL);
           if (rc)
             return unlock_pinentry (map_assuan_err (rc));
           errtext = NULL;