diff --git a/agent/agent.h b/agent/agent.h index 064b7be74..fb2adde79 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -108,6 +108,14 @@ struct upon this timeout value. */ unsigned long pinentry_timeout; + /* Mode for the formatted passphrase option to use by pinentry. + Possible values are: + 0 - Option is not shown (and off). + 1 - Option is shown, off by default, and user can change it. + 2 - Option is shown, on, and user cannot change it. + 3 - Option is shown, on by default, and user can change it. */ + unsigned int pinentry_formatted_passphrase; + /* The default and maximum TTL of cache entries. */ unsigned long def_cache_ttl; /* Default. */ unsigned long def_cache_ttl_ssh; /* for SSH. */ diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c index 65ba3c23b..8e28e3bc1 100644 --- a/agent/call-pinentry.c +++ b/agent/call-pinentry.c @@ -983,6 +983,67 @@ setup_genpin (ctrl_t ctrl) } +/* Helper to setup pinentry for formatted passphrase. */ +static gpg_error_t +setup_formatted_passphrase (ctrl_t ctrl) +{ + static const struct { const char *key, *help_id, *value; } tbl[] = { + /* TRANSLATORS: This is the text of an option (usually represented + by a checkbox) as used in pinentry. */ + { "label", "pinentry.formatted_passphrase.label", + N_("Format the passphrase") }, + /* TRANSLATORS: This is the tooltip shown by pinentry when + hovering over the option for formatted passphrase. + The length is limited to about 900 characters. */ + { "tt", "pinentry.formatted_passphrase.tooltip", + N_("Enable this option to make the passphrase easier readable by " + "grouping its characters.") }, + /* TRANSLATORS: This is a text shown by pinentry if the option + for formatted passphrase is enabled. The length is + limited to about 900 characters. */ + { "hint", "pinentry.formatted_passphrase.hint", + N_("Note: The blanks are not part of the passphrase.") }, + { NULL, NULL } + }; + + gpg_error_t rc; + char line[ASSUAN_LINELENGTH]; + int idx; + char *tmpstr; + const char *s; + + (void)ctrl; + + if (opt.pinentry_formatted_passphrase) + { + snprintf (line, DIM(line), "OPTION formatted-passphrase=%d", + opt.pinentry_formatted_passphrase); + rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, + NULL); + if (rc && gpg_err_code (rc) != GPG_ERR_UNKNOWN_OPTION) + return rc; + + for (idx=0; tbl[idx].key; idx++) + { + tmpstr = gnupg_get_help_string (tbl[idx].help_id, 0); + if (tmpstr) + s = tmpstr; + else + s = L_(tbl[idx].value); + snprintf (line, DIM(line), "OPTION formatted-passphrase-%s=%s", + tbl[idx].key, s); + xfree (tmpstr); + rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, + NULL); + if (rc && gpg_err_code (rc) != GPG_ERR_UNKNOWN_OPTION) + return rc; + } + } + + return 0; +} + + /* Helper for agent_askpin and agent_get_passphrase. */ static gpg_error_t setup_qualitybar (ctrl_t ctrl) @@ -1556,6 +1617,10 @@ agent_get_passphrase (ctrl_t ctrl, return unlock_pinentry (ctrl, rc); } + rc = setup_formatted_passphrase (ctrl); + if (rc) + return unlock_pinentry (ctrl, rc); + if (!pininfo) { /* Legacy method without PININFO. */ diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index b4ffe8e8b..edc21f4d9 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -96,6 +96,7 @@ enum cmd_and_opt_values oPinentryTouchFile, oPinentryInvisibleChar, oPinentryTimeout, + oPinentryFormattedPassphrase, oDisplay, oTTYname, oTTYtype, @@ -284,6 +285,8 @@ static gpgrt_opt_t opts[] = { ARGPARSE_s_s (oPinentryInvisibleChar, "pinentry-invisible-char", "@"), ARGPARSE_s_u (oPinentryTimeout, "pinentry-timeout", N_("|N|set the Pinentry timeout to N seconds")), + ARGPARSE_s_u (oPinentryFormattedPassphrase, "pinentry-formatted-passphrase", + "@"), ARGPARSE_s_n (oAllowEmacsPinentry, "allow-emacs-pinentry", N_("allow passphrase to be prompted through Emacs")), @@ -849,6 +852,7 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread) xfree (opt.pinentry_invisible_char); opt.pinentry_invisible_char = NULL; opt.pinentry_timeout = 0; + opt.pinentry_formatted_passphrase = 0; memset (opt.daemon_program, 0, sizeof opt.daemon_program); opt.def_cache_ttl = DEFAULT_CACHE_TTL; opt.def_cache_ttl_ssh = DEFAULT_CACHE_TTL_SSH; @@ -909,6 +913,9 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread) opt.pinentry_invisible_char = xtrystrdup (pargs->r.ret_str); break; break; case oPinentryTimeout: opt.pinentry_timeout = pargs->r.ret_ulong; break; + case oPinentryFormattedPassphrase: + opt.pinentry_formatted_passphrase = pargs->r.ret_ulong; + break; case oTpm2daemonProgram: opt.daemon_program[DAEMON_TPM2D] = pargs->r.ret_str; diff --git a/doc/gpg-agent.texi b/doc/gpg-agent.texi index 41bfb09c2..e83dc6268 100644 --- a/doc/gpg-agent.texi +++ b/doc/gpg-agent.texi @@ -465,6 +465,30 @@ user input. The default value of 0 does not ask the pinentry to timeout, however a Pinentry may use its own default timeout value in this case. A Pinentry may or may not honor this request. +@item --pinentry-formatted-passphrase @var{n} +@opindex pinentry-formatted-passphrase +This option asks the Pinentry to use the mode @var{n} for passphrase +formatting when asking the user for a new passphrase. +Possible values are: +@table @code +@item 0 +Passphrase formatting is disabled. The option to change it is not shown, +so that the user cannot turn it on. This is the default. +@item 1 +Passphrase formatting is disabled. The option to change it is shown, so +that the user can turn it on. +@item 2 +Passphrase formatting is enabled. The option to change it is shown, but +disabled, so that the user cannot turn it off. +@item 3 +Passphrase formatting is enabled. The option to change it is shown, so +that the user can turn it off. +@end table + +If passphrase formatting is enabled, then all non-breaking space characters +are stripped from the entered passphrase. Passphrase formatting is mostly +useful in combination with passphrases generated with the GENPIN command. + @item --pinentry-program @var{filename} @opindex pinentry-program Use program @var{filename} as the PIN entry. The default is