Fixed yesterday's W32 fix.
[gnupg.git] / g10 / keydb.c
index d2b0cea..3360f63 100644 (file)
@@ -1,11 +1,12 @@
 /* keydb.c - key database dispatcher
- * Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2004, 2005, 
+ *               2008 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,8 +15,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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -28,6 +28,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include "gpg.h"
 #include "util.h"
 #include "options.h"
 #include "main.h" /*try_make_homedir ()*/
@@ -42,7 +43,7 @@ typedef enum {
     KEYDB_RESOURCE_TYPE_NONE = 0,
     KEYDB_RESOURCE_TYPE_KEYRING
 } KeydbResourceType;
-#define MAX_KEYDB_RESOURCES 20
+#define MAX_KEYDB_RESOURCES 40
 
 struct resource_item {
   KeydbResourceType type;
@@ -70,6 +71,136 @@ static int lock_all (KEYDB_HANDLE hd);
 static void unlock_all (KEYDB_HANDLE hd);
 
 
+/* Handle the creation of a keyring if it does not yet exist.  Take
+   into acount that other processes might have the keyring already
+   locked.  This lock check does not work if the directory itself is
+   not yet available. */
+static int
+maybe_create_keyring (char *filename, int force)
+{
+  DOTLOCK lockhd = NULL;
+  IOBUF iobuf;
+  int rc;
+  mode_t oldmask;
+  char *last_slash_in_filename;
+  int save_slash;
+
+  /* A quick test whether the filename already exists. */
+  if (!access (filename, F_OK))
+    return 0;
+
+  /* If we don't want to create a new file at all, there is no need to
+     go any further - bail out right here.  */
+  if (!force) 
+    return gpg_error (GPG_ERR_ENOENT);
+
+  /* First of all we try to create the home directory.  Note, that we
+     don't do any locking here because any sane application of gpg
+     would create the home directory by itself and not rely on gpg's
+     tricky auto-creation which is anyway only done for some home
+     directory name patterns. */
+  last_slash_in_filename = strrchr (filename, DIRSEP_C);
+#if HAVE_W32_SYSTEM
+  {
+    /* Windows may either have a slash or a backslash.  Take care of it.  */
+    char *p = strrchr (filename, '/');
+    if (!last_slash_in_filename || p > last_slash_in_filename)
+      last_slash_in_filename = p;
+  }
+#endif /*HAVE_W32_SYSTEM*/
+  if (!last_slash_in_filename)
+    return gpg_error (GPG_ERR_ENOENT);  /* No slash at all - should
+                                           not happen though.  */
+  save_slash = *last_slash_in_filename;
+  *last_slash_in_filename = 0;
+  if (access(filename, F_OK))
+    { 
+      static int tried;
+      
+      if (!tried)
+        {
+          tried = 1;
+          try_make_homedir (filename);
+        }
+      if (access (filename, F_OK))
+        {
+          rc = gpg_error_from_syserror ();
+          *last_slash_in_filename = save_slash;
+          goto leave;
+        }
+    }
+  *last_slash_in_filename = save_slash;
+
+  /* To avoid races with other instances of gpg trying to create or
+     update the keyring (it is removed during an update for a short
+     time), we do the next stuff in a locked state. */
+  lockhd = create_dotlock (filename);
+  if (!lockhd)
+    {
+      /* A reason for this to fail is that the directory is not
+         writable. However, this whole locking stuff does not make
+         sense if this is the case. An empty non-writable directory
+         with no keyring is not really useful at all. */
+      if (opt.verbose)
+        log_info ("can't allocate lock for `%s'\n", filename );
+
+      if (!force) 
+        return gpg_error (GPG_ERR_ENOENT); 
+      else
+        return gpg_error (GPG_ERR_GENERAL);
+    }
+
+  if ( make_dotlock (lockhd, -1) )
+    {
+      /* This is something bad.  Probably a stale lockfile.  */
+      log_info ("can't lock `%s'\n", filename );
+      rc = G10ERR_GENERAL;
+      goto leave;
+    }
+
+  /* Now the real test while we are locked. */
+  if (!access(filename, F_OK))
+    {
+      rc = 0;  /* Okay, we may access the file now.  */
+      goto leave;
+    }
+
+  /* The file does not yet exist, create it now. */
+  oldmask = umask (077);
+  if (is_secured_filename (filename))
+    {
+      iobuf = NULL;
+      errno = EPERM;
+    }
+  else
+    iobuf = iobuf_create (filename);
+  umask (oldmask);
+  if (!iobuf) 
+    {
+      rc = gpg_error_from_syserror ();
+      log_error ( _("error creating keyring `%s': %s\n"),
+                  filename, strerror(errno));
+      goto leave;
+    }
+
+  if (!opt.quiet)
+    log_info (_("keyring `%s' created\n"), filename);
+
+  iobuf_close (iobuf);
+  /* Must invalidate that ugly cache */
+  iobuf_ioctl (NULL, 2, 0, filename);
+  rc = 0;
+
+ leave:
+  if (lockhd)
+    {
+      release_dotlock (lockhd);
+      destroy_dotlock (lockhd);
+    }
+  return rc;
+}
+
+
 /*
  * Register a resource (which currently may only be a keyring file).
  * The first keyring which is added by this function is
@@ -77,14 +208,14 @@ static void unlock_all (KEYDB_HANDLE hd);
  * Note: this function may be called before secure memory is
  * available.
  * Flag 1 == force
- * Flag 2 == default
+ * Flag 2 == mark resource as primary
+ * Flag 4 == This is a default resources
  */
 int
 keydb_add_resource (const char *url, int flags, int secret)
 {
     static int any_secret, any_public;
     const char *resname = url;
-    IOBUF iobuf = NULL;
     char *filename = NULL;
     int force=(flags&1);
     int rc = 0;
@@ -116,7 +247,7 @@ keydb_add_resource (const char *url, int flags, int secret)
            filename = make_filename (opt.homedir, resname, NULL);
     }
     else
-       filename = m_strdup (resname);
+       filename = xstrdup (resname);
 
     if (!force)
        force = secret? !any_secret : !any_public;
@@ -149,56 +280,9 @@ keydb_add_resource (const char *url, int flags, int secret)
        goto leave;
 
       case KEYDB_RESOURCE_TYPE_KEYRING:
-        if (access(filename, F_OK))
-          { /* file does not exist */
-           mode_t oldmask;
-           char *last_slash_in_filename;
-
-            if (!force) 
-              {
-                rc = G10ERR_OPEN_FILE;
-                goto leave;
-              }
-
-           last_slash_in_filename = strrchr (filename, DIRSEP_C);
-           *last_slash_in_filename = 0;
-           if (access(filename, F_OK))
-              { /* On the first time we try to create the default
-                  homedir and check again. */
-                static int tried;
-                
-                if (!tried)
-                  {
-                    tried = 1;
-                    try_make_homedir (filename);
-                  }
-               if (access (filename, F_OK))
-                  {
-                    rc = G10ERR_OPEN_FILE;
-                    *last_slash_in_filename = DIRSEP_C;
-                    goto leave;
-                  }
-              }
-           *last_slash_in_filename = DIRSEP_C;
-
-           oldmask=umask(077);
-           iobuf = iobuf_create (filename);
-           umask(oldmask);
-           if (!iobuf) 
-              {
-               log_error ( _("error creating keyring `%s': %s\n"),
-                            filename, strerror(errno));
-               rc = G10ERR_OPEN_FILE;
-               goto leave;
-              }
-
-            if (!opt.quiet)
-              log_info (_("keyring `%s' created\n"), filename);
-            iobuf_close (iobuf);
-            iobuf = NULL;
-            /* must invalidate that ugly cache */
-            iobuf_ioctl (NULL, 2, 0, (char*)filename);
-          } /* end file creation */
+        rc = maybe_create_keyring (filename, force);
+        if (rc)
+          goto leave;
 
         if(keyring_register_filename (filename, secret, &token))
          {
@@ -235,12 +319,23 @@ keydb_add_resource (const char *url, int flags, int secret)
 
   leave:
     if (rc)
-       log_error ("keyblock resource `%s': %s\n", filename, g10_errstr(rc));
+      {
+        /* Secret keyrings are not required in all cases.  To avoid
+           having gpg return failure we use log_info here if the
+           rewsource is a secret one and marked as default
+           resource.  */
+        if ((flags&4) && secret)
+          log_info (_("keyblock resource `%s': %s\n"),
+                    filename, g10_errstr(rc));
+        else
+          log_error (_("keyblock resource `%s': %s\n"),
+                     filename, g10_errstr(rc));
+      }
     else if (secret)
        any_secret = 1;
     else
        any_public = 1;
-    m_free (filename);
+    xfree (filename);
     return rc;
 }
 
@@ -253,7 +348,7 @@ keydb_new (int secret)
   KEYDB_HANDLE hd;
   int i, j;
   
-  hd = m_alloc_clear (sizeof *hd);
+  hd = xmalloc_clear (sizeof *hd);
   hd->found = -1;
   
   assert (used_resources <= MAX_KEYDB_RESOURCES);
@@ -271,7 +366,7 @@ keydb_new (int secret)
           hd->active[j].secret = all_resources[i].secret;
           hd->active[j].u.kr = keyring_new (all_resources[i].token, secret);
           if (!hd->active[j].u.kr) {
-            m_free (hd);
+            xfree (hd);
             return NULL; /* fixme: release all previously allocated handles*/
           }
           j++;
@@ -305,7 +400,7 @@ keydb_release (KEYDB_HANDLE hd)
         }
     }
 
-    m_free (hd);
+    xfree (hd);
 }
 
 
@@ -597,7 +692,7 @@ keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved)
  * Rebuild the caches of all key resources.
  */
 void
-keydb_rebuild_caches (void)
+keydb_rebuild_caches (int noisy)
 {
   int i, rc;
   
@@ -610,7 +705,7 @@ keydb_rebuild_caches (void)
         case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
           break;
         case KEYDB_RESOURCE_TYPE_KEYRING:
-          rc = keyring_rebuild_cache (all_resources[i].token);
+          rc = keyring_rebuild_cache (all_resources[i].token,noisy);
           if (rc)
             log_error (_("failed to rebuild keyring cache: %s\n"),
                        g10_errstr (rc));
@@ -653,7 +748,8 @@ keydb_search_reset (KEYDB_HANDLE hd)
  * for a keyblock which contains one of the keys described in the DESC array.
  */
 int 
-keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
+keydb_search2 (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
+              size_t ndesc, size_t *descindex)
 {
     int rc = -1;
 
@@ -666,7 +762,8 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
             BUG(); /* we should never see it here */
             break;
           case KEYDB_RESOURCE_TYPE_KEYRING:
-            rc = keyring_search (hd->active[hd->current].u.kr, desc, ndesc);
+            rc = keyring_search (hd->active[hd->current].u.kr, desc,
+                                ndesc, descindex);
             break;
         }
         if (rc == -1) /* EOF -> switch to next resource */
@@ -678,7 +775,6 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
     return rc; 
 }
 
-
 int
 keydb_search_first (KEYDB_HANDLE hd)
 {
@@ -721,6 +817,3 @@ keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr)
     memcpy (desc.u.fpr, fpr, MAX_FINGERPRINT_LEN);
     return keydb_search (hd, &desc, 1);
 }
-
-
-