common: Refactor the call-gpg code.
[gnupg.git] / common / call-gpg.c
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 <http://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 "util.h"
37
38 \f
39 /* Fire up a new GPG.  Handle the server's initial greeting.  Returns
40    0 on success and stores the assuan context at R_CTX.  */
41 static gpg_error_t
42 start_gpg (ctrl_t ctrl, const char *gpg_program,
43            int input_fd, int output_fd, assuan_context_t *r_ctx)
44 {
45   gpg_error_t err;
46   assuan_context_t ctx = NULL;
47   const char *pgmname;
48   const char *argv[10];
49   int no_close_list[5];
50   int i;
51   char line[ASSUAN_LINELENGTH];
52
53   (void)ctrl;
54
55   *r_ctx = NULL;
56
57   err = assuan_new (&ctx);
58   if (err)
59     {
60       log_error ("can't allocate assuan context: %s\n", gpg_strerror (err));
61       return err;
62     }
63
64   /* The first time we are used, intialize the gpg_program variable.  */
65   if ( !gpg_program || !*gpg_program )
66     gpg_program = gnupg_module_name (GNUPG_MODULE_NAME_GPG);
67
68   /* Compute argv[0].  */
69   if ( !(pgmname = strrchr (gpg_program, '/')))
70     pgmname = gpg_program;
71   else
72     pgmname++;
73
74   if (fflush (NULL))
75     {
76       err = gpg_error_from_syserror ();
77       log_error ("error flushing pending output: %s\n", gpg_strerror (err));
78       return err;
79     }
80
81   i = 0;
82   argv[i++] = pgmname;
83   argv[i++] = "--server";
84   argv[i++] = "-z";
85   argv[i++] = "0";
86   argv[i++] = "--trust-model";
87   argv[i++] = "always";
88   argv[i++] = NULL;
89
90   i = 0;
91   if (log_get_fd () != -1)
92     no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
93   no_close_list[i++] = assuan_fd_from_posix_fd (fileno (stderr));
94   if (input_fd != -1)
95     no_close_list[i++] = assuan_fd_from_posix_fd (input_fd);
96   if (output_fd != -1)
97     no_close_list[i++] = assuan_fd_from_posix_fd (output_fd);
98   no_close_list[i] = -1;
99
100   /* Connect to GPG and perform initial handshaking.  */
101   err = assuan_pipe_connect (ctx, gpg_program, argv, no_close_list,
102                              NULL, NULL, 0);
103   if (err)
104     {
105       assuan_release (ctx);
106       log_error ("can't connect to GPG: %s\n", gpg_strerror (err));
107       return gpg_error (GPG_ERR_NO_ENGINE);
108     }
109
110   if (input_fd != -1)
111     {
112       snprintf (line, sizeof line, "INPUT FD=%d", input_fd);
113       err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
114       if (err)
115         {
116           assuan_release (ctx);
117           log_error ("error sending INPUT command: %s\n", gpg_strerror (err));
118           return err;
119         }
120     }
121
122   if (output_fd != -1)
123     {
124       snprintf (line, sizeof line, "OUTPUT FD=%d", output_fd);
125       err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
126       if (err)
127         {
128           assuan_release (ctx);
129           log_error ("error sending OUTPUT command: %s\n", gpg_strerror (err));
130           return err;
131         }
132     }
133
134   *r_ctx = ctx;
135   return 0;
136 }
137
138
139 /* Release the assuan context created by start_gpg.  */
140 static void
141 release_gpg (assuan_context_t ctx)
142 {
143   assuan_release (ctx);
144 }
145
146
147 \f
148 /* The data passed to the writer_thread.  */
149 struct writer_thread_parms
150 {
151   int fd;
152   const void *data;
153   size_t datalen;
154   gpg_error_t *err_addr;
155 };
156
157
158 /* The thread started by start_writer.  */
159 static void *
160 writer_thread_main (void *arg)
161 {
162   struct writer_thread_parms *parm = arg;
163   const char *buffer = parm->data;
164   size_t length = parm->datalen;
165
166   while (length)
167     {
168       ssize_t nwritten;
169
170       nwritten = npth_write (parm->fd, buffer, length < 4096? length:4096);
171       if (nwritten < 0)
172         {
173           if (errno == EINTR)
174             continue;
175           *parm->err_addr = gpg_error_from_syserror ();
176           break; /* Write error.  */
177         }
178       length -= nwritten;
179       buffer += nwritten;
180     }
181
182   if (close (parm->fd))
183     log_error ("closing writer fd %d failed: %s\n", parm->fd, strerror (errno));
184   xfree (parm);
185   return NULL;
186 }
187
188
189 /* Fire up a thread to send (DATA,DATALEN) to the file descriptor FD.
190    On success the thread receives the ownership over FD.  The thread
191    ID is stored at R_TID.  WRITER_ERR is the address of an gpg_error_t
192    variable to receive a possible write error after the thread has
193    finished.  */
194 static gpg_error_t
195 start_writer (int fd, const void *data, size_t datalen,
196               npth_t *r_thread, gpg_error_t *err_addr)
197 {
198   gpg_error_t err;
199   struct writer_thread_parms *parm;
200   npth_attr_t tattr;
201   npth_t thread;
202   int ret;
203
204   memset (r_thread, '\0', sizeof (*r_thread));
205   *err_addr = 0;
206
207   parm = xtrymalloc (sizeof *parm);
208   if (!parm)
209     return gpg_error_from_syserror ();
210   parm->fd = fd;
211   parm->data = data;
212   parm->datalen = datalen;
213   parm->err_addr = err_addr;
214
215   npth_attr_init (&tattr);
216   npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE);
217
218   ret = npth_create (&thread, &tattr, writer_thread_main, parm);
219   if (ret)
220     {
221       err = gpg_error_from_errno (ret);
222       log_error ("error spawning writer thread: %s\n", gpg_strerror (err));
223     }
224   else
225     {
226       npth_setname_np (thread, "fd-writer");
227       err = 0;
228       *r_thread = thread;
229     }
230   npth_attr_destroy (&tattr);
231
232   return err;
233 }
234
235
236 \f
237 /* The data passed to the reader_thread.  */
238 struct reader_thread_parms
239 {
240   int fd;
241   membuf_t *mb;
242   gpg_error_t *err_addr;
243 };
244
245
246 /* The thread started by start_reader.  */
247 static void *
248 reader_thread_main (void *arg)
249 {
250   struct reader_thread_parms *parm = arg;
251   char buffer[4096];
252   int nread;
253
254   while ( (nread = npth_read (parm->fd, buffer, sizeof buffer)) )
255     {
256       if (nread < 0)
257         {
258           if (errno == EINTR)
259             continue;
260           *parm->err_addr = gpg_error_from_syserror ();
261           break;  /* Read error.  */
262         }
263
264       put_membuf (parm->mb, buffer, nread);
265     }
266
267   if (close (parm->fd))
268     log_error ("closing reader fd %d failed: %s\n", parm->fd, strerror (errno));
269   xfree (parm);
270   return NULL;
271 }
272
273
274 /* Fire up a thread to receive data from the file descriptor FD.  On
275    success the thread receives the ownership over FD.  The thread ID
276    is stored at R_TID.  After the thread has finished an error from
277    the thread will be stored at ERR_ADDR.  */
278 static gpg_error_t
279 start_reader (int fd, membuf_t *mb, npth_t *r_thread, gpg_error_t *err_addr)
280 {
281   gpg_error_t err;
282   struct reader_thread_parms *parm;
283   npth_attr_t tattr;
284   npth_t thread;
285   int ret;
286
287   memset (r_thread, '\0', sizeof (*r_thread));
288   *err_addr = 0;
289
290   parm = xtrymalloc (sizeof *parm);
291   if (!parm)
292     return gpg_error_from_syserror ();
293   parm->fd = fd;
294   parm->mb = mb;
295   parm->err_addr = err_addr;
296
297   npth_attr_init (&tattr);
298   npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE);
299
300   ret = npth_create (&thread, &tattr, reader_thread_main, parm);
301   if (ret)
302     {
303       err = gpg_error_from_errno (ret);
304       log_error ("error spawning reader thread: %s\n", gpg_strerror (err));
305     }
306   else
307     {
308       npth_setname_np (thread, "fd-reader");
309       err = 0;
310       *r_thread = thread;
311     }
312   npth_attr_destroy (&tattr);
313
314   return err;
315 }
316
317
318
319 \f
320 /* Call GPG to encrypt a block of data.
321
322
323  */
324 static gpg_error_t
325 _gpg_encrypt (ctrl_t ctrl, const char *gpg_program,
326               const void *plain, size_t plainlen,
327               strlist_t keys,
328               membuf_t *reader_mb)
329 {
330   gpg_error_t err;
331   assuan_context_t ctx = NULL;
332   int outbound_fds[2] = { -1, -1 };
333   int inbound_fds[2]  = { -1, -1 };
334   npth_t writer_thread = (npth_t)0;
335   npth_t reader_thread = (npth_t)0;
336   gpg_error_t writer_err, reader_err;
337   char line[ASSUAN_LINELENGTH];
338   strlist_t sl;
339   int ret;
340
341   /* Create two pipes.  */
342   err = gnupg_create_outbound_pipe (outbound_fds);
343   if (!err)
344     err = gnupg_create_inbound_pipe (inbound_fds);
345   if (err)
346     {
347       log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
348       goto leave;
349     }
350
351   /* Start GPG and send the INPUT and OUTPUT commands.  */
352   err = start_gpg (ctrl, gpg_program, outbound_fds[0], inbound_fds[1], &ctx);
353   if (err)
354     goto leave;
355   close (outbound_fds[0]); outbound_fds[0] = -1;
356   close (inbound_fds[1]); inbound_fds[1] = -1;
357
358   /* Start a writer thread to feed the INPUT command of the server.  */
359   err = start_writer (outbound_fds[1], plain, plainlen,
360                       &writer_thread, &writer_err);
361   if (err)
362     return err;
363   outbound_fds[1] = -1;  /* The thread owns the FD now.  */
364
365   /* Start a reader thread to eat from the OUTPUT command of the
366      server.  */
367   err = start_reader (inbound_fds[0], reader_mb,
368                       &reader_thread, &reader_err);
369   if (err)
370     return err;
371   outbound_fds[0] = -1;  /* The thread owns the FD now.  */
372
373   /* Run the encryption.  */
374   for (sl = keys; sl; sl = sl->next)
375     {
376       snprintf (line, sizeof line, "RECIPIENT -- %s", sl->d);
377       err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
378       if (err)
379         {
380           log_error ("the engine's RECIPIENT command failed: %s <%s>\n",
381                  gpg_strerror (err), gpg_strsource (err));
382           goto leave;
383         }
384     }
385
386   err = assuan_transact (ctx, "ENCRYPT", NULL, NULL, NULL, NULL, NULL, NULL);
387   if (err)
388     {
389       log_error ("the engine's ENCRYPT command failed: %s <%s>\n",
390                  gpg_strerror (err), gpg_strsource (err));
391       goto leave;
392     }
393
394   /* Wait for reader and return the data.  */
395   ret = npth_join (reader_thread, NULL);
396   if (ret)
397     {
398       err = gpg_error_from_errno (ret);
399       log_error ("waiting for reader thread failed: %s\n", gpg_strerror (err));
400       goto leave;
401     }
402   /* FIXME: Not really valid, as npth_t is an opaque type.  */
403   memset (&reader_thread, '\0', sizeof (reader_thread));
404   if (reader_err)
405     {
406       err = reader_err;
407       log_error ("read error in reader thread: %s\n", gpg_strerror (err));
408       goto leave;
409     }
410
411   /* Wait for the writer to catch  a writer error.  */
412   ret = npth_join (writer_thread, NULL);
413   if (ret)
414     {
415       err = gpg_error_from_errno (ret);
416       log_error ("waiting for writer thread failed: %s\n", gpg_strerror (err));
417       goto leave;
418     }
419   memset (&writer_thread, '\0', sizeof (writer_thread));
420   if (writer_err)
421     {
422       err = writer_err;
423       log_error ("write error in writer thread: %s\n", gpg_strerror (err));
424       goto leave;
425     }
426
427  leave:
428   /* FIXME: Not valid, as npth_t is an opaque type.  */
429   if (reader_thread)
430     npth_detach (reader_thread);
431   if (writer_thread)
432     npth_detach (writer_thread);
433   if (outbound_fds[0] != -1)
434     close (outbound_fds[0]);
435   if (outbound_fds[1] != -1)
436     close (outbound_fds[1]);
437   if (inbound_fds[0] != -1)
438     close (inbound_fds[0]);
439   if (inbound_fds[1] != -1)
440     close (inbound_fds[1]);
441   release_gpg (ctx);
442   return err;
443 }
444
445 gpg_error_t
446 gpg_encrypt_blob (ctrl_t ctrl, const char *gpg_program,
447                   const void *plain, size_t plainlen,
448                   strlist_t keys,
449                   void **r_ciph, size_t *r_ciphlen)
450 {
451   gpg_error_t err;
452   membuf_t reader_mb;
453
454   *r_ciph = NULL;
455   *r_ciphlen = 0;
456
457   /* Init the memory buffer to receive the encrypted stuff.  */
458   init_membuf (&reader_mb, 4096);
459
460   err = _gpg_encrypt (ctrl, gpg_program,
461                       plain, plainlen,
462                       keys,
463                       &reader_mb);
464
465   if (! err)
466     {
467       /* Return the data.  */
468       *r_ciph = get_membuf (&reader_mb, r_ciphlen);
469       if (!*r_ciph)
470         {
471           err = gpg_error_from_syserror ();
472           log_error ("error while storing the data in the reader thread: %s\n",
473                      gpg_strerror (err));
474         }
475     }
476
477   xfree (get_membuf (&reader_mb, NULL));
478   return err;
479 }
480
481 \f
482 /* Call GPG to decrypt a block of data.
483
484
485  */
486 static gpg_error_t
487 _gpg_decrypt (ctrl_t ctrl, const char *gpg_program,
488               const void *ciph, size_t ciphlen,
489               membuf_t *reader_mb)
490 {
491   gpg_error_t err;
492   assuan_context_t ctx = NULL;
493   int outbound_fds[2] = { -1, -1 };
494   int inbound_fds[2]  = { -1, -1 };
495   npth_t writer_thread = (npth_t)0;
496   npth_t reader_thread = (npth_t)0;
497   gpg_error_t writer_err, reader_err;
498   int ret;
499
500   /* Create two pipes.  */
501   err = gnupg_create_outbound_pipe (outbound_fds);
502   if (!err)
503     err = gnupg_create_inbound_pipe (inbound_fds);
504   if (err)
505     {
506       log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
507       goto leave;
508     }
509
510   /* Start GPG and send the INPUT and OUTPUT commands.  */
511   err = start_gpg (ctrl, gpg_program, outbound_fds[0], inbound_fds[1], &ctx);
512   if (err)
513     goto leave;
514   close (outbound_fds[0]); outbound_fds[0] = -1;
515   close (inbound_fds[1]); inbound_fds[1] = -1;
516
517   /* Start a writer thread to feed the INPUT command of the server.  */
518   err = start_writer (outbound_fds[1], ciph, ciphlen,
519                       &writer_thread, &writer_err);
520   if (err)
521     return err;
522   outbound_fds[1] = -1;  /* The thread owns the FD now.  */
523
524   /* Start a reader thread to eat from the OUTPUT command of the
525      server.  */
526   err = start_reader (inbound_fds[0], reader_mb,
527                       &reader_thread, &reader_err);
528   if (err)
529     return err;
530   outbound_fds[0] = -1;  /* The thread owns the FD now.  */
531
532   /* Run the decryption.  */
533   err = assuan_transact (ctx, "DECRYPT", NULL, NULL, NULL, NULL, NULL, NULL);
534   if (err)
535     {
536       log_error ("the engine's DECRYPT command failed: %s <%s>\n",
537                  gpg_strerror (err), gpg_strsource (err));
538       goto leave;
539     }
540
541   /* Wait for reader and return the data.  */
542   ret = npth_join (reader_thread, NULL);
543   if (ret)
544     {
545       err = gpg_error_from_errno (ret);
546       log_error ("waiting for reader thread failed: %s\n", gpg_strerror (err));
547       goto leave;
548     }
549   memset (&reader_thread, '\0', sizeof (reader_thread));
550   if (reader_err)
551     {
552       err = reader_err;
553       log_error ("read error in reader thread: %s\n", gpg_strerror (err));
554       goto leave;
555     }
556
557   /* Wait for the writer to catch a writer error.  */
558   ret = npth_join (writer_thread, NULL);
559   if (ret)
560     {
561       err = gpg_error_from_errno (ret);
562       log_error ("waiting for writer thread failed: %s\n", gpg_strerror (err));
563       goto leave;
564     }
565   memset (&writer_thread, '\0', sizeof (writer_thread));
566   if (writer_err)
567     {
568       err = writer_err;
569       log_error ("write error in writer thread: %s\n", gpg_strerror (err));
570       goto leave;
571     }
572
573  leave:
574   if (reader_thread)
575     npth_detach (reader_thread);
576   if (writer_thread)
577     npth_detach (writer_thread);
578   if (outbound_fds[0] != -1)
579     close (outbound_fds[0]);
580   if (outbound_fds[1] != -1)
581     close (outbound_fds[1]);
582   if (inbound_fds[0] != -1)
583     close (inbound_fds[0]);
584   if (inbound_fds[1] != -1)
585     close (inbound_fds[1]);
586   release_gpg (ctx);
587   return err;
588 }
589
590 gpg_error_t
591 gpg_decrypt_blob (ctrl_t ctrl, const char *gpg_program,
592                   const void *ciph, size_t ciphlen,
593                   void **r_plain, size_t *r_plainlen)
594 {
595   gpg_error_t err;
596   membuf_t reader_mb;
597
598   *r_plain = NULL;
599   *r_plainlen = 0;
600
601   /* Init the memory buffer to receive the encrypted stuff.  */
602   init_membuf_secure (&reader_mb, 1024);
603
604   err = _gpg_decrypt (ctrl, gpg_program,
605                       ciph, ciphlen,
606                       &reader_mb);
607
608   if (! err)
609     {
610       /* Return the data.  */
611       *r_plain = get_membuf (&reader_mb, r_plainlen);
612       if (!*r_plain)
613         {
614           err = gpg_error_from_syserror ();
615           log_error ("error while storing the data in the reader thread: %s\n",
616                      gpg_strerror (err));
617         }
618     }
619
620   xfree (get_membuf (&reader_mb, NULL));
621   return err;
622 }