core: Cleanup gpgme_key_unref frees
[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,
1124                int export_session_key, const char *override_session_key)
1125 {
1126   engine_gpgsm_t gpgsm = engine;
1127   gpgme_error_t err;
1128
1129   /* gpgsm is not capable of exporting session keys right now, so we
1130    * will ignore this if requested. */
1131   (void)export_session_key;
1132   (void)override_session_key;
1133
1134   if (!gpgsm)
1135     return gpg_error (GPG_ERR_INV_VALUE);
1136
1137   gpgsm->input_cb.data = ciph;
1138   err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1139   if (err)
1140     return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1141   gpgsm->output_cb.data = plain;
1142   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1143   if (err)
1144     return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1145   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1146   gpgsm->inline_data = NULL;
1147
1148   err = start (engine, "DECRYPT");
1149   return err;
1150 }
1151
1152
1153 static gpgme_error_t
1154 gpgsm_delete (void *engine, gpgme_key_t key, int allow_secret)
1155 {
1156   engine_gpgsm_t gpgsm = engine;
1157   gpgme_error_t err;
1158   char *fpr = key->subkeys ? key->subkeys->fpr : NULL;
1159   char *linep = fpr;
1160   char *line;
1161   int length = 8;       /* "DELKEYS " */
1162
1163   (void)allow_secret;
1164
1165   if (!fpr)
1166     return gpg_error (GPG_ERR_INV_VALUE);
1167
1168   while (*linep)
1169     {
1170       length++;
1171       if (*linep == '%' || *linep == ' ' || *linep == '+')
1172         length += 2;
1173       linep++;
1174     }
1175   length++;
1176
1177   line = malloc (length);
1178   if (!line)
1179     return gpg_error_from_syserror ();
1180
1181   strcpy (line, "DELKEYS ");
1182   linep = &line[8];
1183
1184   while (*fpr)
1185     {
1186       switch (*fpr)
1187         {
1188         case '%':
1189           *(linep++) = '%';
1190           *(linep++) = '2';
1191           *(linep++) = '5';
1192           break;
1193         case ' ':
1194           *(linep++) = '%';
1195           *(linep++) = '2';
1196           *(linep++) = '0';
1197           break;
1198         case '+':
1199           *(linep++) = '%';
1200           *(linep++) = '2';
1201           *(linep++) = 'B';
1202           break;
1203         default:
1204           *(linep++) = *fpr;
1205           break;
1206         }
1207       fpr++;
1208     }
1209   *linep = '\0';
1210
1211   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1212   gpgsm_clear_fd (gpgsm, INPUT_FD);
1213   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1214   gpgsm->inline_data = NULL;
1215
1216   err = start (gpgsm, line);
1217   free (line);
1218
1219   return err;
1220 }
1221
1222
1223 static gpgme_error_t
1224 set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[])
1225 {
1226   gpgme_error_t err = 0;
1227   char *line;
1228   int linelen;
1229   int invalid_recipients = 0;
1230   int i;
1231
1232   linelen = 10 + 40 + 1;        /* "RECIPIENT " + guess + '\0'.  */
1233   line = malloc (10 + 40 + 1);
1234   if (!line)
1235     return gpg_error_from_syserror ();
1236   strcpy (line, "RECIPIENT ");
1237   for (i =0; !err && recp[i]; i++)
1238     {
1239       char *fpr;
1240       int newlen;
1241
1242       if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
1243         {
1244           invalid_recipients++;
1245           continue;
1246         }
1247       fpr = recp[i]->subkeys->fpr;
1248
1249       newlen = 11 + strlen (fpr);
1250       if (linelen < newlen)
1251         {
1252           char *newline = realloc (line, newlen);
1253           if (! newline)
1254             {
1255               int saved_err = gpg_error_from_syserror ();
1256               free (line);
1257               return saved_err;
1258             }
1259           line = newline;
1260           linelen = newlen;
1261         }
1262       strcpy (&line[10], fpr);
1263
1264       err = gpgsm_assuan_simple_command (gpgsm, line, gpgsm->status.fnc,
1265                                          gpgsm->status.fnc_value);
1266       /* FIXME: This requires more work.  */
1267       if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
1268         invalid_recipients++;
1269       else if (err)
1270         {
1271           free (line);
1272           return err;
1273         }
1274     }
1275   free (line);
1276   return gpg_error (invalid_recipients
1277                     ? GPG_ERR_UNUSABLE_PUBKEY : GPG_ERR_NO_ERROR);
1278 }
1279
1280
1281 static gpgme_error_t
1282 gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
1283                gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
1284 {
1285   engine_gpgsm_t gpgsm = engine;
1286   gpgme_error_t err;
1287
1288   if (!gpgsm)
1289     return gpg_error (GPG_ERR_INV_VALUE);
1290   if (!recp)
1291     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1292
1293   if (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO)
1294     {
1295       err = gpgsm_assuan_simple_command (gpgsm,
1296                                          "OPTION no-encrypt-to", NULL, NULL);
1297       if (err)
1298         return err;
1299     }
1300
1301   gpgsm->input_cb.data = plain;
1302   err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1303   if (err)
1304     return err;
1305   gpgsm->output_cb.data = ciph;
1306   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1307                       : map_data_enc (gpgsm->output_cb.data));
1308   if (err)
1309     return err;
1310   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1311   gpgsm->inline_data = NULL;
1312
1313   err = set_recipients (gpgsm, recp);
1314
1315   if (!err)
1316     err = start (gpgsm, "ENCRYPT");
1317
1318   return err;
1319 }
1320
1321
1322 static gpgme_error_t
1323 gpgsm_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
1324               gpgme_data_t keydata, int use_armor)
1325 {
1326   engine_gpgsm_t gpgsm = engine;
1327   gpgme_error_t err = 0;
1328   char *cmd;
1329
1330   if (!gpgsm)
1331     return gpg_error (GPG_ERR_INV_VALUE);
1332
1333   if (!pattern)
1334     pattern = "";
1335
1336   cmd = malloc (7 + 9 + 9 + strlen (pattern) + 1);
1337   if (!cmd)
1338     return gpg_error_from_syserror ();
1339
1340   strcpy (cmd, "EXPORT ");
1341   if ((mode & GPGME_EXPORT_MODE_SECRET))
1342     {
1343       strcat (cmd, "--secret ");
1344       if ((mode & GPGME_EXPORT_MODE_RAW))
1345         strcat (cmd, "--raw ");
1346       else if ((mode & GPGME_EXPORT_MODE_PKCS12))
1347         strcat (cmd, "--pkcs12 ");
1348     }
1349   strcat (cmd, pattern);
1350
1351   gpgsm->output_cb.data = keydata;
1352   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1353                       : map_data_enc (gpgsm->output_cb.data));
1354   if (err)
1355     return err;
1356   gpgsm_clear_fd (gpgsm, INPUT_FD);
1357   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1358   gpgsm->inline_data = NULL;
1359
1360   err = start (gpgsm, cmd);
1361   free (cmd);
1362   return err;
1363 }
1364
1365
1366 static gpgme_error_t
1367 gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
1368                   gpgme_data_t keydata, int use_armor)
1369 {
1370   engine_gpgsm_t gpgsm = engine;
1371   gpgme_error_t err = 0;
1372   char *line;
1373   /* Length is "EXPORT " + "--secret " + "--pkcs12 " + p + '\0'.  */
1374   int length = 7 + 9 + 9 + 1;
1375   char *linep;
1376
1377   if (!gpgsm)
1378     return gpg_error (GPG_ERR_INV_VALUE);
1379
1380   if (pattern && *pattern)
1381     {
1382       const char **pat = pattern;
1383
1384       while (*pat)
1385         {
1386           const char *patlet = *pat;
1387
1388           while (*patlet)
1389             {
1390               length++;
1391               if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1392                 length += 2;
1393               patlet++;
1394             }
1395           pat++;
1396           length++;
1397         }
1398     }
1399   line = malloc (length);
1400   if (!line)
1401     return gpg_error_from_syserror ();
1402
1403   strcpy (line, "EXPORT ");
1404   if ((mode & GPGME_EXPORT_MODE_SECRET))
1405     {
1406       strcat (line, "--secret ");
1407       if ((mode & GPGME_EXPORT_MODE_RAW))
1408         strcat (line, "--raw ");
1409       else if ((mode & GPGME_EXPORT_MODE_PKCS12))
1410         strcat (line, "--pkcs12 ");
1411     }
1412   linep = &line[strlen (line)];
1413
1414   if (pattern && *pattern)
1415     {
1416       while (*pattern)
1417         {
1418           const char *patlet = *pattern;
1419
1420           while (*patlet)
1421             {
1422               switch (*patlet)
1423                 {
1424                 case '%':
1425                   *(linep++) = '%';
1426                   *(linep++) = '2';
1427                   *(linep++) = '5';
1428                   break;
1429                 case ' ':
1430                   *(linep++) = '%';
1431                   *(linep++) = '2';
1432                   *(linep++) = '0';
1433                   break;
1434                 case '+':
1435                   *(linep++) = '%';
1436                   *(linep++) = '2';
1437                   *(linep++) = 'B';
1438                   break;
1439                 default:
1440                   *(linep++) = *patlet;
1441                   break;
1442                 }
1443               patlet++;
1444             }
1445           pattern++;
1446           if (*pattern)
1447             *linep++ = ' ';
1448         }
1449     }
1450   *linep = '\0';
1451
1452   gpgsm->output_cb.data = keydata;
1453   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1454                       : map_data_enc (gpgsm->output_cb.data));
1455   if (err)
1456     return err;
1457   gpgsm_clear_fd (gpgsm, INPUT_FD);
1458   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1459   gpgsm->inline_data = NULL;
1460
1461   err = start (gpgsm, line);
1462   free (line);
1463   return err;
1464 }
1465
1466
1467 static gpgme_error_t
1468 gpgsm_genkey (void *engine,
1469               const char *userid, const char *algo,
1470               unsigned long reserved, unsigned long expires,
1471               gpgme_key_t key, unsigned int flags,
1472               gpgme_data_t help_data, unsigned int extraflags,
1473               gpgme_data_t pubkey, gpgme_data_t seckey)
1474 {
1475   engine_gpgsm_t gpgsm = engine;
1476   gpgme_error_t err;
1477
1478   (void)reserved;
1479
1480   if (!gpgsm)
1481     return gpg_error (GPG_ERR_INV_VALUE);
1482
1483   if (help_data)
1484     {
1485       if (!pubkey || seckey)
1486         return gpg_error (GPG_ERR_INV_VALUE);
1487
1488       gpgsm->input_cb.data = help_data;
1489       err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1490       if (err)
1491         return err;
1492       gpgsm->output_cb.data = pubkey;
1493       err = gpgsm_set_fd (gpgsm, OUTPUT_FD,
1494                           (extraflags & GENKEY_EXTRAFLAG_ARMOR)? "--armor"
1495                           : map_data_enc (gpgsm->output_cb.data));
1496       if (err)
1497         return err;
1498       gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1499       gpgsm->inline_data = NULL;
1500
1501       err = start (gpgsm, "GENKEY");
1502       return err;
1503     }
1504
1505   (void)userid;
1506   (void)algo;
1507   (void)expires;
1508   (void)key;
1509   (void)flags;
1510
1511   /* The new interface has not yet been implemented,  */
1512   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1513 }
1514
1515
1516 static gpgme_error_t
1517 gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
1518 {
1519   engine_gpgsm_t gpgsm = engine;
1520   gpgme_error_t err;
1521   gpgme_data_encoding_t dataenc;
1522   int idx;
1523
1524   if (!gpgsm)
1525     return gpg_error (GPG_ERR_INV_VALUE);
1526
1527   if (keydata && keyarray)
1528     return gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed.  */
1529
1530   dataenc = gpgme_data_get_encoding (keydata);
1531
1532   if (keyarray)
1533     {
1534       size_t buflen;
1535       char *buffer, *p;
1536
1537       /* Fist check whether the engine already features the
1538          --re-import option.  */
1539       err = gpgsm_assuan_simple_command
1540         (gpgsm, "GETINFO cmd_has_option IMPORT re-import", NULL, NULL);
1541       if (err)
1542         return gpg_error (GPG_ERR_NOT_SUPPORTED);
1543
1544       /* Create an internal data object with a list of all
1545          fingerprints.  The data object and its memory (to avoid an
1546          extra copy by gpgme_data_new_from_mem) are stored in two
1547          variables which are released by the close_notify_handler.  */
1548       for (idx=0, buflen=0; keyarray[idx]; idx++)
1549         {
1550           if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
1551               && keyarray[idx]->subkeys
1552               && keyarray[idx]->subkeys->fpr
1553               && *keyarray[idx]->subkeys->fpr)
1554             buflen += strlen (keyarray[idx]->subkeys->fpr) + 1;
1555         }
1556       /* Allocate a bufer with extra space for the trailing Nul
1557          introduced by the use of stpcpy.  */
1558       buffer = malloc (buflen+1);
1559       if (!buffer)
1560         return gpg_error_from_syserror ();
1561       for (idx=0, p = buffer; keyarray[idx]; idx++)
1562         {
1563           if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
1564               && keyarray[idx]->subkeys
1565               && keyarray[idx]->subkeys->fpr
1566               && *keyarray[idx]->subkeys->fpr)
1567             p = stpcpy (stpcpy (p, keyarray[idx]->subkeys->fpr), "\n");
1568         }
1569
1570       err = gpgme_data_new_from_mem (&gpgsm->input_helper_data,
1571                                      buffer, buflen, 0);
1572       if (err)
1573         {
1574           free (buffer);
1575           return err;
1576         }
1577       gpgsm->input_helper_memory = buffer;
1578
1579       gpgsm->input_cb.data = gpgsm->input_helper_data;
1580       err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1581       if (err)
1582         {
1583           gpgme_data_release (gpgsm->input_helper_data);
1584           gpgsm->input_helper_data = NULL;
1585           free (gpgsm->input_helper_memory);
1586           gpgsm->input_helper_memory = NULL;
1587           return err;
1588         }
1589       gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1590       gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1591       gpgsm->inline_data = NULL;
1592
1593       return start (gpgsm, "IMPORT --re-import");
1594     }
1595   else if (dataenc == GPGME_DATA_ENCODING_URL
1596            || dataenc == GPGME_DATA_ENCODING_URL0
1597            || dataenc == GPGME_DATA_ENCODING_URLESC)
1598     {
1599       return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1600     }
1601   else
1602     {
1603       gpgsm->input_cb.data = keydata;
1604       err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1605       if (err)
1606         return err;
1607       gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1608       gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1609       gpgsm->inline_data = NULL;
1610
1611       return start (gpgsm, "IMPORT");
1612     }
1613 }
1614
1615
1616 static gpgme_error_t
1617 gpgsm_keylist (void *engine, const char *pattern, int secret_only,
1618                gpgme_keylist_mode_t mode, int engine_flags)
1619 {
1620   engine_gpgsm_t gpgsm = engine;
1621   char *line;
1622   gpgme_error_t err;
1623   int list_mode = 0;
1624
1625   if (mode & GPGME_KEYLIST_MODE_LOCAL)
1626     list_mode |= 1;
1627   if (mode & GPGME_KEYLIST_MODE_EXTERN)
1628     list_mode |= 2;
1629
1630   if (!pattern)
1631     pattern = "";
1632
1633   /* Hack to make sure that the agent is started.  Only if the agent
1634      has been started an application may connect to the agent via
1635      GPGME_PROTOCOL_ASSUAN - for example to look for smartcards.  We
1636      do this only if a secret key listing has been requested.  In
1637      general this is not needed because a secret key listing starts
1638      the agent.  However on a fresh installation no public keys are
1639      available and thus there is no need for gpgsm to ask the agent
1640      whether a secret key exists for the public key.  */
1641   if (secret_only || (mode & GPGME_KEYLIST_MODE_WITH_SECRET))
1642     gpgsm_assuan_simple_command (gpgsm, "GETINFO agent-check", NULL, NULL);
1643
1644   /* Always send list-mode option because RESET does not reset it.  */
1645   if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1646     return gpg_error_from_syserror ();
1647   err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
1648   free (line);
1649   if (err)
1650     return err;
1651
1652
1653   /* Always send key validation because RESET does not reset it.  */
1654
1655   /* Use the validation mode if requested.  We don't check for an error
1656      yet because this is a pretty fresh gpgsm features. */
1657   gpgsm_assuan_simple_command (gpgsm,
1658                                (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1659                                "OPTION with-validation=1":
1660                                "OPTION with-validation=0" ,
1661                                NULL, NULL);
1662   /* Include the ephemeral keys if requested.  We don't check for an error
1663      yet because this is a pretty fresh gpgsm features. */
1664   gpgsm_assuan_simple_command (gpgsm,
1665                                (mode & GPGME_KEYLIST_MODE_EPHEMERAL)?
1666                                "OPTION with-ephemeral-keys=1":
1667                                "OPTION with-ephemeral-keys=0" ,
1668                                NULL, NULL);
1669   gpgsm_assuan_simple_command (gpgsm,
1670                                (mode & GPGME_KEYLIST_MODE_WITH_SECRET)?
1671                                "OPTION with-secret=1":
1672                                "OPTION with-secret=0" ,
1673                                NULL, NULL);
1674   gpgsm_assuan_simple_command (gpgsm,
1675                                (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)?
1676                                "OPTION offline=1":
1677                                "OPTION offline=0" ,
1678                                NULL, NULL);
1679
1680
1681   /* Length is "LISTSECRETKEYS " + p + '\0'.  */
1682   line = malloc (15 + strlen (pattern) + 1);
1683   if (!line)
1684     return gpg_error_from_syserror ();
1685   if (secret_only)
1686     {
1687       strcpy (line, "LISTSECRETKEYS ");
1688       strcpy (&line[15], pattern);
1689     }
1690   else
1691     {
1692       strcpy (line, "LISTKEYS ");
1693       strcpy (&line[9], pattern);
1694     }
1695
1696   gpgsm_clear_fd (gpgsm, INPUT_FD);
1697   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1698   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1699   gpgsm->inline_data = NULL;
1700
1701   err = start (gpgsm, line);
1702   free (line);
1703   return err;
1704 }
1705
1706
1707 static gpgme_error_t
1708 gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
1709                    int reserved, gpgme_keylist_mode_t mode, int engine_flags)
1710 {
1711   engine_gpgsm_t gpgsm = engine;
1712   char *line;
1713   gpgme_error_t err;
1714   /* Length is "LISTSECRETKEYS " + p + '\0'.  */
1715   int length = 15 + 1;
1716   char *linep;
1717   int any_pattern = 0;
1718   int list_mode = 0;
1719
1720   if (reserved)
1721     return gpg_error (GPG_ERR_INV_VALUE);
1722
1723   if (mode & GPGME_KEYLIST_MODE_LOCAL)
1724     list_mode |= 1;
1725   if (mode & GPGME_KEYLIST_MODE_EXTERN)
1726     list_mode |= 2;
1727
1728   /* Always send list-mode option because RESET does not reset it.  */
1729   if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1730     return gpg_error_from_syserror ();
1731   err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
1732   free (line);
1733   if (err)
1734     return err;
1735
1736   /* Always send key validation because RESET does not reset it.  */
1737   /* Use the validation mode if required.  We don't check for an error
1738      yet because this is a pretty fresh gpgsm features. */
1739   gpgsm_assuan_simple_command (gpgsm,
1740                                (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1741                                "OPTION with-validation=1":
1742                                "OPTION with-validation=0" ,
1743                                NULL, NULL);
1744   gpgsm_assuan_simple_command (gpgsm,
1745                                (mode & GPGME_KEYLIST_MODE_WITH_SECRET)?
1746                                "OPTION with-secret=1":
1747                                "OPTION with-secret=0" ,
1748                                NULL, NULL);
1749   gpgsm_assuan_simple_command (gpgsm,
1750                                (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)?
1751                                "OPTION offline=1":
1752                                "OPTION offline=0" ,
1753                                NULL, NULL);
1754
1755   if (pattern && *pattern)
1756     {
1757       const char **pat = pattern;
1758
1759       while (*pat)
1760         {
1761           const char *patlet = *pat;
1762
1763           while (*patlet)
1764             {
1765               length++;
1766               if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1767                 length += 2;
1768               patlet++;
1769             }
1770           pat++;
1771           length++;
1772         }
1773     }
1774   line = malloc (length);
1775   if (!line)
1776     return gpg_error_from_syserror ();
1777   if (secret_only)
1778     {
1779       strcpy (line, "LISTSECRETKEYS ");
1780       linep = &line[15];
1781     }
1782   else
1783     {
1784       strcpy (line, "LISTKEYS ");
1785       linep = &line[9];
1786     }
1787
1788   if (pattern && *pattern)
1789     {
1790       while (*pattern)
1791         {
1792           const char *patlet = *pattern;
1793
1794           while (*patlet)
1795             {
1796               switch (*patlet)
1797                 {
1798                 case '%':
1799                   *(linep++) = '%';
1800                   *(linep++) = '2';
1801                   *(linep++) = '5';
1802                   break;
1803                 case ' ':
1804                   *(linep++) = '%';
1805                   *(linep++) = '2';
1806                   *(linep++) = '0';
1807                   break;
1808                 case '+':
1809                   *(linep++) = '%';
1810                   *(linep++) = '2';
1811                   *(linep++) = 'B';
1812                   break;
1813                 default:
1814                   *(linep++) = *patlet;
1815                   break;
1816                 }
1817               patlet++;
1818             }
1819           any_pattern = 1;
1820           *linep++ = ' ';
1821           pattern++;
1822         }
1823     }
1824   if (any_pattern)
1825     linep--;
1826   *linep = '\0';
1827
1828   gpgsm_clear_fd (gpgsm, INPUT_FD);
1829   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1830   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1831   gpgsm->inline_data = NULL;
1832
1833   err = start (gpgsm, line);
1834   free (line);
1835   return err;
1836 }
1837
1838
1839 static gpgme_error_t
1840 gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
1841             gpgme_sig_mode_t mode, int use_armor, int use_textmode,
1842             int include_certs, gpgme_ctx_t ctx /* FIXME */)
1843 {
1844   engine_gpgsm_t gpgsm = engine;
1845   gpgme_error_t err;
1846   char *assuan_cmd;
1847   int i;
1848   gpgme_key_t key;
1849
1850   (void)use_textmode;
1851
1852   if (!gpgsm)
1853     return gpg_error (GPG_ERR_INV_VALUE);
1854
1855   /* FIXME: This does not work as RESET does not reset it so we can't
1856      revert back to default.  */
1857   if (include_certs != GPGME_INCLUDE_CERTS_DEFAULT)
1858     {
1859       /* FIXME: Make sure that if we run multiple operations, that we
1860          can reset any previously set value in case the default is
1861          requested.  */
1862
1863       if (asprintf (&assuan_cmd, "OPTION include-certs %i", include_certs) < 0)
1864         return gpg_error_from_syserror ();
1865       err = gpgsm_assuan_simple_command (gpgsm, assuan_cmd, NULL, NULL);
1866       free (assuan_cmd);
1867       if (err)
1868         return err;
1869     }
1870
1871   for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1872     {
1873       const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1874       if (s && strlen (s) < 80)
1875         {
1876           char buf[100];
1877
1878           strcpy (stpcpy (buf, "SIGNER "), s);
1879           err = gpgsm_assuan_simple_command (gpgsm, buf,
1880                                              gpgsm->status.fnc,
1881                                              gpgsm->status.fnc_value);
1882         }
1883       else
1884         err = gpg_error (GPG_ERR_INV_VALUE);
1885       gpgme_key_unref (key);
1886       if (err)
1887         return err;
1888     }
1889
1890   gpgsm->input_cb.data = in;
1891   err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1892   if (err)
1893     return err;
1894   gpgsm->output_cb.data = out;
1895   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1896                       : map_data_enc (gpgsm->output_cb.data));
1897   if (err)
1898     return err;
1899   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1900   gpgsm->inline_data = NULL;
1901
1902   err = start (gpgsm, mode == GPGME_SIG_MODE_DETACH
1903                ? "SIGN --detached" : "SIGN");
1904   return err;
1905 }
1906
1907
1908 static gpgme_error_t
1909 gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
1910               gpgme_data_t plaintext, gpgme_ctx_t ctx)
1911 {
1912   engine_gpgsm_t gpgsm = engine;
1913   gpgme_error_t err;
1914
1915   (void)ctx;
1916
1917   if (!gpgsm)
1918     return gpg_error (GPG_ERR_INV_VALUE);
1919
1920   gpgsm->input_cb.data = sig;
1921   err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1922   if (err)
1923     return err;
1924   if (plaintext)
1925     {
1926       /* Normal or cleartext signature.  */
1927       gpgsm->output_cb.data = plaintext;
1928       err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1929       gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1930     }
1931   else
1932     {
1933       /* Detached signature.  */
1934       gpgsm->message_cb.data = signed_text;
1935       err = gpgsm_set_fd (gpgsm, MESSAGE_FD, 0);
1936       gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1937     }
1938   gpgsm->inline_data = NULL;
1939
1940   if (!err)
1941     err = start (gpgsm, "VERIFY");
1942
1943   return err;
1944 }
1945
1946
1947 /* Send the GETAUDITLOG command.  The result is saved to a gpgme data
1948    object.  */
1949 static gpgme_error_t
1950 gpgsm_getauditlog (void *engine, gpgme_data_t output, unsigned int flags)
1951 {
1952   engine_gpgsm_t gpgsm = engine;
1953   gpgme_error_t err = 0;
1954
1955   if (!gpgsm || !output)
1956     return gpg_error (GPG_ERR_INV_VALUE);
1957
1958 #if USE_DESCRIPTOR_PASSING
1959   gpgsm->output_cb.data = output;
1960   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1961   if (err)
1962     return err;
1963
1964   gpgsm_clear_fd (gpgsm, INPUT_FD);
1965   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1966   gpgsm->inline_data = NULL;
1967 # define CMD  "GETAUDITLOG"
1968 #else
1969   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1970   gpgsm_clear_fd (gpgsm, INPUT_FD);
1971   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1972   gpgsm->inline_data = output;
1973 # define CMD  "GETAUDITLOG --data"
1974 #endif
1975
1976   err = start (gpgsm, (flags & GPGME_AUDITLOG_HTML)? CMD " --html" : CMD);
1977
1978   return err;
1979 }
1980
1981
1982 /* This sets a status callback for monitoring status lines before they
1983  * are passed to a caller set handler.  */
1984 static void
1985 gpgsm_set_status_cb (void *engine, gpgme_status_cb_t cb, void *cb_value)
1986 {
1987   engine_gpgsm_t gpgsm = engine;
1988
1989   gpgsm->status.mon_cb = cb;
1990   gpgsm->status.mon_cb_value = cb_value;
1991 }
1992
1993
1994 static void
1995 gpgsm_set_status_handler (void *engine, engine_status_handler_t fnc,
1996                           void *fnc_value)
1997 {
1998   engine_gpgsm_t gpgsm = engine;
1999
2000   gpgsm->status.fnc = fnc;
2001   gpgsm->status.fnc_value = fnc_value;
2002 }
2003
2004
2005 static gpgme_error_t
2006 gpgsm_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
2007                               void *fnc_value)
2008 {
2009   engine_gpgsm_t gpgsm = engine;
2010
2011   gpgsm->colon.fnc = fnc;
2012   gpgsm->colon.fnc_value = fnc_value;
2013   gpgsm->colon.any = 0;
2014   return 0;
2015 }
2016
2017
2018 static void
2019 gpgsm_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
2020 {
2021   engine_gpgsm_t gpgsm = engine;
2022   gpgsm->io_cbs = *io_cbs;
2023 }
2024
2025
2026 static void
2027 gpgsm_io_event (void *engine, gpgme_event_io_t type, void *type_data)
2028 {
2029   engine_gpgsm_t gpgsm = engine;
2030
2031   TRACE3 (DEBUG_ENGINE, "gpgme:gpgsm_io_event", gpgsm,
2032           "event %p, type %d, type_data %p",
2033           gpgsm->io_cbs.event, type, type_data);
2034   if (gpgsm->io_cbs.event)
2035     (*gpgsm->io_cbs.event) (gpgsm->io_cbs.event_priv, type, type_data);
2036 }
2037
2038
2039 static gpgme_error_t
2040 gpgsm_passwd (void *engine, gpgme_key_t key, unsigned int flags)
2041 {
2042   engine_gpgsm_t gpgsm = engine;
2043   gpgme_error_t err;
2044   char *line;
2045
2046   (void)flags;
2047
2048   if (!key || !key->subkeys || !key->subkeys->fpr)
2049     return gpg_error (GPG_ERR_INV_CERT_OBJ);
2050
2051   if (asprintf (&line, "PASSWD -- %s", key->subkeys->fpr) < 0)
2052     return gpg_error_from_syserror ();
2053
2054   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
2055   gpgsm_clear_fd (gpgsm, INPUT_FD);
2056   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
2057   gpgsm->inline_data = NULL;
2058
2059   err = start (gpgsm, line);
2060   free (line);
2061
2062   return err;
2063 }
2064
2065
2066
2067 struct engine_ops _gpgme_engine_ops_gpgsm =
2068   {
2069     /* Static functions.  */
2070     _gpgme_get_default_gpgsm_name,
2071     NULL,
2072     gpgsm_get_version,
2073     gpgsm_get_req_version,
2074     gpgsm_new,
2075
2076     /* Member functions.  */
2077     gpgsm_release,
2078 #if USE_DESCRIPTOR_PASSING
2079     gpgsm_reset,
2080 #else
2081     NULL,                       /* reset */
2082 #endif
2083     gpgsm_set_status_cb,
2084     gpgsm_set_status_handler,
2085     NULL,               /* set_command_handler */
2086     gpgsm_set_colon_line_handler,
2087     gpgsm_set_locale,
2088     NULL,               /* set_protocol */
2089     gpgsm_decrypt,
2090     gpgsm_decrypt,
2091     gpgsm_delete,       /* decrypt_verify */
2092     NULL,               /* edit */
2093     gpgsm_encrypt,
2094     NULL,               /* encrypt_sign */
2095     gpgsm_export,
2096     gpgsm_export_ext,
2097     gpgsm_genkey,
2098     gpgsm_import,
2099     gpgsm_keylist,
2100     gpgsm_keylist_ext,
2101     NULL,               /* keysign */
2102     NULL,               /* tofu_policy */
2103     gpgsm_sign,
2104     NULL,               /* trustlist */
2105     gpgsm_verify,
2106     gpgsm_getauditlog,
2107     NULL,               /* opassuan_transact */
2108     NULL,               /* conf_load */
2109     NULL,               /* conf_save */
2110     NULL,               /* query_swdb */
2111     gpgsm_set_io_cbs,
2112     gpgsm_io_event,
2113     gpgsm_cancel,
2114     NULL,               /* cancel_op */
2115     gpgsm_passwd,
2116     NULL,               /* set_pinentry_mode */
2117     NULL                /* opspawn */
2118   };