core: New public API gpgme_op_keylist_from_data_start.
[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 (gpgrt_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       gpgrt_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 (gpgrt_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           gpgrt_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 (gpgrt_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               gpgrt_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 (gpgrt_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       gpgrt_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         break;
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         break;
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           cb_err = 0;
614         }
615       else if (linelen >= 2
616                && line[0] == 'S' && line[1] == ' ')
617         {
618           /* After an error from a status callback we skip all further
619              status lines.  */
620           if (!cb_err)
621             {
622               char *rest;
623               gpgme_status_code_t r;
624
625               rest = strchr (line + 2, ' ');
626               if (!rest)
627                 rest = line + linelen; /* set to an empty string */
628               else
629                 *(rest++) = 0;
630
631               r = _gpgme_parse_status (line + 2);
632               if (gpgsm->status.mon_cb && r != GPGME_STATUS_PROGRESS)
633                 {
634                   /* Note that we call the monitor even if we do
635                    * not know the status code (r < 0).  */
636                   cb_err = gpgsm->status.mon_cb (gpgsm->status.mon_cb_value,
637                                                  line + 2, rest);
638                 }
639
640               if (r >= 0 && status_fnc && !cb_err)
641                 cb_err = status_fnc (status_fnc_value, r, rest);
642             }
643         }
644       else
645         {
646           /* Invalid line or INQUIRY.  We can't do anything else than
647              to stop.  As with ERR we prefer a status callback
648              generated error code, though.  */
649           err = cb_err ? cb_err : gpg_error (GPG_ERR_GENERAL);
650           cb_err = 0;
651         }
652     }
653   while (!err);
654
655   /* We only want the first error from the status handler, thus we
656    * take the one saved in CB_ERR. */
657   if (!err && cb_err)
658     err = cb_err;
659
660   return err;
661 }
662
663
664 typedef enum { INPUT_FD, OUTPUT_FD, MESSAGE_FD } fd_type_t;
665
666 static void
667 gpgsm_clear_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type)
668 {
669 #if !USE_DESCRIPTOR_PASSING
670   switch (fd_type)
671     {
672     case INPUT_FD:
673       _gpgme_io_close (gpgsm->input_cb.fd);
674       break;
675     case OUTPUT_FD:
676       _gpgme_io_close (gpgsm->output_cb.fd);
677       break;
678     case MESSAGE_FD:
679       _gpgme_io_close (gpgsm->message_cb.fd);
680       break;
681     }
682 #else
683   (void)gpgsm;
684   (void)fd_type;
685 #endif
686 }
687
688 #define COMMANDLINELEN 40
689 static gpgme_error_t
690 gpgsm_set_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type, const char *opt)
691 {
692   gpg_error_t err = 0;
693   char line[COMMANDLINELEN];
694   const char *which;
695   iocb_data_t *iocb_data;
696 #if USE_DESCRIPTOR_PASSING
697   int dir;
698 #endif
699
700   switch (fd_type)
701     {
702     case INPUT_FD:
703       which = "INPUT";
704       iocb_data = &gpgsm->input_cb;
705       break;
706
707     case OUTPUT_FD:
708       which = "OUTPUT";
709       iocb_data = &gpgsm->output_cb;
710       break;
711
712     case MESSAGE_FD:
713       which = "MESSAGE";
714       iocb_data = &gpgsm->message_cb;
715       break;
716
717     default:
718       return gpg_error (GPG_ERR_INV_VALUE);
719     }
720
721 #if USE_DESCRIPTOR_PASSING
722   dir = iocb_data->dir;
723   /* We try to short-cut the communication by giving GPGSM direct
724      access to the file descriptor, rather than using a pipe.  */
725   iocb_data->server_fd = _gpgme_data_get_fd (iocb_data->data);
726   if (iocb_data->server_fd < 0)
727     {
728       int fds[2];
729
730       if (_gpgme_io_pipe (fds, dir) < 0)
731         return gpg_error_from_syserror ();
732
733       iocb_data->fd = dir ? fds[0] : fds[1];
734       iocb_data->server_fd = dir ? fds[1] : fds[0];
735
736       if (_gpgme_io_set_close_notify (iocb_data->fd,
737                                       close_notify_handler, gpgsm))
738         {
739           err = gpg_error (GPG_ERR_GENERAL);
740           goto leave_set_fd;
741         }
742     }
743
744   err = assuan_sendfd (gpgsm->assuan_ctx, iocb_data->server_fd);
745   if (err)
746     goto leave_set_fd;
747
748   _gpgme_io_close (iocb_data->server_fd);
749   iocb_data->server_fd = -1;
750
751   if (opt)
752     snprintf (line, COMMANDLINELEN, "%s FD %s", which, opt);
753   else
754     snprintf (line, COMMANDLINELEN, "%s FD", which);
755 #else
756   if (opt)
757     snprintf (line, COMMANDLINELEN, "%s FD=%s %s",
758               which, iocb_data->server_fd_str, opt);
759   else
760     snprintf (line, COMMANDLINELEN, "%s FD=%s",
761               which, iocb_data->server_fd_str);
762 #endif
763
764   err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
765
766 #if USE_DESCRIPTOR_PASSING
767  leave_set_fd:
768   if (err)
769     {
770       _gpgme_io_close (iocb_data->fd);
771       iocb_data->fd = -1;
772       if (iocb_data->server_fd != -1)
773         {
774           _gpgme_io_close (iocb_data->server_fd);
775           iocb_data->server_fd = -1;
776         }
777     }
778 #endif
779
780   return err;
781 }
782
783
784 static const char *
785 map_data_enc (gpgme_data_t d)
786 {
787   switch (gpgme_data_get_encoding (d))
788     {
789     case GPGME_DATA_ENCODING_NONE:
790       break;
791     case GPGME_DATA_ENCODING_BINARY:
792       return "--binary";
793     case GPGME_DATA_ENCODING_BASE64:
794       return "--base64";
795     case GPGME_DATA_ENCODING_ARMOR:
796       return "--armor";
797     default:
798       break;
799     }
800   return NULL;
801 }
802
803
804 static gpgme_error_t
805 status_handler (void *opaque, int fd)
806 {
807   struct io_cb_data *data = (struct io_cb_data *) opaque;
808   engine_gpgsm_t gpgsm = (engine_gpgsm_t) data->handler_value;
809   gpgme_error_t err = 0;
810   char *line;
811   size_t linelen;
812
813   do
814     {
815       err = assuan_read_line (gpgsm->assuan_ctx, &line, &linelen);
816       if (err)
817         {
818           /* Try our best to terminate the connection friendly.  */
819           /*      assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
820           TRACE3 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
821                   "fd 0x%x: error from assuan (%d) getting status line : %s",
822                   fd, err, gpg_strerror (err));
823         }
824       else if (linelen >= 3
825                && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
826                && (line[3] == '\0' || line[3] == ' '))
827         {
828           if (line[3] == ' ')
829             err = atoi (&line[4]);
830           if (! err)
831             err = gpg_error (GPG_ERR_GENERAL);
832           TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
833                   "fd 0x%x: ERR line - mapped to: %s",
834                   fd, err ? gpg_strerror (err) : "ok");
835           /* Try our best to terminate the connection friendly.  */
836           /*      assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
837         }
838       else if (linelen >= 2
839                && line[0] == 'O' && line[1] == 'K'
840                && (line[2] == '\0' || line[2] == ' '))
841         {
842           if (gpgsm->status.fnc)
843             {
844               char emptystring[1] = {0};
845               err = gpgsm->status.fnc (gpgsm->status.fnc_value,
846                                        GPGME_STATUS_EOF, emptystring);
847               if (gpg_err_code (err) == GPG_ERR_FALSE)
848                 err = 0; /* Drop special error code.  */
849             }
850
851           if (!err && gpgsm->colon.fnc && gpgsm->colon.any)
852             {
853               /* We must tell a colon function about the EOF. We do
854                  this only when we have seen any data lines.  Note
855                  that this inlined use of colon data lines will
856                  eventually be changed into using a regular data
857                  channel. */
858               gpgsm->colon.any = 0;
859               err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, NULL);
860             }
861           TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
862                   "fd 0x%x: OK line - final status: %s",
863                   fd, err ? gpg_strerror (err) : "ok");
864           _gpgme_io_close (gpgsm->status_cb.fd);
865           return err;
866         }
867       else if (linelen > 2
868                && line[0] == 'D' && line[1] == ' '
869                && gpgsm->colon.fnc)
870         {
871           /* We are using the colon handler even for plain inline data
872              - strange name for that function but for historic reasons
873              we keep it.  */
874           /* FIXME We can't use this for binary data because we
875              assume this is a string.  For the current usage of colon
876              output it is correct.  */
877           char *src = line + 2;
878           char *end = line + linelen;
879           char *dst;
880           char **aline = &gpgsm->colon.attic.line;
881           int *alinelen = &gpgsm->colon.attic.linelen;
882
883           if (gpgsm->colon.attic.linesize < *alinelen + linelen + 1)
884             {
885               char *newline = realloc (*aline, *alinelen + linelen + 1);
886               if (!newline)
887                 err = gpg_error_from_syserror ();
888               else
889                 {
890                   *aline = newline;
891                   gpgsm->colon.attic.linesize = *alinelen + linelen + 1;
892                 }
893             }
894           if (!err)
895             {
896               dst = *aline + *alinelen;
897
898               while (!err && src < end)
899                 {
900                   if (*src == '%' && src + 2 < end)
901                     {
902                       /* Handle escaped characters.  */
903                       ++src;
904                       *dst = _gpgme_hextobyte (src);
905                       (*alinelen)++;
906                       src += 2;
907                     }
908                   else
909                     {
910                       *dst = *src++;
911                       (*alinelen)++;
912                     }
913
914                   if (*dst == '\n')
915                     {
916                       /* Terminate the pending line, pass it to the colon
917                          handler and reset it.  */
918
919                       gpgsm->colon.any = 1;
920                       if (*alinelen > 1 && *(dst - 1) == '\r')
921                         dst--;
922                       *dst = '\0';
923
924                       /* FIXME How should we handle the return code?  */
925                       err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, *aline);
926                       if (!err)
927                         {
928                           dst = *aline;
929                           *alinelen = 0;
930                         }
931                     }
932                   else
933                     dst++;
934                 }
935             }
936           TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
937                   "fd 0x%x: D line; final status: %s",
938                   fd, err? gpg_strerror (err):"ok");
939         }
940       else if (linelen > 2
941                && line[0] == 'D' && line[1] == ' '
942                && gpgsm->inline_data)
943         {
944           char *src = line + 2;
945           char *end = line + linelen;
946           char *dst = src;
947           gpgme_ssize_t nwritten;
948
949           linelen = 0;
950           while (src < end)
951             {
952               if (*src == '%' && src + 2 < end)
953                 {
954                   /* Handle escaped characters.  */
955                   ++src;
956                   *dst++ = _gpgme_hextobyte (src);
957                   src += 2;
958                 }
959               else
960                 *dst++ = *src++;
961
962               linelen++;
963             }
964
965           src = line + 2;
966           while (linelen > 0)
967             {
968               nwritten = gpgme_data_write (gpgsm->inline_data, src, linelen);
969               if (!nwritten || (nwritten < 0 && errno != EINTR)
970                   || nwritten > linelen)
971                 {
972                   err = gpg_error_from_syserror ();
973                   break;
974                 }
975               src += nwritten;
976               linelen -= nwritten;
977             }
978
979           TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
980                   "fd 0x%x: D inlinedata; final status: %s",
981                   fd, err? gpg_strerror (err):"ok");
982         }
983       else if (linelen > 2
984                && line[0] == 'S' && line[1] == ' ')
985         {
986           char *rest;
987           gpgme_status_code_t r;
988
989           rest = strchr (line + 2, ' ');
990           if (!rest)
991             rest = line + linelen; /* set to an empty string */
992           else
993             *(rest++) = 0;
994
995           r = _gpgme_parse_status (line + 2);
996
997           if (r >= 0)
998             {
999               if (gpgsm->status.fnc)
1000                 {
1001                   err = gpgsm->status.fnc (gpgsm->status.fnc_value, r, rest);
1002                   if (gpg_err_code (err) == GPG_ERR_FALSE)
1003                     err = 0; /* Drop special error code.  */
1004                 }
1005             }
1006           else
1007             fprintf (stderr, "[UNKNOWN STATUS]%s %s", line + 2, rest);
1008           TRACE3 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
1009                   "fd 0x%x: S line (%s) - final status: %s",
1010                   fd, line+2, err? gpg_strerror (err):"ok");
1011         }
1012       else if (linelen >= 7
1013                && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
1014                && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
1015                && line[6] == 'E'
1016                && (line[7] == '\0' || line[7] == ' '))
1017         {
1018           char *keyword = line+7;
1019
1020           while (*keyword == ' ')
1021             keyword++;;
1022           default_inq_cb (gpgsm, keyword);
1023           assuan_write_line (gpgsm->assuan_ctx, "END");
1024         }
1025
1026     }
1027   while (!err && assuan_pending_line (gpgsm->assuan_ctx));
1028
1029   return err;
1030 }
1031
1032
1033 static gpgme_error_t
1034 add_io_cb (engine_gpgsm_t gpgsm, iocb_data_t *iocbd, gpgme_io_cb_t handler)
1035 {
1036   gpgme_error_t err;
1037
1038   TRACE_BEG2 (DEBUG_ENGINE, "engine-gpgsm:add_io_cb", gpgsm,
1039               "fd %d, dir %d", iocbd->fd, iocbd->dir);
1040   err = (*gpgsm->io_cbs.add) (gpgsm->io_cbs.add_priv,
1041                               iocbd->fd, iocbd->dir,
1042                               handler, iocbd->data, &iocbd->tag);
1043   if (err)
1044     return TRACE_ERR (err);
1045   if (!iocbd->dir)
1046     /* FIXME Kludge around poll() problem.  */
1047     err = _gpgme_io_set_nonblocking (iocbd->fd);
1048   return TRACE_ERR (err);
1049 }
1050
1051
1052 static gpgme_error_t
1053 start (engine_gpgsm_t gpgsm, const char *command)
1054 {
1055   gpgme_error_t err;
1056   assuan_fd_t afdlist[5];
1057   int fdlist[5];
1058   int nfds;
1059   int i;
1060
1061   /* We need to know the fd used by assuan for reads.  We do this by
1062      using the assumption that the first returned fd from
1063      assuan_get_active_fds() is always this one.  */
1064   nfds = assuan_get_active_fds (gpgsm->assuan_ctx, 0 /* read fds */,
1065                                 afdlist, DIM (afdlist));
1066   if (nfds < 1)
1067     return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1068   /* For now... */
1069   for (i = 0; i < nfds; i++)
1070     fdlist[i] = (int) afdlist[i];
1071
1072   /* We "duplicate" the file descriptor, so we can close it here (we
1073      can't close fdlist[0], as that is closed by libassuan, and
1074      closing it here might cause libassuan to close some unrelated FD
1075      later).  Alternatively, we could special case status_fd and
1076      register/unregister it manually as needed, but this increases
1077      code duplication and is more complicated as we can not use the
1078      close notifications etc.  A third alternative would be to let
1079      Assuan know that we closed the FD, but that complicates the
1080      Assuan interface.  */
1081
1082   gpgsm->status_cb.fd = _gpgme_io_dup (fdlist[0]);
1083   if (gpgsm->status_cb.fd < 0)
1084     return gpg_error_from_syserror ();
1085
1086   if (_gpgme_io_set_close_notify (gpgsm->status_cb.fd,
1087                                   close_notify_handler, gpgsm))
1088     {
1089       _gpgme_io_close (gpgsm->status_cb.fd);
1090       gpgsm->status_cb.fd = -1;
1091       return gpg_error (GPG_ERR_GENERAL);
1092     }
1093
1094   err = add_io_cb (gpgsm, &gpgsm->status_cb, status_handler);
1095   if (!err && gpgsm->input_cb.fd != -1)
1096     err = add_io_cb (gpgsm, &gpgsm->input_cb, _gpgme_data_outbound_handler);
1097   if (!err && gpgsm->output_cb.fd != -1)
1098     err = add_io_cb (gpgsm, &gpgsm->output_cb, _gpgme_data_inbound_handler);
1099   if (!err && gpgsm->message_cb.fd != -1)
1100     err = add_io_cb (gpgsm, &gpgsm->message_cb, _gpgme_data_outbound_handler);
1101
1102   if (!err)
1103     err = assuan_write_line (gpgsm->assuan_ctx, command);
1104
1105   if (!err)
1106     gpgsm_io_event (gpgsm, GPGME_EVENT_START, NULL);
1107
1108   return err;
1109 }
1110
1111
1112 #if USE_DESCRIPTOR_PASSING
1113 static gpgme_error_t
1114 gpgsm_reset (void *engine)
1115 {
1116   engine_gpgsm_t gpgsm = engine;
1117
1118   /* IF we have an active connection we must send a reset because we
1119      need to reset the list of signers.  Note that RESET does not
1120      reset OPTION commands. */
1121   return (gpgsm->assuan_ctx
1122           ? gpgsm_assuan_simple_command (gpgsm, "RESET", NULL, NULL)
1123           : 0);
1124 }
1125 #endif
1126
1127
1128
1129 static gpgme_error_t
1130 gpgsm_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain,
1131                int export_session_key, const char *override_session_key)
1132 {
1133   engine_gpgsm_t gpgsm = engine;
1134   gpgme_error_t err;
1135
1136   /* gpgsm is not capable of exporting session keys right now, so we
1137    * will ignore this if requested. */
1138   (void)export_session_key;
1139   (void)override_session_key;
1140
1141   if (!gpgsm)
1142     return gpg_error (GPG_ERR_INV_VALUE);
1143
1144   gpgsm->input_cb.data = ciph;
1145   err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1146   if (err)
1147     return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1148   gpgsm->output_cb.data = plain;
1149   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1150   if (err)
1151     return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1152   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1153   gpgsm->inline_data = NULL;
1154
1155   err = start (engine, "DECRYPT");
1156   return err;
1157 }
1158
1159
1160 static gpgme_error_t
1161 gpgsm_delete (void *engine, gpgme_key_t key, int allow_secret)
1162 {
1163   engine_gpgsm_t gpgsm = engine;
1164   gpgme_error_t err;
1165   char *fpr = key->subkeys ? key->subkeys->fpr : NULL;
1166   char *linep = fpr;
1167   char *line;
1168   int length = 8;       /* "DELKEYS " */
1169
1170   (void)allow_secret;
1171
1172   if (!fpr)
1173     return gpg_error (GPG_ERR_INV_VALUE);
1174
1175   while (*linep)
1176     {
1177       length++;
1178       if (*linep == '%' || *linep == ' ' || *linep == '+')
1179         length += 2;
1180       linep++;
1181     }
1182   length++;
1183
1184   line = malloc (length);
1185   if (!line)
1186     return gpg_error_from_syserror ();
1187
1188   strcpy (line, "DELKEYS ");
1189   linep = &line[8];
1190
1191   while (*fpr)
1192     {
1193       switch (*fpr)
1194         {
1195         case '%':
1196           *(linep++) = '%';
1197           *(linep++) = '2';
1198           *(linep++) = '5';
1199           break;
1200         case ' ':
1201           *(linep++) = '%';
1202           *(linep++) = '2';
1203           *(linep++) = '0';
1204           break;
1205         case '+':
1206           *(linep++) = '%';
1207           *(linep++) = '2';
1208           *(linep++) = 'B';
1209           break;
1210         default:
1211           *(linep++) = *fpr;
1212           break;
1213         }
1214       fpr++;
1215     }
1216   *linep = '\0';
1217
1218   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1219   gpgsm_clear_fd (gpgsm, INPUT_FD);
1220   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1221   gpgsm->inline_data = NULL;
1222
1223   err = start (gpgsm, line);
1224   free (line);
1225
1226   return err;
1227 }
1228
1229
1230 static gpgme_error_t
1231 set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[])
1232 {
1233   gpgme_error_t err = 0;
1234   char *line;
1235   int linelen;
1236   int invalid_recipients = 0;
1237   int i;
1238
1239   linelen = 10 + 40 + 1;        /* "RECIPIENT " + guess + '\0'.  */
1240   line = malloc (10 + 40 + 1);
1241   if (!line)
1242     return gpg_error_from_syserror ();
1243   strcpy (line, "RECIPIENT ");
1244   for (i =0; !err && recp[i]; i++)
1245     {
1246       char *fpr;
1247       int newlen;
1248
1249       if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
1250         {
1251           invalid_recipients++;
1252           continue;
1253         }
1254       fpr = recp[i]->subkeys->fpr;
1255
1256       newlen = 11 + strlen (fpr);
1257       if (linelen < newlen)
1258         {
1259           char *newline = realloc (line, newlen);
1260           if (! newline)
1261             {
1262               int saved_err = gpg_error_from_syserror ();
1263               free (line);
1264               return saved_err;
1265             }
1266           line = newline;
1267           linelen = newlen;
1268         }
1269       strcpy (&line[10], fpr);
1270
1271       err = gpgsm_assuan_simple_command (gpgsm, line, gpgsm->status.fnc,
1272                                          gpgsm->status.fnc_value);
1273       /* FIXME: This requires more work.  */
1274       if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
1275         invalid_recipients++;
1276       else if (err)
1277         {
1278           free (line);
1279           return err;
1280         }
1281     }
1282   free (line);
1283   return gpg_error (invalid_recipients
1284                     ? GPG_ERR_UNUSABLE_PUBKEY : GPG_ERR_NO_ERROR);
1285 }
1286
1287
1288 static gpgme_error_t
1289 gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
1290                gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
1291 {
1292   engine_gpgsm_t gpgsm = engine;
1293   gpgme_error_t err;
1294
1295   if (!gpgsm)
1296     return gpg_error (GPG_ERR_INV_VALUE);
1297   if (!recp)
1298     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1299
1300   if (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO)
1301     {
1302       err = gpgsm_assuan_simple_command (gpgsm,
1303                                          "OPTION no-encrypt-to", NULL, NULL);
1304       if (err)
1305         return err;
1306     }
1307
1308   gpgsm->input_cb.data = plain;
1309   err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1310   if (err)
1311     return err;
1312   gpgsm->output_cb.data = ciph;
1313   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1314                       : map_data_enc (gpgsm->output_cb.data));
1315   if (err)
1316     return err;
1317   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1318   gpgsm->inline_data = NULL;
1319
1320   err = set_recipients (gpgsm, recp);
1321
1322   if (!err)
1323     err = start (gpgsm, "ENCRYPT");
1324
1325   return err;
1326 }
1327
1328
1329 static gpgme_error_t
1330 gpgsm_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
1331               gpgme_data_t keydata, int use_armor)
1332 {
1333   engine_gpgsm_t gpgsm = engine;
1334   gpgme_error_t err = 0;
1335   char *cmd;
1336
1337   if (!gpgsm)
1338     return gpg_error (GPG_ERR_INV_VALUE);
1339
1340   if (!pattern)
1341     pattern = "";
1342
1343   cmd = malloc (7 + 9 + 9 + strlen (pattern) + 1);
1344   if (!cmd)
1345     return gpg_error_from_syserror ();
1346
1347   strcpy (cmd, "EXPORT ");
1348   if ((mode & GPGME_EXPORT_MODE_SECRET))
1349     {
1350       strcat (cmd, "--secret ");
1351       if ((mode & GPGME_EXPORT_MODE_RAW))
1352         strcat (cmd, "--raw ");
1353       else if ((mode & GPGME_EXPORT_MODE_PKCS12))
1354         strcat (cmd, "--pkcs12 ");
1355     }
1356   strcat (cmd, pattern);
1357
1358   gpgsm->output_cb.data = keydata;
1359   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1360                       : map_data_enc (gpgsm->output_cb.data));
1361   if (err)
1362     return err;
1363   gpgsm_clear_fd (gpgsm, INPUT_FD);
1364   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1365   gpgsm->inline_data = NULL;
1366
1367   err = start (gpgsm, cmd);
1368   free (cmd);
1369   return err;
1370 }
1371
1372
1373 static gpgme_error_t
1374 gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
1375                   gpgme_data_t keydata, int use_armor)
1376 {
1377   engine_gpgsm_t gpgsm = engine;
1378   gpgme_error_t err = 0;
1379   char *line;
1380   /* Length is "EXPORT " + "--secret " + "--pkcs12 " + p + '\0'.  */
1381   int length = 7 + 9 + 9 + 1;
1382   char *linep;
1383
1384   if (!gpgsm)
1385     return gpg_error (GPG_ERR_INV_VALUE);
1386
1387   if (pattern && *pattern)
1388     {
1389       const char **pat = pattern;
1390
1391       while (*pat)
1392         {
1393           const char *patlet = *pat;
1394
1395           while (*patlet)
1396             {
1397               length++;
1398               if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1399                 length += 2;
1400               patlet++;
1401             }
1402           pat++;
1403           length++;
1404         }
1405     }
1406   line = malloc (length);
1407   if (!line)
1408     return gpg_error_from_syserror ();
1409
1410   strcpy (line, "EXPORT ");
1411   if ((mode & GPGME_EXPORT_MODE_SECRET))
1412     {
1413       strcat (line, "--secret ");
1414       if ((mode & GPGME_EXPORT_MODE_RAW))
1415         strcat (line, "--raw ");
1416       else if ((mode & GPGME_EXPORT_MODE_PKCS12))
1417         strcat (line, "--pkcs12 ");
1418     }
1419   linep = &line[strlen (line)];
1420
1421   if (pattern && *pattern)
1422     {
1423       while (*pattern)
1424         {
1425           const char *patlet = *pattern;
1426
1427           while (*patlet)
1428             {
1429               switch (*patlet)
1430                 {
1431                 case '%':
1432                   *(linep++) = '%';
1433                   *(linep++) = '2';
1434                   *(linep++) = '5';
1435                   break;
1436                 case ' ':
1437                   *(linep++) = '%';
1438                   *(linep++) = '2';
1439                   *(linep++) = '0';
1440                   break;
1441                 case '+':
1442                   *(linep++) = '%';
1443                   *(linep++) = '2';
1444                   *(linep++) = 'B';
1445                   break;
1446                 default:
1447                   *(linep++) = *patlet;
1448                   break;
1449                 }
1450               patlet++;
1451             }
1452           pattern++;
1453           if (*pattern)
1454             *linep++ = ' ';
1455         }
1456     }
1457   *linep = '\0';
1458
1459   gpgsm->output_cb.data = keydata;
1460   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1461                       : map_data_enc (gpgsm->output_cb.data));
1462   if (err)
1463     return err;
1464   gpgsm_clear_fd (gpgsm, INPUT_FD);
1465   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1466   gpgsm->inline_data = NULL;
1467
1468   err = start (gpgsm, line);
1469   free (line);
1470   return err;
1471 }
1472
1473
1474 static gpgme_error_t
1475 gpgsm_genkey (void *engine,
1476               const char *userid, const char *algo,
1477               unsigned long reserved, unsigned long expires,
1478               gpgme_key_t key, unsigned int flags,
1479               gpgme_data_t help_data, unsigned int extraflags,
1480               gpgme_data_t pubkey, gpgme_data_t seckey)
1481 {
1482   engine_gpgsm_t gpgsm = engine;
1483   gpgme_error_t err;
1484
1485   (void)reserved;
1486
1487   if (!gpgsm)
1488     return gpg_error (GPG_ERR_INV_VALUE);
1489
1490   if (help_data)
1491     {
1492       if (!pubkey || seckey)
1493         return gpg_error (GPG_ERR_INV_VALUE);
1494
1495       gpgsm->input_cb.data = help_data;
1496       err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1497       if (err)
1498         return err;
1499       gpgsm->output_cb.data = pubkey;
1500       err = gpgsm_set_fd (gpgsm, OUTPUT_FD,
1501                           (extraflags & GENKEY_EXTRAFLAG_ARMOR)? "--armor"
1502                           : map_data_enc (gpgsm->output_cb.data));
1503       if (err)
1504         return err;
1505       gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1506       gpgsm->inline_data = NULL;
1507
1508       err = start (gpgsm, "GENKEY");
1509       return err;
1510     }
1511
1512   (void)userid;
1513   (void)algo;
1514   (void)expires;
1515   (void)key;
1516   (void)flags;
1517
1518   /* The new interface has not yet been implemented,  */
1519   return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1520 }
1521
1522
1523 static gpgme_error_t
1524 gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
1525 {
1526   engine_gpgsm_t gpgsm = engine;
1527   gpgme_error_t err;
1528   gpgme_data_encoding_t dataenc;
1529   int idx;
1530
1531   if (!gpgsm)
1532     return gpg_error (GPG_ERR_INV_VALUE);
1533
1534   if (keydata && keyarray)
1535     return gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed.  */
1536
1537   dataenc = gpgme_data_get_encoding (keydata);
1538
1539   if (keyarray)
1540     {
1541       size_t buflen;
1542       char *buffer, *p;
1543
1544       /* Fist check whether the engine already features the
1545          --re-import option.  */
1546       err = gpgsm_assuan_simple_command
1547         (gpgsm, "GETINFO cmd_has_option IMPORT re-import", NULL, NULL);
1548       if (err)
1549         return gpg_error (GPG_ERR_NOT_SUPPORTED);
1550
1551       /* Create an internal data object with a list of all
1552          fingerprints.  The data object and its memory (to avoid an
1553          extra copy by gpgme_data_new_from_mem) are stored in two
1554          variables which are released by the close_notify_handler.  */
1555       for (idx=0, buflen=0; 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             buflen += strlen (keyarray[idx]->subkeys->fpr) + 1;
1562         }
1563       /* Allocate a bufer with extra space for the trailing Nul
1564          introduced by the use of stpcpy.  */
1565       buffer = malloc (buflen+1);
1566       if (!buffer)
1567         return gpg_error_from_syserror ();
1568       for (idx=0, p = buffer; keyarray[idx]; idx++)
1569         {
1570           if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
1571               && keyarray[idx]->subkeys
1572               && keyarray[idx]->subkeys->fpr
1573               && *keyarray[idx]->subkeys->fpr)
1574             p = stpcpy (stpcpy (p, keyarray[idx]->subkeys->fpr), "\n");
1575         }
1576
1577       err = gpgme_data_new_from_mem (&gpgsm->input_helper_data,
1578                                      buffer, buflen, 0);
1579       if (err)
1580         {
1581           free (buffer);
1582           return err;
1583         }
1584       gpgsm->input_helper_memory = buffer;
1585
1586       gpgsm->input_cb.data = gpgsm->input_helper_data;
1587       err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1588       if (err)
1589         {
1590           gpgme_data_release (gpgsm->input_helper_data);
1591           gpgsm->input_helper_data = NULL;
1592           free (gpgsm->input_helper_memory);
1593           gpgsm->input_helper_memory = NULL;
1594           return err;
1595         }
1596       gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1597       gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1598       gpgsm->inline_data = NULL;
1599
1600       return start (gpgsm, "IMPORT --re-import");
1601     }
1602   else if (dataenc == GPGME_DATA_ENCODING_URL
1603            || dataenc == GPGME_DATA_ENCODING_URL0
1604            || dataenc == GPGME_DATA_ENCODING_URLESC)
1605     {
1606       return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1607     }
1608   else
1609     {
1610       gpgsm->input_cb.data = keydata;
1611       err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1612       if (err)
1613         return err;
1614       gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1615       gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1616       gpgsm->inline_data = NULL;
1617
1618       return start (gpgsm, "IMPORT");
1619     }
1620 }
1621
1622
1623 static gpgme_error_t
1624 gpgsm_keylist (void *engine, const char *pattern, int secret_only,
1625                gpgme_keylist_mode_t mode, int engine_flags)
1626 {
1627   engine_gpgsm_t gpgsm = engine;
1628   char *line;
1629   gpgme_error_t err;
1630   int list_mode = 0;
1631
1632   if (mode & GPGME_KEYLIST_MODE_LOCAL)
1633     list_mode |= 1;
1634   if (mode & GPGME_KEYLIST_MODE_EXTERN)
1635     list_mode |= 2;
1636
1637   if (!pattern)
1638     pattern = "";
1639
1640   /* Hack to make sure that the agent is started.  Only if the agent
1641      has been started an application may connect to the agent via
1642      GPGME_PROTOCOL_ASSUAN - for example to look for smartcards.  We
1643      do this only if a secret key listing has been requested.  In
1644      general this is not needed because a secret key listing starts
1645      the agent.  However on a fresh installation no public keys are
1646      available and thus there is no need for gpgsm to ask the agent
1647      whether a secret key exists for the public key.  */
1648   if (secret_only || (mode & GPGME_KEYLIST_MODE_WITH_SECRET))
1649     gpgsm_assuan_simple_command (gpgsm, "GETINFO agent-check", NULL, NULL);
1650
1651   /* Always send list-mode option because RESET does not reset it.  */
1652   if (gpgrt_asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1653     return gpg_error_from_syserror ();
1654   err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
1655   gpgrt_free (line);
1656   if (err)
1657     return err;
1658
1659
1660   /* Always send key validation because RESET does not reset it.  */
1661
1662   /* Use the validation mode 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_VALIDATE)?
1666                                "OPTION with-validation=1":
1667                                "OPTION with-validation=0" ,
1668                                NULL, NULL);
1669   /* Include the ephemeral keys if requested.  We don't check for an error
1670      yet because this is a pretty fresh gpgsm features. */
1671   gpgsm_assuan_simple_command (gpgsm,
1672                                (mode & GPGME_KEYLIST_MODE_EPHEMERAL)?
1673                                "OPTION with-ephemeral-keys=1":
1674                                "OPTION with-ephemeral-keys=0" ,
1675                                NULL, NULL);
1676   gpgsm_assuan_simple_command (gpgsm,
1677                                (mode & GPGME_KEYLIST_MODE_WITH_SECRET)?
1678                                "OPTION with-secret=1":
1679                                "OPTION with-secret=0" ,
1680                                NULL, NULL);
1681   gpgsm_assuan_simple_command (gpgsm,
1682                                (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)?
1683                                "OPTION offline=1":
1684                                "OPTION offline=0" ,
1685                                NULL, NULL);
1686
1687
1688   /* Length is "LISTSECRETKEYS " + p + '\0'.  */
1689   line = malloc (15 + strlen (pattern) + 1);
1690   if (!line)
1691     return gpg_error_from_syserror ();
1692   if (secret_only)
1693     {
1694       strcpy (line, "LISTSECRETKEYS ");
1695       strcpy (&line[15], pattern);
1696     }
1697   else
1698     {
1699       strcpy (line, "LISTKEYS ");
1700       strcpy (&line[9], pattern);
1701     }
1702
1703   gpgsm_clear_fd (gpgsm, INPUT_FD);
1704   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1705   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1706   gpgsm->inline_data = NULL;
1707
1708   err = start (gpgsm, line);
1709   free (line);
1710   return err;
1711 }
1712
1713
1714 static gpgme_error_t
1715 gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
1716                    int reserved, gpgme_keylist_mode_t mode, int engine_flags)
1717 {
1718   engine_gpgsm_t gpgsm = engine;
1719   char *line;
1720   gpgme_error_t err;
1721   /* Length is "LISTSECRETKEYS " + p + '\0'.  */
1722   int length = 15 + 1;
1723   char *linep;
1724   int any_pattern = 0;
1725   int list_mode = 0;
1726
1727   if (reserved)
1728     return gpg_error (GPG_ERR_INV_VALUE);
1729
1730   if (mode & GPGME_KEYLIST_MODE_LOCAL)
1731     list_mode |= 1;
1732   if (mode & GPGME_KEYLIST_MODE_EXTERN)
1733     list_mode |= 2;
1734
1735   /* Always send list-mode option because RESET does not reset it.  */
1736   if (gpgrt_asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1737     return gpg_error_from_syserror ();
1738   err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
1739   gpgrt_free (line);
1740   if (err)
1741     return err;
1742
1743   /* Always send key validation because RESET does not reset it.  */
1744   /* Use the validation mode if required.  We don't check for an error
1745      yet because this is a pretty fresh gpgsm features. */
1746   gpgsm_assuan_simple_command (gpgsm,
1747                                (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1748                                "OPTION with-validation=1":
1749                                "OPTION with-validation=0" ,
1750                                NULL, NULL);
1751   gpgsm_assuan_simple_command (gpgsm,
1752                                (mode & GPGME_KEYLIST_MODE_WITH_SECRET)?
1753                                "OPTION with-secret=1":
1754                                "OPTION with-secret=0" ,
1755                                NULL, NULL);
1756   gpgsm_assuan_simple_command (gpgsm,
1757                                (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)?
1758                                "OPTION offline=1":
1759                                "OPTION offline=0" ,
1760                                NULL, NULL);
1761
1762   if (pattern && *pattern)
1763     {
1764       const char **pat = pattern;
1765
1766       while (*pat)
1767         {
1768           const char *patlet = *pat;
1769
1770           while (*patlet)
1771             {
1772               length++;
1773               if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1774                 length += 2;
1775               patlet++;
1776             }
1777           pat++;
1778           length++;
1779         }
1780     }
1781   line = malloc (length);
1782   if (!line)
1783     return gpg_error_from_syserror ();
1784   if (secret_only)
1785     {
1786       strcpy (line, "LISTSECRETKEYS ");
1787       linep = &line[15];
1788     }
1789   else
1790     {
1791       strcpy (line, "LISTKEYS ");
1792       linep = &line[9];
1793     }
1794
1795   if (pattern && *pattern)
1796     {
1797       while (*pattern)
1798         {
1799           const char *patlet = *pattern;
1800
1801           while (*patlet)
1802             {
1803               switch (*patlet)
1804                 {
1805                 case '%':
1806                   *(linep++) = '%';
1807                   *(linep++) = '2';
1808                   *(linep++) = '5';
1809                   break;
1810                 case ' ':
1811                   *(linep++) = '%';
1812                   *(linep++) = '2';
1813                   *(linep++) = '0';
1814                   break;
1815                 case '+':
1816                   *(linep++) = '%';
1817                   *(linep++) = '2';
1818                   *(linep++) = 'B';
1819                   break;
1820                 default:
1821                   *(linep++) = *patlet;
1822                   break;
1823                 }
1824               patlet++;
1825             }
1826           any_pattern = 1;
1827           *linep++ = ' ';
1828           pattern++;
1829         }
1830     }
1831   if (any_pattern)
1832     linep--;
1833   *linep = '\0';
1834
1835   gpgsm_clear_fd (gpgsm, INPUT_FD);
1836   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1837   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1838   gpgsm->inline_data = NULL;
1839
1840   err = start (gpgsm, line);
1841   free (line);
1842   return err;
1843 }
1844
1845
1846 static gpgme_error_t
1847 gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
1848             gpgme_sig_mode_t mode, int use_armor, int use_textmode,
1849             int include_certs, gpgme_ctx_t ctx /* FIXME */)
1850 {
1851   engine_gpgsm_t gpgsm = engine;
1852   gpgme_error_t err;
1853   char *assuan_cmd;
1854   int i;
1855   gpgme_key_t key;
1856
1857   (void)use_textmode;
1858
1859   if (!gpgsm)
1860     return gpg_error (GPG_ERR_INV_VALUE);
1861
1862   /* FIXME: This does not work as RESET does not reset it so we can't
1863      revert back to default.  */
1864   if (include_certs != GPGME_INCLUDE_CERTS_DEFAULT)
1865     {
1866       /* FIXME: Make sure that if we run multiple operations, that we
1867          can reset any previously set value in case the default is
1868          requested.  */
1869
1870       if (gpgrt_asprintf (&assuan_cmd,
1871                           "OPTION include-certs %i", include_certs) < 0)
1872         return gpg_error_from_syserror ();
1873       err = gpgsm_assuan_simple_command (gpgsm, assuan_cmd, NULL, NULL);
1874       gpgrt_free (assuan_cmd);
1875       if (err)
1876         return err;
1877     }
1878
1879   for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1880     {
1881       const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1882       if (s && strlen (s) < 80)
1883         {
1884           char buf[100];
1885
1886           strcpy (stpcpy (buf, "SIGNER "), s);
1887           err = gpgsm_assuan_simple_command (gpgsm, buf,
1888                                              gpgsm->status.fnc,
1889                                              gpgsm->status.fnc_value);
1890         }
1891       else
1892         err = gpg_error (GPG_ERR_INV_VALUE);
1893       gpgme_key_unref (key);
1894       if (err)
1895         return err;
1896     }
1897
1898   gpgsm->input_cb.data = in;
1899   err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1900   if (err)
1901     return err;
1902   gpgsm->output_cb.data = out;
1903   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1904                       : map_data_enc (gpgsm->output_cb.data));
1905   if (err)
1906     return err;
1907   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1908   gpgsm->inline_data = NULL;
1909
1910   err = start (gpgsm, mode == GPGME_SIG_MODE_DETACH
1911                ? "SIGN --detached" : "SIGN");
1912   return err;
1913 }
1914
1915
1916 static gpgme_error_t
1917 gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
1918               gpgme_data_t plaintext, gpgme_ctx_t ctx)
1919 {
1920   engine_gpgsm_t gpgsm = engine;
1921   gpgme_error_t err;
1922
1923   (void)ctx;
1924
1925   if (!gpgsm)
1926     return gpg_error (GPG_ERR_INV_VALUE);
1927
1928   gpgsm->input_cb.data = sig;
1929   err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1930   if (err)
1931     return err;
1932   if (plaintext)
1933     {
1934       /* Normal or cleartext signature.  */
1935       gpgsm->output_cb.data = plaintext;
1936       err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1937       gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1938     }
1939   else
1940     {
1941       /* Detached signature.  */
1942       gpgsm->message_cb.data = signed_text;
1943       err = gpgsm_set_fd (gpgsm, MESSAGE_FD, 0);
1944       gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1945     }
1946   gpgsm->inline_data = NULL;
1947
1948   if (!err)
1949     err = start (gpgsm, "VERIFY");
1950
1951   return err;
1952 }
1953
1954
1955 /* Send the GETAUDITLOG command.  The result is saved to a gpgme data
1956    object.  */
1957 static gpgme_error_t
1958 gpgsm_getauditlog (void *engine, gpgme_data_t output, unsigned int flags)
1959 {
1960   engine_gpgsm_t gpgsm = engine;
1961   gpgme_error_t err = 0;
1962
1963   if (!gpgsm || !output)
1964     return gpg_error (GPG_ERR_INV_VALUE);
1965
1966 #if USE_DESCRIPTOR_PASSING
1967   gpgsm->output_cb.data = output;
1968   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1969   if (err)
1970     return err;
1971
1972   gpgsm_clear_fd (gpgsm, INPUT_FD);
1973   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1974   gpgsm->inline_data = NULL;
1975 # define CMD  "GETAUDITLOG"
1976 #else
1977   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1978   gpgsm_clear_fd (gpgsm, INPUT_FD);
1979   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1980   gpgsm->inline_data = output;
1981 # define CMD  "GETAUDITLOG --data"
1982 #endif
1983
1984   err = start (gpgsm, (flags & GPGME_AUDITLOG_HTML)? CMD " --html" : CMD);
1985
1986   return err;
1987 }
1988
1989
1990 /* This sets a status callback for monitoring status lines before they
1991  * are passed to a caller set handler.  */
1992 static void
1993 gpgsm_set_status_cb (void *engine, gpgme_status_cb_t cb, void *cb_value)
1994 {
1995   engine_gpgsm_t gpgsm = engine;
1996
1997   gpgsm->status.mon_cb = cb;
1998   gpgsm->status.mon_cb_value = cb_value;
1999 }
2000
2001
2002 static void
2003 gpgsm_set_status_handler (void *engine, engine_status_handler_t fnc,
2004                           void *fnc_value)
2005 {
2006   engine_gpgsm_t gpgsm = engine;
2007
2008   gpgsm->status.fnc = fnc;
2009   gpgsm->status.fnc_value = fnc_value;
2010 }
2011
2012
2013 static gpgme_error_t
2014 gpgsm_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
2015                               void *fnc_value)
2016 {
2017   engine_gpgsm_t gpgsm = engine;
2018
2019   gpgsm->colon.fnc = fnc;
2020   gpgsm->colon.fnc_value = fnc_value;
2021   gpgsm->colon.any = 0;
2022   return 0;
2023 }
2024
2025
2026 static void
2027 gpgsm_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
2028 {
2029   engine_gpgsm_t gpgsm = engine;
2030   gpgsm->io_cbs = *io_cbs;
2031 }
2032
2033
2034 static void
2035 gpgsm_io_event (void *engine, gpgme_event_io_t type, void *type_data)
2036 {
2037   engine_gpgsm_t gpgsm = engine;
2038
2039   TRACE3 (DEBUG_ENGINE, "gpgme:gpgsm_io_event", gpgsm,
2040           "event %p, type %d, type_data %p",
2041           gpgsm->io_cbs.event, type, type_data);
2042   if (gpgsm->io_cbs.event)
2043     (*gpgsm->io_cbs.event) (gpgsm->io_cbs.event_priv, type, type_data);
2044 }
2045
2046
2047 static gpgme_error_t
2048 gpgsm_passwd (void *engine, gpgme_key_t key, unsigned int flags)
2049 {
2050   engine_gpgsm_t gpgsm = engine;
2051   gpgme_error_t err;
2052   char *line;
2053
2054   (void)flags;
2055
2056   if (!key || !key->subkeys || !key->subkeys->fpr)
2057     return gpg_error (GPG_ERR_INV_CERT_OBJ);
2058
2059   if (gpgrt_asprintf (&line, "PASSWD -- %s", key->subkeys->fpr) < 0)
2060     return gpg_error_from_syserror ();
2061
2062   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
2063   gpgsm_clear_fd (gpgsm, INPUT_FD);
2064   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
2065   gpgsm->inline_data = NULL;
2066
2067   err = start (gpgsm, line);
2068   gpgrt_free (line);
2069
2070   return err;
2071 }
2072
2073
2074
2075 struct engine_ops _gpgme_engine_ops_gpgsm =
2076   {
2077     /* Static functions.  */
2078     _gpgme_get_default_gpgsm_name,
2079     NULL,
2080     gpgsm_get_version,
2081     gpgsm_get_req_version,
2082     gpgsm_new,
2083
2084     /* Member functions.  */
2085     gpgsm_release,
2086 #if USE_DESCRIPTOR_PASSING
2087     gpgsm_reset,
2088 #else
2089     NULL,                       /* reset */
2090 #endif
2091     gpgsm_set_status_cb,
2092     gpgsm_set_status_handler,
2093     NULL,               /* set_command_handler */
2094     gpgsm_set_colon_line_handler,
2095     gpgsm_set_locale,
2096     NULL,               /* set_protocol */
2097     gpgsm_decrypt,
2098     gpgsm_decrypt,
2099     gpgsm_delete,       /* decrypt_verify */
2100     NULL,               /* edit */
2101     gpgsm_encrypt,
2102     NULL,               /* encrypt_sign */
2103     gpgsm_export,
2104     gpgsm_export_ext,
2105     gpgsm_genkey,
2106     gpgsm_import,
2107     gpgsm_keylist,
2108     gpgsm_keylist_ext,
2109     NULL,               /* keylist_data */
2110     NULL,               /* keysign */
2111     NULL,               /* tofu_policy */
2112     gpgsm_sign,
2113     NULL,               /* trustlist */
2114     gpgsm_verify,
2115     gpgsm_getauditlog,
2116     NULL,               /* opassuan_transact */
2117     NULL,               /* conf_load */
2118     NULL,               /* conf_save */
2119     NULL,               /* query_swdb */
2120     gpgsm_set_io_cbs,
2121     gpgsm_io_event,
2122     gpgsm_cancel,
2123     NULL,               /* cancel_op */
2124     gpgsm_passwd,
2125     NULL,               /* set_pinentry_mode */
2126     NULL                /* opspawn */
2127   };