More include guards.
[gpgme.git] / src / engine-assuan.c
1 /* engine-assuan.c - Low-level Assuan protocol engine
2  * Copyright (C) 2009 g10 Code GmbH
3  *
4  * This file is part of GPGME.
5  *
6  * GPGME is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * GPGME is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /*
21    Note: This engine requires a modern Assuan server which uses
22    gpg-error codes.  In particular there is no backward compatible
23    mapping of old Assuan error codes implemented.
24 */
25
26
27 #if HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30
31 #include <stdlib.h>
32 #include <string.h>
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
35 #endif
36 #include <assert.h>
37 #ifdef HAVE_UNISTD_H
38 # include <unistd.h>
39 #endif
40 #ifdef HAVE_LOCALE_H
41 #include <locale.h>
42 #endif
43 #include <errno.h>
44
45 #include "gpgme.h"
46 #include "util.h"
47 #include "ops.h"
48 #include "wait.h"
49 #include "priv-io.h"
50 #include "sema.h"
51
52 #include "assuan.h"
53 #include "debug.h"
54
55 #include "engine-backend.h"
56
57 \f
58 typedef struct
59 {
60   int fd;       /* FD we talk about.  */
61   int server_fd;/* Server FD for this connection.  */
62   int dir;      /* Inbound/Outbound, maybe given implicit?  */
63   void *data;   /* Handler-specific data.  */
64   void *tag;    /* ID from the user for gpgme_remove_io_callback.  */
65 } iocb_data_t;
66
67 /* Engine instance data.  */
68 struct engine_llass
69 {
70   assuan_context_t assuan_ctx;
71
72   int lc_ctype_set;
73   int lc_messages_set;
74
75   iocb_data_t status_cb;
76
77   struct gpgme_io_cbs io_cbs;
78
79   /* Hack for old opassuan.c interface, see there the result struct.  */
80   gpg_error_t last_op_err;
81
82   /* User provided callbacks.  */
83   struct {
84     gpgme_assuan_data_cb_t data_cb;
85     void *data_cb_value;
86
87     gpgme_assuan_inquire_cb_t inq_cb;
88     void *inq_cb_value;
89
90     gpgme_assuan_status_cb_t status_cb;
91     void *status_cb_value;
92   } user;
93
94   /* Option flags.  */
95   struct {
96     int gpg_agent:1;  /* Assume this is a gpg-agent connection.  */
97   } opt;
98
99 };
100 typedef struct engine_llass *engine_llass_t;
101
102
103 gpg_error_t _gpgme_engine_assuan_last_op_err (void *engine)
104 {
105   engine_llass_t llass = engine;
106   return llass->last_op_err;
107 }
108
109
110 /* Prototypes.  */
111 static void llass_io_event (void *engine,
112                             gpgme_event_io_t type, void *type_data);
113
114
115
116
117 \f
118 /* return the default home directory.  */
119 static const char *
120 llass_get_home_dir (void)
121 {
122   /* For this engine the home directory is not a filename but a string
123      used to convey options.  The exclamation mark is a marker to show
124      that this is not a directory name. Options are strings delimited
125      by a space.  The only option defined for now is GPG_AGENT to
126      enable GPG_AGENT specific commands to send to the server at
127      connection startup.  */
128   return "!GPG_AGENT";
129 }
130
131 static char *
132 llass_get_version (const char *file_name)
133 {
134   return strdup ("1.0");
135 }
136
137
138 static const char *
139 llass_get_req_version (void)
140 {
141   return "1.0";
142 }
143
144 \f
145 static void
146 close_notify_handler (int fd, void *opaque)
147 {
148   engine_llass_t llass = opaque;
149
150   assert (fd != -1);
151   if (llass->status_cb.fd == fd)
152     {
153       if (llass->status_cb.tag)
154         llass->io_cbs.remove (llass->status_cb.tag);
155       llass->status_cb.fd = -1;
156       llass->status_cb.tag = NULL;
157     }
158 }
159
160
161
162 static gpgme_error_t
163 llass_cancel (void *engine)
164 {
165   engine_llass_t llass = engine;
166
167   if (!llass)
168     return gpg_error (GPG_ERR_INV_VALUE);
169
170   if (llass->status_cb.fd != -1)
171     _gpgme_io_close (llass->status_cb.fd);
172
173   if (llass->assuan_ctx)
174     {
175       assuan_release (llass->assuan_ctx);
176       llass->assuan_ctx = NULL;
177     }
178
179   return 0;
180 }
181
182
183 static gpgme_error_t
184 llass_cancel_op (void *engine)
185 {
186   engine_llass_t llass = engine;
187
188   if (!llass)
189     return gpg_error (GPG_ERR_INV_VALUE);
190
191   if (llass->status_cb.fd != -1)
192     _gpgme_io_close (llass->status_cb.fd);
193
194   return 0;
195 }
196
197
198 static void
199 llass_release (void *engine)
200 {
201   engine_llass_t llass = engine;
202
203   if (!llass)
204     return;
205
206   llass_cancel (engine);
207
208   free (llass);
209 }
210
211
212 /* Create a new instance. If HOME_DIR is NULL standard options for use
213    with gpg-agent are issued.  */  
214 static gpgme_error_t
215 llass_new (void **engine, const char *file_name, const char *home_dir)
216 {
217   gpgme_error_t err = 0;
218   engine_llass_t llass;
219   char *optstr;
220
221   llass = calloc (1, sizeof *llass);
222   if (!llass)
223     return gpg_error_from_syserror ();
224
225   llass->status_cb.fd = -1;
226   llass->status_cb.dir = 1;
227   llass->status_cb.tag = 0;
228   llass->status_cb.data = llass;
229
230   /* Parse_options.  */
231   if (home_dir && *home_dir == '!')
232     {
233       home_dir++;
234       /* Very simple parser only working for the one option we support.  */
235       /* Note that wk promised to write a regression test if this
236          parser will be extended.  */
237       if (!strncmp (home_dir, "GPG_AGENT", 9) 
238           && (!home_dir[9] || home_dir[9] == ' '))
239         llass->opt.gpg_agent = 1;
240     }
241
242   err = assuan_new_ext (&llass->assuan_ctx, GPG_ERR_SOURCE_GPGME,
243                         &_gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb,
244                         NULL);
245   if (err)
246     goto leave;
247   assuan_ctx_set_system_hooks (llass->assuan_ctx, &_gpgme_assuan_system_hooks);
248
249   err = assuan_socket_connect (llass->assuan_ctx, file_name, 0, 0);
250   if (err)
251     goto leave;
252
253   if (llass->opt.gpg_agent)
254     {
255       char *dft_display = NULL;
256
257       err = _gpgme_getenv ("DISPLAY", &dft_display);
258       if (err)
259         goto leave;
260       if (dft_display)
261         {
262           if (asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
263             {
264               err = gpg_error_from_syserror ();
265               free (dft_display);
266               goto leave;
267             }
268           free (dft_display);
269
270           err = assuan_transact (llass->assuan_ctx, optstr, NULL, NULL, NULL,
271                                  NULL, NULL, NULL);
272           free (optstr);
273           if (err)
274             goto leave;
275         }
276     }
277
278   if (llass->opt.gpg_agent && isatty (1))
279     {
280       int rc;
281       char dft_ttyname[64];
282       char *dft_ttytype = NULL;
283
284       rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
285       if (rc)
286         {
287           err = gpg_error_from_errno (rc);
288           goto leave;
289         }
290       else
291         {
292           if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
293             {
294               err = gpg_error_from_syserror ();
295               goto leave;
296             }
297           err = assuan_transact (llass->assuan_ctx, optstr, NULL, NULL, NULL,
298                                  NULL, NULL, NULL);
299           free (optstr);
300           if (err)
301             goto leave;
302
303           err = _gpgme_getenv ("TERM", &dft_ttytype);
304           if (err)
305             goto leave;
306           if (dft_ttytype)
307             {
308               if (asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype) < 0)
309                 {
310                   err = gpg_error_from_syserror ();
311                   free (dft_ttytype);
312                   goto leave;
313                 }
314               free (dft_ttytype);
315               
316               err = assuan_transact (llass->assuan_ctx, optstr, NULL, NULL,
317                                      NULL, NULL, NULL, NULL);
318               free (optstr);
319               if (err)
320                 goto leave;
321             }
322         }
323     }
324
325
326 #ifdef HAVE_W32_SYSTEM
327   /* Under Windows we need to use AllowSetForegroundWindow.  Tell
328      llass to tell us when it needs it.  */
329   if (!err && llass->opt.gpg_agent)
330     {
331       err = assuan_transact (llass->assuan_ctx, "OPTION allow-pinentry-notify",
332                              NULL, NULL, NULL, NULL, NULL, NULL);
333       if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
334         err = 0; /* This work only with recent gpg-agents.  */
335     }
336 #endif /*HAVE_W32_SYSTEM*/
337
338
339  leave:
340   /* Close the server ends of the pipes (because of this, we must use
341      the stored server_fd_str in the function start).  Our ends are
342      closed in llass_release().  */
343
344   if (err)
345     llass_release (llass);
346   else
347     *engine = llass;
348
349   return err;
350 }
351
352
353 static gpgme_error_t
354 llass_set_locale (void *engine, int category, const char *value)
355 {
356   gpgme_error_t err;
357   engine_llass_t llass = engine;
358   char *optstr;
359   char *catstr;
360
361   if (!llass->opt.gpg_agent)
362     return 0;
363
364   /* FIXME: If value is NULL, we need to reset the option to default.
365      But we can't do this.  So we error out here.  gpg-agent needs
366      support for this.  */
367   if (0)
368     ;
369 #ifdef LC_CTYPE
370   else if (category == LC_CTYPE)
371     {
372       catstr = "lc-ctype";
373       if (!value && llass->lc_ctype_set)
374         return gpg_error (GPG_ERR_INV_VALUE);
375       if (value)
376         llass->lc_ctype_set = 1;
377     }
378 #endif
379 #ifdef LC_MESSAGES
380   else if (category == LC_MESSAGES)
381     {
382       catstr = "lc-messages";
383       if (!value && llass->lc_messages_set)
384         return gpg_error (GPG_ERR_INV_VALUE);
385       if (value)
386         llass->lc_messages_set = 1;
387     }
388 #endif /* LC_MESSAGES */
389   else
390     return gpg_error (GPG_ERR_INV_VALUE);
391
392   /* FIXME: Reset value to default.  */
393   if (!value)
394     return 0;
395
396   if (asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0)
397     err = gpg_error_from_errno (errno);
398   else
399     {
400       err = assuan_transact (llass->assuan_ctx, optstr, NULL, NULL,
401                              NULL, NULL, NULL, NULL);
402       free (optstr);
403     }
404   return err;
405 }
406
407
408 /* This is the inquiry callback.  It handles stuff which ee need to
409    handle here and passes everything on to the user callback.  */
410 static gpgme_error_t
411 inquire_cb (engine_llass_t llass, const char *keyword, const char *args)
412 {
413   gpg_error_t err;
414
415   if (llass->opt.gpg_agent && !strcmp (keyword, "PINENTRY_LAUNCHED"))
416     {
417       _gpgme_allow_set_foreground_window ((pid_t)strtoul (args, NULL, 10));
418     }
419
420   if (llass->user.inq_cb)
421     {
422       gpgme_data_t data = NULL;
423
424       err = llass->user.inq_cb (llass->user.inq_cb_value,
425                                 keyword, args, &data);
426       if (!err && data)
427         {
428           /* FIXME: Returning data is not yet implemented.  However we
429              need to allow the caller to cleanup his data object.
430              Thus we run the callback in finish mode immediately.  */
431           err = llass->user.inq_cb (llass->user.inq_cb_value,
432                                     NULL, NULL, &data);
433         }
434     }
435   else
436     err = 0;
437
438   return err;
439 }
440
441
442 static gpgme_error_t
443 llass_status_handler (void *opaque, int fd)
444 {
445   struct io_cb_data *data = (struct io_cb_data *) opaque;
446   engine_llass_t llass = (engine_llass_t) data->handler_value;
447   gpgme_error_t err = 0;
448   char *line;
449   size_t linelen;
450
451   do
452     {
453       err = assuan_read_line (llass->assuan_ctx, &line, &linelen);
454       if (err)
455         {
456           /* Reading a full line may not be possible when
457              communicating over a socket in nonblocking mode.  In this
458              case, we are done for now.  */
459           if (gpg_err_code (err) == GPG_ERR_EAGAIN)
460             {
461               TRACE1 (DEBUG_CTX, "gpgme:llass_status_handler", llass,
462                       "fd 0x%x: EAGAIN reading assuan line (ignored)", fd);
463               err = 0;
464               continue;
465             }
466           
467           TRACE2 (DEBUG_CTX, "gpgme:llass_status_handler", llass,
468                   "fd 0x%x: error reading assuan line: %s",
469                   fd, gpg_strerror (err));
470         }
471       else if (linelen >= 2 && line[0] == 'D' && line[1] == ' ')
472         {
473           char *src = line + 2;
474           char *end = line + linelen;
475           char *dst = src;
476
477           linelen = 0;
478           while (src < end)
479             {
480               if (*src == '%' && src + 2 < end)
481                 {
482                   /* Handle escaped characters.  */
483                   ++src;
484                   *dst++ = _gpgme_hextobyte (src);
485                   src += 2;
486                 }
487               else
488                 *dst++ = *src++;
489
490               linelen++;
491             }
492
493           src = line + 2;
494           if (linelen && llass->user.data_cb)
495             err = llass->user.data_cb (llass->user.data_cb_value,
496                                        src, linelen);
497
498           TRACE2 (DEBUG_CTX, "gpgme:llass_status_handler", llass,
499                   "fd 0x%x: D inlinedata; status from cb: %s",
500                   fd, (llass->user.data_cb ?
501                        (err? gpg_strerror (err):"ok"):"no callback"));
502         }
503       else if (linelen >= 3
504                && line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
505                && (line[3] == '\0' || line[3] == ' '))
506         {
507           /* END received.  Tell the data callback.  */
508           if (llass->user.data_cb)
509             err = llass->user.data_cb (llass->user.data_cb_value, NULL, 0);
510
511           TRACE2 (DEBUG_CTX, "gpgme:llass_status_handler", llass,
512                   "fd 0x%x: END line; status from cb: %s",
513                   fd, (llass->user.data_cb ?
514                        (err? gpg_strerror (err):"ok"):"no callback"));
515         }
516       else if (linelen > 2 && line[0] == 'S' && line[1] == ' ')
517         {
518           char *args;
519           char *src;
520
521           for (src=line+2; *src == ' '; src++)
522             ;
523
524           args = strchr (src, ' ');
525           if (!args)
526             args = line + linelen; /* Let it point to an empty string.  */
527           else
528             *(args++) = 0;
529
530           while (*args == ' ')
531             args++;
532
533           if (llass->user.status_cb)
534             err = llass->user.status_cb (llass->user.status_cb_value,
535                                          src, args);
536
537           TRACE3 (DEBUG_CTX, "gpgme:llass_status_handler", llass,
538                   "fd 0x%x: S line (%s) - status from cb: %s",
539                   fd, line+2, (llass->user.status_cb ?
540                                (err? gpg_strerror (err):"ok"):"no callback"));
541         }
542       else if (linelen >= 7
543                && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
544                && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
545                && line[6] == 'E'
546                && (line[7] == '\0' || line[7] == ' '))
547         {
548           char *src;
549           char *args;
550
551           for (src=line+7; *src == ' '; src++)
552             ;
553
554           args = strchr (src, ' ');
555           if (!args)
556             args = line + linelen; /* Let it point to an empty string.  */
557           else
558             *(args++) = 0;
559
560           while (*args == ' ')
561             args++;
562
563           err = inquire_cb (llass, src, args);
564           if (!err) 
565             {
566               /* Flush and send END.  */
567               err = assuan_send_data (llass->assuan_ctx, NULL, 0);
568             }
569           else if (gpg_err_code (err) == GPG_ERR_ASS_CANCELED)
570             {
571               /* Flush and send CANcel.  */
572               err = assuan_send_data (llass->assuan_ctx, NULL, 1);
573             }
574         }
575       else if (linelen >= 3
576                && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
577                && (line[3] == '\0' || line[3] == ' '))
578         {
579           if (line[3] == ' ')
580             err = atoi (line+4);
581           else
582             err = gpg_error (GPG_ERR_GENERAL);
583           TRACE2 (DEBUG_CTX, "gpgme:llass_status_handler", llass,
584                   "fd 0x%x: ERR line: %s",
585                   fd, err ? gpg_strerror (err) : "ok");
586
587           /* Command execution errors are not fatal, as we use
588              a session based protocol.  */
589           data->op_err = err;
590           llass->last_op_err = err;
591
592           /* The caller will do the rest (namely, call cancel_op,
593              which closes status_fd).  */
594           return 0;
595         }
596       else if (linelen >= 2
597                && line[0] == 'O' && line[1] == 'K'
598                && (line[2] == '\0' || line[2] == ' '))
599         {
600           TRACE1 (DEBUG_CTX, "gpgme:llass_status_handler", llass,
601                   "fd 0x%x: OK line", fd);
602
603           llass->last_op_err = 0;
604
605           _gpgme_io_close (llass->status_cb.fd);
606           return 0;
607         }
608       else
609         {
610           /* Comment line or invalid line.  */
611         }
612
613     }
614   while (!err && assuan_pending_line (llass->assuan_ctx));
615
616   return err;
617 }
618
619
620 static gpgme_error_t
621 add_io_cb (engine_llass_t llass, iocb_data_t *iocbd, gpgme_io_cb_t handler)
622 {
623   gpgme_error_t err;
624
625   TRACE_BEG2 (DEBUG_ENGINE, "engine-assuan:add_io_cb", llass,
626               "fd %d, dir %d", iocbd->fd, iocbd->dir);
627   err = (*llass->io_cbs.add) (llass->io_cbs.add_priv,
628                               iocbd->fd, iocbd->dir,
629                               handler, iocbd->data, &iocbd->tag);
630   if (err)
631     return TRACE_ERR (err);
632   if (!iocbd->dir)
633     /* FIXME Kludge around poll() problem.  */
634     err = _gpgme_io_set_nonblocking (iocbd->fd);
635   return TRACE_ERR (err);
636 }
637
638
639 static gpgme_error_t
640 start (engine_llass_t llass, const char *command)
641 {
642   gpgme_error_t err;
643   assuan_fd_t afdlist[5];
644   int fdlist[5];
645   int nfds;
646   int i;
647
648   /* We need to know the fd used by assuan for reads.  We do this by
649      using the assumption that the first returned fd from
650      assuan_get_active_fds() is always this one.  */
651   nfds = assuan_get_active_fds (llass->assuan_ctx, 0 /* read fds */,
652                                 afdlist, DIM (afdlist));
653   if (nfds < 1)
654     return gpg_error (GPG_ERR_GENERAL); /* FIXME */
655   /* For now... */
656   for (i = 0; i < nfds; i++)
657     fdlist[i] = (int) afdlist[i];
658
659   /* We "duplicate" the file descriptor, so we can close it here (we
660      can't close fdlist[0], as that is closed by libassuan, and
661      closing it here might cause libassuan to close some unrelated FD
662      later).  Alternatively, we could special case status_fd and
663      register/unregister it manually as needed, but this increases
664      code duplication and is more complicated as we can not use the
665      close notifications etc.  A third alternative would be to let
666      Assuan know that we closed the FD, but that complicates the
667      Assuan interface.  */
668
669   llass->status_cb.fd = _gpgme_io_dup (fdlist[0]);
670   if (llass->status_cb.fd < 0)
671     return gpg_error_from_syserror ();
672
673   if (_gpgme_io_set_close_notify (llass->status_cb.fd,
674                                   close_notify_handler, llass))
675     {
676       _gpgme_io_close (llass->status_cb.fd);
677       llass->status_cb.fd = -1;
678       return gpg_error (GPG_ERR_GENERAL);
679     }
680
681   err = add_io_cb (llass, &llass->status_cb, llass_status_handler);
682   if (!err)
683     err = assuan_write_line (llass->assuan_ctx, command);
684
685   /* FIXME: If *command == '#' no answer is expected.  */
686
687   if (!err)
688     llass_io_event (llass, GPGME_EVENT_START, NULL);
689
690   return err;
691 }
692
693
694
695 static gpgme_error_t
696 llass_transact (void *engine,
697                 const char *command,
698                 gpgme_assuan_data_cb_t data_cb,
699                 void *data_cb_value,
700                 gpgme_assuan_inquire_cb_t inq_cb,
701                 void *inq_cb_value,
702                 gpgme_assuan_status_cb_t status_cb,
703                 void *status_cb_value)
704 {
705   engine_llass_t llass = engine;
706   gpgme_error_t err;
707
708   if (!llass || !command || !*command)
709     return gpg_error (GPG_ERR_INV_VALUE);
710
711   llass->user.data_cb = data_cb;
712   llass->user.data_cb_value = data_cb_value;
713   llass->user.inq_cb = inq_cb;
714   llass->user.inq_cb_value = inq_cb_value;
715   llass->user.status_cb = status_cb;
716   llass->user.status_cb_value = status_cb_value;
717
718   err = start (llass, command);
719   return err;
720 }
721
722
723
724 static void
725 llass_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
726 {
727   engine_llass_t llass = engine;
728   llass->io_cbs = *io_cbs;
729 }
730
731
732 static void
733 llass_io_event (void *engine, gpgme_event_io_t type, void *type_data)
734 {
735   engine_llass_t llass = engine;
736
737   TRACE3 (DEBUG_ENGINE, "gpgme:llass_io_event", llass,
738           "event %p, type %d, type_data %p",
739           llass->io_cbs.event, type, type_data);
740   if (llass->io_cbs.event)
741     (*llass->io_cbs.event) (llass->io_cbs.event_priv, type, type_data);
742 }
743
744
745 struct engine_ops _gpgme_engine_ops_assuan =
746   {
747     /* Static functions.  */
748     _gpgme_get_default_agent_socket,
749     llass_get_home_dir,
750     llass_get_version,
751     llass_get_req_version,
752     llass_new,
753
754     /* Member functions.  */
755     llass_release,
756     NULL,               /* reset */
757     NULL,               /* set_status_handler */
758     NULL,               /* set_command_handler */
759     NULL,               /* set_colon_line_handler */
760     llass_set_locale,
761     NULL,               /* set_protocol */
762     NULL,               /* decrypt */
763     NULL,               /* decrypt_verify */
764     NULL,               /* delete */
765     NULL,               /* edit */
766     NULL,               /* encrypt */
767     NULL,               /* encrypt_sign */
768     NULL,               /* export */
769     NULL,               /* export_ext */
770     NULL,               /* genkey */
771     NULL,               /* import */
772     NULL,               /* keylist */
773     NULL,               /* keylist_ext */
774     NULL,               /* sign */
775     NULL,               /* trustlist */
776     NULL,               /* verify */
777     NULL,               /* getauditlog */
778     llass_transact,     /* opassuan_transact */
779     NULL,               /* conf_load */
780     NULL,               /* conf_save */
781     llass_set_io_cbs,
782     llass_io_event,
783     llass_cancel,
784     llass_cancel_op
785   };