tests: Use gpgconf to set the ssh socket envvar.
[gnupg.git] / dirmngr / dirmngr.c
index 2256c59..7e629db 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, 2011 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
  * 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.
  *
  * (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
  * 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>
  */
 
 #include <config.h>
 #ifdef HAVE_SIGNAL_H
 # include <signal.h>
 #endif
 #ifdef HAVE_SIGNAL_H
 # include <signal.h>
 #endif
-#include <pth.h>
+#include <npth.h>
 
 
+#include "dirmngr-err.h"
 
 
-#define JNLIB_NEED_LOG_LOGV
-#define JNLIB_NEED_AFLOCAL
+#if  HTTP_USE_NTBTLS
+# include <ntbtls.h>
+#elif HTTP_USE_GNUTLS
+# include <gnutls/gnutls.h>
+#endif /*HTTP_USE_GNUTLS*/
+
+
+#define GNUPG_COMMON_NEED_AFLOCAL
 #include "dirmngr.h"
 
 #include <assuan.h>
 #include "dirmngr.h"
 
 #include <assuan.h>
 #include "crlcache.h"
 #include "crlfetch.h"
 #include "misc.h"
 #include "crlcache.h"
 #include "crlfetch.h"
 #include "misc.h"
-#include "ldapserver.h"
+#if USE_LDAP
+# include "ldapserver.h"
+#endif
 #include "asshelp.h"
 #include "asshelp.h"
-#include "ldap-wrapper.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".
 
 /* The plain Windows version uses the windows service system.  For
    example to start the service you may use "sc start dirmngr".
 # define USE_W32_SERVICE 1
 #endif
 
 # define USE_W32_SERVICE 1
 #endif
 
+#ifndef ENAMETOOLONG
+# define ENAMETOOLONG EINVAL
+#endif
+
 
 enum cmd_and_opt_values {
   aNull = 0,
 
 enum cmd_and_opt_values {
   aNull = 0,
@@ -91,6 +108,7 @@ enum cmd_and_opt_values {
   oDebugAll,
   oDebugWait,
   oDebugLevel,
   oDebugAll,
   oDebugWait,
   oDebugLevel,
+  oGnutlsDebug,
   oNoGreeting,
   oNoOptions,
   oHomedir,
   oNoGreeting,
   oNoOptions,
   oHomedir,
@@ -115,6 +133,7 @@ enum cmd_and_opt_values {
   oOCSPMaxPeriod,
   oOCSPCurrentPeriod,
   oMaxReplies,
   oOCSPMaxPeriod,
   oOCSPCurrentPeriod,
   oMaxReplies,
+  oHkpCaCert,
   oFakedSystemTime,
   oForce,
   oAllowOCSP,
   oFakedSystemTime,
   oForce,
   oAllowOCSP,
@@ -122,6 +141,9 @@ enum cmd_and_opt_values {
   oLDAPWrapperProgram,
   oHTTPWrapperProgram,
   oIgnoreCertExtension,
   oLDAPWrapperProgram,
   oHTTPWrapperProgram,
   oIgnoreCertExtension,
+  oUseTor,
+  oKeyServer,
+  oNameServer,
   aTest
 };
 
   aTest
 };
 
@@ -194,11 +216,20 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_i (oMaxReplies, "max-replies",
                 N_("|N|do not return more than N items in one query")),
 
   ARGPARSE_s_i (oMaxReplies, "max-replies",
                 N_("|N|do not return more than N items in one query")),
 
+  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_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_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_i (oDebugWait, "debug-wait", "@"),
   ARGPARSE_s_n (oNoGreeting, "no-greeting", "@"),
   ARGPARSE_s_s (oHomedir, "homedir", "@"),
@@ -213,17 +244,34 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_end ()
 };
 
   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 */
 
 #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;
 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;
 
 
 /* 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
 static int cleanup_socket;
 
 /* Keep track of the current log file so that we can avoid updating
@@ -233,6 +281,9 @@ static char *current_logfile;
 /* Helper to implement --debug-level. */
 static const char *debug_level;
 
 /* 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;
 
 /* Flag indicating that a shutdown has been requested.  */
 static volatile int shutdown_pending;
 
@@ -241,9 +292,7 @@ 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 timer tick used for housekeeping stuff.  For Windows we use a
    longer period as the SetWaitableTimer seems to signal earlier than
-   the 2 seconds.  CHECK_OWN_SOCKET_INTERVAL defines how often we
-   check our own socket in standard socket mode.  If that value is 0
-   we don't check at all.   All values are in seconds. */
+   the 2 seconds.  All values are in seconds. */
 #if defined(HAVE_W32CE_SYSTEM)
 # define TIMERTICK_INTERVAL         (60)
 #elif defined(HAVE_W32_SYSTEM)
 #if defined(HAVE_W32CE_SYSTEM)
 # define TIMERTICK_INTERVAL         (60)
 #elif defined(HAVE_W32_SYSTEM)
@@ -252,9 +301,12 @@ static int active_connections;
 # define TIMERTICK_INTERVAL          (2)
 #endif
 
 # 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
 /* 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;
 union int_and_ptr_u
 {
   int  aint;
@@ -266,38 +318,21 @@ 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
 
 /* 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);
 #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);
 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);
 
 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;
-
-#if GCRY_THREAD_OPTION_VERSION == 0
-#define USE_GCRY_THREAD_CBS 1
-#endif
-
-#ifdef USE_GCRY_THREAD_CBS
-GCRY_THREAD_OPTION_PTH_IMPL;
-static int fixed_gcry_pth_init (void)
-{
-  return pth_self ()? 0 : (pth_init () == FALSE) ? errno : 0;
-}
-#endif
-
-#ifndef PTH_HAVE_PTH_THREAD_ID
-static unsigned long pth_thread_id (void)
-{
-  return (unsigned long)pth_self ();
-}
-#endif
+/* NPth wrapper function definitions. */
+ASSUAN_SYSTEM_NPTH_IMPL;
 
 static const char *
 my_strusage( int level )
 
 static const char *
 my_strusage( int level )
@@ -305,7 +340,7 @@ my_strusage( int level )
   const char *p;
   switch ( level )
     {
   const char *p;
   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;
       break;
     case 13: p = VERSION; break;
     case 17: p = PRINTABLE_OS_NAME; break;
@@ -315,10 +350,10 @@ my_strusage( int level )
     case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
     case 49: p = PACKAGE_BUGREPORT; break;
     case 1:
     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;
       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;
       break;
 
     default: p = NULL;
@@ -348,6 +383,21 @@ my_ksba_hash_buffer (void *arg, const char *oid,
 }
 
 
 }
 
 
+/* 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
 /* 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
@@ -363,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))
   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))
   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))
   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)
     {
                  |DBG_CACHE_VALUE|DBG_CRYPTO_VALUE);
   else if (!strcmp (debug_level, "guru") || numok)
     {
@@ -381,7 +431,7 @@ set_debug (void)
     }
   else
     {
     }
   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
       log_info (_("valid debug levels are: %s\n"),
                 "none, basic, advanced, expert, guru");
       opt.debug = 0; /* Reset debugging, so that prior debug
@@ -399,13 +449,43 @@ set_debug (void)
 
   if (opt.debug & DBG_CRYPTO_VALUE )
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
 
   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
+set_tor_mode (void)
+{
+  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");
+        }
+    }
 }
 
 
 static void
 wrong_args (const char *text)
 {
 }
 
 
 static void
 wrong_args (const char *text)
 {
-  es_fputs (_("usage: dirmngr [options] "), es_stderr);
+  es_fprintf (es_stderr, _("usage: %s [options] "), DIRMNGR_NAME);
   es_fputs (text, es_stderr);
   es_putc ('\n', es_stderr);
   dirmngr_exit (2);
   es_fputs (text, es_stderr);
   es_putc ('\n', es_stderr);
   dirmngr_exit (2);
@@ -416,7 +496,9 @@ wrong_args (const char *text)
 static void
 shutdown_reaper (void)
 {
 static void
 shutdown_reaper (void)
 {
+#if USE_LDAP
   ldap_wrapper_wait_connections ();
   ldap_wrapper_wait_connections ();
+#endif
 }
 
 
 }
 
 
@@ -456,6 +538,9 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
           opt.ocsp_signer = tmp;
         }
       FREE_STRLIST (opt.ignored_cert_extensions);
           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;
     }
 
       return 1;
     }
 
@@ -463,9 +548,12 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
     {
     case oQuiet:   opt.quiet = 1; break;
     case oVerbose: opt.verbose++; break;
     {
     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 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)
 
     case oLogFile:
       if (!reread)
@@ -507,10 +595,38 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
 
     case oMaxReplies: opt.max_replies = pargs->r.ret_int; break;
 
 
     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 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. */
     }
     default:
       return 0; /* Not handled. */
     }
@@ -528,6 +644,10 @@ DWORD WINAPI
 w32_service_control (DWORD control, DWORD event_type, LPVOID event_data,
                     LPVOID context)
 {
 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)
     {
   /* event_type and event_data are not used here.  */
   switch (control)
     {
@@ -557,7 +677,8 @@ pid_suffix_callback (unsigned long *r_suffix)
 {
   union int_and_ptr_u value;
 
 {
   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.  */
 }
   *r_suffix = value.aint;
   return (*r_suffix != -1);  /* Use decimal representation.  */
 }
@@ -588,12 +709,16 @@ main (int argc, char **argv)
   int nodetach = 0;
   int csh_style = 0;
   char *logfile = NULL;
   int nodetach = 0;
   int csh_style = 0;
   char *logfile = NULL;
+#if USE_LDAP
   char *ldapfile = NULL;
   char *ldapfile = NULL;
+#endif /*USE_LDAP*/
   int debug_wait = 0;
   int rc;
   int homedir_seen = 0;
   struct assuan_malloc_hooks malloc_hooks;
 
   int debug_wait = 0;
   int rc;
   int homedir_seen = 0;
   struct assuan_malloc_hooks malloc_hooks;
 
+  early_system_init ();
+
 #ifdef USE_W32_SERVICE
   /* The option will be set by main() below if we should run as a
      system daemon.  */
 #ifdef USE_W32_SERVICE
   /* The option will be set by main() below if we should run as a
      system daemon.  */
@@ -618,23 +743,14 @@ main (int argc, char **argv)
 #endif /*USE_W32_SERVICE*/
 
   set_strusage (my_strusage);
 #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);
 
 
   /* Make sure that our subsystems are ready.  */
   i18n_init ();
   init_common_subsystems (&argc, &argv);
 
-#ifdef USE_GCRY_THREAD_CBS
-  /* 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));
-    }
-#endif
+  npth_init ();
+
   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
 
  /* Check that the libraries are suitable.  Do it here because
   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
 
  /* Check that the libraries are suitable.  Do it here because
@@ -650,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);
 
   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;
 
   /* Init Assuan. */
   malloc_hooks.malloc = gcry_malloc;
@@ -658,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_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);
 
   assuan_sock_init ();
   setup_libassuan_logging (&opt.debug);
 
@@ -669,14 +795,12 @@ main (int argc, char **argv)
   if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
     csh_style = 1;
 
   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
      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*/
 
       log_set_pid_suffix_cb (pid_suffix_callback);
 #endif /*!HAVE_W32_SYSTEM*/
 
@@ -688,7 +812,6 @@ main (int argc, char **argv)
   opt.ldaptimeout = DEFAULT_LDAP_TIMEOUT;
 
   /* Other defaults.  */
   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;
 
   /* Check whether we have a config file given on the commandline */
   orig_argc = argc;
@@ -710,7 +833,7 @@ main (int argc, char **argv)
         default_config = 0; /* --no-options */
       else if (pargs.r_opt == oHomedir)
         {
         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)
           homedir_seen = 1;
         }
       else if (pargs.r_opt == aDaemon)
@@ -732,21 +855,25 @@ main (int argc, char **argv)
     }
 
   /* If --daemon has been given on the command line but not --homedir,
     }
 
   /* 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)
     {
 #ifdef HAVE_W32CE_SYSTEM
      this also overrides the GNUPGHOME environment variable.  */
   if (opt.system_daemon && !homedir_seen)
     {
 #ifdef HAVE_W32CE_SYSTEM
-      opt.homedir = DIRSEP_S "gnupg";
+      gnupg_set_homedir (DIRSEP_S "gnupg");
 #else
 #else
-      opt.homedir = gnupg_sysconfdir ();
+      gnupg_set_homedir (gnupg_sysconfdir ());
 #endif
 #endif
-      opt.homedir_data = gnupg_datadir ();
       opt.homedir_cache = gnupg_cachedir ();
       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)
 
   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;
 
   argc = orig_argc;
   argv = orig_argv;
@@ -763,12 +890,12 @@ main (int argc, char **argv)
           if (default_config)
             {
               if( parse_debug )
           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
             {
                           configname );
            }
           else
             {
-              log_error (_("option file `%s': %s\n"),
+              log_error (_("option file '%s': %s\n"),
                          configname, strerror(errno) );
               exit(2);
            }
                          configname, strerror(errno) );
               exit(2);
            }
@@ -776,7 +903,7 @@ main (int argc, char **argv)
           configname = NULL;
        }
       if (parse_debug && 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;
     }
 
       default_config = 0;
     }
 
@@ -803,9 +930,6 @@ main (int argc, char **argv)
         case oVerbose: opt.verbose++; break;
         case oBatch: opt.batch=1; break;
 
         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:
         case oDebugWait: debug_wait = pargs.r.ret_int; break;
 
         case oOptions:
@@ -825,7 +949,11 @@ 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 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 oLDAPAddServers: opt.add_new_ldapservers = 1; break;
        case oLDAPTimeout:
          opt.ldaptimeout = pargs.r.ret_int;
@@ -858,10 +986,8 @@ main (int argc, char **argv)
   if (nogreeting )
     greeting = 0;
 
   if (nogreeting )
     greeting = 0;
 
-  if (!opt.homedir_data)
-    opt.homedir_data = opt.homedir;
   if (!opt.homedir_cache)
   if (!opt.homedir_cache)
-    opt.homedir_cache = opt.homedir;
+    opt.homedir_cache = xstrdup (gnupg_homedir ());
 
   if (greeting)
     {
 
   if (greeting)
     {
@@ -874,12 +1000,30 @@ main (int argc, char **argv)
   log_info ("NOTE: this is a development version!\n");
 #endif
 
   log_info ("NOTE: this is a development version!\n");
 #endif
 
-  if (!access ("/etc/dirmngr", F_OK) && !strncmp (opt.homedir, "/etc/", 5))
+  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
     log_info
-      ("NOTE: DirMngr is now a proper part of GnuPG.  The configuration and"
+      ("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"
        " 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");
+       " directory '/etc/dirmngr'.\n", GNUPG_NAME);
 
   if (gnupg_faked_time_p ())
     {
 
   if (gnupg_faked_time_p ())
     {
@@ -892,11 +1036,13 @@ main (int argc, char **argv)
     }
 
   set_debug ();
     }
 
   set_debug ();
+  set_tor_mode ();
 
   /* Get LDAP server list from file. */
 
   /* Get LDAP server list from file. */
+#if USE_LDAP
   if (!ldapfile)
     {
   if (!ldapfile)
     {
-      ldapfile = make_filename (opt.homedir,
+      ldapfile = make_filename (gnupg_homedir (),
                                 opt.system_daemon?
                                 "ldapservers.conf":"dirmngr_ldapservers.conf",
                                 NULL);
                                 opt.system_daemon?
                                 "ldapservers.conf":"dirmngr_ldapservers.conf",
                                 NULL);
@@ -905,6 +1051,7 @@ main (int argc, char **argv)
     }
   else
       opt.ldapservers = parse_ldapserver_file (ldapfile);
     }
   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
 
 #ifndef HAVE_W32_SYSTEM
   /* We need to ignore the PIPE signal because the we might log to a
@@ -923,7 +1070,7 @@ main (int argc, char **argv)
 
   if (cmd == aServer)
     {
 
   if (cmd == aServer)
     {
-      /* Note that this server mode is maily useful for debugging.  */
+      /* Note that this server mode is mainly useful for debugging.  */
       if (argc)
         wrong_args ("--server");
 
       if (argc)
         wrong_args ("--server");
 
@@ -941,7 +1088,10 @@ main (int argc, char **argv)
           log_debug ("... okay\n");
         }
 
           log_debug ("... okay\n");
         }
 
+#if USE_LDAP
       ldap_wrapper_launch_thread ();
       ldap_wrapper_launch_thread ();
+#endif /*USE_LDAP*/
+
       cert_cache_init ();
       crl_cache_init ();
       start_command_handler (ASSUAN_INVALID_FD);
       cert_cache_init ();
       crl_cache_init ();
       start_command_handler (ASSUAN_INVALID_FD);
@@ -961,9 +1111,9 @@ main (int argc, char **argv)
       if (logfile)
         {
           log_set_file (logfile);
       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);
         }
 
           current_logfile = xstrdup (logfile);
         }
 
@@ -974,12 +1124,6 @@ main (int argc, char **argv)
           dirmngr_exit (1);
         }
 #endif
           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)
         {
       fd = assuan_sock_new (AF_UNIX, SOCK_STREAM, 0);
       if (fd == ASSUAN_INVALID_FD)
         {
@@ -988,9 +1132,30 @@ main (int argc, char **argv)
           dirmngr_exit (1);
         }
 
           dirmngr_exit (1);
         }
 
-      memset (&serv_addr, 0, sizeof serv_addr);
-      serv_addr.sun_family = AF_UNIX;
-      strcpy (serv_addr.sun_path, socket_name);
+      {
+        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);
       len = SUN_LEN (&serv_addr);
 
       rc = assuan_sock_bind (fd, (struct sockaddr*) &serv_addr, len);
@@ -1002,7 +1167,7 @@ main (int argc, char **argv)
               ))
        {
           /* Fixme: We should test whether a dirmngr is already running. */
               ))
        {
           /* Fixme: We should test whether a dirmngr is already running. */
-         gnupg_remove (socket_name);
+         gnupg_remove (redir_socket_name? redir_socket_name : socket_name);
          rc = assuan_sock_bind (fd, (struct sockaddr*) &serv_addr, len);
        }
       if (rc != -1
          rc = assuan_sock_bind (fd, (struct sockaddr*) &serv_addr, len);
        }
       if (rc != -1
@@ -1010,13 +1175,18 @@ main (int argc, char **argv)
        log_error (_("error getting nonce for the socket\n"));
       if (rc == -1)
         {
        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;
 
           assuan_sock_close (fd);
           dirmngr_exit (1);
         }
       cleanup_socket = 1;
 
+      if (gnupg_chmod (serv_addr.sun_path, "-rwx"))
+        log_error (_("can't set permissions of '%s': %s\n"),
+                   serv_addr.sun_path, strerror (errno));
+
       if (listen (FD2INT (fd), 5) == -1)
         {
           log_error (_("listen() failed: %s\n"), strerror (errno));
       if (listen (FD2INT (fd), 5) == -1)
         {
           log_error (_("listen() failed: %s\n"), strerror (errno));
@@ -1025,7 +1195,7 @@ main (int argc, char **argv)
         }
 
       if (opt.verbose)
         }
 
       if (opt.verbose)
-        log_info (_("listening on socket `%s'\n"), socket_name );
+        log_info (_("listening on socket '%s'\n"), serv_addr.sun_path);
 
       es_fflush (NULL);
 
 
       es_fflush (NULL);
 
@@ -1033,10 +1203,14 @@ main (int argc, char **argv)
          existing scripts which might use this to detect a successful
          start of the dirmngr.  */
 #ifdef HAVE_W32_SYSTEM
          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 ();
       pid = getpid ();
-      es_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
 #else
-      pid = pth_fork ();
+      pid = fork();
       if (pid == (pid_t)-1)
         {
           log_fatal (_("error forking process: %s\n"), strerror (errno));
       if (pid == (pid_t)-1)
         {
           log_fatal (_("error forking process: %s\n"), strerror (errno));
@@ -1054,8 +1228,8 @@ main (int argc, char **argv)
           close (fd);
 
           /* Create the info string: <name>:<pid>:<protocol_version> */
           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);
             {
               log_error (_("out of core\n"));
               kill (pid, SIGTERM);
@@ -1070,7 +1244,7 @@ main (int argc, char **argv)
             }
           else
             {
             }
           else
             {
-              es_printf ( "%s; export DIRMNGR_INFO;\n", infostr);
+              es_printf ( "%s; export %s;\n", infostr, DIRMNGR_INFO_NAME);
             }
           free (infostr);
           exit (0);
             }
           free (infostr);
           exit (0);
@@ -1101,7 +1275,7 @@ main (int argc, char **argv)
             }
 
           log_get_prefix (&oldflags);
             }
 
           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("/"))
           opt.running_detached = 1;
 
           if (chdir("/"))
@@ -1112,7 +1286,10 @@ main (int argc, char **argv)
         }
 #endif
 
         }
 #endif
 
+#if USE_LDAP
       ldap_wrapper_launch_thread ();
       ldap_wrapper_launch_thread ();
+#endif /*USE_LDAP*/
+
       cert_cache_init ();
       crl_cache_init ();
 #ifdef USE_W32_SERVICE
       cert_cache_init ();
       crl_cache_init ();
 #ifdef USE_W32_SERVICE
@@ -1138,7 +1315,9 @@ main (int argc, char **argv)
       /* Just list the CRL cache and exit. */
       if (argc)
         wrong_args ("--list-crls");
       /* Just list the CRL cache and exit. */
       if (argc)
         wrong_args ("--list-crls");
+#if USE_LDAP
       ldap_wrapper_launch_thread ();
       ldap_wrapper_launch_thread ();
+#endif /*USE_LDAP*/
       crl_cache_init ();
       crl_cache_list (es_stdout);
     }
       crl_cache_init ();
       crl_cache_list (es_stdout);
     }
@@ -1149,7 +1328,9 @@ main (int argc, char **argv)
       memset (&ctrlbuf, 0, sizeof ctrlbuf);
       dirmngr_init_default_ctrl (&ctrlbuf);
 
       memset (&ctrlbuf, 0, sizeof ctrlbuf);
       dirmngr_init_default_ctrl (&ctrlbuf);
 
+#if USE_LDAP
       ldap_wrapper_launch_thread ();
       ldap_wrapper_launch_thread ();
+#endif /*USE_LDAP*/
       cert_cache_init ();
       crl_cache_init ();
       if (!argc)
       cert_cache_init ();
       crl_cache_init ();
       if (!argc)
@@ -1159,6 +1340,7 @@ main (int argc, char **argv)
           for (; !rc && argc; argc--, argv++)
             rc = crl_cache_load (&ctrlbuf, *argv);
         }
           for (; !rc && argc; argc--, argv++)
             rc = crl_cache_load (&ctrlbuf, *argv);
         }
+      dirmngr_deinit_default_ctrl (&ctrlbuf);
     }
   else if (cmd == aFetchCRL)
     {
     }
   else if (cmd == aFetchCRL)
     {
@@ -1171,21 +1353,24 @@ main (int argc, char **argv)
       memset (&ctrlbuf, 0, sizeof ctrlbuf);
       dirmngr_init_default_ctrl (&ctrlbuf);
 
       memset (&ctrlbuf, 0, sizeof ctrlbuf);
       dirmngr_init_default_ctrl (&ctrlbuf);
 
+#if USE_LDAP
       ldap_wrapper_launch_thread ();
       ldap_wrapper_launch_thread ();
+#endif /*USE_LDAP*/
       cert_cache_init ();
       crl_cache_init ();
       rc = crl_fetch (&ctrlbuf, argv[0], &reader);
       if (rc)
       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);
           if (rc)
                      argv[0], gpg_strerror (rc));
       else
         {
           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);
         }
                        argv[0], gpg_strerror (rc));
           crl_close_reader (reader);
         }
+      dirmngr_deinit_default_ctrl (&ctrlbuf);
     }
   else if (cmd == aFlush)
     {
     }
   else if (cmd == aFlush)
     {
@@ -1202,23 +1387,6 @@ main (int argc, char **argv)
       char *filename;
       char *filename_esc;
 
       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
 #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
@@ -1231,7 +1399,7 @@ 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)
       /* 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);
                                              "dirmngr.conf", NULL );
 
       filename = percent_escape (opt.config_filename, NULL);
@@ -1251,7 +1419,7 @@ 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.  */
 
          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);
                                 opt.system_daemon?
                                 "ldapservers.conf":"dirmngr_ldapservers.conf",
                                 NULL);
@@ -1284,6 +1452,9 @@ main (int argc, char **argv)
       /* Note: The next one is to fix a typo in gpgconf - should be
          removed eventually. */
       es_printf ("ignore-ocsp-servic-url:%lu:\n", flags | GC_OPT_FLAG_NONE);
       /* Note: The next one is to fix a typo in gpgconf - should be
          removed eventually. */
       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;
     }
   cleanup ();
   return !!rc;
@@ -1291,6 +1462,12 @@ main (int argc, char **argv)
 
 
 #ifdef USE_W32_SERVICE
 
 
 #ifdef USE_W32_SERVICE
+static void WINAPI
+call_real_main (DWORD argc, LPSTR *argv)
+{
+  real_main (argc, argv);
+}
+
 int
 main (int argc, char *argv[])
 {
 int
 main (int argc, char *argv[])
 {
@@ -1311,8 +1488,7 @@ main (int argc, char *argv[])
     {
       SERVICE_TABLE_ENTRY DispatchTable [] =
        {
     {
       SERVICE_TABLE_ENTRY DispatchTable [] =
        {
-         /* Ignore warning.  */
-         { "DirMngr", &real_main },
+         { "DirMngr", &call_real_main },
          { NULL, NULL }
        };
 
          { NULL, NULL }
        };
 
@@ -1330,13 +1506,17 @@ cleanup (void)
   crl_cache_deinit ();
   cert_cache_deinit (1);
 
   crl_cache_deinit ();
   cert_cache_deinit (1);
 
+#if USE_LDAP
   ldapserver_list_free (opt.ldapservers);
   ldapserver_list_free (opt.ldapservers);
+#endif /*USE_LDAP*/
   opt.ldapservers = NULL;
 
   if (cleanup_socket)
     {
       cleanup_socket = 0;
   opt.ldapservers = NULL;
 
   if (cleanup_socket)
     {
       cleanup_socket = 0;
-      if (socket_name && *socket_name)
+      if (redir_socket_name)
+        gnupg_remove (redir_socket_name);
+      else if (socket_name && *socket_name)
         gnupg_remove (socket_name);
     }
 }
         gnupg_remove (socket_name);
     }
 }
@@ -1353,9 +1533,18 @@ dirmngr_exit (int rc)
 void
 dirmngr_init_default_ctrl (ctrl_t ctrl)
 {
 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;
 }
 
 
 }
 
 
@@ -1373,6 +1562,7 @@ dirmngr_init_default_ctrl (ctrl_t ctrl)
    5. field: Base DN
 
 */
    5. field: Base DN
 
 */
+#if USE_LDAP
 static ldap_server_t
 parse_ldapserver_file (const char* filename)
 {
 static ldap_server_t
 parse_ldapserver_file (const char* filename)
 {
@@ -1386,7 +1576,7 @@ parse_ldapserver_file (const char* filename)
   fp = es_fopen (filename, "r");
   if (!fp)
     {
   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;
     }
 
       return NULL;
     }
 
@@ -1424,12 +1614,12 @@ parse_ldapserver_file (const char* filename)
     }
 
   if (es_ferror (fp))
     }
 
   if (es_ferror (fp))
-    log_error (_("error reading `%s': %s\n"), filename, strerror (errno));
+    log_error (_("error reading '%s': %s\n"), filename, strerror (errno));
   es_fclose (fp);
 
   return serverstart;
 }
   es_fclose (fp);
 
   return serverstart;
 }
-
+#endif /*USE_LDAP*/
 
 static fingerprint_list_t
 parse_ocsp_signer (const char *string)
 
 static fingerprint_list_t
 parse_ocsp_signer (const char *string)
@@ -1471,14 +1661,14 @@ parse_ocsp_signer (const char *string)
     {
       if (string[0] == '.' && string[1] == '/' )
         string += 2;
     {
       if (string[0] == '.' && string[1] == '/' )
         string += 2;
-      fname = make_filename (opt.homedir, string, NULL);
+      fname = make_filename (gnupg_homedir (), string, NULL);
     }
 
   fp = es_fopen (fname, "r");
   if (!fp)
     {
       err = gpg_error_from_syserror ();
     }
 
   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;
     }
       xfree (fname);
       return NULL;
     }
@@ -1562,7 +1752,7 @@ parse_ocsp_signer (const char *string)
 
 
 /* Reread parts of the configuration.  Note, that this function is
 
 
 /* Reread parts of the configuration.  Note, that this function is
-   obviously not thread-safe and should only be called from the PTH
+   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
    signal handler.
 
    Fixme: Due to the way the argument parsing works, we create a
@@ -1584,7 +1774,7 @@ reread_configuration (void)
   fp = fopen (opt.config_filename, "r");
   if (!fp)
     {
   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;
     }
                  opt.config_filename, strerror(errno) );
       return;
     }
@@ -1605,6 +1795,7 @@ reread_configuration (void)
   fclose (fp);
 
   set_debug ();
   fclose (fp);
 
   set_debug ();
+  set_tor_mode ();
 }
 
 
 }
 
 
@@ -1625,12 +1816,12 @@ dirmngr_sighup_action (void)
 
 
 /* The signal handler. */
 
 
 /* The signal handler. */
+#ifndef HAVE_W32_SYSTEM
 static void
 handle_signal (int signo)
 {
   switch (signo)
     {
 static void
 handle_signal (int signo)
 {
   switch (signo)
     {
-#ifndef HAVE_W32_SYSTEM
     case SIGHUP:
       dirmngr_sighup_action ();
       break;
     case SIGHUP:
       dirmngr_sighup_action ();
       break;
@@ -1665,11 +1856,66 @@ handle_signal (int signo)
       cleanup ();
       dirmngr_exit (0);
       break;
       cleanup ();
       dirmngr_exit (0);
       break;
-#endif
+
     default:
       log_info (_("signal %d received - no action defined\n"), signo);
     }
 }
     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
 
 
 /* This is the worker for the ticker.  It is called every few seconds
@@ -1677,9 +1923,8 @@ handle_signal (int signo)
 static void
 handle_tick (void)
 {
 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"));
 #ifdef HAVE_W32_SYSTEM
   if (shutdown_pending)
     log_info (_("SIGTERM received - shutting down ...\n"));
@@ -1691,11 +1936,31 @@ handle_tick (void)
       dirmngr_exit (0);
     }
 #endif /*HAVE_W32_SYSTEM*/
       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.  */
+/* 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)
 {
 static int
 check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce)
 {
@@ -1711,24 +1976,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;
   gnupg_fd_t fd;
 
 static void *
 start_connection_thread (void *arg)
 {
   union int_and_ptr_u argval;
   gnupg_fd_t fd;
 
+  memset (&argval, 0, sizeof argval);
   argval.aptr = arg;
   fd = argval.afd;
 
   if (check_nonce (fd, &socket_nonce))
     {
   argval.aptr = arg;
   fd = argval.afd;
 
   if (check_nonce (fd, &socket_nonce))
     {
-      log_error ("handler 0x%lx nonce check FAILED\n", pth_thread_id ());
+      log_error ("handler nonce check FAILED\n");
       return NULL;
     }
 
 #ifndef HAVE_W32_SYSTEM
       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++;
 #endif
 
   active_connections++;
@@ -1743,7 +2009,7 @@ start_connection_thread (void *arg)
 
 #ifndef HAVE_W32_SYSTEM
   argval.afd = ASSUAN_INVALID_FD;
 
 #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;
 #endif
 
   return NULL;
@@ -1754,53 +2020,32 @@ start_connection_thread (void *arg)
 static void
 handle_connections (assuan_fd_t listen_fd)
 {
 static void
 handle_connections (assuan_fd_t listen_fd)
 {
-  pth_attr_t tattr;
-  pth_event_t ev, time_ev;
-  sigset_t sigs;
+  npth_attr_t tattr;
+#ifndef HAVE_W32_SYSTEM
   int signo;
   int signo;
+#endif
   struct sockaddr_un paddr;
   socklen_t plen = sizeof( paddr );
   gnupg_fd_t fd;
   int nfd, ret;
   fd_set fdset, read_fdset;
   struct sockaddr_un paddr;
   socklen_t plen = sizeof( paddr );
   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 */
 
 #ifndef HAVE_W32_SYSTEM /* FIXME */
-  /* Make sure that the signals we are going to handle are not blocked
-     and create an event object for them.  We also set the default
-     action to ignore because we use an Pth event to get notified
-     about signals.  This avoids that the default action is taken in
-     case soemthing goes wrong within Pth.  The problem might also be
-     a Pth bug.  */
-  sigemptyset (&sigs );
-  {
-    static const int mysigs[] = { SIGHUP, SIGUSR1, SIGUSR2, SIGINT, SIGTERM };
-    struct sigaction sa;
-    int i;
-
-    for (i=0; i < DIM (mysigs); i++)
-      {
-        sigemptyset (&sa.sa_mask);
-        sa.sa_handler = SIG_IGN;
-        sa.sa_flags = 0;
-        sigaction (mysigs[i], &sa, NULL);
-
-        sigaddset (&sigs, mysigs[i]);
-      }
-  }
-
-  pth_sigmask (SIG_UNBLOCK, &sigs, NULL);
-  ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
-#else
-  /* Use a dummy event.  */
-  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
 #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
 
   /* Setup the fdset.  It has only one member.  This is because we use
      pth_select instead of pth_accept to properly sync timeouts with
@@ -1809,12 +2054,12 @@ handle_connections (assuan_fd_t listen_fd)
   FD_SET (FD2INT (listen_fd), &fdset);
   nfd = FD2INT (listen_fd);
 
   FD_SET (FD2INT (listen_fd), &fdset);
   nfd = FD2INT (listen_fd);
 
+  npth_clock_gettime (&abstime);
+  abstime.tv_sec += TIMERTICK_INTERVAL;
+
   /* Main loop.  */
   for (;;)
     {
   /* Main loop.  */
   for (;;)
     {
-      /* Make sure that our signals are not blocked.  */
-      pth_sigmask (SIG_UNBLOCK, &sigs, NULL);
-
       /* Shutdown test.  */
       if (shutdown_pending)
         {
       /* Shutdown test.  */
       if (shutdown_pending)
         {
@@ -1826,76 +2071,48 @@ handle_connections (assuan_fd_t listen_fd)
           FD_ZERO (&fdset);
        }
 
           FD_ZERO (&fdset);
        }
 
-      /* Create a timeout event if needed.  To help with power saving
-         we syncronize the ticks to the next full second.  */
-      if (!time_ev)
-        {
-          pth_time_t nexttick;
-
-          nexttick = pth_timeout (TIMERTICK_INTERVAL, 0);
-          if (nexttick.tv_usec > 10)  /* Use a 10 usec threshhold.  */
-            {
-              nexttick.tv_sec++;
-              nexttick.tv_usec = 0;
-            }
-          time_ev = pth_event (PTH_EVENT_TIME, nexttick);
-        }
-
       /* Take a copy of the fdset.  */
       read_fdset = fdset;
 
       /* Take a copy of the fdset.  */
       read_fdset = fdset;
 
-      if (time_ev)
-        pth_event_concat (ev, time_ev, NULL);
+      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);
 
 
-      ret = pth_select_ev (nfd+1, &read_fdset, NULL, NULL, NULL, ev);
+#ifndef HAVE_W32_SYSTEM
+      ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout, npth_sigev_sigmask());
+      saved_errno = errno;
 
 
-      if (time_ev)
-        pth_event_isolate (time_ev);
+      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
 
 
-      if (ret == -1)
-        {
-          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 (_("pth_select failed: %s - waiting 1s\n"),
-                     strerror (errno));
-          pth_sleep (1);
+      if (ret == -1 && saved_errno != EINTR)
+       {
+          log_error (_("npth_pselect failed: %s - waiting 1s\n"),
+                     strerror (saved_errno));
+          npth_sleep (1);
           continue;
        }
 
           continue;
        }
 
-      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 ();
-        }
-
-
-      /* 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, NULL);
+      if (ret <= 0)
+       /* Interrupt or timeout.  Will be handled when calculating the
+          next timeout.  */
+       continue;
 
       if (!shutdown_pending && FD_ISSET (FD2INT (listen_fd), &read_fdset))
        {
           plen = sizeof paddr;
 
       if (!shutdown_pending && FD_ISSET (FD2INT (listen_fd), &read_fdset))
        {
           plen = sizeof paddr;
-         fd = INT2FD (pth_accept (FD2INT(listen_fd),
-                                   (struct sockaddr *)&paddr, &plen));
+         fd = INT2FD (npth_accept (FD2INT(listen_fd),
+                                   (struct sockaddr *)&paddr, &plen));
          if (fd == GNUPG_INVALID_FD)
            {
              log_error ("accept failed: %s\n", strerror (errno));
          if (fd == GNUPG_INVALID_FD)
            {
              log_error ("accept failed: %s\n", strerror (errno));
@@ -1904,27 +2121,29 @@ handle_connections (assuan_fd_t listen_fd)
             {
               char threadname[50];
               union int_and_ptr_u argval;
             {
               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;
               argval.afd = fd;
               snprintf (threadname, sizeof threadname-1,
                         "conn fd=%d", FD2INT(fd));
               threadname[sizeof threadname -1] = 0;
-              pth_attr_set (tattr, PTH_ATTR_NAME, threadname);
-              if (!pth_spawn (tattr, start_connection_thread, argval.aptr))
+
+              ret = npth_create (&thread, &tattr,
+                                 start_connection_thread, argval.aptr);
+             if (ret)
                 {
                   log_error ("error spawning connection handler: %s\n",
                 {
                   log_error ("error spawning connection handler: %s\n",
-                             strerror (errno) );
+                             strerror (ret) );
                   assuan_sock_close (fd);
                 }
                   assuan_sock_close (fd);
                 }
+             npth_setname_np (thread, threadname);
             }
           fd = GNUPG_INVALID_FD;
        }
     }
 
             }
           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));
 }
   cleanup ();
   log_info ("%s %s stopped\n", strusage(11), strusage(13));
 }