1 /* exectool.c - Utility functions to execute a helper tool
2 * Copyright (C) 2015 Werner Koch
3 * Copyright (C) 2016 g10 Code GmbH
5 * This file is part of GnuPG.
7 * This file is free software; you can redistribute it and/or modify
8 * it under the terms of either
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.
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.
20 * or both in parallel, as here.
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.
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/>.
38 #include <gpg-error.h>
53 exec_tool_status_cb_t status_cb;
54 void *status_cb_value;
60 } read_and_log_buffer_t;
63 static inline gpg_error_t
64 my_error_from_syserror (void)
66 return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
71 read_and_log_stderr (read_and_log_buffer_t *state, es_poll_t *fderr)
78 /* Flush internal buffer. */
84 state->buffer[state->used] = 0;
87 pname = strrchr (state->pgmname, '/');
88 if (pname && pname != state->pgmname && pname[1])
91 pname = state->pgmname;
95 && !strncmp (state->buffer, "[GNUPG:] ", 9)
96 && state->buffer[9] >= 'A' && state->buffer[9] <= 'Z')
100 rest = strchr (state->buffer + 9, ' ');
103 /* Set REST to an empty string. */
104 rest = state->buffer + strlen (state->buffer);
111 state->status_cb (state->status_cb_value,
112 state->buffer + 9, rest);
114 else if (state->quiet)
116 else if (!state->cont
117 && !strncmp (state->buffer, pname, len)
118 && strlen (state->buffer) > strlen (pname)
119 && state->buffer[len] == ':' )
121 /* PGMNAME plus colon is identical to the start of
122 the output: print only the output. */
123 log_info ("%s\n", state->buffer);
126 log_info ("%s%c %s\n",
127 pname, state->cont? '+':':', state->buffer);
134 c = es_fgetc (fderr->stream);
137 if (es_feof (fderr->stream))
139 fderr->ignore = 1; /* Not anymore needed. */
141 else if (es_ferror (fderr->stream))
143 err = my_error_from_syserror ();
144 log_error ("error reading stderr of '%s': %s\n",
145 state->pgmname, gpg_strerror (err));
146 fderr->ignore = 1; /* Disable. */
153 read_and_log_stderr (state, NULL);
157 if (state->used >= state->buffer_size - 1)
159 if (state->status_cb)
161 /* A status callback requires that we have a full
162 * line. Thus we need to enlarget the buffer in
165 size_t newsize = state->buffer_size + 256;
167 newbuffer = xtrymalloc (newsize);
170 log_error ("error allocating memory for status cb: %s\n",
171 gpg_strerror (my_error_from_syserror ()));
172 /* We better disable the status CB in this case. */
173 state->status_cb = NULL;
174 read_and_log_stderr (state, NULL);
179 memcpy (newbuffer, state->buffer, state->used);
180 xfree (state->buffer);
181 state->buffer = newbuffer;
182 state->buffer_size = newsize;
187 read_and_log_stderr (state, NULL);
191 state->buffer[state->used++] = c;
198 /* A buffer to copy from one stream to another. */
207 /* Initialize a copy buffer. */
209 copy_buffer_init (struct copy_buffer *c)
211 c->writep = c->buffer;
216 /* Securely wipe a copy buffer. */
218 copy_buffer_shred (struct copy_buffer *c)
222 wipememory (c->buffer, sizeof c->buffer);
228 /* Copy data from SOURCE to SINK using copy buffer C. */
230 copy_buffer_do_copy (struct copy_buffer *c, estream_t source, estream_t sink)
237 c->writep = c->buffer;
238 if (es_read (source, c->buffer, sizeof c->buffer, &c->nread))
240 err = my_error_from_syserror ();
241 if (gpg_err_code (err) == GPG_ERR_EAGAIN)
242 return 0; /* We will just retry next time. */
247 log_assert (c->nread <= sizeof c->buffer);
251 return 0; /* Done copying. */
254 if (sink && es_write (sink, c->writep, c->nread, &nwritten))
255 err = my_error_from_syserror ();
259 log_assert (nwritten <= c->nread);
260 c->writep += nwritten;
261 c->nread -= nwritten;
262 log_assert (c->writep - c->buffer <= sizeof c->buffer);
266 if (gpg_err_code (err) == GPG_ERR_EAGAIN)
267 return 0; /* We will just retry next time. */
272 if (sink && es_fflush (sink) && errno != EAGAIN)
273 err = my_error_from_syserror ();
279 /* Flush the remaining data to SINK. */
281 copy_buffer_flush (struct copy_buffer *c, estream_t sink)
286 if (es_write (sink, c->writep, c->nread, &nwritten))
287 err = my_error_from_syserror ();
289 log_assert (nwritten <= c->nread);
290 c->writep += nwritten;
291 c->nread -= nwritten;
292 log_assert (c->writep - c->buffer <= sizeof c->buffer);
297 if (es_fflush (sink))
298 err = my_error_from_syserror ();
305 /* Run the program PGMNAME with the command line arguments given in
306 * the NULL terminates array ARGV. If INPUT is not NULL it will be
307 * fed to stdin of the process. stderr is logged using log_info and
308 * the process's stdout is written to OUTPUT. If OUTPUT is NULL the
309 * output is discarded. If INEXTRA is given, an additional input
310 * stream will be passed to the child; to tell the child about this
311 * ARGV is scanned and the first occurrence of an argument
312 * "-&@INEXTRA@" is replaced by the concatenation of "-&" and the
313 * child's file descriptor of the pipe created for the INEXTRA stream.
315 * On error a diagnostic is printed and an error code returned. */
317 gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
318 estream_t input, estream_t inextra,
320 exec_tool_status_cb_t status_cb,
321 void *status_cb_value)
324 pid_t pid = (pid_t) -1;
325 estream_t infp = NULL;
326 estream_t extrafp = NULL;
327 estream_t outfp = NULL, errfp = NULL;
330 int extrapipe[2] = {-1, -1};
332 const char *argsave = NULL;
335 read_and_log_buffer_t fderrstate;
336 struct copy_buffer *cpbuf_in = NULL, *cpbuf_out = NULL, *cpbuf_extra = NULL;
340 memset (fds, 0, sizeof fds);
341 memset (&fderrstate, 0, sizeof fderrstate);
343 /* If the first argument to the program is "--quiet" avoid all extra
345 quiet = (argv && argv[0] && !strcmp (argv[0], "--quiet"));
347 cpbuf_in = xtrymalloc (sizeof *cpbuf_in);
348 if (cpbuf_in == NULL)
350 err = my_error_from_syserror ();
353 copy_buffer_init (cpbuf_in);
355 cpbuf_out = xtrymalloc (sizeof *cpbuf_out);
356 if (cpbuf_out == NULL)
358 err = my_error_from_syserror ();
361 copy_buffer_init (cpbuf_out);
363 cpbuf_extra = xtrymalloc (sizeof *cpbuf_extra);
364 if (cpbuf_extra == NULL)
366 err = my_error_from_syserror ();
369 copy_buffer_init (cpbuf_extra);
371 fderrstate.pgmname = pgmname;
372 fderrstate.quiet = quiet;
373 fderrstate.status_cb = status_cb;
374 fderrstate.status_cb_value = status_cb_value;
375 fderrstate.buffer_size = 256;
376 fderrstate.buffer = xtrymalloc (fderrstate.buffer_size);
377 if (!fderrstate.buffer)
379 err = my_error_from_syserror ();
385 err = gnupg_create_outbound_pipe (extrapipe, &extrafp, 1);
388 log_error ("error creating outbound pipe for extra fp: %s\n",
392 exceptclose[0] = extrapipe[0]; /* Do not close in child. */
394 /* Now find the argument marker and replace by the pipe's fd.
395 Yeah, that is an ugly non-thread safe hack but it safes us to
396 create a copy of the array. */
397 #ifdef HAVE_W32_SYSTEM
398 snprintf (extrafdbuf, sizeof extrafdbuf, "-&%lu",
399 (unsigned long)_get_osfhandle (extrapipe[0]));
401 snprintf (extrafdbuf, sizeof extrafdbuf, "-&%d", extrapipe[0]);
403 for (argsaveidx=0; argv[argsaveidx]; argsaveidx++)
404 if (!strcmp (argv[argsaveidx], "-&@INEXTRA@"))
406 argsave = argv[argsaveidx];
407 argv[argsaveidx] = extrafdbuf;
414 err = gnupg_spawn_process (pgmname, argv,
415 exceptclose, GNUPG_SPAWN_NONBLOCK,
417 &outfp, &errfp, &pid);
418 if (extrapipe[0] != -1)
419 close (extrapipe[0]);
421 argv[argsaveidx] = argsave;
425 log_error ("error running '%s': %s\n", pgmname, gpg_strerror (err));
429 fds[0].stream = infp;
430 fds[0].want_write = 1;
433 fds[1].stream = outfp;
434 fds[1].want_read = 1;
435 fds[2].stream = errfp;
436 fds[2].want_read = 1;
437 fds[3].stream = extrafp;
438 fds[3].want_write = 1;
442 /* Now read as long as we have something to poll. We continue
443 reading even after EOF or error on stdout so that we get the
444 other error messages or remaining output. */
445 while (! (fds[1].ignore && fds[2].ignore))
447 count = es_poll (fds, DIM(fds), -1);
450 err = my_error_from_syserror ();
451 log_error ("error polling '%s': %s\n", pgmname, gpg_strerror (err));
456 log_debug ("unexpected timeout while polling '%s'\n", pgmname);
460 if (fds[0].got_write)
462 err = copy_buffer_do_copy (cpbuf_in, input, fds[0].stream);
465 log_error ("error feeding data to '%s': %s\n",
466 pgmname, gpg_strerror (err));
472 err = copy_buffer_flush (cpbuf_in, fds[0].stream);
473 if (gpg_err_code (err) == GPG_ERR_EAGAIN)
474 continue; /* Retry next time. */
477 log_error ("error feeding data to '%s': %s\n",
478 pgmname, gpg_strerror (err));
482 fds[0].ignore = 1; /* ready. */
483 es_fclose (infp); infp = NULL;
487 if (fds[3].got_write)
489 log_assert (inextra);
490 err = copy_buffer_do_copy (cpbuf_extra, inextra, fds[3].stream);
493 log_error ("error feeding data to '%s': %s\n",
494 pgmname, gpg_strerror (err));
498 if (es_feof (inextra))
500 err = copy_buffer_flush (cpbuf_extra, fds[3].stream);
501 if (gpg_err_code (err) == GPG_ERR_EAGAIN)
502 continue; /* Retry next time. */
505 log_error ("error feeding data to '%s': %s\n",
506 pgmname, gpg_strerror (err));
510 fds[3].ignore = 1; /* ready. */
511 es_fclose (extrafp); extrafp = NULL;
517 err = copy_buffer_do_copy (cpbuf_out, fds[1].stream, output);
520 log_error ("error reading data from '%s': %s\n",
521 pgmname, gpg_strerror (err));
525 if (es_feof (fds[1].stream))
527 err = copy_buffer_flush (cpbuf_out, output);
530 log_error ("error reading data from '%s': %s\n",
531 pgmname, gpg_strerror (err));
535 fds[1].ignore = 1; /* ready. */
540 read_and_log_stderr (&fderrstate, fds + 2);
543 read_and_log_stderr (&fderrstate, NULL); /* Flush. */
544 es_fclose (infp); infp = NULL;
545 es_fclose (extrafp); extrafp = NULL;
546 es_fclose (outfp); outfp = NULL;
547 es_fclose (errfp); errfp = NULL;
549 err = gnupg_wait_process (pgmname, pid, 1, quiet? &dummy_exitcode : NULL);
553 if (err && pid != (pid_t) -1)
554 gnupg_kill_process (pid);
560 if (pid != (pid_t)(-1))
561 gnupg_wait_process (pgmname, pid, 1, quiet? &dummy_exitcode : NULL);
562 gnupg_release_process (pid);
564 copy_buffer_shred (cpbuf_in);
566 copy_buffer_shred (cpbuf_out);
568 copy_buffer_shred (cpbuf_extra);
570 xfree (fderrstate.buffer);
575 /* A dummy free function to pass to 'es_mopen'. */
582 /* Run the program PGMNAME with the command line arguments given in
583 the NULL terminates array ARGV. If INPUT_STRING is not NULL it
584 will be fed to stdin of the process. stderr is logged using
585 log_info and the process's stdout is returned in a newly malloced
586 buffer RESULT with the length stored at RESULTLEN if not given as
587 NULL. A hidden Nul is appended to the output. On error NULL is
588 stored at RESULT, a diagnostic is printed, and an error code
591 gnupg_exec_tool (const char *pgmname, const char *argv[],
592 const char *input_string,
593 char **result, size_t *resultlen)
596 estream_t input = NULL;
607 len = strlen (input_string);
608 input = es_mopen ((char *) input_string, len, len,
609 0 /* don't grow */, NULL, nop_free, "rb");
611 return my_error_from_syserror ();
614 output = es_fopenmem (0, "wb");
617 err = my_error_from_syserror ();
621 err = gnupg_exec_tool_stream (pgmname, argv, input, NULL, output, NULL, NULL);
625 len = es_ftello (output);
626 err = es_fseek (output, 0, SEEK_SET);
630 *result = xtrymalloc (len + 1);
633 err = my_error_from_syserror ();
639 if (es_read (output, *result, len, &nread))
641 err = my_error_from_syserror ();
645 log_fatal ("%s: short read from memstream\n", __func__);