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;
59 } read_and_log_buffer_t;
62 static inline gpg_error_t
63 my_error_from_syserror (void)
65 return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
70 read_and_log_stderr (read_and_log_buffer_t *state, es_poll_t *fderr)
77 /* Flush internal buffer. */
83 state->buffer[state->used] = 0;
86 pname = strrchr (state->pgmname, '/');
87 if (pname && pname != state->pgmname && pname[1])
90 pname = state->pgmname;
94 && !strncmp (state->buffer, "[GNUPG:] ", 9)
95 && state->buffer[9] >= 'A' && state->buffer[9] <= 'Z')
99 rest = strchr (state->buffer + 9, ' ');
102 /* Set REST to an empty string. */
103 rest = state->buffer + strlen (state->buffer);
110 state->status_cb (state->status_cb_value,
111 state->buffer + 9, rest);
113 else if (!state->cont
114 && !strncmp (state->buffer, pname, len)
115 && strlen (state->buffer) > strlen (pname)
116 && state->buffer[len] == ':' )
118 /* PGMNAME plus colon is identical to the start of
119 the output: print only the output. */
120 log_info ("%s\n", state->buffer);
123 log_info ("%s%c %s\n",
124 pname, state->cont? '+':':', state->buffer);
131 c = es_fgetc (fderr->stream);
134 if (es_feof (fderr->stream))
136 fderr->ignore = 1; /* Not anymore needed. */
138 else if (es_ferror (fderr->stream))
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. */
150 read_and_log_stderr (state, NULL);
154 if (state->used >= state->buffer_size - 1)
156 if (state->status_cb)
158 /* A status callback requires that we have a full
159 * line. Thus we need to enlarget the buffer in
162 size_t newsize = state->buffer_size + 256;
164 newbuffer = xtrymalloc (newsize);
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);
176 memcpy (newbuffer, state->buffer, state->used);
177 xfree (state->buffer);
178 state->buffer = newbuffer;
179 state->buffer_size = newsize;
184 read_and_log_stderr (state, NULL);
188 state->buffer[state->used++] = c;
195 /* A buffer to copy from one stream to another. */
204 /* Initialize a copy buffer. */
206 copy_buffer_init (struct copy_buffer *c)
208 c->writep = c->buffer;
213 /* Securely wipe a copy buffer. */
215 copy_buffer_shred (struct copy_buffer *c)
219 wipememory (c->buffer, sizeof c->buffer);
225 /* Copy data from SOURCE to SINK using copy buffer C. */
227 copy_buffer_do_copy (struct copy_buffer *c, estream_t source, estream_t sink)
234 c->writep = c->buffer;
235 if (es_read (source, c->buffer, sizeof c->buffer, &c->nread))
237 err = my_error_from_syserror ();
238 if (gpg_err_code (err) == GPG_ERR_EAGAIN)
239 return 0; /* We will just retry next time. */
244 log_assert (c->nread <= sizeof c->buffer);
248 return 0; /* Done copying. */
251 if (sink && es_write (sink, c->writep, c->nread, &nwritten))
252 err = my_error_from_syserror ();
256 log_assert (nwritten <= c->nread);
257 c->writep += nwritten;
258 c->nread -= nwritten;
259 log_assert (c->writep - c->buffer <= sizeof c->buffer);
263 if (gpg_err_code (err) == GPG_ERR_EAGAIN)
264 return 0; /* We will just retry next time. */
269 if (sink && es_fflush (sink) && errno != EAGAIN)
270 err = my_error_from_syserror ();
276 /* Flush the remaining data to SINK. */
278 copy_buffer_flush (struct copy_buffer *c, estream_t sink)
283 if (es_write (sink, c->writep, c->nread, &nwritten))
284 err = my_error_from_syserror ();
286 log_assert (nwritten <= c->nread);
287 c->writep += nwritten;
288 c->nread -= nwritten;
289 log_assert (c->writep - c->buffer <= sizeof c->buffer);
294 if (es_fflush (sink))
295 err = my_error_from_syserror ();
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.
312 * On error a diagnostic is printed and an error code returned. */
314 gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
315 estream_t input, estream_t inextra,
317 exec_tool_status_cb_t status_cb,
318 void *status_cb_value)
321 pid_t pid = (pid_t) -1;
322 estream_t infp = NULL;
323 estream_t extrafp = NULL;
324 estream_t outfp = NULL, errfp = NULL;
327 int extrapipe[2] = {-1, -1};
329 const char *argsave = NULL;
332 read_and_log_buffer_t fderrstate;
333 struct copy_buffer *cpbuf_in = NULL, *cpbuf_out = NULL, *cpbuf_extra = NULL;
335 memset (fds, 0, sizeof fds);
336 memset (&fderrstate, 0, sizeof fderrstate);
338 cpbuf_in = xtrymalloc (sizeof *cpbuf_in);
339 if (cpbuf_in == NULL)
341 err = my_error_from_syserror ();
344 copy_buffer_init (cpbuf_in);
346 cpbuf_out = xtrymalloc (sizeof *cpbuf_out);
347 if (cpbuf_out == NULL)
349 err = my_error_from_syserror ();
352 copy_buffer_init (cpbuf_out);
354 cpbuf_extra = xtrymalloc (sizeof *cpbuf_extra);
355 if (cpbuf_extra == NULL)
357 err = my_error_from_syserror ();
360 copy_buffer_init (cpbuf_extra);
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)
369 err = my_error_from_syserror ();
375 err = gnupg_create_outbound_pipe (extrapipe, &extrafp, 1);
378 log_error ("error running outbound pipe for extra fp: %s\n",
382 exceptclose[0] = extrapipe[0]; /* Do not close in child. */
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]));
391 snprintf (extrafdbuf, sizeof extrafdbuf, "-&%d", extrapipe[0]);
393 for (argsaveidx=0; argv[argsaveidx]; argsaveidx++)
394 if (!strcmp (argv[argsaveidx], "-&@INEXTRA@"))
396 argsave = argv[argsaveidx];
397 argv[argsaveidx] = extrafdbuf;
404 err = gnupg_spawn_process (pgmname, argv,
405 exceptclose, NULL, GNUPG_SPAWN_NONBLOCK,
407 &outfp, &errfp, &pid);
408 if (extrapipe[0] != -1)
409 close (extrapipe[0]);
411 argv[argsaveidx] = argsave;
414 log_error ("error running '%s': %s\n", pgmname, gpg_strerror (err));
418 fds[0].stream = infp;
419 fds[0].want_write = 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;
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))
436 count = es_poll (fds, DIM(fds), -1);
439 err = my_error_from_syserror ();
440 log_error ("error polling '%s': %s\n", pgmname, gpg_strerror (err));
445 log_debug ("unexpected timeout while polling '%s'\n", pgmname);
449 if (fds[0].got_write)
451 err = copy_buffer_do_copy (cpbuf_in, input, fds[0].stream);
454 log_error ("error feeding data to '%s': %s\n",
455 pgmname, gpg_strerror (err));
461 err = copy_buffer_flush (cpbuf_in, fds[0].stream);
462 if (gpg_err_code (err) == GPG_ERR_EAGAIN)
463 continue; /* Retry next time. */
466 log_error ("error feeding data to '%s': %s\n",
467 pgmname, gpg_strerror (err));
471 fds[0].ignore = 1; /* ready. */
472 es_fclose (infp); infp = NULL;
476 if (fds[3].got_write)
478 log_assert (inextra);
479 err = copy_buffer_do_copy (cpbuf_extra, inextra, fds[3].stream);
482 log_error ("error feeding data to '%s': %s\n",
483 pgmname, gpg_strerror (err));
487 if (es_feof (inextra))
489 err = copy_buffer_flush (cpbuf_extra, fds[3].stream);
490 if (gpg_err_code (err) == GPG_ERR_EAGAIN)
491 continue; /* Retry next time. */
494 log_error ("error feeding data to '%s': %s\n",
495 pgmname, gpg_strerror (err));
499 fds[3].ignore = 1; /* ready. */
500 es_fclose (extrafp); extrafp = NULL;
506 err = copy_buffer_do_copy (cpbuf_out, fds[1].stream, output);
509 log_error ("error reading data from '%s': %s\n",
510 pgmname, gpg_strerror (err));
514 if (es_feof (fds[1].stream))
516 err = copy_buffer_flush (cpbuf_out, output);
519 log_error ("error reading data from '%s': %s\n",
520 pgmname, gpg_strerror (err));
524 fds[1].ignore = 1; /* ready. */
529 read_and_log_stderr (&fderrstate, fds + 2);
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;
538 err = gnupg_wait_process (pgmname, pid, 1, NULL);
542 if (err && pid != (pid_t) -1)
543 gnupg_kill_process (pid);
549 if (pid != (pid_t)(-1))
550 gnupg_wait_process (pgmname, pid, 1, NULL);
551 gnupg_release_process (pid);
553 copy_buffer_shred (cpbuf_in);
555 copy_buffer_shred (cpbuf_out);
557 copy_buffer_shred (cpbuf_extra);
559 xfree (fderrstate.buffer);
564 /* A dummy free function to pass to 'es_mopen'. */
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
580 gnupg_exec_tool (const char *pgmname, const char *argv[],
581 const char *input_string,
582 char **result, size_t *resultlen)
585 estream_t input = NULL;
596 len = strlen (input_string);
597 input = es_mopen ((char *) input_string, len, len,
598 0 /* don't grow */, NULL, nop_free, "rb");
600 return my_error_from_syserror ();
603 output = es_fopenmem (0, "wb");
606 err = my_error_from_syserror ();
610 err = gnupg_exec_tool_stream (pgmname, argv, input, NULL, output, NULL, NULL);
614 len = es_ftello (output);
615 err = es_fseek (output, 0, SEEK_SET);
619 *result = xtrymalloc (len + 1);
622 err = my_error_from_syserror ();
628 if (es_read (output, *result, len, &nread))
630 err = my_error_from_syserror ();
634 log_fatal ("%s: short read from memstream\n", __func__);