953c34af0b2c0f27bbe9708dc725a600a72b9f57
[gnupg.git] / common / exectool.c
1 /* exectool.c - Utility functions to execute a helper tool
2  * Copyright (C) 2015 Werner Koch
3  *
4  * This file is part of GnuPG.
5  *
6  * This file is free software; you can redistribute it and/or modify
7  * it under the terms of either
8  *
9  *   - the GNU Lesser General Public License as published by the Free
10  *     Software Foundation; either version 3 of the License, or (at
11  *     your option) any later version.
12  *
13  * or
14  *
15  *   - the GNU General Public License as published by the Free
16  *     Software Foundation; either version 2 of the License, or (at
17  *     your option) any later version.
18  *
19  * or both in parallel, as here.
20  *
21  * This file is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, see <http://www.gnu.org/licenses/>.
28  */
29
30 #include <config.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdarg.h>
35 #include <errno.h>
36 #include <assert.h>
37 #include <gpg-error.h>
38
39 #include <assuan.h>
40 #include "i18n.h"
41 #include "logging.h"
42 #include "membuf.h"
43 #include "mischelp.h"
44 #include "exechelp.h"
45 #include "sysutils.h"
46 #include "util.h"
47
48 typedef struct
49 {
50   const char *pgmname;
51   int cont;
52   int used;
53   char buffer[256];
54 } read_and_log_buffer_t;
55
56
57 static inline gpg_error_t
58 my_error_from_syserror (void)
59 {
60   return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
61 }
62
63
64 static void
65 read_and_log_stderr (read_and_log_buffer_t *state, es_poll_t *fderr)
66 {
67   gpg_error_t err;
68   int c;
69
70   if (!fderr)
71     {
72       /* Flush internal buffer.  */
73       if (state->used)
74         {
75           const char *pname;
76           int len;
77
78           state->buffer[state->used] = 0;
79           state->used = 0;
80
81           pname = strrchr (state->pgmname, '/');
82           if (pname && pname != state->pgmname && pname[1])
83             pname++;
84           else
85             pname = state->pgmname;
86           /* If our pgmname plus colon is identical to the start of
87              the output, print only the output.  */
88           len = strlen (pname);
89           if (!state->cont
90               && !strncmp (state->buffer, pname, len)
91               && strlen (state->buffer) > strlen (pname)
92               && state->buffer[len] == ':' )
93             log_info ("%s\n", state->buffer);
94           else
95             log_info ("%s%c %s\n",
96                       pname, state->cont? '+':':', state->buffer);
97         }
98       state->cont = 0;
99       return;
100     }
101   for (;;)
102     {
103       c = es_fgetc (fderr->stream);
104       if (c == EOF)
105         {
106           if (es_feof (fderr->stream))
107             {
108               fderr->ignore = 1; /* Not anymore needed.  */
109             }
110           else if (es_ferror (fderr->stream))
111             {
112               err = my_error_from_syserror ();
113               log_error ("error reading stderr of '%s': %s\n",
114                          state->pgmname, gpg_strerror (err));
115               fderr->ignore = 1; /* Disable.  */
116             }
117
118           break;
119         }
120       else if (c == '\n')
121         {
122           read_and_log_stderr (state, NULL);
123         }
124       else
125         {
126           if (state->used >= sizeof state->buffer - 1)
127             {
128               read_and_log_stderr (state, NULL);
129               state->cont = 1;
130             }
131           state->buffer[state->used++] = c;
132         }
133     }
134 }
135
136 \f
137
138 /* A buffer to copy from one stream to another.  */
139 struct copy_buffer
140 {
141   char buffer[4096];
142   char *writep;
143   size_t nread;
144 };
145
146
147 /* Initialize a copy buffer.  */
148 static void
149 copy_buffer_init (struct copy_buffer *c)
150 {
151   c->writep = c->buffer;
152   c->nread = 0;
153 }
154
155
156 /* Securely wipe a copy buffer.  */
157 static void
158 copy_buffer_shred (struct copy_buffer *c)
159 {
160   wipememory (c->buffer, sizeof c->buffer);
161   c->writep = NULL;
162   c->nread = ~0U;
163 }
164
165
166 /* Copy data from SOURCE to SINK using copy buffer C.  */
167 static gpg_error_t
168 copy_buffer_do_copy (struct copy_buffer *c, estream_t source, estream_t sink)
169 {
170   gpg_error_t err;
171   size_t nwritten;
172
173   if (c->nread == 0)
174     {
175       c->writep = c->buffer;
176       err = es_read (source, c->buffer, sizeof c->buffer, &c->nread);
177       if (err)
178         {
179           if (errno == EAGAIN)
180             return 0;   /* We will just retry next time.  */
181
182           return my_error_from_syserror ();
183         }
184
185       assert (c->nread <= sizeof c->buffer);
186     }
187
188   if (c->nread == 0)
189     return 0;   /* Done copying.  */
190
191
192   err = sink? es_write (sink, c->writep, c->nread, &nwritten) : 0;
193   if (err)
194     {
195       if (errno == EAGAIN)
196         return 0;       /* We will just retry next time.  */
197
198       return my_error_from_syserror ();
199     }
200
201   assert (nwritten <= c->nread);
202   c->writep += nwritten;
203   c->nread -= nwritten;
204   assert (c->writep - c->buffer <= sizeof c->buffer);
205
206   if (sink && es_fflush (sink) && errno != EAGAIN)
207     err = my_error_from_syserror ();
208
209   return err;
210 }
211
212
213 /* Flush the remaining data to SINK.  */
214 static gpg_error_t
215 copy_buffer_flush (struct copy_buffer *c, estream_t sink)
216 {
217   gpg_error_t err;
218
219   while (c->nread > 0)
220     {
221       err = copy_buffer_do_copy (c, NULL, sink);
222       if (err)
223         return err;
224     }
225
226   return 0;
227 }
228
229 \f
230
231 /* Run the program PGMNAME with the command line arguments given in
232  * the NULL terminates array ARGV.  If INPUT is not NULL it will be
233  * fed to stdin of the process.  stderr is logged using log_info and
234  * the process' stdout is written to OUTPUT.  If OUTPUT is NULL the
235  * output is discarded.  If INEXTRA is given, an additional input
236  * stream will be passed to the child; to tell the child about this
237  * ARGV is scanned and the first occurrence of an argument
238  * "-&@INEXTRA@" is replaced by the concatenation of "-&" and the
239  * child's file descriptor of the pipe created for the INEXTRA stream.
240  *
241  * On error a diagnostic is printed and an error code returned.  */
242 gpg_error_t
243 gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
244                         estream_t input, estream_t inextra,
245                         estream_t output)
246 {
247   gpg_error_t err;
248   pid_t pid;
249   estream_t infp = NULL;
250   estream_t extrafp = NULL;
251   estream_t outfp, errfp;
252   es_poll_t fds[4];
253   int exceptclose[2];
254   int extrapipe[2] = {-1, -1};
255   char extrafdbuf[20];
256   const char *argsave = NULL;
257   int argsaveidx;
258   int count;
259   read_and_log_buffer_t fderrstate;
260   struct copy_buffer cpbuf_in, cpbuf_out, cpbuf_extra; /* Fixme: malloc them. */
261
262   memset (fds, 0, sizeof fds);
263   memset (&fderrstate, 0, sizeof fderrstate);
264   copy_buffer_init (&cpbuf_in);
265   copy_buffer_init (&cpbuf_out);
266   copy_buffer_init (&cpbuf_extra);
267
268   if (inextra)
269     {
270       err = gnupg_create_outbound_pipe (extrapipe, &extrafp, 1);
271       if (err)
272         {
273           log_error ("error running outbound pipe for extra fp: %s\n",
274                      gpg_strerror (err));
275           return err;
276         }
277       exceptclose[0] = extrapipe[0]; /* Do not close in child. */
278       exceptclose[1] = -1;
279       /* Now find the argument marker and replace by the pipe's fd.
280          Yeah, that is an ugly non-thread safe hack but it safes us to
281          create a copy of the array.  */
282       snprintf (extrafdbuf, sizeof extrafdbuf, "-&%d", extrapipe[0]);
283       for (argsaveidx=0; argv[argsaveidx]; argsaveidx++)
284         if (!strcmp (argv[argsaveidx], "-&@INEXTRA@"))
285           {
286             argsave = argv[argsaveidx];
287             argv[argsaveidx] = extrafdbuf;
288             break;
289           }
290     }
291   else
292     exceptclose[0] = -1;
293
294   err = gnupg_spawn_process (pgmname, argv,
295                              exceptclose, NULL, GNUPG_SPAWN_NONBLOCK,
296                              input? &infp : NULL,
297                              &outfp, &errfp, &pid);
298   if (extrapipe[0] != -1)
299     close (extrapipe[0]);
300   if (argsave)
301     argv[argsaveidx] = argsave;
302   if (err)
303     {
304       log_error ("error running '%s': %s\n", pgmname, gpg_strerror (err));
305       es_fclose (extrafp);
306       return err;
307     }
308
309   fderrstate.pgmname = pgmname;
310
311   fds[0].stream = infp;
312   fds[0].want_write = 1;
313   if (!input)
314     fds[0].ignore = 1;
315   fds[1].stream = outfp;
316   fds[1].want_read = 1;
317   fds[2].stream = errfp;
318   fds[2].want_read = 1;
319   fds[3].stream = extrafp;
320   fds[3].want_write = 1;
321   if (!inextra)
322     fds[3].ignore = 1;
323
324   /* Now read as long as we have something to poll.  We continue
325      reading even after EOF or error on stdout so that we get the
326      other error messages or remaining outut.  */
327   while (!fds[1].ignore && !fds[2].ignore)
328     {
329       count = es_poll (fds, DIM(fds), -1);
330       if (count == -1)
331         {
332           err = my_error_from_syserror ();
333           log_error ("error polling '%s': %s\n", pgmname, gpg_strerror (err));
334           goto leave;
335         }
336       if (!count)
337         {
338           log_debug ("unexpected timeout while polling '%s'\n", pgmname);
339           break;
340         }
341
342       if (fds[0].got_write)
343         {
344           err = copy_buffer_do_copy (&cpbuf_in, input, fds[0].stream);
345           if (err)
346             {
347               log_error ("error feeding data to '%s': %s\n",
348                          pgmname, gpg_strerror (err));
349               goto leave;
350             }
351
352           if (es_feof (input))
353             {
354               err = copy_buffer_flush (&cpbuf_in, fds[0].stream);
355               if (err)
356                 {
357                   log_error ("error feeding data to '%s': %s\n",
358                              pgmname, gpg_strerror (err));
359                   goto leave;
360                 }
361
362               fds[0].ignore = 1; /* ready.  */
363               es_fclose (infp); infp = NULL;
364             }
365         }
366
367       if (fds[3].got_write)
368         {
369           log_assert (inextra);
370           err = copy_buffer_do_copy (&cpbuf_extra, inextra, fds[3].stream);
371           if (err)
372             {
373               log_error ("error feeding data to '%s': %s\n",
374                          pgmname, gpg_strerror (err));
375               goto leave;
376             }
377
378           if (es_feof (inextra))
379             {
380               err = copy_buffer_flush (&cpbuf_extra, fds[3].stream);
381               if (err)
382                 {
383                   log_error ("error feeding data to '%s': %s\n",
384                              pgmname, gpg_strerror (err));
385                   goto leave;
386                 }
387
388               fds[3].ignore = 1; /* ready.  */
389               es_fclose (extrafp); extrafp = NULL;
390             }
391         }
392
393       if (fds[1].got_read)
394         {
395           err = copy_buffer_do_copy (&cpbuf_out, fds[1].stream, output);
396           if (err)
397             {
398               log_error ("error reading data from '%s': %s\n",
399                          pgmname, gpg_strerror (err));
400               goto leave;
401             }
402         }
403
404       if (fds[2].got_read)
405         read_and_log_stderr (&fderrstate, fds + 2);
406     }
407
408   err = copy_buffer_flush (&cpbuf_out, output);
409   if (err)
410     {
411       log_error ("error reading data from '%s': %s\n",
412                  pgmname, gpg_strerror (err));
413       goto leave;
414     }
415
416   read_and_log_stderr (&fderrstate, NULL); /* Flush.  */
417   es_fclose (infp); infp = NULL;
418   es_fclose (extrafp); extrafp = NULL;
419   es_fclose (outfp); outfp = NULL;
420   es_fclose (errfp); errfp = NULL;
421
422   err = gnupg_wait_process (pgmname, pid, 1, NULL);
423   pid = (pid_t)(-1);
424
425  leave:
426   if (err)
427     gnupg_kill_process (pid);
428
429   es_fclose (infp);
430   es_fclose (extrafp);
431   es_fclose (outfp);
432   es_fclose (errfp);
433   if (pid != (pid_t)(-1))
434     gnupg_wait_process (pgmname, pid, 1, NULL);
435   gnupg_release_process (pid);
436
437   copy_buffer_shred (&cpbuf_in);
438   copy_buffer_shred (&cpbuf_out);
439   if (inextra)
440     copy_buffer_shred (&cpbuf_extra);
441   return err;
442 }
443
444
445 /* A dummy free function to pass to 'es_mopen'.  */
446 static void
447 nop_free (void *ptr)
448 {
449   (void) ptr;
450 }
451
452 /* Run the program PGMNAME with the command line arguments given in
453    the NULL terminates array ARGV.  If INPUT_STRING is not NULL it
454    will be fed to stdin of the process.  stderr is logged using
455    log_info and the process' stdout is returned in a newly malloced
456    buffer RESULT with the length stored at RESULTLEN if not given as
457    NULL.  A hidden Nul is appended to the output.  On error NULL is
458    stored at RESULT, a diagnostic is printed, and an error code
459    returned.  */
460 gpg_error_t
461 gnupg_exec_tool (const char *pgmname, const char *argv[],
462                  const char *input_string,
463                  char **result, size_t *resultlen)
464 {
465   gpg_error_t err;
466   estream_t input = NULL;
467   estream_t output;
468   size_t len;
469   size_t nread;
470
471   *result = NULL;
472   if (resultlen)
473     *resultlen = 0;
474
475   if (input_string)
476     {
477       len = strlen (input_string);
478       input = es_mopen ((char *) input_string, len, len,
479                         0 /* don't grow */, NULL, nop_free, "rb");
480       if (! input)
481         return my_error_from_syserror ();
482     }
483
484   output = es_fopenmem (0, "wb");
485   if (! output)
486     {
487       err = my_error_from_syserror ();
488       goto leave;
489     }
490
491   err = gnupg_exec_tool_stream (pgmname, argv, input, NULL, output);
492   if (err)
493     goto leave;
494
495   len = es_ftello (output);
496   err = es_fseek (output, 0, SEEK_SET);
497   if (err)
498     goto leave;
499
500   *result = xtrymalloc (len + 1);
501   if (!*result)
502     {
503       err = my_error_from_syserror ();
504       goto leave;
505     }
506
507   if (len)
508     {
509       err = es_read (output, *result, len, &nread);
510       if (err)
511         goto leave;
512       if (nread != len)
513         log_fatal ("%s: short read from memstream\n", __func__);
514     }
515   (*result)[len] = 0;
516
517   if (resultlen)
518     *resultlen = len;
519
520  leave:
521   es_fclose (input);
522   es_fclose (output);
523   if (err)
524     {
525       xfree (*result);
526       *result = NULL;
527     }
528   return err;
529 }