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;
91 gpgme_status_cb_t mon_cb;
97 engine_colon_line_handler_t fnc;
105 int any; /* any data line seen */
108 gpgme_data_t inline_data; /* Used to collect D lines. */
110 char request_origin[10];
112 struct gpgme_io_cbs io_cbs;
115 typedef struct engine_gpgsm *engine_gpgsm_t;
118 static void gpgsm_io_event (void *engine,
119 gpgme_event_io_t type, void *type_data);
124 gpgsm_get_version (const char *file_name)
126 return _gpgme_get_program_version (file_name ? file_name
127 : _gpgme_get_default_gpgsm_name ());
132 gpgsm_get_req_version (void)
139 close_notify_handler (int fd, void *opaque)
141 engine_gpgsm_t gpgsm = opaque;
144 if (gpgsm->status_cb.fd == fd)
146 if (gpgsm->status_cb.tag)
147 (*gpgsm->io_cbs.remove) (gpgsm->status_cb.tag);
148 gpgsm->status_cb.fd = -1;
149 gpgsm->status_cb.tag = NULL;
151 else if (gpgsm->input_cb.fd == fd)
153 if (gpgsm->input_cb.tag)
154 (*gpgsm->io_cbs.remove) (gpgsm->input_cb.tag);
155 gpgsm->input_cb.fd = -1;
156 gpgsm->input_cb.tag = NULL;
157 if (gpgsm->input_helper_data)
159 gpgme_data_release (gpgsm->input_helper_data);
160 gpgsm->input_helper_data = NULL;
162 if (gpgsm->input_helper_memory)
164 free (gpgsm->input_helper_memory);
165 gpgsm->input_helper_memory = NULL;
168 else if (gpgsm->output_cb.fd == fd)
170 if (gpgsm->output_cb.tag)
171 (*gpgsm->io_cbs.remove) (gpgsm->output_cb.tag);
172 gpgsm->output_cb.fd = -1;
173 gpgsm->output_cb.tag = NULL;
175 else if (gpgsm->message_cb.fd == fd)
177 if (gpgsm->message_cb.tag)
178 (*gpgsm->io_cbs.remove) (gpgsm->message_cb.tag);
179 gpgsm->message_cb.fd = -1;
180 gpgsm->message_cb.tag = NULL;
185 /* This is the default inquiry callback. We use it to handle the
186 Pinentry notifications. */
188 default_inq_cb (engine_gpgsm_t gpgsm, const char *line)
192 if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
194 _gpgme_allow_set_foreground_window ((pid_t)strtoul (line+17, NULL, 10));
202 gpgsm_cancel (void *engine)
204 engine_gpgsm_t gpgsm = engine;
207 return gpg_error (GPG_ERR_INV_VALUE);
209 if (gpgsm->status_cb.fd != -1)
210 _gpgme_io_close (gpgsm->status_cb.fd);
211 if (gpgsm->input_cb.fd != -1)
212 _gpgme_io_close (gpgsm->input_cb.fd);
213 if (gpgsm->output_cb.fd != -1)
214 _gpgme_io_close (gpgsm->output_cb.fd);
215 if (gpgsm->message_cb.fd != -1)
216 _gpgme_io_close (gpgsm->message_cb.fd);
218 if (gpgsm->assuan_ctx)
220 assuan_release (gpgsm->assuan_ctx);
221 gpgsm->assuan_ctx = NULL;
229 gpgsm_release (void *engine)
231 engine_gpgsm_t gpgsm = engine;
236 gpgsm_cancel (engine);
238 free (gpgsm->colon.attic.line);
244 gpgsm_new (void **engine, const char *file_name, const char *home_dir,
247 gpgme_error_t err = 0;
248 engine_gpgsm_t gpgsm;
252 #if !USE_DESCRIPTOR_PASSING
256 char *dft_display = NULL;
257 char dft_ttyname[64];
258 char *env_tty = NULL;
259 char *dft_ttytype = NULL;
262 (void)version; /* Not yet used. */
264 gpgsm = calloc (1, sizeof *gpgsm);
266 return gpg_error_from_syserror ();
268 gpgsm->status_cb.fd = -1;
269 gpgsm->status_cb.dir = 1;
270 gpgsm->status_cb.tag = 0;
271 gpgsm->status_cb.data = gpgsm;
273 gpgsm->input_cb.fd = -1;
274 gpgsm->input_cb.dir = 0;
275 gpgsm->input_cb.tag = 0;
276 gpgsm->input_cb.server_fd = -1;
277 *gpgsm->input_cb.server_fd_str = 0;
278 gpgsm->output_cb.fd = -1;
279 gpgsm->output_cb.dir = 1;
280 gpgsm->output_cb.tag = 0;
281 gpgsm->output_cb.server_fd = -1;
282 *gpgsm->output_cb.server_fd_str = 0;
283 gpgsm->message_cb.fd = -1;
284 gpgsm->message_cb.dir = 0;
285 gpgsm->message_cb.tag = 0;
286 gpgsm->message_cb.server_fd = -1;
287 *gpgsm->message_cb.server_fd_str = 0;
289 gpgsm->status.fnc = 0;
290 gpgsm->colon.fnc = 0;
291 gpgsm->colon.attic.line = 0;
292 gpgsm->colon.attic.linesize = 0;
293 gpgsm->colon.attic.linelen = 0;
294 gpgsm->colon.any = 0;
296 gpgsm->inline_data = NULL;
298 gpgsm->io_cbs.add = NULL;
299 gpgsm->io_cbs.add_priv = NULL;
300 gpgsm->io_cbs.remove = NULL;
301 gpgsm->io_cbs.event = NULL;
302 gpgsm->io_cbs.event_priv = NULL;
304 #if !USE_DESCRIPTOR_PASSING
305 if (_gpgme_io_pipe (fds, 0) < 0)
307 err = gpg_error_from_syserror ();
310 gpgsm->input_cb.fd = fds[1];
311 gpgsm->input_cb.server_fd = fds[0];
313 if (_gpgme_io_pipe (fds, 1) < 0)
315 err = gpg_error_from_syserror ();
318 gpgsm->output_cb.fd = fds[0];
319 gpgsm->output_cb.server_fd = fds[1];
321 if (_gpgme_io_pipe (fds, 0) < 0)
323 err = gpg_error_from_syserror ();
326 gpgsm->message_cb.fd = fds[1];
327 gpgsm->message_cb.server_fd = fds[0];
329 child_fds[0] = gpgsm->input_cb.server_fd;
330 child_fds[1] = gpgsm->output_cb.server_fd;
331 child_fds[2] = gpgsm->message_cb.server_fd;
335 pgmname = file_name ? file_name : _gpgme_get_default_gpgsm_name ();
338 argv[argc++] = _gpgme_get_basename (pgmname);
341 argv[argc++] = "--homedir";
342 argv[argc++] = home_dir;
344 argv[argc++] = "--server";
347 err = assuan_new_ext (&gpgsm->assuan_ctx, GPG_ERR_SOURCE_GPGME,
348 &_gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb,
352 assuan_ctx_set_system_hooks (gpgsm->assuan_ctx, &_gpgme_assuan_system_hooks);
354 #if USE_DESCRIPTOR_PASSING
355 err = assuan_pipe_connect (gpgsm->assuan_ctx, pgmname, argv,
356 NULL, NULL, NULL, ASSUAN_PIPE_CONNECT_FDPASSING);
359 assuan_fd_t achild_fds[4];
363 for (i = 0; i < 4; i++)
364 achild_fds[i] = (assuan_fd_t) child_fds[i];
366 err = assuan_pipe_connect (gpgsm->assuan_ctx, pgmname, argv,
367 achild_fds, NULL, NULL, 0);
370 for (i = 0; i < 4; i++)
371 child_fds[i] = (int) achild_fds[i];
374 /* On Windows, handles are inserted in the spawned process with
375 DuplicateHandle, and child_fds contains the server-local names
376 for the inserted handles when assuan_pipe_connect returns. */
379 /* Note: We don't use _gpgme_io_fd2str here. On W32 the
380 returned handles are real W32 system handles, not whatever
381 GPGME uses internally (which may be a system handle, a C
382 library handle or a GLib/Qt channel. Confusing, yes, but
383 remember these are server-local names, so they are not part
385 snprintf (gpgsm->input_cb.server_fd_str,
386 sizeof gpgsm->input_cb.server_fd_str, "%d", child_fds[0]);
387 snprintf (gpgsm->output_cb.server_fd_str,
388 sizeof gpgsm->output_cb.server_fd_str, "%d", child_fds[1]);
389 snprintf (gpgsm->message_cb.server_fd_str,
390 sizeof gpgsm->message_cb.server_fd_str, "%d", child_fds[2]);
396 err = _gpgme_getenv ("DISPLAY", &dft_display);
401 if (gpgrt_asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
404 err = gpg_error_from_syserror ();
409 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
416 err = _gpgme_getenv ("GPG_TTY", &env_tty);
417 if (isatty (1) || env_tty || err)
425 snprintf (dft_ttyname, sizeof (dft_ttyname), "%s", env_tty);
429 rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
431 /* Even though isatty() returns 1, ttyname_r() may fail in many
432 ways, e.g., when /dev/pts is not accessible under chroot. */
435 if (gpgrt_asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
437 err = gpg_error_from_syserror ();
440 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
446 err = _gpgme_getenv ("TERM", &dft_ttytype);
451 if (gpgrt_asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype)< 0)
454 err = gpg_error_from_syserror ();
459 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
460 NULL, NULL, NULL, NULL);
468 /* Ask gpgsm to enable the audit log support. */
471 err = assuan_transact (gpgsm->assuan_ctx, "OPTION enable-audit-log=1",
472 NULL, NULL, NULL, NULL, NULL, NULL);
473 if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
474 err = 0; /* This is an optional feature of gpgsm. */
478 #ifdef HAVE_W32_SYSTEM
479 /* Under Windows we need to use AllowSetForegroundWindow. Tell
480 gpgsm to tell us when it needs it. */
483 err = assuan_transact (gpgsm->assuan_ctx, "OPTION allow-pinentry-notify",
484 NULL, NULL, NULL, NULL, NULL, NULL);
485 if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
486 err = 0; /* This is a new feature of gpgsm. */
488 #endif /*HAVE_W32_SYSTEM*/
490 #if !USE_DESCRIPTOR_PASSING
492 && (_gpgme_io_set_close_notify (gpgsm->input_cb.fd,
493 close_notify_handler, gpgsm)
494 || _gpgme_io_set_close_notify (gpgsm->output_cb.fd,
495 close_notify_handler, gpgsm)
496 || _gpgme_io_set_close_notify (gpgsm->message_cb.fd,
497 close_notify_handler, gpgsm)))
499 err = gpg_error (GPG_ERR_GENERAL);
505 /* Close the server ends of the pipes (because of this, we must use
506 the stored server_fd_str in the function start). Our ends are
507 closed in gpgsm_release(). */
508 #if !USE_DESCRIPTOR_PASSING
509 if (gpgsm->input_cb.server_fd != -1)
510 _gpgme_io_close (gpgsm->input_cb.server_fd);
511 if (gpgsm->output_cb.server_fd != -1)
512 _gpgme_io_close (gpgsm->output_cb.server_fd);
513 if (gpgsm->message_cb.server_fd != -1)
514 _gpgme_io_close (gpgsm->message_cb.server_fd);
518 gpgsm_release (gpgsm);
526 /* Copy flags from CTX into the engine object. */
528 gpgsm_set_engine_flags (void *engine, const gpgme_ctx_t ctx)
530 engine_gpgsm_t gpgsm = engine;
532 if (ctx->request_origin)
534 if (strlen (ctx->request_origin) + 1 > sizeof gpgsm->request_origin)
535 strcpy (gpgsm->request_origin, "xxx"); /* Too long - force error */
537 strcpy (gpgsm->request_origin, ctx->request_origin);
540 *gpgsm->request_origin = 0;
545 gpgsm_set_locale (void *engine, int category, const char *value)
547 engine_gpgsm_t gpgsm = engine;
552 /* FIXME: If value is NULL, we need to reset the option to default.
553 But we can't do this. So we error out here. GPGSM needs support
558 else if (category == LC_CTYPE)
561 if (!value && gpgsm->lc_ctype_set)
562 return gpg_error (GPG_ERR_INV_VALUE);
564 gpgsm->lc_ctype_set = 1;
568 else if (category == LC_MESSAGES)
570 catstr = "lc-messages";
571 if (!value && gpgsm->lc_messages_set)
572 return gpg_error (GPG_ERR_INV_VALUE);
574 gpgsm->lc_messages_set = 1;
576 #endif /* LC_MESSAGES */
578 return gpg_error (GPG_ERR_INV_VALUE);
580 /* FIXME: Reset value to default. */
584 if (gpgrt_asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0)
585 err = gpg_error_from_syserror ();
588 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
589 NULL, NULL, NULL, NULL);
598 gpgsm_assuan_simple_command (engine_gpgsm_t gpgsm, const char *cmd,
599 engine_status_handler_t status_fnc,
600 void *status_fnc_value)
602 assuan_context_t ctx = gpgsm->assuan_ctx;
603 gpg_error_t err, cb_err;
607 err = assuan_write_line (ctx, cmd);
614 err = assuan_read_line (ctx, &line, &linelen);
618 if (*line == '#' || !linelen)
622 && line[0] == 'O' && line[1] == 'K'
623 && (line[2] == '\0' || line[2] == ' '))
625 else if (linelen >= 4
626 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
629 /* We prefer a callback generated error because that one is
630 more related to gpgme and thus probably more important
631 than the error returned by the engine. */
632 err = cb_err? cb_err : atoi (&line[4]);
635 else if (linelen >= 2
636 && line[0] == 'S' && line[1] == ' ')
638 /* After an error from a status callback we skip all further
643 gpgme_status_code_t r;
645 rest = strchr (line + 2, ' ');
647 rest = line + linelen; /* set to an empty string */
651 r = _gpgme_parse_status (line + 2);
652 if (gpgsm->status.mon_cb && r != GPGME_STATUS_PROGRESS)
654 /* Note that we call the monitor even if we do
655 * not know the status code (r < 0). */
656 cb_err = gpgsm->status.mon_cb (gpgsm->status.mon_cb_value,
660 if (r >= 0 && status_fnc && !cb_err)
661 cb_err = status_fnc (status_fnc_value, r, rest);
666 /* Invalid line or INQUIRY. We can't do anything else than
667 to stop. As with ERR we prefer a status callback
668 generated error code, though. */
669 err = cb_err ? cb_err : gpg_error (GPG_ERR_GENERAL);
675 /* We only want the first error from the status handler, thus we
676 * take the one saved in CB_ERR. */
684 typedef enum { INPUT_FD, OUTPUT_FD, MESSAGE_FD } fd_type_t;
687 gpgsm_clear_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type)
689 #if !USE_DESCRIPTOR_PASSING
693 _gpgme_io_close (gpgsm->input_cb.fd);
696 _gpgme_io_close (gpgsm->output_cb.fd);
699 _gpgme_io_close (gpgsm->message_cb.fd);
708 #define COMMANDLINELEN 40
710 gpgsm_set_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type, const char *opt)
713 char line[COMMANDLINELEN];
715 iocb_data_t *iocb_data;
716 #if USE_DESCRIPTOR_PASSING
724 iocb_data = &gpgsm->input_cb;
729 iocb_data = &gpgsm->output_cb;
734 iocb_data = &gpgsm->message_cb;
738 return gpg_error (GPG_ERR_INV_VALUE);
741 #if USE_DESCRIPTOR_PASSING
742 dir = iocb_data->dir;
743 /* We try to short-cut the communication by giving GPGSM direct
744 access to the file descriptor, rather than using a pipe. */
745 iocb_data->server_fd = _gpgme_data_get_fd (iocb_data->data);
746 if (iocb_data->server_fd < 0)
750 if (_gpgme_io_pipe (fds, dir) < 0)
751 return gpg_error_from_syserror ();
753 iocb_data->fd = dir ? fds[0] : fds[1];
754 iocb_data->server_fd = dir ? fds[1] : fds[0];
756 if (_gpgme_io_set_close_notify (iocb_data->fd,
757 close_notify_handler, gpgsm))
759 err = gpg_error (GPG_ERR_GENERAL);
764 err = assuan_sendfd (gpgsm->assuan_ctx, iocb_data->server_fd);
768 _gpgme_io_close (iocb_data->server_fd);
769 iocb_data->server_fd = -1;
772 snprintf (line, COMMANDLINELEN, "%s FD %s", which, opt);
774 snprintf (line, COMMANDLINELEN, "%s FD", which);
777 snprintf (line, COMMANDLINELEN, "%s FD=%s %s",
778 which, iocb_data->server_fd_str, opt);
780 snprintf (line, COMMANDLINELEN, "%s FD=%s",
781 which, iocb_data->server_fd_str);
784 err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
786 #if USE_DESCRIPTOR_PASSING
790 _gpgme_io_close (iocb_data->fd);
792 if (iocb_data->server_fd != -1)
794 _gpgme_io_close (iocb_data->server_fd);
795 iocb_data->server_fd = -1;
805 map_data_enc (gpgme_data_t d)
807 switch (gpgme_data_get_encoding (d))
809 case GPGME_DATA_ENCODING_NONE:
811 case GPGME_DATA_ENCODING_BINARY:
813 case GPGME_DATA_ENCODING_BASE64:
815 case GPGME_DATA_ENCODING_ARMOR:
825 status_handler (void *opaque, int fd)
827 struct io_cb_data *data = (struct io_cb_data *) opaque;
828 engine_gpgsm_t gpgsm = (engine_gpgsm_t) data->handler_value;
829 gpgme_error_t err = 0;
835 err = assuan_read_line (gpgsm->assuan_ctx, &line, &linelen);
838 /* Try our best to terminate the connection friendly. */
839 /* assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
840 TRACE3 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
841 "fd 0x%x: error from assuan (%d) getting status line : %s",
842 fd, err, gpg_strerror (err));
844 else if (linelen >= 3
845 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
846 && (line[3] == '\0' || line[3] == ' '))
849 err = atoi (&line[4]);
851 err = gpg_error (GPG_ERR_GENERAL);
852 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
853 "fd 0x%x: ERR line - mapped to: %s",
854 fd, err ? gpg_strerror (err) : "ok");
855 /* Try our best to terminate the connection friendly. */
856 /* assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
858 else if (linelen >= 2
859 && line[0] == 'O' && line[1] == 'K'
860 && (line[2] == '\0' || line[2] == ' '))
862 if (gpgsm->status.fnc)
864 char emptystring[1] = {0};
865 err = gpgsm->status.fnc (gpgsm->status.fnc_value,
866 GPGME_STATUS_EOF, emptystring);
867 if (gpg_err_code (err) == GPG_ERR_FALSE)
868 err = 0; /* Drop special error code. */
871 if (!err && gpgsm->colon.fnc && gpgsm->colon.any)
873 /* We must tell a colon function about the EOF. We do
874 this only when we have seen any data lines. Note
875 that this inlined use of colon data lines will
876 eventually be changed into using a regular data
878 gpgsm->colon.any = 0;
879 err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, NULL);
881 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
882 "fd 0x%x: OK line - final status: %s",
883 fd, err ? gpg_strerror (err) : "ok");
884 _gpgme_io_close (gpgsm->status_cb.fd);
888 && line[0] == 'D' && line[1] == ' '
891 /* We are using the colon handler even for plain inline data
892 - strange name for that function but for historic reasons
894 /* FIXME We can't use this for binary data because we
895 assume this is a string. For the current usage of colon
896 output it is correct. */
897 char *src = line + 2;
898 char *end = line + linelen;
900 char **aline = &gpgsm->colon.attic.line;
901 int *alinelen = &gpgsm->colon.attic.linelen;
903 if (gpgsm->colon.attic.linesize < *alinelen + linelen + 1)
905 char *newline = realloc (*aline, *alinelen + linelen + 1);
907 err = gpg_error_from_syserror ();
911 gpgsm->colon.attic.linesize = *alinelen + linelen + 1;
916 dst = *aline + *alinelen;
918 while (!err && src < end)
920 if (*src == '%' && src + 2 < end)
922 /* Handle escaped characters. */
924 *dst = _gpgme_hextobyte (src);
936 /* Terminate the pending line, pass it to the colon
937 handler and reset it. */
939 gpgsm->colon.any = 1;
940 if (*alinelen > 1 && *(dst - 1) == '\r')
944 /* FIXME How should we handle the return code? */
945 err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, *aline);
956 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
957 "fd 0x%x: D line; final status: %s",
958 fd, err? gpg_strerror (err):"ok");
961 && line[0] == 'D' && line[1] == ' '
962 && gpgsm->inline_data)
964 char *src = line + 2;
965 char *end = line + linelen;
967 gpgme_ssize_t nwritten;
972 if (*src == '%' && src + 2 < end)
974 /* Handle escaped characters. */
976 *dst++ = _gpgme_hextobyte (src);
988 nwritten = gpgme_data_write (gpgsm->inline_data, src, linelen);
989 if (!nwritten || (nwritten < 0 && errno != EINTR)
990 || nwritten > linelen)
992 err = gpg_error_from_syserror ();
999 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
1000 "fd 0x%x: D inlinedata; final status: %s",
1001 fd, err? gpg_strerror (err):"ok");
1003 else if (linelen > 2
1004 && line[0] == 'S' && line[1] == ' ')
1007 gpgme_status_code_t r;
1009 rest = strchr (line + 2, ' ');
1011 rest = line + linelen; /* set to an empty string */
1015 r = _gpgme_parse_status (line + 2);
1019 if (gpgsm->status.fnc)
1021 err = gpgsm->status.fnc (gpgsm->status.fnc_value, r, rest);
1022 if (gpg_err_code (err) == GPG_ERR_FALSE)
1023 err = 0; /* Drop special error code. */
1027 fprintf (stderr, "[UNKNOWN STATUS]%s %s", line + 2, rest);
1028 TRACE3 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
1029 "fd 0x%x: S line (%s) - final status: %s",
1030 fd, line+2, err? gpg_strerror (err):"ok");
1032 else if (linelen >= 7
1033 && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
1034 && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
1036 && (line[7] == '\0' || line[7] == ' '))
1038 char *keyword = line+7;
1040 while (*keyword == ' ')
1042 default_inq_cb (gpgsm, keyword);
1043 assuan_write_line (gpgsm->assuan_ctx, "END");
1047 while (!err && assuan_pending_line (gpgsm->assuan_ctx));
1053 static gpgme_error_t
1054 add_io_cb (engine_gpgsm_t gpgsm, iocb_data_t *iocbd, gpgme_io_cb_t handler)
1058 TRACE_BEG2 (DEBUG_ENGINE, "engine-gpgsm:add_io_cb", gpgsm,
1059 "fd %d, dir %d", iocbd->fd, iocbd->dir);
1060 err = (*gpgsm->io_cbs.add) (gpgsm->io_cbs.add_priv,
1061 iocbd->fd, iocbd->dir,
1062 handler, iocbd->data, &iocbd->tag);
1064 return TRACE_ERR (err);
1066 /* FIXME Kludge around poll() problem. */
1067 err = _gpgme_io_set_nonblocking (iocbd->fd);
1068 return TRACE_ERR (err);
1072 static gpgme_error_t
1073 start (engine_gpgsm_t gpgsm, const char *command)
1076 assuan_fd_t afdlist[5];
1081 if (*gpgsm->request_origin)
1085 cmd = _gpgme_strconcat ("OPTION request-origin=",
1086 gpgsm->request_origin, NULL);
1088 return gpg_error_from_syserror ();
1089 err = gpgsm_assuan_simple_command (gpgsm, cmd, NULL, NULL);
1091 if (err && gpg_err_code (err) != GPG_ERR_UNKNOWN_OPTION)
1095 /* We need to know the fd used by assuan for reads. We do this by
1096 using the assumption that the first returned fd from
1097 assuan_get_active_fds() is always this one. */
1098 nfds = assuan_get_active_fds (gpgsm->assuan_ctx, 0 /* read fds */,
1099 afdlist, DIM (afdlist));
1101 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1103 for (i = 0; i < nfds; i++)
1104 fdlist[i] = (int) afdlist[i];
1106 /* We "duplicate" the file descriptor, so we can close it here (we
1107 can't close fdlist[0], as that is closed by libassuan, and
1108 closing it here might cause libassuan to close some unrelated FD
1109 later). Alternatively, we could special case status_fd and
1110 register/unregister it manually as needed, but this increases
1111 code duplication and is more complicated as we can not use the
1112 close notifications etc. A third alternative would be to let
1113 Assuan know that we closed the FD, but that complicates the
1114 Assuan interface. */
1116 gpgsm->status_cb.fd = _gpgme_io_dup (fdlist[0]);
1117 if (gpgsm->status_cb.fd < 0)
1118 return gpg_error_from_syserror ();
1120 if (_gpgme_io_set_close_notify (gpgsm->status_cb.fd,
1121 close_notify_handler, gpgsm))
1123 _gpgme_io_close (gpgsm->status_cb.fd);
1124 gpgsm->status_cb.fd = -1;
1125 return gpg_error (GPG_ERR_GENERAL);
1128 err = add_io_cb (gpgsm, &gpgsm->status_cb, status_handler);
1129 if (!err && gpgsm->input_cb.fd != -1)
1130 err = add_io_cb (gpgsm, &gpgsm->input_cb, _gpgme_data_outbound_handler);
1131 if (!err && gpgsm->output_cb.fd != -1)
1132 err = add_io_cb (gpgsm, &gpgsm->output_cb, _gpgme_data_inbound_handler);
1133 if (!err && gpgsm->message_cb.fd != -1)
1134 err = add_io_cb (gpgsm, &gpgsm->message_cb, _gpgme_data_outbound_handler);
1137 err = assuan_write_line (gpgsm->assuan_ctx, command);
1140 gpgsm_io_event (gpgsm, GPGME_EVENT_START, NULL);
1146 #if USE_DESCRIPTOR_PASSING
1147 static gpgme_error_t
1148 gpgsm_reset (void *engine)
1150 engine_gpgsm_t gpgsm = engine;
1152 /* IF we have an active connection we must send a reset because we
1153 need to reset the list of signers. Note that RESET does not
1154 reset OPTION commands. */
1155 return (gpgsm->assuan_ctx
1156 ? gpgsm_assuan_simple_command (gpgsm, "RESET", NULL, NULL)
1163 static gpgme_error_t
1164 gpgsm_decrypt (void *engine,
1165 gpgme_decrypt_flags_t flags,
1166 gpgme_data_t ciph, gpgme_data_t plain,
1167 int export_session_key, const char *override_session_key,
1168 int auto_key_retrieve)
1170 engine_gpgsm_t gpgsm = engine;
1175 /* gpgsm is not capable of exporting session keys right now, so we
1176 * will ignore this if requested. */
1177 (void)export_session_key;
1178 (void)override_session_key;
1180 /* --auto-key-retrieve is also not supported. */
1181 (void)auto_key_retrieve;
1184 return gpg_error (GPG_ERR_INV_VALUE);
1186 gpgsm->input_cb.data = ciph;
1187 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1189 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1190 gpgsm->output_cb.data = plain;
1191 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1193 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1194 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1195 gpgsm->inline_data = NULL;
1197 err = start (engine, "DECRYPT");
1202 static gpgme_error_t
1203 gpgsm_delete (void *engine, gpgme_key_t key, unsigned int flags)
1205 engine_gpgsm_t gpgsm = engine;
1207 char *fpr = key->subkeys ? key->subkeys->fpr : NULL;
1210 int length = 8; /* "DELKEYS " */
1215 return gpg_error (GPG_ERR_INV_VALUE);
1220 if (*linep == '%' || *linep == ' ' || *linep == '+')
1226 line = malloc (length);
1228 return gpg_error_from_syserror ();
1230 strcpy (line, "DELKEYS ");
1260 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1261 gpgsm_clear_fd (gpgsm, INPUT_FD);
1262 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1263 gpgsm->inline_data = NULL;
1265 err = start (gpgsm, line);
1272 static gpgme_error_t
1273 set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[])
1275 gpgme_error_t err = 0;
1278 int invalid_recipients = 0;
1281 linelen = 10 + 40 + 1; /* "RECIPIENT " + guess + '\0'. */
1282 line = malloc (10 + 40 + 1);
1284 return gpg_error_from_syserror ();
1285 strcpy (line, "RECIPIENT ");
1286 for (i =0; !err && recp[i]; i++)
1291 if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
1293 invalid_recipients++;
1296 fpr = recp[i]->subkeys->fpr;
1298 newlen = 11 + strlen (fpr);
1299 if (linelen < newlen)
1301 char *newline = realloc (line, newlen);
1304 int saved_err = gpg_error_from_syserror ();
1311 strcpy (&line[10], fpr);
1313 err = gpgsm_assuan_simple_command (gpgsm, line, gpgsm->status.fnc,
1314 gpgsm->status.fnc_value);
1315 /* FIXME: This requires more work. */
1316 if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
1317 invalid_recipients++;
1325 return gpg_error (invalid_recipients
1326 ? GPG_ERR_UNUSABLE_PUBKEY : GPG_ERR_NO_ERROR);
1330 /* Take recipients from the LF delimited STRING and send RECIPIENT
1331 * commands to gpgsm. */
1332 static gpgme_error_t
1333 set_recipients_from_string (engine_gpgsm_t gpgsm, const char *string)
1335 gpg_error_t err = 0;
1343 while (*string == ' ' || *string == '\t')
1348 s = strchr (string, '\n');
1352 n = strlen (string);
1353 while (n && (string[n-1] == ' ' || string[n-1] == '\t'))
1357 if (gpgrt_asprintf (&line, "RECIPIENT %.*s", n, string) < 0)
1359 err = gpg_error_from_syserror ();
1364 err = gpgsm_assuan_simple_command (gpgsm, line, gpgsm->status.fnc,
1365 gpgsm->status.fnc_value);
1367 /* Fixme: Improve error reporting. */
1368 if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
1374 return err? err : no_pubkey? gpg_error (GPG_ERR_NO_PUBKEY) : 0;
1378 static gpgme_error_t
1379 gpgsm_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
1380 gpgme_encrypt_flags_t flags,
1381 gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
1383 engine_gpgsm_t gpgsm = engine;
1387 return gpg_error (GPG_ERR_INV_VALUE);
1389 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1391 if ((flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
1393 err = gpgsm_assuan_simple_command (gpgsm,
1394 "OPTION no-encrypt-to", NULL, NULL);
1399 gpgsm->input_cb.data = plain;
1400 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1403 gpgsm->output_cb.data = ciph;
1404 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1405 : map_data_enc (gpgsm->output_cb.data));
1408 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1409 gpgsm->inline_data = NULL;
1411 if (!recp && recpstring)
1412 err = set_recipients_from_string (gpgsm, recpstring);
1414 err = set_recipients (gpgsm, recp);
1417 err = start (gpgsm, "ENCRYPT");
1423 static gpgme_error_t
1424 gpgsm_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
1425 gpgme_data_t keydata, int use_armor)
1427 engine_gpgsm_t gpgsm = engine;
1428 gpgme_error_t err = 0;
1432 return gpg_error (GPG_ERR_INV_VALUE);
1437 cmd = malloc (7 + 9 + 9 + strlen (pattern) + 1);
1439 return gpg_error_from_syserror ();
1441 strcpy (cmd, "EXPORT ");
1442 if ((mode & GPGME_EXPORT_MODE_SECRET))
1444 strcat (cmd, "--secret ");
1445 if ((mode & GPGME_EXPORT_MODE_RAW))
1446 strcat (cmd, "--raw ");
1447 else if ((mode & GPGME_EXPORT_MODE_PKCS12))
1448 strcat (cmd, "--pkcs12 ");
1450 strcat (cmd, pattern);
1452 gpgsm->output_cb.data = keydata;
1453 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1454 : map_data_enc (gpgsm->output_cb.data));
1457 gpgsm_clear_fd (gpgsm, INPUT_FD);
1458 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1459 gpgsm->inline_data = NULL;
1461 err = start (gpgsm, cmd);
1467 static gpgme_error_t
1468 gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
1469 gpgme_data_t keydata, int use_armor)
1471 engine_gpgsm_t gpgsm = engine;
1472 gpgme_error_t err = 0;
1474 /* Length is "EXPORT " + "--secret " + "--pkcs12 " + p + '\0'. */
1475 int length = 7 + 9 + 9 + 1;
1479 return gpg_error (GPG_ERR_INV_VALUE);
1481 if (pattern && *pattern)
1483 const char **pat = pattern;
1487 const char *patlet = *pat;
1492 if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1500 line = malloc (length);
1502 return gpg_error_from_syserror ();
1504 strcpy (line, "EXPORT ");
1505 if ((mode & GPGME_EXPORT_MODE_SECRET))
1507 strcat (line, "--secret ");
1508 if ((mode & GPGME_EXPORT_MODE_RAW))
1509 strcat (line, "--raw ");
1510 else if ((mode & GPGME_EXPORT_MODE_PKCS12))
1511 strcat (line, "--pkcs12 ");
1513 linep = &line[strlen (line)];
1515 if (pattern && *pattern)
1519 const char *patlet = *pattern;
1541 *(linep++) = *patlet;
1553 gpgsm->output_cb.data = keydata;
1554 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1555 : map_data_enc (gpgsm->output_cb.data));
1558 gpgsm_clear_fd (gpgsm, INPUT_FD);
1559 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1560 gpgsm->inline_data = NULL;
1562 err = start (gpgsm, line);
1568 static gpgme_error_t
1569 gpgsm_genkey (void *engine,
1570 const char *userid, const char *algo,
1571 unsigned long reserved, unsigned long expires,
1572 gpgme_key_t key, unsigned int flags,
1573 gpgme_data_t help_data, unsigned int extraflags,
1574 gpgme_data_t pubkey, gpgme_data_t seckey)
1576 engine_gpgsm_t gpgsm = engine;
1582 return gpg_error (GPG_ERR_INV_VALUE);
1586 if (!pubkey || seckey)
1587 return gpg_error (GPG_ERR_INV_VALUE);
1589 gpgsm->input_cb.data = help_data;
1590 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1593 gpgsm->output_cb.data = pubkey;
1594 err = gpgsm_set_fd (gpgsm, OUTPUT_FD,
1595 (extraflags & GENKEY_EXTRAFLAG_ARMOR)? "--armor"
1596 : map_data_enc (gpgsm->output_cb.data));
1599 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1600 gpgsm->inline_data = NULL;
1602 err = start (gpgsm, "GENKEY");
1612 /* The new interface has not yet been implemented, */
1613 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1617 static gpgme_error_t
1618 gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
1620 engine_gpgsm_t gpgsm = engine;
1622 gpgme_data_encoding_t dataenc;
1626 return gpg_error (GPG_ERR_INV_VALUE);
1628 if (keydata && keyarray)
1629 return gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed. */
1631 dataenc = gpgme_data_get_encoding (keydata);
1638 /* Fist check whether the engine already features the
1639 --re-import option. */
1640 err = gpgsm_assuan_simple_command
1641 (gpgsm, "GETINFO cmd_has_option IMPORT re-import", NULL, NULL);
1643 return gpg_error (GPG_ERR_NOT_SUPPORTED);
1645 /* Create an internal data object with a list of all
1646 fingerprints. The data object and its memory (to avoid an
1647 extra copy by gpgme_data_new_from_mem) are stored in two
1648 variables which are released by the close_notify_handler. */
1649 for (idx=0, buflen=0; keyarray[idx]; idx++)
1651 if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
1652 && keyarray[idx]->subkeys
1653 && keyarray[idx]->subkeys->fpr
1654 && *keyarray[idx]->subkeys->fpr)
1655 buflen += strlen (keyarray[idx]->subkeys->fpr) + 1;
1657 /* Allocate a bufer with extra space for the trailing Nul
1658 introduced by the use of stpcpy. */
1659 buffer = malloc (buflen+1);
1661 return gpg_error_from_syserror ();
1662 for (idx=0, p = buffer; keyarray[idx]; idx++)
1664 if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
1665 && keyarray[idx]->subkeys
1666 && keyarray[idx]->subkeys->fpr
1667 && *keyarray[idx]->subkeys->fpr)
1668 p = stpcpy (stpcpy (p, keyarray[idx]->subkeys->fpr), "\n");
1671 err = gpgme_data_new_from_mem (&gpgsm->input_helper_data,
1678 gpgsm->input_helper_memory = buffer;
1680 gpgsm->input_cb.data = gpgsm->input_helper_data;
1681 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1684 gpgme_data_release (gpgsm->input_helper_data);
1685 gpgsm->input_helper_data = NULL;
1686 free (gpgsm->input_helper_memory);
1687 gpgsm->input_helper_memory = NULL;
1690 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1691 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1692 gpgsm->inline_data = NULL;
1694 return start (gpgsm, "IMPORT --re-import");
1696 else if (dataenc == GPGME_DATA_ENCODING_URL
1697 || dataenc == GPGME_DATA_ENCODING_URL0
1698 || dataenc == GPGME_DATA_ENCODING_URLESC)
1700 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1704 gpgsm->input_cb.data = keydata;
1705 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1708 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1709 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1710 gpgsm->inline_data = NULL;
1712 return start (gpgsm, "IMPORT");
1717 static gpgme_error_t
1718 gpgsm_keylist (void *engine, const char *pattern, int secret_only,
1719 gpgme_keylist_mode_t mode, int engine_flags)
1721 engine_gpgsm_t gpgsm = engine;
1726 if (mode & GPGME_KEYLIST_MODE_LOCAL)
1728 if (mode & GPGME_KEYLIST_MODE_EXTERN)
1734 /* Hack to make sure that the agent is started. Only if the agent
1735 has been started an application may connect to the agent via
1736 GPGME_PROTOCOL_ASSUAN - for example to look for smartcards. We
1737 do this only if a secret key listing has been requested. In
1738 general this is not needed because a secret key listing starts
1739 the agent. However on a fresh installation no public keys are
1740 available and thus there is no need for gpgsm to ask the agent
1741 whether a secret key exists for the public key. */
1742 if (secret_only || (mode & GPGME_KEYLIST_MODE_WITH_SECRET))
1743 gpgsm_assuan_simple_command (gpgsm, "GETINFO agent-check", NULL, NULL);
1745 /* Always send list-mode option because RESET does not reset it. */
1746 if (gpgrt_asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1747 return gpg_error_from_syserror ();
1748 err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
1754 /* Always send key validation because RESET does not reset it. */
1756 /* Use the validation mode if requested. We don't check for an error
1757 yet because this is a pretty fresh gpgsm features. */
1758 gpgsm_assuan_simple_command (gpgsm,
1759 (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1760 "OPTION with-validation=1":
1761 "OPTION with-validation=0" ,
1763 /* Include the ephemeral keys if requested. We don't check for an error
1764 yet because this is a pretty fresh gpgsm features. */
1765 gpgsm_assuan_simple_command (gpgsm,
1766 (mode & GPGME_KEYLIST_MODE_EPHEMERAL)?
1767 "OPTION with-ephemeral-keys=1":
1768 "OPTION with-ephemeral-keys=0" ,
1770 gpgsm_assuan_simple_command (gpgsm,
1771 (mode & GPGME_KEYLIST_MODE_WITH_SECRET)?
1772 "OPTION with-secret=1":
1773 "OPTION with-secret=0" ,
1775 gpgsm_assuan_simple_command (gpgsm,
1776 (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)?
1778 "OPTION offline=0" ,
1782 /* Length is "LISTSECRETKEYS " + p + '\0'. */
1783 line = malloc (15 + strlen (pattern) + 1);
1785 return gpg_error_from_syserror ();
1788 strcpy (line, "LISTSECRETKEYS ");
1789 strcpy (&line[15], pattern);
1793 strcpy (line, "LISTKEYS ");
1794 strcpy (&line[9], pattern);
1797 gpgsm_clear_fd (gpgsm, INPUT_FD);
1798 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1799 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1800 gpgsm->inline_data = NULL;
1802 err = start (gpgsm, line);
1808 static gpgme_error_t
1809 gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
1810 int reserved, gpgme_keylist_mode_t mode, int engine_flags)
1812 engine_gpgsm_t gpgsm = engine;
1815 /* Length is "LISTSECRETKEYS " + p + '\0'. */
1816 int length = 15 + 1;
1818 int any_pattern = 0;
1822 return gpg_error (GPG_ERR_INV_VALUE);
1824 if (mode & GPGME_KEYLIST_MODE_LOCAL)
1826 if (mode & GPGME_KEYLIST_MODE_EXTERN)
1829 /* Always send list-mode option because RESET does not reset it. */
1830 if (gpgrt_asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1831 return gpg_error_from_syserror ();
1832 err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
1837 /* Always send key validation because RESET does not reset it. */
1838 /* Use the validation mode if required. We don't check for an error
1839 yet because this is a pretty fresh gpgsm features. */
1840 gpgsm_assuan_simple_command (gpgsm,
1841 (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1842 "OPTION with-validation=1":
1843 "OPTION with-validation=0" ,
1845 gpgsm_assuan_simple_command (gpgsm,
1846 (mode & GPGME_KEYLIST_MODE_WITH_SECRET)?
1847 "OPTION with-secret=1":
1848 "OPTION with-secret=0" ,
1850 gpgsm_assuan_simple_command (gpgsm,
1851 (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)?
1853 "OPTION offline=0" ,
1856 if (pattern && *pattern)
1858 const char **pat = pattern;
1862 const char *patlet = *pat;
1867 if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1875 line = malloc (length);
1877 return gpg_error_from_syserror ();
1880 strcpy (line, "LISTSECRETKEYS ");
1885 strcpy (line, "LISTKEYS ");
1889 if (pattern && *pattern)
1893 const char *patlet = *pattern;
1915 *(linep++) = *patlet;
1929 gpgsm_clear_fd (gpgsm, INPUT_FD);
1930 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1931 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1932 gpgsm->inline_data = NULL;
1934 err = start (gpgsm, line);
1940 static gpgme_error_t
1941 gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
1942 gpgme_sig_mode_t mode, int use_armor, int use_textmode,
1943 int include_certs, gpgme_ctx_t ctx /* FIXME */)
1945 engine_gpgsm_t gpgsm = engine;
1954 return gpg_error (GPG_ERR_INV_VALUE);
1956 /* FIXME: This does not work as RESET does not reset it so we can't
1957 revert back to default. */
1958 if (include_certs != GPGME_INCLUDE_CERTS_DEFAULT)
1960 /* FIXME: Make sure that if we run multiple operations, that we
1961 can reset any previously set value in case the default is
1964 if (gpgrt_asprintf (&assuan_cmd,
1965 "OPTION include-certs %i", include_certs) < 0)
1966 return gpg_error_from_syserror ();
1967 err = gpgsm_assuan_simple_command (gpgsm, assuan_cmd, NULL, NULL);
1968 gpgrt_free (assuan_cmd);
1973 for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1975 const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1976 if (s && strlen (s) < 80)
1980 strcpy (stpcpy (buf, "SIGNER "), s);
1981 err = gpgsm_assuan_simple_command (gpgsm, buf,
1983 gpgsm->status.fnc_value);
1986 err = gpg_error (GPG_ERR_INV_VALUE);
1987 gpgme_key_unref (key);
1992 gpgsm->input_cb.data = in;
1993 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1996 gpgsm->output_cb.data = out;
1997 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1998 : map_data_enc (gpgsm->output_cb.data));
2001 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
2002 gpgsm->inline_data = NULL;
2004 err = start (gpgsm, mode == GPGME_SIG_MODE_DETACH
2005 ? "SIGN --detached" : "SIGN");
2010 static gpgme_error_t
2011 gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
2012 gpgme_data_t plaintext, gpgme_ctx_t ctx)
2014 engine_gpgsm_t gpgsm = engine;
2020 return gpg_error (GPG_ERR_INV_VALUE);
2022 gpgsm->input_cb.data = sig;
2023 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
2028 /* Normal or cleartext signature. */
2029 gpgsm->output_cb.data = plaintext;
2030 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
2031 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
2035 /* Detached signature. */
2036 gpgsm->message_cb.data = signed_text;
2037 err = gpgsm_set_fd (gpgsm, MESSAGE_FD, 0);
2038 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
2040 gpgsm->inline_data = NULL;
2043 err = start (gpgsm, "VERIFY");
2049 /* Send the GETAUDITLOG command. The result is saved to a gpgme data
2051 static gpgme_error_t
2052 gpgsm_getauditlog (void *engine, gpgme_data_t output, unsigned int flags)
2054 engine_gpgsm_t gpgsm = engine;
2055 gpgme_error_t err = 0;
2057 if (!gpgsm || !output)
2058 return gpg_error (GPG_ERR_INV_VALUE);
2060 #if USE_DESCRIPTOR_PASSING
2061 gpgsm->output_cb.data = output;
2062 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
2066 gpgsm_clear_fd (gpgsm, INPUT_FD);
2067 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
2068 gpgsm->inline_data = NULL;
2069 # define CMD "GETAUDITLOG"
2071 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
2072 gpgsm_clear_fd (gpgsm, INPUT_FD);
2073 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
2074 gpgsm->inline_data = output;
2075 # define CMD "GETAUDITLOG --data"
2078 err = start (gpgsm, (flags & GPGME_AUDITLOG_HTML)? CMD " --html" : CMD);
2084 /* This sets a status callback for monitoring status lines before they
2085 * are passed to a caller set handler. */
2087 gpgsm_set_status_cb (void *engine, gpgme_status_cb_t cb, void *cb_value)
2089 engine_gpgsm_t gpgsm = engine;
2091 gpgsm->status.mon_cb = cb;
2092 gpgsm->status.mon_cb_value = cb_value;
2097 gpgsm_set_status_handler (void *engine, engine_status_handler_t fnc,
2100 engine_gpgsm_t gpgsm = engine;
2102 gpgsm->status.fnc = fnc;
2103 gpgsm->status.fnc_value = fnc_value;
2107 static gpgme_error_t
2108 gpgsm_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
2111 engine_gpgsm_t gpgsm = engine;
2113 gpgsm->colon.fnc = fnc;
2114 gpgsm->colon.fnc_value = fnc_value;
2115 gpgsm->colon.any = 0;
2121 gpgsm_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
2123 engine_gpgsm_t gpgsm = engine;
2124 gpgsm->io_cbs = *io_cbs;
2129 gpgsm_io_event (void *engine, gpgme_event_io_t type, void *type_data)
2131 engine_gpgsm_t gpgsm = engine;
2133 TRACE3 (DEBUG_ENGINE, "gpgme:gpgsm_io_event", gpgsm,
2134 "event %p, type %d, type_data %p",
2135 gpgsm->io_cbs.event, type, type_data);
2136 if (gpgsm->io_cbs.event)
2137 (*gpgsm->io_cbs.event) (gpgsm->io_cbs.event_priv, type, type_data);
2141 static gpgme_error_t
2142 gpgsm_passwd (void *engine, gpgme_key_t key, unsigned int flags)
2144 engine_gpgsm_t gpgsm = engine;
2150 if (!key || !key->subkeys || !key->subkeys->fpr)
2151 return gpg_error (GPG_ERR_INV_CERT_OBJ);
2153 if (gpgrt_asprintf (&line, "PASSWD -- %s", key->subkeys->fpr) < 0)
2154 return gpg_error_from_syserror ();
2156 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
2157 gpgsm_clear_fd (gpgsm, INPUT_FD);
2158 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
2159 gpgsm->inline_data = NULL;
2161 err = start (gpgsm, line);
2169 struct engine_ops _gpgme_engine_ops_gpgsm =
2171 /* Static functions. */
2172 _gpgme_get_default_gpgsm_name,
2175 gpgsm_get_req_version,
2178 /* Member functions. */
2180 #if USE_DESCRIPTOR_PASSING
2185 gpgsm_set_status_cb,
2186 gpgsm_set_status_handler,
2187 NULL, /* set_command_handler */
2188 gpgsm_set_colon_line_handler,
2190 NULL, /* set_protocol */
2191 gpgsm_set_engine_flags,
2193 gpgsm_delete, /* decrypt_verify */
2196 NULL, /* encrypt_sign */
2203 NULL, /* keylist_data */
2205 NULL, /* tofu_policy */
2207 NULL, /* trustlist */
2210 NULL, /* opassuan_transact */
2211 NULL, /* conf_load */
2212 NULL, /* conf_save */
2213 NULL, /* conf_dir */
2214 NULL, /* query_swdb */
2218 NULL, /* cancel_op */
2220 NULL, /* set_pinentry_mode */