Fix regression with gpgsm 2.0 due to "OPTION with-secret".
[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)
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
1603
1604   /* Length is "LISTSECRETKEYS " + p + '\0'.  */
1605   line = malloc (15 + strlen (pattern) + 1);
1606   if (!line)
1607     return gpg_error_from_syserror ();
1608   if (secret_only)
1609     {
1610       strcpy (line, "LISTSECRETKEYS ");
1611       strcpy (&line[15], pattern);
1612     }
1613   else
1614     {
1615       strcpy (line, "LISTKEYS ");
1616       strcpy (&line[9], pattern);
1617     }
1618
1619   gpgsm_clear_fd (gpgsm, INPUT_FD);
1620   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1621   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1622   gpgsm->inline_data = NULL;
1623
1624   err = start (gpgsm, line);
1625   free (line);
1626   return err;
1627 }
1628
1629
1630 static gpgme_error_t
1631 gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
1632                    int reserved, gpgme_keylist_mode_t mode)
1633 {
1634   engine_gpgsm_t gpgsm = engine;
1635   char *line;
1636   gpgme_error_t err;
1637   /* Length is "LISTSECRETKEYS " + p + '\0'.  */
1638   int length = 15 + 1;
1639   char *linep;
1640   int any_pattern = 0;
1641   int list_mode = 0;
1642
1643   if (reserved)
1644     return gpg_error (GPG_ERR_INV_VALUE);
1645
1646   if (mode & GPGME_KEYLIST_MODE_LOCAL)
1647     list_mode |= 1;
1648   if (mode & GPGME_KEYLIST_MODE_EXTERN)
1649     list_mode |= 2;
1650
1651   /* Always send list-mode option because RESET does not reset it.  */
1652   if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1653     return gpg_error_from_syserror ();
1654   err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
1655   free (line);
1656   if (err)
1657     return err;
1658
1659   /* Always send key validation because RESET does not reset it.  */
1660   /* Use the validation mode if required.  We don't check for an error
1661      yet because this is a pretty fresh gpgsm features. */
1662   gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
1663                                (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1664                                "OPTION with-validation=1":
1665                                "OPTION with-validation=0" ,
1666                                NULL, NULL);
1667   gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
1668                                (mode & GPGME_KEYLIST_MODE_WITH_SECRET)?
1669                                "OPTION with-secret=1":
1670                                "OPTION with-secret=0" ,
1671                                NULL, NULL);
1672
1673
1674   if (pattern && *pattern)
1675     {
1676       const char **pat = pattern;
1677
1678       while (*pat)
1679         {
1680           const char *patlet = *pat;
1681
1682           while (*patlet)
1683             {
1684               length++;
1685               if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1686                 length += 2;
1687               patlet++;
1688             }
1689           pat++;
1690           length++;
1691         }
1692     }
1693   line = malloc (length);
1694   if (!line)
1695     return gpg_error_from_syserror ();
1696   if (secret_only)
1697     {
1698       strcpy (line, "LISTSECRETKEYS ");
1699       linep = &line[15];
1700     }
1701   else
1702     {
1703       strcpy (line, "LISTKEYS ");
1704       linep = &line[9];
1705     }
1706
1707   if (pattern && *pattern)
1708     {
1709       while (*pattern)
1710         {
1711           const char *patlet = *pattern;
1712
1713           while (*patlet)
1714             {
1715               switch (*patlet)
1716                 {
1717                 case '%':
1718                   *(linep++) = '%';
1719                   *(linep++) = '2';
1720                   *(linep++) = '5';
1721                   break;
1722                 case ' ':
1723                   *(linep++) = '%';
1724                   *(linep++) = '2';
1725                   *(linep++) = '0';
1726                   break;
1727                 case '+':
1728                   *(linep++) = '%';
1729                   *(linep++) = '2';
1730                   *(linep++) = 'B';
1731                   break;
1732                 default:
1733                   *(linep++) = *patlet;
1734                   break;
1735                 }
1736               patlet++;
1737             }
1738           any_pattern = 1;
1739           *linep++ = ' ';
1740           pattern++;
1741         }
1742     }
1743   if (any_pattern)
1744     linep--;
1745   *linep = '\0';
1746
1747   gpgsm_clear_fd (gpgsm, INPUT_FD);
1748   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1749   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1750   gpgsm->inline_data = NULL;
1751
1752   err = start (gpgsm, line);
1753   free (line);
1754   return err;
1755 }
1756
1757
1758 static gpgme_error_t
1759 gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
1760             gpgme_sig_mode_t mode, int use_armor, int use_textmode,
1761             int include_certs, gpgme_ctx_t ctx /* FIXME */)
1762 {
1763   engine_gpgsm_t gpgsm = engine;
1764   gpgme_error_t err;
1765   char *assuan_cmd;
1766   int i;
1767   gpgme_key_t key;
1768
1769   if (!gpgsm)
1770     return gpg_error (GPG_ERR_INV_VALUE);
1771
1772   /* FIXME: This does not work as RESET does not reset it so we can't
1773      revert back to default.  */
1774   if (include_certs != GPGME_INCLUDE_CERTS_DEFAULT)
1775     {
1776       /* FIXME: Make sure that if we run multiple operations, that we
1777          can reset any previously set value in case the default is
1778          requested.  */
1779
1780       if (asprintf (&assuan_cmd, "OPTION include-certs %i", include_certs) < 0)
1781         return gpg_error_from_syserror ();
1782       err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, assuan_cmd,
1783                                          NULL, NULL);
1784       free (assuan_cmd);
1785       if (err)
1786         return err;
1787     }
1788
1789   for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1790     {
1791       const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1792       if (s && strlen (s) < 80)
1793         {
1794           char buf[100];
1795
1796           strcpy (stpcpy (buf, "SIGNER "), s);
1797           err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, buf,
1798                                              gpgsm->status.fnc,
1799                                              gpgsm->status.fnc_value);
1800         }
1801       else
1802         err = gpg_error (GPG_ERR_INV_VALUE);
1803       gpgme_key_unref (key);
1804       if (err)
1805         return err;
1806     }
1807
1808   gpgsm->input_cb.data = in;
1809   err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1810   if (err)
1811     return err;
1812   gpgsm->output_cb.data = out;
1813   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1814                       : map_data_enc (gpgsm->output_cb.data));
1815   if (err)
1816     return err;
1817   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1818   gpgsm->inline_data = NULL;
1819
1820   err = start (gpgsm, mode == GPGME_SIG_MODE_DETACH
1821                ? "SIGN --detached" : "SIGN");
1822   return err;
1823 }
1824
1825
1826 static gpgme_error_t
1827 gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
1828               gpgme_data_t plaintext)
1829 {
1830   engine_gpgsm_t gpgsm = engine;
1831   gpgme_error_t err;
1832
1833   if (!gpgsm)
1834     return gpg_error (GPG_ERR_INV_VALUE);
1835
1836   gpgsm->input_cb.data = sig;
1837   err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1838   if (err)
1839     return err;
1840   if (plaintext)
1841     {
1842       /* Normal or cleartext signature.  */
1843       gpgsm->output_cb.data = plaintext;
1844       err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1845       gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1846     }
1847   else
1848     {
1849       /* Detached signature.  */
1850       gpgsm->message_cb.data = signed_text;
1851       err = gpgsm_set_fd (gpgsm, MESSAGE_FD, 0);
1852       gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1853     }
1854   gpgsm->inline_data = NULL;
1855
1856   if (!err)
1857     err = start (gpgsm, "VERIFY");
1858
1859   return err;
1860 }
1861
1862
1863 /* Send the GETAUDITLOG command.  The result is saved to a gpgme data
1864    object.  */
1865 static gpgme_error_t
1866 gpgsm_getauditlog (void *engine, gpgme_data_t output, unsigned int flags)
1867 {
1868   engine_gpgsm_t gpgsm = engine;
1869   gpgme_error_t err = 0;
1870
1871   if (!gpgsm || !output)
1872     return gpg_error (GPG_ERR_INV_VALUE);
1873
1874 #if USE_DESCRIPTOR_PASSING
1875   gpgsm->output_cb.data = output;
1876   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1877   if (err)
1878     return err;
1879
1880   gpgsm_clear_fd (gpgsm, INPUT_FD);
1881   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1882   gpgsm->inline_data = NULL;
1883 # define CMD  "GETAUDITLOG"
1884 #else
1885   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1886   gpgsm_clear_fd (gpgsm, INPUT_FD);
1887   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1888   gpgsm->inline_data = output;
1889 # define CMD  "GETAUDITLOG --data"
1890 #endif
1891
1892   err = start (gpgsm, (flags & GPGME_AUDITLOG_HTML)? CMD " --html" : CMD);
1893
1894   return err;
1895 }
1896
1897
1898
1899 static void
1900 gpgsm_set_status_handler (void *engine, engine_status_handler_t fnc,
1901                           void *fnc_value)
1902 {
1903   engine_gpgsm_t gpgsm = engine;
1904
1905   gpgsm->status.fnc = fnc;
1906   gpgsm->status.fnc_value = fnc_value;
1907 }
1908
1909
1910 static gpgme_error_t
1911 gpgsm_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
1912                               void *fnc_value)
1913 {
1914   engine_gpgsm_t gpgsm = engine;
1915
1916   gpgsm->colon.fnc = fnc;
1917   gpgsm->colon.fnc_value = fnc_value;
1918   gpgsm->colon.any = 0;
1919   return 0;
1920 }
1921
1922
1923 static void
1924 gpgsm_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
1925 {
1926   engine_gpgsm_t gpgsm = engine;
1927   gpgsm->io_cbs = *io_cbs;
1928 }
1929
1930
1931 static void
1932 gpgsm_io_event (void *engine, gpgme_event_io_t type, void *type_data)
1933 {
1934   engine_gpgsm_t gpgsm = engine;
1935
1936   TRACE3 (DEBUG_ENGINE, "gpgme:gpgsm_io_event", gpgsm,
1937           "event %p, type %d, type_data %p",
1938           gpgsm->io_cbs.event, type, type_data);
1939   if (gpgsm->io_cbs.event)
1940     (*gpgsm->io_cbs.event) (gpgsm->io_cbs.event_priv, type, type_data);
1941 }
1942
1943
1944 static gpgme_error_t
1945 gpgsm_passwd (void *engine, gpgme_key_t key, unsigned int flags)
1946 {
1947   engine_gpgsm_t gpgsm = engine;
1948   gpgme_error_t err;
1949   char *line;
1950
1951   if (!key || !key->subkeys || !key->subkeys->fpr)
1952     return gpg_error (GPG_ERR_INV_CERT_OBJ);
1953
1954   if (asprintf (&line, "PASSWD -- %s", key->subkeys->fpr) < 0)
1955     return gpg_error_from_syserror ();
1956
1957   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1958   gpgsm_clear_fd (gpgsm, INPUT_FD);
1959   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1960   gpgsm->inline_data = NULL;
1961
1962   err = start (gpgsm, line);
1963   free (line);
1964
1965   return err;
1966 }
1967
1968
1969
1970 struct engine_ops _gpgme_engine_ops_gpgsm =
1971   {
1972     /* Static functions.  */
1973     _gpgme_get_default_gpgsm_name,
1974     NULL,
1975     gpgsm_get_version,
1976     gpgsm_get_req_version,
1977     gpgsm_new,
1978
1979     /* Member functions.  */
1980     gpgsm_release,
1981 #if USE_DESCRIPTOR_PASSING
1982     gpgsm_reset,
1983 #else
1984     NULL,                       /* reset */
1985 #endif
1986     gpgsm_set_status_handler,
1987     NULL,               /* set_command_handler */
1988     gpgsm_set_colon_line_handler,
1989     gpgsm_set_locale,
1990     NULL,               /* set_protocol */
1991     gpgsm_decrypt,
1992     gpgsm_decrypt,
1993     gpgsm_delete,       /* decrypt_verify */
1994     NULL,               /* edit */
1995     gpgsm_encrypt,
1996     NULL,               /* encrypt_sign */
1997     gpgsm_export,
1998     gpgsm_export_ext,
1999     gpgsm_genkey,
2000     gpgsm_import,
2001     gpgsm_keylist,
2002     gpgsm_keylist_ext,
2003     gpgsm_sign,
2004     NULL,               /* trustlist */
2005     gpgsm_verify,
2006     gpgsm_getauditlog,
2007     NULL,               /* opassuan_transact */
2008     NULL,               /* conf_load */
2009     NULL,               /* conf_save */
2010     gpgsm_set_io_cbs,
2011     gpgsm_io_event,
2012     gpgsm_cancel,
2013     NULL,               /* cancel_op */
2014     gpgsm_passwd,
2015     NULL,               /* set_pinentry_mode */
2016     NULL                /* opspawn */
2017   };