Some work on the dirmngr
[gnupg.git] / dirmngr / ldap-wrapper-ce.c
1 /* ldap-wrapper-ce.c - LDAP access via W32 threads
2  * Copyright (C) 2010 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /* 
21    Alternative wrapper for use with WindowsCE.  Under WindowsCE the
22    number of processes is strongly limited (32 processes including the
23    kernel processes) and thus we don't use the process approach but
24    implement a wrapper based on native threads.
25
26    See ldap-wrapper.c for  the standard wrapper interface.
27  */
28
29 #include <config.h>
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <time.h>
38 #include <pth.h>
39
40 #include "dirmngr.h"
41 #include "misc.h"
42 #include "ldap-wrapper.h"
43
44 #ifdef USE_LDAPWRAPPER
45 # error This module is not expected to be build.
46 #endif
47
48
49 /* To keep track of the LDAP wrapper state we use this structure.  */
50 struct wrapper_context_s
51 {
52   struct wrapper_context_s *next;
53
54   pid_t pid;    /* The pid of the wrapper process. */
55   int printable_pid; /* Helper to print diagnostics after the process has
56                         been cleaned up. */
57   int fd;       /* Connected with stdout of the ldap wrapper.  */
58   gpg_error_t fd_error; /* Set to the gpg_error of the last read error
59                            if any.  */
60   int log_fd;   /* Connected with stderr of the ldap wrapper.  */
61   pth_event_t log_ev;
62   ctrl_t ctrl;  /* Connection data. */
63   int ready;    /* Internally used to mark to be removed contexts. */
64   ksba_reader_t reader; /* The ksba reader object or NULL. */
65   char *line;     /* Used to print the log lines (malloced). */
66   size_t linesize;/* Allocated size of LINE.  */
67   size_t linelen; /* Use size of LINE.  */
68   time_t stamp;   /* The last time we noticed ativity.  */
69 };
70
71
72
73 /* We keep a global list of spawed wrapper process.  A separate thread
74    makes use of this list to log error messages and to watch out for
75    finished processes. */
76 static struct wrapper_context_s *wrapper_list;
77
78 /* We need to know whether we are shutting down the process.  */
79 static int shutting_down;
80
81
82
83 /* Start the reaper thread for this wrapper.  */
84 void
85 ldap_wrapper_launch_thread (void)
86 {
87   static int done;
88   pth_attr_t tattr;
89
90   if (done)
91     return;
92   done = 1;
93
94   tattr = pth_attr_new();
95   pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
96   pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
97   pth_attr_set (tattr, PTH_ATTR_NAME, "ldap-reaper");
98
99   if (!pth_spawn (tattr, ldap_wrapper_thread, NULL))
100     {
101       log_error (_("error spawning ldap wrapper reaper thread: %s\n"),
102                  strerror (errno) );
103       dirmngr_exit (1);
104     }
105   pth_attr_destroy (tattr);
106 }
107
108
109
110
111
112 /* Wait until all ldap wrappers have terminated.  We assume that the
113    kill has already been sent to all of them.  */
114 void
115 ldap_wrapper_wait_connections ()
116 {
117   shutting_down = 1;
118   while (wrapper_list)
119     pth_yield (NULL);
120 }
121
122
123 /* This function is to be used to release a context associated with the
124    given reader object. */
125 void
126 ldap_wrapper_release_context (ksba_reader_t reader)
127 {
128   if (!reader )
129     return;
130     
131   for (ctx=wrapper_list; ctx; ctx=ctx->next)
132     if (ctx->reader == reader)
133       {
134         if (DBG_LOOKUP)
135           log_info ("releasing ldap worker c=%p pid=%d/%d rdr=%p ctrl=%p/%d\n",
136                     ctx, 
137                     (int)ctx->pid, (int)ctx->printable_pid,
138                     ctx->reader,
139                     ctx->ctrl, ctx->ctrl? ctx->ctrl->refcount:0);
140
141         ctx->reader = NULL;
142         SAFE_PTH_CLOSE (ctx->fd);
143         if (ctx->ctrl)
144           {
145             ctx->ctrl->refcount--;
146             ctx->ctrl = NULL;
147           }
148         if (ctx->fd_error)
149           log_info (_("reading from ldap wrapper %d failed: %s\n"),
150                     ctx->printable_pid, gpg_strerror (ctx->fd_error));
151         break;
152       }
153 }
154
155 /* Cleanup all resources held by the connection associated with
156    CTRL.  This is used after a cancel to kill running wrappers.  */
157 void
158 ldap_wrapper_connection_cleanup (ctrl_t ctrl)
159 {
160   struct wrapper_context_s *ctx;
161
162   for (ctx=wrapper_list; ctx; ctx=ctx->next)
163     if (ctx->ctrl && ctx->ctrl == ctrl)
164       {
165         ctx->ctrl->refcount--;
166         ctx->ctrl = NULL;
167         if (ctx->pid != (pid_t)(-1))
168           gnupg_kill_process (ctx->pid);
169         if (ctx->fd_error)
170           log_info (_("reading from ldap wrapper %d failed: %s\n"),
171                     ctx->printable_pid, gpg_strerror (ctx->fd_error));
172       }
173 }
174
175 /* Start a new LDAP thread and returns a new libksba reader
176    object at READER.  ARGV is a NULL terminated list of arguments for
177    the wrapper.  The function returns 0 on success or an error code.  */
178 gpg_error_t
179 ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
180 {
181   gpg_error_t err;
182   pid_t pid;
183   struct wrapper_context_s *ctx;
184   int i;
185   int j;
186   const char **arg_list;
187   const char *pgmname;
188   int outpipe[2], errpipe[2];
189
190   /* It would be too simple to connect stderr just to our logging
191      stream.  The problem is that if we are running multi-threaded
192      everything gets intermixed.  Clearly we don't want this.  So the
193      only viable solutions are either to have another thread
194      responsible for logging the messages or to add an option to the
195      wrapper module to do the logging on its own.  Given that we anyway
196      need a way to rip the child process and this is best done using a
197      general ripping thread, that thread can do the logging too. */
198
199   *reader = NULL;
200
201   /* Files: We need to prepare stdin and stdout.  We get stderr from
202      the function.  */
203   if (!opt.ldap_wrapper_program || !*opt.ldap_wrapper_program)
204     pgmname = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR_LDAP);
205   else
206     pgmname = opt.ldap_wrapper_program;
207
208   /* Create command line argument array.  */
209   for (i = 0; argv[i]; i++)
210     ;
211   arg_list = xtrycalloc (i + 2, sizeof *arg_list);
212   if (!arg_list)
213     {
214       err = gpg_error_from_syserror ();
215       log_error (_("error allocating memory: %s\n"), strerror (errno));
216       return err;
217     }
218   for (i = j = 0; argv[i]; i++, j++)
219     if (!i && argv[i + 1] && !strcmp (*argv, "--pass"))
220       {
221         arg_list[j] = "--env-pass";
222         setenv ("DIRMNGR_LDAP_PASS", argv[1], 1);
223         i++;
224       }
225     else
226       arg_list[j] = (char*) argv[i];
227
228   ctx = xtrycalloc (1, sizeof *ctx);
229   if (!ctx)
230     {
231       err = gpg_error_from_syserror ();
232       log_error (_("error allocating memory: %s\n"), strerror (errno));
233       xfree (arg_list);
234       return err;
235     }
236
237   err = gnupg_create_inbound_pipe (outpipe);
238   if (!err)
239     {
240       err = gnupg_create_inbound_pipe (errpipe);
241       if (err)
242         {
243           close (outpipe[0]);
244           close (outpipe[1]);
245         }
246     }
247   if (err)
248     {
249       log_error (_("error creating pipe: %s\n"), gpg_strerror (err));
250       xfree (arg_list);
251       xfree (ctx);
252       return err;
253     }
254
255   err = gnupg_spawn_process_fd (pgmname, arg_list,
256                                 -1, outpipe[1], errpipe[1], &pid);
257   xfree (arg_list);
258   close (outpipe[1]);
259   close (errpipe[1]);
260   if (err)
261     {
262       close (outpipe[0]);
263       close (errpipe[0]);
264       xfree (ctx);
265       return err;
266     }
267
268   ctx->pid = pid;
269   ctx->printable_pid = (int) pid;
270   ctx->fd = outpipe[0];
271   ctx->log_fd = errpipe[0];
272   ctx->log_ev = pth_event (PTH_EVENT_FD | PTH_UNTIL_FD_READABLE, ctx->log_fd);
273   if (! ctx->log_ev)
274     {
275       xfree (ctx);
276       return gpg_error_from_syserror ();
277     }
278   ctx->ctrl = ctrl;
279   ctrl->refcount++;
280   ctx->stamp = time (NULL);
281
282   err = ksba_reader_new (reader);
283   if (!err)
284     err = ksba_reader_set_cb (*reader, reader_callback, ctx);
285   if (err)
286     {
287       log_error (_("error initializing reader object: %s\n"),
288                  gpg_strerror (err));
289       destroy_wrapper (ctx);
290       ksba_reader_release (*reader);
291       *reader = NULL;
292       return err;
293     }
294
295   /* Hook the context into our list of running wrappers.  */
296   ctx->reader = *reader;
297   ctx->next = wrapper_list;
298   wrapper_list = ctx;
299   if (opt.verbose)
300     log_info ("ldap wrapper %d started (reader %p)\n",
301               (int)ctx->pid, ctx->reader);
302
303   /* Need to wait for the first byte so we are able to detect an empty
304      output and not let the consumer see an EOF without further error
305      indications.  The CRL loading logic assumes that after return
306      from this function, a failed search (e.g. host not found ) is
307      indicated right away. */
308   {
309     unsigned char c;
310
311     err = read_buffer (*reader, &c, 1);
312     if (err)
313       {
314         ldap_wrapper_release_context (*reader);
315         ksba_reader_release (*reader);
316         *reader = NULL;
317         if (gpg_err_code (err) == GPG_ERR_EOF)
318           return gpg_error (GPG_ERR_NO_DATA);
319         else
320           return err;
321       }
322     ksba_reader_unread (*reader, &c, 1);
323   }
324
325   return 0;
326 }