1 /* engine-g13.c - G13 engine.
2 Copyright (C) 2000 Werner Koch (dd9jn)
3 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009 g10 Code GmbH
5 This file is part of GPGME.
7 GPGME is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of
10 the License, or (at your option) any later version.
12 GPGME is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public
18 License along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
28 #include <sys/types.h>
32 #include <fcntl.h> /* FIXME */
45 #include "engine-backend.h"
50 int fd; /* FD we talk about. */
51 int server_fd;/* Server FD for this connection. */
52 int dir; /* Inbound/Outbound, maybe given implicit? */
53 void *data; /* Handler-specific data. */
54 void *tag; /* ID from the user for gpgme_remove_io_callback. */
55 char server_fd_str[15]; /* Same as SERVER_FD but as a string. We
56 need this because _gpgme_io_fd2str can't
57 be used on a closed descriptor. */
63 assuan_context_t assuan_ctx;
68 iocb_data_t status_cb;
70 struct gpgme_io_cbs io_cbs;
72 /* Internal callbacks. */
73 engine_assuan_result_cb_t result_cb;
74 void *result_cb_value;
76 /* User provided callbacks. */
78 gpgme_assuan_data_cb_t data_cb;
81 gpgme_assuan_inquire_cb_t inq_cb;
84 gpgme_assuan_status_cb_t status_cb;
85 void *status_cb_value;
89 typedef struct engine_g13 *engine_g13_t;
92 static void g13_io_event (void *engine,
93 gpgme_event_io_t type, void *type_data);
98 g13_get_version (const char *file_name)
100 return _gpgme_get_program_version (file_name ? file_name
101 : _gpgme_get_g13_path ());
106 g13_get_req_version (void)
108 return NEED_G13_VERSION;
113 close_notify_handler (int fd, void *opaque)
115 engine_g13_t g13 = opaque;
118 if (g13->status_cb.fd == fd)
120 if (g13->status_cb.tag)
121 (*g13->io_cbs.remove) (g13->status_cb.tag);
122 g13->status_cb.fd = -1;
123 g13->status_cb.tag = NULL;
128 /* This is the default inquiry callback. We use it to handle the
129 Pinentry notifications. */
131 default_inq_cb (engine_g13_t g13, const char *keyword, const char *args)
135 if (!strcmp (keyword, "PINENTRY_LAUNCHED"))
137 _gpgme_allow_set_foreground_window ((pid_t)strtoul (args, NULL, 10));
140 if (g13->user.inq_cb)
142 gpgme_data_t data = NULL;
144 err = g13->user.inq_cb (g13->user.inq_cb_value,
145 keyword, args, &data);
148 /* FIXME: Returning data is not yet implemented. However we
149 need to allow the caller to cleanup his data object.
150 Thus we run the callback in finish mode immediately. */
151 err = g13->user.inq_cb (g13->user.inq_cb_value,
163 g13_cancel (void *engine)
165 engine_g13_t g13 = engine;
168 return gpg_error (GPG_ERR_INV_VALUE);
170 if (g13->status_cb.fd != -1)
171 _gpgme_io_close (g13->status_cb.fd);
175 assuan_release (g13->assuan_ctx);
176 g13->assuan_ctx = NULL;
184 g13_cancel_op (void *engine)
186 engine_g13_t g13 = engine;
189 return gpg_error (GPG_ERR_INV_VALUE);
191 if (g13->status_cb.fd != -1)
192 _gpgme_io_close (g13->status_cb.fd);
199 g13_release (void *engine)
201 engine_g13_t g13 = engine;
213 g13_new (void **engine, const char *file_name, const char *home_dir)
215 gpgme_error_t err = 0;
219 char *dft_display = NULL;
220 char dft_ttyname[64];
221 char *dft_ttytype = NULL;
224 g13 = calloc (1, sizeof *g13);
226 return gpg_error_from_errno (errno);
228 g13->status_cb.fd = -1;
229 g13->status_cb.dir = 1;
230 g13->status_cb.tag = 0;
231 g13->status_cb.data = g13;
233 err = assuan_new (&g13->assuan_ctx);
238 argv[argc++] = "g13";
241 argv[argc++] = "--homedir";
242 argv[argc++] = home_dir;
244 argv[argc++] = "--server";
247 err = assuan_new_ext (&g13->assuan_ctx, GPG_ERR_SOURCE_GPGME,
248 &_gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb,
252 assuan_ctx_set_system_hooks (g13->assuan_ctx, &_gpgme_assuan_system_hooks);
254 #if USE_DESCRIPTOR_PASSING
255 err = assuan_pipe_connect_ext
256 (g13->assuan_ctx, file_name ? file_name : _gpgme_get_g13_path (),
257 argv, NULL, NULL, NULL, 1);
259 err = assuan_pipe_connect
260 (g13->assuan_ctx, file_name ? file_name : _gpgme_get_g13_path (),
266 err = _gpgme_getenv ("DISPLAY", &dft_display);
271 if (asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
274 err = gpg_error_from_errno (errno);
279 err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL, NULL,
290 rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
293 err = gpg_error_from_errno (rc);
298 if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
300 err = gpg_error_from_errno (errno);
303 err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL, NULL,
309 err = _gpgme_getenv ("TERM", &dft_ttytype);
314 if (asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype) < 0)
317 err = gpg_error_from_errno (errno);
322 err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL,
323 NULL, NULL, NULL, NULL);
331 #ifdef HAVE_W32_SYSTEM
332 /* Under Windows we need to use AllowSetForegroundWindow. Tell
333 g13 to tell us when it needs it. */
336 err = assuan_transact (g13->assuan_ctx, "OPTION allow-pinentry-notify",
337 NULL, NULL, NULL, NULL, NULL, NULL);
338 if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
339 err = 0; /* This is a new feature of g13. */
341 #endif /*HAVE_W32_SYSTEM*/
355 g13_set_locale (void *engine, int category, const char *value)
357 engine_g13_t g13 = engine;
362 /* FIXME: If value is NULL, we need to reset the option to default.
363 But we can't do this. So we error out here. G13 needs support
365 if (category == LC_CTYPE)
368 if (!value && g13->lc_ctype_set)
369 return gpg_error (GPG_ERR_INV_VALUE);
371 g13->lc_ctype_set = 1;
374 else if (category == LC_MESSAGES)
376 catstr = "lc-messages";
377 if (!value && g13->lc_messages_set)
378 return gpg_error (GPG_ERR_INV_VALUE);
380 g13->lc_messages_set = 1;
382 #endif /* LC_MESSAGES */
384 return gpg_error (GPG_ERR_INV_VALUE);
386 /* FIXME: Reset value to default. */
390 if (asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0)
391 err = gpg_error_from_errno (errno);
394 err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL,
395 NULL, NULL, NULL, NULL);
404 g13_assuan_simple_command (assuan_context_t ctx, char *cmd,
405 engine_status_handler_t status_fnc,
406 void *status_fnc_value)
412 err = assuan_write_line (ctx, cmd);
418 err = assuan_read_line (ctx, &line, &linelen);
422 if (*line == '#' || !linelen)
426 && line[0] == 'O' && line[1] == 'K'
427 && (line[2] == '\0' || line[2] == ' '))
429 else if (linelen >= 4
430 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
432 err = atoi (&line[4]);
433 else if (linelen >= 2
434 && line[0] == 'S' && line[1] == ' ')
438 rest = strchr (line + 2, ' ');
440 rest = line + linelen; /* set to an empty string */
444 /* Nothing to do with status lines. */
447 err = gpg_error (GPG_ERR_GENERAL);
456 status_handler (void *opaque, int fd)
458 struct io_cb_data *data = (struct io_cb_data *) opaque;
459 engine_g13_t g13 = (engine_g13_t) data->handler_value;
460 gpgme_error_t err = 0;
466 err = assuan_read_line (g13->assuan_ctx, &line, &linelen);
469 /* Try our best to terminate the connection friendly. */
470 /* assuan_write_line (g13->assuan_ctx, "BYE"); */
471 TRACE2 (DEBUG_CTX, "gpgme:status_handler", g13,
472 "fd 0x%x: error reading assuan line: %s",
473 fd, gpg_strerror (err));
475 else if (linelen >= 3
476 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
477 && (line[3] == '\0' || line[3] == ' '))
480 err = atoi (&line[4]);
482 err = gpg_error (GPG_ERR_GENERAL);
483 TRACE2 (DEBUG_CTX, "gpgme:status_handler", g13,
484 "fd 0x%x: ERR line: %s",
485 fd, err ? gpg_strerror (err) : "ok");
487 /* In g13, command execution errors are not fatal, as we use
488 a session based protocol. */
490 err = g13->result_cb (g13->result_cb_value, err);
495 _gpgme_io_close (g13->status_cb.fd);
499 else if (linelen >= 2
500 && line[0] == 'O' && line[1] == 'K'
501 && (line[2] == '\0' || line[2] == ' '))
503 TRACE1 (DEBUG_CTX, "gpgme:status_handler", g13,
504 "fd 0x%x: OK line", fd);
506 err = g13->result_cb (g13->result_cb_value, 0);
511 _gpgme_io_close (g13->status_cb.fd);
516 && line[0] == 'D' && line[1] == ' ')
518 /* We are using the colon handler even for plain inline data
519 - strange name for that function but for historic reasons
521 /* FIXME We can't use this for binary data because we
522 assume this is a string. For the current usage of colon
523 output it is correct. */
524 char *src = line + 2;
525 char *end = line + linelen;
531 if (*src == '%' && src + 2 < end)
533 /* Handle escaped characters. */
535 *dst++ = _gpgme_hextobyte (src);
545 if (linelen && g13->user.data_cb)
546 err = g13->user.data_cb (g13->user.data_cb_value,
551 TRACE2 (DEBUG_CTX, "gpgme:g13_status_handler", g13,
552 "fd 0x%x: D inlinedata; status from cb: %s",
553 fd, (g13->user.data_cb ?
554 (err? gpg_strerror (err):"ok"):"no callback"));
558 && line[0] == 'S' && line[1] == ' ')
567 args = strchr (line + 2, ' ');
569 args = line + linelen; /* set to an empty string */
576 if (g13->user.status_cb)
577 err = g13->user.status_cb (g13->user.status_cb_value,
582 TRACE3 (DEBUG_CTX, "gpgme:g13_status_handler", g13,
583 "fd 0x%x: S line (%s) - status from cb: %s",
584 fd, line+2, (g13->user.status_cb ?
585 (err? gpg_strerror (err):"ok"):"no callback"));
587 else if (linelen >= 7
588 && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
589 && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
591 && (line[7] == '\0' || line[7] == ' '))
596 for (src=line+7; *src == ' '; src++)
599 args = strchr (src, ' ');
601 args = line + linelen; /* Let it point to an empty string. */
608 err = default_inq_cb (g13, src, args);
611 /* Flush and send END. */
612 err = assuan_send_data (g13->assuan_ctx, NULL, 0);
614 else if (gpg_err_code (err) == GPG_ERR_ASS_CANCELED)
616 /* Flush and send CANcel. */
617 err = assuan_send_data (g13->assuan_ctx, NULL, 1);
619 assuan_write_line (g13->assuan_ctx, "END");
622 while (!err && assuan_pending_line (g13->assuan_ctx));
629 add_io_cb (engine_g13_t g13, iocb_data_t *iocbd, gpgme_io_cb_t handler)
633 TRACE_BEG2 (DEBUG_ENGINE, "engine-g13:add_io_cb", g13,
634 "fd %d, dir %d", iocbd->fd, iocbd->dir);
635 err = (*g13->io_cbs.add) (g13->io_cbs.add_priv,
636 iocbd->fd, iocbd->dir,
637 handler, iocbd->data, &iocbd->tag);
639 return TRACE_ERR (err);
641 /* FIXME Kludge around poll() problem. */
642 err = _gpgme_io_set_nonblocking (iocbd->fd);
643 return TRACE_ERR (err);
648 start (engine_g13_t g13, const char *command)
654 /* We need to know the fd used by assuan for reads. We do this by
655 using the assumption that the first returned fd from
656 assuan_get_active_fds() is always this one. */
657 nfds = assuan_get_active_fds (g13->assuan_ctx, 0 /* read fds */,
658 fdlist, DIM (fdlist));
660 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
662 /* We "duplicate" the file descriptor, so we can close it here (we
663 can't close fdlist[0], as that is closed by libassuan, and
664 closing it here might cause libassuan to close some unrelated FD
665 later). Alternatively, we could special case status_fd and
666 register/unregister it manually as needed, but this increases
667 code duplication and is more complicated as we can not use the
668 close notifications etc. A third alternative would be to let
669 Assuan know that we closed the FD, but that complicates the
672 g13->status_cb.fd = _gpgme_io_dup (fdlist[0]);
673 if (g13->status_cb.fd < 0)
674 return gpg_error_from_syserror ();
676 if (_gpgme_io_set_close_notify (g13->status_cb.fd,
677 close_notify_handler, g13))
679 _gpgme_io_close (g13->status_cb.fd);
680 g13->status_cb.fd = -1;
681 return gpg_error (GPG_ERR_GENERAL);
684 err = add_io_cb (g13, &g13->status_cb, status_handler);
686 err = assuan_write_line (g13->assuan_ctx, command);
689 g13_io_event (g13, GPGME_EVENT_START, NULL);
695 #if USE_DESCRIPTOR_PASSING
697 g13_reset (void *engine)
699 engine_g13_t g13 = engine;
701 /* We must send a reset because we need to reset the list of
702 signers. Note that RESET does not reset OPTION commands. */
703 return g13_assuan_simple_command (g13->assuan_ctx, "RESET", NULL, NULL);
709 g13_transact (void *engine,
711 engine_assuan_result_cb_t result_cb,
712 void *result_cb_value,
713 gpgme_assuan_data_cb_t data_cb,
715 gpgme_assuan_inquire_cb_t inq_cb,
717 gpgme_assuan_status_cb_t status_cb,
718 void *status_cb_value)
720 engine_g13_t g13 = engine;
723 if (!g13 || !command || !*command)
724 return gpg_error (GPG_ERR_INV_VALUE);
726 g13->result_cb = result_cb;
727 g13->result_cb_value = result_cb_value;
728 g13->user.data_cb = data_cb;
729 g13->user.data_cb_value = data_cb_value;
730 g13->user.inq_cb = inq_cb;
731 g13->user.inq_cb_value = inq_cb_value;
732 g13->user.status_cb = status_cb;
733 g13->user.status_cb_value = status_cb_value;
735 err = start (g13, command);
742 g13_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
744 engine_g13_t g13 = engine;
745 g13->io_cbs = *io_cbs;
750 g13_io_event (void *engine, gpgme_event_io_t type, void *type_data)
752 engine_g13_t g13 = engine;
754 TRACE3 (DEBUG_ENGINE, "gpgme:g13_io_event", g13,
755 "event %p, type %d, type_data %p",
756 g13->io_cbs.event, type, type_data);
757 if (g13->io_cbs.event)
758 (*g13->io_cbs.event) (g13->io_cbs.event_priv, type, type_data);
762 struct engine_ops _gpgme_engine_ops_g13 =
764 /* Static functions. */
771 /* Member functions. */
773 #if USE_DESCRIPTOR_PASSING
778 NULL, /* set_status_handler */
779 NULL, /* set_command_handler */
780 NULL, /* set_colon_line_handler */
786 NULL, /* encrypt_sign */
788 NULL, /* export_ext */
792 NULL, /* keylist_ext */
794 NULL, /* trustlist */
796 NULL, /* getauditlog */
798 NULL, /* conf_load */
799 NULL, /* conf_save */