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