Preparing a release candidate.
[gnupg.git] / agent / trustlist.c
index b5bafa9..a154da8 100644 (file)
@@ -1,11 +1,11 @@
 /* trustlist.c - Maintain the list of trusted keys
- *     Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc.
+ * Copyright (C) 2002, 2004, 2006, 2007 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -14,9 +14,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -44,6 +42,7 @@ struct trustitem_s
     int for_smime:1;      /* Set by '*' or 'S' as first flag. */
     int relax:1;          /* Relax checking of root certificate
                              constraints. */
+    int cm:1;             /* Use chain model for validation. */
   } flags;
   unsigned char fpr[20];  /* The binary fingerprint. */
 };
@@ -53,7 +52,7 @@ typedef struct trustitem_s trustitem_t;
 static trustitem_t *trusttable; 
 static size_t trusttablesize; 
 /* A mutex used to protect the table. */
-static pth_mutex_t trusttable_lock = PTH_MUTEX_INIT;
+static pth_mutex_t trusttable_lock;
 
 
 
@@ -71,6 +70,24 @@ static const char headerblurb[] =
 "\n";
 
 
+/* 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 particular, it is not possible for W32. */
+void
+initialize_module_trustlist (void)
+{
+  static int initialized;
+
+  if (!initialized)
+    {
+      if (!pth_mutex_init (&trusttable_lock))
+        log_fatal ("error initializing mutex: %s\n", strerror (errno));
+      initialized = 1;
+    }
+}
+
+
 
 \f
 static void
@@ -153,7 +170,7 @@ read_one_trustfile (const char *fname, int allow_include,
             }
           /* fixme: Should check for trailing garbage.  */
 
-          etcname = make_filename (GNUPG_SYSCONFDIR, "trustlist.txt", NULL);
+          etcname = make_filename (gnupg_sysconfdir (), "trustlist.txt", NULL);
           if ( !strcmp (etcname, fname) ) /* Same file. */
             log_info (_("statement \"%s\" ignored in `%s', line %d\n"),
                       "include-default", fname, lnr);
@@ -251,6 +268,8 @@ read_one_trustfile (const char *fname, int allow_include,
             }
           else if (n == 5 && !memcmp (p, "relax", 5))
             ti->flags.relax = 1;
+          else if (n == 2 && !memcmp (p, "cm", 2))
+            ti->flags.cm = 1;
           else
             log_error ("flag `%.*s' in `%s', line %d ignored\n",
                        n, p, fname, lnr);
@@ -303,7 +322,7 @@ read_trustfiles (void)
           log_error (_("error opening `%s': %s\n"), fname, gpg_strerror (err));
         }
       xfree (fname);
-      fname = make_filename (GNUPG_SYSCONFDIR, "trustlist.txt", NULL);
+      fname = make_filename (gnupg_sysconfdir (), "trustlist.txt", NULL);
       allow_include = 0;
     }
   err = read_one_trustfile (fname, allow_include,
@@ -380,6 +399,14 @@ agent_istrusted (ctrl_t ctrl, const char *fpr)
                 if (err)
                   return err;
               }
+            else if (ti->flags.cm)
+              {
+                err = agent_write_status (ctrl,
+                                          "TRUSTLISTFLAG", "cm", 
+                                          NULL);
+                if (err)
+                  return err;
+              }
             return 0; /* Trusted. */
           }
     }
@@ -428,13 +455,40 @@ agent_listtrusted (void *assuan_context)
 }
 
 
+/* Create a copy of string with colons inserted after each two bytes.
+   Caller needs to release the string.  In case of a memory failure,
+   NULL is returned.  */
+static char *
+insert_colons (const char *string)
+{
+  char *buffer, *p;
+  size_t n = strlen (string);
+
+  p = buffer = xtrymalloc ( n + (n+2)/3 + 1 );
+  if (!buffer)
+    return NULL;
+  while (*string)
+    {
+      *p++ = *string++;
+      if (*string)
+        {
+          *p++ = *string++;
+          if (*string)
+            *p++ = ':';
+        }
+    }
+  *p = 0;
+
+  return buffer;
+}
+
+
 /* Insert the given fpr into our trustdb.  We expect FPR to be an all
    uppercase hexstring of 40 characters. FLAG is either 'P' or 'C'.
-   This function does first check whether that key has alreay been put
+   This function does first check whether that key has already been put
    into the trustdb and returns success in this case.  Before a FPR
-   actually gets inserted, the user is asked by means of the pin-entry
-   whether this is actual wants he want to do.
-*/
+   actually gets inserted, the user is asked by means of the Pinentry
+   whether this is actual wants he want to do.  */
 gpg_error_t
 agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
 {
@@ -442,6 +496,8 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
   char *desc;
   char *fname;
   FILE *fp;
+  char *fprformatted;
+
 
   /* Check whether we are at all allowed to modify the trustlist.
      This is useful so that the trustlist may be a symlink to a global
@@ -467,6 +523,9 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
     return gpg_error (GPG_ERR_NOT_SUPPORTED);
 
   /* Insert a new one. */
+  fprformatted = insert_colons (fpr);
+  if (!fprformatted)
+    return out_of_core ();
   if (asprintf (&desc,
                 /* TRANSLATORS: This prompt is shown by the Pinentry
                    and has one special property: A "%%0A" is used by
@@ -476,12 +535,15 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
                    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. */
+                   the name as stored in the certificate. */
                 _("Please verify that the certificate identified as:%%0A"
                   "  \"%s\"%%0A"
                   "has the fingerprint:%%0A"
-                  "  %s"), name, fpr) < 0 )
-    return out_of_core ();
+                  "  %s"), name, fprformatted) < 0 )
+    {
+      xfree (fprformatted);
+      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
@@ -492,8 +554,11 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
      gpgsm may stop asking further questions.  We won't do this for
      the second question of course. */
   if (err)
-    return (gpg_err_code (err) == GPG_ERR_NOT_CONFIRMED ? 
-            gpg_err_make (gpg_err_source (err), GPG_ERR_CANCELED) : err);
+    {
+      xfree (fprformatted);
+      return (gpg_err_code (err) == GPG_ERR_NOT_CONFIRMED ? 
+              gpg_err_make (gpg_err_source (err), GPG_ERR_CANCELED) : err);
+    }
 
 
 
@@ -510,12 +575,18 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
                   "  \"%s\"%%0A"
                   "to correctly certify user certificates?"),
                 name) < 0 )
-    return out_of_core ();
+    {
+      xfree (fprformatted);
+      return out_of_core ();
+    }
 
   err = agent_get_confirmation (ctrl, desc, _("Yes"), _("No"));
   free (desc);
   if (err)
-    return err;
+    {
+      xfree (fprformatted);
+      return err;
+    }
 
   /* Now check again to avoid duplicates.  We take the lock to make
      sure that nobody else plays with our file.  Frankly we don't work
@@ -525,6 +596,7 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
   if (!agent_istrusted (ctrl, fpr))
     {
       unlock_trusttable ();
+      xfree (fprformatted);
       return 0; 
     }
 
@@ -539,6 +611,7 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
           log_error ("can't create `%s': %s\n", fname, gpg_strerror (err));
           xfree (fname);
           unlock_trusttable ();
+          xfree (fprformatted);
           return err;
         }
       fputs (headerblurb, fp);
@@ -551,13 +624,14 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
       log_error ("can't open `%s': %s\n", fname, gpg_strerror (err));
       xfree (fname);
       unlock_trusttable ();
+      xfree (fprformatted);
       return err;
     }
 
   /* Append the key. */
   fputs ("\n# ", fp);
   print_sanitized_string (fp, name, 0);
-  fprintf (fp, "\n%s %c\n", fpr, flag);
+  fprintf (fp, "\n%s %c\n", fprformatted, flag);
   if (ferror (fp))
     err = gpg_error_from_syserror ();
   
@@ -568,6 +642,7 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
     agent_reload_trustlist ();
   xfree (fname);
   unlock_trusttable ();
+  xfree (fprformatted);
   return err;
 }