core: Extend gpgme_user_id_t with 'address'.
[gpgme.git] / src / engine-gpgsm.c
1 /* engine-gpgsm.c - GpgSM engine.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009,
4                  2010 g10 Code GmbH
5
6    This file is part of GPGME.
7
8    GPGME is free software; you can redistribute it and/or modify it
9    under the terms of the GNU Lesser General Public License as
10    published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    GPGME is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21    02111-1307, USA.  */
22
23 #if HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdlib.h>
28 #include <string.h>
29 #ifdef HAVE_SYS_TYPES_H
30 # include <sys/types.h>
31 #endif
32 #include <assert.h>
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36 #ifdef HAVE_LOCALE_H
37 #include <locale.h>
38 #endif
39 #include <fcntl.h> /* FIXME */
40 #include <errno.h>
41
42 #include "gpgme.h"
43 #include "util.h"
44 #include "ops.h"
45 #include "wait.h"
46 #include "priv-io.h"
47 #include "sema.h"
48 #include "data.h"
49
50 #include "assuan.h"
51 #include "debug.h"
52
53 #include "engine-backend.h"
54
55 \f
56 typedef struct
57 {
58   int fd;       /* FD we talk about.  */
59   int server_fd;/* Server FD for this connection.  */
60   int dir;      /* Inbound/Outbound, maybe given implicit?  */
61   void *data;   /* Handler-specific data.  */
62   void *tag;    /* ID from the user for gpgme_remove_io_callback.  */
63   char server_fd_str[15]; /* Same as SERVER_FD but as a string.  We
64                              need this because _gpgme_io_fd2str can't
65                              be used on a closed descriptor.  */
66 } iocb_data_t;
67
68
69 struct engine_gpgsm
70 {
71   assuan_context_t assuan_ctx;
72
73   int lc_ctype_set;
74   int lc_messages_set;
75
76   iocb_data_t status_cb;
77
78   /* Input, output etc are from the servers perspective.  */
79   iocb_data_t input_cb;
80   gpgme_data_t input_helper_data;  /* Input helper data object.  */
81   void *input_helper_memory;       /* Input helper memory block.  */
82
83   iocb_data_t output_cb;
84
85   iocb_data_t message_cb;
86
87   struct
88   {
89     engine_status_handler_t fnc;
90     void *fnc_value;
91     gpgme_status_cb_t mon_cb;
92     void *mon_cb_value;
93   } status;
94
95   struct
96   {
97     engine_colon_line_handler_t fnc;
98     void *fnc_value;
99     struct
100     {
101       char *line;
102       int linesize;
103       int linelen;
104     } attic;
105     int any; /* any data line seen */
106   } colon;
107
108   gpgme_data_t inline_data;  /* Used to collect D lines.  */
109
110   struct gpgme_io_cbs io_cbs;
111 };
112
113 typedef struct engine_gpgsm *engine_gpgsm_t;
114
115
116 static void gpgsm_io_event (void *engine,
117                             gpgme_event_io_t type, void *type_data);
118
119
120 \f
121 static char *
122 gpgsm_get_version (const char *file_name)
123 {
124   return _gpgme_get_program_version (file_name ? file_name
125                                      : _gpgme_get_default_gpgsm_name ());
126 }
127
128
129 static const char *
130 gpgsm_get_req_version (void)
131 {
132   return "2.0.4";
133 }
134
135 \f
136 static void
137 close_notify_handler (int fd, void *opaque)
138 {
139   engine_gpgsm_t gpgsm = opaque;
140
141   assert (fd != -1);
142   if (gpgsm->status_cb.fd == fd)
143     {
144       if (gpgsm->status_cb.tag)
145         (*gpgsm->io_cbs.remove) (gpgsm->status_cb.tag);
146       gpgsm->status_cb.fd = -1;
147       gpgsm->status_cb.tag = NULL;
148     }
149   else if (gpgsm->input_cb.fd == fd)
150     {
151       if (gpgsm->input_cb.tag)
152         (*gpgsm->io_cbs.remove) (gpgsm->input_cb.tag);
153       gpgsm->input_cb.fd = -1;
154       gpgsm->input_cb.tag = NULL;
155       if (gpgsm->input_helper_data)
156         {
157           gpgme_data_release (gpgsm->input_helper_data);
158           gpgsm->input_helper_data = NULL;
159         }
160       if (gpgsm->input_helper_memory)
161         {
162           free (gpgsm->input_helper_memory);
163           gpgsm->input_helper_memory = NULL;
164         }
165     }
166   else if (gpgsm->output_cb.fd == fd)
167     {
168       if (gpgsm->output_cb.tag)
169         (*gpgsm->io_cbs.remove) (gpgsm->output_cb.tag);
170       gpgsm->output_cb.fd = -1;
171       gpgsm->output_cb.tag = NULL;
172     }
173   else if (gpgsm->message_cb.fd == fd)
174     {
175       if (gpgsm->message_cb.tag)
176         (*gpgsm->io_cbs.remove) (gpgsm->message_cb.tag);
177       gpgsm->message_cb.fd = -1;
178       gpgsm->message_cb.tag = NULL;
179     }
180 }
181
182
183 /* This is the default inquiry callback.  We use it to handle the
184    Pinentry notifications.  */
185 static gpgme_error_t
186 default_inq_cb (engine_gpgsm_t gpgsm, const char *line)
187 {
188   if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
189     {
190       _gpgme_allow_set_foreground_window ((pid_t)strtoul (line+17, NULL, 10));
191     }
192
193   return 0;
194 }
195
196
197 static gpgme_error_t
198 gpgsm_cancel (void *engine)
199 {
200   engine_gpgsm_t gpgsm = engine;
201
202   if (!gpgsm)
203     return gpg_error (GPG_ERR_INV_VALUE);
204
205   if (gpgsm->status_cb.fd != -1)
206     _gpgme_io_close (gpgsm->status_cb.fd);
207   if (gpgsm->input_cb.fd != -1)
208     _gpgme_io_close (gpgsm->input_cb.fd);
209   if (gpgsm->output_cb.fd != -1)
210     _gpgme_io_close (gpgsm->output_cb.fd);
211   if (gpgsm->message_cb.fd != -1)
212     _gpgme_io_close (gpgsm->message_cb.fd);
213
214   if (gpgsm->assuan_ctx)
215     {
216       assuan_release (gpgsm->assuan_ctx);
217       gpgsm->assuan_ctx = NULL;
218     }
219
220   return 0;
221 }
222
223
224 static void
225 gpgsm_release (void *engine)
226 {
227   engine_gpgsm_t gpgsm = engine;
228
229   if (!gpgsm)
230     return;
231
232   gpgsm_cancel (engine);
233
234   free (gpgsm->colon.attic.line);
235   free (gpgsm);
236 }
237
238
239 static gpgme_error_t
240 gpgsm_new (void **engine, const char *file_name, const char *home_dir,
241            const char *version)
242 {
243   gpgme_error_t err = 0;
244   engine_gpgsm_t gpgsm;
245   const char *pgmname;
246   const char *argv[5];
247   int argc;
248 #if !USE_DESCRIPTOR_PASSING
249   int fds[2];
250   int child_fds[4];
251 #endif
252   char *dft_display = NULL;
253   char dft_ttyname[64];
254   char *dft_ttytype = NULL;
255   char *optstr;
256
257   (void)version; /* Not yet used.  */
258
259   gpgsm = calloc (1, sizeof *gpgsm);
260   if (!gpgsm)
261     return gpg_error_from_syserror ();
262
263   gpgsm->status_cb.fd = -1;
264   gpgsm->status_cb.dir = 1;
265   gpgsm->status_cb.tag = 0;
266   gpgsm->status_cb.data = gpgsm;
267
268   gpgsm->input_cb.fd = -1;
269   gpgsm->input_cb.dir = 0;
270   gpgsm->input_cb.tag = 0;
271   gpgsm->input_cb.server_fd = -1;
272   *gpgsm->input_cb.server_fd_str = 0;
273   gpgsm->output_cb.fd = -1;
274   gpgsm->output_cb.dir = 1;
275   gpgsm->output_cb.tag = 0;
276   gpgsm->output_cb.server_fd = -1;
277   *gpgsm->output_cb.server_fd_str = 0;
278   gpgsm->message_cb.fd = -1;
279   gpgsm->message_cb.dir = 0;
280   gpgsm->message_cb.tag = 0;
281   gpgsm->message_cb.server_fd = -1;
282   *gpgsm->message_cb.server_fd_str = 0;
283
284   gpgsm->status.fnc = 0;
285   gpgsm->colon.fnc = 0;
286   gpgsm->colon.attic.line = 0;
287   gpgsm->colon.attic.linesize = 0;
288   gpgsm->colon.attic.linelen = 0;
289   gpgsm->colon.any = 0;
290
291   gpgsm->inline_data = NULL;
292
293   gpgsm->io_cbs.add = NULL;
294   gpgsm->io_cbs.add_priv = NULL;
295   gpgsm->io_cbs.remove = NULL;
296   gpgsm->io_cbs.event = NULL;
297   gpgsm->io_cbs.event_priv = NULL;
298
299 #if !USE_DESCRIPTOR_PASSING
300   if (_gpgme_io_pipe (fds, 0) < 0)
301     {
302       err = gpg_error_from_syserror ();
303       goto leave;
304     }
305   gpgsm->input_cb.fd = fds[1];
306   gpgsm->input_cb.server_fd = fds[0];
307
308   if (_gpgme_io_pipe (fds, 1) < 0)
309     {
310       err = gpg_error_from_syserror ();
311       goto leave;
312     }
313   gpgsm->output_cb.fd = fds[0];
314   gpgsm->output_cb.server_fd = fds[1];
315
316   if (_gpgme_io_pipe (fds, 0) < 0)
317     {
318       err = gpg_error_from_syserror ();
319       goto leave;
320     }
321   gpgsm->message_cb.fd = fds[1];
322   gpgsm->message_cb.server_fd = fds[0];
323
324   child_fds[0] = gpgsm->input_cb.server_fd;
325   child_fds[1] = gpgsm->output_cb.server_fd;
326   child_fds[2] = gpgsm->message_cb.server_fd;
327   child_fds[3] = -1;
328 #endif
329
330   pgmname = file_name ? file_name : _gpgme_get_default_gpgsm_name ();
331
332   argc = 0;
333   argv[argc++] = _gpgme_get_basename (pgmname);
334   if (home_dir)
335     {
336       argv[argc++] = "--homedir";
337       argv[argc++] = home_dir;
338     }
339   argv[argc++] = "--server";
340   argv[argc++] = NULL;
341
342   err = assuan_new_ext (&gpgsm->assuan_ctx, GPG_ERR_SOURCE_GPGME,
343                         &_gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb,
344                         NULL);
345   if (err)
346     goto leave;
347   assuan_ctx_set_system_hooks (gpgsm->assuan_ctx, &_gpgme_assuan_system_hooks);
348
349 #if USE_DESCRIPTOR_PASSING
350   err = assuan_pipe_connect (gpgsm->assuan_ctx, pgmname, argv,
351                              NULL, NULL, NULL, ASSUAN_PIPE_CONNECT_FDPASSING);
352 #else
353   {
354     assuan_fd_t achild_fds[4];
355     int i;
356
357     /* For now... */
358     for (i = 0; i < 4; i++)
359       achild_fds[i] = (assuan_fd_t) child_fds[i];
360
361     err = assuan_pipe_connect (gpgsm->assuan_ctx, pgmname, argv,
362                                achild_fds, NULL, NULL, 0);
363
364     /* For now... */
365     for (i = 0; i < 4; i++)
366       child_fds[i] = (int) achild_fds[i];
367   }
368
369   /* On Windows, handles are inserted in the spawned process with
370      DuplicateHandle, and child_fds contains the server-local names
371      for the inserted handles when assuan_pipe_connect returns.  */
372   if (!err)
373     {
374       /* Note: We don't use _gpgme_io_fd2str here.  On W32 the
375          returned handles are real W32 system handles, not whatever
376          GPGME uses internally (which may be a system handle, a C
377          library handle or a GLib/Qt channel.  Confusing, yes, but
378          remember these are server-local names, so they are not part
379          of GPGME at all.  */
380       snprintf (gpgsm->input_cb.server_fd_str,
381                 sizeof gpgsm->input_cb.server_fd_str, "%d", child_fds[0]);
382       snprintf (gpgsm->output_cb.server_fd_str,
383                 sizeof gpgsm->output_cb.server_fd_str, "%d", child_fds[1]);
384       snprintf (gpgsm->message_cb.server_fd_str,
385                 sizeof gpgsm->message_cb.server_fd_str, "%d", child_fds[2]);
386     }
387 #endif
388   if (err)
389     goto leave;
390
391   err = _gpgme_getenv ("DISPLAY", &dft_display);
392   if (err)
393     goto leave;
394   if (dft_display)
395     {
396       if (asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
397         {
398           free (dft_display);
399           err = gpg_error_from_syserror ();
400           goto leave;
401         }
402       free (dft_display);
403
404       err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
405                              NULL, NULL, NULL);
406       free (optstr);
407       if (err)
408         goto leave;
409     }
410
411   if (isatty (1))
412     {
413       int rc;
414
415       rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
416
417       /* Even though isatty() returns 1, ttyname_r() may fail in many
418          ways, e.g., when /dev/pts is not accessible under chroot.  */
419       if (!rc)
420         {
421           if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
422             {
423               err = gpg_error_from_syserror ();
424               goto leave;
425             }
426           err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
427                                  NULL, NULL, NULL);
428           free (optstr);
429           if (err)
430             goto leave;
431
432           err = _gpgme_getenv ("TERM", &dft_ttytype);
433           if (err)
434             goto leave;
435           if (dft_ttytype)
436             {
437               if (asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype) < 0)
438                 {
439                   free (dft_ttytype);
440                   err = gpg_error_from_syserror ();
441                   goto leave;
442                 }
443               free (dft_ttytype);
444
445               err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
446                                      NULL, NULL, NULL, NULL);
447               free (optstr);
448               if (err)
449                 goto leave;
450             }
451         }
452     }
453
454   /* Ask gpgsm to enable the audit log support.  */
455   if (!err)
456     {
457       err = assuan_transact (gpgsm->assuan_ctx, "OPTION enable-audit-log=1",
458                              NULL, NULL, NULL, NULL, NULL, NULL);
459       if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
460         err = 0; /* This is an optional feature of gpgsm.  */
461     }
462
463
464 #ifdef HAVE_W32_SYSTEM
465   /* Under Windows we need to use AllowSetForegroundWindow.  Tell
466      gpgsm to tell us when it needs it.  */
467   if (!err)
468     {
469       err = assuan_transact (gpgsm->assuan_ctx, "OPTION allow-pinentry-notify",
470                              NULL, NULL, NULL, NULL, NULL, NULL);
471       if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
472         err = 0; /* This is a new feature of gpgsm.  */
473     }
474 #endif /*HAVE_W32_SYSTEM*/
475
476 #if !USE_DESCRIPTOR_PASSING
477   if (!err
478       && (_gpgme_io_set_close_notify (gpgsm->input_cb.fd,
479                                       close_notify_handler, gpgsm)
480           || _gpgme_io_set_close_notify (gpgsm->output_cb.fd,
481                                          close_notify_handler, gpgsm)
482           || _gpgme_io_set_close_notify (gpgsm->message_cb.fd,
483                                          close_notify_handler, gpgsm)))
484     {
485       err = gpg_error (GPG_ERR_GENERAL);
486       goto leave;
487     }
488 #endif
489
490  leave:
491   /* Close the server ends of the pipes (because of this, we must use
492      the stored server_fd_str in the function start).  Our ends are
493      closed in gpgsm_release().  */
494 #if !USE_DESCRIPTOR_PASSING
495   if (gpgsm->input_cb.server_fd != -1)
496     _gpgme_io_close (gpgsm->input_cb.server_fd);
497   if (gpgsm->output_cb.server_fd != -1)
498     _gpgme_io_close (gpgsm->output_cb.server_fd);
499   if (gpgsm->message_cb.server_fd != -1)
500     _gpgme_io_close (gpgsm->message_cb.server_fd);
501 #endif
502
503   if (err)
504     gpgsm_release (gpgsm);
505   else
506     *engine = gpgsm;
507
508   return err;
509 }
510
511
512 static gpgme_error_t
513 gpgsm_set_locale (void *engine, int category, const char *value)
514 {
515   engine_gpgsm_t gpgsm = engine;
516   gpgme_error_t err;
517   char *optstr;
518   char *catstr;
519
520   /* FIXME: If value is NULL, we need to reset the option to default.
521      But we can't do this.  So we error out here.  GPGSM needs support
522      for this.  */
523   if (0)
524     ;
525 #ifdef LC_CTYPE
526   else if (category == LC_CTYPE)
527     {
528       catstr = "lc-ctype";
529       if (!value && gpgsm->lc_ctype_set)
530         return gpg_error (GPG_ERR_INV_VALUE);
531       if (value)
532         gpgsm->lc_ctype_set = 1;
533     }
534 #endif
535 #ifdef LC_MESSAGES
536   else if (category == LC_MESSAGES)
537     {
538       catstr = "lc-messages";
539       if (!value && gpgsm->lc_messages_set)
540         return gpg_error (GPG_ERR_INV_VALUE);
541       if (value)
542         gpgsm->lc_messages_set = 1;
543     }
544 #endif /* LC_MESSAGES */
545   else
546     return gpg_error (GPG_ERR_INV_VALUE);
547
548   /* FIXME: Reset value to default.  */
549   if (!value)
550     return 0;
551
552   if (asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0)
553     err = gpg_error_from_syserror ();
554   else
555     {
556       err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
557                              NULL, NULL, NULL, NULL);
558       free (optstr);
559     }
560
561   return err;
562 }
563
564
565 static gpgme_error_t
566 gpgsm_assuan_simple_command (engine_gpgsm_t gpgsm, char *cmd,
567                              engine_status_handler_t status_fnc,
568                              void *status_fnc_value)
569 {
570   assuan_context_t ctx = gpgsm->assuan_ctx;
571   gpg_error_t err, cb_err;
572   char *line;
573   size_t linelen;
574
575   err = assuan_write_line (ctx, cmd);
576   if (err)
577     return err;
578
579   cb_err = 0;
580   do
581     {
582       err = assuan_read_line (ctx, &line, &linelen);
583       if (err)
584         return err;
585
586       if (*line == '#' || !linelen)
587         continue;
588
589       if (linelen >= 2
590           && line[0] == 'O' && line[1] == 'K'
591           && (line[2] == '\0' || line[2] == ' '))
592         return cb_err;
593       else if (linelen >= 4
594           && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
595           && line[3] == ' ')
596         {
597           /* We prefer a callback generated error because that one is
598              more related to gpgme and thus probably more important
599              than the error returned by the engine.  */
600           err = cb_err? cb_err : atoi (&line[4]);
601         }
602       else if (linelen >= 2
603                && line[0] == 'S' && line[1] == ' ')
604         {
605           /* After an error from a status callback we skip all further
606              status lines.  */
607           if (!cb_err)
608             {
609               char *rest;
610               gpgme_status_code_t r;
611
612               rest = strchr (line + 2, ' ');
613               if (!rest)
614                 rest = line + linelen; /* set to an empty string */
615               else
616                 *(rest++) = 0;
617
618               r = _gpgme_parse_status (line + 2);
619               if (gpgsm->status.mon_cb && r != GPGME_STATUS_PROGRESS)
620                 {
621                   /* Note that we call the monitor even if we do
622                    * not know the status code (r < 0).  */
623                   cb_err = gpgsm->status.mon_cb (gpgsm->status.mon_cb_value,
624                                                  line + 2, rest);
625                 }
626
627               if (r >= 0 && status_fnc && !cb_err)
628                 cb_err = status_fnc (status_fnc_value, r, rest);
629             }
630         }
631       else
632         {
633           /* Invalid line or INQUIRY.  We can't do anything else than
634              to stop.  As with ERR we prefer a status callback
635              generated error code, though.  */
636           err = cb_err ? cb_err : gpg_error (GPG_ERR_GENERAL);
637         }
638     }
639   while (!err);
640
641   return err;
642 }
643
644
645 typedef enum { INPUT_FD, OUTPUT_FD, MESSAGE_FD } fd_type_t;
646
647 static void
648 gpgsm_clear_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type)
649 {
650 #if !USE_DESCRIPTOR_PASSING
651   switch (fd_type)
652     {
653     case INPUT_FD:
654       _gpgme_io_close (gpgsm->input_cb.fd);
655       break;
656     case OUTPUT_FD:
657       _gpgme_io_close (gpgsm->output_cb.fd);
658       break;
659     case MESSAGE_FD:
660       _gpgme_io_close (gpgsm->message_cb.fd);
661       break;
662     }
663 #endif
664 }
665
666 #define COMMANDLINELEN 40
667 static gpgme_error_t
668 gpgsm_set_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type, const char *opt)
669 {
670   gpg_error_t err = 0;
671   char line[COMMANDLINELEN];
672   char *which;
673   iocb_data_t *iocb_data;
674 #if USE_DESCRIPTOR_PASSING
675   int dir;
676 #endif
677
678   switch (fd_type)
679     {
680     case INPUT_FD:
681       which = "INPUT";
682       iocb_data = &gpgsm->input_cb;
683       break;
684
685     case OUTPUT_FD:
686       which = "OUTPUT";
687       iocb_data = &gpgsm->output_cb;
688       break;
689
690     case MESSAGE_FD:
691       which = "MESSAGE";
692       iocb_data = &gpgsm->message_cb;
693       break;
694
695     default:
696       return gpg_error (GPG_ERR_INV_VALUE);
697     }
698
699 #if USE_DESCRIPTOR_PASSING
700   dir = iocb_data->dir;
701   /* We try to short-cut the communication by giving GPGSM direct
702      access to the file descriptor, rather than using a pipe.  */
703   iocb_data->server_fd = _gpgme_data_get_fd (iocb_data->data);
704   if (iocb_data->server_fd < 0)
705     {
706       int fds[2];
707
708       if (_gpgme_io_pipe (fds, dir) < 0)
709         return gpg_error_from_syserror ();
710
711       iocb_data->fd = dir ? fds[0] : fds[1];
712       iocb_data->server_fd = dir ? fds[1] : fds[0];
713
714       if (_gpgme_io_set_close_notify (iocb_data->fd,
715                                       close_notify_handler, gpgsm))
716         {
717           err = gpg_error (GPG_ERR_GENERAL);
718           goto leave_set_fd;
719         }
720     }
721
722   err = assuan_sendfd (gpgsm->assuan_ctx, iocb_data->server_fd);
723   if (err)
724     goto leave_set_fd;
725
726   _gpgme_io_close (iocb_data->server_fd);
727   iocb_data->server_fd = -1;
728
729   if (opt)
730     snprintf (line, COMMANDLINELEN, "%s FD %s", which, opt);
731   else
732     snprintf (line, COMMANDLINELEN, "%s FD", which);
733 #else
734   if (opt)
735     snprintf (line, COMMANDLINELEN, "%s FD=%s %s",
736               which, iocb_data->server_fd_str, opt);
737   else
738     snprintf (line, COMMANDLINELEN, "%s FD=%s",
739               which, iocb_data->server_fd_str);
740 #endif
741
742   err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
743
744 #if USE_DESCRIPTOR_PASSING
745  leave_set_fd:
746   if (err)
747     {
748       _gpgme_io_close (iocb_data->fd);
749       iocb_data->fd = -1;
750       if (iocb_data->server_fd != -1)
751         {
752           _gpgme_io_close (iocb_data->server_fd);
753           iocb_data->server_fd = -1;
754         }
755     }
756 #endif
757
758   return err;
759 }
760
761
762 static const char *
763 map_data_enc (gpgme_data_t d)
764 {
765   switch (gpgme_data_get_encoding (d))
766     {
767     case GPGME_DATA_ENCODING_NONE:
768       break;
769     case GPGME_DATA_ENCODING_BINARY:
770       return "--binary";
771     case GPGME_DATA_ENCODING_BASE64:
772       return "--base64";
773     case GPGME_DATA_ENCODING_ARMOR:
774       return "--armor";
775     default:
776       break;
777     }
778   return NULL;
779 }
780
781
782 static gpgme_error_t
783 status_handler (void *opaque, int fd)
784 {
785   struct io_cb_data *data = (struct io_cb_data *) opaque;
786   engine_gpgsm_t gpgsm = (engine_gpgsm_t) data->handler_value;
787   gpgme_error_t err = 0;
788   char *line;
789   size_t linelen;
790
791   do
792     {
793       err = assuan_read_line (gpgsm->assuan_ctx, &line, &linelen);
794       if (err)
795         {
796           /* Try our best to terminate the connection friendly.  */
797           /*      assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
798           TRACE3 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
799                   "fd 0x%x: error from assuan (%d) getting status line : %s",
800                   fd, err, gpg_strerror (err));
801         }
802       else if (linelen >= 3
803                && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
804                && (line[3] == '\0' || line[3] == ' '))
805         {
806           if (line[3] == ' ')
807             err = atoi (&line[4]);
808           if (! err)
809             err = gpg_error (GPG_ERR_GENERAL);
810           TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
811                   "fd 0x%x: ERR line - mapped to: %s",
812                   fd, err ? gpg_strerror (err) : "ok");
813           /* Try our best to terminate the connection friendly.  */
814           /*      assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
815         }
816       else if (linelen >= 2
817                && line[0] == 'O' && line[1] == 'K'
818                && (line[2] == '\0' || line[2] == ' '))
819         {
820           if (gpgsm->status.fnc)
821             err = gpgsm->status.fnc (gpgsm->status.fnc_value,
822                                      GPGME_STATUS_EOF, "");
823
824           if (!err && gpgsm->colon.fnc && gpgsm->colon.any)
825             {
826               /* We must tell a colon function about the EOF. We do
827                  this only when we have seen any data lines.  Note
828                  that this inlined use of colon data lines will
829                  eventually be changed into using a regular data
830                  channel. */
831               gpgsm->colon.any = 0;
832               err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, NULL);
833             }
834           TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
835                   "fd 0x%x: OK line - final status: %s",
836                   fd, err ? gpg_strerror (err) : "ok");
837           _gpgme_io_close (gpgsm->status_cb.fd);
838           return err;
839         }
840       else if (linelen > 2
841                && line[0] == 'D' && line[1] == ' '
842                && gpgsm->colon.fnc)
843         {
844           /* We are using the colon handler even for plain inline data
845              - strange name for that function but for historic reasons
846              we keep it.  */
847           /* FIXME We can't use this for binary data because we
848              assume this is a string.  For the current usage of colon
849              output it is correct.  */
850           char *src = line + 2;
851           char *end = line + linelen;
852           char *dst;
853           char **aline = &gpgsm->colon.attic.line;
854           int *alinelen = &gpgsm->colon.attic.linelen;
855
856           if (gpgsm->colon.attic.linesize < *alinelen + linelen + 1)
857             {
858               char *newline = realloc (*aline, *alinelen + linelen + 1);
859               if (!newline)
860                 err = gpg_error_from_syserror ();
861               else
862                 {
863                   *aline = newline;
864                   gpgsm->colon.attic.linesize = *alinelen + linelen + 1;
865                 }
866             }
867           if (!err)
868             {
869               dst = *aline + *alinelen;
870
871               while (!err && src < end)
872                 {
873                   if (*src == '%' && src + 2 < end)
874                     {
875                       /* Handle escaped characters.  */
876                       ++src;
877                       *dst = _gpgme_hextobyte (src);
878                       (*alinelen)++;
879                       src += 2;
880                     }
881                   else
882                     {
883                       *dst = *src++;
884                       (*alinelen)++;
885                     }
886
887                   if (*dst == '\n')
888                     {
889                       /* Terminate the pending line, pass it to the colon
890                          handler and reset it.  */
891
892                       gpgsm->colon.any = 1;
893                       if (*alinelen > 1 && *(dst - 1) == '\r')
894                         dst--;
895                       *dst = '\0';
896
897                       /* FIXME How should we handle the return code?  */
898                       err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, *aline);
899                       if (!err)
900                         {
901                           dst = *aline;
902                           *alinelen = 0;
903                         }
904                     }
905                   else
906                     dst++;
907                 }
908             }
909           TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
910                   "fd 0x%x: D line; final status: %s",
911                   fd, err? gpg_strerror (err):"ok");
912         }
913       else if (linelen > 2
914                && line[0] == 'D' && line[1] == ' '
915                && gpgsm->inline_data)
916         {
917           char *src = line + 2;
918           char *end = line + linelen;
919           char *dst = src;
920           gpgme_ssize_t nwritten;
921
922           linelen = 0;
923           while (src < end)
924             {
925               if (*src == '%' && src + 2 < end)
926                 {
927                   /* Handle escaped characters.  */
928                   ++src;
929                   *dst++ = _gpgme_hextobyte (src);
930                   src += 2;
931                 }
932               else
933                 *dst++ = *src++;
934
935               linelen++;
936             }
937
938           src = line + 2;
939           while (linelen > 0)
940             {
941               nwritten = gpgme_data_write (gpgsm->inline_data, src, linelen);
942               if (!nwritten || (nwritten < 0 && errno != EINTR)
943                   || nwritten > linelen)
944                 {
945                   err = gpg_error_from_syserror ();
946                   break;
947                 }
948               src += nwritten;
949               linelen -= nwritten;
950             }
951
952           TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
953                   "fd 0x%x: D inlinedata; final status: %s",
954                   fd, err? gpg_strerror (err):"ok");
955         }
956       else if (linelen > 2
957                && line[0] == 'S' && line[1] == ' ')
958         {
959           char *rest;
960           gpgme_status_code_t r;
961
962           rest = strchr (line + 2, ' ');
963           if (!rest)
964             rest = line + linelen; /* set to an empty string */
965           else
966             *(rest++) = 0;
967
968           r = _gpgme_parse_status (line + 2);
969
970           if (r >= 0)
971             {
972               if (gpgsm->status.fnc)
973                 err = gpgsm->status.fnc (gpgsm->status.fnc_value, r, rest);
974             }
975           else
976             fprintf (stderr, "[UNKNOWN STATUS]%s %s", line + 2, rest);
977           TRACE3 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
978                   "fd 0x%x: S line (%s) - final status: %s",
979                   fd, line+2, err? gpg_strerror (err):"ok");
980         }
981       else if (linelen >= 7
982                && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
983                && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
984                && line[6] == 'E'
985                && (line[7] == '\0' || line[7] == ' '))
986         {
987           char *keyword = line+7;
988
989           while (*keyword == ' ')
990             keyword++;;
991           default_inq_cb (gpgsm, keyword);
992           assuan_write_line (gpgsm->assuan_ctx, "END");
993         }
994
995     }
996   while (!err && assuan_pending_line (gpgsm->assuan_ctx));
997
998   return err;
999 }
1000
1001
1002 static gpgme_error_t
1003 add_io_cb (engine_gpgsm_t gpgsm, iocb_data_t *iocbd, gpgme_io_cb_t handler)
1004 {
1005   gpgme_error_t err;
1006
1007   TRACE_BEG2 (DEBUG_ENGINE, "engine-gpgsm:add_io_cb", gpgsm,
1008               "fd %d, dir %d", iocbd->fd, iocbd->dir);
1009   err = (*gpgsm->io_cbs.add) (gpgsm->io_cbs.add_priv,
1010                               iocbd->fd, iocbd->dir,
1011                               handler, iocbd->data, &iocbd->tag);
1012   if (err)
1013     return TRACE_ERR (err);
1014   if (!iocbd->dir)
1015     /* FIXME Kludge around poll() problem.  */
1016     err = _gpgme_io_set_nonblocking (iocbd->fd);
1017   return TRACE_ERR (err);
1018 }
1019
1020
1021 static gpgme_error_t
1022 start (engine_gpgsm_t gpgsm, const char *command)
1023 {
1024   gpgme_error_t err;
1025   assuan_fd_t afdlist[5];
1026   int fdlist[5];
1027   int nfds;
1028   int i;
1029
1030   /* We need to know the fd used by assuan for reads.  We do this by
1031      using the assumption that the first returned fd from
1032      assuan_get_active_fds() is always this one.  */
1033   nfds = assuan_get_active_fds (gpgsm->assuan_ctx, 0 /* read fds */,
1034                                 afdlist, DIM (afdlist));
1035   if (nfds < 1)
1036     return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1037   /* For now... */
1038   for (i = 0; i < nfds; i++)
1039     fdlist[i] = (int) afdlist[i];
1040
1041   /* We "duplicate" the file descriptor, so we can close it here (we
1042      can't close fdlist[0], as that is closed by libassuan, and
1043      closing it here might cause libassuan to close some unrelated FD
1044      later).  Alternatively, we could special case status_fd and
1045      register/unregister it manually as needed, but this increases
1046      code duplication and is more complicated as we can not use the
1047      close notifications etc.  A third alternative would be to let
1048      Assuan know that we closed the FD, but that complicates the
1049      Assuan interface.  */
1050
1051   gpgsm->status_cb.fd = _gpgme_io_dup (fdlist[0]);
1052   if (gpgsm->status_cb.fd < 0)
1053     return gpg_error_from_syserror ();
1054
1055   if (_gpgme_io_set_close_notify (gpgsm->status_cb.fd,
1056                                   close_notify_handler, gpgsm))
1057     {
1058       _gpgme_io_close (gpgsm->status_cb.fd);
1059       gpgsm->status_cb.fd = -1;
1060       return gpg_error (GPG_ERR_GENERAL);
1061     }
1062
1063   err = add_io_cb (gpgsm, &gpgsm->status_cb, status_handler);
1064   if (!err && gpgsm->input_cb.fd != -1)
1065     err = add_io_cb (gpgsm, &gpgsm->input_cb, _gpgme_data_outbound_handler);
1066   if (!err && gpgsm->output_cb.fd != -1)
1067     err = add_io_cb (gpgsm, &gpgsm->output_cb, _gpgme_data_inbound_handler);
1068   if (!err && gpgsm->message_cb.fd != -1)
1069     err = add_io_cb (gpgsm, &gpgsm->message_cb, _gpgme_data_outbound_handler);
1070
1071   if (!err)
1072     err = assuan_write_line (gpgsm->assuan_ctx, command);
1073
1074   if (!err)
1075     gpgsm_io_event (gpgsm, GPGME_EVENT_START, NULL);
1076
1077   return err;
1078 }
1079
1080
1081 #if USE_DESCRIPTOR_PASSING
1082 static gpgme_error_t
1083 gpgsm_reset (void *engine)
1084 {
1085   engine_gpgsm_t gpgsm = engine;
1086
1087   /* IF we have an active connection we must send a reset because we
1088      need to reset the list of signers.  Note that RESET does not
1089      reset OPTION commands. */
1090   return (gpgsm->assuan_ctx
1091           ? gpgsm_assuan_simple_command (gpgsm, "RESET", NULL, NULL)
1092           : 0);
1093 }
1094 #endif
1095
1096
1097
1098 static gpgme_error_t
1099 gpgsm_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
1100 {
1101   engine_gpgsm_t gpgsm = engine;
1102   gpgme_error_t err;
1103
1104   if (!gpgsm)
1105     return gpg_error (GPG_ERR_INV_VALUE);
1106
1107   gpgsm->input_cb.data = ciph;
1108   err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1109   if (err)
1110     return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1111   gpgsm->output_cb.data = plain;
1112   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1113   if (err)
1114     return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1115   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1116   gpgsm->inline_data = NULL;
1117
1118   err = start (engine, "DECRYPT");
1119   return err;
1120 }
1121
1122
1123 static gpgme_error_t
1124 gpgsm_delete (void *engine, gpgme_key_t key, int allow_secret)
1125 {
1126   engine_gpgsm_t gpgsm = engine;
1127   gpgme_error_t err;
1128   char *fpr = key->subkeys ? key->subkeys->fpr : NULL;
1129   char *linep = fpr;
1130   char *line;
1131   int length = 8;       /* "DELKEYS " */
1132
1133   if (!fpr)
1134     return gpg_error (GPG_ERR_INV_VALUE);
1135
1136   while (*linep)
1137     {
1138       length++;
1139       if (*linep == '%' || *linep == ' ' || *linep == '+')
1140         length += 2;
1141       linep++;
1142     }
1143   length++;
1144
1145   line = malloc (length);
1146   if (!line)
1147     return gpg_error_from_syserror ();
1148
1149   strcpy (line, "DELKEYS ");
1150   linep = &line[8];
1151
1152   while (*fpr)
1153     {
1154       switch (*fpr)
1155         {
1156         case '%':
1157           *(linep++) = '%';
1158           *(linep++) = '2';
1159           *(linep++) = '5';
1160           break;
1161         case ' ':
1162           *(linep++) = '%';
1163           *(linep++) = '2';
1164           *(linep++) = '0';
1165           break;
1166         case '+':
1167           *(linep++) = '%';
1168           *(linep++) = '2';
1169           *(linep++) = 'B';
1170           break;
1171         default:
1172           *(linep++) = *fpr;
1173           break;
1174         }
1175       fpr++;
1176     }
1177   *linep = '\0';
1178
1179   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1180   gpgsm_clear_fd (gpgsm, INPUT_FD);
1181   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1182   gpgsm->inline_data = NULL;
1183
1184   err = start (gpgsm, line);
1185   free (line);
1186
1187   return err;
1188 }
1189
1190
1191 static gpgme_error_t
1192 set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[])
1193 {
1194   gpgme_error_t err = 0;
1195   char *line;
1196   int linelen;
1197   int invalid_recipients = 0;
1198   int i;
1199
1200   linelen = 10 + 40 + 1;        /* "RECIPIENT " + guess + '\0'.  */
1201   line = malloc (10 + 40 + 1);
1202   if (!line)
1203     return gpg_error_from_syserror ();
1204   strcpy (line, "RECIPIENT ");
1205   for (i =0; !err && recp[i]; i++)
1206     {
1207       char *fpr;
1208       int newlen;
1209
1210       if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
1211         {
1212           invalid_recipients++;
1213           continue;
1214         }
1215       fpr = recp[i]->subkeys->fpr;
1216
1217       newlen = 11 + strlen (fpr);
1218       if (linelen < newlen)
1219         {
1220           char *newline = realloc (line, newlen);
1221           if (! newline)
1222             {
1223               int saved_err = gpg_error_from_syserror ();
1224               free (line);
1225               return saved_err;
1226             }
1227           line = newline;
1228           linelen = newlen;
1229         }
1230       strcpy (&line[10], fpr);
1231
1232       err = gpgsm_assuan_simple_command (gpgsm, line, gpgsm->status.fnc,
1233                                          gpgsm->status.fnc_value);
1234       /* FIXME: This requires more work.  */
1235       if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
1236         invalid_recipients++;
1237       else if (err)
1238         {
1239           free (line);
1240           return err;
1241         }
1242     }
1243   free (line);
1244   return gpg_error (invalid_recipients
1245                     ? GPG_ERR_UNUSABLE_PUBKEY : GPG_ERR_NO_ERROR);
1246 }
1247
1248
1249 static gpgme_error_t
1250 gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
1251                gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
1252 {
1253   engine_gpgsm_t gpgsm = engine;
1254   gpgme_error_t err;
1255
1256   if (!gpgsm)
1257     return gpg_error (GPG_ERR_INV_VALUE);
1258   if (!recp)
1259     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1260
1261   if (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO)
1262     {
1263       err = gpgsm_assuan_simple_command (gpgsm,
1264                                          "OPTION no-encrypt-to", NULL, NULL);
1265       if (err)
1266         return err;
1267     }
1268
1269   gpgsm->input_cb.data = plain;
1270   err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1271   if (err)
1272     return err;
1273   gpgsm->output_cb.data = ciph;
1274   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1275                       : map_data_enc (gpgsm->output_cb.data));
1276   if (err)
1277     return err;
1278   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1279   gpgsm->inline_data = NULL;
1280
1281   err = set_recipients (gpgsm, recp);
1282
1283   if (!err)
1284     err = start (gpgsm, "ENCRYPT");
1285
1286   return err;
1287 }
1288
1289
1290 static gpgme_error_t
1291 gpgsm_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
1292               gpgme_data_t keydata, int use_armor)
1293 {
1294   engine_gpgsm_t gpgsm = engine;
1295   gpgme_error_t err = 0;
1296   char *cmd;
1297
1298   if (!gpgsm)
1299     return gpg_error (GPG_ERR_INV_VALUE);
1300
1301   if (!pattern)
1302     pattern = "";
1303
1304   cmd = malloc (7 + 9 + 9 + strlen (pattern) + 1);
1305   if (!cmd)
1306     return gpg_error_from_syserror ();
1307
1308   strcpy (cmd, "EXPORT ");
1309   if ((mode & GPGME_EXPORT_MODE_SECRET))
1310     {
1311       strcat (cmd, "--secret ");
1312       if ((mode & GPGME_EXPORT_MODE_RAW))
1313         strcat (cmd, "--raw ");
1314       else if ((mode & GPGME_EXPORT_MODE_PKCS12))
1315         strcat (cmd, "--pkcs12 ");
1316     }
1317   strcat (cmd, pattern);
1318
1319   gpgsm->output_cb.data = keydata;
1320   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1321                       : map_data_enc (gpgsm->output_cb.data));
1322   if (err)
1323     return err;
1324   gpgsm_clear_fd (gpgsm, INPUT_FD);
1325   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1326   gpgsm->inline_data = NULL;
1327
1328   err = start (gpgsm, cmd);
1329   free (cmd);
1330   return err;
1331 }
1332
1333
1334 static gpgme_error_t
1335 gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
1336                   gpgme_data_t keydata, int use_armor)
1337 {
1338   engine_gpgsm_t gpgsm = engine;
1339   gpgme_error_t err = 0;
1340   char *line;
1341   /* Length is "EXPORT " + "--secret " + "--pkcs12 " + p + '\0'.  */
1342   int length = 7 + 9 + 9 + 1;
1343   char *linep;
1344
1345   if (!gpgsm)
1346     return gpg_error (GPG_ERR_INV_VALUE);
1347
1348   if (pattern && *pattern)
1349     {
1350       const char **pat = pattern;
1351
1352       while (*pat)
1353         {
1354           const char *patlet = *pat;
1355
1356           while (*patlet)
1357             {
1358               length++;
1359               if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1360                 length += 2;
1361               patlet++;
1362             }
1363           pat++;
1364           length++;
1365         }
1366     }
1367   line = malloc (length);
1368   if (!line)
1369     return gpg_error_from_syserror ();
1370
1371   strcpy (line, "EXPORT ");
1372   if ((mode & GPGME_EXPORT_MODE_SECRET))
1373     {
1374       strcat (line, "--secret ");
1375       if ((mode & GPGME_EXPORT_MODE_RAW))
1376         strcat (line, "--raw ");
1377       else if ((mode & GPGME_EXPORT_MODE_PKCS12))
1378         strcat (line, "--pkcs12 ");
1379     }
1380   linep = &line[strlen (line)];
1381
1382   if (pattern && *pattern)
1383     {
1384       while (*pattern)
1385         {
1386           const char *patlet = *pattern;
1387
1388           while (*patlet)
1389             {
1390               switch (*patlet)
1391                 {
1392                 case '%':
1393                   *(linep++) = '%';
1394                   *(linep++) = '2';
1395                   *(linep++) = '5';
1396                   break;
1397                 case ' ':
1398                   *(linep++) = '%';
1399                   *(linep++) = '2';
1400                   *(linep++) = '0';
1401                   break;
1402                 case '+':
1403                   *(linep++) = '%';
1404                   *(linep++) = '2';
1405                   *(linep++) = 'B';
1406                   break;
1407                 default:
1408                   *(linep++) = *patlet;
1409                   break;
1410                 }
1411               patlet++;
1412             }
1413           pattern++;
1414           if (*pattern)
1415             *linep++ = ' ';
1416         }
1417     }
1418   *linep = '\0';
1419
1420   gpgsm->output_cb.data = keydata;
1421   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1422                       : map_data_enc (gpgsm->output_cb.data));
1423   if (err)
1424     return err;
1425   gpgsm_clear_fd (gpgsm, INPUT_FD);
1426   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1427   gpgsm->inline_data = NULL;
1428
1429   err = start (gpgsm, line);
1430   free (line);
1431   return err;
1432 }
1433
1434
1435 static gpgme_error_t
1436 gpgsm_genkey (void *engine, gpgme_data_t help_data, int use_armor,
1437               gpgme_data_t pubkey, gpgme_data_t seckey)
1438 {
1439   engine_gpgsm_t gpgsm = engine;
1440   gpgme_error_t err;
1441
1442   if (!gpgsm || !pubkey || seckey)
1443     return gpg_error (GPG_ERR_INV_VALUE);
1444
1445   gpgsm->input_cb.data = help_data;
1446   err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1447   if (err)
1448     return err;
1449   gpgsm->output_cb.data = pubkey;
1450   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1451                       : map_data_enc (gpgsm->output_cb.data));
1452   if (err)
1453     return err;
1454   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1455   gpgsm->inline_data = NULL;
1456
1457   err = start (gpgsm, "GENKEY");
1458   return err;
1459 }
1460
1461
1462 static gpgme_error_t
1463 gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
1464 {
1465   engine_gpgsm_t gpgsm = engine;
1466   gpgme_error_t err;
1467   gpgme_data_encoding_t dataenc;
1468   int idx;
1469
1470   if (!gpgsm)
1471     return gpg_error (GPG_ERR_INV_VALUE);
1472
1473   if (keydata && keyarray)
1474     return gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed.  */
1475
1476   dataenc = gpgme_data_get_encoding (keydata);
1477
1478   if (keyarray)
1479     {
1480       size_t buflen;
1481       char *buffer, *p;
1482
1483       /* Fist check whether the engine already features the
1484          --re-import option.  */
1485       err = gpgsm_assuan_simple_command
1486         (gpgsm, "GETINFO cmd_has_option IMPORT re-import", NULL, NULL);
1487       if (err)
1488         return gpg_error (GPG_ERR_NOT_SUPPORTED);
1489
1490       /* Create an internal data object with a list of all
1491          fingerprints.  The data object and its memory (to avoid an
1492          extra copy by gpgme_data_new_from_mem) are stored in two
1493          variables which are released by the close_notify_handler.  */
1494       for (idx=0, buflen=0; keyarray[idx]; idx++)
1495         {
1496           if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
1497               && keyarray[idx]->subkeys
1498               && keyarray[idx]->subkeys->fpr
1499               && *keyarray[idx]->subkeys->fpr)
1500             buflen += strlen (keyarray[idx]->subkeys->fpr) + 1;
1501         }
1502       /* Allocate a bufer with extra space for the trailing Nul
1503          introduced by the use of stpcpy.  */
1504       buffer = malloc (buflen+1);
1505       if (!buffer)
1506         return gpg_error_from_syserror ();
1507       for (idx=0, p = buffer; keyarray[idx]; idx++)
1508         {
1509           if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
1510               && keyarray[idx]->subkeys
1511               && keyarray[idx]->subkeys->fpr
1512               && *keyarray[idx]->subkeys->fpr)
1513             p = stpcpy (stpcpy (p, keyarray[idx]->subkeys->fpr), "\n");
1514         }
1515
1516       err = gpgme_data_new_from_mem (&gpgsm->input_helper_data,
1517                                      buffer, buflen, 0);
1518       if (err)
1519         {
1520           free (buffer);
1521           return err;
1522         }
1523       gpgsm->input_helper_memory = buffer;
1524
1525       gpgsm->input_cb.data = gpgsm->input_helper_data;
1526       err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1527       if (err)
1528         {
1529           gpgme_data_release (gpgsm->input_helper_data);
1530           gpgsm->input_helper_data = NULL;
1531           free (gpgsm->input_helper_memory);
1532           gpgsm->input_helper_memory = NULL;
1533           return err;
1534         }
1535       gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1536       gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1537       gpgsm->inline_data = NULL;
1538
1539       return start (gpgsm, "IMPORT --re-import");
1540     }
1541   else if (dataenc == GPGME_DATA_ENCODING_URL
1542            || dataenc == GPGME_DATA_ENCODING_URL0
1543            || dataenc == GPGME_DATA_ENCODING_URLESC)
1544     {
1545       return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1546     }
1547   else
1548     {
1549       gpgsm->input_cb.data = keydata;
1550       err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1551       if (err)
1552         return err;
1553       gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1554       gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1555       gpgsm->inline_data = NULL;
1556
1557       return start (gpgsm, "IMPORT");
1558     }
1559 }
1560
1561
1562 static gpgme_error_t
1563 gpgsm_keylist (void *engine, const char *pattern, int secret_only,
1564                gpgme_keylist_mode_t mode, int engine_flags)
1565 {
1566   engine_gpgsm_t gpgsm = engine;
1567   char *line;
1568   gpgme_error_t err;
1569   int list_mode = 0;
1570
1571   if (mode & GPGME_KEYLIST_MODE_LOCAL)
1572     list_mode |= 1;
1573   if (mode & GPGME_KEYLIST_MODE_EXTERN)
1574     list_mode |= 2;
1575
1576   if (!pattern)
1577     pattern = "";
1578
1579   /* Hack to make sure that the agent is started.  Only if the agent
1580      has been started an application may connect to the agent via
1581      GPGME_PROTOCOL_ASSUAN - for example to look for smartcards.  We
1582      do this only if a secret key listing has been requested.  In
1583      general this is not needed because a secret key listing starts
1584      the agent.  However on a fresh installation no public keys are
1585      available and thus there is no need for gpgsm to ask the agent
1586      whether a secret key exists for the public key.  */
1587   if (secret_only || (mode & GPGME_KEYLIST_MODE_WITH_SECRET))
1588     gpgsm_assuan_simple_command (gpgsm, "GETINFO agent-check", NULL, NULL);
1589
1590   /* Always send list-mode option because RESET does not reset it.  */
1591   if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1592     return gpg_error_from_syserror ();
1593   err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
1594   free (line);
1595   if (err)
1596     return err;
1597
1598
1599   /* Always send key validation because RESET does not reset it.  */
1600
1601   /* Use the validation mode if requested.  We don't check for an error
1602      yet because this is a pretty fresh gpgsm features. */
1603   gpgsm_assuan_simple_command (gpgsm,
1604                                (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1605                                "OPTION with-validation=1":
1606                                "OPTION with-validation=0" ,
1607                                NULL, NULL);
1608   /* Include the ephemeral keys if requested.  We don't check for an error
1609      yet because this is a pretty fresh gpgsm features. */
1610   gpgsm_assuan_simple_command (gpgsm,
1611                                (mode & GPGME_KEYLIST_MODE_EPHEMERAL)?
1612                                "OPTION with-ephemeral-keys=1":
1613                                "OPTION with-ephemeral-keys=0" ,
1614                                NULL, NULL);
1615   gpgsm_assuan_simple_command (gpgsm,
1616                                (mode & GPGME_KEYLIST_MODE_WITH_SECRET)?
1617                                "OPTION with-secret=1":
1618                                "OPTION with-secret=0" ,
1619                                NULL, NULL);
1620   gpgsm_assuan_simple_command (gpgsm,
1621                                (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)?
1622                                "OPTION offline=1":
1623                                "OPTION offline=0" ,
1624                                NULL, NULL);
1625
1626
1627   /* Length is "LISTSECRETKEYS " + p + '\0'.  */
1628   line = malloc (15 + strlen (pattern) + 1);
1629   if (!line)
1630     return gpg_error_from_syserror ();
1631   if (secret_only)
1632     {
1633       strcpy (line, "LISTSECRETKEYS ");
1634       strcpy (&line[15], pattern);
1635     }
1636   else
1637     {
1638       strcpy (line, "LISTKEYS ");
1639       strcpy (&line[9], pattern);
1640     }
1641
1642   gpgsm_clear_fd (gpgsm, INPUT_FD);
1643   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1644   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1645   gpgsm->inline_data = NULL;
1646
1647   err = start (gpgsm, line);
1648   free (line);
1649   return err;
1650 }
1651
1652
1653 static gpgme_error_t
1654 gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
1655                    int reserved, gpgme_keylist_mode_t mode, int engine_flags)
1656 {
1657   engine_gpgsm_t gpgsm = engine;
1658   char *line;
1659   gpgme_error_t err;
1660   /* Length is "LISTSECRETKEYS " + p + '\0'.  */
1661   int length = 15 + 1;
1662   char *linep;
1663   int any_pattern = 0;
1664   int list_mode = 0;
1665
1666   if (reserved)
1667     return gpg_error (GPG_ERR_INV_VALUE);
1668
1669   if (mode & GPGME_KEYLIST_MODE_LOCAL)
1670     list_mode |= 1;
1671   if (mode & GPGME_KEYLIST_MODE_EXTERN)
1672     list_mode |= 2;
1673
1674   /* Always send list-mode option because RESET does not reset it.  */
1675   if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1676     return gpg_error_from_syserror ();
1677   err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
1678   free (line);
1679   if (err)
1680     return err;
1681
1682   /* Always send key validation because RESET does not reset it.  */
1683   /* Use the validation mode if required.  We don't check for an error
1684      yet because this is a pretty fresh gpgsm features. */
1685   gpgsm_assuan_simple_command (gpgsm,
1686                                (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1687                                "OPTION with-validation=1":
1688                                "OPTION with-validation=0" ,
1689                                NULL, NULL);
1690   gpgsm_assuan_simple_command (gpgsm,
1691                                (mode & GPGME_KEYLIST_MODE_WITH_SECRET)?
1692                                "OPTION with-secret=1":
1693                                "OPTION with-secret=0" ,
1694                                NULL, NULL);
1695   gpgsm_assuan_simple_command (gpgsm,
1696                                (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)?
1697                                "OPTION offline=1":
1698                                "OPTION offline=0" ,
1699                                NULL, NULL);
1700
1701   if (pattern && *pattern)
1702     {
1703       const char **pat = pattern;
1704
1705       while (*pat)
1706         {
1707           const char *patlet = *pat;
1708
1709           while (*patlet)
1710             {
1711               length++;
1712               if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1713                 length += 2;
1714               patlet++;
1715             }
1716           pat++;
1717           length++;
1718         }
1719     }
1720   line = malloc (length);
1721   if (!line)
1722     return gpg_error_from_syserror ();
1723   if (secret_only)
1724     {
1725       strcpy (line, "LISTSECRETKEYS ");
1726       linep = &line[15];
1727     }
1728   else
1729     {
1730       strcpy (line, "LISTKEYS ");
1731       linep = &line[9];
1732     }
1733
1734   if (pattern && *pattern)
1735     {
1736       while (*pattern)
1737         {
1738           const char *patlet = *pattern;
1739
1740           while (*patlet)
1741             {
1742               switch (*patlet)
1743                 {
1744                 case '%':
1745                   *(linep++) = '%';
1746                   *(linep++) = '2';
1747                   *(linep++) = '5';
1748                   break;
1749                 case ' ':
1750                   *(linep++) = '%';
1751                   *(linep++) = '2';
1752                   *(linep++) = '0';
1753                   break;
1754                 case '+':
1755                   *(linep++) = '%';
1756                   *(linep++) = '2';
1757                   *(linep++) = 'B';
1758                   break;
1759                 default:
1760                   *(linep++) = *patlet;
1761                   break;
1762                 }
1763               patlet++;
1764             }
1765           any_pattern = 1;
1766           *linep++ = ' ';
1767           pattern++;
1768         }
1769     }
1770   if (any_pattern)
1771     linep--;
1772   *linep = '\0';
1773
1774   gpgsm_clear_fd (gpgsm, INPUT_FD);
1775   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1776   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1777   gpgsm->inline_data = NULL;
1778
1779   err = start (gpgsm, line);
1780   free (line);
1781   return err;
1782 }
1783
1784
1785 static gpgme_error_t
1786 gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
1787             gpgme_sig_mode_t mode, int use_armor, int use_textmode,
1788             int include_certs, gpgme_ctx_t ctx /* FIXME */)
1789 {
1790   engine_gpgsm_t gpgsm = engine;
1791   gpgme_error_t err;
1792   char *assuan_cmd;
1793   int i;
1794   gpgme_key_t key;
1795
1796   if (!gpgsm)
1797     return gpg_error (GPG_ERR_INV_VALUE);
1798
1799   /* FIXME: This does not work as RESET does not reset it so we can't
1800      revert back to default.  */
1801   if (include_certs != GPGME_INCLUDE_CERTS_DEFAULT)
1802     {
1803       /* FIXME: Make sure that if we run multiple operations, that we
1804          can reset any previously set value in case the default is
1805          requested.  */
1806
1807       if (asprintf (&assuan_cmd, "OPTION include-certs %i", include_certs) < 0)
1808         return gpg_error_from_syserror ();
1809       err = gpgsm_assuan_simple_command (gpgsm, assuan_cmd, NULL, NULL);
1810       free (assuan_cmd);
1811       if (err)
1812         return err;
1813     }
1814
1815   for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1816     {
1817       const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1818       if (s && strlen (s) < 80)
1819         {
1820           char buf[100];
1821
1822           strcpy (stpcpy (buf, "SIGNER "), s);
1823           err = gpgsm_assuan_simple_command (gpgsm, buf,
1824                                              gpgsm->status.fnc,
1825                                              gpgsm->status.fnc_value);
1826         }
1827       else
1828         err = gpg_error (GPG_ERR_INV_VALUE);
1829       gpgme_key_unref (key);
1830       if (err)
1831         return err;
1832     }
1833
1834   gpgsm->input_cb.data = in;
1835   err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1836   if (err)
1837     return err;
1838   gpgsm->output_cb.data = out;
1839   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1840                       : map_data_enc (gpgsm->output_cb.data));
1841   if (err)
1842     return err;
1843   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1844   gpgsm->inline_data = NULL;
1845
1846   err = start (gpgsm, mode == GPGME_SIG_MODE_DETACH
1847                ? "SIGN --detached" : "SIGN");
1848   return err;
1849 }
1850
1851
1852 static gpgme_error_t
1853 gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
1854               gpgme_data_t plaintext)
1855 {
1856   engine_gpgsm_t gpgsm = engine;
1857   gpgme_error_t err;
1858
1859   if (!gpgsm)
1860     return gpg_error (GPG_ERR_INV_VALUE);
1861
1862   gpgsm->input_cb.data = sig;
1863   err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1864   if (err)
1865     return err;
1866   if (plaintext)
1867     {
1868       /* Normal or cleartext signature.  */
1869       gpgsm->output_cb.data = plaintext;
1870       err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1871       gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1872     }
1873   else
1874     {
1875       /* Detached signature.  */
1876       gpgsm->message_cb.data = signed_text;
1877       err = gpgsm_set_fd (gpgsm, MESSAGE_FD, 0);
1878       gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1879     }
1880   gpgsm->inline_data = NULL;
1881
1882   if (!err)
1883     err = start (gpgsm, "VERIFY");
1884
1885   return err;
1886 }
1887
1888
1889 /* Send the GETAUDITLOG command.  The result is saved to a gpgme data
1890    object.  */
1891 static gpgme_error_t
1892 gpgsm_getauditlog (void *engine, gpgme_data_t output, unsigned int flags)
1893 {
1894   engine_gpgsm_t gpgsm = engine;
1895   gpgme_error_t err = 0;
1896
1897   if (!gpgsm || !output)
1898     return gpg_error (GPG_ERR_INV_VALUE);
1899
1900 #if USE_DESCRIPTOR_PASSING
1901   gpgsm->output_cb.data = output;
1902   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1903   if (err)
1904     return err;
1905
1906   gpgsm_clear_fd (gpgsm, INPUT_FD);
1907   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1908   gpgsm->inline_data = NULL;
1909 # define CMD  "GETAUDITLOG"
1910 #else
1911   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1912   gpgsm_clear_fd (gpgsm, INPUT_FD);
1913   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1914   gpgsm->inline_data = output;
1915 # define CMD  "GETAUDITLOG --data"
1916 #endif
1917
1918   err = start (gpgsm, (flags & GPGME_AUDITLOG_HTML)? CMD " --html" : CMD);
1919
1920   return err;
1921 }
1922
1923
1924 /* This sets a status callback for monitoring status lines before they
1925  * are passed to a caller set handler.  */
1926 static void
1927 gpgsm_set_status_cb (void *engine, gpgme_status_cb_t cb, void *cb_value)
1928 {
1929   engine_gpgsm_t gpgsm = engine;
1930
1931   gpgsm->status.mon_cb = cb;
1932   gpgsm->status.mon_cb_value = cb_value;
1933 }
1934
1935
1936 static void
1937 gpgsm_set_status_handler (void *engine, engine_status_handler_t fnc,
1938                           void *fnc_value)
1939 {
1940   engine_gpgsm_t gpgsm = engine;
1941
1942   gpgsm->status.fnc = fnc;
1943   gpgsm->status.fnc_value = fnc_value;
1944 }
1945
1946
1947 static gpgme_error_t
1948 gpgsm_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
1949                               void *fnc_value)
1950 {
1951   engine_gpgsm_t gpgsm = engine;
1952
1953   gpgsm->colon.fnc = fnc;
1954   gpgsm->colon.fnc_value = fnc_value;
1955   gpgsm->colon.any = 0;
1956   return 0;
1957 }
1958
1959
1960 static void
1961 gpgsm_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
1962 {
1963   engine_gpgsm_t gpgsm = engine;
1964   gpgsm->io_cbs = *io_cbs;
1965 }
1966
1967
1968 static void
1969 gpgsm_io_event (void *engine, gpgme_event_io_t type, void *type_data)
1970 {
1971   engine_gpgsm_t gpgsm = engine;
1972
1973   TRACE3 (DEBUG_ENGINE, "gpgme:gpgsm_io_event", gpgsm,
1974           "event %p, type %d, type_data %p",
1975           gpgsm->io_cbs.event, type, type_data);
1976   if (gpgsm->io_cbs.event)
1977     (*gpgsm->io_cbs.event) (gpgsm->io_cbs.event_priv, type, type_data);
1978 }
1979
1980
1981 static gpgme_error_t
1982 gpgsm_passwd (void *engine, gpgme_key_t key, unsigned int flags)
1983 {
1984   engine_gpgsm_t gpgsm = engine;
1985   gpgme_error_t err;
1986   char *line;
1987
1988   if (!key || !key->subkeys || !key->subkeys->fpr)
1989     return gpg_error (GPG_ERR_INV_CERT_OBJ);
1990
1991   if (asprintf (&line, "PASSWD -- %s", key->subkeys->fpr) < 0)
1992     return gpg_error_from_syserror ();
1993
1994   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1995   gpgsm_clear_fd (gpgsm, INPUT_FD);
1996   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1997   gpgsm->inline_data = NULL;
1998
1999   err = start (gpgsm, line);
2000   free (line);
2001
2002   return err;
2003 }
2004
2005
2006
2007 struct engine_ops _gpgme_engine_ops_gpgsm =
2008   {
2009     /* Static functions.  */
2010     _gpgme_get_default_gpgsm_name,
2011     NULL,
2012     gpgsm_get_version,
2013     gpgsm_get_req_version,
2014     gpgsm_new,
2015
2016     /* Member functions.  */
2017     gpgsm_release,
2018 #if USE_DESCRIPTOR_PASSING
2019     gpgsm_reset,
2020 #else
2021     NULL,                       /* reset */
2022 #endif
2023     gpgsm_set_status_cb,
2024     gpgsm_set_status_handler,
2025     NULL,               /* set_command_handler */
2026     gpgsm_set_colon_line_handler,
2027     gpgsm_set_locale,
2028     NULL,               /* set_protocol */
2029     gpgsm_decrypt,
2030     gpgsm_decrypt,
2031     gpgsm_delete,       /* decrypt_verify */
2032     NULL,               /* edit */
2033     gpgsm_encrypt,
2034     NULL,               /* encrypt_sign */
2035     gpgsm_export,
2036     gpgsm_export_ext,
2037     gpgsm_genkey,
2038     gpgsm_import,
2039     gpgsm_keylist,
2040     gpgsm_keylist_ext,
2041     gpgsm_sign,
2042     NULL,               /* trustlist */
2043     gpgsm_verify,
2044     gpgsm_getauditlog,
2045     NULL,               /* opassuan_transact */
2046     NULL,               /* conf_load */
2047     NULL,               /* conf_save */
2048     gpgsm_set_io_cbs,
2049     gpgsm_io_event,
2050     gpgsm_cancel,
2051     NULL,               /* cancel_op */
2052     gpgsm_passwd,
2053     NULL,               /* set_pinentry_mode */
2054     NULL                /* opspawn */
2055   };