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