ssh: Improve key lookup for many keys.
[gnupg.git] / dirmngr / dirmngr_ldap.c
index f862081..1b513ea 100644 (file)
@@ -1,21 +1,21 @@
 /* dirmngr-ldap.c  -  The LDAP helper for dirmngr.
- *     Copyright (C) 2004 g10 Code GmbH
+ * Copyright (C) 2004 g10 Code GmbH
+ * Copyright (C) 2010 Free Software Foundation, Inc.
  *
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <stddef.h>
 #include <stdarg.h>
 #include <string.h>
-#include <signal.h>
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
 #include <errno.h>
 #include <assert.h>
 #include <sys/time.h>
 #include <unistd.h>
+#ifndef USE_LDAPWRAPPER
+# include <npth.h>
+#endif
 
 #ifdef HAVE_W32_SYSTEM
 #include <winsock2.h>
 
 #include "i18n.h"
 #include "util.h"
+#include "../common/init.h"
+
+/* With the ldap wrapper, there is no need for the npth_unprotect and leave
+   functions; thus we redefine them to nops.  If we are not using the
+   ldap wrapper process we need to include the prototype for our
+   module's main function.  */
+#ifdef USE_LDAPWRAPPER
+static void npth_unprotect (void) { }
+static void npth_protect (void) { }
+#else
+# include "./ldap-wrapper.h"
+#endif
+
+#ifdef HAVE_W32CE_SYSTEM
+# include "w32-ldap-help.h"
+# define my_ldap_init(a,b)                      \
+  _dirmngr_ldap_init ((a), (b))
+# define my_ldap_simple_bind_s(a,b,c)           \
+  _dirmngr_ldap_simple_bind_s ((a),(b),(c))
+# define my_ldap_search_st(a,b,c,d,e,f,g,h)     \
+  _dirmngr_ldap_search_st ((a), (b), (c), (d), (e), (f), (g), (h))
+# define my_ldap_first_attribute(a,b,c)         \
+  _dirmngr_ldap_first_attribute ((a),(b),(c))
+# define my_ldap_next_attribute(a,b,c)          \
+  _dirmngr_ldap_next_attribute ((a),(b),(c))
+# define my_ldap_get_values_len(a,b,c)          \
+  _dirmngr_ldap_get_values_len ((a),(b),(c))
+# define my_ldap_free_attr(a)                   \
+  xfree ((a))
+#else
+# define my_ldap_init(a,b)              ldap_init ((a), (b))
+# define my_ldap_simple_bind_s(a,b,c)   ldap_simple_bind_s ((a), (b), (c))
+# define my_ldap_search_st(a,b,c,d,e,f,g,h)     \
+  ldap_search_st ((a), (b), (c), (d), (e), (f), (g), (h))
+# define my_ldap_first_attribute(a,b,c) ldap_first_attribute ((a),(b),(c))
+# define my_ldap_next_attribute(a,b,c)  ldap_next_attribute ((a),(b),(c))
+# define my_ldap_get_values_len(a,b,c)  ldap_get_values_len ((a),(b),(c))
+# define my_ldap_free_attr(a)           ldap_memfree ((a))
+#endif
 
 #define DEFAULT_LDAP_TIMEOUT 100 /* Arbitrary long timeout. */
 
 
 /* Constants for the options.  */
-enum 
+enum
   {
     oQuiet       = 'q',
     oVerbose     = 'v',
@@ -103,8 +147,10 @@ static ARGPARSE_OPTS opts[] = {
 };
 
 
-/* The usual structure for the program flags.  */
-static struct
+/* A structure with module options.  This is not a static variable
+   because if we are not build as a standalone binary, each thread
+   using this module needs to handle its own values.  */
+struct my_opt_s
 {
   int quiet;
   int verbose;
@@ -112,6 +158,8 @@ static struct
   unsigned int alarm_timeout; /* And for the alarm based timeout.  */
   int multi;
 
+  estream_t outstream;    /* Send output to thsi stream.  */
+
   /* Note that we can't use const for the strings because ldap_* are
      not defined that way.  */
   char *proxy; /* Host and Port override.  */
@@ -122,21 +170,25 @@ static struct
   char *dn;    /* Override DN.  */
   char *filter;/* Override filter.  */
   char *attr;  /* Override attribute.  */
-} opt;
+};
+typedef struct my_opt_s *my_opt_t;
 
 
 /* Prototypes.  */
+#ifndef HAVE_W32_SYSTEM
 static void catch_alarm (int dummy);
-static int process_url (const char *url);
+#endif
+static int process_url (my_opt_t myopt, const char *url);
 
 
 
 /* Function called by argparse.c to display information.  */
+#ifdef USE_LDAPWRAPPER
 static const char *
 my_strusage (int level)
 {
   const char *p;
-    
+
   switch(level)
     {
     case 11: p = "dirmngr_ldap (GnuPG)";
@@ -151,39 +203,58 @@ my_strusage (int level)
       break;
     case 41: p =
           _("Syntax: dirmngr_ldap [options] [URL]\n"
-            "Internal LDAP helper for Dirmngr.\n"
-            "Interface and options may change without notice.\n");
+            "Internal LDAP helper for Dirmngr\n"
+            "Interface and options may change without notice\n");
       break;
 
     default: p = NULL;
     }
   return p;
 }
+#endif /*!USE_LDAPWRAPPER*/
 
 
 int
-main (int argc, char **argv )
+#ifdef USE_LDAPWRAPPER
+main (int argc, char **argv)
+#else
+ldap_wrapper_main (char **argv, estream_t outstream)
+#endif
 {
+#ifndef USE_LDAPWRAPPER
+  int argc;
+#endif
   ARGPARSE_ARGS pargs;
   int any_err = 0;
   char *p;
   int only_search_timeout = 0;
+  struct my_opt_s my_opt_buffer;
+  my_opt_t myopt = &my_opt_buffer;
+  char *malloced_buffer1 = NULL;
 
-#ifdef HAVE_W32_SYSTEM
-  /* Yeah, right.  Sigh.  */
-  _setmode (_fileno (stdout), _O_BINARY);
-#endif
+  memset (&my_opt_buffer, 0, sizeof my_opt_buffer);
 
+#ifdef USE_LDAPWRAPPER
   set_strusage (my_strusage);
-  log_set_prefix ("dirmngr_ldap", JNLIB_LOG_WITH_PREFIX); 
-  
-  /* Setup I18N. */
+  log_set_prefix ("dirmngr_ldap", JNLIB_LOG_WITH_PREFIX);
+
+  /* Setup I18N and common subsystems. */
   i18n_init();
 
+  init_common_subsystems (&argc, &argv);
+
+  es_set_binary (es_stdout);
+  myopt->outstream = es_stdout;
+#else /*!USE_LDAPWRAPPER*/
+  myopt->outstream = outstream;
+  for (argc=0; argv[argc]; argc++)
+    ;
+#endif /*!USE_LDAPWRAPPER*/
+
   /* LDAP defaults */
-  opt.timeout.tv_sec = DEFAULT_LDAP_TIMEOUT;
-  opt.timeout.tv_usec = 0;
-  opt.alarm_timeout = 0;
+  myopt->timeout.tv_sec = DEFAULT_LDAP_TIMEOUT;
+  myopt->timeout.tv_usec = 0;
+  myopt->alarm_timeout = 0;
 
   /* Parse the command line.  */
   pargs.argc = &argc;
@@ -193,26 +264,26 @@ main (int argc, char **argv )
     {
       switch (pargs.r_opt)
         {
-        case oVerbose: opt.verbose++; break;
-        case oQuiet: opt.quiet++; break;
-       case oTimeout: 
-         opt.timeout.tv_sec = pargs.r.ret_int; 
-         opt.timeout.tv_usec = 0;
-          opt.alarm_timeout = pargs.r.ret_int;
+        case oVerbose: myopt->verbose++; break;
+        case oQuiet: myopt->quiet++; break;
+       case oTimeout:
+         myopt->timeout.tv_sec = pargs.r.ret_int;
+         myopt->timeout.tv_usec = 0;
+          myopt->alarm_timeout = pargs.r.ret_int;
          break;
         case oOnlySearchTimeout: only_search_timeout = 1; break;
-        case oMulti: opt.multi = 1; break;
-        case oUser: opt.user = pargs.r.ret_str; break;
-        case oPass: opt.pass = pargs.r.ret_str; break;
+        case oMulti: myopt->multi = 1; break;
+        case oUser: myopt->user = pargs.r.ret_str; break;
+        case oPass: myopt->pass = pargs.r.ret_str; break;
         case oEnvPass:
-          opt.pass = getenv ("DIRMNGR_LDAP_PASS");
+          myopt->pass = getenv ("DIRMNGR_LDAP_PASS");
           break;
-        case oProxy: opt.proxy = pargs.r.ret_str; break;
-        case oHost: opt.host = pargs.r.ret_str; break;
-        case oPort: opt.port = pargs.r.ret_int; break;
-        case oDN:   opt.dn = pargs.r.ret_str; break;
-        case oFilter: opt.filter = pargs.r.ret_str; break;
-        case oAttr: opt.attr = pargs.r.ret_str; break;
+        case oProxy: myopt->proxy = pargs.r.ret_str; break;
+        case oHost: myopt->host = pargs.r.ret_str; break;
+        case oPort: myopt->port = pargs.r.ret_int; break;
+        case oDN:   myopt->dn = pargs.r.ret_str; break;
+        case oFilter: myopt->filter = pargs.r.ret_str; break;
+        case oAttr: myopt->attr = pargs.r.ret_str; break;
         case oLogWithPID:
           {
             unsigned int oldflags;
@@ -221,99 +292,121 @@ main (int argc, char **argv )
           }
           break;
 
-        default : pargs.err = 2; break;
+        default :
+#ifdef USE_LDAPWRAPPER
+          pargs.err = ARGPARSE_PRINT_ERROR;
+#else
+          pargs.err = ARGPARSE_PRINT_WARNING;  /* No exit() please.  */
+#endif
+          break;
        }
     }
 
   if (only_search_timeout)
-    opt.alarm_timeout = 0;
+    myopt->alarm_timeout = 0;
 
-  if (opt.proxy)
+  if (myopt->proxy)
     {
-      opt.host = xstrdup (opt.proxy);
-      p = strchr (opt.host, ':');
+      malloced_buffer1 = xtrystrdup (myopt->proxy);
+      if (!malloced_buffer1)
+        {
+          log_error ("error copying string: %s\n", strerror (errno));
+          return 1;
+        }
+      myopt->host = malloced_buffer1;
+      p = strchr (myopt->host, ':');
       if (p)
         {
           *p++ = 0;
-          opt.port = atoi (p);
+          myopt->port = atoi (p);
         }
-      if (!opt.port)
-        opt.port = 389;  /* make sure ports gets overridden.  */
+      if (!myopt->port)
+        myopt->port = 389;  /* make sure ports gets overridden.  */
     }
-        
-  if (opt.port < 0 || opt.port > 65535)
-    log_error (_("invalid port number %d\n"), opt.port);
 
+  if (myopt->port < 0 || myopt->port > 65535)
+    log_error (_("invalid port number %d\n"), myopt->port);
+
+#ifdef USE_LDAPWRAPPER
   if (log_get_errorcount (0))
     exit (2);
-
   if (argc < 1)
     usage (1);
+#else
+  /* All passed arguments should be fine in this case.  */
+  assert (argc);
+#endif
 
-  if (opt.alarm_timeout)
+#ifdef USE_LDAPWRAPPER
+  if (myopt->alarm_timeout)
     {
 #ifndef HAVE_W32_SYSTEM
 # if defined(HAVE_SIGACTION) && defined(HAVE_STRUCT_SIGACTION)
       struct sigaction act;
-      
+
       act.sa_handler = catch_alarm;
       sigemptyset (&act.sa_mask);
       act.sa_flags = 0;
       if (sigaction (SIGALRM,&act,NULL))
-# else 
+# else
       if (signal (SIGALRM, catch_alarm) == SIG_ERR)
 # endif
           log_fatal ("unable to register timeout handler\n");
 #endif
     }
+#endif /*USE_LDAPWRAPPER*/
 
   for (; argc; argc--, argv++)
-    if (process_url (*argv))
+    if (process_url (myopt, *argv))
       any_err = 1;
 
+  xfree (malloced_buffer1);
   return any_err;
 }
 
-
+#ifndef HAVE_W32_SYSTEM
 static void
 catch_alarm (int dummy)
 {
   (void)dummy;
   _exit (10);
 }
-
+#endif
 
 static void
-set_timeout (void)
+set_timeout (my_opt_t myopt)
 {
-#ifndef HAVE_W32_SYSTEM
+#ifdef HAVE_W32_SYSTEM
   /* FIXME for W32.  */
-  if (opt.alarm_timeout)
-    alarm (opt.alarm_timeout);
+  (void)myopt;
+#else
+  if (myopt->alarm_timeout)
+    alarm (myopt->alarm_timeout);
 #endif
 }
 
 
 /* Helper for fetch_ldap().  */
 static int
-print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr)
+print_ldap_entries (my_opt_t myopt, LDAP *ld, LDAPMessage *msg, char *want_attr)
 {
   LDAPMessage *item;
   int any = 0;
 
-  for (item = ldap_first_entry (ld, msg); item;
-       item = ldap_next_entry (ld, item))
+  for (npth_unprotect (), item = ldap_first_entry (ld, msg), npth_protect ();
+       item;
+       npth_unprotect (), item = ldap_next_entry (ld, item), npth_protect ())
     {
       BerElement *berctx;
       char *attr;
 
-      if (opt.verbose > 1)
-        log_info (_("scanning result for attribute `%s'\n"),
+      if (myopt->verbose > 1)
+        log_info (_("scanning result for attribute '%s'\n"),
                   want_attr? want_attr : "[all]");
 
-      if (opt.multi)
+      if (myopt->multi)
         { /*  Write item marker. */
-          if (fwrite ("I\0\0\0\0", 5, 1, stdout) != 1)
+          if (es_fwrite ("I\0\0\0\0", 5, 1, myopt->outstream) != 1)
             {
               log_error (_("error writing to stdout: %s\n"),
                          strerror (errno));
@@ -321,17 +414,20 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr)
             }
         }
 
-          
-      for (attr = ldap_first_attribute (ld, item, &berctx); attr;
-           attr = ldap_next_attribute (ld, item, berctx))
+
+      for (npth_unprotect (), attr = my_ldap_first_attribute (ld, item, &berctx),
+             npth_protect ();
+           attr;
+           npth_unprotect (), attr = my_ldap_next_attribute (ld, item, berctx),
+             npth_protect ())
         {
           struct berval **values;
           int idx;
 
-          if (opt.verbose > 1)
-            log_info (_("          available attribute `%s'\n"), attr);
-          
-          set_timeout ();
+          if (myopt->verbose > 1)
+            log_info (_("          available attribute '%s'\n"), attr);
+
+          set_timeout (myopt);
 
           /* I case we want only one attribute we do a case
              insensitive compare without the optional extension
@@ -355,32 +451,34 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr)
                 *cp2 = ';';
               if (cmpres)
                 {
-                  ldap_memfree (attr);
+                  my_ldap_free_attr (attr);
                   continue; /* Not found:  Try next attribute.  */
                 }
             }
 
-          values = ldap_get_values_len (ld, item, attr);
-  
+          npth_unprotect ();
+          values = my_ldap_get_values_len (ld, item, attr);
+          npth_protect ();
+
           if (!values)
             {
-              if (opt.verbose)
-                log_info (_("attribute `%s' not found\n"), attr);
-              ldap_memfree (attr);
+              if (myopt->verbose)
+                log_info (_("attribute '%s' not found\n"), attr);
+              my_ldap_free_attr (attr);
               continue;
             }
 
-          if (opt.verbose)
+          if (myopt->verbose)
             {
-              log_info (_("found attribute `%s'\n"), attr);
-              if (opt.verbose > 1)
+              log_info (_("found attribute '%s'\n"), attr);
+              if (myopt->verbose > 1)
                 for (idx=0; values[idx]; idx++)
                   log_info ("         length[%d]=%d\n",
                             idx, (int)values[0]->bv_len);
-              
+
             }
 
-          if (opt.multi)
+          if (myopt->multi)
             { /*  Write attribute marker. */
               unsigned char tmp[5];
               size_t n = strlen (attr);
@@ -390,13 +488,13 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr)
               tmp[2] = (n >> 16);
               tmp[3] = (n >> 8);
               tmp[4] = (n);
-              if (fwrite (tmp, 5, 1, stdout) != 1 
-                  || fwrite (attr, n, 1, stdout) != 1)
+              if (es_fwrite (tmp, 5, 1, myopt->outstream) != 1
+                  || es_fwrite (attr, n, 1, myopt->outstream) != 1)
                 {
                   log_error (_("error writing to stdout: %s\n"),
                              strerror (errno));
                   ldap_value_free_len (values);
-                  ldap_memfree (attr);
+                  my_ldap_free_attr (attr);
                   ber_free (berctx, 0);
                   return -1;
                 }
@@ -404,7 +502,7 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr)
 
           for (idx=0; values[idx]; idx++)
             {
-              if (opt.multi)
+              if (myopt->multi)
                 { /* Write value marker.  */
                   unsigned char tmp[5];
                   size_t n = values[0]->bv_len;
@@ -415,70 +513,41 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr)
                   tmp[3] = (n >> 8);
                   tmp[4] = (n);
 
-                  if (fwrite (tmp, 5, 1, stdout) != 1)
+                  if (es_fwrite (tmp, 5, 1, myopt->outstream) != 1)
                     {
                       log_error (_("error writing to stdout: %s\n"),
                                  strerror (errno));
                       ldap_value_free_len (values);
-                      ldap_memfree (attr);
+                      my_ldap_free_attr (attr);
                       ber_free (berctx, 0);
                       return -1;
                     }
                 }
-#if 1
-             /* Note: this does not work for STDOUT on a Windows
-                console, where it fails with "Not enough space" for
-                CRLs which are 52 KB or larger.  */
-             if (fwrite (values[0]->bv_val, values[0]->bv_len,
-                         1, stdout) != 1)
+
+             if (es_fwrite (values[0]->bv_val, values[0]->bv_len,
+                             1, myopt->outstream) != 1)
                 {
                   log_error (_("error writing to stdout: %s\n"),
                              strerror (errno));
                   ldap_value_free_len (values);
-                  ldap_memfree (attr);
+                  my_ldap_free_attr (attr);
                   ber_free (berctx, 0);
                   return -1;
                 }
-#else
-             /* On Windows console STDOUT, we have to break up the
-                writes into small parts.  */
-             {
-               int n = 0;
-               while (n < values[0]->bv_len)
-                 {
-                   int cnt = values[0]->bv_len - n;
-                   /* The actual limit is (52 * 1024 - 1) on Windows XP SP2.  */
-#define MAX_CNT (32*1024)
-                   if (cnt > MAX_CNT)
-                     cnt = MAX_CNT;
-                   
-                   if (fwrite (((char *) values[0]->bv_val) + n, cnt, 1,
-                               stdout) != 1)
-                     {
-                       log_error (_("error writing to stdout: %s\n"),
-                                  strerror (errno));
-                       ldap_value_free_len (values);
-                       ldap_memfree (attr);
-                       ber_free (berctx, 0);
-                       return -1;
-                     }
-                   n += cnt;
-                 }
-             }
-#endif
+
               any = 1;
-              if (!opt.multi)
+              if (!myopt->multi)
                 break; /* Print only the first value.  */
             }
           ldap_value_free_len (values);
-          ldap_memfree (attr);
-          if (want_attr || !opt.multi)
+          my_ldap_free_attr (attr);
+          if (want_attr || !myopt->multi)
             break; /* We only want to return the first attribute.  */
         }
       ber_free (berctx, 0);
-    } 
+    }
 
-  if (opt.verbose > 1 && any)
+  if (myopt->verbose > 1 && any)
     log_info ("result has been printed\n");
 
   return any?0:-1;
@@ -488,101 +557,113 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr)
 
 /* Helper for the URL based LDAP query. */
 static int
-fetch_ldap (const char *url, const LDAPURLDesc *ludp)
+fetch_ldap (my_opt_t myopt, const char *url, const LDAPURLDesc *ludp)
 {
   LDAP *ld;
   LDAPMessage *msg;
   int rc = 0;
   char *host, *dn, *filter, *attrs[2], *attr;
   int port;
+  int ret;
 
-  host     = opt.host?   opt.host   : ludp->lud_host;
-  port     = opt.port?   opt.port   : ludp->lud_port;
-  dn       = opt.dn?     opt.dn     : ludp->lud_dn;
-  filter   = opt.filter? opt.filter : ludp->lud_filter;
-  attrs[0] = opt.attr?   opt.attr   : ludp->lud_attrs? ludp->lud_attrs[0]:NULL;
+  host     = myopt->host?   myopt->host   : ludp->lud_host;
+  port     = myopt->port?   myopt->port   : ludp->lud_port;
+  dn       = myopt->dn?     myopt->dn     : ludp->lud_dn;
+  filter   = myopt->filter? myopt->filter : ludp->lud_filter;
+  attrs[0] = myopt->attr?   myopt->attr   : ludp->lud_attrs? ludp->lud_attrs[0]:NULL;
   attrs[1] = NULL;
   attr = attrs[0];
 
   if (!port)
     port = (ludp->lud_scheme && !strcmp (ludp->lud_scheme, "ldaps"))? 636:389;
 
-  if (opt.verbose)
+  if (myopt->verbose)
     {
-      log_info (_("processing url `%s'\n"), url);
-      if (opt.user)
-        log_info (_("          user `%s'\n"), opt.user);
-      if (opt.pass)
-        log_info (_("          pass `%s'\n"), *opt.pass?"*****":"");
+      log_info (_("processing url '%s'\n"), url);
+      if (myopt->user)
+        log_info (_("          user '%s'\n"), myopt->user);
+      if (myopt->pass)
+        log_info (_("          pass '%s'\n"), *myopt->pass?"*****":"");
       if (host)
-        log_info (_("          host `%s'\n"), host);
+        log_info (_("          host '%s'\n"), host);
       log_info (_("          port %d\n"), port);
       if (dn)
-        log_info (_("            DN `%s'\n"), dn);
+        log_info (_("            DN '%s'\n"), dn);
       if (filter)
-        log_info (_("        filter `%s'\n"), filter);
-      if (opt.multi && !opt.attr && ludp->lud_attrs)
+        log_info (_("        filter '%s'\n"), filter);
+      if (myopt->multi && !myopt->attr && ludp->lud_attrs)
         {
           int i;
           for (i=0; ludp->lud_attrs[i]; i++)
-            log_info (_("          attr `%s'\n"), ludp->lud_attrs[i]);
+            log_info (_("          attr '%s'\n"), ludp->lud_attrs[i]);
         }
       else if (attr)
-        log_info (_("          attr `%s'\n"), attr);
+        log_info (_("          attr '%s'\n"), attr);
     }
 
 
   if (!host || !*host)
     {
-      log_error (_("no host name in `%s'\n"), url);
+      log_error (_("no host name in '%s'\n"), url);
       return -1;
     }
-  if (!opt.multi && !attr)
+  if (!myopt->multi && !attr)
     {
-      log_error (_("no attribute given for query `%s'\n"), url);
+      log_error (_("no attribute given for query '%s'\n"), url);
       return -1;
     }
 
-  if (!opt.multi && !opt.attr
+  if (!myopt->multi && !myopt->attr
       && ludp->lud_attrs && ludp->lud_attrs[0] && ludp->lud_attrs[1])
     log_info (_("WARNING: using first attribute only\n"));
 
 
-  set_timeout ();
-  ld = ldap_init (host, port);
+  set_timeout (myopt);
+  npth_unprotect ();
+  ld = my_ldap_init (host, port);
+  npth_protect ();
   if (!ld)
     {
-      log_error (_("LDAP init to `%s:%d' failed: %s\n"), 
+      log_error (_("LDAP init to '%s:%d' failed: %s\n"),
                  host, port, strerror (errno));
       return -1;
     }
-  if (ldap_simple_bind_s (ld, opt.user, opt.pass))
+  npth_unprotect ();
+  /* Fixme:  Can we use MYOPT->user or is it shared with other theeads?.  */
+  ret = my_ldap_simple_bind_s (ld, myopt->user, myopt->pass);
+  npth_protect ();
+  if (ret)
     {
-      log_error (_("binding to `%s:%d' failed: %s\n"), 
+      log_error (_("binding to '%s:%d' failed: %s\n"),
                  host, port, strerror (errno));
-      /* FIXME: Need deinit (ld)?  */
+      ldap_unbind (ld);
       return -1;
     }
 
-  set_timeout ();
-  rc = ldap_search_st (ld, dn, ludp->lud_scope, filter,
-                       opt.multi && !opt.attr && ludp->lud_attrs?
-                       ludp->lud_attrs:attrs,
-                       0,
-                       &opt.timeout, &msg);
-  if (rc == LDAP_SIZELIMIT_EXCEEDED && opt.multi)
+  set_timeout (myopt);
+  npth_unprotect ();
+  rc = my_ldap_search_st (ld, dn, ludp->lud_scope, filter,
+                          myopt->multi && !myopt->attr && ludp->lud_attrs?
+                          ludp->lud_attrs:attrs,
+                          0,
+                          &myopt->timeout, &msg);
+  npth_protect ();
+  if (rc == LDAP_SIZELIMIT_EXCEEDED && myopt->multi)
     {
-      if (fwrite ("E\0\0\0\x09truncated", 14, 1, stdout) != 1)
+      if (es_fwrite ("E\0\0\0\x09truncated", 14, 1, myopt->outstream) != 1)
         {
-          log_error (_("error writing to stdout: %s\n"),
-                     strerror (errno));
+          log_error (_("error writing to stdout: %s\n"), strerror (errno));
           return -1;
         }
     }
   else if (rc)
     {
-      log_error (_("searching `%s' failed: %s\n"), 
+#ifdef HAVE_W32CE_SYSTEM
+      log_error ("searching '%s' failed: %d\n", url, rc);
+#else
+      log_error (_("searching '%s' failed: %s\n"),
                  url, ldap_err2string (rc));
+#endif
       if (rc != LDAP_NO_SUCH_OBJECT)
         {
           /* FIXME: Need deinit (ld)?  */
@@ -591,10 +672,10 @@ fetch_ldap (const char *url, const LDAPURLDesc *ludp)
         }
     }
 
-  rc = print_ldap_entries (ld, msg, opt.multi? NULL:attr);
+  rc = print_ldap_entries (myopt, ld, msg, myopt->multi? NULL:attr);
 
   ldap_msgfree (msg);
-  /* FIXME: Need deinit (ld)?  */
+  ldap_unbind (ld);
   return rc;
 }
 
@@ -604,7 +685,7 @@ fetch_ldap (const char *url, const LDAPURLDesc *ludp)
 /* Main processing.  Take the URL and run the LDAP query. The result
    is printed to stdout, errors are logged to the log stream. */
 static int
-process_url (const char *url)
+process_url (my_opt_t myopt, const char *url)
 {
   int rc;
   LDAPURLDesc *ludp = NULL;
@@ -612,19 +693,18 @@ process_url (const char *url)
 
   if (!ldap_is_ldap_url (url))
     {
-      log_error (_("`%s' is not an LDAP URL\n"), url);
+      log_error (_("'%s' is not an LDAP URL\n"), url);
       return -1;
     }
 
   if (ldap_url_parse (url, &ludp))
     {
-      log_error (_("`%s' is an invalid LDAP URL\n"), url);
+      log_error (_("'%s' is an invalid LDAP URL\n"), url);
       return -1;
     }
 
-  rc = fetch_ldap (url, ludp);
+  rc = fetch_ldap (myopt, url, ludp);
 
   ldap_free_urldesc (ludp);
   return rc;
 }
-