agent/
[gnupg.git] / agent / trustlist.c
index 19de070..edb0065 100644 (file)
@@ -1,5 +1,5 @@
 /* trustlist.c - Maintain the list of trusted keys
- *     Copyright (C) 2002 Free Software Foundation, Inc.
+ *     Copyright (C) 2002, 2004 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 
 #include "agent.h"
 #include <assuan.h> /* fixme: need a way to avoid assuan calls here */
+#include "i18n.h"
 
 static const char headerblurb[] =
-"# This is the list of trusted keys.  Comments like this one and empty\n"
-"# lines are allowed but keep in mind that the entire file is integrity\n"
+"# This is the list of trusted keys.  Comment lines, like this one, as\n"
+"# well as empty lines are ignored. The entire file may be integrity\n"
 "# protected by the use of a MAC, so changing the file does not make\n"
-"# much sense without the knowledge of the MAC key.  Lines do have a\n"
-"# length limit but this is not serious limitation as the format of the\n"
+"# sense without the knowledge of the MAC key.  Lines do have a length\n"
+"# limit but this is not serious limitation as the format of the\n"
 "# entries is fixed and checked by gpg-agent: A non-comment line starts\n"
-"# with optional white spaces, followed by exactly 40 hex character,\n"
-"# optioanlly followed by a flag character which my either be 'P', 'S'\n"
-"# or '*'. Additional data delimited with by a white space is ignored.\n"
+"# with optional white spaces, followed by the SHA-1 fingerpint in hex,\n"
+"# optionally followed by a flag character which my either be 'P', 'S'\n"
+"# or '*'. Additional data, delimited by white space, is ignored.\n"
+"#\n"
+"# NOTE: You should give the gpg-agent a HUP after editing this file.\n"
 "\n";
 
 
 static FILE *trustfp;
+static int   trustfp_used; /* Counter to track usage of TRUSTFP. */
+static int   reload_trustlist_pending;
 
 
 static int
@@ -94,7 +99,7 @@ static int
 read_list (char *key, int *keyflag)
 {
   int rc;
-  int c, i;
+  int c, i, j;
   char *p, line[256];
   
   if (!trustfp)
@@ -122,16 +127,17 @@ read_list (char *key, int *keyflag)
                                  : GPG_ERR_INCOMPLETE_LINE);
         }
       
-      /* Allow for emty lines and spaces */
+      /* Allow for empty lines and spaces */
       for (p=line; spacep (p); p++)
         ;
     }
   while (!*p || *p == '\n' || *p == '#');
   
-  for (i=0; hexdigitp (p+i) && i < 40; i++)
-    key[i] = p[i] >= 'a'? (p[i] & 0xdf): p[i];
-  key[i] = 0;
-  if (i!=40 || !(spacep (p+i) || p[i] == '\n'))
+  for (i=j=0; (p[i] == ':' || hexdigitp (p+i)) && j < 40; i++)
+    if ( p[i] != ':' )
+      key[j++] = p[i] >= 'a'? (p[i] & 0xdf): p[i];
+  key[j] = 0;
+  if (j!=40 || !(spacep (p+i) || p[i] == '\n'))
     {
       log_error ("invalid formatted fingerprint in trustlist\n");
       return gpg_error (GPG_ERR_BAD_DATA);
@@ -164,7 +170,7 @@ read_list (char *key, int *keyflag)
   return 0;
 }
 
-/* check whether the given fpr is in our trustdb.  We expect FPR to be
+/* Check whether the given fpr is in our trustdb.  We expect FPR to be
    an all uppercase hexstring of 40 characters. */
 int 
 agent_istrusted (const char *fpr)
@@ -173,25 +179,31 @@ agent_istrusted (const char *fpr)
   static char key[41];
   int keyflag;
 
+  trustfp_used++;
   if (trustfp)
     rewind (trustfp);
   while (!(rc=read_list (key, &keyflag)))
     {
       if (!strcmp (key, fpr))
-        return 0;
+        {
+          trustfp_used--;
+          return 0;
+        }
     }
   if (rc != -1)
     {
-      /* error in the trustdb - close it to give the user a chance for
+      /* Error in the trustdb - close it to give the user a chance for
          correction */
-      fclose (trustfp);
+      if (trustfp)
+        fclose (trustfp);
       trustfp = NULL;
     }
+  trustfp_used--;
   return rc;
 }
 
 
-/* write all trust entries to FP */
+/* Write all trust entries to FP. */
 int 
 agent_listtrusted (void *assuan_context)
 {
@@ -199,6 +211,7 @@ agent_listtrusted (void *assuan_context)
   static char key[51];
   int keyflag;
 
+  trustfp_used++;
   if (trustfp)
     rewind (trustfp);
   while (!(rc=read_list (key, &keyflag)))
@@ -213,11 +226,13 @@ agent_listtrusted (void *assuan_context)
     rc = 0;
   if (rc)
     {
-      /* error in the trustdb - close it to give the user a chance for
+      /* Error in the trustdb - close it to give the user a chance for
          correction */
-      fclose (trustfp);
+      if (trustfp)
+        fclose (trustfp);
       trustfp = NULL;
     }
+  trustfp_used--;
   return rc;
 }
 
@@ -252,7 +267,7 @@ agent_marktrusted (CTRL ctrl, const char *name, const char *fpr, int flag)
     }    
   xfree (fname);
 
-
+  trustfp_used++;
   if (trustfp)
     rewind (trustfp);
   while (!(rc=read_list (key, &keyflag)))
@@ -260,57 +275,105 @@ agent_marktrusted (CTRL ctrl, const char *name, const char *fpr, int flag)
       if (!strcmp (key, fpr))
         return 0;
     }
-  fclose (trustfp);
+  if (trustfp)
+    fclose (trustfp);
   trustfp = NULL;
   if (rc != -1)
-    return rc;   /* error in the trustdb */
+    {
+      trustfp_used--;
+      return rc;   /* Error in the trustlist. */
+    }
 
   /* This feature must explicitly been enabled. */
   if (!opt.allow_mark_trusted)
-    return gpg_error (GPG_ERR_NOT_SUPPORTED);
+    {
+      trustfp_used--;
+      return gpg_error (GPG_ERR_NOT_SUPPORTED);
+    }
 
-  /* insert a new one */
+  /* Insert a new one. */
   if (asprintf (&desc,
-                "Please verify that the certificate identified as:%%0A"
-                "  \"%s\"%%0A"
-                "has the fingerprint:%%0A"
-                "  %s", name, fpr) < 0 )
-    return out_of_core ();
-  rc = agent_get_confirmation (ctrl, desc, "Correct", "No");
+                /* TRANSLATORS: This prompt is shown by the Pinentry
+                   and has one special property: A "%%0A" is used by
+                   Pinentry to insert a line break.  The double
+                   percent sign is actually needed because it is also
+                   a printf format string.  If you need to insert a
+                   plain % sign, you need to encode it as "%%25".  The
+                   second "%s" gets replaced by a hexdecimal
+                   fingerprint string whereas the first one receives
+                   the name as store in the certificate. */
+                _("Please verify that the certificate identified as:%%0A"
+                  "  \"%s\"%%0A"
+                  "has the fingerprint:%%0A"
+                  "  %s"), name, fpr) < 0 )
+    {
+      trustfp_used--;
+      return out_of_core ();
+    }
+
+  /* TRANSLATORS: "Correct" is the label of a button and intended to
+     be hit if the fingerprint matches the one of the CA.  The other
+     button is "the default "Cancel" of the Pinentry. */
+  rc = agent_get_confirmation (ctrl, desc, _("Correct"), NULL);
   free (desc);
   if (rc)
-    return rc;
+    {
+      trustfp_used--;
+      return rc;
+    }
 
   if (asprintf (&desc,
-                "Do you ultimately trust%%0A"
-                "  \"%s\"%%0A"
-                "to correctly certify user certificates?",
+                /* TRANSLATORS: This prompt is shown by the Pinentry
+                   and has one special property: A "%%0A" is used by
+                   Pinentry to insert a line break.  The double
+                   percent sign is actually needed because it is also
+                   a printf format string.  If you need to insert a
+                   plain % sign, you need to encode it as "%%25".  The
+                   "%s" gets replaced by the name as store in the
+                   certificate. */
+                _("Do you ultimately trust%%0A"
+                  "  \"%s\"%%0A"
+                  "to correctly certify user certificates?"),
                 name) < 0 )
-    return out_of_core ();
-  rc = agent_get_confirmation (ctrl, desc, "Yes", "No");
+    {
+      trustfp_used--;
+      return out_of_core ();
+    }
+  rc = agent_get_confirmation (ctrl, desc, _("Yes"), _("No"));
   free (desc);
   if (rc)
-    return rc;
+    {
+      trustfp_used--;
+      return rc;
+    }
 
-  /* now check again to avoid duplicates.  Also open in append mode now */
+  /* Now check again to avoid duplicates.  Also open in append mode now. */
   rc = open_list (1);
   if (rc)
-    return rc;
+    {
+      trustfp_used--;
+      return rc;
+    }
   rewind (trustfp);
   while (!(rc=read_list (key, &keyflag)))
     {
       if (!strcmp (key, fpr))
-        return 0;
+        {
+          trustfp_used--;
+          return 0;
+        }
     }
   if (rc != -1)
     {
-      fclose (trustfp);
+      if (trustfp)
+        fclose (trustfp);
       trustfp = NULL;
-      return rc;   /* error in the trustdb */
+      trustfp_used--;
+      return rc;   /* Error in the trustlist. */
     }
   rc = 0;
 
-  /* append the key */
+  /* Append the key. */
   fflush (trustfp);
   fputs ("\n# ", trustfp);
   print_sanitized_string (trustfp, name, 0);
@@ -322,5 +385,33 @@ agent_marktrusted (CTRL ctrl, const char *name, const char *fpr, int flag)
   if (fclose (trustfp))
     rc = gpg_error (gpg_err_code_from_errno (errno));
   trustfp = NULL;
+  trustfp_used--;
   return rc;
 }
+
+
+void
+agent_trustlist_housekeeping (void)
+{
+  if (reload_trustlist_pending && !trustfp_used)
+    {
+      if (trustfp)
+        {
+          fclose (trustfp);
+          trustfp = NULL;
+        }
+      reload_trustlist_pending = 0;
+    }
+}
+
+
+/* Not all editors are editing files in place, thus a changes
+   trustlist.txt won't be recognozed if we keep the file descriptor
+   open. This function may be used to explicitly close that file
+   descriptor, which will force a reopen in turn. */
+void
+agent_reload_trustlist (void)
+{
+  reload_trustlist_pending = 1;
+  agent_trustlist_housekeeping ();
+}