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