LCOV - code coverage report
Current view: top level - common - call-gpg.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 327 0.0 %
Date: 2016-11-29 15:00:56 Functions: 0 14 0.0 %

          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             : }

Generated by: LCOV version 1.11