Imported Upstream version 2.1.19
[platform/upstream/gpg2.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 <https://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       if (es_read (source, c->buffer, sizeof c->buffer, &c->nread))
236         {
237           err = my_error_from_syserror ();
238           if (gpg_err_code (err) == GPG_ERR_EAGAIN)
239             return 0;   /* We will just retry next time.  */
240
241           return err;
242         }
243
244       log_assert (c->nread <= sizeof c->buffer);
245     }
246
247   if (c->nread == 0)
248     return 0;   /* Done copying.  */
249
250   nwritten = 0;
251   if (sink && es_write (sink, c->writep, c->nread, &nwritten))
252     err = my_error_from_syserror ();
253   else
254     err = 0;
255
256   log_assert (nwritten <= c->nread);
257   c->writep += nwritten;
258   c->nread -= nwritten;
259   log_assert (c->writep - c->buffer <= sizeof c->buffer);
260
261   if (err)
262     {
263       if (gpg_err_code (err) == GPG_ERR_EAGAIN)
264         return 0;       /* We will just retry next time.  */
265
266       return err;
267     }
268
269   if (sink && es_fflush (sink) && errno != EAGAIN)
270     err = my_error_from_syserror ();
271
272   return err;
273 }
274
275
276 /* Flush the remaining data to SINK.  */
277 static gpg_error_t
278 copy_buffer_flush (struct copy_buffer *c, estream_t sink)
279 {
280   gpg_error_t err = 0;
281   size_t nwritten = 0;
282
283   if (es_write (sink, c->writep, c->nread, &nwritten))
284     err = my_error_from_syserror ();
285
286   log_assert (nwritten <= c->nread);
287   c->writep += nwritten;
288   c->nread -= nwritten;
289   log_assert (c->writep - c->buffer <= sizeof c->buffer);
290
291   if (err)
292     return err;
293
294   if (es_fflush (sink))
295     err = my_error_from_syserror ();
296
297   return err;
298 }
299
300 \f
301
302 /* Run the program PGMNAME with the command line arguments given in
303  * the NULL terminates array ARGV.  If INPUT is not NULL it will be
304  * fed to stdin of the process.  stderr is logged using log_info and
305  * the process' stdout is written to OUTPUT.  If OUTPUT is NULL the
306  * output is discarded.  If INEXTRA is given, an additional input
307  * stream will be passed to the child; to tell the child about this
308  * ARGV is scanned and the first occurrence of an argument
309  * "-&@INEXTRA@" is replaced by the concatenation of "-&" and the
310  * child's file descriptor of the pipe created for the INEXTRA stream.
311  *
312  * On error a diagnostic is printed and an error code returned.  */
313 gpg_error_t
314 gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
315                         estream_t input, estream_t inextra,
316                         estream_t output,
317                         exec_tool_status_cb_t status_cb,
318                         void *status_cb_value)
319 {
320   gpg_error_t err;
321   pid_t pid = (pid_t) -1;
322   estream_t infp = NULL;
323   estream_t extrafp = NULL;
324   estream_t outfp = NULL, errfp = NULL;
325   es_poll_t fds[4];
326   int exceptclose[2];
327   int extrapipe[2] = {-1, -1};
328   char extrafdbuf[20];
329   const char *argsave = NULL;
330   int argsaveidx;
331   int count;
332   read_and_log_buffer_t fderrstate;
333   struct copy_buffer *cpbuf_in = NULL, *cpbuf_out = NULL, *cpbuf_extra = NULL;
334
335   memset (fds, 0, sizeof fds);
336   memset (&fderrstate, 0, sizeof fderrstate);
337
338   cpbuf_in = xtrymalloc (sizeof *cpbuf_in);
339   if (cpbuf_in == NULL)
340     {
341       err = my_error_from_syserror ();
342       goto leave;
343     }
344   copy_buffer_init (cpbuf_in);
345
346   cpbuf_out = xtrymalloc (sizeof *cpbuf_out);
347   if (cpbuf_out == NULL)
348     {
349       err = my_error_from_syserror ();
350       goto leave;
351     }
352   copy_buffer_init (cpbuf_out);
353
354   cpbuf_extra = xtrymalloc (sizeof *cpbuf_extra);
355   if (cpbuf_extra == NULL)
356     {
357       err = my_error_from_syserror ();
358       goto leave;
359     }
360   copy_buffer_init (cpbuf_extra);
361
362   fderrstate.pgmname = pgmname;
363   fderrstate.status_cb = status_cb;
364   fderrstate.status_cb_value = status_cb_value;
365   fderrstate.buffer_size = 256;
366   fderrstate.buffer = xtrymalloc (fderrstate.buffer_size);
367   if (!fderrstate.buffer)
368     {
369       err = my_error_from_syserror ();
370       goto leave;
371     }
372
373   if (inextra)
374     {
375       err = gnupg_create_outbound_pipe (extrapipe, &extrafp, 1);
376       if (err)
377         {
378           log_error ("error running outbound pipe for extra fp: %s\n",
379                      gpg_strerror (err));
380           goto leave;
381         }
382       exceptclose[0] = extrapipe[0]; /* Do not close in child. */
383       exceptclose[1] = -1;
384       /* Now find the argument marker and replace by the pipe's fd.
385          Yeah, that is an ugly non-thread safe hack but it safes us to
386          create a copy of the array.  */
387 #ifdef HAVE_W32_SYSTEM
388       snprintf (extrafdbuf, sizeof extrafdbuf, "-&%lu",
389                 (unsigned long)(void*)_get_osfhandle (extrapipe[0]));
390 #else
391       snprintf (extrafdbuf, sizeof extrafdbuf, "-&%d", extrapipe[0]);
392 #endif
393       for (argsaveidx=0; argv[argsaveidx]; argsaveidx++)
394         if (!strcmp (argv[argsaveidx], "-&@INEXTRA@"))
395           {
396             argsave = argv[argsaveidx];
397             argv[argsaveidx] = extrafdbuf;
398             break;
399           }
400     }
401   else
402     exceptclose[0] = -1;
403
404   err = gnupg_spawn_process (pgmname, argv,
405                              exceptclose, NULL, GNUPG_SPAWN_NONBLOCK,
406                              input? &infp : NULL,
407                              &outfp, &errfp, &pid);
408   if (extrapipe[0] != -1)
409     close (extrapipe[0]);
410   if (argsave)
411     argv[argsaveidx] = argsave;
412   if (err)
413     {
414       log_error ("error running '%s': %s\n", pgmname, gpg_strerror (err));
415       goto leave;
416     }
417
418   fds[0].stream = infp;
419   fds[0].want_write = 1;
420   if (!input)
421     fds[0].ignore = 1;
422   fds[1].stream = outfp;
423   fds[1].want_read = 1;
424   fds[2].stream = errfp;
425   fds[2].want_read = 1;
426   fds[3].stream = extrafp;
427   fds[3].want_write = 1;
428   if (!inextra)
429     fds[3].ignore = 1;
430
431   /* Now read as long as we have something to poll.  We continue
432      reading even after EOF or error on stdout so that we get the
433      other error messages or remaining outut.  */
434   while (! (fds[1].ignore && fds[2].ignore))
435     {
436       count = es_poll (fds, DIM(fds), -1);
437       if (count == -1)
438         {
439           err = my_error_from_syserror ();
440           log_error ("error polling '%s': %s\n", pgmname, gpg_strerror (err));
441           goto leave;
442         }
443       if (!count)
444         {
445           log_debug ("unexpected timeout while polling '%s'\n", pgmname);
446           break;
447         }
448
449       if (fds[0].got_write)
450         {
451           err = copy_buffer_do_copy (cpbuf_in, input, fds[0].stream);
452           if (err)
453             {
454               log_error ("error feeding data to '%s': %s\n",
455                          pgmname, gpg_strerror (err));
456               goto leave;
457             }
458
459           if (es_feof (input))
460             {
461               err = copy_buffer_flush (cpbuf_in, fds[0].stream);
462               if (gpg_err_code (err) == GPG_ERR_EAGAIN)
463                 continue;       /* Retry next time.  */
464               if (err)
465                 {
466                   log_error ("error feeding data to '%s': %s\n",
467                              pgmname, gpg_strerror (err));
468                   goto leave;
469                 }
470
471               fds[0].ignore = 1; /* ready.  */
472               es_fclose (infp); infp = NULL;
473             }
474         }
475
476       if (fds[3].got_write)
477         {
478           log_assert (inextra);
479           err = copy_buffer_do_copy (cpbuf_extra, inextra, fds[3].stream);
480           if (err)
481             {
482               log_error ("error feeding data to '%s': %s\n",
483                          pgmname, gpg_strerror (err));
484               goto leave;
485             }
486
487           if (es_feof (inextra))
488             {
489               err = copy_buffer_flush (cpbuf_extra, fds[3].stream);
490               if (gpg_err_code (err) == GPG_ERR_EAGAIN)
491                 continue;       /* Retry next time.  */
492               if (err)
493                 {
494                   log_error ("error feeding data to '%s': %s\n",
495                              pgmname, gpg_strerror (err));
496                   goto leave;
497                 }
498
499               fds[3].ignore = 1; /* ready.  */
500               es_fclose (extrafp); extrafp = NULL;
501             }
502         }
503
504       if (fds[1].got_read)
505         {
506           err = copy_buffer_do_copy (cpbuf_out, fds[1].stream, output);
507           if (err)
508             {
509               log_error ("error reading data from '%s': %s\n",
510                          pgmname, gpg_strerror (err));
511               goto leave;
512             }
513
514           if (es_feof (fds[1].stream))
515             {
516               err = copy_buffer_flush (cpbuf_out, output);
517               if (err)
518                 {
519                   log_error ("error reading data from '%s': %s\n",
520                              pgmname, gpg_strerror (err));
521                   goto leave;
522                 }
523
524               fds[1].ignore = 1; /* ready.  */
525             }
526         }
527
528       if (fds[2].got_read)
529         read_and_log_stderr (&fderrstate, fds + 2);
530     }
531
532   read_and_log_stderr (&fderrstate, NULL); /* Flush.  */
533   es_fclose (infp); infp = NULL;
534   es_fclose (extrafp); extrafp = NULL;
535   es_fclose (outfp); outfp = NULL;
536   es_fclose (errfp); errfp = NULL;
537
538   err = gnupg_wait_process (pgmname, pid, 1, NULL);
539   pid = (pid_t)(-1);
540
541  leave:
542   if (err && pid != (pid_t) -1)
543     gnupg_kill_process (pid);
544
545   es_fclose (infp);
546   es_fclose (extrafp);
547   es_fclose (outfp);
548   es_fclose (errfp);
549   if (pid != (pid_t)(-1))
550     gnupg_wait_process (pgmname, pid, 1, NULL);
551   gnupg_release_process (pid);
552
553   copy_buffer_shred (cpbuf_in);
554   xfree (cpbuf_in);
555   copy_buffer_shred (cpbuf_out);
556   xfree (cpbuf_out);
557   copy_buffer_shred (cpbuf_extra);
558   xfree (cpbuf_extra);
559   xfree (fderrstate.buffer);
560   return err;
561 }
562
563
564 /* A dummy free function to pass to 'es_mopen'.  */
565 static void
566 nop_free (void *ptr)
567 {
568   (void) ptr;
569 }
570
571 /* Run the program PGMNAME with the command line arguments given in
572    the NULL terminates array ARGV.  If INPUT_STRING is not NULL it
573    will be fed to stdin of the process.  stderr is logged using
574    log_info and the process' stdout is returned in a newly malloced
575    buffer RESULT with the length stored at RESULTLEN if not given as
576    NULL.  A hidden Nul is appended to the output.  On error NULL is
577    stored at RESULT, a diagnostic is printed, and an error code
578    returned.  */
579 gpg_error_t
580 gnupg_exec_tool (const char *pgmname, const char *argv[],
581                  const char *input_string,
582                  char **result, size_t *resultlen)
583 {
584   gpg_error_t err;
585   estream_t input = NULL;
586   estream_t output;
587   size_t len;
588   size_t nread;
589
590   *result = NULL;
591   if (resultlen)
592     *resultlen = 0;
593
594   if (input_string)
595     {
596       len = strlen (input_string);
597       input = es_mopen ((char *) input_string, len, len,
598                         0 /* don't grow */, NULL, nop_free, "rb");
599       if (! input)
600         return my_error_from_syserror ();
601     }
602
603   output = es_fopenmem (0, "wb");
604   if (! output)
605     {
606       err = my_error_from_syserror ();
607       goto leave;
608     }
609
610   err = gnupg_exec_tool_stream (pgmname, argv, input, NULL, output, NULL, NULL);
611   if (err)
612     goto leave;
613
614   len = es_ftello (output);
615   err = es_fseek (output, 0, SEEK_SET);
616   if (err)
617     goto leave;
618
619   *result = xtrymalloc (len + 1);
620   if (!*result)
621     {
622       err = my_error_from_syserror ();
623       goto leave;
624     }
625
626   if (len)
627     {
628       if (es_read (output, *result, len, &nread))
629         {
630           err = my_error_from_syserror ();
631           goto leave;
632         }
633       if (nread != len)
634         log_fatal ("%s: short read from memstream\n", __func__);
635     }
636   (*result)[len] = 0;
637
638   if (resultlen)
639     *resultlen = len;
640
641  leave:
642   es_fclose (input);
643   es_fclose (output);
644   if (err)
645     {
646       xfree (*result);
647       *result = NULL;
648     }
649   return err;
650 }