1 /* ldap-wrapper.c - LDAP access via a wrapper process
2  * Copyright (C) 2004, 2005, 2007, 2008, 2018 g10 Code GmbH
3  * Copyright (C) 2010 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 /*
22  * We can't use LDAP directly for these reasons:
23  *
24  * 1. The LDAP library is linked to separate crypto library like
25  *    OpenSSL and even if it is linked to the library we use in dirmngr
26  *    (ntbtls or gnutls) it is sometimes a different version of that
27  *    library with all the surprising failures you may get due to this.
28  *
29  * 2. It is huge library in particular if TLS comes into play.  So
30  *    problems with unfreed memory might turn up and we don't want
31  *    this in a long running daemon.
32  *
33  * 3. There is no easy way for timeouts. In particular the timeout
34  *    value does not work for DNS lookups (well, this is usual) and it
35  *    seems not to work while loading a large attribute like a
36  *    CRL. Having a separate process allows us to either tell the
37  *    process to commit suicide or have our own housekepping function
38  *    kill it after some time.  The latter also allows proper
39  *    cancellation of a query at any point of time.
40  *
41  * 4. Given that we are going out to the network and usually get back
42  *    a long response, the fork/exec overhead is acceptable.
43  *
44  * Note that under WindowsCE the number of processes is strongly
45  * limited (32 processes including the kernel processes) and thus we
46  * don't use the process approach but implement a different wrapper in
47  * ldap-wrapper-ce.c.
48  */
49 
50 
51 #include <config.h>
52 
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <errno.h>
57 #include <unistd.h>
58 #include <fcntl.h>
59 #include <time.h>
60 #include <npth.h>
61 
62 #include "dirmngr.h"
63 #include "../common/exechelp.h"
64 #include "misc.h"
65 #include "ldap-wrapper.h"
66 
67 
68 #ifdef HAVE_W32_SYSTEM
69 #define setenv(a,b,c) SetEnvironmentVariable ((a),(b))
70 #else
71 #define pth_close(fd) close(fd)
72 #endif
73 
74 /* In case sysconf does not return a value we need to have a limit. */
75 #ifdef _POSIX_OPEN_MAX
76 #define MAX_OPEN_FDS _POSIX_OPEN_MAX
77 #else
78 #define MAX_OPEN_FDS 20
79 #endif
80 
81 #define INACTIVITY_TIMEOUT (opt.ldaptimeout + 60*5)  /* seconds */
82 
83 #define TIMERTICK_INTERVAL 2
84 
85 /* To keep track of the LDAP wrapper state we use this structure.  */
86 struct wrapper_context_s
87 {
88   struct wrapper_context_s *next;
89 
90   pid_t pid;           /* The pid of the wrapper process. */
91   int printable_pid;   /* Helper to print diagnostics after the process has
92                         * been cleaned up. */
93   estream_t fp;        /* Connected with stdout of the ldap wrapper.  */
94   gpg_error_t fp_err;  /* Set to the gpg_error of the last read error
95                         * if any.  */
96   estream_t log_fp;    /* Connected with stderr of the ldap wrapper.  */
97   ctrl_t ctrl;         /* Connection data. */
98   int ready;           /* Internally used to mark to be removed contexts. */
99   ksba_reader_t reader;/* The ksba reader object or NULL. */
100   char *line;          /* Used to print the log lines (malloced). */
101   size_t linesize;     /* Allocated size of LINE.  */
102   size_t linelen;      /* Use size of LINE.  */
103   time_t stamp;        /* The last time we noticed ativity.  */
104   int reaper_idx;      /* Private to ldap_wrapper_thread.   */
105 };
106 
107 
108 
109 /* We keep a global list of spawned wrapper process.  A separate
110  * thread makes use of this list to log error messages and to watch
111  * out for finished processes.  Access to list is protected by a
112  * mutex.  The condition variable is used to wakeup the reaper
113  * thread.  */
114 static struct wrapper_context_s *reaper_list;
115 static npth_mutex_t reaper_list_mutex = NPTH_MUTEX_INITIALIZER;
116 static npth_cond_t  reaper_run_cond  = NPTH_COND_INITIALIZER;
117 
118 /* We need to know whether we are shutting down the process.  */
119 static int shutting_down;
120 
121 
122 
123 /* Close the estream fp and set it to NULL.  */
124 #define SAFE_CLOSE(fp) \
125   do { estream_t _fp = fp; es_fclose (_fp); fp = NULL; } while (0)
126 
127 
128 
129 
130 
131 static void
lock_reaper_list(void)132 lock_reaper_list (void)
133 {
134   if (npth_mutex_lock (&reaper_list_mutex))
135     log_fatal ("%s: failed to acquire mutex: %s\n", __func__,
136                gpg_strerror (gpg_error_from_syserror ()));
137 }
138 
139 
140 static void
unlock_reaper_list(void)141 unlock_reaper_list (void)
142 {
143   if (npth_mutex_unlock (&reaper_list_mutex))
144     log_fatal ("%s: failed to release mutex: %s\n", __func__,
145                gpg_strerror (gpg_error_from_syserror ()));
146 }
147 
148 
149 
150 /* Read a fixed amount of data from READER into BUFFER.  */
151 static gpg_error_t
read_buffer(ksba_reader_t reader,unsigned char * buffer,size_t count)152 read_buffer (ksba_reader_t reader, unsigned char *buffer, size_t count)
153 {
154   gpg_error_t err;
155   size_t nread;
156 
157   while (count)
158     {
159       err = ksba_reader_read (reader, buffer, count, &nread);
160       if (err)
161         return err;
162       buffer += nread;
163       count -= nread;
164     }
165   return 0;
166 }
167 
168 
169 /* Release the wrapper context and kill a running wrapper process. */
170 static void
destroy_wrapper(struct wrapper_context_s * ctx)171 destroy_wrapper (struct wrapper_context_s *ctx)
172 {
173   if (ctx->pid != (pid_t)(-1))
174     {
175       gnupg_kill_process (ctx->pid);
176       gnupg_release_process (ctx->pid);
177     }
178   ksba_reader_release (ctx->reader);
179   SAFE_CLOSE (ctx->fp);
180   SAFE_CLOSE (ctx->log_fp);
181   xfree (ctx->line);
182   xfree (ctx);
183 }
184 
185 
186 /* Print the content of LINE to the log stream but make sure to only
187    print complete lines.  Using NULL for LINE will flush any pending
188    output.  LINE may be modified by this function. */
189 static void
print_log_line(struct wrapper_context_s * ctx,char * line)190 print_log_line (struct wrapper_context_s *ctx, char *line)
191 {
192   char *s;
193   size_t n;
194 
195   if (!line)
196     {
197       if (ctx->line && ctx->linelen)
198         {
199 
200           log_info ("%s\n", ctx->line);
201           ctx->linelen = 0;
202         }
203       return;
204     }
205 
206   while ((s = strchr (line, '\n')))
207     {
208       *s = 0;
209       if (ctx->line && ctx->linelen)
210         {
211           log_info ("%s", ctx->line);
212           ctx->linelen = 0;
213           log_printf ("%s\n", line);
214         }
215       else
216         log_info ("%s\n", line);
217       line = s + 1;
218     }
219   n = strlen (line);
220   if (n)
221     {
222       if (ctx->linelen + n + 1 >= ctx->linesize)
223         {
224           char *tmp;
225           size_t newsize;
226 
227           newsize = ctx->linesize + ((n + 255) & ~255) + 1;
228           tmp = (ctx->line ? xtryrealloc (ctx->line, newsize)
229                            : xtrymalloc (newsize));
230           if (!tmp)
231             {
232               log_error (_("error printing log line: %s\n"), strerror (errno));
233               return;
234             }
235           ctx->line = tmp;
236           ctx->linesize = newsize;
237         }
238       memcpy (ctx->line + ctx->linelen, line, n);
239       ctx->linelen += n;
240       ctx->line[ctx->linelen] = 0;
241     }
242 }
243 
244 
245 /* Read data from the log stream.  Returns true if the log stream
246  * indicated EOF or error.  */
247 static int
read_log_data(struct wrapper_context_s * ctx)248 read_log_data (struct wrapper_context_s *ctx)
249 {
250   int rc;
251   size_t n;
252   char line[256];
253 
254   rc = es_read (ctx->log_fp, line, sizeof line - 1, &n);
255   if (rc || !n)  /* Error or EOF.  */
256     {
257       if (rc)
258         {
259           gpg_error_t err = gpg_error_from_syserror ();
260           if (gpg_err_code (err) == GPG_ERR_EAGAIN)
261             return 0;
262           log_error (_("error reading log from ldap wrapper %d: %s\n"),
263                      (int)ctx->pid, gpg_strerror (err));
264         }
265       print_log_line (ctx, NULL);  /* Flush.  */
266       SAFE_CLOSE (ctx->log_fp);
267       return 1;
268     }
269 
270   line[n] = 0;
271   print_log_line (ctx, line);
272   if (ctx->stamp != (time_t)(-1))
273     ctx->stamp = time (NULL);
274   return 0;
275 }
276 
277 
278 /* This function is run by a separate thread to maintain the list of
279    wrappers and to log error messages from these wrappers.  */
280 void *
ldap_reaper_thread(void * dummy)281 ldap_reaper_thread (void *dummy)
282 {
283   gpg_error_t err;
284   struct wrapper_context_s *ctx;
285   struct wrapper_context_s *ctx_prev;
286   struct timespec abstime;
287   struct timespec curtime;
288   struct timespec timeout;
289   int millisecs;
290   gpgrt_poll_t *fparray = NULL;
291   int fparraysize = 0;
292   int count, i;
293   int ret;
294   time_t exptime;
295 
296   (void)dummy;
297 
298   npth_clock_gettime (&abstime);
299   abstime.tv_sec += TIMERTICK_INTERVAL;
300 
301   for (;;)
302     {
303       int any_action = 0;
304 
305       /* Wait until we are needed and then setup the FPARRAY.  */
306       /* Note: There is one unlock inside the block!  */
307       lock_reaper_list ();
308       {
309         while (!reaper_list && !shutting_down)
310           {
311             if (npth_cond_wait (&reaper_run_cond, &reaper_list_mutex))
312               log_error ("ldap-reaper: waiting on condition failed: %s\n",
313                          gpg_strerror (gpg_error_from_syserror ()));
314           }
315 
316         for (count = 0, ctx = reaper_list; ctx; ctx = ctx->next)
317           if (ctx->log_fp)
318             count++;
319         if (count > fparraysize || !fparray)
320           {
321             /* Need to realloc the array.  We simply discard it and
322              * replace it by a new one.  */
323             xfree (fparray);
324             fparray = xtrycalloc (count? count : 1, sizeof *fparray);
325             if (!fparray)
326               {
327                 err = gpg_error_from_syserror ();
328                 log_error ("ldap-reaper can't allocate poll array: %s"
329                            " - waiting 1s\n", gpg_strerror (err));
330                 /* Note: Here we unlock and continue! */
331                 unlock_reaper_list ();
332                 gnupg_sleep (1);
333                 continue;
334             }
335             fparraysize = count;
336           }
337         for (count = 0, ctx = reaper_list; ctx; ctx = ctx->next)
338           {
339             if (ctx->log_fp)
340               {
341                 log_assert (count < fparraysize);
342                 fparray[count].stream = ctx->log_fp;
343                 fparray[count].want_read = 1;
344                 fparray[count].ignore = 0;
345                 ctx->reaper_idx = count;
346                 count++;
347               }
348             else
349               {
350                 ctx->reaper_idx = -1;
351                 fparray[count].ignore = 1;
352               }
353           }
354         for (i=count; i < fparraysize; i++)
355           fparray[i].ignore = 1;
356       }
357       unlock_reaper_list (); /* Note the one unlock inside the block.  */
358 
359       /* Compute the next timeout.  */
360       npth_clock_gettime (&curtime);
361       if (!(npth_timercmp (&curtime, &abstime, <)))
362 	{
363 	  /* Inactivity is checked below.  Nothing else to do.  */
364 	  npth_clock_gettime (&abstime);
365 	  abstime.tv_sec += TIMERTICK_INTERVAL;
366 	}
367       npth_timersub (&abstime, &curtime, &timeout);
368       millisecs = timeout.tv_sec * 1000;
369       millisecs += timeout.tv_nsec / 1000000;
370       if (millisecs < 0)
371         millisecs = 1;
372 
373       if (DBG_EXTPROG)
374         {
375           log_debug ("ldap-reaper: next run (count=%d size=%d timeout=%d)\n",
376                      count, fparraysize, millisecs);
377           for (count=0; count < fparraysize; count++)
378             if (!fparray[count].ignore)
379               log_debug ("ldap-reaper: fp[%d] stream=%p %s\n",
380                          count, fparray[count].stream,
381                          fparray[count].want_read? "want_read":"");
382         }
383 
384       ret = es_poll (fparray, fparraysize, millisecs);
385       if (ret < 0)
386 	{
387           err = gpg_error_from_syserror ();
388           log_error ("ldap-reaper failed to poll: %s"
389                      " - waiting 1s\n", gpg_strerror (err));
390           /* In case the reason for the error is a too large array, we
391            * release it so that it will be allocated smaller in the
392            * next round.  */
393           xfree (fparray);
394           fparray = NULL;
395           fparraysize = 0;
396           gnupg_sleep (1);
397           continue;
398 	}
399 
400       if (DBG_EXTPROG)
401         {
402           for (count=0; count < fparraysize; count++)
403             if (!fparray[count].ignore)
404               log_debug ("ldap-reaper: fp[%d] stream=%p rc=%d %c%c%c%c%c%c%c\n",
405                          count, fparray[count].stream, ret,
406                          fparray[count].got_read? 'r':'-',
407                          fparray[count].got_write?'w':'-',
408                          fparray[count].got_oob?  'o':'-',
409                          fparray[count].got_rdhup?'H':'-',
410                          fparray[count].got_err?  'e':'-',
411                          fparray[count].got_hup?  'h':'-',
412                          fparray[count].got_nval? 'n':'-');
413         }
414 
415       /* All timestamps before exptime should be considered expired.  */
416       exptime = time (NULL);
417       if (exptime > INACTIVITY_TIMEOUT)
418         exptime -= INACTIVITY_TIMEOUT;
419 
420       lock_reaper_list ();
421       {
422         for (ctx = reaper_list; ctx; ctx = ctx->next)
423           {
424             /* Check whether there is any logging to be done.  We need
425              * to check FPARRAYSIZE because it can be 0 in case
426              * es_poll returned a timeout.  */
427             if (fparraysize && ctx->log_fp && ctx->reaper_idx >= 0)
428               {
429                 log_assert (ctx->reaper_idx < fparraysize);
430                 if (fparray[ctx->reaper_idx].got_read)
431                   {
432                     if (read_log_data (ctx))
433                       {
434                         SAFE_CLOSE (ctx->log_fp);
435                         any_action = 1;
436                       }
437                   }
438               }
439 
440             /* Check whether the process is still running.  */
441             if (ctx->pid != (pid_t)(-1))
442               {
443                 int status;
444 
445                 err = gnupg_wait_process ("[dirmngr_ldap]", ctx->pid, 0,
446                                           &status);
447                 if (!err)
448                   {
449                     if (DBG_EXTPROG)
450                       log_info (_("ldap wrapper %d ready"), (int)ctx->pid);
451                     ctx->ready = 1;
452                     gnupg_release_process (ctx->pid);
453                     ctx->pid = (pid_t)(-1);
454                     any_action = 1;
455                   }
456                 else if (gpg_err_code (err) == GPG_ERR_GENERAL)
457                   {
458                     if (status == 10)
459                       log_info (_("ldap wrapper %d ready: timeout\n"),
460                                 (int)ctx->pid);
461                     else
462                       log_info (_("ldap wrapper %d ready: exitcode=%d\n"),
463                                 (int)ctx->pid, status);
464                     ctx->ready = 1;
465                     gnupg_release_process (ctx->pid);
466                     ctx->pid = (pid_t)(-1);
467                     any_action = 1;
468                   }
469                 else if (gpg_err_code (err) != GPG_ERR_TIMEOUT)
470                   {
471                     log_error (_("waiting for ldap wrapper %d failed: %s\n"),
472                                (int)ctx->pid, gpg_strerror (err));
473                     any_action = 1;
474                   }
475               }
476 
477             /* Check whether we should terminate the process. */
478             if (ctx->pid != (pid_t)(-1)
479                 && ctx->stamp != (time_t)(-1) && ctx->stamp < exptime)
480               {
481                 gnupg_kill_process (ctx->pid);
482                 ctx->stamp = (time_t)(-1);
483                 log_info (_("ldap wrapper %d stalled - killing\n"),
484                           (int)ctx->pid);
485                 /* We need to close the log stream because the cleanup
486                  * loop waits for it.  */
487                 SAFE_CLOSE (ctx->log_fp);
488                 any_action = 1;
489               }
490           }
491 
492         /* If something has been printed to the log file or we got an
493          * EOF from a wrapper, we now print the list of active
494          * wrappers.  */
495         if (any_action && DBG_EXTPROG)
496           {
497             log_debug ("ldap worker states:\n");
498             for (ctx = reaper_list; ctx; ctx = ctx->next)
499               log_debug ("  c=%p pid=%d/%d rdr=%p logfp=%p"
500                          " ctrl=%p/%d la=%lu rdy=%d\n",
501                          ctx,
502                          (int)ctx->pid, (int)ctx->printable_pid,
503                          ctx->reader, ctx->log_fp,
504                          ctx->ctrl, ctx->ctrl? ctx->ctrl->refcount:0,
505                          (unsigned long)ctx->stamp, ctx->ready);
506           }
507 
508         /* An extra loop to check whether ready marked wrappers may be
509          * removed.  We may only do so if the ksba reader object is
510          * not anymore in use or we are in shutdown state.  */
511       again:
512         for (ctx_prev=NULL, ctx=reaper_list; ctx; ctx_prev=ctx, ctx=ctx->next)
513           {
514             if (ctx->ready
515                 && ((!ctx->log_fp && !ctx->reader) || shutting_down))
516               {
517                 if (ctx_prev)
518                   ctx_prev->next = ctx->next;
519                 else
520                   reaper_list = ctx->next;
521                 destroy_wrapper (ctx);
522                 goto again;
523               }
524           }
525       }
526       unlock_reaper_list ();
527     }
528 
529   /*NOTREACHED*/
530   return NULL; /* Make the compiler happy.  */
531 }
532 
533 
534 
535 /* Start the reaper thread for the ldap wrapper.  */
536 void
ldap_reaper_launch_thread(void)537 ldap_reaper_launch_thread (void)
538 {
539   static int done;
540   npth_attr_t tattr;
541   npth_t thread;
542   int err;
543 
544   if (done)
545     return;
546   done = 1;
547 
548 #ifdef HAVE_W32_SYSTEM
549   /* Static init does not yet work in W32 nPth.  */
550   if (npth_cond_init (&reaper_run_cond, NULL))
551     log_fatal ("%s: failed to init condition variable: %s\n",
552                __func__, gpg_strerror (gpg_error_from_syserror ()));
553 #endif
554 
555   npth_attr_init (&tattr);
556   npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
557 
558   if (npth_create (&thread, &tattr, ldap_reaper_thread, NULL))
559     {
560       err = gpg_error_from_syserror ();
561       log_error ("error spawning ldap reaper reaper thread: %s\n",
562                  gpg_strerror (err) );
563       dirmngr_exit (1);
564     }
565   npth_setname_np (thread, "ldap-reaper");
566   npth_attr_destroy (&tattr);
567 }
568 
569 
570 
571 /* Wait until all ldap wrappers have terminated.  We assume that the
572    kill has already been sent to all of them.  */
573 void
ldap_wrapper_wait_connections()574 ldap_wrapper_wait_connections ()
575 {
576   lock_reaper_list ();
577   {
578     shutting_down = 1;
579     if (npth_cond_signal (&reaper_run_cond))
580       log_error ("%s: Ooops: signaling condition failed: %s\n",
581                  __func__, gpg_strerror (gpg_error_from_syserror ()));
582   }
583   unlock_reaper_list ();
584   while (reaper_list)
585     gnupg_usleep (200);
586 }
587 
588 
589 /* This function is to be used to release a context associated with the
590    given reader object. */
591 void
ldap_wrapper_release_context(ksba_reader_t reader)592 ldap_wrapper_release_context (ksba_reader_t reader)
593 {
594   struct wrapper_context_s *ctx;
595 
596   if (!reader )
597     return;
598 
599   lock_reaper_list ();
600   {
601     for (ctx=reaper_list; ctx; ctx=ctx->next)
602       if (ctx->reader == reader)
603         {
604           if (DBG_EXTPROG)
605             log_debug ("releasing ldap worker c=%p pid=%d/%d rdr=%p"
606                        " ctrl=%p/%d\n", ctx,
607                        (int)ctx->pid, (int)ctx->printable_pid,
608                        ctx->reader,
609                        ctx->ctrl, ctx->ctrl? ctx->ctrl->refcount:0);
610 
611           ctx->reader = NULL;
612           SAFE_CLOSE (ctx->fp);
613           if (ctx->ctrl)
614             {
615               ctx->ctrl->refcount--;
616               ctx->ctrl = NULL;
617             }
618           if (ctx->fp_err)
619             log_info ("%s: reading from ldap wrapper %d failed: %s\n",
620                       __func__, ctx->printable_pid, gpg_strerror (ctx->fp_err));
621           break;
622         }
623   }
624   unlock_reaper_list ();
625 }
626 
627 
628 /* Cleanup all resources held by the connection associated with
629    CTRL.  This is used after a cancel to kill running wrappers.  */
630 void
ldap_wrapper_connection_cleanup(ctrl_t ctrl)631 ldap_wrapper_connection_cleanup (ctrl_t ctrl)
632 {
633   struct wrapper_context_s *ctx;
634 
635   lock_reaper_list ();
636   {
637     for (ctx=reaper_list; ctx; ctx=ctx->next)
638       if (ctx->ctrl && ctx->ctrl == ctrl)
639         {
640           ctx->ctrl->refcount--;
641           ctx->ctrl = NULL;
642           if (ctx->pid != (pid_t)(-1))
643             gnupg_kill_process (ctx->pid);
644           if (ctx->fp_err)
645             log_info ("%s: reading from ldap wrapper %d failed: %s\n",
646                       __func__, ctx->printable_pid, gpg_strerror (ctx->fp_err));
647         }
648   }
649   unlock_reaper_list ();
650 }
651 
652 
653 /* This is the callback used by the ldap wrapper to feed the ksba
654  * reader with the wrapper's stdout.  See the description of
655  * ksba_reader_set_cb for details.  */
656 static int
reader_callback(void * cb_value,char * buffer,size_t count,size_t * nread)657 reader_callback (void *cb_value, char *buffer, size_t count,  size_t *nread)
658 {
659   struct wrapper_context_s *ctx = cb_value;
660   size_t nleft = count;
661   struct timespec abstime;
662   struct timespec curtime;
663   struct timespec timeout;
664   int millisecs;
665   gpgrt_poll_t fparray[1];
666   int ret;
667   gpg_error_t err;
668 
669 
670   /* FIXME: We might want to add some internal buffering because the
671      ksba code does not do any buffering for itself (because a ksba
672      reader may be detached from another stream to read other data and
673      then it would be cumbersome to get back already buffered stuff).  */
674 
675   if (!buffer && !count && !nread)
676     return -1; /* Rewind is not supported. */
677 
678   /* If we ever encountered a read error, don't continue (we don't want to
679      possibly overwrite the last error cause).  Bail out also if the
680      file descriptor has been closed. */
681   if (ctx->fp_err || !ctx->fp)
682     {
683       *nread = 0;
684       return -1;
685     }
686 
687   memset (fparray, 0, sizeof fparray);
688   fparray[0].stream = ctx->fp;
689   fparray[0].want_read = 1;
690 
691   npth_clock_gettime (&abstime);
692   abstime.tv_sec += TIMERTICK_INTERVAL;
693 
694   while (nleft > 0)
695     {
696       npth_clock_gettime (&curtime);
697       if (!(npth_timercmp (&curtime, &abstime, <)))
698 	{
699 	  err = dirmngr_tick (ctx->ctrl);
700           if (err)
701             {
702               ctx->fp_err = err;
703               SAFE_CLOSE (ctx->fp);
704               return -1;
705             }
706 	  npth_clock_gettime (&abstime);
707 	  abstime.tv_sec += TIMERTICK_INTERVAL;
708 	}
709       npth_timersub (&abstime, &curtime, &timeout);
710       millisecs = timeout.tv_sec * 1000;
711       millisecs += timeout.tv_nsec / 1000000;
712       if (millisecs < 0)
713         millisecs = 1;
714 
715       if (DBG_EXTPROG)
716         {
717           log_debug ("%s: fp[0] stream=%p %s\n",
718                      __func__, fparray[0].stream,
719                      fparray[0].want_read?"want_read":"");
720         }
721 
722       ret = es_poll (fparray, DIM (fparray), millisecs);
723       if (ret < 0)
724 	{
725           ctx->fp_err = gpg_error_from_syserror ();
726           log_error ("error polling stdout of ldap wrapper %d: %s\n",
727                      ctx->printable_pid, gpg_strerror (ctx->fp_err));
728           SAFE_CLOSE (ctx->fp);
729           return -1;
730         }
731       if (DBG_EXTPROG)
732         {
733           log_debug ("%s: fp[0] stream=%p rc=%d %c%c%c%c%c%c%c\n",
734                      __func__, fparray[0].stream, ret,
735                      fparray[0].got_read? 'r':'-',
736                      fparray[0].got_write?'w':'-',
737                      fparray[0].got_oob?  'o':'-',
738                      fparray[0].got_rdhup?'H':'-',
739                      fparray[0].got_err?  'e':'-',
740                      fparray[0].got_hup?  'h':'-',
741                      fparray[0].got_nval? 'n':'-');
742         }
743       if (!ret)
744         {
745           /* Timeout.  Will be handled when calculating the next timeout.  */
746           continue;
747         }
748 
749       if (fparray[0].got_read)
750         {
751           size_t n;
752 
753           if (es_read (ctx->fp, buffer, nleft, &n))
754             {
755               ctx->fp_err = gpg_error_from_syserror ();
756               if (gpg_err_code (ctx->fp_err) == GPG_ERR_EAGAIN)
757                 ctx->fp_err = 0;
758               else
759                 {
760                   log_error ("%s: error reading: %s (%d)\n",
761                              __func__, gpg_strerror (ctx->fp_err), ctx->fp_err);
762                   SAFE_CLOSE (ctx->fp);
763                   return -1;
764                 }
765             }
766           else if (!n) /* EOF */
767             {
768               if (nleft == count)
769                 return -1; /* EOF. */
770               break;
771             }
772           nleft -= n;
773           buffer += n;
774           if (n > 0 && ctx->stamp != (time_t)(-1))
775             ctx->stamp = time (NULL);
776         }
777     }
778   *nread = count - nleft;
779 
780   return 0;
781 }
782 
783 
784 /* Fork and exec the LDAP wrapper and return a new libksba reader
785    object at READER.  ARGV is a NULL terminated list of arguments for
786    the wrapper.  The function returns 0 on success or an error code.
787 
788    Special hack to avoid passing a password through the command line
789    which is globally visible: If the first element of ARGV is "--pass"
790    it will be removed and instead the environment variable
791    DIRMNGR_LDAP_PASS will be set to the next value of ARGV.  On modern
792    OSes the environment is not visible to other users.  For those old
793    systems where it can't be avoided, we don't want to go into the
794    hassle of passing the password via stdin; it's just too complicated
795    and an LDAP password used for public directory lookups should not
796    be that confidential.  */
797 gpg_error_t
ldap_wrapper(ctrl_t ctrl,ksba_reader_t * reader,const char * argv[])798 ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
799 {
800   gpg_error_t err;
801   pid_t pid;
802   struct wrapper_context_s *ctx;
803   int i;
804   int j;
805   const char **arg_list;
806   const char *pgmname;
807   estream_t outfp, errfp;
808 
809   /* It would be too simple to connect stderr just to our logging
810      stream.  The problem is that if we are running multi-threaded
811      everything gets intermixed.  Clearly we don't want this.  So the
812      only viable solutions are either to have another thread
813      responsible for logging the messages or to add an option to the
814      wrapper module to do the logging on its own.  Given that we anyway
815      need a way to reap the child process and this is best done using a
816      general reaping thread, that thread can do the logging too. */
817   ldap_reaper_launch_thread ();
818 
819   *reader = NULL;
820 
821   /* Files: We need to prepare stdin and stdout.  We get stderr from
822      the function.  */
823   if (!opt.ldap_wrapper_program || !*opt.ldap_wrapper_program)
824     pgmname = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR_LDAP);
825   else
826     pgmname = opt.ldap_wrapper_program;
827 
828   /* Create command line argument array.  */
829   for (i = 0; argv[i]; i++)
830     ;
831   arg_list = xtrycalloc (i + 2, sizeof *arg_list);
832   if (!arg_list)
833     {
834       err = gpg_error_from_syserror ();
835       log_error (_("error allocating memory: %s\n"), strerror (errno));
836       return err;
837     }
838   for (i = j = 0; argv[i]; i++, j++)
839     if (!i && argv[i + 1] && !strcmp (*argv, "--pass"))
840       {
841 	arg_list[j] = "--env-pass";
842 	setenv ("DIRMNGR_LDAP_PASS", argv[1], 1);
843 	i++;
844       }
845     else
846       arg_list[j] = (char*) argv[i];
847 
848   ctx = xtrycalloc (1, sizeof *ctx);
849   if (!ctx)
850     {
851       err = gpg_error_from_syserror ();
852       log_error (_("error allocating memory: %s\n"), strerror (errno));
853       xfree (arg_list);
854       return err;
855     }
856 
857   err = gnupg_spawn_process (pgmname, arg_list,
858                              NULL, NULL, GNUPG_SPAWN_NONBLOCK,
859                              NULL, &outfp, &errfp, &pid);
860   if (err)
861     {
862   xfree (arg_list);
863       xfree (ctx);
864       log_error ("error running '%s': %s\n", pgmname, gpg_strerror (err));
865       return err;
866     }
867 
868   ctx->pid = pid;
869   ctx->printable_pid = (int) pid;
870   ctx->fp = outfp;
871   ctx->log_fp = errfp;
872   ctx->ctrl = ctrl;
873   ctrl->refcount++;
874   ctx->stamp = time (NULL);
875 
876   err = ksba_reader_new (reader);
877   if (!err)
878     err = ksba_reader_set_cb (*reader, reader_callback, ctx);
879   if (err)
880     {
881       xfree (arg_list);
882       log_error (_("error initializing reader object: %s\n"),
883                  gpg_strerror (err));
884       destroy_wrapper (ctx);
885       ksba_reader_release (*reader);
886       *reader = NULL;
887       return err;
888     }
889 
890   /* Hook the context into our list of running wrappers.  */
891   lock_reaper_list ();
892   {
893     ctx->reader = *reader;
894     ctx->next = reaper_list;
895     reaper_list = ctx;
896     if (npth_cond_signal (&reaper_run_cond))
897       log_error ("ldap-wrapper: Ooops: signaling condition failed: %s (%d)\n",
898                  gpg_strerror (gpg_error_from_syserror ()), errno);
899   }
900   unlock_reaper_list ();
901 
902   if (DBG_EXTPROG)
903     {
904       log_debug ("ldap wrapper %d started (%p, %s)",
905                  (int)ctx->pid, ctx->reader, pgmname);
906       for (i=0; arg_list[i]; i++)
907         log_printf (" [%s]", arg_list[i]);
908       log_printf ("\n");
909     }
910   xfree (arg_list);
911 
912 
913   /* Need to wait for the first byte so we are able to detect an empty
914      output and not let the consumer see an EOF without further error
915      indications.  The CRL loading logic assumes that after return
916      from this function, a failed search (e.g. host not found ) is
917      indicated right away. */
918   {
919     unsigned char c;
920 
921     err = read_buffer (*reader, &c, 1);
922     if (err)
923       {
924         ldap_wrapper_release_context (*reader);
925         ksba_reader_release (*reader);
926         *reader = NULL;
927         if (gpg_err_code (err) == GPG_ERR_EOF)
928           return gpg_error (GPG_ERR_NO_DATA);
929         else
930           return err;
931       }
932     ksba_reader_unread (*reader, &c, 1);
933   }
934 
935   return 0;
936 }
937