diff --git a/NEWS b/NEWS index f5d7ce06..38f38d6d 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,12 @@ Noteworthy changes in version 1.7.2 (unreleased) ------------------------------------------------ + * Interface changes relative to the 1.7.1 release: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + gpgme_set_sender NEW. + gpgme_get_sender NEW. + + Noteworthy changes in version 1.7.1 (2016-10-18) ------------------------------------------------ diff --git a/doc/gpgme.texi b/doc/gpgme.texi index cc598887..9fae9aaf 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -186,6 +186,7 @@ Context Attributes * Protocol Selection:: Selecting the protocol used by a context. * Crypto Engine:: Configuring the crypto engine. +* Setting the Sender:: How to tell the engine the sender. * ASCII Armor:: Requesting @acronym{ASCII} armored output. * Text Mode:: Choosing canonical text mode. * Offline Mode:: Choosing offline mode. @@ -2366,6 +2367,7 @@ started. In fact, these references are accessed through the @menu * Protocol Selection:: Selecting the protocol used by a context. * Crypto Engine:: Configuring the crypto engine. +* Setting the Sender:: How to tell the engine the sender. * ASCII Armor:: Requesting @acronym{ASCII} armored output. * Text Mode:: Choosing canonical text mode. * Offline Mode:: Choosing offline mode. @@ -2448,6 +2450,47 @@ successful, or an eror code on failure. @end deftypefun +@node Setting the Sender +@subsection How to tell the engine the sender. +@cindex context, sender +@cindex sender +@cindex From: + +Some engines can make use of the sender’s address, for example to +figure out the best user id in certain trust models. For verification +and signing of mails, it is thus suggested to let the engine know the +sender ("From:") address. @acronym{GPGME} provides two functions to +accomplish that. Note that the esoteric use of multiple "From:" +addresses is not supported. + +@deftypefun gpgme_error_t gpgme_set_sender @ + (@w{gpgme_ctx_t @var{ctx}}, @ + @w{int @var{address}}) + +The function @code{gpgme_set_sender} specifies the sender address for +use in sign and verify operations. @var{address} is expected to be +the ``addr-spec'' part of an address but my also be a complete mailbox +address, in which case this function extracts the ``addr-spec'' from +it. Using @code{NULL} for @var{address} clears the sender address. + +The function returns 0 on success or an error code on failure. The +most likely failure is that no valid ``addr-spec'' was found in +@var{address}. + +@end deftypefun + +@deftypefun @w{const char *} gpgme_get_sender @ + (@w{gpgme_ctx_t @var{ctx}}) + +The function @code{gpgme_get_sender} returns the current sender +address from the context, or NULL if none was set. The returned +value is valid as long as the @var{ctx} is valid and +@code{gpgme_set_sender} has not been called again. + +@end deftypefun + + + @c FIXME: Unfortunately, using @acronym here breaks texi2dvi. @node ASCII Armor @subsection @acronym{ASCII} Armor diff --git a/src/context.h b/src/context.h index 4b12c3bd..f6c1ad1e 100644 --- a/src/context.h +++ b/src/context.h @@ -119,16 +119,18 @@ struct gpgme_context /* Number of certs to be included. */ unsigned int include_certs; - /* The number of keys in signers. */ + /* The actual number of keys in SIGNERS, the allocated size of the + * array, and the array with the signing keys. */ unsigned int signers_len; - - /* Size of the following array. */ unsigned int signers_size; gpgme_key_t *signers; /* The signature notations for this context. */ gpgme_sig_notation_t sig_notations; + /* The sender's addr-spec or NULL. */ + char *sender; + /* The locale for the pinentry. */ char *lc_ctype; char *lc_messages; diff --git a/src/engine-backend.h b/src/engine-backend.h index ccab0e3e..e02c7157 100644 --- a/src/engine-backend.h +++ b/src/engine-backend.h @@ -111,7 +111,8 @@ struct engine_ops gpgme_ctx_t ctx /* FIXME */); gpgme_error_t (*trustlist) (void *engine, const char *pattern); gpgme_error_t (*verify) (void *engine, gpgme_data_t sig, - gpgme_data_t signed_text, gpgme_data_t plaintext); + gpgme_data_t signed_text, gpgme_data_t plaintext, + gpgme_ctx_t ctx); gpgme_error_t (*getauditlog) (void *engine, gpgme_data_t output, unsigned int flags); gpgme_error_t (*opassuan_transact) (void *engine, diff --git a/src/engine-gpg.c b/src/engine-gpg.c index 4415c946..cb52dea7 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -1645,6 +1645,23 @@ append_args_from_signers (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */) } +static gpgme_error_t +append_args_from_sender (engine_gpg_t gpg, gpgme_ctx_t ctx) +{ + gpgme_error_t err; + + if (ctx->sender && have_gpg_version (gpg, "2.1.15")) + { + err = add_arg (gpg, "--sender"); + if (!err) + err = add_arg (gpg, ctx->sender); + } + else + err = 0; + return err; +} + + static gpgme_error_t append_args_from_sig_notations (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */) { @@ -1892,6 +1909,9 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[], if (!err) err = append_args_from_signers (gpg, ctx); + if (!err) + err = append_args_from_sender (gpg, ctx); + if (!err) err = append_args_from_sig_notations (gpg, ctx); @@ -2793,6 +2813,8 @@ gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out, if (!err) err = append_args_from_signers (gpg, ctx); + if (!err) + err = append_args_from_sender (gpg, ctx); if (!err) err = append_args_from_sig_notations (gpg, ctx); @@ -2845,12 +2867,15 @@ gpg_trustlist (void *engine, const char *pattern) static gpgme_error_t gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text, - gpgme_data_t plaintext) + gpgme_data_t plaintext, gpgme_ctx_t ctx) { engine_gpg_t gpg = engine; - gpgme_error_t err = 0; + gpgme_error_t err; - if (plaintext) + err = append_args_from_sender (gpg, ctx); + if (err) + ; + else if (plaintext) { /* Normal or cleartext signature. */ err = add_arg (gpg, "--output"); diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index e7e2a20d..0ce4a6d1 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -1901,11 +1901,13 @@ gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out, static gpgme_error_t gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text, - gpgme_data_t plaintext) + gpgme_data_t plaintext, gpgme_ctx_t ctx) { engine_gpgsm_t gpgsm = engine; gpgme_error_t err; + (void)ctx; + if (!gpgsm) return gpg_error (GPG_ERR_INV_VALUE); diff --git a/src/engine-uiserver.c b/src/engine-uiserver.c index 63e77de6..76fa4d79 100644 --- a/src/engine-uiserver.c +++ b/src/engine-uiserver.c @@ -1243,13 +1243,16 @@ uiserver_sign (void *engine, gpgme_data_t in, gpgme_data_t out, /* FIXME: Missing a way to specify --silent. */ static gpgme_error_t uiserver_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text, - gpgme_data_t plaintext) + gpgme_data_t plaintext, gpgme_ctx_t ctx) { engine_uiserver_t uiserver = engine; gpgme_error_t err; const char *protocol; char *cmd; + (void)ctx; /* FIXME: We should to add a --sender option to the + * UISever protocol. */ + if (!uiserver) return gpg_error (GPG_ERR_INV_VALUE); if (uiserver->protocol == GPGME_PROTOCOL_DEFAULT) @@ -1395,6 +1398,6 @@ struct engine_ops _gpgme_engine_ops_uiserver = uiserver_cancel, NULL, /* cancel_op */ NULL, /* passwd */ - NULL, /* set_pinentry_mode */ + NULL, /* set_pinentry_mode */ NULL /* opspawn */ }; diff --git a/src/engine.c b/src/engine.c index a1173a07..f5dfe51f 100644 --- a/src/engine.c +++ b/src/engine.c @@ -902,7 +902,8 @@ _gpgme_engine_op_trustlist (engine_t engine, const char *pattern) gpgme_error_t _gpgme_engine_op_verify (engine_t engine, gpgme_data_t sig, - gpgme_data_t signed_text, gpgme_data_t plaintext) + gpgme_data_t signed_text, gpgme_data_t plaintext, + gpgme_ctx_t ctx) { if (!engine) return gpg_error (GPG_ERR_INV_VALUE); @@ -910,7 +911,8 @@ _gpgme_engine_op_verify (engine_t engine, gpgme_data_t sig, if (!engine->ops->verify) return gpg_error (GPG_ERR_NOT_IMPLEMENTED); - return (*engine->ops->verify) (engine->engine, sig, signed_text, plaintext); + return (*engine->ops->verify) (engine->engine, sig, signed_text, plaintext, + ctx); } diff --git a/src/engine.h b/src/engine.h index 4ce2bed1..2999ab64 100644 --- a/src/engine.h +++ b/src/engine.h @@ -152,7 +152,8 @@ gpgme_error_t _gpgme_engine_op_trustlist (engine_t engine, const char *pattern); gpgme_error_t _gpgme_engine_op_verify (engine_t engine, gpgme_data_t sig, gpgme_data_t signed_text, - gpgme_data_t plaintext); + gpgme_data_t plaintext, + gpgme_ctx_t ctx); gpgme_error_t _gpgme_engine_op_getauditlog (engine_t engine, gpgme_data_t output, diff --git a/src/gpgme.c b/src/gpgme.c index d59f8080..6d0dbffa 100644 --- a/src/gpgme.c +++ b/src/gpgme.c @@ -38,6 +38,7 @@ #include "debug.h" #include "priv-io.h" #include "sys-util.h" +#include "mbox-util.h" /* The default locale. */ @@ -275,12 +276,10 @@ gpgme_release (gpgme_ctx_t ctx) _gpgme_release_result (ctx); _gpgme_signers_clear (ctx); _gpgme_sig_notation_clear (ctx); - if (ctx->signers) - free (ctx->signers); - if (ctx->lc_ctype) - free (ctx->lc_ctype); - if (ctx->lc_messages) - free (ctx->lc_messages); + free (ctx->sender); + free (ctx->signers); + free (ctx->lc_ctype); + free (ctx->lc_messages); _gpgme_engine_info_release (ctx->engine_info); ctx->engine_info = NULL; DESTROY_LOCK (ctx->lock); @@ -459,6 +458,42 @@ gpgme_get_protocol_name (gpgme_protocol_t protocol) } } + +/* Store the sender's address in the context. ADDRESS is addr-spec of + * mailbox but my also be a complete mailbox, in which case this + * function extracts the addr-spec from it. Returns 0 on success or + * an error code if no valid addr-spec could be extracted from + * ADDRESS. */ +gpgme_error_t +gpgme_set_sender (gpgme_ctx_t ctx, const char *address) +{ + char *p = NULL; + + TRACE_BEG1 (DEBUG_CTX, "gpgme_set_sender", ctx, "sender='%s'", + address?address:"(null)"); + + if (!ctx || (address && !(p = _gpgme_mailbox_from_userid (address)))) + return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE)); + + free (ctx->sender); + ctx->sender = p; + return TRACE_ERR (0); +} + + +/* Return the sender's address (addr-spec part) from the context or + * NULL if none was set. The returned value is valid as long as the + * CTX is valid and gpgme_set_sender has not been used. */ +const char * +gpgme_get_sender (gpgme_ctx_t ctx) +{ + TRACE1 (DEBUG_CTX, "gpgme_get_sender", ctx, "sender='%s'", + ctx?ctx->sender:""); + + return ctx->sender; +} + + /* Enable or disable the use of an ascii armor for all output. */ void gpgme_set_armor (gpgme_ctx_t ctx, int use_armor) diff --git a/src/gpgme.def b/src/gpgme.def index c94c9607..d633df57 100644 --- a/src/gpgme.def +++ b/src/gpgme.def @@ -246,5 +246,8 @@ EXPORTS gpgme_addrspec_from_uid @186 + gpgme_set_sender @187 + gpgme_get_sender @188 + ; END diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 5c914ae7..94ef51de 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -1161,6 +1161,12 @@ gpgme_error_t gpgme_sig_notation_add (gpgme_ctx_t ctx, const char *name, /* Get the sig notations for this context. */ gpgme_sig_notation_t gpgme_sig_notation_get (gpgme_ctx_t ctx); +/* Store a sender address in the context. */ +gpgme_error_t gpgme_set_sender (gpgme_ctx_t ctx, const char *address); + +/* Get the sender address from the context. */ +const char *gpgme_get_sender (gpgme_ctx_t ctx); + /* diff --git a/src/libgpgme.vers b/src/libgpgme.vers index d3962db0..42f00d5a 100644 --- a/src/libgpgme.vers +++ b/src/libgpgme.vers @@ -119,6 +119,9 @@ GPGME_1.1 { gpgme_op_interact; gpgme_addrspec_from_uid; + + gpgme_set_sender; + gpgme_get_sender; }; diff --git a/src/verify.c b/src/verify.c index eb1cc108..faa8deb9 100644 --- a/src/verify.c +++ b/src/verify.c @@ -1104,7 +1104,8 @@ verify_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t sig, if (!sig) return gpg_error (GPG_ERR_NO_DATA); - return _gpgme_engine_op_verify (ctx->engine, sig, signed_text, plaintext); + return _gpgme_engine_op_verify (ctx->engine, sig, signed_text, plaintext, + ctx); } diff --git a/tests/gpg/t-verify.c b/tests/gpg/t-verify.c index 9842d3af..f955cc9d 100644 --- a/tests/gpg/t-verify.c +++ b/tests/gpg/t-verify.c @@ -209,6 +209,7 @@ main (int argc, char *argv[]) gpgme_error_t err; gpgme_data_t sig, text; gpgme_verify_result_t result; + const char *s; (void)argc; (void)argv; @@ -270,6 +271,54 @@ main (int argc, char *argv[]) exit (1); } + /* Checking that set/get_sernder works. */ + err = gpgme_set_sender (ctx, "foo@example.org"); + fail_if_err (err); + s = gpgme_get_sender (ctx); + if (!s || strcmp (s, "foo@example.org")) + { + fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n", + __FILE__, __LINE__); + exit (1); + } + + err = gpgme_set_sender (ctx, ""); + fail_if_err (err); + s = gpgme_get_sender (ctx); + if (!s || strcmp (s, "bar@example.org")) + { + fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n", + __FILE__, __LINE__); + exit (1); + } + + err = gpgme_set_sender (ctx, "Foo bar (comment) "); + fail_if_err (err); + s = gpgme_get_sender (ctx); + if (!s || strcmp (s, "foo@example.org")) + { + fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n", + __FILE__, __LINE__); + exit (1); + } + + err = gpgme_set_sender (ctx, "foo"); + if (gpgme_err_code (err) != GPG_ERR_INV_VALUE) + { + fprintf (stderr, "%s:%i: gpgme_set_sender didn't detect bogus address\n", + __FILE__, __LINE__); + exit (1); + } + /* (the former address should still be there.) */ + s = gpgme_get_sender (ctx); + if (!s || strcmp (s, "foo@example.org")) + { + fprintf (stderr, "%s:%i: gpgme_{set,get}_sender mismatch\n", + __FILE__, __LINE__); + exit (1); + } + + gpgme_data_release (sig); gpgme_data_release (text); gpgme_release (ctx); diff --git a/tests/run-sign.c b/tests/run-sign.c index 70853ed6..f790cb64 100644 --- a/tests/run-sign.c +++ b/tests/run-sign.c @@ -83,6 +83,7 @@ show_usage (int ex) " --uiserver use the UI server\n" " --loopback use a loopback pinentry\n" " --key NAME use key NAME for signing\n" + " --sender MBOX use MBOX as sender address\n" , stderr); exit (ex); } @@ -101,6 +102,7 @@ main (int argc, char **argv) gpgme_sign_result_t result; int print_status = 0; int use_loopback = 0; + const char *sender = NULL; if (argc) { argc--; argv++; } @@ -148,6 +150,14 @@ main (int argc, char **argv) key_string = *argv; argc--; argv++; } + else if (!strcmp (*argv, "--sender")) + { + argc--; argv++; + if (!argc) + show_usage (1); + sender = *argv; + argc--; argv++; + } else if (!strcmp (*argv, "--loopback")) { use_loopback = 1; @@ -192,6 +202,12 @@ main (int argc, char **argv) gpgme_key_unref (akey); } + if (sender) + { + err = gpgme_set_sender (ctx, sender); + fail_if_err (err); + } + err = gpgme_data_new_from_file (&in, *argv, 1); if (err) { diff --git a/tests/run-verify.c b/tests/run-verify.c index ebc20d97..22242c00 100644 --- a/tests/run-verify.c +++ b/tests/run-verify.c @@ -221,6 +221,7 @@ show_usage (int ex) " --status print status lines from the backend\n" " --openpgp use the OpenPGP protocol (default)\n" " --cms use the CMS protocol\n" + " --sender MBOX use MBOX as sender address\n" , stderr); exit (ex); } @@ -239,6 +240,7 @@ main (int argc, char **argv) gpgme_data_t msg = NULL; gpgme_verify_result_t result; int print_status = 0; + const char *sender = NULL; if (argc) { argc--; argv++; } @@ -273,6 +275,14 @@ main (int argc, char **argv) protocol = GPGME_PROTOCOL_CMS; argc--; argv++; } + else if (!strcmp (*argv, "--sender")) + { + argc--; argv++; + if (!argc) + show_usage (1); + sender = *argv; + argc--; argv++; + } else if (!strncmp (*argv, "--", 2)) show_usage (1); @@ -313,6 +323,12 @@ main (int argc, char **argv) } /* gpgme_set_ctx_flag (ctx, "raw-description", "1"); */ + if (sender) + { + err = gpgme_set_sender (ctx, sender); + fail_if_err (err); + } + err = gpgme_data_new_from_stream (&sig, fp_sig); if (err) {