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
45
46 /* To keep track of the LDAP wrapper state we use this structure.  */
47 struct wrapper_context_s
48 {
49   struct wrapper_context_s *next;
50
51   pid_t pid;    /* The pid of the wrapper process. */
52   int printable_pid; /* Helper to print diagnostics after the process has
53                         been cleaned up. */
54   int fd;       /* Connected with stdout of the ldap wrapper.  */
55   gpg_error_t fd_error; /* Set to the gpg_error of the last read error
56                            if any.  */
57   int log_fd;   /* Connected with stderr of the ldap wrapper.  */
58   pth_event_t log_ev;
59   ctrl_t ctrl;  /* Connection data. */
60   int ready;    /* Internally used to mark to be removed contexts. */
61   ksba_reader_t reader; /* The ksba reader object or NULL. */
62   char *line;     /* Used to print the log lines (malloced). */
63   size_t linesize;/* Allocated size of LINE.  */
64   size_t linelen; /* Use size of LINE.  */
65   time_t stamp;   /* The last time we noticed ativity.  */
66 };
67
68
69
70 /* We keep a global list of spawed wrapper process.  A separate thread
71    makes use of this list to log error messages and to watch out for
72    finished processes. */
73 static struct wrapper_context_s *wrapper_list;
74
75 /* We need to know whether we are shutting down the process.  */
76 static int shutting_down;
77
78
79
80 /* Start the reaper thread for this wrapper.  */
81 void
82 ldap_wrapper_launch_thread (void)
83 {
84   static int done;
85   pth_attr_t tattr;
86
87   if (done)
88     return;
89   done = 1;
90
91   tattr = pth_attr_new();
92   pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
93   pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
94   pth_attr_set (tattr, PTH_ATTR_NAME, "ldap-reaper");
95
96   if (!pth_spawn (tattr, ldap_wrapper_thread, NULL))
97     {
98       log_error (_("error spawning ldap wrapper reaper thread: %s\n"),
99                  strerror (errno) );
100       dirmngr_exit (1);
101     }
102   pth_attr_destroy (tattr);
103 }
104
105
106
107
108
109 /* Wait until all ldap wrappers have terminated.  We assume that the
110    kill has already been sent to all of them.  */
111 void
112 ldap_wrapper_wait_connections ()
113 {
114   shutting_down = 1;
115   while (wrapper_list)
116     pth_yield (NULL);
117 }
118
119
120 /* This function is to be used to release a context associated with the
121    given reader object. */
122 void
123 ldap_wrapper_release_context (ksba_reader_t reader)
124 {
125   if (!reader )
126     return;
127     
128   for (ctx=wrapper_list; ctx; ctx=ctx->next)
129     if (ctx->reader == reader)
130       {
131         if (DBG_LOOKUP)
132           log_info ("releasing ldap worker c=%p pid=%d/%d rdr=%p ctrl=%p/%d\n",
133                     ctx, 
134                     (int)ctx->pid, (int)ctx->printable_pid,
135                     ctx->reader,
136                     ctx->ctrl, ctx->ctrl? ctx->ctrl->refcount:0);
137
138         ctx->reader = NULL;
139         SAFE_PTH_CLOSE (ctx->fd);
140         if (ctx->ctrl)
141           {
142             ctx->ctrl->refcount--;
143             ctx->ctrl = NULL;
144           }
145         if (ctx->fd_error)
146           log_info (_("reading from ldap wrapper %d failed: %s\n"),
147                     ctx->printable_pid, gpg_strerror (ctx->fd_error));
148         break;
149       }
150 }
151
152 /* Cleanup all resources held by the connection associated with
153    CTRL.  This is used after a cancel to kill running wrappers.  */
154 void
155 ldap_wrapper_connection_cleanup (ctrl_t ctrl)
156 {
157   struct wrapper_context_s *ctx;
158
159   for (ctx=wrapper_list; ctx; ctx=ctx->next)
160     if (ctx->ctrl && ctx->ctrl == ctrl)
161       {
162         ctx->ctrl->refcount--;
163         ctx->ctrl = NULL;
164         if (ctx->pid != (pid_t)(-1))
165           gnupg_kill_process (ctx->pid);
166         if (ctx->fd_error)
167           log_info (_("reading from ldap wrapper %d failed: %s\n"),
168                     ctx->printable_pid, gpg_strerror (ctx->fd_error));
169       }
170 }
171
172 /* Fork and exec the LDAP wrapper and returns a new libksba reader
173    object at READER.  ARGV is a NULL terminated list of arguments for
174    the wrapper.  The function returns 0 on success or an error code.
175
176    Special hack to avoid passing a password through the command line
177    which is globally visible: If the first element of ARGV is "--pass"
178    it will be removed and instead the environment variable
179    DIRMNGR_LDAP_PASS will be set to the next value of ARGV.  On modern
180    OSes the environment is not visible to other users.  For those old
181    systems where it can't be avoided, we don't want to go into the
182    hassle of passing the password via stdin; it's just too complicated
183    and an LDAP password used for public directory lookups should not
184    be that confidential.  */
185 gpg_error_t
186 ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
187 {
188   gpg_error_t err;
189   pid_t pid;
190   struct wrapper_context_s *ctx;
191   int i;
192   int j;
193   const char **arg_list;
194   const char *pgmname;
195   int outpipe[2], errpipe[2];
196
197   /* It would be too simple to connect stderr just to our logging
198      stream.  The problem is that if we are running multi-threaded
199      everything gets intermixed.  Clearly we don't want this.  So the
200      only viable solutions are either to have another thread
201      responsible for logging the messages or to add an option to the
202      wrapper module to do the logging on its own.  Given that we anyway
203      need a way to rip the child process and this is best done using a
204      general ripping thread, that thread can do the logging too. */
205
206   *reader = NULL;
207
208   /* Files: We need to prepare stdin and stdout.  We get stderr from
209      the function.  */
210   if (!opt.ldap_wrapper_program || !*opt.ldap_wrapper_program)
211     pgmname = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR_LDAP);
212   else
213     pgmname = opt.ldap_wrapper_program;
214
215   /* Create command line argument array.  */
216   for (i = 0; argv[i]; i++)
217     ;
218   arg_list = xtrycalloc (i + 2, sizeof *arg_list);
219   if (!arg_list)
220     {
221       err = gpg_error_from_syserror ();
222       log_error (_("error allocating memory: %s\n"), strerror (errno));
223       return err;
224     }
225   for (i = j = 0; argv[i]; i++, j++)
226     if (!i && argv[i + 1] && !strcmp (*argv, "--pass"))
227       {
228         arg_list[j] = "--env-pass";
229         setenv ("DIRMNGR_LDAP_PASS", argv[1], 1);
230         i++;
231       }
232     else
233       arg_list[j] = (char*) argv[i];
234
235   ctx = xtrycalloc (1, sizeof *ctx);
236   if (!ctx)
237     {
238       err = gpg_error_from_syserror ();
239       log_error (_("error allocating memory: %s\n"), strerror (errno));
240       xfree (arg_list);
241       return err;
242     }
243
244   err = gnupg_create_inbound_pipe (outpipe);
245   if (!err)
246     {
247       err = gnupg_create_inbound_pipe (errpipe);
248       if (err)
249         {
250           close (outpipe[0]);
251           close (outpipe[1]);
252         }
253     }
254   if (err)
255     {
256       log_error (_("error creating pipe: %s\n"), gpg_strerror (err));
257       xfree (arg_list);
258       xfree (ctx);
259       return err;
260     }
261
262   err = gnupg_spawn_process_fd (pgmname, arg_list,
263                                 -1, outpipe[1], errpipe[1], &pid);
264   xfree (arg_list);
265   close (outpipe[1]);
266   close (errpipe[1]);
267   if (err)
268     {
269       close (outpipe[0]);
270       close (errpipe[0]);
271       xfree (ctx);
272       return err;
273     }
274
275   ctx->pid = pid;
276   ctx->printable_pid = (int) pid;
277   ctx->fd = outpipe[0];
278   ctx->log_fd = errpipe[0];
279   ctx->log_ev = pth_event (PTH_EVENT_FD | PTH_UNTIL_FD_READABLE, ctx->log_fd);
280   if (! ctx->log_ev)
281     {
282       xfree (ctx);
283       return gpg_error_from_syserror ();
284     }
285   ctx->ctrl = ctrl;
286   ctrl->refcount++;
287   ctx->stamp = time (NULL);
288
289   err = ksba_reader_new (reader);
290   if (!err)
291     err = ksba_reader_set_cb (*reader, reader_callback, ctx);
292   if (err)
293     {
294       log_error (_("error initializing reader object: %s\n"),
295                  gpg_strerror (err));
296       destroy_wrapper (ctx);
297       ksba_reader_release (*reader);
298       *reader = NULL;
299       return err;
300     }
301
302   /* Hook the context into our list of running wrappers.  */
303   ctx->reader = *reader;
304   ctx->next = wrapper_list;
305   wrapper_list = ctx;
306   if (opt.verbose)
307     log_info ("ldap wrapper %d started (reader %p)\n",
308               (int)ctx->pid, ctx->reader);
309
310   /* Need to wait for the first byte so we are able to detect an empty
311      output and not let the consumer see an EOF without further error
312      indications.  The CRL loading logic assumes that after return
313      from this function, a failed search (e.g. host not found ) is
314      indicated right away. */
315   {
316     unsigned char c;
317
318     err = read_buffer (*reader, &c, 1);
319     if (err)
320       {
321         ldap_wrapper_release_context (*reader);
322         ksba_reader_release (*reader);
323         *reader = NULL;
324         if (gpg_err_code (err) == GPG_ERR_EOF)
325           return gpg_error (GPG_ERR_NO_DATA);
326         else
327           return err;
328       }
329     ksba_reader_unread (*reader, &c, 1);
330   }
331
332   return 0;
333 }