dirmngr: Add command option to mark hosts as dead or alive.
authorWerner Koch <wk@gnupg.org>
Tue, 11 Mar 2014 15:19:41 +0000 (16:19 +0100)
committerWerner Koch <wk@gnupg.org>
Tue, 11 Mar 2014 15:30:36 +0000 (16:30 +0100)
* dirmngr/server.c (cmd_killdirmngr): Factor some code out to ...
(check_owner_permission): here.
(cmd_keyserver): Add options --dead and --alive.
* dirmngr/ks-engine-hkp.c (host_in_pool_p): New.
(ks_hkp_mark_host): New.
--

Also removed the warning that the widnows part has not yet been done.
AFAICS, the current mingw supports the all used socket functions.

dirmngr/ks-engine-hkp.c
dirmngr/ks-engine.h
dirmngr/server.c

index 5d68cce..4075930 100644 (file)
@@ -18,7 +18,6 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#warning fixme Windows part not yet done
 #include <config.h>
 
 #include <stdio.h>
@@ -153,6 +152,19 @@ sort_hostpool (const void *xa, const void *xb)
 }
 
 
+/* Return true if the host with the hosttable index TBLIDX is in POOL.  */
+static int
+host_in_pool_p (int *pool, int tblidx)
+{
+  int i, pidx;
+
+  for (i=0; (pidx = pool[i]) != -1; i++)
+    if (pidx == tblidx && hosttable[pidx])
+      return 1;
+  return 0;
+}
+
+
 /* Select a random host.  Consult TABLE which indices into the global
    hosttable.  Returns index into TABLE or -1 if no host could be
    selected.  */
@@ -374,6 +386,80 @@ mark_host_dead (const char *name)
 }
 
 
+/* Mark a host in the hosttable as dead or - if ALIVE is true - as
+   alive.  If the host NAME does not exist a warning status message is
+   printed.  */
+gpg_error_t
+ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
+{
+  gpg_error_t err = 0;
+  hostinfo_t hi, hi2;
+  int idx, idx2, idx3, n;
+
+  if (!name || !*name || !strcmp (name, "localhost"))
+    return 0;
+
+  idx = find_hostinfo (name);
+  if (idx == -1)
+    return gpg_error (GPG_ERR_NOT_FOUND);
+
+  hi = hosttable[idx];
+  if (alive && hi->dead)
+    {
+      hi->dead = 0;
+      err = ks_printf_help (ctrl, "marking '%s' as alive", name);
+    }
+  else if (!alive && !hi->dead)
+    {
+      hi->dead = 1;
+      err = ks_printf_help (ctrl, "marking '%s' as dead", name);
+    }
+
+  /* If the host is a pool mark all member hosts. */
+  if (!err && hi->pool)
+    {
+      for (idx2=0; !err && (n=hi->pool[idx2]) != -1; idx2++)
+        {
+          assert (n >= 0 && n < hosttable_size);
+
+          if (!alive)
+            {
+              /* Do not mark a host from a pool dead if it is also a
+                 member in another pool.  */
+              for (idx3=0; idx3 < hosttable_size; idx3++)
+                {
+                  if (hosttable[idx3] && hosttable[idx3]
+                      && hosttable[idx3]->pool
+                      && idx3 != idx
+                      && host_in_pool_p (hosttable[idx3]->pool, n))
+                    break;
+                }
+              if (idx3 < hosttable_size)
+                continue;  /* Host is also a member of another pool.  */
+            }
+
+          hi2 = hosttable[n];
+          if (!hi2)
+            ;
+          else if (alive && hi2->dead)
+            {
+              hi2->dead = 0;
+              err = ks_printf_help (ctrl, "marking '%s' as alive",
+                                    hi2->name);
+            }
+          else if (!alive && !hi2->dead)
+            {
+              hi2->dead = 1;
+              err = ks_printf_help (ctrl, "marking '%s' as dead",
+                                    hi2->name);
+            }
+        }
+    }
+
+  return err;
+}
+
+
 /* Debug function to print the entire hosttable.  */
 gpg_error_t
 ks_hkp_print_hosttable (ctrl_t ctrl)
index 01a295c..a2faa75 100644 (file)
@@ -30,6 +30,7 @@ gpg_error_t ks_printf_help (ctrl_t ctrl, const char *format,
 
 /*-- ks-engine-hkp.c --*/
 gpg_error_t ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri);
+gpg_error_t ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive);
 gpg_error_t ks_hkp_print_hosttable (ctrl_t ctrl);
 gpg_error_t ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri);
 gpg_error_t ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
index d2682ea..fb619df 100644 (file)
@@ -298,6 +298,32 @@ skip_options (char *line)
 }
 
 
+/* Return an error if the assuan context does not belong to teh owner
+   of the process or to root.  On error FAILTEXT is set as Assuan
+   error string.  */
+static gpg_error_t
+check_owner_permission (assuan_context_t ctx, const char *failtext)
+{
+#ifdef HAVE_W32_SYSTEM
+  /* Under Windows the dirmngr is always run under the control of the
+     user.  */
+  (void)ctx;
+  (void)failtext;
+#else
+  gpg_err_code_t ec;
+  assuan_peercred_t cred;
+
+  ec = gpg_err_code (assuan_get_peercred (ctx, &cred));
+  if (!ec && cred->uid && cred->uid != getuid ())
+    ec = GPG_ERR_EPERM;
+  if (ec)
+    return set_error (ec, failtext);
+#endif
+  return 0;
+}
+
+
+
 /* Common code for get_cert_local and get_issuer_cert_local. */
 static ksba_cert_t
 do_get_cert_local (ctrl_t ctrl, const char *name, const char *command)
@@ -1392,10 +1418,16 @@ cmd_validate (assuan_context_t ctx, char *line)
 
 \f
 static const char hlp_keyserver[] =
-  "KEYSERVER [--clear|--help] [<uri>]\n"
+  "KEYSERVER [<options>] [<uri>|<host>]\n"
+  "Options are:\n"
+  "  --help\n"
+  "  --clear      Remove all configured keyservers\n"
+  "  --resolve    Resolve HKP host names and rotate\n"
+  "  --hosttable  Print table of known hosts and pools\n"
+  "  --dead       Mark <host> as dead\n"
+  "  --alive      Mark <host> as alive\n"
   "\n"
   "If called without arguments list all configured keyserver URLs.\n"
-  "If called with option \"--clear\" remove all configured keyservers\n"
   "If called with an URI add this as keyserver.  Note that keyservers\n"
   "are configured on a per-session base.  A default keyserver may already be\n"
   "present, thus the \"--clear\" option must be used to get full control.\n"
@@ -1408,6 +1440,7 @@ cmd_keyserver (assuan_context_t ctx, char *line)
   ctrl_t ctrl = assuan_get_pointer (ctx);
   gpg_error_t err = 0;
   int clear_flag, add_flag, help_flag, host_flag, resolve_flag;
+  int dead_flag, alive_flag;
   uri_item_t item = NULL; /* gcc 4.4.5 is not able to detect that it
                              is always initialized.  */
 
@@ -1415,6 +1448,8 @@ cmd_keyserver (assuan_context_t ctx, char *line)
   help_flag = has_option (line, "--help");
   resolve_flag = has_option (line, "--resolve");
   host_flag = has_option (line, "--hosttable");
+  dead_flag = has_option (line, "--dead");
+  alive_flag = has_option (line, "--alive");
   line = skip_options (line);
   add_flag = !!*line;
 
@@ -1431,13 +1466,37 @@ cmd_keyserver (assuan_context_t ctx, char *line)
         goto leave;
     }
 
+  if (alive_flag && dead_flag)
+    {
+      err = set_error (GPG_ERR_ASS_PARAMETER, "no support for zombies");
+      goto leave;
+    }
+  if (dead_flag)
+    {
+      err = check_owner_permission (ctx, "no permission to use --dead");
+      if (err)
+        goto leave;
+    }
+  if (alive_flag || dead_flag)
+    {
+      if (!*line)
+        {
+          err = set_error (GPG_ERR_ASS_PARAMETER, "name of host missing");
+          goto leave;
+        }
+
+      err = ks_hkp_mark_host (ctrl, line, alive_flag);
+      if (err)
+        goto leave;
+    }
+
   if (host_flag)
     {
       err = ks_hkp_print_hosttable (ctrl);
       if (err)
         goto leave;
     }
-  if (resolve_flag || host_flag)
+  if (resolve_flag || host_flag || alive_flag || dead_flag)
     goto leave;
 
   if (add_flag)
@@ -1746,30 +1805,28 @@ static gpg_error_t
 cmd_killdirmngr (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err;
 
   (void)line;
 
   if (opt.system_daemon)
     {
       if (opt.system_service)
-        return set_error (GPG_ERR_NOT_SUPPORTED,
-                          "can't do that whilst running as system service");
-#ifndef HAVE_W32_SYSTEM
-      {
-        gpg_err_code_t ec;
-        assuan_peercred_t cred;
-
-        ec = gpg_err_code (assuan_get_peercred (ctx, &cred));
-        if (!ec && cred->uid)
-          ec = GPG_ERR_EPERM; /* Only root may terminate.  */
-        if (ec)
-          return set_error (ec, "no permission to kill this process");
-      }
-#endif
+        err = set_error (GPG_ERR_NOT_SUPPORTED,
+                         "can't do that whilst running as system service");
+      else
+        err = check_owner_permission (ctx,
+                                      "no permission to kill this process");
     }
+  else
+    err = 0;
 
-  ctrl->server_local->stopme = 1;
-  return gpg_error (GPG_ERR_EOF);
+  if (!err)
+    {
+      ctrl->server_local->stopme = 1;
+      err = gpg_error (GPG_ERR_EOF);
+    }
+  return err;
 }