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