* keyserver.c (parse_keyserver_uri): If there is a path present, set the
[gnupg.git] / g10 / keydb.c
index 7b31e2d..b1a7268 100644 (file)
@@ -1,5 +1,5 @@
 /* keydb.c - key database dispatcher
- * Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -15,7 +15,8 @@
  *
  * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
  */
 
 #include <config.h>
@@ -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;
@@ -55,7 +56,7 @@ struct resource_item {
 
 static struct resource_item all_resources[MAX_KEYDB_RESOURCES];
 static int used_resources;
-static void *default_keyring=NULL;
+static void *primary_keyring=NULL;
 
 struct keydb_handle {
   int locked;
@@ -70,6 +71,124 @@ 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;
+
+  /* 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 G10ERR_OPEN_FILE;
+
+  /* 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);
+  *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 = G10ERR_OPEN_FILE;
+          *last_slash_in_filename = DIRSEP_C;
+          goto leave;
+        }
+    }
+  *last_slash_in_filename = DIRSEP_C;
+
+
+  /* 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 G10ERR_OPEN_FILE; 
+      else
+        return G10ERR_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) 
+    {
+      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);
+  /* 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 +196,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;
@@ -100,13 +219,13 @@ keydb_add_resource (const char *url, int flags, int secret)
            rt = KEYDB_RESOURCE_TYPE_KEYRING;
            resname += 11;
        }
-      #if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
+#if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
        else if (strchr (resname, ':')) {
            log_error ("invalid key resource URL `%s'\n", url );
            rc = G10ERR_GENERAL;
            goto leave;
        }
-      #endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
+#endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
     }
 
     if (*resname != DIRSEP_C ) { /* do tilde expansion etc */
@@ -116,7 +235,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,49 +268,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 in this case the process will be
-                  terminated, so that on the next invocation it can
-                  read the options file in on startup */
-               try_make_homedir (filename);
-               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))
          {
@@ -200,7 +279,7 @@ keydb_add_resource (const char *url, int flags, int secret)
            else 
              {
                if(flags&2)
-                 default_keyring=token;
+                 primary_keyring=token;
                all_resources[used_resources].type = rt;
                all_resources[used_resources].u.kr = NULL; /* Not used here */
                all_resources[used_resources].token = token;
@@ -211,10 +290,10 @@ keydb_add_resource (const char *url, int flags, int secret)
        else
          {
            /* This keyring was already registered, so ignore it.
-              However, we can still mark it as default even if it was
+              However, we can still mark it as primary even if it was
               already registered. */
            if(flags&2)
-             default_keyring=token;
+             primary_keyring=token;
          }
        break;
 
@@ -228,12 +307,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;
 }
 
@@ -246,7 +336,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);
@@ -264,7 +354,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++;
@@ -298,7 +388,7 @@ keydb_release (KEYDB_HANDLE hd)
         }
     }
 
-    m_free (hd);
+    xfree (hd);
 }
 
 
@@ -550,12 +640,12 @@ keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved)
   if (rc)
     return rc;
 
-  /* If we have a default set, try that one first */
-  if(default_keyring)
+  /* If we have a primary set, try that one first */
+  if(primary_keyring)
     {
       for ( ; hd->current >= 0 && hd->current < hd->used; hd->current++)
        {
-         if(hd->active[hd->current].token==default_keyring)
+         if(hd->active[hd->current].token==primary_keyring)
            {
              if(keyring_is_writable (hd->active[hd->current].token))
                return 0;
@@ -590,7 +680,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;
   
@@ -603,7 +693,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));
@@ -646,7 +736,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;
 
@@ -659,7 +750,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 */
@@ -671,7 +763,6 @@ keydb_search (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc)
     return rc; 
 }
 
-
 int
 keydb_search_first (KEYDB_HANDLE hd)
 {
@@ -714,6 +805,3 @@ keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr)
     memcpy (desc.u.fpr, fpr, MAX_FINGERPRINT_LEN);
     return keydb_search (hd, &desc, 1);
 }
-
-
-