diff --git a/ChangeLog b/ChangeLog index 6899474d..83e47d49 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2006-12-17 Marcus Brinkmann + + * configure.ac: Fix two typos in last change. + 2006-12-03 Marcus Brinkmann * configure.ac: Use descriptor passing only if --enable-fd-passing diff --git a/TODO b/TODO index c2255ca5..ddcf6b11 100644 --- a/TODO +++ b/TODO @@ -78,6 +78,8 @@ Hey Emacs, this is -*- outline -*- mode! release everything properly at a reset and at an error. Think hard about where to guarantee what (ie, what happens if start fails, are the fds unregistered immediately - i think so?) + Note that we need support in gpgsm to set include-certs to default + as RESET does not reset it. ** Optimize the case where a data object has 0an underlying fd we can pass directly to the engine. This will be automatic with socket I/O and descriptor passing. diff --git a/assuan/assuan.h b/assuan/assuan.h index 4916d6fb..cdf0445a 100644 --- a/assuan/assuan.h +++ b/assuan/assuan.h @@ -75,6 +75,8 @@ int _gpgme_ath_accept (int s, struct sockaddr *addr, socklen_t *length_ptr); int _gpgme_ath_connect (int s, struct sockaddr *addr, socklen_t length); int _gpgme_ath_sendmsg (int s, const struct msghdr *msg, int flags); int _gpgme_ath_recvmsg (int s, struct msghdr *msg, int flags); +int _gpgme_io_sendmsg (int sock, const struct msghdr *msg, int flags); +int _gpgme_io_recvmsg (int sock, struct msghdr *msg, int flags); #endif /*!HAVE_W32_SYSTEM*/ #define read _gpgme_io_read @@ -83,8 +85,8 @@ int _gpgme_ath_recvmsg (int s, struct msghdr *msg, int flags); #define select _gpgme_ath_select #define accept _gpgme_ath_accept #define connect _gpgme_ath_connect -#define sendmsg _gpgme_ath_sendmsg -#define recvmsg _gpgme_ath_recvmsg +#define sendmsg _gpgme_io_sendmsg +#define recvmsg _gpgme_io_recvmsg #endif /*_ASSUAN_IN_GPGME_BUILD_ASSUAN*/ /**** End GPGME specific modifications. ******/ diff --git a/configure.ac b/configure.ac index c03e42f3..581e0537 100644 --- a/configure.ac +++ b/configure.ac @@ -491,7 +491,7 @@ AC_CHECK_MEMBER(struct cmsghdr.cmsg_len, AC_ARG_ENABLE(fd-passing, AC_HELP_STRING([--enable-fd-passing], [use FD passing if supported]), - use_desciptor_passing=$withval) + use_descriptor_passing=$enableval) if test "$supports_descriptor_passing" != "yes"; then use_descriptor_passing=no diff --git a/gpgme/ChangeLog b/gpgme/ChangeLog index fea3b67d..6e6749d2 100644 --- a/gpgme/ChangeLog +++ b/gpgme/ChangeLog @@ -1,5 +1,23 @@ 2006-12-17 Marcus Brinkmann + * gpgme.c (gpgme_set_protocol): Shut down the engine when + switching protocols. + (gpgme_ctx_set_engine_info): Likewise for engine info. + * engine.h (_gpgme_engine_reset): New function prototype. + * engine.c (_gpgme_engine_reset): New function. + * engine-backend.h (struct engine_ops): New member RESET. + * rungpg.c (_gpgme_engine_ops_gpg): Add NULL for reset function. + * engine-gpgsm.c (_gpgme_engine_ops_gpgsm) + [USE_DESCRIPTOR_PASSING]: Add gpgsm_reset for reset. + (_gpgme_engine_ops_gpgsm) [!USE_DESCRIPTOR_PASSING]: Add NULL for + reset function. + (gpgsm_reset) [USE_DESCRIPTOR_PASSING]: New function. + * op-support.c (_gpgme_op_reset): Try to use the engine's reset + function if available. + * engine-gpgsm.c (gpgsm_new): Move code to dup status_fd to ... + (start): ... here. + * posix-io.c (_gpgme_io_recvmsg, _gpgme_io_sendmsg): New functions. + * engine.h (_gpgme_engine_new): Remove arguments lc_ctype and lc_messages from prototype. (_gpgme_engine_set_locale): New prototype. diff --git a/gpgme/engine-backend.h b/gpgme/engine-backend.h index eed8ffd9..052e724c 100644 --- a/gpgme/engine-backend.h +++ b/gpgme/engine-backend.h @@ -49,6 +49,7 @@ struct engine_ops /* Member functions. */ void (*release) (void *engine); + gpgme_error_t (*reset) (void *engine); void (*set_status_handler) (void *engine, engine_status_handler_t fnc, void *fnc_value); gpgme_error_t (*set_command_handler) (void *engine, diff --git a/gpgme/engine-gpgsm.c b/gpgme/engine-gpgsm.c index 766323a4..23e49a67 100644 --- a/gpgme/engine-gpgsm.c +++ b/gpgme/engine-gpgsm.c @@ -334,15 +334,15 @@ gpgsm_new (void **engine, const char *file_name, const char *home_dir) char dft_ttyname[64]; char *dft_ttytype = NULL; char *optstr; - int fdlist[5]; - int nfds; gpgsm = calloc (1, sizeof *gpgsm); if (!gpgsm) return gpg_error_from_errno (errno); gpgsm->status_cb.fd = -1; + gpgsm->status_cb.dir = 1; gpgsm->status_cb.tag = 0; + gpgsm->status_cb.data = gpgsm; gpgsm->input_cb.fd = -1; gpgsm->input_cb.dir = 0; @@ -423,30 +423,6 @@ gpgsm_new (void **engine, const char *file_name, const char *home_dir) if (err) goto leave; - /* We need to know the fd used by assuan for reads. We do this by - using the assumption that the first returned fd from - assuan_get_active_fds() is always this one. */ - nfds = assuan_get_active_fds (gpgsm->assuan_ctx, 0 /* read fds */, - fdlist, DIM (fdlist)); - if (nfds < 1) - { - err = gpg_error (GPG_ERR_GENERAL); /* FIXME */ - goto leave; - } - /* We duplicate the file descriptor, so we can close it without - disturbing assuan. Alternatively, we could special case - status_fd and register/unregister it manually as needed, but this - increases code duplication and is more complicated as we can not - use the close notifications etc. */ - gpgsm->status_cb.fd = dup (fdlist[0]); - if (gpgsm->status_cb.fd < 0) - { - err = gpg_error (GPG_ERR_GENERAL); /* FIXME */ - goto leave; - } - gpgsm->status_cb.dir = 1; - gpgsm->status_cb.data = gpgsm; - err = _gpgme_getenv ("DISPLAY", &dft_display); if (err) goto leave; @@ -518,14 +494,6 @@ gpgsm_new (void **engine, const char *file_name, const char *home_dir) } } - if (!err - && (_gpgme_io_set_close_notify (gpgsm->status_cb.fd, - close_notify_handler, gpgsm))) - { - err = gpg_error (GPG_ERR_GENERAL); - goto leave; - } - #if !USE_DESCRIPTOR_PASSING if (!err && (_gpgme_io_set_close_notify (gpgsm->input_cb.fd, @@ -997,6 +965,33 @@ static gpgme_error_t start (engine_gpgsm_t gpgsm, const char *command) { gpgme_error_t err; + int fdlist[5]; + int nfds; + + /* We need to know the fd used by assuan for reads. We do this by + using the assumption that the first returned fd from + assuan_get_active_fds() is always this one. */ + nfds = assuan_get_active_fds (gpgsm->assuan_ctx, 0 /* read fds */, + fdlist, DIM (fdlist)); + if (nfds < 1) + return gpg_error (GPG_ERR_GENERAL); /* FIXME */ + + /* We duplicate the file descriptor, so we can close it without + disturbing assuan. Alternatively, we could special case + status_fd and register/unregister it manually as needed, but this + increases code duplication and is more complicated as we can not + use the close notifications etc. */ + gpgsm->status_cb.fd = dup (fdlist[0]); + if (gpgsm->status_cb.fd < 0) + return gpg_error_from_syserror (); + + if (_gpgme_io_set_close_notify (gpgsm->status_cb.fd, + close_notify_handler, gpgsm)) + { + close (gpgsm->status_cb.fd); + gpgsm->status_cb.fd = -1; + return gpg_error (GPG_ERR_GENERAL); + } err = add_io_cb (gpgsm, &gpgsm->status_cb, status_handler); if (!err && gpgsm->input_cb.fd != -1) @@ -1016,6 +1011,19 @@ start (engine_gpgsm_t gpgsm, const char *command) } +#if USE_DESCRIPTOR_PASSING +static gpgme_error_t +gpgsm_reset (void *engine) +{ + engine_gpgsm_t gpgsm = engine; + + /* We must send a reset because we need to reset the list of + signers. Note that RESET does not reset OPTION commands. */ + return gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "RESET", NULL, NULL); +} +#endif + + static gpgme_error_t gpgsm_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain) { @@ -1385,6 +1393,7 @@ gpgsm_keylist (void *engine, const char *pattern, int secret_only, if (!pattern) pattern = ""; + /* Always send list-mode option because RESET does not reset it. */ if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0) return gpg_error_from_errno (errno); err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL); @@ -1393,6 +1402,8 @@ gpgsm_keylist (void *engine, const char *pattern, int secret_only, return err; + /* Always send key validation because RESET does not reset it. */ + /* Use the validation mode if required. We don't check for an error yet because this is a pretty fresh gpgsm features. */ gpgsm_assuan_simple_command (gpgsm->assuan_ctx, @@ -1448,6 +1459,7 @@ gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only, if (mode & GPGME_KEYLIST_MODE_EXTERN) list_mode |= 2; + /* Always send list-mode option because RESET does not reset it. */ if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0) return gpg_error_from_errno (errno); err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL); @@ -1455,6 +1467,7 @@ gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only, if (err) return err; + /* Always send key validation because RESET does not reset it. */ /* Use the validation mode if required. We don't check for an error yet because this is a pretty fresh gpgsm features. */ gpgsm_assuan_simple_command (gpgsm->assuan_ctx, @@ -1561,12 +1574,8 @@ gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out, if (!gpgsm) return gpg_error (GPG_ERR_INV_VALUE); - /* We must send a reset because we need to reset the list of - signers. Note that RESET does not reset OPTION commands. */ - err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "RESET", NULL, NULL); - if (err) - return err; - + /* FIXME: This does not work as RESET does not reset it so we can't + revert back to default. */ if (include_certs != GPGME_INCLUDE_CERTS_DEFAULT) { /* FIXME: Make sure that if we run multiple operations, that we @@ -1704,6 +1713,11 @@ struct engine_ops _gpgme_engine_ops_gpgsm = /* Member functions. */ gpgsm_release, +#if USE_DESCRIPTOR_PASSING + gpgsm_reset, +#else + NULL, /* reset */ +#endif gpgsm_set_status_handler, NULL, /* set_command_handler */ gpgsm_set_colon_line_handler, diff --git a/gpgme/engine.c b/gpgme/engine.c index dd89c2d7..a64b4625 100644 --- a/gpgme/engine.c +++ b/gpgme/engine.c @@ -420,6 +420,19 @@ _gpgme_engine_new (gpgme_engine_info_t info, engine_t *r_engine) } +gpgme_error_t +_gpgme_engine_reset (engine_t engine) +{ + if (!engine) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!engine->ops->reset) + return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + + return (*engine->ops->reset) (engine->engine); +} + + void _gpgme_engine_release (engine_t engine) { diff --git a/gpgme/engine.h b/gpgme/engine.h index 893e5914..1fe24f55 100644 --- a/gpgme/engine.h +++ b/gpgme/engine.h @@ -52,6 +52,7 @@ gpgme_error_t _gpgme_set_engine_info (gpgme_engine_info_t info, gpgme_error_t _gpgme_engine_new (gpgme_engine_info_t info, engine_t *r_engine); +gpgme_error_t _gpgme_engine_reset (engine_t engine); gpgme_error_t _gpgme_engine_set_locale (engine_t engine, int category, const char *value); diff --git a/gpgme/gpgme.c b/gpgme/gpgme.c index 85f377ff..6604cb08 100644 --- a/gpgme/gpgme.c +++ b/gpgme/gpgme.c @@ -159,7 +159,17 @@ gpgme_set_protocol (gpgme_ctx_t ctx, gpgme_protocol_t protocol) if (protocol != GPGME_PROTOCOL_OpenPGP && protocol != GPGME_PROTOCOL_CMS) return gpg_error (GPG_ERR_INV_VALUE); - ctx->protocol = protocol; + if (ctx->protocol != protocol) + { + /* Shut down the engine when switching protocols. */ + if (ctx->engine) + { + _gpgme_engine_release (ctx->engine); + ctx->engine = NULL; + } + + ctx->protocol = protocol; + } return 0; } @@ -417,8 +427,12 @@ gpgme_error_t gpgme_ctx_set_engine_info (gpgme_ctx_t ctx, gpgme_protocol_t proto, const char *file_name, const char *home_dir) { - /* FIXME: Make sure to reset the context if we are running in daemon - mode. */ + /* Shut down the engine when changing engine info. */ + if (ctx->engine) + { + _gpgme_engine_release (ctx->engine); + ctx->engine = NULL; + } return _gpgme_set_engine_info (ctx->engine_info, proto, file_name, home_dir); } diff --git a/gpgme/gpgme.h b/gpgme/gpgme.h index 6251a2f7..bf69d87f 100644 --- a/gpgme/gpgme.h +++ b/gpgme/gpgme.h @@ -72,7 +72,7 @@ extern "C" { AM_PATH_GPGME macro) check that this header matches the installed library. Warning: Do not edit the next line. configure will do that for you! */ -#define GPGME_VERSION "1.1.3-cvs1188" +#define GPGME_VERSION "1.1.3-cvs1196" diff --git a/gpgme/op-support.c b/gpgme/op-support.c index 8a428512..4be7a018 100644 --- a/gpgme/op-support.c +++ b/gpgme/op-support.c @@ -68,28 +68,37 @@ gpgme_error_t _gpgme_op_reset (gpgme_ctx_t ctx, int type) { gpgme_error_t err = 0; - gpgme_engine_info_t info; struct gpgme_io_cbs io_cbs; - info = ctx->engine_info; - while (info && info->protocol != ctx->protocol) - info = info->next; - - if (!info) - return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL); - _gpgme_release_result (ctx); if (ctx->engine) { - _gpgme_engine_release (ctx->engine); - ctx->engine = NULL; + /* Attempt to reset an existing engine. */ + + err = _gpgme_engine_reset (ctx->engine); + if (gpg_err_code (err) == GPG_ERR_NOT_IMPLEMENTED) + { + _gpgme_engine_release (ctx->engine); + ctx->engine = NULL; + } } - /* Create an engine object. */ - err = _gpgme_engine_new (info, &ctx->engine); - if (err) - return err; + if (!ctx->engine) + { + gpgme_engine_info_t info; + info = ctx->engine_info; + while (info && info->protocol != ctx->protocol) + info = info->next; + + if (!info) + return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL); + + /* Create an engine object. */ + err = _gpgme_engine_new (info, &ctx->engine); + if (err) + return err; + } err = _gpgme_engine_set_locale (ctx->engine, LC_CTYPE, ctx->lc_ctype); if (!err) diff --git a/gpgme/posix-io.c b/gpgme/posix-io.c index 0e26a91e..5cb71f9b 100644 --- a/gpgme/posix-io.c +++ b/gpgme/posix-io.c @@ -412,3 +412,86 @@ _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock) } return count; } + + +int +_gpgme_io_recvmsg (int fd, struct msghdr *msg, int flags) +{ + int nread; + int saved_errno; + struct iovec *iov; + + nread = 0; + iov = msg->msg_iov; + while (iov < msg->msg_iov + msg->msg_iovlen) + { + nread += iov->iov_len; + iov++; + } + + DEBUG2 ("fd %d: about to receive %d bytes\n", + fd, (int) nread); + do + { + nread = _gpgme_ath_recvmsg (fd, msg, flags); + } + while (nread == -1 && errno == EINTR); + saved_errno = errno; + DEBUG2 ("fd %d: got %d bytes\n", fd, nread); + if (nread > 0) + { + int nr = nread; + + iov = msg->msg_iov; + while (nr > 0) + { + int len = nr > iov->iov_len ? iov->iov_len : nr; + _gpgme_debug (2, "fd %d: got `%.*s'\n", fd, len, + msg->msg_iov->iov_base); + iov++; + nr -= len; + } + } + errno = saved_errno; + return nread; +} + + +int +_gpgme_io_sendmsg (int fd, const struct msghdr *msg, int flags) +{ + int saved_errno; + int nwritten; + struct iovec *iov; + + nwritten = 0; + iov = msg->msg_iov; + while (iov < msg->msg_iov + msg->msg_iovlen) + { + nwritten += iov->iov_len; + iov++; + } + + DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int) nwritten); + iov = msg->msg_iov; + while (nwritten > 0) + { + int len = nwritten > iov->iov_len ? iov->iov_len : nwritten; + _gpgme_debug (2, "fd %d: write `%.*s'\n", fd, len, + msg->msg_iov->iov_base); + iov++; + nwritten -= len; + } + + do + { + nwritten = _gpgme_ath_sendmsg (fd, msg, flags); + } + while (nwritten == -1 && errno == EINTR); + saved_errno = errno; + DEBUG2 ("fd %d: wrote %d bytes\n", fd, (int) nwritten); + errno = saved_errno; + return nwritten; +} + + diff --git a/gpgme/rungpg.c b/gpgme/rungpg.c index f3326b30..b81aca37 100644 --- a/gpgme/rungpg.c +++ b/gpgme/rungpg.c @@ -2078,6 +2078,7 @@ struct engine_ops _gpgme_engine_ops_gpg = /* Member functions. */ gpg_release, + NULL, /* reset */ gpg_set_status_handler, gpg_set_command_handler, gpg_set_colon_line_handler,