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 */
53 #include "engine-backend.h"
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. */
71 assuan_context_t assuan_ctx;
76 iocb_data_t status_cb;
78 /* Input, output etc are from the servers perspective. */
80 gpgme_data_t input_helper_data; /* Input helper data object. */
81 void *input_helper_memory; /* Input helper memory block. */
83 iocb_data_t output_cb;
85 iocb_data_t message_cb;
89 engine_status_handler_t fnc;
95 engine_colon_line_handler_t fnc;
103 int any; /* any data line seen */
106 gpgme_data_t inline_data; /* Used to collect D lines. */
108 struct gpgme_io_cbs io_cbs;
111 typedef struct engine_gpgsm *engine_gpgsm_t;
114 static void gpgsm_io_event (void *engine,
115 gpgme_event_io_t type, void *type_data);
120 gpgsm_get_version (const char *file_name)
122 return _gpgme_get_program_version (file_name ? file_name
123 : _gpgme_get_gpgsm_path ());
128 gpgsm_get_req_version (void)
130 return NEED_GPGSM_VERSION;
135 close_notify_handler (int fd, void *opaque)
137 engine_gpgsm_t gpgsm = opaque;
140 if (gpgsm->status_cb.fd == fd)
142 if (gpgsm->status_cb.tag)
143 (*gpgsm->io_cbs.remove) (gpgsm->status_cb.tag);
144 gpgsm->status_cb.fd = -1;
145 gpgsm->status_cb.tag = NULL;
147 else if (gpgsm->input_cb.fd == fd)
149 if (gpgsm->input_cb.tag)
150 (*gpgsm->io_cbs.remove) (gpgsm->input_cb.tag);
151 gpgsm->input_cb.fd = -1;
152 gpgsm->input_cb.tag = NULL;
153 if (gpgsm->input_helper_data)
155 gpgme_data_release (gpgsm->input_helper_data);
156 gpgsm->input_helper_data = NULL;
158 if (gpgsm->input_helper_memory)
160 free (gpgsm->input_helper_memory);
161 gpgsm->input_helper_memory = NULL;
164 else if (gpgsm->output_cb.fd == fd)
166 if (gpgsm->output_cb.tag)
167 (*gpgsm->io_cbs.remove) (gpgsm->output_cb.tag);
168 gpgsm->output_cb.fd = -1;
169 gpgsm->output_cb.tag = NULL;
171 else if (gpgsm->message_cb.fd == fd)
173 if (gpgsm->message_cb.tag)
174 (*gpgsm->io_cbs.remove) (gpgsm->message_cb.tag);
175 gpgsm->message_cb.fd = -1;
176 gpgsm->message_cb.tag = NULL;
181 /* This is the default inquiry callback. We use it to handle the
182 Pinentry notifications. */
184 default_inq_cb (engine_gpgsm_t gpgsm, const char *line)
186 if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
188 _gpgme_allow_set_foreground_window ((pid_t)strtoul (line+17, NULL, 10));
196 gpgsm_cancel (void *engine)
198 engine_gpgsm_t gpgsm = engine;
201 return gpg_error (GPG_ERR_INV_VALUE);
203 if (gpgsm->status_cb.fd != -1)
204 _gpgme_io_close (gpgsm->status_cb.fd);
205 if (gpgsm->input_cb.fd != -1)
206 _gpgme_io_close (gpgsm->input_cb.fd);
207 if (gpgsm->output_cb.fd != -1)
208 _gpgme_io_close (gpgsm->output_cb.fd);
209 if (gpgsm->message_cb.fd != -1)
210 _gpgme_io_close (gpgsm->message_cb.fd);
212 if (gpgsm->assuan_ctx)
214 assuan_release (gpgsm->assuan_ctx);
215 gpgsm->assuan_ctx = NULL;
223 gpgsm_release (void *engine)
225 engine_gpgsm_t gpgsm = engine;
230 gpgsm_cancel (engine);
232 free (gpgsm->colon.attic.line);
238 gpgsm_new (void **engine, const char *file_name, const char *home_dir)
240 gpgme_error_t err = 0;
241 engine_gpgsm_t gpgsm;
244 #if !USE_DESCRIPTOR_PASSING
248 char *dft_display = NULL;
249 char dft_ttyname[64];
250 char *dft_ttytype = NULL;
253 gpgsm = calloc (1, sizeof *gpgsm);
255 return gpg_error_from_syserror ();
257 gpgsm->status_cb.fd = -1;
258 gpgsm->status_cb.dir = 1;
259 gpgsm->status_cb.tag = 0;
260 gpgsm->status_cb.data = gpgsm;
262 gpgsm->input_cb.fd = -1;
263 gpgsm->input_cb.dir = 0;
264 gpgsm->input_cb.tag = 0;
265 gpgsm->input_cb.server_fd = -1;
266 *gpgsm->input_cb.server_fd_str = 0;
267 gpgsm->output_cb.fd = -1;
268 gpgsm->output_cb.dir = 1;
269 gpgsm->output_cb.tag = 0;
270 gpgsm->output_cb.server_fd = -1;
271 *gpgsm->output_cb.server_fd_str = 0;
272 gpgsm->message_cb.fd = -1;
273 gpgsm->message_cb.dir = 0;
274 gpgsm->message_cb.tag = 0;
275 gpgsm->message_cb.server_fd = -1;
276 *gpgsm->message_cb.server_fd_str = 0;
278 gpgsm->status.fnc = 0;
279 gpgsm->colon.fnc = 0;
280 gpgsm->colon.attic.line = 0;
281 gpgsm->colon.attic.linesize = 0;
282 gpgsm->colon.attic.linelen = 0;
283 gpgsm->colon.any = 0;
285 gpgsm->inline_data = NULL;
287 gpgsm->io_cbs.add = NULL;
288 gpgsm->io_cbs.add_priv = NULL;
289 gpgsm->io_cbs.remove = NULL;
290 gpgsm->io_cbs.event = NULL;
291 gpgsm->io_cbs.event_priv = NULL;
293 #if !USE_DESCRIPTOR_PASSING
294 if (_gpgme_io_pipe (fds, 0) < 0)
296 err = gpg_error_from_syserror ();
299 gpgsm->input_cb.fd = fds[1];
300 gpgsm->input_cb.server_fd = fds[0];
302 if (_gpgme_io_pipe (fds, 1) < 0)
304 err = gpg_error_from_syserror ();
307 gpgsm->output_cb.fd = fds[0];
308 gpgsm->output_cb.server_fd = fds[1];
310 if (_gpgme_io_pipe (fds, 0) < 0)
312 err = gpg_error_from_syserror ();
315 gpgsm->message_cb.fd = fds[1];
316 gpgsm->message_cb.server_fd = fds[0];
318 child_fds[0] = gpgsm->input_cb.server_fd;
319 child_fds[1] = gpgsm->output_cb.server_fd;
320 child_fds[2] = gpgsm->message_cb.server_fd;
325 argv[argc++] = "gpgsm";
328 argv[argc++] = "--homedir";
329 argv[argc++] = home_dir;
331 argv[argc++] = "--server";
334 err = assuan_new_ext (&gpgsm->assuan_ctx, GPG_ERR_SOURCE_GPGME,
335 &_gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb,
339 assuan_ctx_set_system_hooks (gpgsm->assuan_ctx, &_gpgme_assuan_system_hooks);
341 #if USE_DESCRIPTOR_PASSING
342 err = assuan_pipe_connect
343 (gpgsm->assuan_ctx, file_name ? file_name : _gpgme_get_gpgsm_path (),
344 argv, NULL, NULL, NULL, ASSUAN_PIPE_CONNECT_FDPASSING);
347 assuan_fd_t achild_fds[4];
351 for (i = 0; i < 4; i++)
352 achild_fds[i] = (assuan_fd_t) child_fds[i];
354 err = assuan_pipe_connect
355 (gpgsm->assuan_ctx, file_name ? file_name : _gpgme_get_gpgsm_path (),
356 argv, achild_fds, NULL, NULL, 0);
359 for (i = 0; i < 4; i++)
360 child_fds[i] = (int) achild_fds[i];
363 /* On Windows, handles are inserted in the spawned process with
364 DuplicateHandle, and child_fds contains the server-local names
365 for the inserted handles when assuan_pipe_connect returns. */
368 /* Note: We don't use _gpgme_io_fd2str here. On W32 the
369 returned handles are real W32 system handles, not whatever
370 GPGME uses internally (which may be a system handle, a C
371 library handle or a GLib/Qt channel. Confusing, yes, but
372 remember these are server-local names, so they are not part
374 snprintf (gpgsm->input_cb.server_fd_str,
375 sizeof gpgsm->input_cb.server_fd_str, "%d", child_fds[0]);
376 snprintf (gpgsm->output_cb.server_fd_str,
377 sizeof gpgsm->output_cb.server_fd_str, "%d", child_fds[1]);
378 snprintf (gpgsm->message_cb.server_fd_str,
379 sizeof gpgsm->message_cb.server_fd_str, "%d", child_fds[2]);
385 err = _gpgme_getenv ("DISPLAY", &dft_display);
390 if (asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
393 err = gpg_error_from_syserror ();
398 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
409 rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
412 err = gpg_error_from_errno (rc);
417 if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
419 err = gpg_error_from_syserror ();
422 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
428 err = _gpgme_getenv ("TERM", &dft_ttytype);
433 if (asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype) < 0)
436 err = gpg_error_from_syserror ();
441 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
442 NULL, NULL, NULL, NULL);
450 /* Ask gpgsm to enable the audit log support. */
453 err = assuan_transact (gpgsm->assuan_ctx, "OPTION enable-audit-log=1",
454 NULL, NULL, NULL, NULL, NULL, NULL);
455 if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
456 err = 0; /* This is an optional feature of gpgsm. */
460 #ifdef HAVE_W32_SYSTEM
461 /* Under Windows we need to use AllowSetForegroundWindow. Tell
462 gpgsm to tell us when it needs it. */
465 err = assuan_transact (gpgsm->assuan_ctx, "OPTION allow-pinentry-notify",
466 NULL, NULL, NULL, NULL, NULL, NULL);
467 if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
468 err = 0; /* This is a new feature of gpgsm. */
470 #endif /*HAVE_W32_SYSTEM*/
472 #if !USE_DESCRIPTOR_PASSING
474 && (_gpgme_io_set_close_notify (gpgsm->input_cb.fd,
475 close_notify_handler, gpgsm)
476 || _gpgme_io_set_close_notify (gpgsm->output_cb.fd,
477 close_notify_handler, gpgsm)
478 || _gpgme_io_set_close_notify (gpgsm->message_cb.fd,
479 close_notify_handler, gpgsm)))
481 err = gpg_error (GPG_ERR_GENERAL);
487 /* Close the server ends of the pipes (because of this, we must use
488 the stored server_fd_str in the function start). Our ends are
489 closed in gpgsm_release(). */
490 #if !USE_DESCRIPTOR_PASSING
491 if (gpgsm->input_cb.server_fd != -1)
492 _gpgme_io_close (gpgsm->input_cb.server_fd);
493 if (gpgsm->output_cb.server_fd != -1)
494 _gpgme_io_close (gpgsm->output_cb.server_fd);
495 if (gpgsm->message_cb.server_fd != -1)
496 _gpgme_io_close (gpgsm->message_cb.server_fd);
500 gpgsm_release (gpgsm);
509 gpgsm_set_locale (void *engine, int category, const char *value)
511 engine_gpgsm_t gpgsm = engine;
516 /* FIXME: If value is NULL, we need to reset the option to default.
517 But we can't do this. So we error out here. GPGSM needs support
522 else if (category == LC_CTYPE)
525 if (!value && gpgsm->lc_ctype_set)
526 return gpg_error (GPG_ERR_INV_VALUE);
528 gpgsm->lc_ctype_set = 1;
532 else if (category == LC_MESSAGES)
534 catstr = "lc-messages";
535 if (!value && gpgsm->lc_messages_set)
536 return gpg_error (GPG_ERR_INV_VALUE);
538 gpgsm->lc_messages_set = 1;
540 #endif /* LC_MESSAGES */
542 return gpg_error (GPG_ERR_INV_VALUE);
544 /* FIXME: Reset value to default. */
548 if (asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0)
549 err = gpg_error_from_syserror ();
552 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
553 NULL, NULL, NULL, NULL);
562 gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd,
563 engine_status_handler_t status_fnc,
564 void *status_fnc_value)
570 err = assuan_write_line (ctx, cmd);
576 err = assuan_read_line (ctx, &line, &linelen);
580 if (*line == '#' || !linelen)
584 && line[0] == 'O' && line[1] == 'K'
585 && (line[2] == '\0' || line[2] == ' '))
587 else if (linelen >= 4
588 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
590 err = atoi (&line[4]);
591 else if (linelen >= 2
592 && line[0] == 'S' && line[1] == ' ')
595 gpgme_status_code_t r;
597 rest = strchr (line + 2, ' ');
599 rest = line + linelen; /* set to an empty string */
603 r = _gpgme_parse_status (line + 2);
605 if (r >= 0 && status_fnc)
606 err = status_fnc (status_fnc_value, r, rest);
608 err = gpg_error (GPG_ERR_GENERAL);
611 err = gpg_error (GPG_ERR_GENERAL);
619 typedef enum { INPUT_FD, OUTPUT_FD, MESSAGE_FD } fd_type_t;
622 gpgsm_clear_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type)
624 #if !USE_DESCRIPTOR_PASSING
628 _gpgme_io_close (gpgsm->input_cb.fd);
631 _gpgme_io_close (gpgsm->output_cb.fd);
634 _gpgme_io_close (gpgsm->message_cb.fd);
640 #define COMMANDLINELEN 40
642 gpgsm_set_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type, const char *opt)
645 char line[COMMANDLINELEN];
647 iocb_data_t *iocb_data;
654 iocb_data = &gpgsm->input_cb;
659 iocb_data = &gpgsm->output_cb;
664 iocb_data = &gpgsm->message_cb;
668 return gpg_error (GPG_ERR_INV_VALUE);
671 dir = iocb_data->dir;
673 #if USE_DESCRIPTOR_PASSING
674 /* We try to short-cut the communication by giving GPGSM direct
675 access to the file descriptor, rather than using a pipe. */
676 iocb_data->server_fd = _gpgme_data_get_fd (iocb_data->data);
677 if (iocb_data->server_fd < 0)
681 if (_gpgme_io_pipe (fds, dir) < 0)
682 return gpg_error_from_syserror ();
684 iocb_data->fd = dir ? fds[0] : fds[1];
685 iocb_data->server_fd = dir ? fds[1] : fds[0];
687 if (_gpgme_io_set_close_notify (iocb_data->fd,
688 close_notify_handler, gpgsm))
690 err = gpg_error (GPG_ERR_GENERAL);
695 err = assuan_sendfd (gpgsm->assuan_ctx, iocb_data->server_fd);
699 _gpgme_io_close (iocb_data->server_fd);
700 iocb_data->server_fd = -1;
703 snprintf (line, COMMANDLINELEN, "%s FD %s", which, opt);
705 snprintf (line, COMMANDLINELEN, "%s FD", which);
708 snprintf (line, COMMANDLINELEN, "%s FD=%s %s",
709 which, iocb_data->server_fd_str, opt);
711 snprintf (line, COMMANDLINELEN, "%s FD=%s",
712 which, iocb_data->server_fd_str);
715 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
717 #if USE_DESCRIPTOR_PASSING
721 _gpgme_io_close (iocb_data->fd);
723 if (iocb_data->server_fd != -1)
725 _gpgme_io_close (iocb_data->server_fd);
726 iocb_data->server_fd = -1;
736 map_data_enc (gpgme_data_t d)
738 switch (gpgme_data_get_encoding (d))
740 case GPGME_DATA_ENCODING_NONE:
742 case GPGME_DATA_ENCODING_BINARY:
744 case GPGME_DATA_ENCODING_BASE64:
746 case GPGME_DATA_ENCODING_ARMOR:
756 status_handler (void *opaque, int fd)
758 struct io_cb_data *data = (struct io_cb_data *) opaque;
759 engine_gpgsm_t gpgsm = (engine_gpgsm_t) data->handler_value;
760 gpgme_error_t err = 0;
766 err = assuan_read_line (gpgsm->assuan_ctx, &line, &linelen);
769 /* Try our best to terminate the connection friendly. */
770 /* assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
771 TRACE3 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
772 "fd 0x%x: error from assuan (%d) getting status line : %s",
773 fd, err, gpg_strerror (err));
775 else if (linelen >= 3
776 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
777 && (line[3] == '\0' || line[3] == ' '))
780 err = atoi (&line[4]);
782 err = gpg_error (GPG_ERR_GENERAL);
783 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
784 "fd 0x%x: ERR line - mapped to: %s",
785 fd, err ? gpg_strerror (err) : "ok");
786 /* Try our best to terminate the connection friendly. */
787 /* assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
789 else if (linelen >= 2
790 && line[0] == 'O' && line[1] == 'K'
791 && (line[2] == '\0' || line[2] == ' '))
793 if (gpgsm->status.fnc)
794 err = gpgsm->status.fnc (gpgsm->status.fnc_value,
795 GPGME_STATUS_EOF, "");
797 if (!err && gpgsm->colon.fnc && gpgsm->colon.any)
799 /* We must tell a colon function about the EOF. We do
800 this only when we have seen any data lines. Note
801 that this inlined use of colon data lines will
802 eventually be changed into using a regular data
804 gpgsm->colon.any = 0;
805 err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, NULL);
807 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
808 "fd 0x%x: OK line - final status: %s",
809 fd, err ? gpg_strerror (err) : "ok");
810 _gpgme_io_close (gpgsm->status_cb.fd);
814 && line[0] == 'D' && line[1] == ' '
817 /* We are using the colon handler even for plain inline data
818 - strange name for that function but for historic reasons
820 /* FIXME We can't use this for binary data because we
821 assume this is a string. For the current usage of colon
822 output it is correct. */
823 char *src = line + 2;
824 char *end = line + linelen;
826 char **aline = &gpgsm->colon.attic.line;
827 int *alinelen = &gpgsm->colon.attic.linelen;
829 if (gpgsm->colon.attic.linesize < *alinelen + linelen + 1)
831 char *newline = realloc (*aline, *alinelen + linelen + 1);
833 err = gpg_error_from_syserror ();
837 gpgsm->colon.attic.linesize += linelen + 1;
842 dst = *aline + *alinelen;
844 while (!err && src < end)
846 if (*src == '%' && src + 2 < end)
848 /* Handle escaped characters. */
850 *dst = _gpgme_hextobyte (src);
862 /* Terminate the pending line, pass it to the colon
863 handler and reset it. */
865 gpgsm->colon.any = 1;
866 if (*alinelen > 1 && *(dst - 1) == '\r')
870 /* FIXME How should we handle the return code? */
871 err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, *aline);
882 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
883 "fd 0x%x: D line; final status: %s",
884 fd, err? gpg_strerror (err):"ok");
887 && line[0] == 'D' && line[1] == ' '
888 && gpgsm->inline_data)
890 char *src = line + 2;
891 char *end = line + linelen;
898 if (*src == '%' && src + 2 < end)
900 /* Handle escaped characters. */
902 *dst++ = _gpgme_hextobyte (src);
914 nwritten = gpgme_data_write (gpgsm->inline_data, src, linelen);
915 if (!nwritten || (nwritten < 0 && errno != EINTR)
916 || nwritten > linelen)
918 err = gpg_error_from_syserror ();
925 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
926 "fd 0x%x: D inlinedata; final status: %s",
927 fd, err? gpg_strerror (err):"ok");
930 && line[0] == 'S' && line[1] == ' ')
933 gpgme_status_code_t r;
935 rest = strchr (line + 2, ' ');
937 rest = line + linelen; /* set to an empty string */
941 r = _gpgme_parse_status (line + 2);
945 if (gpgsm->status.fnc)
946 err = gpgsm->status.fnc (gpgsm->status.fnc_value, r, rest);
949 fprintf (stderr, "[UNKNOWN STATUS]%s %s", line + 2, rest);
950 TRACE3 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
951 "fd 0x%x: S line (%s) - final status: %s",
952 fd, line+2, err? gpg_strerror (err):"ok");
954 else if (linelen >= 7
955 && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
956 && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
958 && (line[7] == '\0' || line[7] == ' '))
960 char *keyword = line+7;
962 while (*keyword == ' ')
964 default_inq_cb (gpgsm, keyword);
965 assuan_write_line (gpgsm->assuan_ctx, "END");
969 while (!err && assuan_pending_line (gpgsm->assuan_ctx));
976 add_io_cb (engine_gpgsm_t gpgsm, iocb_data_t *iocbd, gpgme_io_cb_t handler)
980 TRACE_BEG2 (DEBUG_ENGINE, "engine-gpgsm:add_io_cb", gpgsm,
981 "fd %d, dir %d", iocbd->fd, iocbd->dir);
982 err = (*gpgsm->io_cbs.add) (gpgsm->io_cbs.add_priv,
983 iocbd->fd, iocbd->dir,
984 handler, iocbd->data, &iocbd->tag);
986 return TRACE_ERR (err);
988 /* FIXME Kludge around poll() problem. */
989 err = _gpgme_io_set_nonblocking (iocbd->fd);
990 return TRACE_ERR (err);
995 start (engine_gpgsm_t gpgsm, const char *command)
998 assuan_fd_t afdlist[5];
1003 /* We need to know the fd used by assuan for reads. We do this by
1004 using the assumption that the first returned fd from
1005 assuan_get_active_fds() is always this one. */
1006 nfds = assuan_get_active_fds (gpgsm->assuan_ctx, 0 /* read fds */,
1007 afdlist, DIM (afdlist));
1009 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1011 for (i = 0; i < nfds; i++)
1012 fdlist[i] = (int) afdlist[i];
1014 /* We "duplicate" the file descriptor, so we can close it here (we
1015 can't close fdlist[0], as that is closed by libassuan, and
1016 closing it here might cause libassuan to close some unrelated FD
1017 later). Alternatively, we could special case status_fd and
1018 register/unregister it manually as needed, but this increases
1019 code duplication and is more complicated as we can not use the
1020 close notifications etc. A third alternative would be to let
1021 Assuan know that we closed the FD, but that complicates the
1022 Assuan interface. */
1024 gpgsm->status_cb.fd = _gpgme_io_dup (fdlist[0]);
1025 if (gpgsm->status_cb.fd < 0)
1026 return gpg_error_from_syserror ();
1028 if (_gpgme_io_set_close_notify (gpgsm->status_cb.fd,
1029 close_notify_handler, gpgsm))
1031 _gpgme_io_close (gpgsm->status_cb.fd);
1032 gpgsm->status_cb.fd = -1;
1033 return gpg_error (GPG_ERR_GENERAL);
1036 err = add_io_cb (gpgsm, &gpgsm->status_cb, status_handler);
1037 if (!err && gpgsm->input_cb.fd != -1)
1038 err = add_io_cb (gpgsm, &gpgsm->input_cb, _gpgme_data_outbound_handler);
1039 if (!err && gpgsm->output_cb.fd != -1)
1040 err = add_io_cb (gpgsm, &gpgsm->output_cb, _gpgme_data_inbound_handler);
1041 if (!err && gpgsm->message_cb.fd != -1)
1042 err = add_io_cb (gpgsm, &gpgsm->message_cb, _gpgme_data_outbound_handler);
1045 err = assuan_write_line (gpgsm->assuan_ctx, command);
1048 gpgsm_io_event (gpgsm, GPGME_EVENT_START, NULL);
1054 #if USE_DESCRIPTOR_PASSING
1055 static gpgme_error_t
1056 gpgsm_reset (void *engine)
1058 engine_gpgsm_t gpgsm = engine;
1060 /* IF we have an active connection we must send a reset because we
1061 need to reset the list of signers. Note that RESET does not
1062 reset OPTION commands. */
1063 return (gpgsm->assuan_ctx
1064 ? gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "RESET",
1072 static gpgme_error_t
1073 gpgsm_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
1075 engine_gpgsm_t gpgsm = engine;
1079 return gpg_error (GPG_ERR_INV_VALUE);
1081 gpgsm->input_cb.data = ciph;
1082 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1084 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1085 gpgsm->output_cb.data = plain;
1086 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1088 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1089 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1090 gpgsm->inline_data = NULL;
1092 err = start (engine, "DECRYPT");
1097 static gpgme_error_t
1098 gpgsm_delete (void *engine, gpgme_key_t key, int allow_secret)
1100 engine_gpgsm_t gpgsm = engine;
1102 char *fpr = key->subkeys ? key->subkeys->fpr : NULL;
1105 int length = 8; /* "DELKEYS " */
1108 return gpg_error (GPG_ERR_INV_VALUE);
1113 if (*linep == '%' || *linep == ' ' || *linep == '+')
1119 line = malloc (length);
1121 return gpg_error_from_syserror ();
1123 strcpy (line, "DELKEYS ");
1153 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1154 gpgsm_clear_fd (gpgsm, INPUT_FD);
1155 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1156 gpgsm->inline_data = NULL;
1158 err = start (gpgsm, line);
1165 static gpgme_error_t
1166 set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[])
1168 gpgme_error_t err = 0;
1169 assuan_context_t ctx = gpgsm->assuan_ctx;
1172 int invalid_recipients = 0;
1175 linelen = 10 + 40 + 1; /* "RECIPIENT " + guess + '\0'. */
1176 line = malloc (10 + 40 + 1);
1178 return gpg_error_from_syserror ();
1179 strcpy (line, "RECIPIENT ");
1180 for (i =0; !err && recp[i]; i++)
1185 if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
1187 invalid_recipients++;
1190 fpr = recp[i]->subkeys->fpr;
1192 newlen = 11 + strlen (fpr);
1193 if (linelen < newlen)
1195 char *newline = realloc (line, newlen);
1198 int saved_errno = errno;
1200 return gpg_error_from_errno (saved_errno);
1205 strcpy (&line[10], fpr);
1207 err = gpgsm_assuan_simple_command (ctx, line, gpgsm->status.fnc,
1208 gpgsm->status.fnc_value);
1209 /* FIXME: This requires more work. */
1210 if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
1211 invalid_recipients++;
1219 return gpg_error (invalid_recipients
1220 ? GPG_ERR_UNUSABLE_PUBKEY : GPG_ERR_NO_ERROR);
1224 static gpgme_error_t
1225 gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
1226 gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
1228 engine_gpgsm_t gpgsm = engine;
1232 return gpg_error (GPG_ERR_INV_VALUE);
1234 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1236 if (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO)
1238 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
1239 "OPTION no-encrypt-to", NULL, NULL);
1244 gpgsm->input_cb.data = plain;
1245 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1248 gpgsm->output_cb.data = ciph;
1249 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1250 : map_data_enc (gpgsm->output_cb.data));
1253 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1254 gpgsm->inline_data = NULL;
1256 err = set_recipients (gpgsm, recp);
1259 err = start (gpgsm, "ENCRYPT");
1265 static gpgme_error_t
1266 gpgsm_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
1267 gpgme_data_t keydata, int use_armor)
1269 engine_gpgsm_t gpgsm = engine;
1270 gpgme_error_t err = 0;
1274 return gpg_error (GPG_ERR_INV_VALUE);
1277 return gpg_error (GPG_ERR_NOT_SUPPORTED);
1282 cmd = malloc (7 + strlen (pattern) + 1);
1284 return gpg_error_from_syserror ();
1285 strcpy (cmd, "EXPORT ");
1286 strcpy (&cmd[7], pattern);
1288 gpgsm->output_cb.data = keydata;
1289 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1290 : map_data_enc (gpgsm->output_cb.data));
1293 gpgsm_clear_fd (gpgsm, INPUT_FD);
1294 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1295 gpgsm->inline_data = NULL;
1297 err = start (gpgsm, cmd);
1303 static gpgme_error_t
1304 gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
1305 gpgme_data_t keydata, int use_armor)
1307 engine_gpgsm_t gpgsm = engine;
1308 gpgme_error_t err = 0;
1310 /* Length is "EXPORT " + p + '\0'. */
1315 return gpg_error (GPG_ERR_INV_VALUE);
1318 return gpg_error (GPG_ERR_NOT_SUPPORTED);
1320 if (pattern && *pattern)
1322 const char **pat = pattern;
1326 const char *patlet = *pat;
1331 if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1339 line = malloc (length);
1341 return gpg_error_from_syserror ();
1343 strcpy (line, "EXPORT ");
1346 if (pattern && *pattern)
1350 const char *patlet = *pattern;
1372 *(linep++) = *patlet;
1384 gpgsm->output_cb.data = keydata;
1385 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1386 : map_data_enc (gpgsm->output_cb.data));
1389 gpgsm_clear_fd (gpgsm, INPUT_FD);
1390 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1391 gpgsm->inline_data = NULL;
1393 err = start (gpgsm, line);
1399 static gpgme_error_t
1400 gpgsm_genkey (void *engine, gpgme_data_t help_data, int use_armor,
1401 gpgme_data_t pubkey, gpgme_data_t seckey)
1403 engine_gpgsm_t gpgsm = engine;
1406 if (!gpgsm || !pubkey || seckey)
1407 return gpg_error (GPG_ERR_INV_VALUE);
1409 gpgsm->input_cb.data = help_data;
1410 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1413 gpgsm->output_cb.data = pubkey;
1414 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1415 : map_data_enc (gpgsm->output_cb.data));
1418 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1419 gpgsm->inline_data = NULL;
1421 err = start (gpgsm, "GENKEY");
1426 static gpgme_error_t
1427 gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
1429 engine_gpgsm_t gpgsm = engine;
1431 gpgme_data_encoding_t dataenc;
1435 return gpg_error (GPG_ERR_INV_VALUE);
1437 if (keydata && keyarray)
1438 return gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed. */
1440 dataenc = gpgme_data_get_encoding (keydata);
1447 /* Fist check whether the engine already features the
1448 --re-import option. */
1449 err = gpgsm_assuan_simple_command
1451 "GETINFO cmd_has_option IMPORT re-import", NULL, NULL);
1453 return gpg_error (GPG_ERR_NOT_SUPPORTED);
1455 /* Create an internal data object with a list of all
1456 fingerprints. The data object and its memory (to avoid an
1457 extra copy by gpgme_data_new_from_mem) are stored in two
1458 variables which are released by the close_notify_handler. */
1459 for (idx=0, buflen=0; keyarray[idx]; idx++)
1461 if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
1462 && keyarray[idx]->subkeys
1463 && keyarray[idx]->subkeys->fpr
1464 && *keyarray[idx]->subkeys->fpr)
1465 buflen += strlen (keyarray[idx]->subkeys->fpr) + 1;
1467 /* Allocate a bufer with extra space for the trailing Nul
1468 introduced by the use of stpcpy. */
1469 buffer = malloc (buflen+1);
1471 return gpg_error_from_syserror ();
1472 for (idx=0, p = buffer; keyarray[idx]; idx++)
1474 if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
1475 && keyarray[idx]->subkeys
1476 && keyarray[idx]->subkeys->fpr
1477 && *keyarray[idx]->subkeys->fpr)
1478 p = stpcpy (stpcpy (p, keyarray[idx]->subkeys->fpr), "\n");
1481 err = gpgme_data_new_from_mem (&gpgsm->input_helper_data,
1488 gpgsm->input_helper_memory = buffer;
1490 gpgsm->input_cb.data = gpgsm->input_helper_data;
1491 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1494 gpgme_data_release (gpgsm->input_helper_data);
1495 gpgsm->input_helper_data = NULL;
1496 free (gpgsm->input_helper_memory);
1497 gpgsm->input_helper_memory = NULL;
1500 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1501 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1502 gpgsm->inline_data = NULL;
1504 return start (gpgsm, "IMPORT --re-import");
1506 else if (dataenc == GPGME_DATA_ENCODING_URL
1507 || dataenc == GPGME_DATA_ENCODING_URL0
1508 || dataenc == GPGME_DATA_ENCODING_URLESC)
1510 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1514 gpgsm->input_cb.data = keydata;
1515 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1518 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1519 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1520 gpgsm->inline_data = NULL;
1522 return start (gpgsm, "IMPORT");
1527 static gpgme_error_t
1528 gpgsm_keylist (void *engine, const char *pattern, int secret_only,
1529 gpgme_keylist_mode_t mode)
1531 engine_gpgsm_t gpgsm = engine;
1536 if (mode & GPGME_KEYLIST_MODE_LOCAL)
1538 if (mode & GPGME_KEYLIST_MODE_EXTERN)
1544 /* Hack to make sure that the agent is started. Only if the agent
1545 has been started an application may connect to the agent via
1546 GPGME_PROTOCOL_ASSUAN - for example to look for smartcards. We
1547 do this only if a secret key listing has been requested. In
1548 general this is not needed because a secret key listing starts
1549 the agent. However on a fresh installation no public keys are
1550 available and thus there is no need for gpgsm to ask the agent
1551 whether a secret key exists for the public key. */
1553 gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "GETINFO agent-check",
1556 /* Always send list-mode option because RESET does not reset it. */
1557 if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1558 return gpg_error_from_syserror ();
1559 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
1565 /* Always send key validation because RESET does not reset it. */
1567 /* Use the validation mode if requested. We don't check for an error
1568 yet because this is a pretty fresh gpgsm features. */
1569 gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
1570 (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1571 "OPTION with-validation=1":
1572 "OPTION with-validation=0" ,
1574 /* Include the ephemeral keys if requested. We don't check for an error
1575 yet because this is a pretty fresh gpgsm features. */
1576 gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
1577 (mode & GPGME_KEYLIST_MODE_EPHEMERAL)?
1578 "OPTION with-ephemeral-keys=1":
1579 "OPTION with-ephemeral-keys=0" ,
1583 /* Length is "LISTSECRETKEYS " + p + '\0'. */
1584 line = malloc (15 + strlen (pattern) + 1);
1586 return gpg_error_from_syserror ();
1589 strcpy (line, "LISTSECRETKEYS ");
1590 strcpy (&line[15], pattern);
1594 strcpy (line, "LISTKEYS ");
1595 strcpy (&line[9], pattern);
1598 gpgsm_clear_fd (gpgsm, INPUT_FD);
1599 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1600 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1601 gpgsm->inline_data = NULL;
1603 err = start (gpgsm, line);
1609 static gpgme_error_t
1610 gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
1611 int reserved, gpgme_keylist_mode_t mode)
1613 engine_gpgsm_t gpgsm = engine;
1616 /* Length is "LISTSECRETKEYS " + p + '\0'. */
1617 int length = 15 + 1;
1619 int any_pattern = 0;
1623 return gpg_error (GPG_ERR_INV_VALUE);
1625 if (mode & GPGME_KEYLIST_MODE_LOCAL)
1627 if (mode & GPGME_KEYLIST_MODE_EXTERN)
1630 /* Always send list-mode option because RESET does not reset it. */
1631 if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1632 return gpg_error_from_syserror ();
1633 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
1638 /* Always send key validation because RESET does not reset it. */
1639 /* Use the validation mode if required. We don't check for an error
1640 yet because this is a pretty fresh gpgsm features. */
1641 gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
1642 (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1643 "OPTION with-validation=1":
1644 "OPTION with-validation=0" ,
1648 if (pattern && *pattern)
1650 const char **pat = pattern;
1654 const char *patlet = *pat;
1659 if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1667 line = malloc (length);
1669 return gpg_error_from_syserror ();
1672 strcpy (line, "LISTSECRETKEYS ");
1677 strcpy (line, "LISTKEYS ");
1681 if (pattern && *pattern)
1685 const char *patlet = *pattern;
1707 *(linep++) = *patlet;
1721 gpgsm_clear_fd (gpgsm, INPUT_FD);
1722 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1723 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1724 gpgsm->inline_data = NULL;
1726 err = start (gpgsm, line);
1732 static gpgme_error_t
1733 gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
1734 gpgme_sig_mode_t mode, int use_armor, int use_textmode,
1735 int include_certs, gpgme_ctx_t ctx /* FIXME */)
1737 engine_gpgsm_t gpgsm = engine;
1744 return gpg_error (GPG_ERR_INV_VALUE);
1746 /* FIXME: This does not work as RESET does not reset it so we can't
1747 revert back to default. */
1748 if (include_certs != GPGME_INCLUDE_CERTS_DEFAULT)
1750 /* FIXME: Make sure that if we run multiple operations, that we
1751 can reset any previously set value in case the default is
1754 if (asprintf (&assuan_cmd, "OPTION include-certs %i", include_certs) < 0)
1755 return gpg_error_from_syserror ();
1756 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, assuan_cmd,
1763 for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1765 const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1766 if (s && strlen (s) < 80)
1770 strcpy (stpcpy (buf, "SIGNER "), s);
1771 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, buf,
1773 gpgsm->status.fnc_value);
1776 err = gpg_error (GPG_ERR_INV_VALUE);
1777 gpgme_key_unref (key);
1782 gpgsm->input_cb.data = in;
1783 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1786 gpgsm->output_cb.data = out;
1787 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1788 : map_data_enc (gpgsm->output_cb.data));
1791 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1792 gpgsm->inline_data = NULL;
1794 err = start (gpgsm, mode == GPGME_SIG_MODE_DETACH
1795 ? "SIGN --detached" : "SIGN");
1800 static gpgme_error_t
1801 gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
1802 gpgme_data_t plaintext)
1804 engine_gpgsm_t gpgsm = engine;
1808 return gpg_error (GPG_ERR_INV_VALUE);
1810 gpgsm->input_cb.data = sig;
1811 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1816 /* Normal or cleartext signature. */
1817 gpgsm->output_cb.data = plaintext;
1818 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1819 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1823 /* Detached signature. */
1824 gpgsm->message_cb.data = signed_text;
1825 err = gpgsm_set_fd (gpgsm, MESSAGE_FD, 0);
1826 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1828 gpgsm->inline_data = NULL;
1831 err = start (gpgsm, "VERIFY");
1837 /* Send the GETAUDITLOG command. The result is saved to a gpgme data
1839 static gpgme_error_t
1840 gpgsm_getauditlog (void *engine, gpgme_data_t output, unsigned int flags)
1842 engine_gpgsm_t gpgsm = engine;
1843 gpgme_error_t err = 0;
1845 if (!gpgsm || !output)
1846 return gpg_error (GPG_ERR_INV_VALUE);
1848 #if USE_DESCRIPTOR_PASSING
1849 gpgsm->output_cb.data = output;
1850 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1854 gpgsm_clear_fd (gpgsm, INPUT_FD);
1855 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1856 gpgsm->inline_data = NULL;
1857 # define CMD "GETAUDITLOG"
1859 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1860 gpgsm_clear_fd (gpgsm, INPUT_FD);
1861 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1862 gpgsm->inline_data = output;
1863 # define CMD "GETAUDITLOG --data"
1866 err = start (gpgsm, (flags & GPGME_AUDITLOG_HTML)? CMD " --html" : CMD);
1874 gpgsm_set_status_handler (void *engine, engine_status_handler_t fnc,
1877 engine_gpgsm_t gpgsm = engine;
1879 gpgsm->status.fnc = fnc;
1880 gpgsm->status.fnc_value = fnc_value;
1884 static gpgme_error_t
1885 gpgsm_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
1888 engine_gpgsm_t gpgsm = engine;
1890 gpgsm->colon.fnc = fnc;
1891 gpgsm->colon.fnc_value = fnc_value;
1892 gpgsm->colon.any = 0;
1898 gpgsm_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
1900 engine_gpgsm_t gpgsm = engine;
1901 gpgsm->io_cbs = *io_cbs;
1906 gpgsm_io_event (void *engine, gpgme_event_io_t type, void *type_data)
1908 engine_gpgsm_t gpgsm = engine;
1910 TRACE3 (DEBUG_ENGINE, "gpgme:gpgsm_io_event", gpgsm,
1911 "event %p, type %d, type_data %p",
1912 gpgsm->io_cbs.event, type, type_data);
1913 if (gpgsm->io_cbs.event)
1914 (*gpgsm->io_cbs.event) (gpgsm->io_cbs.event_priv, type, type_data);
1918 static gpgme_error_t
1919 gpgsm_passwd (void *engine, gpgme_key_t key, unsigned int flags)
1921 engine_gpgsm_t gpgsm = engine;
1925 if (!key || !key->subkeys || !key->subkeys->fpr)
1926 return gpg_error (GPG_ERR_INV_CERT_OBJ);
1928 if (asprintf (&line, "PASSWD -- %s", key->subkeys->fpr) < 0)
1929 return gpg_error_from_syserror ();
1931 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1932 gpgsm_clear_fd (gpgsm, INPUT_FD);
1933 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1934 gpgsm->inline_data = NULL;
1936 err = start (gpgsm, line);
1944 struct engine_ops _gpgme_engine_ops_gpgsm =
1946 /* Static functions. */
1947 _gpgme_get_gpgsm_path,
1950 gpgsm_get_req_version,
1953 /* Member functions. */
1955 #if USE_DESCRIPTOR_PASSING
1960 gpgsm_set_status_handler,
1961 NULL, /* set_command_handler */
1962 gpgsm_set_colon_line_handler,
1964 NULL, /* set_protocol */
1967 gpgsm_delete, /* decrypt_verify */
1970 NULL, /* encrypt_sign */
1978 NULL, /* trustlist */
1981 NULL, /* opassuan_transact */
1982 NULL, /* conf_load */
1983 NULL, /* conf_save */
1987 NULL, /* cancel_op */