dirmngr: Fix memory leak.
[gnupg.git] / dirmngr / server.c
index d2682ea..6094bc9 100644 (file)
 
 #include "crlcache.h"
 #include "crlfetch.h"
-#include "ldapserver.h"
+#if USE_LDAP
+# include "ldapserver.h"
+#endif
 #include "ocsp.h"
 #include "certcache.h"
 #include "validate.h"
 #include "misc.h"
-#include "ldap-wrapper.h"
+#if USE_LDAP
+# include "ldap-wrapper.h"
+#endif
 #include "ks-action.h"
 #include "ks-engine.h"  /* (ks_hkp_print_hosttable) */
 
@@ -298,6 +302,32 @@ skip_options (char *line)
 }
 
 
+/* Return an error if the assuan context does not belong to the 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)
@@ -569,6 +599,7 @@ static const char hlp_ldapserver[] =
 static gpg_error_t
 cmd_ldapserver (assuan_context_t ctx, char *line)
 {
+#if USE_LDAP
   ctrl_t ctrl = assuan_get_pointer (ctx);
   ldap_server_t server;
   ldap_server_t *last_next_p;
@@ -587,6 +618,10 @@ cmd_ldapserver (assuan_context_t ctx, char *line)
     last_next_p = &(*last_next_p)->next;
   *last_next_p = server;
   return leave_cmd (ctx, 0);
+#else
+  (void)line;
+  return leave_cmd (ctx, gpg_error (GPG_ERR_NOT_IMPLEMENTED));
+#endif
 }
 
 
@@ -965,17 +1000,19 @@ static int
 lookup_cert_by_pattern (assuan_context_t ctx, char *line,
                         int single, int cache_only)
 {
-  ctrl_t ctrl = assuan_get_pointer (ctx);
   gpg_error_t err = 0;
   char *p;
   strlist_t sl, list = NULL;
   int truncated = 0, truncation_forced = 0;
   int count = 0;
   int local_count = 0;
+#if USE_LDAP
+  ctrl_t ctrl = assuan_get_pointer (ctx);
   unsigned char *value = NULL;
   size_t valuelen;
   struct ldapserver_iter ldapserver_iter;
   cert_fetch_context_t fetch_context;
+#endif /*USE_LDAP*/
   int any_no_data = 0;
 
   /* Break the line down into an STRLIST */
@@ -1034,6 +1071,7 @@ lookup_cert_by_pattern (assuan_context_t ctx, char *line,
 
   /* Loop over all configured servers unless we want only the
      certificates from the cache.  */
+#if USE_LDAP
   for (ldapserver_iter_begin (&ldapserver_iter, ctrl);
        !cache_only && !ldapserver_iter_end_p (&ldapserver_iter)
         && ldapserver_iter.server->host && !truncation_forced;
@@ -1126,6 +1164,7 @@ lookup_cert_by_pattern (assuan_context_t ctx, char *line,
 
       end_cert_fetch (fetch_context);
     }
+#endif /*USE_LDAP*/
 
  ready:
   if (truncated || truncation_forced)
@@ -1392,10 +1431,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 +1453,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 +1461,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 +1479,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)
@@ -1514,7 +1586,6 @@ cmd_ks_search (assuan_context_t ctx, char *line)
           if (!sl)
             {
               err = gpg_error_from_syserror ();
-              free_strlist (list);
               goto leave;
             }
           sl->flags = 0;
@@ -1535,6 +1606,7 @@ cmd_ks_search (assuan_context_t ctx, char *line)
     }
 
  leave:
+  free_strlist (list);
   return leave_cmd (ctx, err);
 }
 
@@ -1544,7 +1616,8 @@ static const char hlp_ks_get[] =
   "KS_GET {<pattern>}\n"
   "\n"
   "Get the keys matching PATTERN from the configured OpenPGP keyservers\n"
-  "(see command KEYSERVER).  Each pattern should be a keyid or a fingerprint";
+  "(see command KEYSERVER).  Each pattern should be a keyid, a fingerprint,\n"
+  "or an exact name indicastes by the '=' prefix.";
 static gpg_error_t
 cmd_ks_get (assuan_context_t ctx, char *line)
 {
@@ -1574,7 +1647,6 @@ cmd_ks_get (assuan_context_t ctx, char *line)
           if (!sl)
             {
               err = gpg_error_from_syserror ();
-              free_strlist (list);
               goto leave;
             }
           sl->flags = 0;
@@ -1595,6 +1667,7 @@ cmd_ks_get (assuan_context_t ctx, char *line)
     }
 
  leave:
+  free_strlist (list);
   return leave_cmd (ctx, err);
 }
 
@@ -1722,7 +1795,10 @@ cmd_getinfo (assuan_context_t ctx, char *line)
     }
   else if (!strcmp (line, "socket_name"))
     {
-      const char *s = dirmngr_socket_name ();
+      const char *s = dirmngr_user_socket_name ();
+
+      if (!s)
+        s = dirmngr_sys_socket_name ();
 
       if (s)
         err = assuan_send_data (ctx, s, strlen (s));
@@ -1746,30 +1822,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;
 }
 
 
@@ -1855,7 +1929,9 @@ reset_notify (assuan_context_t ctx, char *line)
   ctrl_t ctrl = assuan_get_pointer (ctx);
   (void)line;
 
+#if USE_LDAP
   ldapserver_list_free (ctrl->server_local->ldapservers);
+#endif /*USE_LDAP*/
   ctrl->server_local->ldapservers = NULL;
   return 0;
 }
@@ -1981,9 +2057,11 @@ start_command_handler (assuan_fd_t fd)
         }
     }
 
+#if USE_LDAP
   ldap_wrapper_connection_cleanup (ctrl);
 
   ldapserver_list_free (ctrl->server_local->ldapservers);
+#endif /*USE_LDAP*/
   ctrl->server_local->ldapservers = NULL;
 
   ctrl->server_local->assuan_ctx = NULL;
@@ -2073,7 +2151,7 @@ dirmngr_status_help (ctrl_t ctrl, const char *text)
   return err;
 }
 
-/* Send a tick progress indicator back.  Fixme: This is only does for
+/* Send a tick progress indicator back.  Fixme: This is only done for
    the currently active channel.  */
 gpg_error_t
 dirmngr_tick (ctrl_t ctrl)