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