Replace use of opt.homedir by accessor functions.
[gnupg.git] / dirmngr / dirmngr.c
index 12b74bd..bc71a40 100644 (file)
@@ -1,23 +1,22 @@
-/* dirmngr.c - LDAP access
- *     Copyright (C) 2002 Klarälvdalens Datakonsult AB
- *      Copyright (C) 2003, 2004, 2006, 2007, 2008, 2010 g10 Code GmbH
+/* dirmngr.c - Keyserver and X.509 LDAP access
+ * Copyright (C) 2002 Klarälvdalens Datakonsult AB
+ * Copyright (C) 2003, 2004, 2006, 2007, 2008, 2010, 2011 g10 Code GmbH
+ * Copyright (C) 2014 Werner Koch
  *
- * This file is part of DirMngr.
+ * This file is part of GnuPG.
  *
- * DirMngr is free software; you can redistribute it and/or modify
+ * 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.
  *
- * DirMngr is distributed in the hope that it will be useful,
+ * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * 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., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #endif
 #include <sys/stat.h>
 #include <unistd.h>
-#include <signal.h>
-#include <pth.h>
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+#include <npth.h>
+
+#include "dirmngr-err.h"
 
+#if  HTTP_USE_NTBTLS
+# include <ntbtls.h>
+#elif HTTP_USE_GNUTLS
+# include <gnutls/gnutls.h>
+#endif /*HTTP_USE_GNUTLS*/
 
-#define JNLIB_NEED_LOG_LOGV
+
+#define GNUPG_COMMON_NEED_AFLOCAL
 #include "dirmngr.h"
 
-#include <assuan.h> 
+#include <assuan.h>
 
 #include "certcache.h"
 #include "crlcache.h"
 #include "crlfetch.h"
 #include "misc.h"
-#include "ldapserver.h"
+#if USE_LDAP
+# include "ldapserver.h"
+#endif
 #include "asshelp.h"
+#if USE_LDAP
+# include "ldap-wrapper.h"
+#endif
+#include "../common/init.h"
+#include "gc-opt-flags.h"
+#include "dns-stuff.h"
+
+/* The plain Windows version uses the windows service system.  For
+   example to start the service you may use "sc start dirmngr".
+   WindowsCE does not support this; the service system over there is
+   based on a single process with all services being DLLs - we can't
+   support this easily.  */
+#if defined(HAVE_W32_SYSTEM) && !defined(HAVE_W32CE_SYSTEM)
+# define USE_W32_SERVICE 1
+#endif
+
+#ifndef ENAMETOOLONG
+# define ENAMETOOLONG EINVAL
+#endif
+
 
 enum cmd_and_opt_values {
   aNull = 0,
@@ -60,7 +91,7 @@ enum cmd_and_opt_values {
   oSh            = 's',
   oVerbose       = 'v',
   oNoVerbose = 500,
-  
+
   aServer,
   aDaemon,
   aService,
@@ -77,6 +108,7 @@ enum cmd_and_opt_values {
   oDebugAll,
   oDebugWait,
   oDebugLevel,
+  oGnutlsDebug,
   oNoGreeting,
   oNoOptions,
   oHomedir,
@@ -101,6 +133,7 @@ enum cmd_and_opt_values {
   oOCSPMaxPeriod,
   oOCSPCurrentPeriod,
   oMaxReplies,
+  oHkpCaCert,
   oFakedSystemTime,
   oForce,
   oAllowOCSP,
@@ -108,18 +141,21 @@ enum cmd_and_opt_values {
   oLDAPWrapperProgram,
   oHTTPWrapperProgram,
   oIgnoreCertExtension,
+  oUseTor,
+  oKeyServer,
+  oNameServer,
   aTest
 };
 
 
 
 static ARGPARSE_OPTS opts[] = {
-  
+
   ARGPARSE_group (300, N_("@Commands:\n ")),
 
   ARGPARSE_c (aServer,   "server",  N_("run in server mode (foreground)") ),
   ARGPARSE_c (aDaemon,   "daemon",  N_("run in daemon mode (background)") ),
-#ifdef HAVE_W32_SYSTEM
+#ifdef USE_W32_SERVICE
   ARGPARSE_c (aService,  "service", N_("run as windows service (background)")),
 #endif
   ARGPARSE_c (aListCRLs, "list-crls", N_("list the contents of the CRL cache")),
@@ -171,23 +207,32 @@ static ARGPARSE_OPTS opts[] = {
 
   ARGPARSE_s_s (oOCSPResponder, "ocsp-responder",
                 N_("|URL|use OCSP responder at URL")),
-  ARGPARSE_s_s (oOCSPSigner, "ocsp-signer", 
-                N_("|FPR|OCSP response signed by FPR")), 
+  ARGPARSE_s_s (oOCSPSigner, "ocsp-signer",
+                N_("|FPR|OCSP response signed by FPR")),
   ARGPARSE_s_i (oOCSPMaxClockSkew, "ocsp-max-clock-skew", "@"),
   ARGPARSE_s_i (oOCSPMaxPeriod,    "ocsp-max-period", "@"),
   ARGPARSE_s_i (oOCSPCurrentPeriod, "ocsp-current-period", "@"),
 
-  ARGPARSE_s_i (oMaxReplies, "max-replies", 
+  ARGPARSE_s_i (oMaxReplies, "max-replies",
                 N_("|N|do not return more than N items in one query")),
 
-  ARGPARSE_s_s (oSocketName, "socket-name", N_("|FILE|listen on socket FILE")),
+  ARGPARSE_s_s (oNameServer, "nameserver", "@"),
+  ARGPARSE_s_s (oKeyServer, "keyserver", "@"),
+  ARGPARSE_s_s (oHkpCaCert, "hkp-cacert",
+                N_("|FILE|use the CA certificates in FILE for HKP over TLS")),
+
+  ARGPARSE_s_n (oUseTor, "use-tor", N_("route all network traffic via Tor")),
+
+  ARGPARSE_s_s (oSocketName, "socket-name", "@"),  /* Only for debugging.  */
 
   ARGPARSE_s_u (oFakedSystemTime, "faked-system-time", "@"), /*(epoch time)*/
-  ARGPARSE_p_u (oDebug,    "debug", "@"),
+  ARGPARSE_s_s (oDebug,    "debug", "@"),
   ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
+  ARGPARSE_s_i (oGnutlsDebug, "gnutls-debug", "@"),
+  ARGPARSE_s_i (oGnutlsDebug, "tls-debug", "@"),
   ARGPARSE_s_i (oDebugWait, "debug-wait", "@"),
   ARGPARSE_s_n (oNoGreeting, "no-greeting", "@"),
-  ARGPARSE_s_s (oHomedir, "homedir", "@"),  
+  ARGPARSE_s_s (oHomedir, "homedir", "@"),
   ARGPARSE_s_s (oLDAPWrapperProgram, "ldap-wrapper-program", "@"),
   ARGPARSE_s_s (oHTTPWrapperProgram, "http-wrapper-program", "@"),
   ARGPARSE_s_n (oHonorHTTPProxy, "honor-http-proxy", "@"),
@@ -199,17 +244,34 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_end ()
 };
 
+/* The list of supported debug flags.  */
+static struct debug_flags_s debug_flags [] =
+  {
+    { DBG_X509_VALUE   , "x509"    },
+    { DBG_CRYPTO_VALUE , "crypto"  },
+    { DBG_MEMORY_VALUE , "memory"  },
+    { DBG_CACHE_VALUE  , "cache"   },
+    { DBG_MEMSTAT_VALUE, "memstat" },
+    { DBG_HASHING_VALUE, "hashing" },
+    { DBG_IPC_VALUE    , "ipc"     },
+    { DBG_LOOKUP_VALUE , "lookup"  },
+    { 77, NULL } /* 77 := Do not exit on "help" or "?".  */
+  };
+
 #define DEFAULT_MAX_REPLIES 10
 #define DEFAULT_LDAP_TIMEOUT 100 /* arbitrary large timeout */
 
-/* For the cleanup handler we need to keep track of the socket's name. */
+/* For the cleanup handler we need to keep track of the socket's name.  */
 static const char *socket_name;
+/* If the socket has been redirected, this is the name of the
+   redirected socket..  */
+static const char *redir_socket_name;
 
 /* We need to keep track of the server's nonces (these are dummies for
    POSIX systems). */
 static assuan_sock_nonce_t socket_nonce;
 
-/* Only if this flag has been set we will remove the socket file.  */
+/* Only if this flag has been set will we remove the socket file.  */
 static int cleanup_socket;
 
 /* Keep track of the current log file so that we can avoid updating
@@ -219,6 +281,9 @@ static char *current_logfile;
 /* Helper to implement --debug-level. */
 static const char *debug_level;
 
+/* Helper to set the NTBTLS or GNUTLS log level.  */
+static int opt_gnutls_debug = -1;
+
 /* Flag indicating that a shutdown has been requested.  */
 static volatile int shutdown_pending;
 
@@ -227,16 +292,21 @@ static int active_connections;
 
 /* The timer tick used for housekeeping stuff.  For Windows we use a
    longer period as the SetWaitableTimer seems to signal earlier than
-   the 2 seconds.  */
-#ifdef HAVE_W32_SYSTEM
-#define TIMERTICK_INTERVAL    (4)
+   the 2 seconds.  All values are in seconds. */
+#if defined(HAVE_W32CE_SYSTEM)
+# define TIMERTICK_INTERVAL         (60)
+#elif defined(HAVE_W32_SYSTEM)
+# define TIMERTICK_INTERVAL          (4)
 #else
-#define TIMERTICK_INTERVAL    (2)    /* Seconds.  */
+# define TIMERTICK_INTERVAL          (2)
 #endif
 
+#define HOUSEKEEPING_INTERVAL      (600)
+
+
 /* This union is used to avoid compiler warnings in case a pointer is
    64 bit and an int 32 bit.  We store an integer in a pointer and get
-   it back later (pth_key_getdata et al.).  */
+   it back later (npth_getspecific et al.).  */
 union int_and_ptr_u
 {
   int  aint;
@@ -248,33 +318,29 @@ union int_and_ptr_u
 
 /* The key used to store the current file descriptor in the thread
    local storage.  We use this in conjunction with the
-   log_set_pid_suffix_cb feature..  */
+   log_set_pid_suffix_cb feature.  */
 #ifndef HAVE_W32_SYSTEM
 static int my_tlskey_current_fd;
 #endif
 
 /* Prototypes. */
 static void cleanup (void);
+#if USE_LDAP
 static ldap_server_t parse_ldapserver_file (const char* filename);
+#endif /*USE_LDAP*/
 static fingerprint_list_t parse_ocsp_signer (const char *string);
 static void handle_connections (assuan_fd_t listen_fd);
 
-/* Pth wrapper function definitions. */
-ASSUAN_SYSTEM_PTH_IMPL;
-
-GCRY_THREAD_OPTION_PTH_IMPL;
-static int fixed_gcry_pth_init (void)
-{
-  return pth_self ()? 0 : (pth_init () == FALSE) ? errno : 0;
-}
+/* NPth wrapper function definitions. */
+ASSUAN_SYSTEM_NPTH_IMPL;
 
 static const char *
 my_strusage( int level )
 {
   const char *p;
-  switch ( level ) 
+  switch ( level )
     {
-    case 11: p = "dirmngr (GnuPG)";
+    case 11: p = "@DIRMNGR@ (@GNUPG@)";
       break;
     case 13: p = VERSION; break;
     case 17: p = PRINTABLE_OS_NAME; break;
@@ -284,12 +350,12 @@ my_strusage( int level )
     case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
     case 49: p = PACKAGE_BUGREPORT; break;
     case 1:
-    case 40: p = _("Usage: dirmngr [options] (-h for help)");
+    case 40: p = _("Usage: @DIRMNGR@ [options] (-h for help)");
       break;
-    case 41: p = _("Syntax: dirmngr [options] [command [args]]\n"
-                   "LDAP and OCSP access for GnuPG\n");
+    case 41: p = _("Syntax: @DIRMNGR@ [options] [command [args]]\n"
+                   "Keyserver, CRL, and OCSP access for @GNUPG@\n");
       break;
-      
+
     default: p = NULL;
     }
   return p;
@@ -300,23 +366,38 @@ my_strusage( int level )
    implementation does only allow SHA-1 for hashing. This may be
    extended by mapping the name, testing for algorithm availibility
    and adjust the length checks accordingly. */
-static gpg_error_t 
+static gpg_error_t
 my_ksba_hash_buffer (void *arg, const char *oid,
                      const void *buffer, size_t length, size_t resultsize,
                      unsigned char *result, size_t *resultlen)
 {
   (void)arg;
 
-  if (oid && strcmp (oid, "1.3.14.3.2.26")) 
-    return gpg_error (GPG_ERR_NOT_SUPPORTED); 
+  if (oid && strcmp (oid, "1.3.14.3.2.26"))
+    return gpg_error (GPG_ERR_NOT_SUPPORTED);
   if (resultsize < 20)
     return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
-  gcry_md_hash_buffer (2, result, buffer, length); 
+  gcry_md_hash_buffer (2, result, buffer, length);
   *resultlen = 20;
   return 0;
 }
 
 
+/* GNUTLS log function callback.  */
+#ifdef HTTP_USE_GNUTLS
+static void
+my_gnutls_log (int level, const char *text)
+{
+  int n;
+
+  n = strlen (text);
+  while (n && text[n-1] == '\n')
+    n--;
+
+  log_debug ("gnutls:L%d: %.*s\n", level, n, text);
+}
+#endif /*HTTP_USE_GNUTLS*/
+
 /* Setup the debugging.  With a LEVEL of NULL only the active debug
    flags are propagated to the subsystems.  With LEVEL set, a specific
    set of debug flags is set; thus overriding all flags already
@@ -332,11 +413,11 @@ set_debug (void)
   else if (!strcmp (debug_level, "none") || (numok && numlvl < 1))
     opt.debug = 0;
   else if (!strcmp (debug_level, "basic") || (numok && numlvl <= 2))
-    opt.debug = DBG_ASSUAN_VALUE;
+    opt.debug = DBG_IPC_VALUE;
   else if (!strcmp (debug_level, "advanced") || (numok && numlvl <= 5))
-    opt.debug = (DBG_ASSUAN_VALUE|DBG_X509_VALUE|DBG_LOOKUP_VALUE);
+    opt.debug = (DBG_IPC_VALUE|DBG_X509_VALUE|DBG_LOOKUP_VALUE);
   else if (!strcmp (debug_level, "expert") || (numok && numlvl <= 8))
-    opt.debug = (DBG_ASSUAN_VALUE|DBG_X509_VALUE|DBG_LOOKUP_VALUE
+    opt.debug = (DBG_IPC_VALUE|DBG_X509_VALUE|DBG_LOOKUP_VALUE
                  |DBG_CACHE_VALUE|DBG_CRYPTO_VALUE);
   else if (!strcmp (debug_level, "guru") || numok)
     {
@@ -344,13 +425,13 @@ set_debug (void)
       /* Unless the "guru" string has been used we don't want to allow
          hashing debugging.  The rationale is that people tend to
          select the highest debug value and would then clutter their
-         disk with debug files which may reveal confidential data.  */ 
+         disk with debug files which may reveal confidential data.  */
       if (numok)
         opt.debug &= ~(DBG_HASHING_VALUE);
     }
   else
     {
-      log_error (_("invalid debug-level `%s' given\n"), debug_level);
+      log_error (_("invalid debug-level '%s' given\n"), debug_level);
       log_info (_("valid debug levels are: %s\n"),
                 "none, basic, advanced, expert, guru");
       opt.debug = 0; /* Reset debugging, so that prior debug
@@ -368,42 +449,46 @@ set_debug (void)
 
   if (opt.debug & DBG_CRYPTO_VALUE )
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
+
+#if HTTP_USE_NTBTLS
+  if (opt_gnutls_debug >= 0)
+    {
+      ntbtls_set_debug (opt_gnutls_debug, NULL, NULL);
+    }
+#elif HTTP_USE_GNUTLS
+  if (opt_gnutls_debug >= 0)
+    {
+      gnutls_global_set_log_function (my_gnutls_log);
+      gnutls_global_set_log_level (opt_gnutls_debug);
+    }
+#endif /*HTTP_USE_GNUTLS*/
+
+  if (opt.debug)
+    parse_debug_flag (NULL, &opt.debug, debug_flags);
 }
+
 
 static void
-wrong_args (const char *text)
+set_tor_mode (void)
 {
-  fputs (_("usage: dirmngr [options] "), stderr);
-  fputs (text, stderr);
-  putc ('\n', stderr);
-  dirmngr_exit (2);
+  if (opt.use_tor)
+    {
+      if (assuan_sock_set_flag (ASSUAN_INVALID_FD, "tor-mode", 1))
+        {
+          log_error ("error enabling Tor mode: %s\n", strerror (errno));
+          log_info ("(is your Libassuan recent enough?)\n");
+        }
+    }
 }
 
 
-/* Helper to start the reaper thread for the ldap wrapper.  */
 static void
-launch_reaper_thread (void)
+wrong_args (const char *text)
 {
-  static int done;
-  pth_attr_t tattr;
-
-  if (done)
-    return;
-  done = 1;
-
-  tattr = pth_attr_new();
-  pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
-  pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
-  pth_attr_set (tattr, PTH_ATTR_NAME, "ldap-reaper");
-
-  if (!pth_spawn (tattr, ldap_wrapper_thread, NULL))
-    {
-      log_error (_("error spawning ldap wrapper reaper thread: %s\n"),
-                 strerror (errno) );
-      dirmngr_exit (1);
-    }
-  pth_attr_destroy (tattr);
+  es_fprintf (es_stderr, _("usage: %s [options] "), DIRMNGR_NAME);
+  es_fputs (text, es_stderr);
+  es_putc ('\n', es_stderr);
+  dirmngr_exit (2);
 }
 
 
@@ -411,7 +496,9 @@ launch_reaper_thread (void)
 static void
 shutdown_reaper (void)
 {
+#if USE_LDAP
   ldap_wrapper_wait_connections ();
+#endif
 }
 
 
@@ -430,10 +517,10 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
       opt.debug = 0;
       opt.ldap_wrapper_program = NULL;
       opt.disable_http = 0;
-      opt.disable_ldap = 0; 
-      opt.honor_http_proxy = 0; 
-      opt.http_proxy = NULL; 
-      opt.ldap_proxy = NULL; 
+      opt.disable_ldap = 0;
+      opt.honor_http_proxy = 0;
+      opt.http_proxy = NULL;
+      opt.ldap_proxy = NULL;
       opt.only_ldap_proxy = 0;
       opt.ignore_http_dp = 0;
       opt.ignore_ldap_dp = 0;
@@ -451,6 +538,9 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
           opt.ocsp_signer = tmp;
         }
       FREE_STRLIST (opt.ignored_cert_extensions);
+      http_register_tls_ca (NULL);
+      FREE_STRLIST (opt.keyserver);
+      /* Note: We do not allow resetting of opt.use_tor at runtime.  */
       return 1;
     }
 
@@ -458,9 +548,12 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
     {
     case oQuiet:   opt.quiet = 1; break;
     case oVerbose: opt.verbose++; break;
-    case oDebug:   opt.debug |= pargs->r.ret_ulong; break;
+    case oDebug:
+      parse_debug_flag (pargs->r.ret_str, &opt.debug, debug_flags);
+      break;
     case oDebugAll: opt.debug = ~0; break;
     case oDebugLevel: debug_level = pargs->r.ret_str; break;
+    case oGnutlsDebug: opt_gnutls_debug = pargs->r.ret_int; break;
 
     case oLogFile:
       if (!reread)
@@ -493,7 +586,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
 
     case oAllowOCSP: opt.allow_ocsp = 1; break;
     case oOCSPResponder: opt.ocsp_responder = pargs->r.ret_str; break;
-    case oOCSPSigner: 
+    case oOCSPSigner:
       opt.ocsp_signer = parse_ocsp_signer (pargs->r.ret_str);
       break;
     case oOCSPMaxClockSkew: opt.ocsp_max_clock_skew = pargs->r.ret_int; break;
@@ -502,10 +595,38 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
 
     case oMaxReplies: opt.max_replies = pargs->r.ret_int; break;
 
+    case oHkpCaCert:
+      {
+        char *tmpname;
+
+        /* Do tilde expansion and print a warning if the file can't be
+           accessed.  */
+        tmpname = make_absfilename_try (pargs->r.ret_str, NULL);
+        if (!tmpname || access (tmpname, F_OK))
+          log_info (_("can't access '%s': %s\n"),
+                    tmpname? tmpname : pargs->r.ret_str,
+                    gpg_strerror (gpg_error_from_syserror()));
+        else
+          http_register_tls_ca (tmpname);
+        xfree (tmpname);
+      }
+      break;
+
     case oIgnoreCertExtension:
       add_to_strlist (&opt.ignored_cert_extensions, pargs->r.ret_str);
       break;
 
+    case oUseTor: opt.use_tor = 1; break;
+
+    case oKeyServer:
+      if (*pargs->r.ret_str)
+        add_to_strlist (&opt.keyserver, pargs->r.ret_str);
+      break;
+
+    case oNameServer:
+      set_dns_nameserver (pargs->r.ret_str);
+      break;
+
     default:
       return 0; /* Not handled. */
     }
@@ -514,7 +635,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
 }
 
 
-#ifdef HAVE_W32_SYSTEM
+#ifdef USE_W32_SERVICE
 /* The global status of our service.  */
 SERVICE_STATUS_HANDLE service_handle;
 SERVICE_STATUS service_status;
@@ -523,19 +644,23 @@ DWORD WINAPI
 w32_service_control (DWORD control, DWORD event_type, LPVOID event_data,
                     LPVOID context)
 {
+  (void)event_type;
+  (void)event_data;
+  (void)context;
+
   /* event_type and event_data are not used here.  */
   switch (control)
     {
     case SERVICE_CONTROL_SHUTDOWN:
       /* For shutdown we will try to force termination.  */
       service_status.dwCurrentState = SERVICE_STOP_PENDING;
-      SetServiceStatus (service_handle, &service_status); 
+      SetServiceStatus (service_handle, &service_status);
       shutdown_pending = 3;
       break;
 
     case SERVICE_CONTROL_STOP:
       service_status.dwCurrentState = SERVICE_STOP_PENDING;
-      SetServiceStatus (service_handle, &service_status); 
+      SetServiceStatus (service_handle, &service_status);
       shutdown_pending = 1;
       break;
 
@@ -544,7 +669,7 @@ w32_service_control (DWORD control, DWORD event_type, LPVOID event_data,
     }
   return 0;
 }
-#endif /*HAVE_W32_SYSTEM*/
+#endif /*USE_W32_SERVICE*/
 
 #ifndef HAVE_W32_SYSTEM
 static int
@@ -552,21 +677,22 @@ pid_suffix_callback (unsigned long *r_suffix)
 {
   union int_and_ptr_u value;
 
-  value.aptr = pth_key_getdata (my_tlskey_current_fd);
+  memset (&value, 0, sizeof value);
+  value.aptr = npth_getspecific (my_tlskey_current_fd);
   *r_suffix = value.aint;
   return (*r_suffix != -1);  /* Use decimal representation.  */
 }
 #endif /*!HAVE_W32_SYSTEM*/
 
 
-#ifdef HAVE_W32_SYSTEM
-#define main real_main
+#ifdef USE_W32_SERVICE
+# define main real_main
 #endif
 int
 main (int argc, char **argv)
 {
-#ifdef HAVE_W32_SYSTEM
-#undef main
+#ifdef USE_W32_SERVICE
+# undef main
 #endif
   enum cmd_and_opt_values cmd = 0;
   ARGPARSE_ARGS pargs;
@@ -583,13 +709,17 @@ main (int argc, char **argv)
   int nodetach = 0;
   int csh_style = 0;
   char *logfile = NULL;
+#if USE_LDAP
   char *ldapfile = NULL;
+#endif /*USE_LDAP*/
   int debug_wait = 0;
   int rc;
   int homedir_seen = 0;
   struct assuan_malloc_hooks malloc_hooks;
 
-#ifdef HAVE_W32_SYSTEM
+  early_system_init ();
+
+#ifdef USE_W32_SERVICE
   /* The option will be set by main() below if we should run as a
      system daemon.  */
   if (opt.system_service)
@@ -608,28 +738,21 @@ main (int argc, char **argv)
       service_status.dwServiceSpecificExitCode = NO_ERROR;
       service_status.dwCheckPoint = 0;
       service_status.dwWaitHint = 10000; /* 10 seconds timeout.  */
-      SetServiceStatus (service_handle, &service_status); 
+      SetServiceStatus (service_handle, &service_status);
     }
-#endif /*HAVE_W32_SYSTEM*/
+#endif /*USE_W32_SERVICE*/
 
   set_strusage (my_strusage);
-  log_set_prefix ("dirmngr", 1|4); 
+  log_set_prefix (DIRMNGR_NAME, 1|4);
 
   /* Make sure that our subsystems are ready.  */
   i18n_init ();
   init_common_subsystems (&argc, &argv);
 
-  /* Libgcrypt requires us to register the threading model first.
-     Note that this will also do the pth_init.  */
-  gcry_threads_pth.init = fixed_gcry_pth_init;
-  rc = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
-  if (rc)
-    {
-      log_fatal ("can't register GNU Pth with Libgcrypt: %s\n",
-                 gpg_strerror (rc));
-    }
+  npth_init ();
+
   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+
  /* Check that the libraries are suitable.  Do it here because
     the option parsing may need services of the libraries. */
 
@@ -643,6 +766,16 @@ main (int argc, char **argv)
   ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free );
   ksba_set_hash_buffer_function (my_ksba_hash_buffer, NULL);
 
+  /* Init TLS library.  */
+#if HTTP_USE_NTBTLS
+  if (!ntbtls_check_version (NEED_NTBTLS_VERSION) )
+    log_fatal( _("%s is too old (need %s, have %s)\n"), "ntbtls",
+               NEED_NTBTLS_VERSION, ntbtls_check_version (NULL) );
+#elif HTTP_USE_GNUTLS
+  rc = gnutls_global_init ();
+  if (rc)
+    log_fatal ("gnutls_global_init failed: %s\n", gnutls_strerror (rc));
+#endif /*HTTP_USE_GNUTLS*/
 
   /* Init Assuan. */
   malloc_hooks.malloc = gcry_malloc;
@@ -651,7 +784,7 @@ main (int argc, char **argv)
   assuan_set_malloc_hooks (&malloc_hooks);
   assuan_set_assuan_log_prefix (log_get_prefix (NULL));
   assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
-  assuan_set_system_hooks (ASSUAN_SYSTEM_PTH);
+  assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
   assuan_sock_init ();
   setup_libassuan_logging (&opt.debug);
 
@@ -662,26 +795,23 @@ main (int argc, char **argv)
   if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
     csh_style = 1;
 
-  opt.homedir = default_homedir ();
-
-  /* Now with Pth running we can set the logging callback.  Our
-     windows implementation does not yet feature the Pth TLS
+    /* Now with NPth running we can set the logging callback.  Our
+     windows implementation does not yet feature the NPth TLS
      functions.  */
 #ifndef HAVE_W32_SYSTEM
-  if (pth_key_create (&my_tlskey_current_fd, NULL))
-    if (pth_key_setdata (my_tlskey_current_fd, NULL))
+  if (npth_key_create (&my_tlskey_current_fd, NULL) == 0)
+    if (npth_setspecific (my_tlskey_current_fd, NULL) == 0)
       log_set_pid_suffix_cb (pid_suffix_callback);
 #endif /*!HAVE_W32_SYSTEM*/
-  
+
   /* Reset rereadable options to default values. */
-  parse_rereadable_options (NULL, 0); 
+  parse_rereadable_options (NULL, 0);
 
   /* LDAP defaults.  */
   opt.add_new_ldapservers = 0;
   opt.ldaptimeout = DEFAULT_LDAP_TIMEOUT;
 
   /* Other defaults.  */
-  socket_name = dirmngr_socket_name ();
 
   /* Check whether we have a config file given on the commandline */
   orig_argc = argc;
@@ -703,7 +833,7 @@ main (int argc, char **argv)
         default_config = 0; /* --no-options */
       else if (pargs.r_opt == oHomedir)
         {
-          opt.homedir = pargs.r.ret_str;
+          gnupg_set_homedir (pargs.r.ret_str);
           homedir_seen = 1;
         }
       else if (pargs.r_opt == aDaemon)
@@ -725,18 +855,26 @@ main (int argc, char **argv)
     }
 
   /* If --daemon has been given on the command line but not --homedir,
-     we switch to /etc/dirmngr as default home directory.  Note, that
+     we switch to /etc/gnupg as default home directory.  Note, that
      this also overrides the GNUPGHOME environment variable.  */
   if (opt.system_daemon && !homedir_seen)
     {
-      opt.homedir = gnupg_sysconfdir ();
-      opt.homedir_data = gnupg_datadir ();
+#ifdef HAVE_W32CE_SYSTEM
+      gnupg_set_homedir (DIRSEP_S "gnupg");
+#else
+      gnupg_set_homedir (gnupg_sysconfdir ());
+#endif
       opt.homedir_cache = gnupg_cachedir ();
+      socket_name = dirmngr_sys_socket_name ();
     }
+  else if (dirmngr_user_socket_name ())
+    socket_name = dirmngr_user_socket_name ();
+  else
+    socket_name = dirmngr_sys_socket_name ();
 
   if (default_config)
-    configname = make_filename (opt.homedir, "dirmngr.conf", NULL );
-  
+    configname = make_filename (gnupg_homedir (), DIRMNGR_NAME".conf", NULL );
+
   argc = orig_argc;
   argv = orig_argv;
   pargs.argc = &argc;
@@ -752,20 +890,20 @@ main (int argc, char **argv)
           if (default_config)
             {
               if( parse_debug )
-                log_info (_("NOTE: no default option file `%s'\n"),
+                log_info (_("Note: no default option file '%s'\n"),
                           configname );
            }
           else
             {
-              log_error (_("option file `%s': %s\n"),
+              log_error (_("option file '%s': %s\n"),
                          configname, strerror(errno) );
               exit(2);
            }
-          xfree (configname); 
+          xfree (configname);
           configname = NULL;
        }
       if (parse_debug && configname )
-        log_info (_("reading options from `%s'\n"), configname );
+        log_info (_("reading options from '%s'\n"), configname );
       default_config = 0;
     }
 
@@ -775,13 +913,13 @@ main (int argc, char **argv)
         continue; /* Already handled */
       switch (pargs.r_opt)
         {
-        case aServer: 
+        case aServer:
         case aDaemon:
         case aService:
-        case aShutdown: 
-        case aFlush: 
-       case aListCRLs: 
-       case aLoadCRL: 
+        case aShutdown:
+        case aFlush:
+       case aListCRLs:
+       case aLoadCRL:
         case aFetchCRL:
        case aGPGConfList:
        case aGPGConfTest:
@@ -792,9 +930,6 @@ main (int argc, char **argv)
         case oVerbose: opt.verbose++; break;
         case oBatch: opt.batch=1; break;
 
-        case oDebug: opt.debug |= pargs.r.ret_ulong; break;
-        case oDebugAll: opt.debug = ~0; break;
-        case oDebugLevel: debug_level = pargs.r.ret_str; break;
         case oDebugWait: debug_wait = pargs.r.ret_int; break;
 
         case oOptions:
@@ -814,10 +949,14 @@ main (int argc, char **argv)
         case oLogFile: logfile = pargs.r.ret_str; break;
         case oCsh: csh_style = 1; break;
         case oSh: csh_style = 0; break;
-       case oLDAPFile: ldapfile = pargs.r.ret_str; break;
+       case oLDAPFile:
+#        if USE_LDAP
+          ldapfile = pargs.r.ret_str;
+#        endif /*USE_LDAP*/
+          break;
        case oLDAPAddServers: opt.add_new_ldapservers = 1; break;
-       case oLDAPTimeout: 
-         opt.ldaptimeout = pargs.r.ret_int; 
+       case oLDAPTimeout:
+         opt.ldaptimeout = pargs.r.ret_int;
          break;
 
         case oFakedSystemTime:
@@ -833,7 +972,7 @@ main (int argc, char **argv)
     }
   if (configfp)
     {
-      fclose( configfp );
+      fclose (configfp);
       configfp = NULL;
       /* Keep a copy of the name so that it can be read on SIGHUP. */
       opt.config_filename = configname;
@@ -847,35 +986,63 @@ main (int argc, char **argv)
   if (nogreeting )
     greeting = 0;
 
-  if (!opt.homedir_data)
-    opt.homedir_data = opt.homedir;
   if (!opt.homedir_cache)
-    opt.homedir_cache = opt.homedir;
+    opt.homedir_cache = xstrdup (gnupg_homedir ());
 
   if (greeting)
     {
-      fprintf (stderr, "%s %s; %s\n",
-               strusage(11), strusage(13), strusage(14) );
-      fprintf (stderr, "%s\n", strusage(15) );
+      es_fprintf (es_stderr, "%s %s; %s\n",
+                  strusage(11), strusage(13), strusage(14) );
+      es_fprintf (es_stderr, "%s\n", strusage(15) );
     }
 
 #ifdef IS_DEVELOPMENT_VERSION
   log_info ("NOTE: this is a development version!\n");
 #endif
 
+  if (opt.use_tor)
+    {
+      log_info ("WARNING: ***************************************\n");
+      log_info ("WARNING: Tor mode (--use-tor) MAY NOT FULLY WORK!\n");
+      log_info ("WARNING: ***************************************\n");
+    }
+
+  /* Print a warning if an argument looks like an option.  */
+  if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN))
+    {
+      int i;
+
+      for (i=0; i < argc; i++)
+        if (argv[i][0] == '-' && argv[i][1] == '-')
+          log_info (_("Note: '%s' is not considered an option\n"), argv[i]);
+    }
+
+  if (!access ("/etc/"DIRMNGR_NAME, F_OK)
+      && !strncmp (gnupg_homedir (), "/etc/", 5))
+    log_info
+      ("NOTE: DirMngr is now a proper part of %s.  The configuration and"
+       " other directory names changed.  Please check that no other version"
+       " of dirmngr is still installed.  To disable this warning, remove the"
+       " directory '/etc/dirmngr'.\n", GNUPG_NAME);
+
   if (gnupg_faked_time_p ())
     {
       gnupg_isotime_t tbuf;
+
+      log_info (_("WARNING: running with faked system time: "));
       gnupg_get_isotime (tbuf);
-      log_info (_("WARNING: running with faked system time %s\n"), tbuf);
+      dump_isotime (tbuf);
+      log_printf ("\n");
     }
 
   set_debug ();
+  set_tor_mode ();
 
   /* Get LDAP server list from file. */
-  if (!ldapfile) 
+#if USE_LDAP
+  if (!ldapfile)
     {
-      ldapfile = make_filename (opt.homedir,
+      ldapfile = make_filename (gnupg_homedir (),
                                 opt.system_daemon?
                                 "ldapservers.conf":"dirmngr_ldapservers.conf",
                                 NULL);
@@ -884,6 +1051,7 @@ main (int argc, char **argv)
     }
   else
       opt.ldapservers = parse_ldapserver_file (ldapfile);
+#endif /*USE_LDAP*/
 
 #ifndef HAVE_W32_SYSTEM
   /* We need to ignore the PIPE signal because the we might log to a
@@ -902,6 +1070,7 @@ main (int argc, char **argv)
 
   if (cmd == aServer)
     {
+      /* Note that this server mode is mainly useful for debugging.  */
       if (argc)
         wrong_args ("--server");
 
@@ -910,7 +1079,7 @@ main (int argc, char **argv)
           log_set_file (logfile);
           log_set_prefix (NULL, 2|4);
         }
-       
+
       if (debug_wait)
         {
           log_debug ("waiting for debugger - my pid is %u .....\n",
@@ -919,7 +1088,10 @@ main (int argc, char **argv)
           log_debug ("... okay\n");
         }
 
-      launch_reaper_thread ();
+#if USE_LDAP
+      ldap_wrapper_launch_thread ();
+#endif /*USE_LDAP*/
+
       cert_cache_init ();
       crl_cache_init ();
       start_command_handler (ASSUAN_INVALID_FD);
@@ -934,14 +1106,14 @@ main (int argc, char **argv)
 
       if (argc)
         wrong_args ("--daemon");
-      
+
       /* Now start with logging to a file if this is desired. */
       if (logfile)
         {
           log_set_file (logfile);
-          log_set_prefix (NULL, (JNLIB_LOG_WITH_PREFIX
-                                 |JNLIB_LOG_WITH_TIME
-                                 |JNLIB_LOG_WITH_PID));
+          log_set_prefix (NULL, (GPGRT_LOG_WITH_PREFIX
+                                 |GPGRT_LOG_WITH_TIME
+                                 |GPGRT_LOG_WITH_PID));
           current_logfile = xstrdup (logfile);
         }
 
@@ -952,12 +1124,6 @@ main (int argc, char **argv)
           dirmngr_exit (1);
         }
 #endif
-      if (strlen (socket_name)+1 >= sizeof serv_addr.sun_path ) 
-        {
-          log_error (_("name of socket too long\n"));
-          dirmngr_exit (1);
-        }
-    
       fd = assuan_sock_new (AF_UNIX, SOCK_STREAM, 0);
       if (fd == ASSUAN_INVALID_FD)
         {
@@ -966,30 +1132,57 @@ main (int argc, char **argv)
           dirmngr_exit (1);
         }
 
-      memset (&serv_addr, 0, sizeof serv_addr);
-      serv_addr.sun_family = AF_UNIX;
-      strcpy (serv_addr.sun_path, socket_name);
-      len = (offsetof (struct sockaddr_un, sun_path)
-             + strlen (serv_addr.sun_path) + 1);
+      {
+        int redirected;
+
+        if (assuan_sock_set_sockaddr_un (socket_name,
+                                         (struct sockaddr*)&serv_addr,
+                                         &redirected))
+          {
+            if (errno == ENAMETOOLONG)
+              log_error (_("socket name '%s' is too long\n"), socket_name);
+            else
+              log_error ("error preparing socket '%s': %s\n",
+                         socket_name,
+                         gpg_strerror (gpg_error_from_syserror ()));
+            dirmngr_exit (1);
+          }
+        if (redirected)
+          {
+            redir_socket_name = xstrdup (serv_addr.sun_path);
+            if (opt.verbose)
+              log_info ("redirecting socket '%s' to '%s'\n",
+                        socket_name, redir_socket_name);
+          }
+      }
+
+      len = SUN_LEN (&serv_addr);
 
       rc = assuan_sock_bind (fd, (struct sockaddr*) &serv_addr, len);
-      if (rc == -1 && errno == EADDRINUSE)
+      if (rc == -1
+          && (errno == EADDRINUSE
+#ifdef HAVE_W32_SYSTEM
+              || errno == EEXIST
+#endif
+              ))
        {
-         remove (socket_name);
+          /* Fixme: We should test whether a dirmngr is already running. */
+         gnupg_remove (redir_socket_name? redir_socket_name : socket_name);
          rc = assuan_sock_bind (fd, (struct sockaddr*) &serv_addr, len);
        }
-      if (rc != -1 
+      if (rc != -1
          && (rc = assuan_sock_get_nonce ((struct sockaddr*) &serv_addr, len, &socket_nonce)))
        log_error (_("error getting nonce for the socket\n"));
       if (rc == -1)
         {
-          log_error (_("error binding socket to `%s': %s\n"),
-                     serv_addr.sun_path, gpg_strerror (gpg_error_from_errno (errno)));
+          log_error (_("error binding socket to '%s': %s\n"),
+                     serv_addr.sun_path,
+                     gpg_strerror (gpg_error_from_errno (errno)));
           assuan_sock_close (fd);
           dirmngr_exit (1);
         }
       cleanup_socket = 1;
-  
+
       if (listen (FD2INT (fd), 5) == -1)
         {
           log_error (_("listen() failed: %s\n"), strerror (errno));
@@ -998,63 +1191,70 @@ main (int argc, char **argv)
         }
 
       if (opt.verbose)
-        log_info (_("listening on socket `%s'\n"), socket_name );
+        log_info (_("listening on socket '%s'\n"), serv_addr.sun_path);
 
-      fflush (NULL);
+      es_fflush (NULL);
 
+      /* Note: We keep the dirmngr_info output only for the sake of
+         existing scripts which might use this to detect a successful
+         start of the dirmngr.  */
 #ifdef HAVE_W32_SYSTEM
+      (void)csh_style;
+      (void)nodetach;
+
       pid = getpid ();
-      printf ("set DIRMNGR_INFO=%s;%lu;1\n", socket_name, (ulong) pid);
+      es_printf ("set %s=%s;%lu;1\n",
+                 DIRMNGR_INFO_NAME, socket_name, (ulong) pid);
 #else
-      pid = pth_fork ();
-      if (pid == (pid_t)-1) 
+      pid = fork();
+      if (pid == (pid_t)-1)
         {
-          log_fatal (_("fork failed: %s\n"), strerror (errno) );
+          log_fatal (_("error forking process: %s\n"), strerror (errno));
           dirmngr_exit (1);
         }
 
-      if (pid) 
+      if (pid)
         { /* We are the parent */
           char *infostr;
-          
+
           /* Don't let cleanup() remove the socket - the child is
              responsible for doing that.  */
           cleanup_socket = 0;
 
           close (fd);
-          
+
           /* Create the info string: <name>:<pid>:<protocol_version> */
-          if (asprintf (&infostr, "DIRMNGR_INFO=%s:%lu:1",
-                        socket_name, (ulong)pid ) < 0)
+          if (asprintf (&infostr, "%s=%s:%lu:1",
+                        DIRMNGR_INFO_NAME, serv_addr.sun_path, (ulong)pid ) < 0)
             {
               log_error (_("out of core\n"));
               kill (pid, SIGTERM);
               dirmngr_exit (1);
             }
           /* Print the environment string, so that the caller can use
-             shell's eval to set it */
+             shell's eval to set it.  But see above.  */
           if (csh_style)
             {
               *strchr (infostr, '=') = ' ';
-              printf ( "setenv %s\n", infostr);
+              es_printf ( "setenv %s;\n", infostr);
             }
           else
             {
-              printf ( "%s; export DIRMNGR_INFO;\n", infostr);
+              es_printf ( "%s; export %s;\n", infostr, DIRMNGR_INFO_NAME);
             }
           free (infostr);
-          exit (0); 
+          exit (0);
           /*NEVER REACHED*/
         } /* end parent */
-      
-      
-      /* 
+
+
+      /*
          This is the child
        */
 
       /* Detach from tty and put process into a new session */
       if (!nodetach )
-        { 
+        {
           int i;
           unsigned int oldflags;
 
@@ -1066,26 +1266,29 @@ main (int argc, char **argv)
             }
           if (setsid() == -1)
             {
-              log_error (_("setsid() failed: %s\n"), strerror(errno) );
+              log_error ("setsid() failed: %s\n", strerror(errno) );
               dirmngr_exit (1);
             }
 
           log_get_prefix (&oldflags);
-          log_set_prefix (NULL, oldflags | JNLIB_LOG_RUN_DETACHED);
+          log_set_prefix (NULL, oldflags | GPGRT_LOG_RUN_DETACHED);
           opt.running_detached = 1;
 
           if (chdir("/"))
             {
-              log_error (_("chdir to / failed: %s\n"), strerror (errno));
+              log_error ("chdir to / failed: %s\n", strerror (errno));
               dirmngr_exit (1);
             }
         }
 #endif
 
-      launch_reaper_thread ();
+#if USE_LDAP
+      ldap_wrapper_launch_thread ();
+#endif /*USE_LDAP*/
+
       cert_cache_init ();
       crl_cache_init ();
-#ifdef HAVE_W32_SYSTEM
+#ifdef USE_W32_SERVICE
       if (opt.system_service)
        {
          service_status.dwCurrentState = SERVICE_RUNNING;
@@ -1095,7 +1298,7 @@ main (int argc, char **argv)
       handle_connections (fd);
       assuan_sock_close (fd);
       shutdown_reaper ();
-#ifdef HAVE_W32_SYSTEM
+#ifdef USE_W32_SERVICE
       if (opt.system_service)
        {
          service_status.dwCurrentState = SERVICE_STOPPED;
@@ -1108,9 +1311,11 @@ main (int argc, char **argv)
       /* Just list the CRL cache and exit. */
       if (argc)
         wrong_args ("--list-crls");
-      launch_reaper_thread ();
+#if USE_LDAP
+      ldap_wrapper_launch_thread ();
+#endif /*USE_LDAP*/
       crl_cache_init ();
-      crl_cache_list (stdout);
+      crl_cache_list (es_stdout);
     }
   else if (cmd == aLoadCRL)
     {
@@ -1119,7 +1324,9 @@ main (int argc, char **argv)
       memset (&ctrlbuf, 0, sizeof ctrlbuf);
       dirmngr_init_default_ctrl (&ctrlbuf);
 
-      launch_reaper_thread ();
+#if USE_LDAP
+      ldap_wrapper_launch_thread ();
+#endif /*USE_LDAP*/
       cert_cache_init ();
       crl_cache_init ();
       if (!argc)
@@ -1129,6 +1336,7 @@ main (int argc, char **argv)
           for (; !rc && argc; argc--, argv++)
             rc = crl_cache_load (&ctrlbuf, *argv);
         }
+      dirmngr_deinit_default_ctrl (&ctrlbuf);
     }
   else if (cmd == aFetchCRL)
     {
@@ -1141,21 +1349,24 @@ main (int argc, char **argv)
       memset (&ctrlbuf, 0, sizeof ctrlbuf);
       dirmngr_init_default_ctrl (&ctrlbuf);
 
-      launch_reaper_thread ();
+#if USE_LDAP
+      ldap_wrapper_launch_thread ();
+#endif /*USE_LDAP*/
       cert_cache_init ();
       crl_cache_init ();
       rc = crl_fetch (&ctrlbuf, argv[0], &reader);
       if (rc)
-        log_error (_("fetching CRL from `%s' failed: %s\n"),
+        log_error (_("fetching CRL from '%s' failed: %s\n"),
                      argv[0], gpg_strerror (rc));
       else
         {
-          rc = crl_cache_insert (&ctrlbuf, argv[0], reader); 
+          rc = crl_cache_insert (&ctrlbuf, argv[0], reader);
           if (rc)
-            log_error (_("processing CRL from `%s' failed: %s\n"),
+            log_error (_("processing CRL from '%s' failed: %s\n"),
                        argv[0], gpg_strerror (rc));
           crl_close_reader (reader);
         }
+      dirmngr_deinit_default_ctrl (&ctrlbuf);
     }
   else if (cmd == aFlush)
     {
@@ -1172,23 +1383,6 @@ main (int argc, char **argv)
       char *filename;
       char *filename_esc;
 
-      /* List options and default values in the GPG Conf format.  */
-
-/* The following list is taken from gnupg/tools/gpgconf-comp.c.  */
-/* Option flags.  YOU MUST NOT CHANGE THE NUMBERS OF THE EXISTING
-   FLAGS, AS THEY ARE PART OF THE EXTERNAL INTERFACE.  */
-#define GC_OPT_FLAG_NONE       0UL
-/* The DEFAULT flag for an option indicates that the option has a
-   default value.  */
-#define GC_OPT_FLAG_DEFAULT    (1UL << 4)
-/* The DEF_DESC flag for an option indicates that the option has a
-   default, which is described by the value of the default field.  */
-#define GC_OPT_FLAG_DEF_DESC   (1UL << 5)
-/* The NO_ARG_DESC flag for an option indicates that the argument has
-   a default, which is described by the value of the ARGDEF field.  */
-#define GC_OPT_FLAG_NO_ARG_DESC        (1UL << 6)
-#define GC_OPT_FLAG_NO_CHANGE   (1UL <<7)
-
 #ifdef HAVE_W32_SYSTEM
       /* On Windows systems, dirmngr always runs as system daemon, and
         the per-user configuration is never used.  So we short-cut
@@ -1201,19 +1395,19 @@ main (int argc, char **argv)
       /* First the configuration file.  This is not an option, but it
         is vital information for GPG Conf.  */
       if (!opt.config_filename)
-        opt.config_filename = make_filename (opt.homedir,
+        opt.config_filename = make_filename (gnupg_homedir (),
                                              "dirmngr.conf", NULL );
 
       filename = percent_escape (opt.config_filename, NULL);
-      printf ("gpgconf-dirmngr.conf:%lu:\"%s\n",
+      es_printf ("gpgconf-dirmngr.conf:%lu:\"%s\n",
               GC_OPT_FLAG_DEFAULT, filename);
       xfree (filename);
 
-      printf ("verbose:%lu:\n", flags | GC_OPT_FLAG_NONE);
-      printf ("quiet:%lu:\n", flags | GC_OPT_FLAG_NONE);
-      printf ("debug-level:%lu:\"none\n", flags | GC_OPT_FLAG_DEFAULT);
-      printf ("log-file:%lu:\n", flags | GC_OPT_FLAG_NONE);
-      printf ("force:%lu:\n", flags | GC_OPT_FLAG_NONE);
+      es_printf ("verbose:%lu:\n", flags | GC_OPT_FLAG_NONE);
+      es_printf ("quiet:%lu:\n", flags | GC_OPT_FLAG_NONE);
+      es_printf ("debug-level:%lu:\"none\n", flags | GC_OPT_FLAG_DEFAULT);
+      es_printf ("log-file:%lu:\n", flags | GC_OPT_FLAG_NONE);
+      es_printf ("force:%lu:\n", flags | GC_OPT_FLAG_NONE);
 
       /* --csh and --sh are mutually exclusive, something we can not
          express in GPG Conf.  --options is only usable from the
@@ -1221,46 +1415,55 @@ main (int argc, char **argv)
          and having both of them is thus problematic.  --no-detach is
          also only usable on the command line.  --batch is unused.  */
 
-      filename = make_filename (opt.homedir, 
+      filename = make_filename (gnupg_homedir (),
                                 opt.system_daemon?
                                 "ldapservers.conf":"dirmngr_ldapservers.conf",
                                 NULL);
       filename_esc = percent_escape (filename, NULL);
-      printf ("ldapserverlist-file:%lu:\"%s\n", flags | GC_OPT_FLAG_DEFAULT,
+      es_printf ("ldapserverlist-file:%lu:\"%s\n", flags | GC_OPT_FLAG_DEFAULT,
              filename_esc);
       xfree (filename_esc);
       xfree (filename);
 
-      printf ("ldaptimeout:%lu:%u\n",
+      es_printf ("ldaptimeout:%lu:%u\n",
               flags | GC_OPT_FLAG_DEFAULT, DEFAULT_LDAP_TIMEOUT);
-      printf ("max-replies:%lu:%u\n",
+      es_printf ("max-replies:%lu:%u\n",
               flags | GC_OPT_FLAG_DEFAULT, DEFAULT_MAX_REPLIES);
-      printf ("allow-ocsp:%lu:\n", flags | GC_OPT_FLAG_NONE);
-      printf ("ocsp-responder:%lu:\n", flags | GC_OPT_FLAG_NONE);
-      printf ("ocsp-signer:%lu:\n", flags | GC_OPT_FLAG_NONE);
-
-      printf ("faked-system-time:%lu:\n", flags | GC_OPT_FLAG_NONE);
-      printf ("no-greeting:%lu:\n", flags | GC_OPT_FLAG_NONE);
-
-      printf ("disable-http:%lu:\n", flags | GC_OPT_FLAG_NONE);
-      printf ("disable-ldap:%lu:\n", flags | GC_OPT_FLAG_NONE);
-      printf ("honor-http-proxy:%lu\n", flags | GC_OPT_FLAG_NONE);
-      printf ("http-proxy:%lu:\n", flags | GC_OPT_FLAG_NONE);
-      printf ("ldap-proxy:%lu:\n", flags | GC_OPT_FLAG_NONE);
-      printf ("only-ldap-proxy:%lu:\n", flags | GC_OPT_FLAG_NONE);
-      printf ("ignore-ldap-dp:%lu:\n", flags | GC_OPT_FLAG_NONE);
-      printf ("ignore-http-dp:%lu:\n", flags | GC_OPT_FLAG_NONE);
-      printf ("ignore-ocsp-service-url:%lu:\n", flags | GC_OPT_FLAG_NONE);
+      es_printf ("allow-ocsp:%lu:\n", flags | GC_OPT_FLAG_NONE);
+      es_printf ("ocsp-responder:%lu:\n", flags | GC_OPT_FLAG_NONE);
+      es_printf ("ocsp-signer:%lu:\n", flags | GC_OPT_FLAG_NONE);
+
+      es_printf ("faked-system-time:%lu:\n", flags | GC_OPT_FLAG_NONE);
+      es_printf ("no-greeting:%lu:\n", flags | GC_OPT_FLAG_NONE);
+
+      es_printf ("disable-http:%lu:\n", flags | GC_OPT_FLAG_NONE);
+      es_printf ("disable-ldap:%lu:\n", flags | GC_OPT_FLAG_NONE);
+      es_printf ("honor-http-proxy:%lu\n", flags | GC_OPT_FLAG_NONE);
+      es_printf ("http-proxy:%lu:\n", flags | GC_OPT_FLAG_NONE);
+      es_printf ("ldap-proxy:%lu:\n", flags | GC_OPT_FLAG_NONE);
+      es_printf ("only-ldap-proxy:%lu:\n", flags | GC_OPT_FLAG_NONE);
+      es_printf ("ignore-ldap-dp:%lu:\n", flags | GC_OPT_FLAG_NONE);
+      es_printf ("ignore-http-dp:%lu:\n", flags | GC_OPT_FLAG_NONE);
+      es_printf ("ignore-ocsp-service-url:%lu:\n", flags | GC_OPT_FLAG_NONE);
       /* Note: The next one is to fix a typo in gpgconf - should be
          removed eventually. */
-      printf ("ignore-ocsp-servic-url:%lu:\n", flags | GC_OPT_FLAG_NONE);
+      es_printf ("ignore-ocsp-servic-url:%lu:\n", flags | GC_OPT_FLAG_NONE);
+
+      es_printf ("use-tor:%lu:\n", flags | GC_OPT_FLAG_NONE);
+      es_printf ("keyserver:%lu:\n", flags | GC_OPT_FLAG_NONE);
     }
   cleanup ();
   return !!rc;
 }
 
 
-#ifdef HAVE_W32_SYSTEM
+#ifdef USE_W32_SERVICE
+static void WINAPI
+call_real_main (DWORD argc, LPSTR *argv)
+{
+  real_main (argc, argv);
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -1281,8 +1484,7 @@ main (int argc, char *argv[])
     {
       SERVICE_TABLE_ENTRY DispatchTable [] =
        {
-         /* Ignore warning.  */
-         { "DirMngr", &real_main },
+         { "DirMngr", &call_real_main },
          { NULL, NULL }
        };
 
@@ -1291,7 +1493,7 @@ main (int argc, char *argv[])
       return 0;
     }
 }
-#endif
+#endif /*USE_W32_SERVICE*/
 
 
 static void
@@ -1300,19 +1502,23 @@ cleanup (void)
   crl_cache_deinit ();
   cert_cache_deinit (1);
 
+#if USE_LDAP
   ldapserver_list_free (opt.ldapservers);
+#endif /*USE_LDAP*/
   opt.ldapservers = NULL;
 
   if (cleanup_socket)
     {
       cleanup_socket = 0;
-      if (socket_name && *socket_name)
-        remove (socket_name);
+      if (redir_socket_name)
+        gnupg_remove (redir_socket_name);
+      else if (socket_name && *socket_name)
+        gnupg_remove (socket_name);
     }
 }
 
 
-void 
+void
 dirmngr_exit (int rc)
 {
   cleanup ();
@@ -1323,14 +1529,23 @@ dirmngr_exit (int rc)
 void
 dirmngr_init_default_ctrl (ctrl_t ctrl)
 {
-  (void)ctrl;
+  if (opt.http_proxy)
+    ctrl->http_proxy = xstrdup (opt.http_proxy);
+}
 
-  /* Nothing for now. */
+
+void
+dirmngr_deinit_default_ctrl (ctrl_t ctrl)
+{
+  if (!ctrl)
+    return;
+  xfree (ctrl->http_proxy);
+  ctrl->http_proxy = NULL;
 }
 
 
 /* Create a list of LDAP servers from the file FILENAME. Returns the
-   list or NULL in case of errors. 
+   list or NULL in case of errors.
 
    The format fo such a file is line oriented where empty lines and
    lines starting with a hash mark are ignored.  All other lines are
@@ -1338,11 +1553,12 @@ dirmngr_init_default_ctrl (ctrl_t ctrl)
 
    1. field: Hostname
    2. field: Portnumber
-   3. field: Username 
+   3. field: Username
    4. field: Password
    5. field: Base DN
 
 */
+#if USE_LDAP
 static ldap_server_t
 parse_ldapserver_file (const char* filename)
 {
@@ -1351,29 +1567,29 @@ parse_ldapserver_file (const char* filename)
   ldap_server_t server, serverstart, *serverend;
   int c;
   unsigned int lineno = 0;
-  FILE *fp;
+  estream_t fp;
 
-  fp = fopen (filename, "r");
+  fp = es_fopen (filename, "r");
   if (!fp)
     {
-      log_error (_("error opening `%s': %s\n"), filename, strerror (errno));
+      log_error (_("error opening '%s': %s\n"), filename, strerror (errno));
       return NULL;
     }
 
   serverstart = NULL;
   serverend = &serverstart;
-  while (fgets (buffer, sizeof buffer, fp))
+  while (es_fgets (buffer, sizeof buffer, fp))
     {
       lineno++;
       if (!*buffer || buffer[strlen(buffer)-1] != '\n')
         {
-          if (*buffer && feof (fp))
+          if (*buffer && es_feof (fp))
             ; /* Last line not terminated - continue. */
           else
             {
               log_error (_("%s:%u: line too long - skipped\n"),
                          filename, lineno);
-              while ( (c=fgetc (fp)) != EOF && c != '\n')
+              while ( (c=es_fgetc (fp)) != EOF && c != '\n')
                 ; /* Skip until end of line. */
               continue;
             }
@@ -1391,22 +1607,22 @@ parse_ldapserver_file (const char* filename)
           *serverend = server;
           serverend = &server->next;
         }
-    } 
-  
-  if (ferror (fp))
-    log_error (_("error reading `%s': %s\n"), filename, strerror (errno));
-  fclose (fp);
+    }
+
+  if (es_ferror (fp))
+    log_error (_("error reading '%s': %s\n"), filename, strerror (errno));
+  es_fclose (fp);
 
   return serverstart;
 }
-
+#endif /*USE_LDAP*/
 
 static fingerprint_list_t
 parse_ocsp_signer (const char *string)
 {
   gpg_error_t err;
   char *fname;
-  FILE *fp;
+  estream_t fp;
   char line[256];
   char *p;
   fingerprint_list_t list, *list_tail, item;
@@ -1426,14 +1642,14 @@ parse_ocsp_signer (const char *string)
       item->hexfpr[j] = 0;
       if (j != 40 || !(spacep (string+i) || !string[i]))
         {
-          log_error (_("%s:%u: invalid fingerprint detected\n"), 
+          log_error (_("%s:%u: invalid fingerprint detected\n"),
                      "--ocsp-signer", 0);
           xfree (item);
           return NULL;
         }
       return item;
     }
-  
+
   /* Well, it is a filename.  */
   if (*string == '/' || (*string == '~' && string[1] == '/'))
     fname = make_filename (string, NULL);
@@ -1441,14 +1657,14 @@ parse_ocsp_signer (const char *string)
     {
       if (string[0] == '.' && string[1] == '/' )
         string += 2;
-      fname = make_filename (opt.homedir, string, NULL);
+      fname = make_filename (gnupg_homedir (), string, NULL);
     }
 
-  fp = fopen (fname, "r");
+  fp = es_fopen (fname, "r");
   if (!fp)
     {
       err = gpg_error_from_syserror ();
-      log_error (_("can't open `%s': %s\n"), fname, gpg_strerror (err));
+      log_error (_("can't open '%s': %s\n"), fname, gpg_strerror (err));
       xfree (fname);
       return NULL;
     }
@@ -1457,16 +1673,16 @@ parse_ocsp_signer (const char *string)
   list_tail = &list;
   for (;;)
     {
-      if (!fgets (line, DIM(line)-1, fp) )
+      if (!es_fgets (line, DIM(line)-1, fp) )
         {
-          if (!feof (fp))
+          if (!es_feof (fp))
             {
               err = gpg_error_from_syserror ();
               log_error (_("%s:%u: read error: %s\n"),
                          fname, lnr, gpg_strerror (err));
               errflag = 1;
             }
-          fclose (fp);
+          es_fclose (fp);
           if (errflag)
             {
               while (list)
@@ -1484,11 +1700,11 @@ parse_ocsp_signer (const char *string)
       if (!*line || line[strlen(line)-1] != '\n')
         {
           /* Eat until end of line. */
-          while ( (c=getc (fp)) != EOF && c != '\n')
+          while ( (c=es_getc (fp)) != EOF && c != '\n')
             ;
           err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG
                            /* */: GPG_ERR_INCOMPLETE_LINE);
-          log_error (_("%s:%u: read error: %s\n"), 
+          log_error (_("%s:%u: read error: %s\n"),
                      fname, lnr, gpg_strerror (err));
           errflag = 1;
           continue;
@@ -1526,14 +1742,14 @@ parse_ocsp_signer (const char *string)
 
 \f
 /*
-   Stuff used in daemon mode.  
+   Stuff used in daemon mode.
  */
 
 
 
 /* Reread parts of the configuration.  Note, that this function is
-   obviously not thread-safe and should only be called from the PTH
-   signal handler. 
+   obviously not thread-safe and should only be called from the NPTH
+   signal handler.
 
    Fixme: Due to the way the argument parsing works, we create a
    memory leak here for all string type arguments.  There is currently
@@ -1554,7 +1770,7 @@ reread_configuration (void)
   fp = fopen (opt.config_filename, "r");
   if (!fp)
     {
-      log_error (_("option file `%s': %s\n"),
+      log_error (_("option file '%s': %s\n"),
                  opt.config_filename, strerror(errno) );
       return;
     }
@@ -1575,31 +1791,41 @@ reread_configuration (void)
   fclose (fp);
 
   set_debug ();
+  set_tor_mode ();
+}
+
+
+/* A global function which allows us to trigger the reload stuff from
+   other places.  */
+void
+dirmngr_sighup_action (void)
+{
+  log_info (_("SIGHUP received - "
+              "re-reading configuration and flushing caches\n"));
+  reread_configuration ();
+  cert_cache_deinit (0);
+  crl_cache_deinit ();
+  cert_cache_init ();
+  crl_cache_init ();
 }
 
 
 
 /* The signal handler. */
+#ifndef HAVE_W32_SYSTEM
 static void
 handle_signal (int signo)
 {
   switch (signo)
     {
-#ifndef HAVE_W32_SYSTEM
     case SIGHUP:
-      log_info (_("SIGHUP received - "
-                  "re-reading configuration and flushing caches\n"));
-      reread_configuration ();
-      cert_cache_deinit (0);
-      crl_cache_deinit ();
-      cert_cache_init ();
-      crl_cache_init ();
+      dirmngr_sighup_action ();
       break;
-      
+
     case SIGUSR1:
       cert_cache_print_stats ();
       break;
-      
+
     case SIGUSR2:
       log_info (_("SIGUSR2 received - no action defined\n"));
       break;
@@ -1619,18 +1845,73 @@ handle_signal (int signo)
           dirmngr_exit (0);
        }
       break;
-        
+
     case SIGINT:
       log_info (_("SIGINT received - immediate shutdown\n"));
       log_info( "%s %s stopped\n", strusage(11), strusage(13));
       cleanup ();
       dirmngr_exit (0);
       break;
-#endif
+
     default:
       log_info (_("signal %d received - no action defined\n"), signo);
     }
 }
+#endif /*!HAVE_W32_SYSTEM*/
+
+
+/* Thread to do the housekeeping.  */
+static void *
+housekeeping_thread (void *arg)
+{
+  static int sentinel;
+  time_t curtime;
+
+  (void)arg;
+
+  curtime = gnupg_get_time ();
+  if (sentinel)
+    {
+      log_info ("housekeeping is already going on\n");
+      return NULL;
+    }
+  sentinel++;
+  if (opt.verbose)
+    log_info ("starting housekeeping\n");
+
+  ks_hkp_housekeeping (curtime);
+
+  if (opt.verbose)
+    log_info ("ready with housekeeping\n");
+  sentinel--;
+  return NULL;
+
+}
+
+
+#if GPGRT_GCC_HAVE_PUSH_PRAGMA
+# pragma GCC push_options
+# pragma GCC optimize ("no-strict-overflow")
+#endif
+static int
+time_for_housekeeping_p (time_t curtime)
+{
+  static time_t last_housekeeping;
+
+  if (!last_housekeeping)
+    last_housekeeping = curtime;
+
+  if (last_housekeeping + HOUSEKEEPING_INTERVAL <= curtime
+      || last_housekeeping > curtime /*(be prepared for y2038)*/)
+    {
+      last_housekeeping = curtime;
+      return 1;
+    }
+  return 0;
+}
+#if GPGRT_GCC_HAVE_PUSH_PRAGMA
+# pragma GCC pop_options
+#endif
 
 
 /* This is the worker for the ticker.  It is called every few seconds
@@ -1638,9 +1919,8 @@ handle_signal (int signo)
 static void
 handle_tick (void)
 {
-  /* Nothing real to do right now.  Actually we need the timeout only
-     for W32 where we don't use signals and need a way for the loop to
-     check for the shutdown flag. */
+  /* Under Windows we don't use signals and need a way for the loop to
+     check for the shutdown flag.  */
 #ifdef HAVE_W32_SYSTEM
   if (shutdown_pending)
     log_info (_("SIGTERM received - shutting down ...\n"));
@@ -1652,17 +1932,37 @@ handle_tick (void)
       dirmngr_exit (0);
     }
 #endif /*HAVE_W32_SYSTEM*/
+
+  if (time_for_housekeeping_p (gnupg_get_time ()))
+    {
+      npth_t thread;
+      npth_attr_t tattr;
+      int err;
+
+      err = npth_attr_init (&tattr);
+      if (err)
+        log_error ("error preparing housekeeping thread: %s\n", strerror (err));
+      else
+        {
+          npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
+          err = npth_create (&thread, &tattr, housekeeping_thread, NULL);
+          if (err)
+            log_error ("error spawning housekeeping thread: %s\n",
+                       strerror (err));
+          npth_attr_destroy (&tattr);
+        }
+    }
 }
 
 
-/* Check the nonce on a new connection.  This is a NOP unless we we
-   are using our Unix domain socket emulation under Windows.  */
-static int 
+/* Check the nonce on a new connection.  This is a NOP unless we are
+   using our Unix domain socket emulation under Windows.  */
+static int
 check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce)
 {
   if (assuan_sock_check_nonce (fd, nonce))
     {
-      log_info (_("error reading nonce on fd %d: %s\n"), 
+      log_info (_("error reading nonce on fd %d: %s\n"),
                 FD2INT (fd), strerror (errno));
       assuan_sock_close (fd);
       return -1;
@@ -1672,21 +1972,25 @@ check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce)
 }
 
 
-/* Helper to call a connection's main fucntion. */
+/* Helper to call a connection's main function. */
 static void *
 start_connection_thread (void *arg)
 {
   union int_and_ptr_u argval;
-  assuan_fd_t fd;
+  gnupg_fd_t fd;
 
+  memset (&argval, 0, sizeof argval);
   argval.aptr = arg;
   fd = argval.afd;
 
   if (check_nonce (fd, &socket_nonce))
-    return NULL;
+    {
+      log_error ("handler nonce check FAILED\n");
+      return NULL;
+    }
 
 #ifndef HAVE_W32_SYSTEM
-  pth_key_setdata (my_tlskey_current_fd, argval.aptr);
+  npth_setspecific (my_tlskey_current_fd, argval.aptr);
 #endif
 
   active_connections++;
@@ -1701,9 +2005,9 @@ start_connection_thread (void *arg)
 
 #ifndef HAVE_W32_SYSTEM
   argval.afd = ASSUAN_INVALID_FD;
-  pth_key_setdata (my_tlskey_current_fd, argval.aptr);
+  npth_setspecific (my_tlskey_current_fd, argval.aptr);
 #endif
-  
+
   return NULL;
 }
 
@@ -1712,118 +2016,130 @@ start_connection_thread (void *arg)
 static void
 handle_connections (assuan_fd_t listen_fd)
 {
-  pth_attr_t tattr;
-  pth_event_t ev, time_ev;
-  sigset_t sigs, oldsigs;
+  npth_attr_t tattr;
+#ifndef HAVE_W32_SYSTEM
   int signo;
+#endif
   struct sockaddr_un paddr;
   socklen_t plen = sizeof( paddr );
-  assuan_fd_t fd;
+  gnupg_fd_t fd;
+  int nfd, ret;
+  fd_set fdset, read_fdset;
+  struct timespec abstime;
+  struct timespec curtime;
+  struct timespec timeout;
+  int saved_errno;
 
-  tattr = pth_attr_new();
-  pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
-  pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 1024*1024);
-  pth_attr_set (tattr, PTH_ATTR_NAME, "dirmngr");
+  npth_attr_init (&tattr);
+  npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
 
 #ifndef HAVE_W32_SYSTEM /* FIXME */
-  sigemptyset (&sigs );
-  sigaddset (&sigs, SIGHUP);
-  sigaddset (&sigs, SIGUSR1);
-  sigaddset (&sigs, SIGUSR2);
-  sigaddset (&sigs, SIGINT);
-  sigaddset (&sigs, SIGTERM);
-  ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
-#else
-  sigs = 0;
-  ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
+  npth_sigev_init ();
+  npth_sigev_add (SIGHUP);
+  npth_sigev_add (SIGUSR1);
+  npth_sigev_add (SIGUSR2);
+  npth_sigev_add (SIGINT);
+  npth_sigev_add (SIGTERM);
+  npth_sigev_fini ();
 #endif
-  time_ev = NULL;
 
+  /* Setup the fdset.  It has only one member.  This is because we use
+     pth_select instead of pth_accept to properly sync timeouts with
+     to full second.  */
+  FD_ZERO (&fdset);
+  FD_SET (FD2INT (listen_fd), &fdset);
+  nfd = FD2INT (listen_fd);
+
+  npth_clock_gettime (&abstime);
+  abstime.tv_sec += TIMERTICK_INTERVAL;
+
+  /* Main loop.  */
   for (;;)
     {
+      /* Shutdown test.  */
       if (shutdown_pending)
         {
           if (!active_connections)
             break; /* ready */
 
-          /* Do not accept anymore connections but wait for existing
-             connections to terminate.  */
-          signo = 0;
-          pth_wait (ev);
-          if (pth_event_occurred (ev) && signo)
-            handle_signal (signo);
-          continue;
+          /* Do not accept new connections but keep on running the
+             loop to cope with the timer events.  */
+          FD_ZERO (&fdset);
        }
 
-      if (!time_ev)
-        time_ev = pth_event (PTH_EVENT_TIME, 
-                             pth_timeout (TIMERTICK_INTERVAL, 0));
-
-      if (time_ev)
-        pth_event_concat (ev, time_ev, NULL);
-      fd = (assuan_fd_t) pth_accept_ev (FD2INT (listen_fd), (struct sockaddr *)&paddr, &plen, ev);
-      if (time_ev)
-        pth_event_isolate (time_ev);
+      /* Take a copy of the fdset.  */
+      read_fdset = fdset;
 
-      if (fd == ASSUAN_INVALID_FD)
-        {
-          if (pth_event_occurred (ev)
-              || (time_ev && pth_event_occurred (time_ev)) )
-            {
-              if (pth_event_occurred (ev))
-                handle_signal (signo);
-              if (time_ev && pth_event_occurred (time_ev))
-                {
-                  pth_event_free (time_ev, PTH_FREE_ALL);
-                  time_ev = NULL;
-                  handle_tick ();
-                }
-              continue;
-           }
-          log_error (_("accept failed: %s - waiting 1s\n"), strerror (errno));
-          pth_sleep (1);
-          continue;
+      npth_clock_gettime (&curtime);
+      if (!(npth_timercmp (&curtime, &abstime, <)))
+       {
+         /* Timeout.  */
+         handle_tick ();
+         npth_clock_gettime (&abstime);
+         abstime.tv_sec += TIMERTICK_INTERVAL;
        }
+      npth_timersub (&abstime, &curtime, &timeout);
 
-      if (pth_event_occurred (ev))
-        {
-          handle_signal (signo);
-        }
-
-      if (time_ev && pth_event_occurred (time_ev))
-        {
-          pth_event_free (time_ev, PTH_FREE_ALL);
-          time_ev = NULL;
-          handle_tick ();
-        }
-
+#ifndef HAVE_W32_SYSTEM
+      ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout, npth_sigev_sigmask());
+      saved_errno = errno;
 
-      /* We now might create a new thread and because we don't want
-         any signals (as we are handling them here) to be delivered to
-         a new thread we need to block those signals. */
-      pth_sigmask (SIG_BLOCK, &sigs, &oldsigs);
+      while (npth_sigev_get_pending(&signo))
+       handle_signal (signo);
+#else
+      ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, &timeout, NULL, NULL);
+      saved_errno = errno;
+#endif
 
-      /* Create thread to handle this connection.  */
-      {
-        union int_and_ptr_u argval;
+      if (ret == -1 && saved_errno != EINTR)
+       {
+          log_error (_("npth_pselect failed: %s - waiting 1s\n"),
+                     strerror (saved_errno));
+          npth_sleep (1);
+          continue;
+       }
 
-        argval.afd = fd;
-        if (!pth_spawn (tattr, start_connection_thread, argval.aptr))
-          {
-            log_error (_("error spawning connection handler: %s\n"),
-                       strerror (errno) );
-            assuan_sock_close (fd);
-          }
-      }
+      if (ret <= 0)
+       /* Interrupt or timeout.  Will be handled when calculating the
+          next timeout.  */
+       continue;
 
-      /* Restore the signal mask. */
-      pth_sigmask (SIG_SETMASK, &oldsigs, NULL);
+      if (!shutdown_pending && FD_ISSET (FD2INT (listen_fd), &read_fdset))
+       {
+          plen = sizeof paddr;
+         fd = INT2FD (npth_accept (FD2INT(listen_fd),
+                                   (struct sockaddr *)&paddr, &plen));
+         if (fd == GNUPG_INVALID_FD)
+           {
+             log_error ("accept failed: %s\n", strerror (errno));
+           }
+          else
+            {
+              char threadname[50];
+              union int_and_ptr_u argval;
+             npth_t thread;
+
+              memset (&argval, 0, sizeof argval);
+              argval.afd = fd;
+              snprintf (threadname, sizeof threadname-1,
+                        "conn fd=%d", FD2INT(fd));
+              threadname[sizeof threadname -1] = 0;
+
+              ret = npth_create (&thread, &tattr,
+                                 start_connection_thread, argval.aptr);
+             if (ret)
+                {
+                  log_error ("error spawning connection handler: %s\n",
+                             strerror (ret) );
+                  assuan_sock_close (fd);
+                }
+             npth_setname_np (thread, threadname);
+            }
+          fd = GNUPG_INVALID_FD;
+       }
     }
-  
-  pth_event_free (ev, PTH_FREE_ALL);
-  if (time_ev)
-    pth_event_free (time_ev, PTH_FREE_ALL);
-  pth_attr_destroy (tattr);
+
+  npth_attr_destroy (&tattr);
   cleanup ();
   log_info ("%s %s stopped\n", strusage(11), strusage(13));
 }