1 /* engine-gpgsm.c - GpgSM engine.
2 Copyright (C) 2000 Werner Koch (dd9jn)
3 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009,
6 This file is part of GPGME.
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.
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.
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
29 #ifdef HAVE_SYS_TYPES_H
30 # include <sys/types.h>
39 #include <fcntl.h> /* FIXME */
51 #include "status-table.h"
54 #include "engine-backend.h"
59 int fd; /* FD we talk about. */
60 int server_fd;/* Server FD for this connection. */
61 int dir; /* Inbound/Outbound, maybe given implicit? */
62 void *data; /* Handler-specific data. */
63 void *tag; /* ID from the user for gpgme_remove_io_callback. */
64 char server_fd_str[15]; /* Same as SERVER_FD but as a string. We
65 need this because _gpgme_io_fd2str can't
66 be used on a closed descriptor. */
72 assuan_context_t assuan_ctx;
77 iocb_data_t status_cb;
79 /* Input, output etc are from the servers perspective. */
81 gpgme_data_t input_helper_data; /* Input helper data object. */
82 void *input_helper_memory; /* Input helper memory block. */
84 iocb_data_t output_cb;
86 iocb_data_t message_cb;
90 engine_status_handler_t fnc;
96 engine_colon_line_handler_t fnc;
104 int any; /* any data line seen */
107 gpgme_data_t inline_data; /* Used to collect D lines. */
109 struct gpgme_io_cbs io_cbs;
112 typedef struct engine_gpgsm *engine_gpgsm_t;
115 static void gpgsm_io_event (void *engine,
116 gpgme_event_io_t type, void *type_data);
121 gpgsm_get_version (const char *file_name)
123 return _gpgme_get_program_version (file_name ? file_name
124 : _gpgme_get_gpgsm_path ());
129 gpgsm_get_req_version (void)
131 return NEED_GPGSM_VERSION;
136 close_notify_handler (int fd, void *opaque)
138 engine_gpgsm_t gpgsm = opaque;
141 if (gpgsm->status_cb.fd == fd)
143 if (gpgsm->status_cb.tag)
144 (*gpgsm->io_cbs.remove) (gpgsm->status_cb.tag);
145 gpgsm->status_cb.fd = -1;
146 gpgsm->status_cb.tag = NULL;
148 else if (gpgsm->input_cb.fd == fd)
150 if (gpgsm->input_cb.tag)
151 (*gpgsm->io_cbs.remove) (gpgsm->input_cb.tag);
152 gpgsm->input_cb.fd = -1;
153 gpgsm->input_cb.tag = NULL;
154 if (gpgsm->input_helper_data)
156 gpgme_data_release (gpgsm->input_helper_data);
157 gpgsm->input_helper_data = NULL;
159 if (gpgsm->input_helper_memory)
161 free (gpgsm->input_helper_memory);
162 gpgsm->input_helper_memory = NULL;
165 else if (gpgsm->output_cb.fd == fd)
167 if (gpgsm->output_cb.tag)
168 (*gpgsm->io_cbs.remove) (gpgsm->output_cb.tag);
169 gpgsm->output_cb.fd = -1;
170 gpgsm->output_cb.tag = NULL;
172 else if (gpgsm->message_cb.fd == fd)
174 if (gpgsm->message_cb.tag)
175 (*gpgsm->io_cbs.remove) (gpgsm->message_cb.tag);
176 gpgsm->message_cb.fd = -1;
177 gpgsm->message_cb.tag = NULL;
182 /* This is the default inquiry callback. We use it to handle the
183 Pinentry notifications. */
185 default_inq_cb (engine_gpgsm_t gpgsm, const char *line)
187 if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
189 _gpgme_allow_set_foreground_window ((pid_t)strtoul (line+17, NULL, 10));
197 gpgsm_cancel (void *engine)
199 engine_gpgsm_t gpgsm = engine;
202 return gpg_error (GPG_ERR_INV_VALUE);
204 if (gpgsm->status_cb.fd != -1)
205 _gpgme_io_close (gpgsm->status_cb.fd);
206 if (gpgsm->input_cb.fd != -1)
207 _gpgme_io_close (gpgsm->input_cb.fd);
208 if (gpgsm->output_cb.fd != -1)
209 _gpgme_io_close (gpgsm->output_cb.fd);
210 if (gpgsm->message_cb.fd != -1)
211 _gpgme_io_close (gpgsm->message_cb.fd);
213 if (gpgsm->assuan_ctx)
215 assuan_release (gpgsm->assuan_ctx);
216 gpgsm->assuan_ctx = NULL;
224 gpgsm_release (void *engine)
226 engine_gpgsm_t gpgsm = engine;
231 gpgsm_cancel (engine);
233 free (gpgsm->colon.attic.line);
239 gpgsm_new (void **engine, const char *file_name, const char *home_dir)
241 gpgme_error_t err = 0;
242 engine_gpgsm_t gpgsm;
245 #if !USE_DESCRIPTOR_PASSING
249 char *dft_display = NULL;
250 char dft_ttyname[64];
251 char *dft_ttytype = NULL;
254 gpgsm = calloc (1, sizeof *gpgsm);
256 return gpg_error_from_syserror ();
258 gpgsm->status_cb.fd = -1;
259 gpgsm->status_cb.dir = 1;
260 gpgsm->status_cb.tag = 0;
261 gpgsm->status_cb.data = gpgsm;
263 gpgsm->input_cb.fd = -1;
264 gpgsm->input_cb.dir = 0;
265 gpgsm->input_cb.tag = 0;
266 gpgsm->input_cb.server_fd = -1;
267 *gpgsm->input_cb.server_fd_str = 0;
268 gpgsm->output_cb.fd = -1;
269 gpgsm->output_cb.dir = 1;
270 gpgsm->output_cb.tag = 0;
271 gpgsm->output_cb.server_fd = -1;
272 *gpgsm->output_cb.server_fd_str = 0;
273 gpgsm->message_cb.fd = -1;
274 gpgsm->message_cb.dir = 0;
275 gpgsm->message_cb.tag = 0;
276 gpgsm->message_cb.server_fd = -1;
277 *gpgsm->message_cb.server_fd_str = 0;
279 gpgsm->status.fnc = 0;
280 gpgsm->colon.fnc = 0;
281 gpgsm->colon.attic.line = 0;
282 gpgsm->colon.attic.linesize = 0;
283 gpgsm->colon.attic.linelen = 0;
284 gpgsm->colon.any = 0;
286 gpgsm->inline_data = NULL;
288 gpgsm->io_cbs.add = NULL;
289 gpgsm->io_cbs.add_priv = NULL;
290 gpgsm->io_cbs.remove = NULL;
291 gpgsm->io_cbs.event = NULL;
292 gpgsm->io_cbs.event_priv = NULL;
294 #if !USE_DESCRIPTOR_PASSING
295 if (_gpgme_io_pipe (fds, 0) < 0)
297 err = gpg_error_from_syserror ();
300 gpgsm->input_cb.fd = fds[1];
301 gpgsm->input_cb.server_fd = fds[0];
303 if (_gpgme_io_pipe (fds, 1) < 0)
305 err = gpg_error_from_syserror ();
308 gpgsm->output_cb.fd = fds[0];
309 gpgsm->output_cb.server_fd = fds[1];
311 if (_gpgme_io_pipe (fds, 0) < 0)
313 err = gpg_error_from_syserror ();
316 gpgsm->message_cb.fd = fds[1];
317 gpgsm->message_cb.server_fd = fds[0];
319 child_fds[0] = gpgsm->input_cb.server_fd;
320 child_fds[1] = gpgsm->output_cb.server_fd;
321 child_fds[2] = gpgsm->message_cb.server_fd;
326 argv[argc++] = "gpgsm";
329 argv[argc++] = "--homedir";
330 argv[argc++] = home_dir;
332 argv[argc++] = "--server";
335 err = assuan_new_ext (&gpgsm->assuan_ctx, GPG_ERR_SOURCE_GPGME,
336 &_gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb,
340 assuan_ctx_set_system_hooks (gpgsm->assuan_ctx, &_gpgme_assuan_system_hooks);
342 #if USE_DESCRIPTOR_PASSING
343 err = assuan_pipe_connect
344 (gpgsm->assuan_ctx, file_name ? file_name : _gpgme_get_gpgsm_path (),
345 argv, NULL, NULL, NULL, ASSUAN_PIPE_CONNECT_FDPASSING);
348 assuan_fd_t achild_fds[4];
352 for (i = 0; i < 4; i++)
353 achild_fds[i] = (assuan_fd_t) child_fds[i];
355 err = assuan_pipe_connect
356 (gpgsm->assuan_ctx, file_name ? file_name : _gpgme_get_gpgsm_path (),
357 argv, achild_fds, NULL, NULL, 0);
360 for (i = 0; i < 4; i++)
361 child_fds[i] = (int) achild_fds[i];
364 /* On Windows, handles are inserted in the spawned process with
365 DuplicateHandle, and child_fds contains the server-local names
366 for the inserted handles when assuan_pipe_connect returns. */
369 /* Note: We don't use _gpgme_io_fd2str here. On W32 the
370 returned handles are real W32 system handles, not whatever
371 GPGME uses internally (which may be a system handle, a C
372 library handle or a GLib/Qt channel. Confusing, yes, but
373 remember these are server-local names, so they are not part
375 snprintf (gpgsm->input_cb.server_fd_str,
376 sizeof gpgsm->input_cb.server_fd_str, "%d", child_fds[0]);
377 snprintf (gpgsm->output_cb.server_fd_str,
378 sizeof gpgsm->output_cb.server_fd_str, "%d", child_fds[1]);
379 snprintf (gpgsm->message_cb.server_fd_str,
380 sizeof gpgsm->message_cb.server_fd_str, "%d", child_fds[2]);
386 err = _gpgme_getenv ("DISPLAY", &dft_display);
391 if (asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
394 err = gpg_error_from_syserror ();
399 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
410 rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
413 err = gpg_error_from_errno (rc);
418 if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
420 err = gpg_error_from_syserror ();
423 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
429 err = _gpgme_getenv ("TERM", &dft_ttytype);
434 if (asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype) < 0)
437 err = gpg_error_from_syserror ();
442 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
443 NULL, NULL, NULL, NULL);
451 /* Ask gpgsm to enable the audit log support. */
454 err = assuan_transact (gpgsm->assuan_ctx, "OPTION enable-audit-log=1",
455 NULL, NULL, NULL, NULL, NULL, NULL);
456 if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
457 err = 0; /* This is an optional feature of gpgsm. */
461 #ifdef HAVE_W32_SYSTEM
462 /* Under Windows we need to use AllowSetForegroundWindow. Tell
463 gpgsm to tell us when it needs it. */
466 err = assuan_transact (gpgsm->assuan_ctx, "OPTION allow-pinentry-notify",
467 NULL, NULL, NULL, NULL, NULL, NULL);
468 if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
469 err = 0; /* This is a new feature of gpgsm. */
471 #endif /*HAVE_W32_SYSTEM*/
473 #if !USE_DESCRIPTOR_PASSING
475 && (_gpgme_io_set_close_notify (gpgsm->input_cb.fd,
476 close_notify_handler, gpgsm)
477 || _gpgme_io_set_close_notify (gpgsm->output_cb.fd,
478 close_notify_handler, gpgsm)
479 || _gpgme_io_set_close_notify (gpgsm->message_cb.fd,
480 close_notify_handler, gpgsm)))
482 err = gpg_error (GPG_ERR_GENERAL);
488 /* Close the server ends of the pipes (because of this, we must use
489 the stored server_fd_str in the function start). Our ends are
490 closed in gpgsm_release(). */
491 #if !USE_DESCRIPTOR_PASSING
492 if (gpgsm->input_cb.server_fd != -1)
493 _gpgme_io_close (gpgsm->input_cb.server_fd);
494 if (gpgsm->output_cb.server_fd != -1)
495 _gpgme_io_close (gpgsm->output_cb.server_fd);
496 if (gpgsm->message_cb.server_fd != -1)
497 _gpgme_io_close (gpgsm->message_cb.server_fd);
501 gpgsm_release (gpgsm);
510 gpgsm_set_locale (void *engine, int category, const char *value)
512 engine_gpgsm_t gpgsm = engine;
517 /* FIXME: If value is NULL, we need to reset the option to default.
518 But we can't do this. So we error out here. GPGSM needs support
523 else if (category == LC_CTYPE)
526 if (!value && gpgsm->lc_ctype_set)
527 return gpg_error (GPG_ERR_INV_VALUE);
529 gpgsm->lc_ctype_set = 1;
533 else if (category == LC_MESSAGES)
535 catstr = "lc-messages";
536 if (!value && gpgsm->lc_messages_set)
537 return gpg_error (GPG_ERR_INV_VALUE);
539 gpgsm->lc_messages_set = 1;
541 #endif /* LC_MESSAGES */
543 return gpg_error (GPG_ERR_INV_VALUE);
545 /* FIXME: Reset value to default. */
549 if (asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0)
550 err = gpg_error_from_syserror ();
553 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
554 NULL, NULL, NULL, NULL);
562 /* Forward declaration. */
563 static gpgme_status_code_t parse_status (const char *name);
566 gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd,
567 engine_status_handler_t status_fnc,
568 void *status_fnc_value)
574 err = assuan_write_line (ctx, cmd);
580 err = assuan_read_line (ctx, &line, &linelen);
584 if (*line == '#' || !linelen)
588 && line[0] == 'O' && line[1] == 'K'
589 && (line[2] == '\0' || line[2] == ' '))
591 else if (linelen >= 4
592 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
594 err = atoi (&line[4]);
595 else if (linelen >= 2
596 && line[0] == 'S' && line[1] == ' ')
599 gpgme_status_code_t r;
601 rest = strchr (line + 2, ' ');
603 rest = line + linelen; /* set to an empty string */
607 r = parse_status (line + 2);
609 if (r >= 0 && status_fnc)
610 err = status_fnc (status_fnc_value, r, rest);
612 err = gpg_error (GPG_ERR_GENERAL);
615 err = gpg_error (GPG_ERR_GENERAL);
623 typedef enum { INPUT_FD, OUTPUT_FD, MESSAGE_FD } fd_type_t;
626 gpgsm_clear_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type)
628 #if !USE_DESCRIPTOR_PASSING
632 _gpgme_io_close (gpgsm->input_cb.fd);
635 _gpgme_io_close (gpgsm->output_cb.fd);
638 _gpgme_io_close (gpgsm->message_cb.fd);
644 #define COMMANDLINELEN 40
646 gpgsm_set_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type, const char *opt)
649 char line[COMMANDLINELEN];
651 iocb_data_t *iocb_data;
658 iocb_data = &gpgsm->input_cb;
663 iocb_data = &gpgsm->output_cb;
668 iocb_data = &gpgsm->message_cb;
672 return gpg_error (GPG_ERR_INV_VALUE);
675 dir = iocb_data->dir;
677 #if USE_DESCRIPTOR_PASSING
678 /* We try to short-cut the communication by giving GPGSM direct
679 access to the file descriptor, rather than using a pipe. */
680 iocb_data->server_fd = _gpgme_data_get_fd (iocb_data->data);
681 if (iocb_data->server_fd < 0)
685 if (_gpgme_io_pipe (fds, dir) < 0)
686 return gpg_error_from_syserror ();
688 iocb_data->fd = dir ? fds[0] : fds[1];
689 iocb_data->server_fd = dir ? fds[1] : fds[0];
691 if (_gpgme_io_set_close_notify (iocb_data->fd,
692 close_notify_handler, gpgsm))
694 err = gpg_error (GPG_ERR_GENERAL);
699 err = assuan_sendfd (gpgsm->assuan_ctx, iocb_data->server_fd);
703 _gpgme_io_close (iocb_data->server_fd);
704 iocb_data->server_fd = -1;
707 snprintf (line, COMMANDLINELEN, "%s FD %s", which, opt);
709 snprintf (line, COMMANDLINELEN, "%s FD", which);
712 snprintf (line, COMMANDLINELEN, "%s FD=%s %s",
713 which, iocb_data->server_fd_str, opt);
715 snprintf (line, COMMANDLINELEN, "%s FD=%s",
716 which, iocb_data->server_fd_str);
719 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
721 #if USE_DESCRIPTOR_PASSING
725 _gpgme_io_close (iocb_data->fd);
727 if (iocb_data->server_fd != -1)
729 _gpgme_io_close (iocb_data->server_fd);
730 iocb_data->server_fd = -1;
740 map_data_enc (gpgme_data_t d)
742 switch (gpgme_data_get_encoding (d))
744 case GPGME_DATA_ENCODING_NONE:
746 case GPGME_DATA_ENCODING_BINARY:
748 case GPGME_DATA_ENCODING_BASE64:
750 case GPGME_DATA_ENCODING_ARMOR:
760 status_cmp (const void *ap, const void *bp)
762 const struct status_table_s *a = ap;
763 const struct status_table_s *b = bp;
765 return strcmp (a->name, b->name);
769 static gpgme_status_code_t
770 parse_status (const char *name)
772 struct status_table_s t, *r;
774 r = bsearch (&t, status_table, DIM(status_table) - 1,
775 sizeof t, status_cmp);
776 return r ? r->code : -1;
781 status_handler (void *opaque, int fd)
783 struct io_cb_data *data = (struct io_cb_data *) opaque;
784 engine_gpgsm_t gpgsm = (engine_gpgsm_t) data->handler_value;
785 gpgme_error_t err = 0;
791 err = assuan_read_line (gpgsm->assuan_ctx, &line, &linelen);
794 /* Try our best to terminate the connection friendly. */
795 /* assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
796 TRACE3 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
797 "fd 0x%x: error from assuan (%d) getting status line : %s",
798 fd, err, gpg_strerror (err));
800 else if (linelen >= 3
801 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
802 && (line[3] == '\0' || line[3] == ' '))
805 err = atoi (&line[4]);
807 err = gpg_error (GPG_ERR_GENERAL);
808 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
809 "fd 0x%x: ERR line - mapped to: %s",
810 fd, err ? gpg_strerror (err) : "ok");
811 /* Try our best to terminate the connection friendly. */
812 /* assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
814 else if (linelen >= 2
815 && line[0] == 'O' && line[1] == 'K'
816 && (line[2] == '\0' || line[2] == ' '))
818 if (gpgsm->status.fnc)
819 err = gpgsm->status.fnc (gpgsm->status.fnc_value,
820 GPGME_STATUS_EOF, "");
822 if (!err && gpgsm->colon.fnc && gpgsm->colon.any)
824 /* We must tell a colon function about the EOF. We do
825 this only when we have seen any data lines. Note
826 that this inlined use of colon data lines will
827 eventually be changed into using a regular data
829 gpgsm->colon.any = 0;
830 err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, NULL);
832 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
833 "fd 0x%x: OK line - final status: %s",
834 fd, err ? gpg_strerror (err) : "ok");
835 _gpgme_io_close (gpgsm->status_cb.fd);
839 && line[0] == 'D' && line[1] == ' '
842 /* We are using the colon handler even for plain inline data
843 - strange name for that function but for historic reasons
845 /* FIXME We can't use this for binary data because we
846 assume this is a string. For the current usage of colon
847 output it is correct. */
848 char *src = line + 2;
849 char *end = line + linelen;
851 char **aline = &gpgsm->colon.attic.line;
852 int *alinelen = &gpgsm->colon.attic.linelen;
854 if (gpgsm->colon.attic.linesize < *alinelen + linelen + 1)
856 char *newline = realloc (*aline, *alinelen + linelen + 1);
858 err = gpg_error_from_syserror ();
862 gpgsm->colon.attic.linesize += linelen + 1;
867 dst = *aline + *alinelen;
869 while (!err && src < end)
871 if (*src == '%' && src + 2 < end)
873 /* Handle escaped characters. */
875 *dst = _gpgme_hextobyte (src);
887 /* Terminate the pending line, pass it to the colon
888 handler and reset it. */
890 gpgsm->colon.any = 1;
891 if (*alinelen > 1 && *(dst - 1) == '\r')
895 /* FIXME How should we handle the return code? */
896 err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, *aline);
907 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
908 "fd 0x%x: D line; final status: %s",
909 fd, err? gpg_strerror (err):"ok");
912 && line[0] == 'D' && line[1] == ' '
913 && gpgsm->inline_data)
915 char *src = line + 2;
916 char *end = line + linelen;
923 if (*src == '%' && src + 2 < end)
925 /* Handle escaped characters. */
927 *dst++ = _gpgme_hextobyte (src);
939 nwritten = gpgme_data_write (gpgsm->inline_data, src, linelen);
940 if (!nwritten || (nwritten < 0 && errno != EINTR)
941 || nwritten > linelen)
943 err = gpg_error_from_syserror ();
950 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
951 "fd 0x%x: D inlinedata; final status: %s",
952 fd, err? gpg_strerror (err):"ok");
955 && line[0] == 'S' && line[1] == ' ')
958 gpgme_status_code_t r;
960 rest = strchr (line + 2, ' ');
962 rest = line + linelen; /* set to an empty string */
966 r = parse_status (line + 2);
970 if (gpgsm->status.fnc)
971 err = gpgsm->status.fnc (gpgsm->status.fnc_value, r, rest);
974 fprintf (stderr, "[UNKNOWN STATUS]%s %s", line + 2, rest);
975 TRACE3 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
976 "fd 0x%x: S line (%s) - final status: %s",
977 fd, line+2, err? gpg_strerror (err):"ok");
979 else if (linelen >= 7
980 && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
981 && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
983 && (line[7] == '\0' || line[7] == ' '))
985 char *keyword = line+7;
987 while (*keyword == ' ')
989 default_inq_cb (gpgsm, keyword);
990 assuan_write_line (gpgsm->assuan_ctx, "END");
994 while (!err && assuan_pending_line (gpgsm->assuan_ctx));
1000 static gpgme_error_t
1001 add_io_cb (engine_gpgsm_t gpgsm, iocb_data_t *iocbd, gpgme_io_cb_t handler)
1005 TRACE_BEG2 (DEBUG_ENGINE, "engine-gpgsm:add_io_cb", gpgsm,
1006 "fd %d, dir %d", iocbd->fd, iocbd->dir);
1007 err = (*gpgsm->io_cbs.add) (gpgsm->io_cbs.add_priv,
1008 iocbd->fd, iocbd->dir,
1009 handler, iocbd->data, &iocbd->tag);
1011 return TRACE_ERR (err);
1013 /* FIXME Kludge around poll() problem. */
1014 err = _gpgme_io_set_nonblocking (iocbd->fd);
1015 return TRACE_ERR (err);
1019 static gpgme_error_t
1020 start (engine_gpgsm_t gpgsm, const char *command)
1023 assuan_fd_t afdlist[5];
1028 /* We need to know the fd used by assuan for reads. We do this by
1029 using the assumption that the first returned fd from
1030 assuan_get_active_fds() is always this one. */
1031 nfds = assuan_get_active_fds (gpgsm->assuan_ctx, 0 /* read fds */,
1032 afdlist, DIM (afdlist));
1034 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1036 for (i = 0; i < nfds; i++)
1037 fdlist[i] = (int) afdlist[i];
1039 /* We "duplicate" the file descriptor, so we can close it here (we
1040 can't close fdlist[0], as that is closed by libassuan, and
1041 closing it here might cause libassuan to close some unrelated FD
1042 later). Alternatively, we could special case status_fd and
1043 register/unregister it manually as needed, but this increases
1044 code duplication and is more complicated as we can not use the
1045 close notifications etc. A third alternative would be to let
1046 Assuan know that we closed the FD, but that complicates the
1047 Assuan interface. */
1049 gpgsm->status_cb.fd = _gpgme_io_dup (fdlist[0]);
1050 if (gpgsm->status_cb.fd < 0)
1051 return gpg_error_from_syserror ();
1053 if (_gpgme_io_set_close_notify (gpgsm->status_cb.fd,
1054 close_notify_handler, gpgsm))
1056 _gpgme_io_close (gpgsm->status_cb.fd);
1057 gpgsm->status_cb.fd = -1;
1058 return gpg_error (GPG_ERR_GENERAL);
1061 err = add_io_cb (gpgsm, &gpgsm->status_cb, status_handler);
1062 if (!err && gpgsm->input_cb.fd != -1)
1063 err = add_io_cb (gpgsm, &gpgsm->input_cb, _gpgme_data_outbound_handler);
1064 if (!err && gpgsm->output_cb.fd != -1)
1065 err = add_io_cb (gpgsm, &gpgsm->output_cb, _gpgme_data_inbound_handler);
1066 if (!err && gpgsm->message_cb.fd != -1)
1067 err = add_io_cb (gpgsm, &gpgsm->message_cb, _gpgme_data_outbound_handler);
1070 err = assuan_write_line (gpgsm->assuan_ctx, command);
1073 gpgsm_io_event (gpgsm, GPGME_EVENT_START, NULL);
1079 #if USE_DESCRIPTOR_PASSING
1080 static gpgme_error_t
1081 gpgsm_reset (void *engine)
1083 engine_gpgsm_t gpgsm = engine;
1085 /* IF we have an active connection we must send a reset because we
1086 need to reset the list of signers. Note that RESET does not
1087 reset OPTION commands. */
1088 return (gpgsm->assuan_ctx
1089 ? gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "RESET",
1097 static gpgme_error_t
1098 gpgsm_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
1100 engine_gpgsm_t gpgsm = engine;
1104 return gpg_error (GPG_ERR_INV_VALUE);
1106 gpgsm->input_cb.data = ciph;
1107 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1109 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1110 gpgsm->output_cb.data = plain;
1111 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1113 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1114 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1115 gpgsm->inline_data = NULL;
1117 err = start (engine, "DECRYPT");
1122 static gpgme_error_t
1123 gpgsm_delete (void *engine, gpgme_key_t key, int allow_secret)
1125 engine_gpgsm_t gpgsm = engine;
1127 char *fpr = key->subkeys ? key->subkeys->fpr : NULL;
1130 int length = 8; /* "DELKEYS " */
1133 return gpg_error (GPG_ERR_INV_VALUE);
1138 if (*linep == '%' || *linep == ' ' || *linep == '+')
1144 line = malloc (length);
1146 return gpg_error_from_syserror ();
1148 strcpy (line, "DELKEYS ");
1178 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1179 gpgsm_clear_fd (gpgsm, INPUT_FD);
1180 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1181 gpgsm->inline_data = NULL;
1183 err = start (gpgsm, line);
1190 static gpgme_error_t
1191 set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[])
1193 gpgme_error_t err = 0;
1194 assuan_context_t ctx = gpgsm->assuan_ctx;
1197 int invalid_recipients = 0;
1200 linelen = 10 + 40 + 1; /* "RECIPIENT " + guess + '\0'. */
1201 line = malloc (10 + 40 + 1);
1203 return gpg_error_from_syserror ();
1204 strcpy (line, "RECIPIENT ");
1205 for (i =0; !err && recp[i]; i++)
1210 if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
1212 invalid_recipients++;
1215 fpr = recp[i]->subkeys->fpr;
1217 newlen = 11 + strlen (fpr);
1218 if (linelen < newlen)
1220 char *newline = realloc (line, newlen);
1223 int saved_errno = errno;
1225 return gpg_error_from_errno (saved_errno);
1230 strcpy (&line[10], fpr);
1232 err = gpgsm_assuan_simple_command (ctx, line, gpgsm->status.fnc,
1233 gpgsm->status.fnc_value);
1234 /* FIXME: This requires more work. */
1235 if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
1236 invalid_recipients++;
1244 return gpg_error (invalid_recipients
1245 ? GPG_ERR_UNUSABLE_PUBKEY : GPG_ERR_NO_ERROR);
1249 static gpgme_error_t
1250 gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
1251 gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
1253 engine_gpgsm_t gpgsm = engine;
1257 return gpg_error (GPG_ERR_INV_VALUE);
1259 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1261 if (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO)
1263 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
1264 "OPTION no-encrypt-to", NULL, NULL);
1269 gpgsm->input_cb.data = plain;
1270 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1273 gpgsm->output_cb.data = ciph;
1274 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1275 : map_data_enc (gpgsm->output_cb.data));
1278 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1279 gpgsm->inline_data = NULL;
1281 err = set_recipients (gpgsm, recp);
1284 err = start (gpgsm, "ENCRYPT");
1290 static gpgme_error_t
1291 gpgsm_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
1292 gpgme_data_t keydata, int use_armor)
1294 engine_gpgsm_t gpgsm = engine;
1295 gpgme_error_t err = 0;
1299 return gpg_error (GPG_ERR_INV_VALUE);
1302 return gpg_error (GPG_ERR_NOT_SUPPORTED);
1307 cmd = malloc (7 + strlen (pattern) + 1);
1309 return gpg_error_from_syserror ();
1310 strcpy (cmd, "EXPORT ");
1311 strcpy (&cmd[7], pattern);
1313 gpgsm->output_cb.data = keydata;
1314 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1315 : map_data_enc (gpgsm->output_cb.data));
1318 gpgsm_clear_fd (gpgsm, INPUT_FD);
1319 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1320 gpgsm->inline_data = NULL;
1322 err = start (gpgsm, cmd);
1328 static gpgme_error_t
1329 gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
1330 gpgme_data_t keydata, int use_armor)
1332 engine_gpgsm_t gpgsm = engine;
1333 gpgme_error_t err = 0;
1335 /* Length is "EXPORT " + p + '\0'. */
1340 return gpg_error (GPG_ERR_INV_VALUE);
1343 return gpg_error (GPG_ERR_NOT_SUPPORTED);
1345 if (pattern && *pattern)
1347 const char **pat = pattern;
1351 const char *patlet = *pat;
1356 if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1364 line = malloc (length);
1366 return gpg_error_from_syserror ();
1368 strcpy (line, "EXPORT ");
1371 if (pattern && *pattern)
1375 const char *patlet = *pattern;
1397 *(linep++) = *patlet;
1409 gpgsm->output_cb.data = keydata;
1410 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1411 : map_data_enc (gpgsm->output_cb.data));
1414 gpgsm_clear_fd (gpgsm, INPUT_FD);
1415 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1416 gpgsm->inline_data = NULL;
1418 err = start (gpgsm, line);
1424 static gpgme_error_t
1425 gpgsm_genkey (void *engine, gpgme_data_t help_data, int use_armor,
1426 gpgme_data_t pubkey, gpgme_data_t seckey)
1428 engine_gpgsm_t gpgsm = engine;
1431 if (!gpgsm || !pubkey || seckey)
1432 return gpg_error (GPG_ERR_INV_VALUE);
1434 gpgsm->input_cb.data = help_data;
1435 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1438 gpgsm->output_cb.data = pubkey;
1439 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1440 : map_data_enc (gpgsm->output_cb.data));
1443 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1444 gpgsm->inline_data = NULL;
1446 err = start (gpgsm, "GENKEY");
1451 static gpgme_error_t
1452 gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
1454 engine_gpgsm_t gpgsm = engine;
1456 gpgme_data_encoding_t dataenc;
1460 return gpg_error (GPG_ERR_INV_VALUE);
1462 if (keydata && keyarray)
1463 return gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed. */
1465 dataenc = gpgme_data_get_encoding (keydata);
1472 /* Fist check whether the engine already features the
1473 --re-import option. */
1474 err = gpgsm_assuan_simple_command
1476 "GETINFO cmd_has_option IMPORT re-import", NULL, NULL);
1478 return gpg_error (GPG_ERR_NOT_SUPPORTED);
1480 /* Create an internal data object with a list of all
1481 fingerprints. The data object and its memory (to avoid an
1482 extra copy by gpgme_data_new_from_mem) are stored in two
1483 variables which are released by the close_notify_handler. */
1484 for (idx=0, buflen=0; keyarray[idx]; idx++)
1486 if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
1487 && keyarray[idx]->subkeys
1488 && keyarray[idx]->subkeys->fpr
1489 && *keyarray[idx]->subkeys->fpr)
1490 buflen += strlen (keyarray[idx]->subkeys->fpr) + 1;
1492 /* Allocate a bufer with extra space for the trailing Nul
1493 introduced by the use of stpcpy. */
1494 buffer = malloc (buflen+1);
1496 return gpg_error_from_syserror ();
1497 for (idx=0, p = buffer; keyarray[idx]; idx++)
1499 if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
1500 && keyarray[idx]->subkeys
1501 && keyarray[idx]->subkeys->fpr
1502 && *keyarray[idx]->subkeys->fpr)
1503 p = stpcpy (stpcpy (p, keyarray[idx]->subkeys->fpr), "\n");
1506 err = gpgme_data_new_from_mem (&gpgsm->input_helper_data,
1513 gpgsm->input_helper_memory = buffer;
1515 gpgsm->input_cb.data = gpgsm->input_helper_data;
1516 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1519 gpgme_data_release (gpgsm->input_helper_data);
1520 gpgsm->input_helper_data = NULL;
1521 free (gpgsm->input_helper_memory);
1522 gpgsm->input_helper_memory = NULL;
1525 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1526 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1527 gpgsm->inline_data = NULL;
1529 return start (gpgsm, "IMPORT --re-import");
1531 else if (dataenc == GPGME_DATA_ENCODING_URL
1532 || dataenc == GPGME_DATA_ENCODING_URL0
1533 || dataenc == GPGME_DATA_ENCODING_URLESC)
1535 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1539 gpgsm->input_cb.data = keydata;
1540 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1543 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1544 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1545 gpgsm->inline_data = NULL;
1547 return start (gpgsm, "IMPORT");
1552 static gpgme_error_t
1553 gpgsm_keylist (void *engine, const char *pattern, int secret_only,
1554 gpgme_keylist_mode_t mode)
1556 engine_gpgsm_t gpgsm = engine;
1561 if (mode & GPGME_KEYLIST_MODE_LOCAL)
1563 if (mode & GPGME_KEYLIST_MODE_EXTERN)
1569 /* Hack to make sure that the agent is started. Only if the agent
1570 has been started an application may connect to the agent via
1571 GPGME_PROTOCOL_ASSUAN - for example to look for smartcards. We
1572 do this only if a secret key listing has been requested. In
1573 general this is not needed because a secret key listing starts
1574 the agent. However on a fresh installation no public keys are
1575 available and thus there is no need for gpgsm to ask the agent
1576 whether a secret key exists for the public key. */
1578 gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "GETINFO agent-check",
1581 /* Always send list-mode option because RESET does not reset it. */
1582 if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1583 return gpg_error_from_syserror ();
1584 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
1590 /* Always send key validation because RESET does not reset it. */
1592 /* Use the validation mode if requested. We don't check for an error
1593 yet because this is a pretty fresh gpgsm features. */
1594 gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
1595 (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1596 "OPTION with-validation=1":
1597 "OPTION with-validation=0" ,
1599 /* Include the ephemeral keys if requested. We don't check for an error
1600 yet because this is a pretty fresh gpgsm features. */
1601 gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
1602 (mode & GPGME_KEYLIST_MODE_EPHEMERAL)?
1603 "OPTION with-ephemeral-keys=1":
1604 "OPTION with-ephemeral-keys=0" ,
1608 /* Length is "LISTSECRETKEYS " + p + '\0'. */
1609 line = malloc (15 + strlen (pattern) + 1);
1611 return gpg_error_from_syserror ();
1614 strcpy (line, "LISTSECRETKEYS ");
1615 strcpy (&line[15], pattern);
1619 strcpy (line, "LISTKEYS ");
1620 strcpy (&line[9], pattern);
1623 gpgsm_clear_fd (gpgsm, INPUT_FD);
1624 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1625 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1626 gpgsm->inline_data = NULL;
1628 err = start (gpgsm, line);
1634 static gpgme_error_t
1635 gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
1636 int reserved, gpgme_keylist_mode_t mode)
1638 engine_gpgsm_t gpgsm = engine;
1641 /* Length is "LISTSECRETKEYS " + p + '\0'. */
1642 int length = 15 + 1;
1644 int any_pattern = 0;
1648 return gpg_error (GPG_ERR_INV_VALUE);
1650 if (mode & GPGME_KEYLIST_MODE_LOCAL)
1652 if (mode & GPGME_KEYLIST_MODE_EXTERN)
1655 /* Always send list-mode option because RESET does not reset it. */
1656 if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1657 return gpg_error_from_syserror ();
1658 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
1663 /* Always send key validation because RESET does not reset it. */
1664 /* Use the validation mode if required. We don't check for an error
1665 yet because this is a pretty fresh gpgsm features. */
1666 gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
1667 (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1668 "OPTION with-validation=1":
1669 "OPTION with-validation=0" ,
1673 if (pattern && *pattern)
1675 const char **pat = pattern;
1679 const char *patlet = *pat;
1684 if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1692 line = malloc (length);
1694 return gpg_error_from_syserror ();
1697 strcpy (line, "LISTSECRETKEYS ");
1702 strcpy (line, "LISTKEYS ");
1706 if (pattern && *pattern)
1710 const char *patlet = *pattern;
1732 *(linep++) = *patlet;
1746 gpgsm_clear_fd (gpgsm, INPUT_FD);
1747 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1748 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1749 gpgsm->inline_data = NULL;
1751 err = start (gpgsm, line);
1757 static gpgme_error_t
1758 gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
1759 gpgme_sig_mode_t mode, int use_armor, int use_textmode,
1760 int include_certs, gpgme_ctx_t ctx /* FIXME */)
1762 engine_gpgsm_t gpgsm = engine;
1769 return gpg_error (GPG_ERR_INV_VALUE);
1771 /* FIXME: This does not work as RESET does not reset it so we can't
1772 revert back to default. */
1773 if (include_certs != GPGME_INCLUDE_CERTS_DEFAULT)
1775 /* FIXME: Make sure that if we run multiple operations, that we
1776 can reset any previously set value in case the default is
1779 if (asprintf (&assuan_cmd, "OPTION include-certs %i", include_certs) < 0)
1780 return gpg_error_from_syserror ();
1781 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, assuan_cmd,
1788 for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1790 const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1791 if (s && strlen (s) < 80)
1795 strcpy (stpcpy (buf, "SIGNER "), s);
1796 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, buf,
1798 gpgsm->status.fnc_value);
1801 err = gpg_error (GPG_ERR_INV_VALUE);
1802 gpgme_key_unref (key);
1807 gpgsm->input_cb.data = in;
1808 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1811 gpgsm->output_cb.data = out;
1812 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1813 : map_data_enc (gpgsm->output_cb.data));
1816 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1817 gpgsm->inline_data = NULL;
1819 err = start (gpgsm, mode == GPGME_SIG_MODE_DETACH
1820 ? "SIGN --detached" : "SIGN");
1825 static gpgme_error_t
1826 gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
1827 gpgme_data_t plaintext)
1829 engine_gpgsm_t gpgsm = engine;
1833 return gpg_error (GPG_ERR_INV_VALUE);
1835 gpgsm->input_cb.data = sig;
1836 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1841 /* Normal or cleartext signature. */
1842 gpgsm->output_cb.data = plaintext;
1843 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1844 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1848 /* Detached signature. */
1849 gpgsm->message_cb.data = signed_text;
1850 err = gpgsm_set_fd (gpgsm, MESSAGE_FD, 0);
1851 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1853 gpgsm->inline_data = NULL;
1856 err = start (gpgsm, "VERIFY");
1862 /* Send the GETAUDITLOG command. The result is saved to a gpgme data
1864 static gpgme_error_t
1865 gpgsm_getauditlog (void *engine, gpgme_data_t output, unsigned int flags)
1867 engine_gpgsm_t gpgsm = engine;
1868 gpgme_error_t err = 0;
1870 if (!gpgsm || !output)
1871 return gpg_error (GPG_ERR_INV_VALUE);
1873 #if USE_DESCRIPTOR_PASSING
1874 gpgsm->output_cb.data = output;
1875 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1879 gpgsm_clear_fd (gpgsm, INPUT_FD);
1880 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1881 gpgsm->inline_data = NULL;
1882 # define CMD "GETAUDITLOG"
1884 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1885 gpgsm_clear_fd (gpgsm, INPUT_FD);
1886 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1887 gpgsm->inline_data = output;
1888 # define CMD "GETAUDITLOG --data"
1891 err = start (gpgsm, (flags & GPGME_AUDITLOG_HTML)? CMD " --html" : CMD);
1899 gpgsm_set_status_handler (void *engine, engine_status_handler_t fnc,
1902 engine_gpgsm_t gpgsm = engine;
1904 gpgsm->status.fnc = fnc;
1905 gpgsm->status.fnc_value = fnc_value;
1909 static gpgme_error_t
1910 gpgsm_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
1913 engine_gpgsm_t gpgsm = engine;
1915 gpgsm->colon.fnc = fnc;
1916 gpgsm->colon.fnc_value = fnc_value;
1917 gpgsm->colon.any = 0;
1923 gpgsm_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
1925 engine_gpgsm_t gpgsm = engine;
1926 gpgsm->io_cbs = *io_cbs;
1931 gpgsm_io_event (void *engine, gpgme_event_io_t type, void *type_data)
1933 engine_gpgsm_t gpgsm = engine;
1935 TRACE3 (DEBUG_ENGINE, "gpgme:gpgsm_io_event", gpgsm,
1936 "event %p, type %d, type_data %p",
1937 gpgsm->io_cbs.event, type, type_data);
1938 if (gpgsm->io_cbs.event)
1939 (*gpgsm->io_cbs.event) (gpgsm->io_cbs.event_priv, type, type_data);
1943 static gpgme_error_t
1944 gpgsm_passwd (void *engine, gpgme_key_t key, unsigned int flags)
1946 engine_gpgsm_t gpgsm = engine;
1950 if (!key || !key->subkeys || !key->subkeys->fpr)
1951 return gpg_error (GPG_ERR_INV_CERT_OBJ);
1953 if (asprintf (&line, "PASSWD -- %s", key->subkeys->fpr) < 0)
1954 return gpg_error_from_syserror ();
1956 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1957 gpgsm_clear_fd (gpgsm, INPUT_FD);
1958 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1959 gpgsm->inline_data = NULL;
1961 err = start (gpgsm, line);
1969 struct engine_ops _gpgme_engine_ops_gpgsm =
1971 /* Static functions. */
1972 _gpgme_get_gpgsm_path,
1975 gpgsm_get_req_version,
1978 /* Member functions. */
1980 #if USE_DESCRIPTOR_PASSING
1985 gpgsm_set_status_handler,
1986 NULL, /* set_command_handler */
1987 gpgsm_set_colon_line_handler,
1989 NULL, /* set_protocol */
1992 gpgsm_delete, /* decrypt_verify */
1995 NULL, /* encrypt_sign */
2003 NULL, /* trustlist */
2006 NULL, /* opassuan_transact */
2007 NULL, /* conf_load */
2008 NULL, /* conf_save */
2012 NULL, /* cancel_op */