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