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, see <https://gnu.org/licenses/>.
20 * SPDX-License-Identifier: LGPL-2.1-or-later
29 #ifdef HAVE_SYS_TYPES_H
30 # include <sys/types.h>
39 #include <fcntl.h> /* FIXME */
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;
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;
114 /* Memory data containing diagnostics (--logger-fd) of gpgsm */
115 gpgme_data_t diagnostics;
118 typedef struct engine_gpgsm *engine_gpgsm_t;
121 static void gpgsm_io_event (void *engine,
122 gpgme_event_io_t type, void *type_data);
127 gpgsm_get_version (const char *file_name)
129 return _gpgme_get_program_version (file_name ? file_name
130 : _gpgme_get_default_gpgsm_name ());
135 gpgsm_get_req_version (void)
142 close_notify_handler (int fd, void *opaque)
144 engine_gpgsm_t gpgsm = opaque;
147 if (gpgsm->status_cb.fd == fd)
149 if (gpgsm->status_cb.tag)
150 (*gpgsm->io_cbs.remove) (gpgsm->status_cb.tag);
151 gpgsm->status_cb.fd = -1;
152 gpgsm->status_cb.tag = NULL;
153 /* Because the server keeps on running as long as the
154 * gpgme_ctx_t is valid the diag fd will not receive a close and
155 * thus the operation gets stuck trying to read the diag fd.
156 * The status fd however is closed right after it received the
157 * "OK" from the command. So we use this event to also close
159 _gpgme_io_close (gpgsm->diag_cb.fd);
161 else if (gpgsm->input_cb.fd == fd)
163 if (gpgsm->input_cb.tag)
164 (*gpgsm->io_cbs.remove) (gpgsm->input_cb.tag);
165 gpgsm->input_cb.fd = -1;
166 gpgsm->input_cb.tag = NULL;
167 if (gpgsm->input_helper_data)
169 gpgme_data_release (gpgsm->input_helper_data);
170 gpgsm->input_helper_data = NULL;
172 if (gpgsm->input_helper_memory)
174 free (gpgsm->input_helper_memory);
175 gpgsm->input_helper_memory = NULL;
178 else if (gpgsm->output_cb.fd == fd)
180 if (gpgsm->output_cb.tag)
181 (*gpgsm->io_cbs.remove) (gpgsm->output_cb.tag);
182 gpgsm->output_cb.fd = -1;
183 gpgsm->output_cb.tag = NULL;
185 else if (gpgsm->message_cb.fd == fd)
187 if (gpgsm->message_cb.tag)
188 (*gpgsm->io_cbs.remove) (gpgsm->message_cb.tag);
189 gpgsm->message_cb.fd = -1;
190 gpgsm->message_cb.tag = NULL;
192 else if (gpgsm->diag_cb.fd == fd)
194 if (gpgsm->diag_cb.tag)
195 (*gpgsm->io_cbs.remove) (gpgsm->diag_cb.tag);
196 gpgsm->diag_cb.fd = -1;
197 gpgsm->diag_cb.tag = NULL;
202 /* This is the default inquiry callback. We use it to handle the
203 Pinentry notifications. */
205 default_inq_cb (engine_gpgsm_t gpgsm, const char *line)
209 if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
211 _gpgme_allow_set_foreground_window ((pid_t)strtoul (line+17, NULL, 10));
219 gpgsm_cancel (void *engine)
221 engine_gpgsm_t gpgsm = engine;
224 return gpg_error (GPG_ERR_INV_VALUE);
226 if (gpgsm->status_cb.fd != -1)
227 _gpgme_io_close (gpgsm->status_cb.fd);
228 if (gpgsm->input_cb.fd != -1)
229 _gpgme_io_close (gpgsm->input_cb.fd);
230 if (gpgsm->output_cb.fd != -1)
231 _gpgme_io_close (gpgsm->output_cb.fd);
232 if (gpgsm->message_cb.fd != -1)
233 _gpgme_io_close (gpgsm->message_cb.fd);
234 if (gpgsm->diag_cb.fd != -1)
235 _gpgme_io_close (gpgsm->diag_cb.fd);
237 if (gpgsm->assuan_ctx)
239 assuan_release (gpgsm->assuan_ctx);
240 gpgsm->assuan_ctx = NULL;
248 gpgsm_release (void *engine)
250 engine_gpgsm_t gpgsm = engine;
255 gpgsm_cancel (engine);
257 gpgme_data_release (gpgsm->diagnostics);
259 free (gpgsm->colon.attic.line);
265 gpgsm_new (void **engine, const char *file_name, const char *home_dir,
268 gpgme_error_t err = 0;
269 engine_gpgsm_t gpgsm;
272 char *diag_fd_str = NULL;
277 char *dft_display = NULL;
278 char dft_ttyname[64];
279 char *env_tty = NULL;
280 char *dft_ttytype = NULL;
282 unsigned int connect_flags;
284 (void)version; /* Not yet used. */
286 gpgsm = calloc (1, sizeof *gpgsm);
288 return gpg_error_from_syserror ();
290 gpgsm->status_cb.fd = -1;
291 gpgsm->status_cb.dir = 1;
292 gpgsm->status_cb.tag = 0;
293 gpgsm->status_cb.data = gpgsm;
295 gpgsm->input_cb.fd = -1;
296 gpgsm->input_cb.dir = 0;
297 gpgsm->input_cb.tag = 0;
298 gpgsm->input_cb.server_fd = -1;
299 *gpgsm->input_cb.server_fd_str = 0;
300 gpgsm->output_cb.fd = -1;
301 gpgsm->output_cb.dir = 1;
302 gpgsm->output_cb.tag = 0;
303 gpgsm->output_cb.server_fd = -1;
304 *gpgsm->output_cb.server_fd_str = 0;
305 gpgsm->message_cb.fd = -1;
306 gpgsm->message_cb.dir = 0;
307 gpgsm->message_cb.tag = 0;
308 gpgsm->message_cb.server_fd = -1;
309 *gpgsm->message_cb.server_fd_str = 0;
310 gpgsm->diag_cb.fd = -1;
311 gpgsm->diag_cb.dir = 1;
312 gpgsm->diag_cb.tag = 0;
313 gpgsm->diag_cb.server_fd = -1;
314 *gpgsm->diag_cb.server_fd_str = 0;
316 gpgsm->status.fnc = 0;
317 gpgsm->colon.fnc = 0;
318 gpgsm->colon.attic.line = 0;
319 gpgsm->colon.attic.linesize = 0;
320 gpgsm->colon.attic.linelen = 0;
321 gpgsm->colon.any = 0;
323 gpgsm->inline_data = NULL;
325 gpgsm->io_cbs.add = NULL;
326 gpgsm->io_cbs.add_priv = NULL;
327 gpgsm->io_cbs.remove = NULL;
328 gpgsm->io_cbs.event = NULL;
329 gpgsm->io_cbs.event_priv = NULL;
331 if (_gpgme_io_pipe (fds, 1) < 0)
333 err = gpg_error_from_syserror ();
336 gpgsm->diag_cb.fd = fds[0];
337 gpgsm->diag_cb.server_fd = fds[1];
339 #if USE_DESCRIPTOR_PASSING
340 child_fds[0] = gpgsm->diag_cb.server_fd;
343 connect_flags = ASSUAN_PIPE_CONNECT_FDPASSING;
344 #else /*!USE_DESCRIPTOR_PASSING*/
345 if (_gpgme_io_pipe (fds, 0) < 0)
347 err = gpg_error_from_syserror ();
350 gpgsm->input_cb.fd = fds[1];
351 gpgsm->input_cb.server_fd = fds[0];
353 if (_gpgme_io_pipe (fds, 1) < 0)
355 err = gpg_error_from_syserror ();
358 gpgsm->output_cb.fd = fds[0];
359 gpgsm->output_cb.server_fd = fds[1];
361 if (_gpgme_io_pipe (fds, 0) < 0)
363 err = gpg_error_from_syserror ();
366 gpgsm->message_cb.fd = fds[1];
367 gpgsm->message_cb.server_fd = fds[0];
369 child_fds[0] = gpgsm->input_cb.server_fd;
370 child_fds[1] = gpgsm->output_cb.server_fd;
371 child_fds[2] = gpgsm->message_cb.server_fd;
372 child_fds[3] = gpgsm->diag_cb.server_fd;
376 #endif /*!USE_DESCRIPTOR_PASSING*/
378 pgmname = file_name ? file_name : _gpgme_get_default_gpgsm_name ();
381 argv[argc++] = _gpgme_get_basename (pgmname);
384 argv[argc++] = "--homedir";
385 argv[argc++] = home_dir;
387 /* Set up diagnostics */
388 err = gpgme_data_new (&gpgsm->diagnostics);
391 gpgsm->diag_cb.data = gpgsm->diagnostics;
392 argv[argc++] = "--logger-fd";
393 if (gpgrt_asprintf (&diag_fd_str, "%i", gpgsm->diag_cb.server_fd) == -1)
395 err = gpg_error_from_syserror ();
398 argv[argc++] = diag_fd_str;
399 argv[argc++] = "--server";
402 err = assuan_new_ext (&gpgsm->assuan_ctx, GPG_ERR_SOURCE_GPGME,
403 &_gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb,
407 assuan_ctx_set_system_hooks (gpgsm->assuan_ctx, &_gpgme_assuan_system_hooks);
410 assuan_fd_t achild_fds[5];
414 for (i = 0; i < nchild_fds; i++)
415 achild_fds[i] = (assuan_fd_t) child_fds[i];
417 err = assuan_pipe_connect (gpgsm->assuan_ctx, pgmname, argv,
418 achild_fds, NULL, NULL, connect_flags);
420 /* FIXME: Check whether our Windows code still updates the list.*/
421 for (i = 0; i < nchild_fds; i++)
422 child_fds[i] = (int) achild_fds[i];
426 #if !USE_DESCRIPTOR_PASSING
427 /* On Windows, handles are inserted in the spawned process with
428 DuplicateHandle, and child_fds contains the server-local names
429 for the inserted handles when assuan_pipe_connect returns. */
432 /* Note: We don't use _gpgme_io_fd2str here. On W32 the
433 returned handles are real W32 system handles, not whatever
434 GPGME uses internally (which may be a system handle, a C
435 library handle or a GLib/Qt channel. Confusing, yes, but
436 remember these are server-local names, so they are not part
438 snprintf (gpgsm->input_cb.server_fd_str,
439 sizeof gpgsm->input_cb.server_fd_str, "%d", child_fds[0]);
440 snprintf (gpgsm->output_cb.server_fd_str,
441 sizeof gpgsm->output_cb.server_fd_str, "%d", child_fds[1]);
442 snprintf (gpgsm->message_cb.server_fd_str,
443 sizeof gpgsm->message_cb.server_fd_str, "%d", child_fds[2]);
444 snprintf (gpgsm->diag_cb.server_fd_str,
445 sizeof gpgsm->diag_cb.server_fd_str, "%d", child_fds[3]);
451 err = _gpgme_getenv ("DISPLAY", &dft_display);
456 if (gpgrt_asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
459 err = gpg_error_from_syserror ();
464 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
471 err = _gpgme_getenv ("GPG_TTY", &env_tty);
472 if (isatty (1) || env_tty || err)
480 snprintf (dft_ttyname, sizeof (dft_ttyname), "%s", env_tty);
484 rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
486 /* Even though isatty() returns 1, ttyname_r() may fail in many
487 ways, e.g., when /dev/pts is not accessible under chroot. */
490 if (gpgrt_asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
492 err = gpg_error_from_syserror ();
495 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
501 err = _gpgme_getenv ("TERM", &dft_ttytype);
506 if (gpgrt_asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype)< 0)
509 err = gpg_error_from_syserror ();
514 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
515 NULL, NULL, NULL, NULL);
523 /* Ask gpgsm to enable the audit log support. */
526 err = assuan_transact (gpgsm->assuan_ctx, "OPTION enable-audit-log=1",
527 NULL, NULL, NULL, NULL, NULL, NULL);
528 if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
529 err = 0; /* This is an optional feature of gpgsm. */
533 #ifdef HAVE_W32_SYSTEM
534 /* Under Windows we need to use AllowSetForegroundWindow. Tell
535 gpgsm to tell us when it needs it. */
538 err = assuan_transact (gpgsm->assuan_ctx, "OPTION allow-pinentry-notify",
539 NULL, NULL, NULL, NULL, NULL, NULL);
540 if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
541 err = 0; /* This is a new feature of gpgsm. */
543 #endif /*HAVE_W32_SYSTEM*/
545 #if !USE_DESCRIPTOR_PASSING
547 && (_gpgme_io_set_close_notify (gpgsm->input_cb.fd,
548 close_notify_handler, gpgsm)
549 || _gpgme_io_set_close_notify (gpgsm->output_cb.fd,
550 close_notify_handler, gpgsm)
551 || _gpgme_io_set_close_notify (gpgsm->message_cb.fd,
552 close_notify_handler, gpgsm)))
554 err = gpg_error (GPG_ERR_GENERAL);
558 if (!err && _gpgme_io_set_close_notify (gpgsm->diag_cb.fd,
559 close_notify_handler, gpgsm))
561 err = gpg_error (GPG_ERR_GENERAL);
566 /* Close the server ends of the pipes (because of this, we must use
567 the stored server_fd_str in the function start). Our ends are
568 closed in gpgsm_release(). */
569 #if !USE_DESCRIPTOR_PASSING
570 if (gpgsm->input_cb.server_fd != -1)
571 _gpgme_io_close (gpgsm->input_cb.server_fd);
572 if (gpgsm->output_cb.server_fd != -1)
573 _gpgme_io_close (gpgsm->output_cb.server_fd);
574 if (gpgsm->message_cb.server_fd != -1)
575 _gpgme_io_close (gpgsm->message_cb.server_fd);
576 if (gpgsm->diag_cb.server_fd != -1)
577 _gpgme_io_close (gpgsm->diag_cb.server_fd);
581 gpgsm_release (gpgsm);
589 /* Copy flags from CTX into the engine object. */
591 gpgsm_set_engine_flags (void *engine, const gpgme_ctx_t ctx)
593 engine_gpgsm_t gpgsm = engine;
595 if (ctx->request_origin)
597 if (strlen (ctx->request_origin) + 1 > sizeof gpgsm->request_origin)
598 strcpy (gpgsm->request_origin, "xxx"); /* Too long - force error */
600 strcpy (gpgsm->request_origin, ctx->request_origin);
603 *gpgsm->request_origin = 0;
608 gpgsm_set_locale (void *engine, int category, const char *value)
610 engine_gpgsm_t gpgsm = engine;
615 /* FIXME: If value is NULL, we need to reset the option to default.
616 But we can't do this. So we error out here. GPGSM needs support
621 else if (category == LC_CTYPE)
624 if (!value && gpgsm->lc_ctype_set)
625 return gpg_error (GPG_ERR_INV_VALUE);
627 gpgsm->lc_ctype_set = 1;
631 else if (category == LC_MESSAGES)
633 catstr = "lc-messages";
634 if (!value && gpgsm->lc_messages_set)
635 return gpg_error (GPG_ERR_INV_VALUE);
637 gpgsm->lc_messages_set = 1;
639 #endif /* LC_MESSAGES */
641 return gpg_error (GPG_ERR_INV_VALUE);
643 /* FIXME: Reset value to default. */
647 if (gpgrt_asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0)
648 err = gpg_error_from_syserror ();
651 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
652 NULL, NULL, NULL, NULL);
661 gpgsm_assuan_simple_command (engine_gpgsm_t gpgsm, const char *cmd,
662 engine_status_handler_t status_fnc,
663 void *status_fnc_value)
665 assuan_context_t ctx = gpgsm->assuan_ctx;
666 gpg_error_t err, cb_err;
670 err = assuan_write_line (ctx, cmd);
677 err = assuan_read_line (ctx, &line, &linelen);
681 if (*line == '#' || !linelen)
685 && line[0] == 'O' && line[1] == 'K'
686 && (line[2] == '\0' || line[2] == ' '))
688 else if (linelen >= 4
689 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
692 /* We prefer a callback generated error because that one is
693 more related to gpgme and thus probably more important
694 than the error returned by the engine. */
695 err = cb_err? cb_err : atoi (&line[4]);
698 else if (linelen >= 2
699 && line[0] == 'S' && line[1] == ' ')
701 /* After an error from a status callback we skip all further
706 gpgme_status_code_t r;
708 rest = strchr (line + 2, ' ');
710 rest = line + linelen; /* set to an empty string */
714 r = _gpgme_parse_status (line + 2);
715 if (gpgsm->status.mon_cb && r != GPGME_STATUS_PROGRESS)
717 /* Note that we call the monitor even if we do
718 * not know the status code (r < 0). */
719 cb_err = gpgsm->status.mon_cb (gpgsm->status.mon_cb_value,
723 if (r >= 0 && status_fnc && !cb_err)
724 cb_err = status_fnc (status_fnc_value, r, rest);
729 /* Invalid line or INQUIRY. We can't do anything else than
730 to stop. As with ERR we prefer a status callback
731 generated error code, though. */
732 err = cb_err ? cb_err : gpg_error (GPG_ERR_GENERAL);
738 /* We only want the first error from the status handler, thus we
739 * take the one saved in CB_ERR. */
747 typedef enum { INPUT_FD, OUTPUT_FD, MESSAGE_FD } fd_type_t;
750 gpgsm_clear_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type)
752 #if !USE_DESCRIPTOR_PASSING
756 _gpgme_io_close (gpgsm->input_cb.fd);
759 _gpgme_io_close (gpgsm->output_cb.fd);
762 _gpgme_io_close (gpgsm->message_cb.fd);
771 #define COMMANDLINELEN 40
773 gpgsm_set_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type, const char *opt)
776 char line[COMMANDLINELEN];
778 iocb_data_t *iocb_data;
779 #if USE_DESCRIPTOR_PASSING
787 iocb_data = &gpgsm->input_cb;
792 iocb_data = &gpgsm->output_cb;
797 iocb_data = &gpgsm->message_cb;
801 return gpg_error (GPG_ERR_INV_VALUE);
804 #if USE_DESCRIPTOR_PASSING
805 dir = iocb_data->dir;
806 /* We try to short-cut the communication by giving GPGSM direct
807 access to the file descriptor, rather than using a pipe. */
808 iocb_data->server_fd = _gpgme_data_get_fd (iocb_data->data);
809 if (iocb_data->server_fd < 0)
813 if (_gpgme_io_pipe (fds, dir) < 0)
814 return gpg_error_from_syserror ();
816 iocb_data->fd = dir ? fds[0] : fds[1];
817 iocb_data->server_fd = dir ? fds[1] : fds[0];
819 if (_gpgme_io_set_close_notify (iocb_data->fd,
820 close_notify_handler, gpgsm))
822 err = gpg_error (GPG_ERR_GENERAL);
827 err = assuan_sendfd (gpgsm->assuan_ctx, iocb_data->server_fd);
831 _gpgme_io_close (iocb_data->server_fd);
832 iocb_data->server_fd = -1;
835 snprintf (line, COMMANDLINELEN, "%s FD %s", which, opt);
837 snprintf (line, COMMANDLINELEN, "%s FD", which);
840 snprintf (line, COMMANDLINELEN, "%s FD=%s %s",
841 which, iocb_data->server_fd_str, opt);
843 snprintf (line, COMMANDLINELEN, "%s FD=%s",
844 which, iocb_data->server_fd_str);
847 err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
849 #if USE_DESCRIPTOR_PASSING
853 _gpgme_io_close (iocb_data->fd);
855 if (iocb_data->server_fd != -1)
857 _gpgme_io_close (iocb_data->server_fd);
858 iocb_data->server_fd = -1;
868 map_data_enc (gpgme_data_t d)
870 switch (gpgme_data_get_encoding (d))
872 case GPGME_DATA_ENCODING_NONE:
874 case GPGME_DATA_ENCODING_BINARY:
876 case GPGME_DATA_ENCODING_BASE64:
878 case GPGME_DATA_ENCODING_ARMOR:
888 status_handler (void *opaque, int fd)
890 struct io_cb_data *data = (struct io_cb_data *) opaque;
891 engine_gpgsm_t gpgsm = (engine_gpgsm_t) data->handler_value;
892 gpgme_error_t err = 0;
898 err = assuan_read_line (gpgsm->assuan_ctx, &line, &linelen);
901 /* Try our best to terminate the connection friendly. */
902 /* assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
903 TRACE (DEBUG_CTX, "gpgme:status_handler", gpgsm,
904 "fd 0x%x: error from assuan (%d) getting status line : %s",
905 fd, err, gpg_strerror (err));
907 else if (linelen >= 3
908 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
909 && (line[3] == '\0' || line[3] == ' '))
912 err = atoi (&line[4]);
914 err = gpg_error (GPG_ERR_GENERAL);
915 TRACE (DEBUG_CTX, "gpgme:status_handler", gpgsm,
916 "fd 0x%x: ERR line - mapped to: %s",
917 fd, err ? gpg_strerror (err) : "ok");
918 /* Try our best to terminate the connection friendly. */
919 /* assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
921 else if (linelen >= 2
922 && line[0] == 'O' && line[1] == 'K'
923 && (line[2] == '\0' || line[2] == ' '))
925 if (gpgsm->status.fnc)
927 char emptystring[1] = {0};
928 err = gpgsm->status.fnc (gpgsm->status.fnc_value,
929 GPGME_STATUS_EOF, emptystring);
930 if (gpg_err_code (err) == GPG_ERR_FALSE)
931 err = 0; /* Drop special error code. */
934 if (!err && gpgsm->colon.fnc && gpgsm->colon.any)
936 /* We must tell a colon function about the EOF. We do
937 this only when we have seen any data lines. Note
938 that this inlined use of colon data lines will
939 eventually be changed into using a regular data
941 gpgsm->colon.any = 0;
942 err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, NULL);
944 TRACE (DEBUG_CTX, "gpgme:status_handler", gpgsm,
945 "fd 0x%x: OK line - final status: %s",
946 fd, err ? gpg_strerror (err) : "ok");
947 _gpgme_io_close (gpgsm->status_cb.fd);
951 && line[0] == 'D' && line[1] == ' '
954 /* We are using the colon handler even for plain inline data
955 - strange name for that function but for historic reasons
957 /* FIXME We can't use this for binary data because we
958 assume this is a string. For the current usage of colon
959 output it is correct. */
960 char *src = line + 2;
961 char *end = line + linelen;
963 char **aline = &gpgsm->colon.attic.line;
964 int *alinelen = &gpgsm->colon.attic.linelen;
966 if (gpgsm->colon.attic.linesize < *alinelen + linelen + 1)
968 char *newline = realloc (*aline, *alinelen + linelen + 1);
970 err = gpg_error_from_syserror ();
974 gpgsm->colon.attic.linesize = *alinelen + linelen + 1;
979 dst = *aline + *alinelen;
981 while (!err && src < end)
983 if (*src == '%' && src + 2 < end)
985 /* Handle escaped characters. */
987 *dst = _gpgme_hextobyte (src);
999 /* Terminate the pending line, pass it to the colon
1000 handler and reset it. */
1002 gpgsm->colon.any = 1;
1003 if (*alinelen > 1 && *(dst - 1) == '\r')
1007 /* FIXME How should we handle the return code? */
1008 err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, *aline);
1019 TRACE (DEBUG_CTX, "gpgme:status_handler", gpgsm,
1020 "fd 0x%x: D line; final status: %s",
1021 fd, err? gpg_strerror (err):"ok");
1023 else if (linelen > 2
1024 && line[0] == 'D' && line[1] == ' '
1025 && gpgsm->inline_data)
1027 char *src = line + 2;
1028 char *end = line + linelen;
1030 gpgme_ssize_t nwritten;
1035 if (*src == '%' && src + 2 < end)
1037 /* Handle escaped characters. */
1039 *dst++ = _gpgme_hextobyte (src);
1051 nwritten = gpgme_data_write (gpgsm->inline_data, src, linelen);
1052 if (nwritten <= 0 || nwritten > linelen)
1054 err = gpg_error_from_syserror ();
1058 linelen -= nwritten;
1061 TRACE (DEBUG_CTX, "gpgme:status_handler", gpgsm,
1062 "fd 0x%x: D inlinedata; final status: %s",
1063 fd, err? gpg_strerror (err):"ok");
1065 else if (linelen > 2
1066 && line[0] == 'S' && line[1] == ' ')
1069 gpgme_status_code_t r;
1071 rest = strchr (line + 2, ' ');
1073 rest = line + linelen; /* set to an empty string */
1077 r = _gpgme_parse_status (line + 2);
1078 if (gpgsm->status.mon_cb && r != GPGME_STATUS_PROGRESS)
1080 /* Note that we call the monitor even if we do
1081 * not know the status code (r < 0). */
1082 err = gpgsm->status.mon_cb (gpgsm->status.mon_cb_value,
1090 if (gpgsm->status.fnc)
1092 err = gpgsm->status.fnc (gpgsm->status.fnc_value, r, rest);
1093 if (gpg_err_code (err) == GPG_ERR_FALSE)
1094 err = 0; /* Drop special error code. */
1098 fprintf (stderr, "[UNKNOWN STATUS]%s %s", line + 2, rest);
1099 TRACE (DEBUG_CTX, "gpgme:status_handler", gpgsm,
1100 "fd 0x%x: S line (%s) - final status: %s",
1101 fd, line+2, err? gpg_strerror (err):"ok");
1103 else if (linelen >= 7
1104 && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
1105 && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
1107 && (line[7] == '\0' || line[7] == ' '))
1109 char *keyword = line+7;
1111 while (*keyword == ' ')
1113 default_inq_cb (gpgsm, keyword);
1114 assuan_write_line (gpgsm->assuan_ctx, "END");
1118 while (!err && assuan_pending_line (gpgsm->assuan_ctx));
1124 static gpgme_error_t
1125 add_io_cb (engine_gpgsm_t gpgsm, iocb_data_t *iocbd, gpgme_io_cb_t handler)
1129 TRACE_BEG (DEBUG_ENGINE, "engine-gpgsm:add_io_cb", gpgsm,
1130 "fd=%d, dir %d", iocbd->fd, iocbd->dir);
1131 err = (*gpgsm->io_cbs.add) (gpgsm->io_cbs.add_priv,
1132 iocbd->fd, iocbd->dir,
1133 handler, iocbd->data, &iocbd->tag);
1135 return TRACE_ERR (err);
1137 /* FIXME Kludge around poll() problem. */
1138 err = _gpgme_io_set_nonblocking (iocbd->fd);
1139 return TRACE_ERR (err);
1143 static gpgme_error_t
1144 start (engine_gpgsm_t gpgsm, const char *command)
1147 assuan_fd_t afdlist[5];
1152 if (*gpgsm->request_origin)
1156 cmd = _gpgme_strconcat ("OPTION request-origin=",
1157 gpgsm->request_origin, NULL);
1159 return gpg_error_from_syserror ();
1160 err = gpgsm_assuan_simple_command (gpgsm, cmd, NULL, NULL);
1162 if (err && gpg_err_code (err) != GPG_ERR_UNKNOWN_OPTION)
1166 /* We need to know the fd used by assuan for reads. We do this by
1167 using the assumption that the first returned fd from
1168 assuan_get_active_fds() is always this one. */
1169 nfds = assuan_get_active_fds (gpgsm->assuan_ctx, 0 /* read fds */,
1170 afdlist, DIM (afdlist));
1172 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1174 for (i = 0; i < nfds; i++)
1175 fdlist[i] = (int) afdlist[i];
1177 /* We "duplicate" the file descriptor, so we can close it here (we
1178 can't close fdlist[0], as that is closed by libassuan, and
1179 closing it here might cause libassuan to close some unrelated FD
1180 later). Alternatively, we could special case status_fd and
1181 register/unregister it manually as needed, but this increases
1182 code duplication and is more complicated as we can not use the
1183 close notifications etc. A third alternative would be to let
1184 Assuan know that we closed the FD, but that complicates the
1185 Assuan interface. */
1187 gpgsm->status_cb.fd = _gpgme_io_dup (fdlist[0]);
1188 if (gpgsm->status_cb.fd < 0)
1189 return gpg_error_from_syserror ();
1191 if (_gpgme_io_set_close_notify (gpgsm->status_cb.fd,
1192 close_notify_handler, gpgsm))
1194 _gpgme_io_close (gpgsm->status_cb.fd);
1195 gpgsm->status_cb.fd = -1;
1196 return gpg_error (GPG_ERR_GENERAL);
1199 err = add_io_cb (gpgsm, &gpgsm->status_cb, status_handler);
1200 if (!err && gpgsm->input_cb.fd != -1)
1201 err = add_io_cb (gpgsm, &gpgsm->input_cb, _gpgme_data_outbound_handler);
1202 if (!err && gpgsm->output_cb.fd != -1)
1203 err = add_io_cb (gpgsm, &gpgsm->output_cb, _gpgme_data_inbound_handler);
1204 if (!err && gpgsm->message_cb.fd != -1)
1205 err = add_io_cb (gpgsm, &gpgsm->message_cb, _gpgme_data_outbound_handler);
1206 if (!err && gpgsm->diag_cb.fd != -1)
1207 err = add_io_cb (gpgsm, &gpgsm->diag_cb, _gpgme_data_inbound_handler);
1210 err = assuan_write_line (gpgsm->assuan_ctx, command);
1213 gpgsm_io_event (gpgsm, GPGME_EVENT_START, NULL);
1219 #if USE_DESCRIPTOR_PASSING
1220 static gpgme_error_t
1221 gpgsm_reset (void *engine)
1223 engine_gpgsm_t gpgsm = engine;
1225 /* IF we have an active connection we must send a reset because we
1226 need to reset the list of signers. Note that RESET does not
1227 reset OPTION commands. */
1228 return (gpgsm->assuan_ctx
1229 ? gpgsm_assuan_simple_command (gpgsm, "RESET", NULL, NULL)
1236 static gpgme_error_t
1237 gpgsm_decrypt (void *engine,
1238 gpgme_decrypt_flags_t flags,
1239 gpgme_data_t ciph, gpgme_data_t plain,
1240 int export_session_key, const char *override_session_key,
1241 int auto_key_retrieve)
1243 engine_gpgsm_t gpgsm = engine;
1248 /* gpgsm is not capable of exporting session keys right now, so we
1249 * will ignore this if requested. */
1250 (void)export_session_key;
1251 (void)override_session_key;
1253 /* --auto-key-retrieve is also not supported. */
1254 (void)auto_key_retrieve;
1257 return gpg_error (GPG_ERR_INV_VALUE);
1259 gpgsm->input_cb.data = ciph;
1260 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1262 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1263 gpgsm->output_cb.data = plain;
1264 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1266 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1267 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1268 gpgsm->inline_data = NULL;
1270 err = start (engine, "DECRYPT");
1275 static gpgme_error_t
1276 gpgsm_delete (void *engine, gpgme_key_t key, unsigned int flags)
1278 engine_gpgsm_t gpgsm = engine;
1280 char *fpr = key->subkeys ? key->subkeys->fpr : NULL;
1283 int length = 8; /* "DELKEYS " */
1288 return gpg_error (GPG_ERR_INV_VALUE);
1293 if (*linep == '%' || *linep == ' ' || *linep == '+')
1299 line = malloc (length);
1301 return gpg_error_from_syserror ();
1303 strcpy (line, "DELKEYS ");
1333 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1334 gpgsm_clear_fd (gpgsm, INPUT_FD);
1335 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1336 gpgsm->inline_data = NULL;
1338 err = start (gpgsm, line);
1345 static gpgme_error_t
1346 set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[])
1348 gpgme_error_t err = 0;
1351 int invalid_recipients = 0;
1354 linelen = 10 + 40 + 1; /* "RECIPIENT " + guess + '\0'. */
1355 line = malloc (10 + 40 + 1);
1357 return gpg_error_from_syserror ();
1358 strcpy (line, "RECIPIENT ");
1359 for (i =0; !err && recp[i]; i++)
1364 if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
1366 invalid_recipients++;
1369 fpr = recp[i]->subkeys->fpr;
1371 newlen = 11 + strlen (fpr);
1372 if (linelen < newlen)
1374 char *newline = realloc (line, newlen);
1377 int saved_err = gpg_error_from_syserror ();
1384 strcpy (&line[10], fpr);
1386 err = gpgsm_assuan_simple_command (gpgsm, line, gpgsm->status.fnc,
1387 gpgsm->status.fnc_value);
1388 /* FIXME: This requires more work. */
1389 if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
1390 invalid_recipients++;
1398 return gpg_error (invalid_recipients
1399 ? GPG_ERR_UNUSABLE_PUBKEY : GPG_ERR_NO_ERROR);
1403 /* Take recipients from the LF delimited STRING and send RECIPIENT
1404 * commands to gpgsm. */
1405 static gpgme_error_t
1406 set_recipients_from_string (engine_gpgsm_t gpgsm, const char *string)
1408 gpg_error_t err = 0;
1417 while (*string == ' ' || *string == '\t')
1422 s = strchr (string, '\n');
1426 n = strlen (string);
1427 while (n && (string[n-1] == ' ' || string[n-1] == '\t'))
1430 if (!ignore && n == 2 && !memcmp (string, "--", 2))
1432 else if (!ignore && n > 2 && !memcmp (string, "--", 2))
1433 err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
1434 else if (n) /* Not empty - use it. */
1437 if (gpgrt_asprintf (&line, "RECIPIENT %.*s", n, string) < 0)
1438 err = gpg_error_from_syserror ();
1441 err = gpgsm_assuan_simple_command (gpgsm, line, gpgsm->status.fnc,
1442 gpgsm->status.fnc_value);
1453 err = gpg_error (GPG_ERR_MISSING_KEY);
1459 static gpgme_error_t
1460 gpgsm_encrypt (void *engine, gpgme_key_t recp[], const char *recpstring,
1461 gpgme_encrypt_flags_t flags,
1462 gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
1464 engine_gpgsm_t gpgsm = engine;
1468 return gpg_error (GPG_ERR_INV_VALUE);
1469 if (!recp && !recpstring) /* Symmetric only */
1470 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1472 if ((flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
1474 err = gpgsm_assuan_simple_command (gpgsm,
1475 "OPTION no-encrypt-to", NULL, NULL);
1480 gpgsm->input_cb.data = plain;
1481 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1484 gpgsm->output_cb.data = ciph;
1485 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1486 : map_data_enc (gpgsm->output_cb.data));
1489 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1490 gpgsm->inline_data = NULL;
1492 if (!recp && recpstring)
1493 err = set_recipients_from_string (gpgsm, recpstring);
1495 err = set_recipients (gpgsm, recp);
1498 err = start (gpgsm, "ENCRYPT");
1504 static gpgme_error_t
1505 gpgsm_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
1506 gpgme_data_t keydata, int use_armor)
1508 engine_gpgsm_t gpgsm = engine;
1509 gpgme_error_t err = 0;
1513 return gpg_error (GPG_ERR_INV_VALUE);
1518 cmd = malloc (7 + 9 + 9 + strlen (pattern) + 1);
1520 return gpg_error_from_syserror ();
1522 strcpy (cmd, "EXPORT ");
1523 if ((mode & GPGME_EXPORT_MODE_SECRET))
1525 strcat (cmd, "--secret ");
1526 if ((mode & GPGME_EXPORT_MODE_RAW))
1527 strcat (cmd, "--raw ");
1528 else if ((mode & GPGME_EXPORT_MODE_PKCS12))
1529 strcat (cmd, "--pkcs12 ");
1531 strcat (cmd, pattern);
1533 gpgsm->output_cb.data = keydata;
1534 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1535 : map_data_enc (gpgsm->output_cb.data));
1538 gpgsm_clear_fd (gpgsm, INPUT_FD);
1539 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1540 gpgsm->inline_data = NULL;
1542 err = start (gpgsm, cmd);
1548 static gpgme_error_t
1549 gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
1550 gpgme_data_t keydata, int use_armor)
1552 engine_gpgsm_t gpgsm = engine;
1553 gpgme_error_t err = 0;
1555 /* Length is "EXPORT " + "--secret " + "--pkcs12 " + p + '\0'. */
1556 int length = 7 + 9 + 9 + 1;
1560 return gpg_error (GPG_ERR_INV_VALUE);
1562 if (pattern && *pattern)
1564 const char **pat = pattern;
1568 const char *patlet = *pat;
1573 if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1581 line = malloc (length);
1583 return gpg_error_from_syserror ();
1585 strcpy (line, "EXPORT ");
1586 if ((mode & GPGME_EXPORT_MODE_SECRET))
1588 strcat (line, "--secret ");
1589 if ((mode & GPGME_EXPORT_MODE_RAW))
1590 strcat (line, "--raw ");
1591 else if ((mode & GPGME_EXPORT_MODE_PKCS12))
1592 strcat (line, "--pkcs12 ");
1594 linep = &line[strlen (line)];
1596 if (pattern && *pattern)
1600 const char *patlet = *pattern;
1622 *(linep++) = *patlet;
1634 gpgsm->output_cb.data = keydata;
1635 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1636 : map_data_enc (gpgsm->output_cb.data));
1639 gpgsm_clear_fd (gpgsm, INPUT_FD);
1640 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1641 gpgsm->inline_data = NULL;
1643 err = start (gpgsm, line);
1649 static gpgme_error_t
1650 gpgsm_genkey (void *engine,
1651 const char *userid, const char *algo,
1652 unsigned long reserved, unsigned long expires,
1653 gpgme_key_t key, unsigned int flags,
1654 gpgme_data_t help_data, unsigned int extraflags,
1655 gpgme_data_t pubkey, gpgme_data_t seckey)
1657 engine_gpgsm_t gpgsm = engine;
1663 return gpg_error (GPG_ERR_INV_VALUE);
1667 if (!pubkey || seckey)
1668 return gpg_error (GPG_ERR_INV_VALUE);
1670 gpgsm->input_cb.data = help_data;
1671 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1674 gpgsm->output_cb.data = pubkey;
1675 err = gpgsm_set_fd (gpgsm, OUTPUT_FD,
1676 (extraflags & GENKEY_EXTRAFLAG_ARMOR)? "--armor"
1677 : map_data_enc (gpgsm->output_cb.data));
1680 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1681 gpgsm->inline_data = NULL;
1683 err = start (gpgsm, "GENKEY");
1693 /* The new interface has not yet been implemented, */
1694 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1698 static gpgme_error_t
1699 gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
1701 engine_gpgsm_t gpgsm = engine;
1703 gpgme_data_encoding_t dataenc;
1707 return gpg_error (GPG_ERR_INV_VALUE);
1709 if (keydata && keyarray)
1710 return gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed. */
1712 dataenc = gpgme_data_get_encoding (keydata);
1719 /* Fist check whether the engine already features the
1720 --re-import option. */
1721 err = gpgsm_assuan_simple_command
1722 (gpgsm, "GETINFO cmd_has_option IMPORT re-import", NULL, NULL);
1724 return gpg_error (GPG_ERR_NOT_SUPPORTED);
1726 /* Create an internal data object with a list of all
1727 fingerprints. The data object and its memory (to avoid an
1728 extra copy by gpgme_data_new_from_mem) are stored in two
1729 variables which are released by the close_notify_handler. */
1730 for (idx=0, buflen=0; keyarray[idx]; idx++)
1732 if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
1733 && keyarray[idx]->subkeys
1734 && keyarray[idx]->subkeys->fpr
1735 && *keyarray[idx]->subkeys->fpr)
1736 buflen += strlen (keyarray[idx]->subkeys->fpr) + 1;
1738 /* Allocate a buffer with extra space for the trailing Nul
1739 introduced by the use of stpcpy. */
1740 buffer = malloc (buflen+1);
1742 return gpg_error_from_syserror ();
1743 for (idx=0, p = buffer; keyarray[idx]; idx++)
1745 if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
1746 && keyarray[idx]->subkeys
1747 && keyarray[idx]->subkeys->fpr
1748 && *keyarray[idx]->subkeys->fpr)
1749 p = stpcpy (stpcpy (p, keyarray[idx]->subkeys->fpr), "\n");
1752 err = gpgme_data_new_from_mem (&gpgsm->input_helper_data,
1759 gpgsm->input_helper_memory = buffer;
1761 gpgsm->input_cb.data = gpgsm->input_helper_data;
1762 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1765 gpgme_data_release (gpgsm->input_helper_data);
1766 gpgsm->input_helper_data = NULL;
1767 free (gpgsm->input_helper_memory);
1768 gpgsm->input_helper_memory = NULL;
1771 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1772 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1773 gpgsm->inline_data = NULL;
1775 return start (gpgsm, "IMPORT --re-import");
1777 else if (dataenc == GPGME_DATA_ENCODING_URL
1778 || dataenc == GPGME_DATA_ENCODING_URL0
1779 || dataenc == GPGME_DATA_ENCODING_URLESC)
1781 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1785 gpgsm->input_cb.data = keydata;
1786 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1789 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1790 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1791 gpgsm->inline_data = NULL;
1793 return start (gpgsm, "IMPORT");
1798 static gpgme_error_t
1799 gpgsm_keylist (void *engine, const char *pattern, int secret_only,
1800 gpgme_keylist_mode_t mode, int engine_flags)
1802 engine_gpgsm_t gpgsm = engine;
1807 if (mode & GPGME_KEYLIST_MODE_LOCAL)
1809 if (mode & GPGME_KEYLIST_MODE_EXTERN)
1815 /* Hack to make sure that the agent is started. Only if the agent
1816 has been started an application may connect to the agent via
1817 GPGME_PROTOCOL_ASSUAN - for example to look for smartcards. We
1818 do this only if a secret key listing has been requested. In
1819 general this is not needed because a secret key listing starts
1820 the agent. However on a fresh installation no public keys are
1821 available and thus there is no need for gpgsm to ask the agent
1822 whether a secret key exists for the public key. */
1823 if (secret_only || (mode & GPGME_KEYLIST_MODE_WITH_SECRET))
1824 gpgsm_assuan_simple_command (gpgsm, "GETINFO agent-check", NULL, NULL);
1826 /* Always send list-mode option because RESET does not reset it. */
1827 if (gpgrt_asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1828 return gpg_error_from_syserror ();
1829 err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
1835 /* Always send key validation because RESET does not reset it. */
1837 /* Use the validation mode if requested. We don't check for an error
1838 yet because this is a pretty fresh gpgsm features. */
1839 gpgsm_assuan_simple_command (gpgsm,
1840 (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1841 "OPTION with-validation=1":
1842 "OPTION with-validation=0" ,
1844 /* Include the ephemeral keys if requested. We don't check for an error
1845 yet because this is a pretty fresh gpgsm features. */
1846 gpgsm_assuan_simple_command (gpgsm,
1847 (mode & GPGME_KEYLIST_MODE_EPHEMERAL)?
1848 "OPTION with-ephemeral-keys=1":
1849 "OPTION with-ephemeral-keys=0" ,
1851 gpgsm_assuan_simple_command (gpgsm,
1852 (mode & GPGME_KEYLIST_MODE_WITH_SECRET)?
1853 "OPTION with-secret=1":
1854 "OPTION with-secret=0" ,
1856 gpgsm_assuan_simple_command (gpgsm,
1857 (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)?
1859 "OPTION offline=0" ,
1863 /* Length is "LISTSECRETKEYS " + p + '\0'. */
1864 line = malloc (15 + strlen (pattern) + 1);
1866 return gpg_error_from_syserror ();
1869 strcpy (line, "LISTSECRETKEYS ");
1870 strcpy (&line[15], pattern);
1874 strcpy (line, "LISTKEYS ");
1875 strcpy (&line[9], pattern);
1878 gpgsm_clear_fd (gpgsm, INPUT_FD);
1879 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1880 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1881 gpgsm->inline_data = NULL;
1883 err = start (gpgsm, line);
1889 static gpgme_error_t
1890 gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
1891 int reserved, gpgme_keylist_mode_t mode, int engine_flags)
1893 engine_gpgsm_t gpgsm = engine;
1896 /* Length is "LISTSECRETKEYS " + p + '\0'. */
1897 int length = 15 + 1;
1899 int any_pattern = 0;
1903 return gpg_error (GPG_ERR_INV_VALUE);
1905 if (mode & GPGME_KEYLIST_MODE_LOCAL)
1907 if (mode & GPGME_KEYLIST_MODE_EXTERN)
1910 /* Always send list-mode option because RESET does not reset it. */
1911 if (gpgrt_asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1912 return gpg_error_from_syserror ();
1913 err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
1918 /* Always send key validation because RESET does not reset it. */
1919 /* Use the validation mode if required. We don't check for an error
1920 yet because this is a pretty fresh gpgsm features. */
1921 gpgsm_assuan_simple_command (gpgsm,
1922 (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1923 "OPTION with-validation=1":
1924 "OPTION with-validation=0" ,
1926 gpgsm_assuan_simple_command (gpgsm,
1927 (mode & GPGME_KEYLIST_MODE_WITH_SECRET)?
1928 "OPTION with-secret=1":
1929 "OPTION with-secret=0" ,
1931 gpgsm_assuan_simple_command (gpgsm,
1932 (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)?
1934 "OPTION offline=0" ,
1937 if (pattern && *pattern)
1939 const char **pat = pattern;
1943 const char *patlet = *pat;
1948 if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1956 line = malloc (length);
1958 return gpg_error_from_syserror ();
1961 strcpy (line, "LISTSECRETKEYS ");
1966 strcpy (line, "LISTKEYS ");
1970 if (pattern && *pattern)
1974 const char *patlet = *pattern;
1996 *(linep++) = *patlet;
2010 gpgsm_clear_fd (gpgsm, INPUT_FD);
2011 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
2012 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
2013 gpgsm->inline_data = NULL;
2015 err = start (gpgsm, line);
2021 static gpgme_error_t
2022 gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
2023 gpgme_sig_mode_t mode, int use_armor, int use_textmode,
2024 int include_certs, gpgme_ctx_t ctx /* FIXME */)
2026 engine_gpgsm_t gpgsm = engine;
2035 return gpg_error (GPG_ERR_INV_VALUE);
2037 /* FIXME: This does not work as RESET does not reset it so we can't
2038 revert back to default. */
2039 if (include_certs != GPGME_INCLUDE_CERTS_DEFAULT)
2041 /* FIXME: Make sure that if we run multiple operations, that we
2042 can reset any previously set value in case the default is
2045 if (gpgrt_asprintf (&assuan_cmd,
2046 "OPTION include-certs %i", include_certs) < 0)
2047 return gpg_error_from_syserror ();
2048 err = gpgsm_assuan_simple_command (gpgsm, assuan_cmd, NULL, NULL);
2049 gpgrt_free (assuan_cmd);
2054 for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
2056 const char *s = key->subkeys ? key->subkeys->fpr : NULL;
2057 if (s && strlen (s) < 80)
2061 strcpy (stpcpy (buf, "SIGNER "), s);
2062 err = gpgsm_assuan_simple_command (gpgsm, buf,
2064 gpgsm->status.fnc_value);
2067 err = gpg_error (GPG_ERR_INV_VALUE);
2068 gpgme_key_unref (key);
2073 gpgsm->input_cb.data = in;
2074 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
2077 gpgsm->output_cb.data = out;
2078 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
2079 : map_data_enc (gpgsm->output_cb.data));
2082 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
2083 gpgsm->inline_data = NULL;
2085 err = start (gpgsm, mode == GPGME_SIG_MODE_DETACH
2086 ? "SIGN --detached" : "SIGN");
2091 static gpgme_error_t
2092 gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
2093 gpgme_data_t plaintext, gpgme_ctx_t ctx)
2095 engine_gpgsm_t gpgsm = engine;
2101 return gpg_error (GPG_ERR_INV_VALUE);
2103 gpgsm->input_cb.data = sig;
2104 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
2109 /* Normal or cleartext signature. */
2112 gpgsm->output_cb.data = plaintext;
2113 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
2117 /* No output requested. */
2118 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
2120 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
2124 /* Detached signature. */
2125 gpgsm->message_cb.data = signed_text;
2126 err = gpgsm_set_fd (gpgsm, MESSAGE_FD, 0);
2127 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
2129 gpgsm->inline_data = NULL;
2132 err = start (gpgsm, "VERIFY");
2138 /* Send the GETAUDITLOG command. The result is saved to a gpgme data
2140 static gpgme_error_t
2141 gpgsm_getauditlog (void *engine, gpgme_data_t output, unsigned int flags)
2143 engine_gpgsm_t gpgsm = engine;
2144 gpgme_error_t err = 0;
2147 if (!gpgsm || !output)
2148 return gpg_error (GPG_ERR_INV_VALUE);
2150 if ((flags & GPGME_AUDITLOG_DIAG) && (flags & GPGME_AUDITLOG_HTML))
2151 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
2153 if ((flags & GPGME_AUDITLOG_DIAG))
2155 char buf[BUFFER_SIZE];
2157 int any_written = 0;
2158 gpgme_data_rewind (gpgsm->diagnostics);
2160 while ((nread = gpgme_data_read (gpgsm->diagnostics,
2161 buf, BUFFER_SIZE)) > 0)
2164 if (gpgme_data_write (output, buf, nread) == -1)
2165 return gpg_error_from_syserror ();
2168 return gpg_error (GPG_ERR_NO_DATA);
2171 return gpg_error_from_syserror ();
2173 gpgme_data_rewind (output);
2177 if (!gpgsm->assuan_ctx)
2178 return gpg_error (GPG_ERR_INV_VALUE);
2180 #if USE_DESCRIPTOR_PASSING
2181 gpgsm->output_cb.data = output;
2182 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
2186 gpgsm_clear_fd (gpgsm, INPUT_FD);
2187 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
2188 gpgsm->inline_data = NULL;
2189 # define CMD "GETAUDITLOG"
2191 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
2192 gpgsm_clear_fd (gpgsm, INPUT_FD);
2193 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
2194 gpgsm->inline_data = output;
2195 # define CMD "GETAUDITLOG --data"
2198 err = start (gpgsm, (flags & GPGME_AUDITLOG_HTML)? CMD " --html" : CMD);
2204 /* This sets a status callback for monitoring status lines before they
2205 * are passed to a caller set handler. */
2207 gpgsm_set_status_cb (void *engine, gpgme_status_cb_t cb, void *cb_value)
2209 engine_gpgsm_t gpgsm = engine;
2211 gpgsm->status.mon_cb = cb;
2212 gpgsm->status.mon_cb_value = cb_value;
2217 gpgsm_set_status_handler (void *engine, engine_status_handler_t fnc,
2220 engine_gpgsm_t gpgsm = engine;
2222 gpgsm->status.fnc = fnc;
2223 gpgsm->status.fnc_value = fnc_value;
2227 static gpgme_error_t
2228 gpgsm_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
2231 engine_gpgsm_t gpgsm = engine;
2233 gpgsm->colon.fnc = fnc;
2234 gpgsm->colon.fnc_value = fnc_value;
2235 gpgsm->colon.any = 0;
2241 gpgsm_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
2243 engine_gpgsm_t gpgsm = engine;
2244 gpgsm->io_cbs = *io_cbs;
2249 gpgsm_io_event (void *engine, gpgme_event_io_t type, void *type_data)
2251 engine_gpgsm_t gpgsm = engine;
2253 TRACE (DEBUG_ENGINE, "gpgme:gpgsm_io_event", gpgsm,
2254 "event %p, type %d, type_data %p",
2255 gpgsm->io_cbs.event, type, type_data);
2256 if (gpgsm->io_cbs.event)
2257 (*gpgsm->io_cbs.event) (gpgsm->io_cbs.event_priv, type, type_data);
2261 static gpgme_error_t
2262 gpgsm_passwd (void *engine, gpgme_key_t key, unsigned int flags)
2264 engine_gpgsm_t gpgsm = engine;
2270 if (!key || !key->subkeys || !key->subkeys->fpr)
2271 return gpg_error (GPG_ERR_INV_CERT_OBJ);
2273 if (gpgrt_asprintf (&line, "PASSWD -- %s", key->subkeys->fpr) < 0)
2274 return gpg_error_from_syserror ();
2276 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
2277 gpgsm_clear_fd (gpgsm, INPUT_FD);
2278 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
2279 gpgsm->inline_data = NULL;
2281 err = start (gpgsm, line);
2289 struct engine_ops _gpgme_engine_ops_gpgsm =
2291 /* Static functions. */
2292 _gpgme_get_default_gpgsm_name,
2295 gpgsm_get_req_version,
2298 /* Member functions. */
2300 #if USE_DESCRIPTOR_PASSING
2305 gpgsm_set_status_cb,
2306 gpgsm_set_status_handler,
2307 NULL, /* set_command_handler */
2308 gpgsm_set_colon_line_handler,
2310 NULL, /* set_protocol */
2311 gpgsm_set_engine_flags,
2313 gpgsm_delete, /* decrypt_verify */
2316 NULL, /* encrypt_sign */
2323 NULL, /* keylist_data */
2325 NULL, /* tofu_policy */
2327 NULL, /* trustlist */
2330 NULL, /* opassuan_transact */
2331 NULL, /* conf_load */
2332 NULL, /* conf_save */
2333 NULL, /* conf_dir */
2334 NULL, /* query_swdb */
2338 NULL, /* cancel_op */
2340 NULL, /* set_pinentry_mode */