Line data Source code
1 : /* call-gpg.c - Communication with the GPG
2 : * Copyright (C) 2009 Free Software Foundation, Inc.
3 : *
4 : * This file is part of GnuPG.
5 : *
6 : * GnuPG is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * GnuPG is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; if not, see <https://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include <config.h>
21 :
22 : #include <assert.h>
23 : #include <assuan.h>
24 : #include <errno.h>
25 : #include <npth.h>
26 : #include <stdlib.h>
27 : #include <stdio.h>
28 : #include <string.h>
29 : #include <time.h>
30 :
31 : #include "call-gpg.h"
32 : #include "exechelp.h"
33 : #include "i18n.h"
34 : #include "logging.h"
35 : #include "membuf.h"
36 : #include "strlist.h"
37 : #include "util.h"
38 :
39 :
40 : static GPGRT_INLINE gpg_error_t
41 0 : my_error_from_syserror (void)
42 : {
43 0 : return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
44 : }
45 :
46 : static GPGRT_INLINE gpg_error_t
47 0 : my_error_from_errno (int e)
48 : {
49 0 : return gpg_err_make (default_errsource, gpg_err_code_from_errno (e));
50 : }
51 :
52 :
53 : /* Fire up a new GPG. Handle the server's initial greeting. Returns
54 : 0 on success and stores the assuan context at R_CTX. */
55 : static gpg_error_t
56 0 : start_gpg (ctrl_t ctrl, const char *gpg_program, strlist_t gpg_arguments,
57 : int input_fd, int output_fd, assuan_context_t *r_ctx)
58 : {
59 : gpg_error_t err;
60 0 : assuan_context_t ctx = NULL;
61 : const char *pgmname;
62 : const char **argv;
63 : assuan_fd_t no_close_list[5];
64 : int i;
65 : char line[ASSUAN_LINELENGTH];
66 :
67 : (void)ctrl;
68 :
69 0 : *r_ctx = NULL;
70 :
71 0 : err = assuan_new (&ctx);
72 0 : if (err)
73 : {
74 0 : log_error ("can't allocate assuan context: %s\n", gpg_strerror (err));
75 0 : return err;
76 : }
77 :
78 : /* The first time we are used, intialize the gpg_program variable. */
79 0 : if ( !gpg_program || !*gpg_program )
80 0 : gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG);
81 :
82 : /* Compute argv[0]. */
83 0 : if ( !(pgmname = strrchr (gpg_program, '/')))
84 0 : pgmname = gpg_program;
85 : else
86 0 : pgmname++;
87 :
88 0 : if (fflush (NULL))
89 : {
90 0 : err = my_error_from_syserror ();
91 0 : log_error ("error flushing pending output: %s\n", gpg_strerror (err));
92 0 : return err;
93 : }
94 :
95 0 : argv = xtrycalloc (strlist_length (gpg_arguments) + 3, sizeof *argv);
96 0 : if (argv == NULL)
97 : {
98 0 : err = my_error_from_syserror ();
99 0 : return err;
100 : }
101 0 : i = 0;
102 0 : argv[i++] = pgmname;
103 0 : argv[i++] = "--server";
104 0 : for (; gpg_arguments; gpg_arguments = gpg_arguments->next)
105 0 : argv[i++] = gpg_arguments->d;
106 0 : argv[i++] = NULL;
107 :
108 0 : i = 0;
109 0 : if (log_get_fd () != -1)
110 0 : no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
111 0 : no_close_list[i++] = assuan_fd_from_posix_fd (fileno (stderr));
112 0 : if (input_fd != -1)
113 0 : no_close_list[i++] = assuan_fd_from_posix_fd (input_fd);
114 0 : if (output_fd != -1)
115 0 : no_close_list[i++] = assuan_fd_from_posix_fd (output_fd);
116 0 : no_close_list[i] = ASSUAN_INVALID_FD;
117 :
118 : /* Connect to GPG and perform initial handshaking. */
119 0 : err = assuan_pipe_connect (ctx, gpg_program, argv, no_close_list,
120 : NULL, NULL, 0);
121 0 : if (err)
122 : {
123 0 : assuan_release (ctx);
124 0 : log_error ("can't connect to GPG: %s\n", gpg_strerror (err));
125 0 : return gpg_error (GPG_ERR_NO_ENGINE);
126 : }
127 :
128 0 : if (input_fd != -1)
129 : {
130 0 : snprintf (line, sizeof line, "INPUT FD=%d", input_fd);
131 0 : err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
132 0 : if (err)
133 : {
134 0 : assuan_release (ctx);
135 0 : log_error ("error sending INPUT command: %s\n", gpg_strerror (err));
136 0 : return err;
137 : }
138 : }
139 :
140 0 : if (output_fd != -1)
141 : {
142 0 : snprintf (line, sizeof line, "OUTPUT FD=%d", output_fd);
143 0 : err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
144 0 : if (err)
145 : {
146 0 : assuan_release (ctx);
147 0 : log_error ("error sending OUTPUT command: %s\n", gpg_strerror (err));
148 0 : return err;
149 : }
150 : }
151 :
152 0 : *r_ctx = ctx;
153 0 : return 0;
154 : }
155 :
156 :
157 : /* Release the assuan context created by start_gpg. */
158 : static void
159 0 : release_gpg (assuan_context_t ctx)
160 : {
161 0 : assuan_release (ctx);
162 0 : }
163 :
164 :
165 :
166 : /* The data passed to the writer_thread. */
167 : struct writer_thread_parms
168 : {
169 : int fd;
170 : const void *data;
171 : size_t datalen;
172 : estream_t stream;
173 : gpg_error_t *err_addr;
174 : };
175 :
176 :
177 : /* The thread started by start_writer. */
178 : static void *
179 0 : writer_thread_main (void *arg)
180 : {
181 0 : gpg_error_t err = 0;
182 0 : struct writer_thread_parms *parm = arg;
183 : char _buffer[4096];
184 : char *buffer;
185 : size_t length;
186 :
187 0 : if (parm->stream)
188 : {
189 0 : buffer = _buffer;
190 0 : err = es_read (parm->stream, buffer, sizeof _buffer, &length);
191 0 : if (err)
192 : {
193 0 : log_error ("reading stream failed: %s\n", gpg_strerror (err));
194 0 : goto leave;
195 : }
196 : }
197 : else
198 : {
199 0 : buffer = (char *) parm->data;
200 0 : length = parm->datalen;
201 : }
202 :
203 0 : while (length)
204 : {
205 : ssize_t nwritten;
206 :
207 0 : nwritten = npth_write (parm->fd, buffer, length < 4096? length:4096);
208 0 : if (nwritten < 0)
209 : {
210 0 : if (errno == EINTR)
211 0 : continue;
212 0 : err = my_error_from_syserror ();
213 0 : break; /* Write error. */
214 : }
215 0 : length -= nwritten;
216 :
217 0 : if (parm->stream)
218 : {
219 0 : if (length == 0)
220 : {
221 0 : err = es_read (parm->stream, buffer, sizeof _buffer, &length);
222 0 : if (err)
223 : {
224 0 : log_error ("reading stream failed: %s\n",
225 : gpg_strerror (err));
226 0 : break;
227 : }
228 0 : if (length == 0)
229 : /* We're done. */
230 0 : break;
231 : }
232 : }
233 : else
234 0 : buffer += nwritten;
235 : }
236 :
237 : leave:
238 0 : *parm->err_addr = err;
239 0 : if (close (parm->fd))
240 0 : log_error ("closing writer fd %d failed: %s\n", parm->fd, strerror (errno));
241 0 : xfree (parm);
242 0 : return NULL;
243 : }
244 :
245 :
246 : /* Fire up a thread to send (DATA,DATALEN) to the file descriptor FD.
247 : On success the thread receives the ownership over FD. The thread
248 : ID is stored at R_TID. WRITER_ERR is the address of an gpg_error_t
249 : variable to receive a possible write error after the thread has
250 : finished. */
251 : static gpg_error_t
252 0 : start_writer (int fd, const void *data, size_t datalen, estream_t stream,
253 : npth_t *r_thread, gpg_error_t *err_addr)
254 : {
255 : gpg_error_t err;
256 : struct writer_thread_parms *parm;
257 : npth_attr_t tattr;
258 : npth_t thread;
259 : int ret;
260 :
261 0 : memset (r_thread, '\0', sizeof (*r_thread));
262 0 : *err_addr = 0;
263 :
264 0 : parm = xtrymalloc (sizeof *parm);
265 0 : if (!parm)
266 0 : return my_error_from_syserror ();
267 0 : parm->fd = fd;
268 0 : parm->data = data;
269 0 : parm->datalen = datalen;
270 0 : parm->stream = stream;
271 0 : parm->err_addr = err_addr;
272 :
273 0 : npth_attr_init (&tattr);
274 0 : npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE);
275 :
276 0 : ret = npth_create (&thread, &tattr, writer_thread_main, parm);
277 0 : if (ret)
278 : {
279 0 : err = my_error_from_errno (ret);
280 0 : log_error ("error spawning writer thread: %s\n", gpg_strerror (err));
281 : }
282 : else
283 : {
284 0 : npth_setname_np (thread, "fd-writer");
285 0 : err = 0;
286 0 : *r_thread = thread;
287 : }
288 0 : npth_attr_destroy (&tattr);
289 :
290 0 : return err;
291 : }
292 :
293 :
294 :
295 : /* The data passed to the reader_thread. */
296 : struct reader_thread_parms
297 : {
298 : int fd;
299 : membuf_t *mb;
300 : estream_t stream;
301 : gpg_error_t *err_addr;
302 : };
303 :
304 :
305 : /* The thread started by start_reader. */
306 : static void *
307 0 : reader_thread_main (void *arg)
308 : {
309 0 : gpg_error_t err = 0;
310 0 : struct reader_thread_parms *parm = arg;
311 : char buffer[4096];
312 : int nread;
313 :
314 0 : while ( (nread = npth_read (parm->fd, buffer, sizeof buffer)) )
315 : {
316 0 : if (nread < 0)
317 : {
318 0 : if (errno == EINTR)
319 0 : continue;
320 0 : err = my_error_from_syserror ();
321 0 : break; /* Read error. */
322 : }
323 :
324 0 : if (parm->stream)
325 : {
326 0 : const char *p = buffer;
327 : size_t nwritten;
328 0 : while (nread)
329 : {
330 0 : err = es_write (parm->stream, p, nread, &nwritten);
331 0 : if (err)
332 : {
333 0 : log_error ("writing stream failed: %s\n",
334 : gpg_strerror (err));
335 0 : goto leave;
336 : }
337 0 : nread -= nwritten;
338 0 : p += nwritten;
339 : }
340 : }
341 : else
342 0 : put_membuf (parm->mb, buffer, nread);
343 : }
344 :
345 : leave:
346 0 : *parm->err_addr = err;
347 0 : if (close (parm->fd))
348 0 : log_error ("closing reader fd %d failed: %s\n", parm->fd, strerror (errno));
349 0 : xfree (parm);
350 0 : return NULL;
351 : }
352 :
353 :
354 : /* Fire up a thread to receive data from the file descriptor FD. On
355 : success the thread receives the ownership over FD. The thread ID
356 : is stored at R_TID. After the thread has finished an error from
357 : the thread will be stored at ERR_ADDR. */
358 : static gpg_error_t
359 0 : start_reader (int fd, membuf_t *mb, estream_t stream,
360 : npth_t *r_thread, gpg_error_t *err_addr)
361 : {
362 : gpg_error_t err;
363 : struct reader_thread_parms *parm;
364 : npth_attr_t tattr;
365 : npth_t thread;
366 : int ret;
367 :
368 0 : memset (r_thread, '\0', sizeof (*r_thread));
369 0 : *err_addr = 0;
370 :
371 0 : parm = xtrymalloc (sizeof *parm);
372 0 : if (!parm)
373 0 : return my_error_from_syserror ();
374 0 : parm->fd = fd;
375 0 : parm->mb = mb;
376 0 : parm->stream = stream;
377 0 : parm->err_addr = err_addr;
378 :
379 0 : npth_attr_init (&tattr);
380 0 : npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE);
381 :
382 0 : ret = npth_create (&thread, &tattr, reader_thread_main, parm);
383 0 : if (ret)
384 : {
385 0 : err = my_error_from_errno (ret);
386 0 : log_error ("error spawning reader thread: %s\n", gpg_strerror (err));
387 : }
388 : else
389 : {
390 0 : npth_setname_np (thread, "fd-reader");
391 0 : err = 0;
392 0 : *r_thread = thread;
393 : }
394 0 : npth_attr_destroy (&tattr);
395 :
396 0 : return err;
397 : }
398 :
399 :
400 :
401 :
402 : /* Call GPG to encrypt a block of data.
403 :
404 :
405 : */
406 : static gpg_error_t
407 0 : _gpg_encrypt (ctrl_t ctrl,
408 : const char *gpg_program,
409 : strlist_t gpg_arguments,
410 : const void *plain, size_t plainlen,
411 : estream_t plain_stream,
412 : strlist_t keys,
413 : membuf_t *reader_mb,
414 : estream_t cipher_stream)
415 : {
416 : gpg_error_t err;
417 0 : assuan_context_t ctx = NULL;
418 0 : int outbound_fds[2] = { -1, -1 };
419 0 : int inbound_fds[2] = { -1, -1 };
420 0 : npth_t writer_thread = (npth_t)0;
421 0 : npth_t reader_thread = (npth_t)0;
422 : gpg_error_t writer_err, reader_err;
423 : char line[ASSUAN_LINELENGTH];
424 : strlist_t sl;
425 : int ret;
426 :
427 : /* Make sure that either the stream interface xor the buffer
428 : interface is used. */
429 0 : assert ((plain == NULL) != (plain_stream == NULL));
430 0 : assert ((reader_mb == NULL) != (cipher_stream == NULL));
431 :
432 : /* Create two pipes. */
433 0 : err = gnupg_create_outbound_pipe (outbound_fds, NULL, 0);
434 0 : if (!err)
435 0 : err = gnupg_create_inbound_pipe (inbound_fds, NULL, 0);
436 0 : if (err)
437 : {
438 0 : log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
439 0 : goto leave;
440 : }
441 :
442 : /* Start GPG and send the INPUT and OUTPUT commands. */
443 0 : err = start_gpg (ctrl, gpg_program, gpg_arguments,
444 : outbound_fds[0], inbound_fds[1], &ctx);
445 0 : if (err)
446 0 : goto leave;
447 0 : close (outbound_fds[0]); outbound_fds[0] = -1;
448 0 : close (inbound_fds[1]); inbound_fds[1] = -1;
449 :
450 : /* Start a writer thread to feed the INPUT command of the server. */
451 0 : err = start_writer (outbound_fds[1], plain, plainlen, plain_stream,
452 : &writer_thread, &writer_err);
453 0 : if (err)
454 0 : return err;
455 0 : outbound_fds[1] = -1; /* The thread owns the FD now. */
456 :
457 : /* Start a reader thread to eat from the OUTPUT command of the
458 : server. */
459 0 : err = start_reader (inbound_fds[0], reader_mb, cipher_stream,
460 : &reader_thread, &reader_err);
461 0 : if (err)
462 0 : return err;
463 0 : outbound_fds[0] = -1; /* The thread owns the FD now. */
464 :
465 : /* Run the encryption. */
466 0 : for (sl = keys; sl; sl = sl->next)
467 : {
468 0 : snprintf (line, sizeof line, "RECIPIENT -- %s", sl->d);
469 0 : err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
470 0 : if (err)
471 : {
472 0 : log_error ("the engine's RECIPIENT command failed: %s <%s>\n",
473 : gpg_strerror (err), gpg_strsource (err));
474 0 : goto leave;
475 : }
476 : }
477 :
478 0 : err = assuan_transact (ctx, "ENCRYPT", NULL, NULL, NULL, NULL, NULL, NULL);
479 0 : if (err)
480 : {
481 0 : log_error ("the engine's ENCRYPT command failed: %s <%s>\n",
482 : gpg_strerror (err), gpg_strsource (err));
483 0 : goto leave;
484 : }
485 :
486 : /* Wait for reader and return the data. */
487 0 : ret = npth_join (reader_thread, NULL);
488 0 : if (ret)
489 : {
490 0 : err = my_error_from_errno (ret);
491 0 : log_error ("waiting for reader thread failed: %s\n", gpg_strerror (err));
492 0 : goto leave;
493 : }
494 : /* FIXME: Not really valid, as npth_t is an opaque type. */
495 0 : memset (&reader_thread, '\0', sizeof (reader_thread));
496 0 : if (reader_err)
497 : {
498 0 : err = reader_err;
499 0 : log_error ("read error in reader thread: %s\n", gpg_strerror (err));
500 0 : goto leave;
501 : }
502 :
503 : /* Wait for the writer to catch a writer error. */
504 0 : ret = npth_join (writer_thread, NULL);
505 0 : if (ret)
506 : {
507 0 : err = my_error_from_errno (ret);
508 0 : log_error ("waiting for writer thread failed: %s\n", gpg_strerror (err));
509 0 : goto leave;
510 : }
511 0 : memset (&writer_thread, '\0', sizeof (writer_thread));
512 0 : if (writer_err)
513 : {
514 0 : err = writer_err;
515 0 : log_error ("write error in writer thread: %s\n", gpg_strerror (err));
516 0 : goto leave;
517 : }
518 :
519 : leave:
520 : /* FIXME: Not valid, as npth_t is an opaque type. */
521 0 : if (reader_thread)
522 0 : npth_detach (reader_thread);
523 0 : if (writer_thread)
524 0 : npth_detach (writer_thread);
525 0 : if (outbound_fds[0] != -1)
526 0 : close (outbound_fds[0]);
527 0 : if (outbound_fds[1] != -1)
528 0 : close (outbound_fds[1]);
529 0 : if (inbound_fds[0] != -1)
530 0 : close (inbound_fds[0]);
531 0 : if (inbound_fds[1] != -1)
532 0 : close (inbound_fds[1]);
533 0 : release_gpg (ctx);
534 0 : return err;
535 : }
536 :
537 : gpg_error_t
538 0 : gpg_encrypt_blob (ctrl_t ctrl,
539 : const char *gpg_program,
540 : strlist_t gpg_arguments,
541 : const void *plain, size_t plainlen,
542 : strlist_t keys,
543 : void **r_ciph, size_t *r_ciphlen)
544 : {
545 : gpg_error_t err;
546 : membuf_t reader_mb;
547 :
548 0 : *r_ciph = NULL;
549 0 : *r_ciphlen = 0;
550 :
551 : /* Init the memory buffer to receive the encrypted stuff. */
552 0 : init_membuf (&reader_mb, 4096);
553 :
554 0 : err = _gpg_encrypt (ctrl, gpg_program, gpg_arguments,
555 : plain, plainlen, NULL,
556 : keys,
557 : &reader_mb, NULL);
558 :
559 0 : if (! err)
560 : {
561 : /* Return the data. */
562 0 : *r_ciph = get_membuf (&reader_mb, r_ciphlen);
563 0 : if (!*r_ciph)
564 : {
565 0 : err = my_error_from_syserror ();
566 0 : log_error ("error while storing the data in the reader thread: %s\n",
567 : gpg_strerror (err));
568 : }
569 : }
570 :
571 0 : xfree (get_membuf (&reader_mb, NULL));
572 0 : return err;
573 : }
574 :
575 : gpg_error_t
576 0 : gpg_encrypt_stream (ctrl_t ctrl,
577 : const char *gpg_program,
578 : strlist_t gpg_arguments,
579 : estream_t plain_stream,
580 : strlist_t keys,
581 : estream_t cipher_stream)
582 : {
583 0 : return _gpg_encrypt (ctrl, gpg_program, gpg_arguments,
584 : NULL, 0, plain_stream,
585 : keys,
586 : NULL, cipher_stream);
587 : }
588 :
589 : /* Call GPG to decrypt a block of data.
590 :
591 :
592 : */
593 : static gpg_error_t
594 0 : _gpg_decrypt (ctrl_t ctrl,
595 : const char *gpg_program,
596 : strlist_t gpg_arguments,
597 : const void *ciph, size_t ciphlen,
598 : estream_t cipher_stream,
599 : membuf_t *reader_mb,
600 : estream_t plain_stream)
601 : {
602 : gpg_error_t err;
603 0 : assuan_context_t ctx = NULL;
604 0 : int outbound_fds[2] = { -1, -1 };
605 0 : int inbound_fds[2] = { -1, -1 };
606 0 : npth_t writer_thread = (npth_t)0;
607 0 : npth_t reader_thread = (npth_t)0;
608 : gpg_error_t writer_err, reader_err;
609 : int ret;
610 :
611 : /* Make sure that either the stream interface xor the buffer
612 : interface is used. */
613 0 : assert ((ciph == NULL) != (cipher_stream == NULL));
614 0 : assert ((reader_mb == NULL) != (plain_stream == NULL));
615 :
616 : /* Create two pipes. */
617 0 : err = gnupg_create_outbound_pipe (outbound_fds, NULL, 0);
618 0 : if (!err)
619 0 : err = gnupg_create_inbound_pipe (inbound_fds, NULL, 0);
620 0 : if (err)
621 : {
622 0 : log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
623 0 : goto leave;
624 : }
625 :
626 : /* Start GPG and send the INPUT and OUTPUT commands. */
627 0 : err = start_gpg (ctrl, gpg_program, gpg_arguments,
628 : outbound_fds[0], inbound_fds[1], &ctx);
629 0 : if (err)
630 0 : goto leave;
631 0 : close (outbound_fds[0]); outbound_fds[0] = -1;
632 0 : close (inbound_fds[1]); inbound_fds[1] = -1;
633 :
634 : /* Start a writer thread to feed the INPUT command of the server. */
635 0 : err = start_writer (outbound_fds[1], ciph, ciphlen, cipher_stream,
636 : &writer_thread, &writer_err);
637 0 : if (err)
638 0 : return err;
639 0 : outbound_fds[1] = -1; /* The thread owns the FD now. */
640 :
641 : /* Start a reader thread to eat from the OUTPUT command of the
642 : server. */
643 0 : err = start_reader (inbound_fds[0], reader_mb, plain_stream,
644 : &reader_thread, &reader_err);
645 0 : if (err)
646 0 : return err;
647 0 : outbound_fds[0] = -1; /* The thread owns the FD now. */
648 :
649 : /* Run the decryption. */
650 0 : err = assuan_transact (ctx, "DECRYPT", NULL, NULL, NULL, NULL, NULL, NULL);
651 0 : if (err)
652 : {
653 0 : log_error ("the engine's DECRYPT command failed: %s <%s>\n",
654 : gpg_strerror (err), gpg_strsource (err));
655 0 : goto leave;
656 : }
657 :
658 : /* Wait for reader and return the data. */
659 0 : ret = npth_join (reader_thread, NULL);
660 0 : if (ret)
661 : {
662 0 : err = my_error_from_errno (ret);
663 0 : log_error ("waiting for reader thread failed: %s\n", gpg_strerror (err));
664 0 : goto leave;
665 : }
666 0 : memset (&reader_thread, '\0', sizeof (reader_thread));
667 0 : if (reader_err)
668 : {
669 0 : err = reader_err;
670 0 : log_error ("read error in reader thread: %s\n", gpg_strerror (err));
671 0 : goto leave;
672 : }
673 :
674 : /* Wait for the writer to catch a writer error. */
675 0 : ret = npth_join (writer_thread, NULL);
676 0 : if (ret)
677 : {
678 0 : err = my_error_from_errno (ret);
679 0 : log_error ("waiting for writer thread failed: %s\n", gpg_strerror (err));
680 0 : goto leave;
681 : }
682 0 : memset (&writer_thread, '\0', sizeof (writer_thread));
683 0 : if (writer_err)
684 : {
685 0 : err = writer_err;
686 0 : log_error ("write error in writer thread: %s\n", gpg_strerror (err));
687 0 : goto leave;
688 : }
689 :
690 : leave:
691 0 : if (reader_thread)
692 0 : npth_detach (reader_thread);
693 0 : if (writer_thread)
694 0 : npth_detach (writer_thread);
695 0 : if (outbound_fds[0] != -1)
696 0 : close (outbound_fds[0]);
697 0 : if (outbound_fds[1] != -1)
698 0 : close (outbound_fds[1]);
699 0 : if (inbound_fds[0] != -1)
700 0 : close (inbound_fds[0]);
701 0 : if (inbound_fds[1] != -1)
702 0 : close (inbound_fds[1]);
703 0 : release_gpg (ctx);
704 0 : return err;
705 : }
706 :
707 : gpg_error_t
708 0 : gpg_decrypt_blob (ctrl_t ctrl,
709 : const char *gpg_program,
710 : strlist_t gpg_arguments,
711 : const void *ciph, size_t ciphlen,
712 : void **r_plain, size_t *r_plainlen)
713 : {
714 : gpg_error_t err;
715 : membuf_t reader_mb;
716 :
717 0 : *r_plain = NULL;
718 0 : *r_plainlen = 0;
719 :
720 : /* Init the memory buffer to receive the encrypted stuff. */
721 0 : init_membuf_secure (&reader_mb, 1024);
722 :
723 0 : err = _gpg_decrypt (ctrl, gpg_program, gpg_arguments,
724 : ciph, ciphlen, NULL,
725 : &reader_mb, NULL);
726 :
727 0 : if (! err)
728 : {
729 : /* Return the data. */
730 0 : *r_plain = get_membuf (&reader_mb, r_plainlen);
731 0 : if (!*r_plain)
732 : {
733 0 : err = my_error_from_syserror ();
734 0 : log_error ("error while storing the data in the reader thread: %s\n",
735 : gpg_strerror (err));
736 : }
737 : }
738 :
739 0 : xfree (get_membuf (&reader_mb, NULL));
740 0 : return err;
741 : }
742 :
743 : gpg_error_t
744 0 : gpg_decrypt_stream (ctrl_t ctrl,
745 : const char *gpg_program,
746 : strlist_t gpg_arguments,
747 : estream_t cipher_stream,
748 : estream_t plain_stream)
749 : {
750 0 : return _gpg_decrypt (ctrl, gpg_program, gpg_arguments,
751 : NULL, 0, cipher_stream,
752 : NULL, plain_stream);
753 : }
|