dirmngr: Print a WARNING status for DNS config problems.
[gnupg.git] / kbx / keybox-init.c
index 60594e3..6a83f71 100644 (file)
@@ -1,4 +1,4 @@
-/* keybox-init.c - Initalization of the library
+/* keybox-init.c - Initialization of the library
  *     Copyright (C) 2001 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
@@ -14,7 +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, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <unistd.h>
 #include <assert.h>
 
-#include "../common/mischelp.h"
 #include "keybox-defs.h"
+#include "../common/mischelp.h"
 
 static KB_NAME kb_names;
 
 
-/* Register a filename for plain keybox files.  Returns a pointer to
-   be used to create a handles and so on.  Returns NULL to indicate
-   that FNAME has already been registered.  */
-void *
-keybox_register_file (const char *fname, int secret)
+/* Register a filename for plain keybox files.  Returns 0 on success,
+ * GPG_ERR_EEXIST if it has already been registered, or another error
+ * code.  On success or with error code GPG_ERR_EEXIST a token usable
+ * to access the keybox handle is stored at R_TOKEN, NULL is stored
+ * for all other errors.  */
+gpg_error_t
+keybox_register_file (const char *fname, int secret, void **r_token)
 {
   KB_NAME kr;
 
+  *r_token = NULL;
+
   for (kr=kb_names; kr; kr = kr->next)
     {
       if (same_file_p (kr->fname, fname) )
-        return NULL; /* Already registered. */
+        {
+          *r_token = kr;
+          return gpg_error (GPG_ERR_EEXIST); /* Already registered. */
+        }
     }
 
   kr = xtrymalloc (sizeof *kr + strlen (fname));
   if (!kr)
-    return NULL;
+    return gpg_error_from_syserror ();
   strcpy (kr->fname, fname);
   kr->secret = !!secret;
 
   kr->handle_table = NULL;
   kr->handle_table_size = 0;
 
-  /* kr->lockhd = NULL;*/
+  kr->lockhd = NULL;
   kr->is_locked = 0;
   kr->did_full_scan = 0;
   /* keep a list of all issued pointers */
@@ -64,7 +71,8 @@ keybox_register_file (const char *fname, int secret)
 /*      if (!kb_offtbl) */
 /*        kb_offtbl = new_offset_hash_table (); */
 
-  return kr;
+  *r_token = kr;
+  return 0;
 }
 
 int
@@ -77,15 +85,10 @@ keybox_is_writable (void *token)
 
 
 
-/* Create a new handle for the resource associated with TOKEN.  SECRET
-   is just a cross-check.
-
-   The returned handle must be released using keybox_release (). */
-KEYBOX_HANDLE
-keybox_new (void *token, int secret)
+static KEYBOX_HANDLE
+do_keybox_new (KB_NAME resource, int secret, int for_openpgp)
 {
   KEYBOX_HANDLE hd;
-  KB_NAME resource = token;
   int idx;
 
   assert (resource && !resource->secret == !secret);
@@ -94,6 +97,7 @@ keybox_new (void *token, int secret)
     {
       hd->kb = resource;
       hd->secret = !!secret;
+      hd->for_openpgp = for_openpgp;
       if (!resource->handle_table)
         {
           resource->handle_table_size = 3;
@@ -135,6 +139,30 @@ keybox_new (void *token, int secret)
   return hd;
 }
 
+
+/* Create a new handle for the resource associated with TOKEN.  SECRET
+   is just a cross-check.  This is the OpenPGP version.  The returned
+   handle must be released using keybox_release.  */
+KEYBOX_HANDLE
+keybox_new_openpgp (void *token, int secret)
+{
+  KB_NAME resource = token;
+
+  return do_keybox_new (resource, secret, 1);
+}
+
+/* Create a new handle for the resource associated with TOKEN.  SECRET
+   is just a cross-check.  This is the X.509 version.  The returned
+   handle must be released using keybox_release.  */
+KEYBOX_HANDLE
+keybox_new_x509 (void *token, int secret)
+{
+  KB_NAME resource = token;
+
+  return do_keybox_new (resource, secret, 0);
+}
+
+
 void
 keybox_release (KEYBOX_HANDLE hd)
 {
@@ -148,6 +176,7 @@ keybox_release (KEYBOX_HANDLE hd)
           hd->kb->handle_table[idx] = NULL;
     }
   _keybox_release_blob (hd->found.blob);
+  _keybox_release_blob (hd->saved_found.blob);
   if (hd->fp)
     {
       fclose (hd->fp);
@@ -159,6 +188,35 @@ keybox_release (KEYBOX_HANDLE hd)
 }
 
 
+/* Save the current found state in HD for later retrieval by
+   keybox_restore_found_state.  Only one state may be saved.  */
+void
+keybox_push_found_state (KEYBOX_HANDLE hd)
+{
+  if (hd->saved_found.blob)
+    {
+      _keybox_release_blob (hd->saved_found.blob);
+      hd->saved_found.blob = NULL;
+    }
+  hd->saved_found = hd->found;
+  hd->found.blob = NULL;
+}
+
+
+/* Restore the saved found state in HD.  */
+void
+keybox_pop_found_state (KEYBOX_HANDLE hd)
+{
+  if (hd->found.blob)
+    {
+      _keybox_release_blob (hd->found.blob);
+      hd->found.blob = NULL;
+    }
+  hd->found = hd->saved_found;
+  hd->saved_found.blob = NULL;
+}
+
+
 const char *
 keybox_get_resource_name (KEYBOX_HANDLE hd)
 {
@@ -178,7 +236,7 @@ keybox_set_ephemeral (KEYBOX_HANDLE hd, int yes)
 
 
 /* Close the file of the resource identified by HD.  For consistent
-   results this fucntion closes the files of all handles pointing to
+   results this function closes the files of all handles pointing to
    the resource identified by HD.  */
 void
 _keybox_close_file (KEYBOX_HANDLE hd)
@@ -200,3 +258,72 @@ _keybox_close_file (KEYBOX_HANDLE hd)
       }
   assert (!hd->fp);
 }
+
+
+/*
+ * Lock the keybox at handle HD, or unlock if YES is false.
+ */
+gpg_error_t
+keybox_lock (KEYBOX_HANDLE hd, int yes)
+{
+  gpg_error_t err = 0;
+  KB_NAME kb = hd->kb;
+
+  if (!keybox_is_writable (kb))
+    return 0;
+
+  /* Make sure the lock handle has been created.  */
+  if (!kb->lockhd)
+    {
+      kb->lockhd = dotlock_create (kb->fname, 0);
+      if (!kb->lockhd)
+        {
+          err = gpg_error_from_syserror ();
+          log_info ("can't allocate lock for '%s'\n", kb->fname );
+          return err;
+        }
+    }
+
+  if (yes) /* Take the lock.  */
+    {
+      if (!kb->is_locked)
+        {
+#ifdef HAVE_W32_SYSTEM
+            /* Under Windows we need to close the file before we try
+             * to lock it.  This is because another process might have
+             * taken the lock and is using keybox_file_rename to
+             * rename the base file.  How if our dotlock_take below is
+             * waiting for the lock but we have the base file still
+             * open, keybox_file_rename will never succeed as we are
+             * in a deadlock.  */
+          if (hd->fp)
+            {
+              fclose (hd->fp);
+              hd->fp = NULL;
+            }
+#endif /*HAVE_W32_SYSTEM*/
+          if (dotlock_take (kb->lockhd, -1))
+            {
+              err = gpg_error_from_syserror ();
+              log_info ("can't lock '%s'\n", kb->fname );
+            }
+          else
+            kb->is_locked = 1;
+        }
+    }
+  else /* Release the lock.  */
+    {
+      if (kb->is_locked)
+        {
+          if (dotlock_release (kb->lockhd))
+            {
+              err = gpg_error_from_syserror ();
+              log_info ("can't unlock '%s'\n", kb->fname );
+            }
+          else
+            kb->is_locked = 0;
+        }
+   }
+
+  return err;
+}