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 #include <sys/types.h>
37 #include <fcntl.h> /* FIXME */
49 #include "status-table.h"
52 #include "engine-backend.h"
57 int fd; /* FD we talk about. */
58 int server_fd;/* Server FD for this connection. */
59 int dir; /* Inbound/Outbound, maybe given implicit? */
60 void *data; /* Handler-specific data. */
61 void *tag; /* ID from the user for gpgme_remove_io_callback. */
62 char server_fd_str[15]; /* Same as SERVER_FD but as a string. We
63 need this because _gpgme_io_fd2str can't
64 be used on a closed descriptor. */
70 assuan_context_t assuan_ctx;
75 iocb_data_t status_cb;
77 /* Input, output etc are from the servers perspective. */
79 gpgme_data_t input_helper_data; /* Input helper data object. */
80 void *input_helper_memory; /* Input helper memory block. */
82 iocb_data_t output_cb;
84 iocb_data_t message_cb;
88 engine_status_handler_t fnc;
94 engine_colon_line_handler_t fnc;
102 int any; /* any data line seen */
105 gpgme_data_t inline_data; /* Used to collect D lines. */
107 struct gpgme_io_cbs io_cbs;
110 typedef struct engine_gpgsm *engine_gpgsm_t;
113 static void gpgsm_io_event (void *engine,
114 gpgme_event_io_t type, void *type_data);
119 gpgsm_get_version (const char *file_name)
121 return _gpgme_get_program_version (file_name ? file_name
122 : _gpgme_get_gpgsm_path ());
127 gpgsm_get_req_version (void)
129 return NEED_GPGSM_VERSION;
134 close_notify_handler (int fd, void *opaque)
136 engine_gpgsm_t gpgsm = opaque;
139 if (gpgsm->status_cb.fd == fd)
141 if (gpgsm->status_cb.tag)
142 (*gpgsm->io_cbs.remove) (gpgsm->status_cb.tag);
143 gpgsm->status_cb.fd = -1;
144 gpgsm->status_cb.tag = NULL;
146 else if (gpgsm->input_cb.fd == fd)
148 if (gpgsm->input_cb.tag)
149 (*gpgsm->io_cbs.remove) (gpgsm->input_cb.tag);
150 gpgsm->input_cb.fd = -1;
151 gpgsm->input_cb.tag = NULL;
152 if (gpgsm->input_helper_data)
154 gpgme_data_release (gpgsm->input_helper_data);
155 gpgsm->input_helper_data = NULL;
157 if (gpgsm->input_helper_memory)
159 free (gpgsm->input_helper_memory);
160 gpgsm->input_helper_memory = NULL;
163 else if (gpgsm->output_cb.fd == fd)
165 if (gpgsm->output_cb.tag)
166 (*gpgsm->io_cbs.remove) (gpgsm->output_cb.tag);
167 gpgsm->output_cb.fd = -1;
168 gpgsm->output_cb.tag = NULL;
170 else if (gpgsm->message_cb.fd == fd)
172 if (gpgsm->message_cb.tag)
173 (*gpgsm->io_cbs.remove) (gpgsm->message_cb.tag);
174 gpgsm->message_cb.fd = -1;
175 gpgsm->message_cb.tag = NULL;
180 /* This is the default inquiry callback. We use it to handle the
181 Pinentry notifications. */
183 default_inq_cb (engine_gpgsm_t gpgsm, const char *line)
185 if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
187 _gpgme_allow_set_foreground_window ((pid_t)strtoul (line+17, NULL, 10));
195 gpgsm_cancel (void *engine)
197 engine_gpgsm_t gpgsm = engine;
200 return gpg_error (GPG_ERR_INV_VALUE);
202 if (gpgsm->status_cb.fd != -1)
203 _gpgme_io_close (gpgsm->status_cb.fd);
204 if (gpgsm->input_cb.fd != -1)
205 _gpgme_io_close (gpgsm->input_cb.fd);
206 if (gpgsm->output_cb.fd != -1)
207 _gpgme_io_close (gpgsm->output_cb.fd);
208 if (gpgsm->message_cb.fd != -1)
209 _gpgme_io_close (gpgsm->message_cb.fd);
211 if (gpgsm->assuan_ctx)
213 assuan_release (gpgsm->assuan_ctx);
214 gpgsm->assuan_ctx = NULL;
222 gpgsm_release (void *engine)
224 engine_gpgsm_t gpgsm = engine;
229 gpgsm_cancel (engine);
231 free (gpgsm->colon.attic.line);
237 gpgsm_new (void **engine, const char *file_name, const char *home_dir)
239 gpgme_error_t err = 0;
240 engine_gpgsm_t gpgsm;
243 #if !USE_DESCRIPTOR_PASSING
247 char *dft_display = NULL;
248 char dft_ttyname[64];
249 char *dft_ttytype = NULL;
252 gpgsm = calloc (1, sizeof *gpgsm);
254 return gpg_error_from_syserror ();
256 gpgsm->status_cb.fd = -1;
257 gpgsm->status_cb.dir = 1;
258 gpgsm->status_cb.tag = 0;
259 gpgsm->status_cb.data = gpgsm;
261 gpgsm->input_cb.fd = -1;
262 gpgsm->input_cb.dir = 0;
263 gpgsm->input_cb.tag = 0;
264 gpgsm->input_cb.server_fd = -1;
265 *gpgsm->input_cb.server_fd_str = 0;
266 gpgsm->output_cb.fd = -1;
267 gpgsm->output_cb.dir = 1;
268 gpgsm->output_cb.tag = 0;
269 gpgsm->output_cb.server_fd = -1;
270 *gpgsm->output_cb.server_fd_str = 0;
271 gpgsm->message_cb.fd = -1;
272 gpgsm->message_cb.dir = 0;
273 gpgsm->message_cb.tag = 0;
274 gpgsm->message_cb.server_fd = -1;
275 *gpgsm->message_cb.server_fd_str = 0;
277 gpgsm->status.fnc = 0;
278 gpgsm->colon.fnc = 0;
279 gpgsm->colon.attic.line = 0;
280 gpgsm->colon.attic.linesize = 0;
281 gpgsm->colon.attic.linelen = 0;
282 gpgsm->colon.any = 0;
284 gpgsm->inline_data = NULL;
286 gpgsm->io_cbs.add = NULL;
287 gpgsm->io_cbs.add_priv = NULL;
288 gpgsm->io_cbs.remove = NULL;
289 gpgsm->io_cbs.event = NULL;
290 gpgsm->io_cbs.event_priv = NULL;
292 #if !USE_DESCRIPTOR_PASSING
293 if (_gpgme_io_pipe (fds, 0) < 0)
295 err = gpg_error_from_syserror ();
298 gpgsm->input_cb.fd = fds[1];
299 gpgsm->input_cb.server_fd = fds[0];
301 if (_gpgme_io_pipe (fds, 1) < 0)
303 err = gpg_error_from_syserror ();
306 gpgsm->output_cb.fd = fds[0];
307 gpgsm->output_cb.server_fd = fds[1];
309 if (_gpgme_io_pipe (fds, 0) < 0)
311 err = gpg_error_from_syserror ();
314 gpgsm->message_cb.fd = fds[1];
315 gpgsm->message_cb.server_fd = fds[0];
317 child_fds[0] = gpgsm->input_cb.server_fd;
318 child_fds[1] = gpgsm->output_cb.server_fd;
319 child_fds[2] = gpgsm->message_cb.server_fd;
324 argv[argc++] = "gpgsm";
327 argv[argc++] = "--homedir";
328 argv[argc++] = home_dir;
330 argv[argc++] = "--server";
333 err = assuan_new_ext (&gpgsm->assuan_ctx, GPG_ERR_SOURCE_GPGME,
334 &_gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb,
338 assuan_ctx_set_system_hooks (gpgsm->assuan_ctx, &_gpgme_assuan_system_hooks);
340 #if USE_DESCRIPTOR_PASSING
341 err = assuan_pipe_connect
342 (gpgsm->assuan_ctx, file_name ? file_name : _gpgme_get_gpgsm_path (),
343 argv, NULL, NULL, NULL, ASSUAN_PIPE_CONNECT_FDPASSING);
346 assuan_fd_t achild_fds[4];
350 for (i = 0; i < 4; i++)
351 achild_fds[i] = (assuan_fd_t) child_fds[i];
353 err = assuan_pipe_connect
354 (gpgsm->assuan_ctx, file_name ? file_name : _gpgme_get_gpgsm_path (),
355 argv, achild_fds, NULL, NULL, 0);
358 for (i = 0; i < 4; i++)
359 child_fds[i] = (int) achild_fds[i];
362 /* On Windows, handles are inserted in the spawned process with
363 DuplicateHandle, and child_fds contains the server-local names
364 for the inserted handles when assuan_pipe_connect returns. */
367 /* Note: We don't use _gpgme_io_fd2str here. On W32 the
368 returned handles are real W32 system handles, not whatever
369 GPGME uses internally (which may be a system handle, a C
370 library handle or a GLib/Qt channel. Confusing, yes, but
371 remember these are server-local names, so they are not part
373 snprintf (gpgsm->input_cb.server_fd_str,
374 sizeof gpgsm->input_cb.server_fd_str, "%d", child_fds[0]);
375 snprintf (gpgsm->output_cb.server_fd_str,
376 sizeof gpgsm->output_cb.server_fd_str, "%d", child_fds[1]);
377 snprintf (gpgsm->message_cb.server_fd_str,
378 sizeof gpgsm->message_cb.server_fd_str, "%d", child_fds[2]);
384 err = _gpgme_getenv ("DISPLAY", &dft_display);
389 if (asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
392 err = gpg_error_from_syserror ();
397 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
408 rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
411 err = gpg_error_from_errno (rc);
416 if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
418 err = gpg_error_from_syserror ();
421 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
427 err = _gpgme_getenv ("TERM", &dft_ttytype);
432 if (asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype) < 0)
435 err = gpg_error_from_syserror ();
440 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
441 NULL, NULL, NULL, NULL);
449 /* Ask gpgsm to enable the audit log support. */
452 err = assuan_transact (gpgsm->assuan_ctx, "OPTION enable-audit-log=1",
453 NULL, NULL, NULL, NULL, NULL, NULL);
454 if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
455 err = 0; /* This is an optional feature of gpgsm. */
459 #ifdef HAVE_W32_SYSTEM
460 /* Under Windows we need to use AllowSetForegroundWindow. Tell
461 gpgsm to tell us when it needs it. */
464 err = assuan_transact (gpgsm->assuan_ctx, "OPTION allow-pinentry-notify",
465 NULL, NULL, NULL, NULL, NULL, NULL);
466 if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
467 err = 0; /* This is a new feature of gpgsm. */
469 #endif /*HAVE_W32_SYSTEM*/
471 #if !USE_DESCRIPTOR_PASSING
473 && (_gpgme_io_set_close_notify (gpgsm->input_cb.fd,
474 close_notify_handler, gpgsm)
475 || _gpgme_io_set_close_notify (gpgsm->output_cb.fd,
476 close_notify_handler, gpgsm)
477 || _gpgme_io_set_close_notify (gpgsm->message_cb.fd,
478 close_notify_handler, gpgsm)))
480 err = gpg_error (GPG_ERR_GENERAL);
486 /* Close the server ends of the pipes (because of this, we must use
487 the stored server_fd_str in the function start). Our ends are
488 closed in gpgsm_release(). */
489 #if !USE_DESCRIPTOR_PASSING
490 if (gpgsm->input_cb.server_fd != -1)
491 _gpgme_io_close (gpgsm->input_cb.server_fd);
492 if (gpgsm->output_cb.server_fd != -1)
493 _gpgme_io_close (gpgsm->output_cb.server_fd);
494 if (gpgsm->message_cb.server_fd != -1)
495 _gpgme_io_close (gpgsm->message_cb.server_fd);
499 gpgsm_release (gpgsm);
508 gpgsm_set_locale (void *engine, int category, const char *value)
510 engine_gpgsm_t gpgsm = engine;
515 /* FIXME: If value is NULL, we need to reset the option to default.
516 But we can't do this. So we error out here. GPGSM needs support
521 else if (category == LC_CTYPE)
524 if (!value && gpgsm->lc_ctype_set)
525 return gpg_error (GPG_ERR_INV_VALUE);
527 gpgsm->lc_ctype_set = 1;
531 else if (category == LC_MESSAGES)
533 catstr = "lc-messages";
534 if (!value && gpgsm->lc_messages_set)
535 return gpg_error (GPG_ERR_INV_VALUE);
537 gpgsm->lc_messages_set = 1;
539 #endif /* LC_MESSAGES */
541 return gpg_error (GPG_ERR_INV_VALUE);
543 /* FIXME: Reset value to default. */
547 if (asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0)
548 err = gpg_error_from_syserror ();
551 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
552 NULL, NULL, NULL, NULL);
560 /* Forward declaration. */
561 static gpgme_status_code_t parse_status (const char *name);
564 gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd,
565 engine_status_handler_t status_fnc,
566 void *status_fnc_value)
572 err = assuan_write_line (ctx, cmd);
578 err = assuan_read_line (ctx, &line, &linelen);
582 if (*line == '#' || !linelen)
586 && line[0] == 'O' && line[1] == 'K'
587 && (line[2] == '\0' || line[2] == ' '))
589 else if (linelen >= 4
590 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
592 err = atoi (&line[4]);
593 else if (linelen >= 2
594 && line[0] == 'S' && line[1] == ' ')
597 gpgme_status_code_t r;
599 rest = strchr (line + 2, ' ');
601 rest = line + linelen; /* set to an empty string */
605 r = parse_status (line + 2);
607 if (r >= 0 && status_fnc)
608 err = status_fnc (status_fnc_value, r, rest);
610 err = gpg_error (GPG_ERR_GENERAL);
613 err = gpg_error (GPG_ERR_GENERAL);
621 typedef enum { INPUT_FD, OUTPUT_FD, MESSAGE_FD } fd_type_t;
624 gpgsm_clear_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type)
626 #if !USE_DESCRIPTOR_PASSING
630 _gpgme_io_close (gpgsm->input_cb.fd);
633 _gpgme_io_close (gpgsm->output_cb.fd);
636 _gpgme_io_close (gpgsm->message_cb.fd);
642 #define COMMANDLINELEN 40
644 gpgsm_set_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type, const char *opt)
647 char line[COMMANDLINELEN];
649 iocb_data_t *iocb_data;
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 dir = iocb_data->dir;
675 #if USE_DESCRIPTOR_PASSING
676 /* We try to short-cut the communication by giving GPGSM direct
677 access to the file descriptor, rather than using a pipe. */
678 iocb_data->server_fd = _gpgme_data_get_fd (iocb_data->data);
679 if (iocb_data->server_fd < 0)
683 if (_gpgme_io_pipe (fds, dir) < 0)
684 return gpg_error_from_syserror ();
686 iocb_data->fd = dir ? fds[0] : fds[1];
687 iocb_data->server_fd = dir ? fds[1] : fds[0];
689 if (_gpgme_io_set_close_notify (iocb_data->fd,
690 close_notify_handler, gpgsm))
692 err = gpg_error (GPG_ERR_GENERAL);
697 err = assuan_sendfd (gpgsm->assuan_ctx, iocb_data->server_fd);
701 _gpgme_io_close (iocb_data->server_fd);
702 iocb_data->server_fd = -1;
705 snprintf (line, COMMANDLINELEN, "%s FD %s", which, opt);
707 snprintf (line, COMMANDLINELEN, "%s FD", which);
710 snprintf (line, COMMANDLINELEN, "%s FD=%s %s",
711 which, iocb_data->server_fd_str, opt);
713 snprintf (line, COMMANDLINELEN, "%s FD=%s",
714 which, iocb_data->server_fd_str);
717 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
719 #if USE_DESCRIPTOR_PASSING
723 _gpgme_io_close (iocb_data->fd);
725 if (iocb_data->server_fd != -1)
727 _gpgme_io_close (iocb_data->server_fd);
728 iocb_data->server_fd = -1;
738 map_data_enc (gpgme_data_t d)
740 switch (gpgme_data_get_encoding (d))
742 case GPGME_DATA_ENCODING_NONE:
744 case GPGME_DATA_ENCODING_BINARY:
746 case GPGME_DATA_ENCODING_BASE64:
748 case GPGME_DATA_ENCODING_ARMOR:
758 status_cmp (const void *ap, const void *bp)
760 const struct status_table_s *a = ap;
761 const struct status_table_s *b = bp;
763 return strcmp (a->name, b->name);
767 static gpgme_status_code_t
768 parse_status (const char *name)
770 struct status_table_s t, *r;
772 r = bsearch (&t, status_table, DIM(status_table) - 1,
773 sizeof t, status_cmp);
774 return r ? r->code : -1;
779 status_handler (void *opaque, int fd)
781 struct io_cb_data *data = (struct io_cb_data *) opaque;
782 engine_gpgsm_t gpgsm = (engine_gpgsm_t) data->handler_value;
783 gpgme_error_t err = 0;
789 err = assuan_read_line (gpgsm->assuan_ctx, &line, &linelen);
792 /* Try our best to terminate the connection friendly. */
793 /* assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
794 TRACE3 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
795 "fd 0x%x: error from assuan (%d) getting status line : %s",
796 fd, err, gpg_strerror (err));
798 else if (linelen >= 3
799 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
800 && (line[3] == '\0' || line[3] == ' '))
803 err = atoi (&line[4]);
805 err = gpg_error (GPG_ERR_GENERAL);
806 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
807 "fd 0x%x: ERR line - mapped to: %s",
808 fd, err ? gpg_strerror (err) : "ok");
809 /* Try our best to terminate the connection friendly. */
810 /* assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
812 else if (linelen >= 2
813 && line[0] == 'O' && line[1] == 'K'
814 && (line[2] == '\0' || line[2] == ' '))
816 if (gpgsm->status.fnc)
817 err = gpgsm->status.fnc (gpgsm->status.fnc_value,
818 GPGME_STATUS_EOF, "");
820 if (!err && gpgsm->colon.fnc && gpgsm->colon.any)
822 /* We must tell a colon function about the EOF. We do
823 this only when we have seen any data lines. Note
824 that this inlined use of colon data lines will
825 eventually be changed into using a regular data
827 gpgsm->colon.any = 0;
828 err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, NULL);
830 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
831 "fd 0x%x: OK line - final status: %s",
832 fd, err ? gpg_strerror (err) : "ok");
833 _gpgme_io_close (gpgsm->status_cb.fd);
837 && line[0] == 'D' && line[1] == ' '
840 /* We are using the colon handler even for plain inline data
841 - strange name for that function but for historic reasons
843 /* FIXME We can't use this for binary data because we
844 assume this is a string. For the current usage of colon
845 output it is correct. */
846 char *src = line + 2;
847 char *end = line + linelen;
849 char **aline = &gpgsm->colon.attic.line;
850 int *alinelen = &gpgsm->colon.attic.linelen;
852 if (gpgsm->colon.attic.linesize < *alinelen + linelen + 1)
854 char *newline = realloc (*aline, *alinelen + linelen + 1);
856 err = gpg_error_from_syserror ();
860 gpgsm->colon.attic.linesize += linelen + 1;
865 dst = *aline + *alinelen;
867 while (!err && src < end)
869 if (*src == '%' && src + 2 < end)
871 /* Handle escaped characters. */
873 *dst = _gpgme_hextobyte (src);
885 /* Terminate the pending line, pass it to the colon
886 handler and reset it. */
888 gpgsm->colon.any = 1;
889 if (*alinelen > 1 && *(dst - 1) == '\r')
893 /* FIXME How should we handle the return code? */
894 err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, *aline);
905 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
906 "fd 0x%x: D line; final status: %s",
907 fd, err? gpg_strerror (err):"ok");
910 && line[0] == 'D' && line[1] == ' '
911 && gpgsm->inline_data)
913 char *src = line + 2;
914 char *end = line + linelen;
921 if (*src == '%' && src + 2 < end)
923 /* Handle escaped characters. */
925 *dst++ = _gpgme_hextobyte (src);
937 nwritten = gpgme_data_write (gpgsm->inline_data, src, linelen);
938 if (!nwritten || (nwritten < 0 && errno != EINTR)
939 || nwritten > linelen)
941 err = gpg_error_from_syserror ();
948 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
949 "fd 0x%x: D inlinedata; final status: %s",
950 fd, err? gpg_strerror (err):"ok");
953 && line[0] == 'S' && line[1] == ' ')
956 gpgme_status_code_t r;
958 rest = strchr (line + 2, ' ');
960 rest = line + linelen; /* set to an empty string */
964 r = parse_status (line + 2);
968 if (gpgsm->status.fnc)
969 err = gpgsm->status.fnc (gpgsm->status.fnc_value, r, rest);
972 fprintf (stderr, "[UNKNOWN STATUS]%s %s", line + 2, rest);
973 TRACE3 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
974 "fd 0x%x: S line (%s) - final status: %s",
975 fd, line+2, err? gpg_strerror (err):"ok");
977 else if (linelen >= 7
978 && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
979 && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
981 && (line[7] == '\0' || line[7] == ' '))
983 char *keyword = line+7;
985 while (*keyword == ' ')
987 default_inq_cb (gpgsm, keyword);
988 assuan_write_line (gpgsm->assuan_ctx, "END");
992 while (!err && assuan_pending_line (gpgsm->assuan_ctx));
999 add_io_cb (engine_gpgsm_t gpgsm, iocb_data_t *iocbd, gpgme_io_cb_t handler)
1003 TRACE_BEG2 (DEBUG_ENGINE, "engine-gpgsm:add_io_cb", gpgsm,
1004 "fd %d, dir %d", iocbd->fd, iocbd->dir);
1005 err = (*gpgsm->io_cbs.add) (gpgsm->io_cbs.add_priv,
1006 iocbd->fd, iocbd->dir,
1007 handler, iocbd->data, &iocbd->tag);
1009 return TRACE_ERR (err);
1011 /* FIXME Kludge around poll() problem. */
1012 err = _gpgme_io_set_nonblocking (iocbd->fd);
1013 return TRACE_ERR (err);
1017 static gpgme_error_t
1018 start (engine_gpgsm_t gpgsm, const char *command)
1021 assuan_fd_t afdlist[5];
1026 /* We need to know the fd used by assuan for reads. We do this by
1027 using the assumption that the first returned fd from
1028 assuan_get_active_fds() is always this one. */
1029 nfds = assuan_get_active_fds (gpgsm->assuan_ctx, 0 /* read fds */,
1030 afdlist, DIM (afdlist));
1032 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1034 for (i = 0; i < nfds; i++)
1035 fdlist[i] = (int) afdlist[i];
1037 /* We "duplicate" the file descriptor, so we can close it here (we
1038 can't close fdlist[0], as that is closed by libassuan, and
1039 closing it here might cause libassuan to close some unrelated FD
1040 later). Alternatively, we could special case status_fd and
1041 register/unregister it manually as needed, but this increases
1042 code duplication and is more complicated as we can not use the
1043 close notifications etc. A third alternative would be to let
1044 Assuan know that we closed the FD, but that complicates the
1045 Assuan interface. */
1047 gpgsm->status_cb.fd = _gpgme_io_dup (fdlist[0]);
1048 if (gpgsm->status_cb.fd < 0)
1049 return gpg_error_from_syserror ();
1051 if (_gpgme_io_set_close_notify (gpgsm->status_cb.fd,
1052 close_notify_handler, gpgsm))
1054 _gpgme_io_close (gpgsm->status_cb.fd);
1055 gpgsm->status_cb.fd = -1;
1056 return gpg_error (GPG_ERR_GENERAL);
1059 err = add_io_cb (gpgsm, &gpgsm->status_cb, status_handler);
1060 if (!err && gpgsm->input_cb.fd != -1)
1061 err = add_io_cb (gpgsm, &gpgsm->input_cb, _gpgme_data_outbound_handler);
1062 if (!err && gpgsm->output_cb.fd != -1)
1063 err = add_io_cb (gpgsm, &gpgsm->output_cb, _gpgme_data_inbound_handler);
1064 if (!err && gpgsm->message_cb.fd != -1)
1065 err = add_io_cb (gpgsm, &gpgsm->message_cb, _gpgme_data_outbound_handler);
1068 err = assuan_write_line (gpgsm->assuan_ctx, command);
1071 gpgsm_io_event (gpgsm, GPGME_EVENT_START, NULL);
1077 #if USE_DESCRIPTOR_PASSING
1078 static gpgme_error_t
1079 gpgsm_reset (void *engine)
1081 engine_gpgsm_t gpgsm = engine;
1083 /* IF we have an active connection we must send a reset because we
1084 need to reset the list of signers. Note that RESET does not
1085 reset OPTION commands. */
1086 return (gpgsm->assuan_ctx
1087 ? gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "RESET",
1095 static gpgme_error_t
1096 gpgsm_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
1098 engine_gpgsm_t gpgsm = engine;
1102 return gpg_error (GPG_ERR_INV_VALUE);
1104 gpgsm->input_cb.data = ciph;
1105 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1107 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1108 gpgsm->output_cb.data = plain;
1109 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1111 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1112 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1113 gpgsm->inline_data = NULL;
1115 err = start (engine, "DECRYPT");
1120 static gpgme_error_t
1121 gpgsm_delete (void *engine, gpgme_key_t key, int allow_secret)
1123 engine_gpgsm_t gpgsm = engine;
1125 char *fpr = key->subkeys ? key->subkeys->fpr : NULL;
1128 int length = 8; /* "DELKEYS " */
1131 return gpg_error (GPG_ERR_INV_VALUE);
1136 if (*linep == '%' || *linep == ' ' || *linep == '+')
1142 line = malloc (length);
1144 return gpg_error_from_syserror ();
1146 strcpy (line, "DELKEYS ");
1176 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1177 gpgsm_clear_fd (gpgsm, INPUT_FD);
1178 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1179 gpgsm->inline_data = NULL;
1181 err = start (gpgsm, line);
1188 static gpgme_error_t
1189 set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[])
1191 gpgme_error_t err = 0;
1192 assuan_context_t ctx = gpgsm->assuan_ctx;
1195 int invalid_recipients = 0;
1198 linelen = 10 + 40 + 1; /* "RECIPIENT " + guess + '\0'. */
1199 line = malloc (10 + 40 + 1);
1201 return gpg_error_from_syserror ();
1202 strcpy (line, "RECIPIENT ");
1203 for (i =0; !err && recp[i]; i++)
1208 if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
1210 invalid_recipients++;
1213 fpr = recp[i]->subkeys->fpr;
1215 newlen = 11 + strlen (fpr);
1216 if (linelen < newlen)
1218 char *newline = realloc (line, newlen);
1221 int saved_errno = errno;
1223 return gpg_error_from_errno (saved_errno);
1228 strcpy (&line[10], fpr);
1230 err = gpgsm_assuan_simple_command (ctx, line, gpgsm->status.fnc,
1231 gpgsm->status.fnc_value);
1232 /* FIXME: This requires more work. */
1233 if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
1234 invalid_recipients++;
1242 return gpg_error (invalid_recipients
1243 ? GPG_ERR_UNUSABLE_PUBKEY : GPG_ERR_NO_ERROR);
1247 static gpgme_error_t
1248 gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
1249 gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
1251 engine_gpgsm_t gpgsm = engine;
1255 return gpg_error (GPG_ERR_INV_VALUE);
1257 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1259 if (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO)
1261 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
1262 "OPTION no-encrypt-to", NULL, NULL);
1267 gpgsm->input_cb.data = plain;
1268 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1271 gpgsm->output_cb.data = ciph;
1272 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1273 : map_data_enc (gpgsm->output_cb.data));
1276 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1277 gpgsm->inline_data = NULL;
1279 err = set_recipients (gpgsm, recp);
1282 err = start (gpgsm, "ENCRYPT");
1288 static gpgme_error_t
1289 gpgsm_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
1290 gpgme_data_t keydata, int use_armor)
1292 engine_gpgsm_t gpgsm = engine;
1293 gpgme_error_t err = 0;
1297 return gpg_error (GPG_ERR_INV_VALUE);
1300 return gpg_error (GPG_ERR_NOT_SUPPORTED);
1305 cmd = malloc (7 + strlen (pattern) + 1);
1307 return gpg_error_from_syserror ();
1308 strcpy (cmd, "EXPORT ");
1309 strcpy (&cmd[7], pattern);
1311 gpgsm->output_cb.data = keydata;
1312 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1313 : map_data_enc (gpgsm->output_cb.data));
1316 gpgsm_clear_fd (gpgsm, INPUT_FD);
1317 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1318 gpgsm->inline_data = NULL;
1320 err = start (gpgsm, cmd);
1326 static gpgme_error_t
1327 gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
1328 gpgme_data_t keydata, int use_armor)
1330 engine_gpgsm_t gpgsm = engine;
1331 gpgme_error_t err = 0;
1333 /* Length is "EXPORT " + p + '\0'. */
1338 return gpg_error (GPG_ERR_INV_VALUE);
1341 return gpg_error (GPG_ERR_NOT_SUPPORTED);
1343 if (pattern && *pattern)
1345 const char **pat = pattern;
1349 const char *patlet = *pat;
1354 if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1362 line = malloc (length);
1364 return gpg_error_from_syserror ();
1366 strcpy (line, "EXPORT ");
1369 if (pattern && *pattern)
1373 const char *patlet = *pattern;
1395 *(linep++) = *patlet;
1407 gpgsm->output_cb.data = keydata;
1408 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1409 : map_data_enc (gpgsm->output_cb.data));
1412 gpgsm_clear_fd (gpgsm, INPUT_FD);
1413 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1414 gpgsm->inline_data = NULL;
1416 err = start (gpgsm, line);
1422 static gpgme_error_t
1423 gpgsm_genkey (void *engine, gpgme_data_t help_data, int use_armor,
1424 gpgme_data_t pubkey, gpgme_data_t seckey)
1426 engine_gpgsm_t gpgsm = engine;
1429 if (!gpgsm || !pubkey || seckey)
1430 return gpg_error (GPG_ERR_INV_VALUE);
1432 gpgsm->input_cb.data = help_data;
1433 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1436 gpgsm->output_cb.data = pubkey;
1437 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1438 : map_data_enc (gpgsm->output_cb.data));
1441 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1442 gpgsm->inline_data = NULL;
1444 err = start (gpgsm, "GENKEY");
1449 static gpgme_error_t
1450 gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
1452 engine_gpgsm_t gpgsm = engine;
1454 gpgme_data_encoding_t dataenc;
1458 return gpg_error (GPG_ERR_INV_VALUE);
1460 if (keydata && keyarray)
1461 return gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed. */
1463 dataenc = gpgme_data_get_encoding (keydata);
1470 /* Fist check whether the engine already features the
1471 --re-import option. */
1472 err = gpgsm_assuan_simple_command
1474 "GETINFO cmd_has_option IMPORT re-import", NULL, NULL);
1476 return gpg_error (GPG_ERR_NOT_SUPPORTED);
1478 /* Create an internal data object with a list of all
1479 fingerprints. The data object and its memory (to avoid an
1480 extra copy by gpgme_data_new_from_mem) are stored in two
1481 variables which are released by the close_notify_handler. */
1482 for (idx=0, buflen=0; keyarray[idx]; idx++)
1484 if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
1485 && keyarray[idx]->subkeys
1486 && keyarray[idx]->subkeys->fpr
1487 && *keyarray[idx]->subkeys->fpr)
1488 buflen += strlen (keyarray[idx]->subkeys->fpr) + 1;
1490 /* Allocate a bufer with extra space for the trailing Nul
1491 introduced by the use of stpcpy. */
1492 buffer = malloc (buflen+1);
1494 return gpg_error_from_syserror ();
1495 for (idx=0, p = buffer; keyarray[idx]; idx++)
1497 if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
1498 && keyarray[idx]->subkeys
1499 && keyarray[idx]->subkeys->fpr
1500 && *keyarray[idx]->subkeys->fpr)
1501 p = stpcpy (stpcpy (p, keyarray[idx]->subkeys->fpr), "\n");
1504 err = gpgme_data_new_from_mem (&gpgsm->input_helper_data,
1511 gpgsm->input_helper_memory = buffer;
1513 gpgsm->input_cb.data = gpgsm->input_helper_data;
1514 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1517 gpgme_data_release (gpgsm->input_helper_data);
1518 gpgsm->input_helper_data = NULL;
1519 free (gpgsm->input_helper_memory);
1520 gpgsm->input_helper_memory = NULL;
1523 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1524 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1525 gpgsm->inline_data = NULL;
1527 return start (gpgsm, "IMPORT --re-import");
1529 else if (dataenc == GPGME_DATA_ENCODING_URL
1530 || dataenc == GPGME_DATA_ENCODING_URL0
1531 || dataenc == GPGME_DATA_ENCODING_URLESC)
1533 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1537 gpgsm->input_cb.data = keydata;
1538 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1541 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1542 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1543 gpgsm->inline_data = NULL;
1545 return start (gpgsm, "IMPORT");
1550 static gpgme_error_t
1551 gpgsm_keylist (void *engine, const char *pattern, int secret_only,
1552 gpgme_keylist_mode_t mode)
1554 engine_gpgsm_t gpgsm = engine;
1559 if (mode & GPGME_KEYLIST_MODE_LOCAL)
1561 if (mode & GPGME_KEYLIST_MODE_EXTERN)
1567 /* Hack to make sure that the agent is started. Only if the agent
1568 has been started an application may connect to the agent via
1569 GPGME_PROTOCOL_ASSUAN - for example to look for smartcards. We
1570 do this only if a secret key listing has been requested. In
1571 general this is not needed because a secret key listing starts
1572 the agent. However on a fresh installation no public keys are
1573 available and thus there is no need for gpgsm to ask the agent
1574 whether a secret key exists for the public key. */
1576 gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "GETINFO agent-check",
1579 /* Always send list-mode option because RESET does not reset it. */
1580 if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1581 return gpg_error_from_syserror ();
1582 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
1588 /* Always send key validation because RESET does not reset it. */
1590 /* Use the validation mode if requested. We don't check for an error
1591 yet because this is a pretty fresh gpgsm features. */
1592 gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
1593 (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1594 "OPTION with-validation=1":
1595 "OPTION with-validation=0" ,
1597 /* Include the ephemeral keys if requested. We don't check for an error
1598 yet because this is a pretty fresh gpgsm features. */
1599 gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
1600 (mode & GPGME_KEYLIST_MODE_EPHEMERAL)?
1601 "OPTION with-ephemeral-keys=1":
1602 "OPTION with-ephemeral-keys=0" ,
1606 /* Length is "LISTSECRETKEYS " + p + '\0'. */
1607 line = malloc (15 + strlen (pattern) + 1);
1609 return gpg_error_from_syserror ();
1612 strcpy (line, "LISTSECRETKEYS ");
1613 strcpy (&line[15], pattern);
1617 strcpy (line, "LISTKEYS ");
1618 strcpy (&line[9], pattern);
1621 gpgsm_clear_fd (gpgsm, INPUT_FD);
1622 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1623 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1624 gpgsm->inline_data = NULL;
1626 err = start (gpgsm, line);
1632 static gpgme_error_t
1633 gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
1634 int reserved, gpgme_keylist_mode_t mode)
1636 engine_gpgsm_t gpgsm = engine;
1639 /* Length is "LISTSECRETKEYS " + p + '\0'. */
1640 int length = 15 + 1;
1642 int any_pattern = 0;
1646 return gpg_error (GPG_ERR_INV_VALUE);
1648 if (mode & GPGME_KEYLIST_MODE_LOCAL)
1650 if (mode & GPGME_KEYLIST_MODE_EXTERN)
1653 /* Always send list-mode option because RESET does not reset it. */
1654 if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1655 return gpg_error_from_syserror ();
1656 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
1661 /* Always send key validation because RESET does not reset it. */
1662 /* Use the validation mode if required. We don't check for an error
1663 yet because this is a pretty fresh gpgsm features. */
1664 gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
1665 (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1666 "OPTION with-validation=1":
1667 "OPTION with-validation=0" ,
1671 if (pattern && *pattern)
1673 const char **pat = pattern;
1677 const char *patlet = *pat;
1682 if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1690 line = malloc (length);
1692 return gpg_error_from_syserror ();
1695 strcpy (line, "LISTSECRETKEYS ");
1700 strcpy (line, "LISTKEYS ");
1704 if (pattern && *pattern)
1708 const char *patlet = *pattern;
1730 *(linep++) = *patlet;
1744 gpgsm_clear_fd (gpgsm, INPUT_FD);
1745 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1746 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1747 gpgsm->inline_data = NULL;
1749 err = start (gpgsm, line);
1755 static gpgme_error_t
1756 gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
1757 gpgme_sig_mode_t mode, int use_armor, int use_textmode,
1758 int include_certs, gpgme_ctx_t ctx /* FIXME */)
1760 engine_gpgsm_t gpgsm = engine;
1767 return gpg_error (GPG_ERR_INV_VALUE);
1769 /* FIXME: This does not work as RESET does not reset it so we can't
1770 revert back to default. */
1771 if (include_certs != GPGME_INCLUDE_CERTS_DEFAULT)
1773 /* FIXME: Make sure that if we run multiple operations, that we
1774 can reset any previously set value in case the default is
1777 if (asprintf (&assuan_cmd, "OPTION include-certs %i", include_certs) < 0)
1778 return gpg_error_from_syserror ();
1779 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, assuan_cmd,
1786 for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1788 const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1789 if (s && strlen (s) < 80)
1793 strcpy (stpcpy (buf, "SIGNER "), s);
1794 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, buf,
1796 gpgsm->status.fnc_value);
1799 err = gpg_error (GPG_ERR_INV_VALUE);
1800 gpgme_key_unref (key);
1805 gpgsm->input_cb.data = in;
1806 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1809 gpgsm->output_cb.data = out;
1810 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1811 : map_data_enc (gpgsm->output_cb.data));
1814 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1815 gpgsm->inline_data = NULL;
1817 err = start (gpgsm, mode == GPGME_SIG_MODE_DETACH
1818 ? "SIGN --detached" : "SIGN");
1823 static gpgme_error_t
1824 gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
1825 gpgme_data_t plaintext)
1827 engine_gpgsm_t gpgsm = engine;
1831 return gpg_error (GPG_ERR_INV_VALUE);
1833 gpgsm->input_cb.data = sig;
1834 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1839 /* Normal or cleartext signature. */
1840 gpgsm->output_cb.data = plaintext;
1841 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1842 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1846 /* Detached signature. */
1847 gpgsm->message_cb.data = signed_text;
1848 err = gpgsm_set_fd (gpgsm, MESSAGE_FD, 0);
1849 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1851 gpgsm->inline_data = NULL;
1854 err = start (gpgsm, "VERIFY");
1860 /* Send the GETAUDITLOG command. The result is saved to a gpgme data
1862 static gpgme_error_t
1863 gpgsm_getauditlog (void *engine, gpgme_data_t output, unsigned int flags)
1865 engine_gpgsm_t gpgsm = engine;
1866 gpgme_error_t err = 0;
1868 if (!gpgsm || !output)
1869 return gpg_error (GPG_ERR_INV_VALUE);
1871 #if USE_DESCRIPTOR_PASSING
1872 gpgsm->output_cb.data = output;
1873 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1877 gpgsm_clear_fd (gpgsm, INPUT_FD);
1878 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1879 gpgsm->inline_data = NULL;
1880 # define CMD "GETAUDITLOG"
1882 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1883 gpgsm_clear_fd (gpgsm, INPUT_FD);
1884 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1885 gpgsm->inline_data = output;
1886 # define CMD "GETAUDITLOG --data"
1889 err = start (gpgsm, (flags & GPGME_AUDITLOG_HTML)? CMD " --html" : CMD);
1897 gpgsm_set_status_handler (void *engine, engine_status_handler_t fnc,
1900 engine_gpgsm_t gpgsm = engine;
1902 gpgsm->status.fnc = fnc;
1903 gpgsm->status.fnc_value = fnc_value;
1907 static gpgme_error_t
1908 gpgsm_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
1911 engine_gpgsm_t gpgsm = engine;
1913 gpgsm->colon.fnc = fnc;
1914 gpgsm->colon.fnc_value = fnc_value;
1915 gpgsm->colon.any = 0;
1921 gpgsm_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
1923 engine_gpgsm_t gpgsm = engine;
1924 gpgsm->io_cbs = *io_cbs;
1929 gpgsm_io_event (void *engine, gpgme_event_io_t type, void *type_data)
1931 engine_gpgsm_t gpgsm = engine;
1933 TRACE3 (DEBUG_ENGINE, "gpgme:gpgsm_io_event", gpgsm,
1934 "event %p, type %d, type_data %p",
1935 gpgsm->io_cbs.event, type, type_data);
1936 if (gpgsm->io_cbs.event)
1937 (*gpgsm->io_cbs.event) (gpgsm->io_cbs.event_priv, type, type_data);
1941 static gpgme_error_t
1942 gpgsm_passwd (void *engine, gpgme_key_t key, unsigned int flags)
1944 engine_gpgsm_t gpgsm = engine;
1948 if (!key || !key->subkeys || !key->subkeys->fpr)
1949 return gpg_error (GPG_ERR_INV_CERT_OBJ);
1951 if (asprintf (&line, "PASSWD -- %s", key->subkeys->fpr) < 0)
1952 return gpg_error_from_syserror ();
1954 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1955 gpgsm_clear_fd (gpgsm, INPUT_FD);
1956 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1957 gpgsm->inline_data = NULL;
1959 err = start (gpgsm, line);
1967 struct engine_ops _gpgme_engine_ops_gpgsm =
1969 /* Static functions. */
1970 _gpgme_get_gpgsm_path,
1973 gpgsm_get_req_version,
1976 /* Member functions. */
1978 #if USE_DESCRIPTOR_PASSING
1983 gpgsm_set_status_handler,
1984 NULL, /* set_command_handler */
1985 gpgsm_set_colon_line_handler,
1987 NULL, /* set_protocol */
1990 gpgsm_delete, /* decrypt_verify */
1993 NULL, /* encrypt_sign */
2001 NULL, /* trustlist */
2004 NULL, /* opassuan_transact */
2005 NULL, /* conf_load */
2006 NULL, /* conf_save */
2010 NULL, /* cancel_op */