diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c index 487b21e81..c2105cd6e 100644 --- a/agent/call-pinentry.c +++ b/agent/call-pinentry.c @@ -1391,6 +1391,9 @@ agent_get_confirmation (ctrl_t ctrl, if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL) return gpg_error (GPG_ERR_CANCELED); + if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK) + return pinentry_loopback_confirm (ctrl, desc, 1, ok, notok); + return gpg_error (GPG_ERR_NO_PIN_ENTRY); } @@ -1486,7 +1489,15 @@ agent_popup_message_start (ctrl_t ctrl, const char *desc, const char *ok_btn) int err; if (ctrl->pinentry_mode != PINENTRY_MODE_ASK) - return gpg_error (GPG_ERR_CANCELED); + { + if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL) + return gpg_error (GPG_ERR_CANCELED); + + if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK) + return pinentry_loopback_confirm (ctrl, desc, 0, ok_btn, NULL); + + return gpg_error (GPG_ERR_NO_PIN_ENTRY); + } rc = start_pinentry (ctrl); if (rc) @@ -1537,6 +1548,9 @@ agent_popup_message_stop (ctrl_t ctrl) (void)ctrl; + if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK) + return; + if (!popup_tid || !entry_ctx) { log_debug ("agent_popup_message_stop called with no active popup\n"); diff --git a/agent/command.c b/agent/command.c index 3c2da183c..b59532ce5 100644 --- a/agent/command.c +++ b/agent/command.c @@ -3680,3 +3680,26 @@ pinentry_loopback(ctrl_t ctrl, const char *keyword, assuan_end_confidential (ctx); return rc; } + +/* Helper for the pinentry loopback mode to ask confirmation + or just to show message. */ +gpg_error_t +pinentry_loopback_confirm (ctrl_t ctrl, const char *desc, + int ask_confirmation, + const char *ok, const char *notok) +{ + gpg_error_t err = 0; + assuan_context_t ctx = ctrl->server_local->assuan_ctx; + + if (desc) + err = print_assuan_status (ctx, "SETDESC", "%s", desc); + if (!err && ok) + err = print_assuan_status (ctx, "SETOK", "%s", ok); + if (!err && notok) + err = print_assuan_status (ctx, "SETNOTOK", "%s", notok); + + if (!err) + err = assuan_inquire (ctx, ask_confirmation ? "CONFIRM 1" : "CONFIRM 0", + NULL, NULL, 0); + return err; +} diff --git a/g10/call-agent.c b/g10/call-agent.c index f6c7d3951..19deb73d7 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -41,6 +41,7 @@ #include "../common/status.h" #include "../common/shareddefs.h" #include "../common/host2net.h" +#include "../common/ttyio.h" #define CONTROL_D ('D' - 'A' + 1) @@ -48,6 +49,13 @@ static assuan_context_t agent_ctx = NULL; static int did_early_card_test; +struct confirm_parm_s +{ + char *desc; + char *ok; + char *notok; +}; + struct default_inq_parm_s { ctrl_t ctrl; @@ -57,6 +65,7 @@ struct default_inq_parm_s u32 *mainkeyid; int pubkey_algo; } keyinfo; + struct confirm_parm_s *confirm; }; struct cipher_parm_s @@ -136,6 +145,7 @@ default_inq_cb (void *opaque, const char *line) { gpg_error_t err = 0; struct default_inq_parm_s *parm = opaque; + const char *s; if (has_leading_keyword (line, "PINENTRY_LAUNCHED")) { @@ -151,7 +161,7 @@ default_inq_cb (void *opaque, const char *line) { if (have_static_passphrase ()) { - const char *s = get_static_passphrase (); + s = get_static_passphrase (); err = assuan_send_data (parm->ctx, s, strlen (s)); } else @@ -176,6 +186,27 @@ default_inq_cb (void *opaque, const char *line) xfree (pw); } } + else if ((s = has_leading_keyword (line, "CONFIRM")) + && opt.pinentry_mode == PINENTRY_MODE_LOOPBACK + && parm->confirm) + { + int ask = atoi (s); + int yes; + + if (ask) + { + yes = cpr_get_answer_is_yes (NULL, parm->confirm->desc); + if (yes) + err = assuan_send_data (parm->ctx, NULL, 0); + else + err = gpg_error (GPG_ERR_NOT_CONFIRMED); + } + else + { + tty_printf ("%s", parm->confirm->desc); + err = assuan_send_data (parm->ctx, NULL, 0); + } + } else log_debug ("ignoring gpg-agent inquiry '%s'\n", line); @@ -2512,6 +2543,31 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc, } +/* Status callback for handling confirmation. */ +static gpg_error_t +confirm_status_cb (void *opaque, const char *line) +{ + struct confirm_parm_s *parm = opaque; + const char *s; + + if ((s = has_leading_keyword (line, "SETDESC"))) + { + xfree (parm->desc); + parm->desc = unescape_status_string (s); + } + else if ((s = has_leading_keyword (line, "SETOK"))) + { + xfree (parm->ok); + parm->ok = unescape_status_string (s); + } + else if ((s = has_leading_keyword (line, "SETNOTOK"))) + { + xfree (parm->notok); + parm->notok = unescape_status_string (s); + } + + return 0; +} /* Ask the agent to delete the key identified by HEXKEYGRIP. If DESC is not NULL, display DESC instead of the default description @@ -2524,9 +2580,12 @@ agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc, gpg_error_t err; char line[ASSUAN_LINELENGTH]; struct default_inq_parm_s dfltparm; + struct confirm_parm_s confirm_parm; + memset (&confirm_parm, 0, sizeof confirm_parm); memset (&dfltparm, 0, sizeof dfltparm); dfltparm.ctrl = ctrl; + dfltparm.confirm = &confirm_parm; err = start_agent (ctrl, 0); if (err) @@ -2548,7 +2607,10 @@ agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc, force? " --force":"", hexkeygrip); err = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, &dfltparm, - NULL, NULL); + confirm_status_cb, &confirm_parm); + xfree (confirm_parm.desc); + xfree (confirm_parm.ok); + xfree (confirm_parm.notok); return err; }