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;
648 #if USE_DESCRIPTOR_PASSING
656 iocb_data = &gpgsm->input_cb;
661 iocb_data = &gpgsm->output_cb;
666 iocb_data = &gpgsm->message_cb;
670 return gpg_error (GPG_ERR_INV_VALUE);
673 #if USE_DESCRIPTOR_PASSING
674 dir = iocb_data->dir;
675 /* We try to short-cut the communication by giving GPGSM direct
676 access to the file descriptor, rather than using a pipe. */
677 iocb_data->server_fd = _gpgme_data_get_fd (iocb_data->data);
678 if (iocb_data->server_fd < 0)
682 if (_gpgme_io_pipe (fds, dir) < 0)
683 return gpg_error_from_syserror ();
685 iocb_data->fd = dir ? fds[0] : fds[1];
686 iocb_data->server_fd = dir ? fds[1] : fds[0];
688 if (_gpgme_io_set_close_notify (iocb_data->fd,
689 close_notify_handler, gpgsm))
691 err = gpg_error (GPG_ERR_GENERAL);
696 err = assuan_sendfd (gpgsm->assuan_ctx, iocb_data->server_fd);
700 _gpgme_io_close (iocb_data->server_fd);
701 iocb_data->server_fd = -1;
704 snprintf (line, COMMANDLINELEN, "%s FD %s", which, opt);
706 snprintf (line, COMMANDLINELEN, "%s FD", which);
709 snprintf (line, COMMANDLINELEN, "%s FD=%s %s",
710 which, iocb_data->server_fd_str, opt);
712 snprintf (line, COMMANDLINELEN, "%s FD=%s",
713 which, iocb_data->server_fd_str);
716 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
718 #if USE_DESCRIPTOR_PASSING
722 _gpgme_io_close (iocb_data->fd);
724 if (iocb_data->server_fd != -1)
726 _gpgme_io_close (iocb_data->server_fd);
727 iocb_data->server_fd = -1;
737 map_data_enc (gpgme_data_t d)
739 switch (gpgme_data_get_encoding (d))
741 case GPGME_DATA_ENCODING_NONE:
743 case GPGME_DATA_ENCODING_BINARY:
745 case GPGME_DATA_ENCODING_BASE64:
747 case GPGME_DATA_ENCODING_ARMOR:
757 status_handler (void *opaque, int fd)
759 struct io_cb_data *data = (struct io_cb_data *) opaque;
760 engine_gpgsm_t gpgsm = (engine_gpgsm_t) data->handler_value;
761 gpgme_error_t err = 0;
767 err = assuan_read_line (gpgsm->assuan_ctx, &line, &linelen);
770 /* Try our best to terminate the connection friendly. */
771 /* assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
772 TRACE3 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
773 "fd 0x%x: error from assuan (%d) getting status line : %s",
774 fd, err, gpg_strerror (err));
776 else if (linelen >= 3
777 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
778 && (line[3] == '\0' || line[3] == ' '))
781 err = atoi (&line[4]);
783 err = gpg_error (GPG_ERR_GENERAL);
784 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
785 "fd 0x%x: ERR line - mapped to: %s",
786 fd, err ? gpg_strerror (err) : "ok");
787 /* Try our best to terminate the connection friendly. */
788 /* assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
790 else if (linelen >= 2
791 && line[0] == 'O' && line[1] == 'K'
792 && (line[2] == '\0' || line[2] == ' '))
794 if (gpgsm->status.fnc)
795 err = gpgsm->status.fnc (gpgsm->status.fnc_value,
796 GPGME_STATUS_EOF, "");
798 if (!err && gpgsm->colon.fnc && gpgsm->colon.any)
800 /* We must tell a colon function about the EOF. We do
801 this only when we have seen any data lines. Note
802 that this inlined use of colon data lines will
803 eventually be changed into using a regular data
805 gpgsm->colon.any = 0;
806 err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, NULL);
808 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
809 "fd 0x%x: OK line - final status: %s",
810 fd, err ? gpg_strerror (err) : "ok");
811 _gpgme_io_close (gpgsm->status_cb.fd);
815 && line[0] == 'D' && line[1] == ' '
818 /* We are using the colon handler even for plain inline data
819 - strange name for that function but for historic reasons
821 /* FIXME We can't use this for binary data because we
822 assume this is a string. For the current usage of colon
823 output it is correct. */
824 char *src = line + 2;
825 char *end = line + linelen;
827 char **aline = &gpgsm->colon.attic.line;
828 int *alinelen = &gpgsm->colon.attic.linelen;
830 if (gpgsm->colon.attic.linesize < *alinelen + linelen + 1)
832 char *newline = realloc (*aline, *alinelen + linelen + 1);
834 err = gpg_error_from_syserror ();
838 gpgsm->colon.attic.linesize += linelen + 1;
843 dst = *aline + *alinelen;
845 while (!err && src < end)
847 if (*src == '%' && src + 2 < end)
849 /* Handle escaped characters. */
851 *dst = _gpgme_hextobyte (src);
863 /* Terminate the pending line, pass it to the colon
864 handler and reset it. */
866 gpgsm->colon.any = 1;
867 if (*alinelen > 1 && *(dst - 1) == '\r')
871 /* FIXME How should we handle the return code? */
872 err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, *aline);
883 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
884 "fd 0x%x: D line; final status: %s",
885 fd, err? gpg_strerror (err):"ok");
888 && line[0] == 'D' && line[1] == ' '
889 && gpgsm->inline_data)
891 char *src = line + 2;
892 char *end = line + linelen;
899 if (*src == '%' && src + 2 < end)
901 /* Handle escaped characters. */
903 *dst++ = _gpgme_hextobyte (src);
915 nwritten = gpgme_data_write (gpgsm->inline_data, src, linelen);
916 if (!nwritten || (nwritten < 0 && errno != EINTR)
917 || nwritten > linelen)
919 err = gpg_error_from_syserror ();
926 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
927 "fd 0x%x: D inlinedata; final status: %s",
928 fd, err? gpg_strerror (err):"ok");
931 && line[0] == 'S' && line[1] == ' ')
934 gpgme_status_code_t r;
936 rest = strchr (line + 2, ' ');
938 rest = line + linelen; /* set to an empty string */
942 r = _gpgme_parse_status (line + 2);
946 if (gpgsm->status.fnc)
947 err = gpgsm->status.fnc (gpgsm->status.fnc_value, r, rest);
950 fprintf (stderr, "[UNKNOWN STATUS]%s %s", line + 2, rest);
951 TRACE3 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
952 "fd 0x%x: S line (%s) - final status: %s",
953 fd, line+2, err? gpg_strerror (err):"ok");
955 else if (linelen >= 7
956 && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
957 && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
959 && (line[7] == '\0' || line[7] == ' '))
961 char *keyword = line+7;
963 while (*keyword == ' ')
965 default_inq_cb (gpgsm, keyword);
966 assuan_write_line (gpgsm->assuan_ctx, "END");
970 while (!err && assuan_pending_line (gpgsm->assuan_ctx));
977 add_io_cb (engine_gpgsm_t gpgsm, iocb_data_t *iocbd, gpgme_io_cb_t handler)
981 TRACE_BEG2 (DEBUG_ENGINE, "engine-gpgsm:add_io_cb", gpgsm,
982 "fd %d, dir %d", iocbd->fd, iocbd->dir);
983 err = (*gpgsm->io_cbs.add) (gpgsm->io_cbs.add_priv,
984 iocbd->fd, iocbd->dir,
985 handler, iocbd->data, &iocbd->tag);
987 return TRACE_ERR (err);
989 /* FIXME Kludge around poll() problem. */
990 err = _gpgme_io_set_nonblocking (iocbd->fd);
991 return TRACE_ERR (err);
996 start (engine_gpgsm_t gpgsm, const char *command)
999 assuan_fd_t afdlist[5];
1004 /* We need to know the fd used by assuan for reads. We do this by
1005 using the assumption that the first returned fd from
1006 assuan_get_active_fds() is always this one. */
1007 nfds = assuan_get_active_fds (gpgsm->assuan_ctx, 0 /* read fds */,
1008 afdlist, DIM (afdlist));
1010 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1012 for (i = 0; i < nfds; i++)
1013 fdlist[i] = (int) afdlist[i];
1015 /* We "duplicate" the file descriptor, so we can close it here (we
1016 can't close fdlist[0], as that is closed by libassuan, and
1017 closing it here might cause libassuan to close some unrelated FD
1018 later). Alternatively, we could special case status_fd and
1019 register/unregister it manually as needed, but this increases
1020 code duplication and is more complicated as we can not use the
1021 close notifications etc. A third alternative would be to let
1022 Assuan know that we closed the FD, but that complicates the
1023 Assuan interface. */
1025 gpgsm->status_cb.fd = _gpgme_io_dup (fdlist[0]);
1026 if (gpgsm->status_cb.fd < 0)
1027 return gpg_error_from_syserror ();
1029 if (_gpgme_io_set_close_notify (gpgsm->status_cb.fd,
1030 close_notify_handler, gpgsm))
1032 _gpgme_io_close (gpgsm->status_cb.fd);
1033 gpgsm->status_cb.fd = -1;
1034 return gpg_error (GPG_ERR_GENERAL);
1037 err = add_io_cb (gpgsm, &gpgsm->status_cb, status_handler);
1038 if (!err && gpgsm->input_cb.fd != -1)
1039 err = add_io_cb (gpgsm, &gpgsm->input_cb, _gpgme_data_outbound_handler);
1040 if (!err && gpgsm->output_cb.fd != -1)
1041 err = add_io_cb (gpgsm, &gpgsm->output_cb, _gpgme_data_inbound_handler);
1042 if (!err && gpgsm->message_cb.fd != -1)
1043 err = add_io_cb (gpgsm, &gpgsm->message_cb, _gpgme_data_outbound_handler);
1046 err = assuan_write_line (gpgsm->assuan_ctx, command);
1049 gpgsm_io_event (gpgsm, GPGME_EVENT_START, NULL);
1055 #if USE_DESCRIPTOR_PASSING
1056 static gpgme_error_t
1057 gpgsm_reset (void *engine)
1059 engine_gpgsm_t gpgsm = engine;
1061 /* IF we have an active connection we must send a reset because we
1062 need to reset the list of signers. Note that RESET does not
1063 reset OPTION commands. */
1064 return (gpgsm->assuan_ctx
1065 ? gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "RESET",
1073 static gpgme_error_t
1074 gpgsm_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
1076 engine_gpgsm_t gpgsm = engine;
1080 return gpg_error (GPG_ERR_INV_VALUE);
1082 gpgsm->input_cb.data = ciph;
1083 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1085 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1086 gpgsm->output_cb.data = plain;
1087 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1089 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1090 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1091 gpgsm->inline_data = NULL;
1093 err = start (engine, "DECRYPT");
1098 static gpgme_error_t
1099 gpgsm_delete (void *engine, gpgme_key_t key, int allow_secret)
1101 engine_gpgsm_t gpgsm = engine;
1103 char *fpr = key->subkeys ? key->subkeys->fpr : NULL;
1106 int length = 8; /* "DELKEYS " */
1109 return gpg_error (GPG_ERR_INV_VALUE);
1114 if (*linep == '%' || *linep == ' ' || *linep == '+')
1120 line = malloc (length);
1122 return gpg_error_from_syserror ();
1124 strcpy (line, "DELKEYS ");
1154 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1155 gpgsm_clear_fd (gpgsm, INPUT_FD);
1156 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1157 gpgsm->inline_data = NULL;
1159 err = start (gpgsm, line);
1166 static gpgme_error_t
1167 set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[])
1169 gpgme_error_t err = 0;
1170 assuan_context_t ctx = gpgsm->assuan_ctx;
1173 int invalid_recipients = 0;
1176 linelen = 10 + 40 + 1; /* "RECIPIENT " + guess + '\0'. */
1177 line = malloc (10 + 40 + 1);
1179 return gpg_error_from_syserror ();
1180 strcpy (line, "RECIPIENT ");
1181 for (i =0; !err && recp[i]; i++)
1186 if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
1188 invalid_recipients++;
1191 fpr = recp[i]->subkeys->fpr;
1193 newlen = 11 + strlen (fpr);
1194 if (linelen < newlen)
1196 char *newline = realloc (line, newlen);
1199 int saved_errno = errno;
1201 return gpg_error_from_errno (saved_errno);
1206 strcpy (&line[10], fpr);
1208 err = gpgsm_assuan_simple_command (ctx, line, gpgsm->status.fnc,
1209 gpgsm->status.fnc_value);
1210 /* FIXME: This requires more work. */
1211 if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
1212 invalid_recipients++;
1220 return gpg_error (invalid_recipients
1221 ? GPG_ERR_UNUSABLE_PUBKEY : GPG_ERR_NO_ERROR);
1225 static gpgme_error_t
1226 gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
1227 gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
1229 engine_gpgsm_t gpgsm = engine;
1233 return gpg_error (GPG_ERR_INV_VALUE);
1235 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1237 if (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO)
1239 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
1240 "OPTION no-encrypt-to", NULL, NULL);
1245 gpgsm->input_cb.data = plain;
1246 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1249 gpgsm->output_cb.data = ciph;
1250 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1251 : map_data_enc (gpgsm->output_cb.data));
1254 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1255 gpgsm->inline_data = NULL;
1257 err = set_recipients (gpgsm, recp);
1260 err = start (gpgsm, "ENCRYPT");
1266 static gpgme_error_t
1267 gpgsm_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
1268 gpgme_data_t keydata, int use_armor)
1270 engine_gpgsm_t gpgsm = engine;
1271 gpgme_error_t err = 0;
1275 return gpg_error (GPG_ERR_INV_VALUE);
1278 return gpg_error (GPG_ERR_NOT_SUPPORTED);
1283 cmd = malloc (7 + strlen (pattern) + 1);
1285 return gpg_error_from_syserror ();
1286 strcpy (cmd, "EXPORT ");
1287 strcpy (&cmd[7], pattern);
1289 gpgsm->output_cb.data = keydata;
1290 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1291 : map_data_enc (gpgsm->output_cb.data));
1294 gpgsm_clear_fd (gpgsm, INPUT_FD);
1295 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1296 gpgsm->inline_data = NULL;
1298 err = start (gpgsm, cmd);
1304 static gpgme_error_t
1305 gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
1306 gpgme_data_t keydata, int use_armor)
1308 engine_gpgsm_t gpgsm = engine;
1309 gpgme_error_t err = 0;
1311 /* Length is "EXPORT " + p + '\0'. */
1316 return gpg_error (GPG_ERR_INV_VALUE);
1319 return gpg_error (GPG_ERR_NOT_SUPPORTED);
1321 if (pattern && *pattern)
1323 const char **pat = pattern;
1327 const char *patlet = *pat;
1332 if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1340 line = malloc (length);
1342 return gpg_error_from_syserror ();
1344 strcpy (line, "EXPORT ");
1347 if (pattern && *pattern)
1351 const char *patlet = *pattern;
1373 *(linep++) = *patlet;
1385 gpgsm->output_cb.data = keydata;
1386 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1387 : map_data_enc (gpgsm->output_cb.data));
1390 gpgsm_clear_fd (gpgsm, INPUT_FD);
1391 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1392 gpgsm->inline_data = NULL;
1394 err = start (gpgsm, line);
1400 static gpgme_error_t
1401 gpgsm_genkey (void *engine, gpgme_data_t help_data, int use_armor,
1402 gpgme_data_t pubkey, gpgme_data_t seckey)
1404 engine_gpgsm_t gpgsm = engine;
1407 if (!gpgsm || !pubkey || seckey)
1408 return gpg_error (GPG_ERR_INV_VALUE);
1410 gpgsm->input_cb.data = help_data;
1411 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1414 gpgsm->output_cb.data = pubkey;
1415 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1416 : map_data_enc (gpgsm->output_cb.data));
1419 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1420 gpgsm->inline_data = NULL;
1422 err = start (gpgsm, "GENKEY");
1427 static gpgme_error_t
1428 gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
1430 engine_gpgsm_t gpgsm = engine;
1432 gpgme_data_encoding_t dataenc;
1436 return gpg_error (GPG_ERR_INV_VALUE);
1438 if (keydata && keyarray)
1439 return gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed. */
1441 dataenc = gpgme_data_get_encoding (keydata);
1448 /* Fist check whether the engine already features the
1449 --re-import option. */
1450 err = gpgsm_assuan_simple_command
1452 "GETINFO cmd_has_option IMPORT re-import", NULL, NULL);
1454 return gpg_error (GPG_ERR_NOT_SUPPORTED);
1456 /* Create an internal data object with a list of all
1457 fingerprints. The data object and its memory (to avoid an
1458 extra copy by gpgme_data_new_from_mem) are stored in two
1459 variables which are released by the close_notify_handler. */
1460 for (idx=0, buflen=0; keyarray[idx]; idx++)
1462 if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
1463 && keyarray[idx]->subkeys
1464 && keyarray[idx]->subkeys->fpr
1465 && *keyarray[idx]->subkeys->fpr)
1466 buflen += strlen (keyarray[idx]->subkeys->fpr) + 1;
1468 /* Allocate a bufer with extra space for the trailing Nul
1469 introduced by the use of stpcpy. */
1470 buffer = malloc (buflen+1);
1472 return gpg_error_from_syserror ();
1473 for (idx=0, p = buffer; keyarray[idx]; idx++)
1475 if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
1476 && keyarray[idx]->subkeys
1477 && keyarray[idx]->subkeys->fpr
1478 && *keyarray[idx]->subkeys->fpr)
1479 p = stpcpy (stpcpy (p, keyarray[idx]->subkeys->fpr), "\n");
1482 err = gpgme_data_new_from_mem (&gpgsm->input_helper_data,
1489 gpgsm->input_helper_memory = buffer;
1491 gpgsm->input_cb.data = gpgsm->input_helper_data;
1492 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1495 gpgme_data_release (gpgsm->input_helper_data);
1496 gpgsm->input_helper_data = NULL;
1497 free (gpgsm->input_helper_memory);
1498 gpgsm->input_helper_memory = NULL;
1501 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1502 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1503 gpgsm->inline_data = NULL;
1505 return start (gpgsm, "IMPORT --re-import");
1507 else if (dataenc == GPGME_DATA_ENCODING_URL
1508 || dataenc == GPGME_DATA_ENCODING_URL0
1509 || dataenc == GPGME_DATA_ENCODING_URLESC)
1511 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1515 gpgsm->input_cb.data = keydata;
1516 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1519 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1520 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1521 gpgsm->inline_data = NULL;
1523 return start (gpgsm, "IMPORT");
1528 static gpgme_error_t
1529 gpgsm_keylist (void *engine, const char *pattern, int secret_only,
1530 gpgme_keylist_mode_t mode)
1532 engine_gpgsm_t gpgsm = engine;
1537 if (mode & GPGME_KEYLIST_MODE_LOCAL)
1539 if (mode & GPGME_KEYLIST_MODE_EXTERN)
1545 /* Hack to make sure that the agent is started. Only if the agent
1546 has been started an application may connect to the agent via
1547 GPGME_PROTOCOL_ASSUAN - for example to look for smartcards. We
1548 do this only if a secret key listing has been requested. In
1549 general this is not needed because a secret key listing starts
1550 the agent. However on a fresh installation no public keys are
1551 available and thus there is no need for gpgsm to ask the agent
1552 whether a secret key exists for the public key. */
1554 gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "GETINFO agent-check",
1557 /* Always send list-mode option because RESET does not reset it. */
1558 if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1559 return gpg_error_from_syserror ();
1560 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
1566 /* Always send key validation because RESET does not reset it. */
1568 /* Use the validation mode if requested. We don't check for an error
1569 yet because this is a pretty fresh gpgsm features. */
1570 gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
1571 (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1572 "OPTION with-validation=1":
1573 "OPTION with-validation=0" ,
1575 /* Include the ephemeral keys if requested. We don't check for an error
1576 yet because this is a pretty fresh gpgsm features. */
1577 gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
1578 (mode & GPGME_KEYLIST_MODE_EPHEMERAL)?
1579 "OPTION with-ephemeral-keys=1":
1580 "OPTION with-ephemeral-keys=0" ,
1584 /* Length is "LISTSECRETKEYS " + p + '\0'. */
1585 line = malloc (15 + strlen (pattern) + 1);
1587 return gpg_error_from_syserror ();
1590 strcpy (line, "LISTSECRETKEYS ");
1591 strcpy (&line[15], pattern);
1595 strcpy (line, "LISTKEYS ");
1596 strcpy (&line[9], pattern);
1599 gpgsm_clear_fd (gpgsm, INPUT_FD);
1600 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1601 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1602 gpgsm->inline_data = NULL;
1604 err = start (gpgsm, line);
1610 static gpgme_error_t
1611 gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
1612 int reserved, gpgme_keylist_mode_t mode)
1614 engine_gpgsm_t gpgsm = engine;
1617 /* Length is "LISTSECRETKEYS " + p + '\0'. */
1618 int length = 15 + 1;
1620 int any_pattern = 0;
1624 return gpg_error (GPG_ERR_INV_VALUE);
1626 if (mode & GPGME_KEYLIST_MODE_LOCAL)
1628 if (mode & GPGME_KEYLIST_MODE_EXTERN)
1631 /* Always send list-mode option because RESET does not reset it. */
1632 if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1633 return gpg_error_from_syserror ();
1634 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
1639 /* Always send key validation because RESET does not reset it. */
1640 /* Use the validation mode if required. We don't check for an error
1641 yet because this is a pretty fresh gpgsm features. */
1642 gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
1643 (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1644 "OPTION with-validation=1":
1645 "OPTION with-validation=0" ,
1649 if (pattern && *pattern)
1651 const char **pat = pattern;
1655 const char *patlet = *pat;
1660 if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1668 line = malloc (length);
1670 return gpg_error_from_syserror ();
1673 strcpy (line, "LISTSECRETKEYS ");
1678 strcpy (line, "LISTKEYS ");
1682 if (pattern && *pattern)
1686 const char *patlet = *pattern;
1708 *(linep++) = *patlet;
1722 gpgsm_clear_fd (gpgsm, INPUT_FD);
1723 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1724 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1725 gpgsm->inline_data = NULL;
1727 err = start (gpgsm, line);
1733 static gpgme_error_t
1734 gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
1735 gpgme_sig_mode_t mode, int use_armor, int use_textmode,
1736 int include_certs, gpgme_ctx_t ctx /* FIXME */)
1738 engine_gpgsm_t gpgsm = engine;
1745 return gpg_error (GPG_ERR_INV_VALUE);
1747 /* FIXME: This does not work as RESET does not reset it so we can't
1748 revert back to default. */
1749 if (include_certs != GPGME_INCLUDE_CERTS_DEFAULT)
1751 /* FIXME: Make sure that if we run multiple operations, that we
1752 can reset any previously set value in case the default is
1755 if (asprintf (&assuan_cmd, "OPTION include-certs %i", include_certs) < 0)
1756 return gpg_error_from_syserror ();
1757 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, assuan_cmd,
1764 for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1766 const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1767 if (s && strlen (s) < 80)
1771 strcpy (stpcpy (buf, "SIGNER "), s);
1772 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, buf,
1774 gpgsm->status.fnc_value);
1777 err = gpg_error (GPG_ERR_INV_VALUE);
1778 gpgme_key_unref (key);
1783 gpgsm->input_cb.data = in;
1784 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1787 gpgsm->output_cb.data = out;
1788 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1789 : map_data_enc (gpgsm->output_cb.data));
1792 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1793 gpgsm->inline_data = NULL;
1795 err = start (gpgsm, mode == GPGME_SIG_MODE_DETACH
1796 ? "SIGN --detached" : "SIGN");
1801 static gpgme_error_t
1802 gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
1803 gpgme_data_t plaintext)
1805 engine_gpgsm_t gpgsm = engine;
1809 return gpg_error (GPG_ERR_INV_VALUE);
1811 gpgsm->input_cb.data = sig;
1812 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1817 /* Normal or cleartext signature. */
1818 gpgsm->output_cb.data = plaintext;
1819 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1820 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1824 /* Detached signature. */
1825 gpgsm->message_cb.data = signed_text;
1826 err = gpgsm_set_fd (gpgsm, MESSAGE_FD, 0);
1827 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1829 gpgsm->inline_data = NULL;
1832 err = start (gpgsm, "VERIFY");
1838 /* Send the GETAUDITLOG command. The result is saved to a gpgme data
1840 static gpgme_error_t
1841 gpgsm_getauditlog (void *engine, gpgme_data_t output, unsigned int flags)
1843 engine_gpgsm_t gpgsm = engine;
1844 gpgme_error_t err = 0;
1846 if (!gpgsm || !output)
1847 return gpg_error (GPG_ERR_INV_VALUE);
1849 #if USE_DESCRIPTOR_PASSING
1850 gpgsm->output_cb.data = output;
1851 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1855 gpgsm_clear_fd (gpgsm, INPUT_FD);
1856 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1857 gpgsm->inline_data = NULL;
1858 # define CMD "GETAUDITLOG"
1860 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1861 gpgsm_clear_fd (gpgsm, INPUT_FD);
1862 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1863 gpgsm->inline_data = output;
1864 # define CMD "GETAUDITLOG --data"
1867 err = start (gpgsm, (flags & GPGME_AUDITLOG_HTML)? CMD " --html" : CMD);
1875 gpgsm_set_status_handler (void *engine, engine_status_handler_t fnc,
1878 engine_gpgsm_t gpgsm = engine;
1880 gpgsm->status.fnc = fnc;
1881 gpgsm->status.fnc_value = fnc_value;
1885 static gpgme_error_t
1886 gpgsm_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
1889 engine_gpgsm_t gpgsm = engine;
1891 gpgsm->colon.fnc = fnc;
1892 gpgsm->colon.fnc_value = fnc_value;
1893 gpgsm->colon.any = 0;
1899 gpgsm_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
1901 engine_gpgsm_t gpgsm = engine;
1902 gpgsm->io_cbs = *io_cbs;
1907 gpgsm_io_event (void *engine, gpgme_event_io_t type, void *type_data)
1909 engine_gpgsm_t gpgsm = engine;
1911 TRACE3 (DEBUG_ENGINE, "gpgme:gpgsm_io_event", gpgsm,
1912 "event %p, type %d, type_data %p",
1913 gpgsm->io_cbs.event, type, type_data);
1914 if (gpgsm->io_cbs.event)
1915 (*gpgsm->io_cbs.event) (gpgsm->io_cbs.event_priv, type, type_data);
1919 static gpgme_error_t
1920 gpgsm_passwd (void *engine, gpgme_key_t key, unsigned int flags)
1922 engine_gpgsm_t gpgsm = engine;
1926 if (!key || !key->subkeys || !key->subkeys->fpr)
1927 return gpg_error (GPG_ERR_INV_CERT_OBJ);
1929 if (asprintf (&line, "PASSWD -- %s", key->subkeys->fpr) < 0)
1930 return gpg_error_from_syserror ();
1932 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1933 gpgsm_clear_fd (gpgsm, INPUT_FD);
1934 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1935 gpgsm->inline_data = NULL;
1937 err = start (gpgsm, line);
1945 struct engine_ops _gpgme_engine_ops_gpgsm =
1947 /* Static functions. */
1948 _gpgme_get_gpgsm_path,
1951 gpgsm_get_req_version,
1954 /* Member functions. */
1956 #if USE_DESCRIPTOR_PASSING
1961 gpgsm_set_status_handler,
1962 NULL, /* set_command_handler */
1963 gpgsm_set_colon_line_handler,
1965 NULL, /* set_protocol */
1968 gpgsm_delete, /* decrypt_verify */
1971 NULL, /* encrypt_sign */
1979 NULL, /* trustlist */
1982 NULL, /* opassuan_transact */
1983 NULL, /* conf_load */
1984 NULL, /* conf_save */
1988 NULL, /* cancel_op */