diff --git a/TODO b/TODO index fe10e9f77..74763a71f 100644 --- a/TODO +++ b/TODO @@ -96,11 +96,3 @@ might want to have an agent context for each service request -* IMPORTANT: - Check that the PIN cache is cleared after failed card operations. - After receiving a HUP gpg-agent should set a flag to kill scdaemon - as soon as possible, w/o that scdaemon will continue running as a - zombie and gpg-agent won't be able to fire up a new one. - Implement an scd/agent option to wait for a card. - - diff --git a/agent/ChangeLog b/agent/ChangeLog index 6c271c8e2..dcf0cdfd3 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,12 @@ +2005-05-24 Werner Koch + + * call-scd.c (inq_needpin): Skip leading spaces in of PIN + description. + * divert-scd.c (getpin_cb): Enhanced to cope with description + flags. + * query.c (agent_askpin): Add arg PROMPT_TEXT. Changed all + callers. + 2005-05-21 Werner Koch * call-scd.c (start_scd): Don't test for an alive scdaemon here. diff --git a/agent/agent.h b/agent/agent.h index 7e4f555e8..e416914cf 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -179,7 +179,8 @@ int agent_key_available (const unsigned char *grip); /*-- query.c --*/ void initialize_module_query (void); int agent_askpin (ctrl_t ctrl, - const char *desc_text, const char *inital_errtext, + const char *desc_text, const char *prompt_text, + const char *inital_errtext, struct pin_entry_info_s *pininfo); int agent_get_passphrase (ctrl_t ctrl, char **retpass, const char *desc, const char *prompt, diff --git a/agent/call-scd.c b/agent/call-scd.c index 617ef0d48..78e28fe97 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -601,6 +601,8 @@ inq_needpin (void *opaque, const char *line) return ASSUAN_Inquire_Unknown; } line += 7; + while (*line == ' ') + line++; pinlen = 90; pin = gcry_malloc_secure (pinlen); diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 92a84c662..030cc70a0 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -2369,7 +2369,7 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl) } pi->max_length = 100; pi->max_tries = 1; - err = agent_askpin (ctrl, description, NULL, pi); + err = agent_askpin (ctrl, description, NULL, NULL, pi); if (err) goto out; diff --git a/agent/divert-scd.c b/agent/divert-scd.c index f460ffe0c..41a5dfcda 100644 --- a/agent/divert-scd.c +++ b/agent/divert-scd.c @@ -168,35 +168,113 @@ encode_md_for_card (const unsigned char *digest, size_t digestlen, int algo, buf has been allocated by the caller and is of size MAXBUF which includes the terminating null. The function should return an UTF-8 string with the passphrase, the buffer may optionally be padded - with arbitrary characters */ + with arbitrary characters. + + INFO gets displayed as part of a generic string. However if the + first character of INFO is a vertical bar all up to the next + verical bar are considered flags and only everything after the + second vertical bar gets displayed as the full prompt. + + Flags: + + 'N' = New PIN, this requests a second prompt to repeat the the + PIN. If the PIN is not correctly repeated it starts from + all over. + 'A' = The PIN is an Admin PIN, SO-PIN, PUK or alike. + + Example: + + "|AN|Please enter the new security officer's PIN" + + The text "Please ..." will get displayed and the flags 'A' and 'N' + are considered. + */ static int getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf) { struct pin_entry_info_s *pi; int rc; - char *desc; - CTRL ctrl = opaque; + ctrl_t ctrl = opaque; + const char *ends, *s; + int any_flags = 0; + int newpin = 0; + const char *again_text = NULL; + const char *prompt = "PIN"; if (maxbuf < 2) return gpg_error (GPG_ERR_INV_VALUE); + /* Parse the flags. */ + if (info && *info =='|' && (ends=strchr (info+1, '|'))) + { + for (s=info+1; s < ends; s++) + { + if (*s == 'A') + prompt = _("Admin PIN"); + else if (*s == 'N') + newpin = 1; + } + info = ends+1; + any_flags = 1; + } + else if (info && *info == '|') + log_debug ("pin_cb called without proper PIN info hack\n"); + /* FIXME: keep PI and TRIES in OPAQUE. Frankly this is a whole mess because we should call the card's verify function from the pinentry check pin CB. */ - pi = gcry_calloc_secure (1, sizeof (*pi) + 100); + again: + pi = gcry_calloc_secure (1, sizeof (*pi) + maxbuf + 10); + if (!pi) + return gpg_error_from_errno (errno); pi->max_length = maxbuf-1; pi->min_digits = 0; /* we want a real passphrase */ pi->max_digits = 8; pi->max_tries = 3; - if ( asprintf (&desc, _("Please enter the PIN%s%s%s to unlock the card"), - info? " (`":"", - info? info:"", - info? "')":"") < 0) - desc = NULL; - rc = agent_askpin (ctrl, desc?desc:info, NULL, pi); - free (desc); + if (any_flags) + { + rc = agent_askpin (ctrl, info, prompt, again_text, pi); + again_text = NULL; + if (!rc && newpin) + { + struct pin_entry_info_s *pi2; + pi2 = gcry_calloc_secure (1, sizeof (*pi) + maxbuf + 10); + if (!pi2) + { + rc = gpg_error_from_errno (errno); + xfree (pi); + return rc; + } + pi2->max_length = maxbuf-1; + pi2->min_digits = 0; + pi2->max_digits = 8; + pi2->max_tries = 1; + rc = agent_askpin (ctrl, _("Repeat this PIN"), prompt, NULL, pi2); + if (!rc && strcmp (pi->pin, pi2->pin)) + { + again_text = N_("PIN not correctly repeated; try again"); + xfree (pi2); + xfree (pi); + goto again; + } + xfree (pi2); + } + } + else + { + char *desc; + if ( asprintf (&desc, + _("Please enter the PIN%s%s%s to unlock the card"), + info? " (`":"", + info? info:"", + info? "')":"") < 0) + desc = NULL; + rc = agent_askpin (ctrl, desc?desc:info, prompt, NULL, pi); + free (desc); + } + if (!rc) { strncpy (buf, pi->pin, maxbuf-1); diff --git a/agent/findkey.c b/agent/findkey.c index 0b5816bf5..999a5d620 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -276,7 +276,7 @@ unprotect (CTRL ctrl, const char *desc_text, arg.unprotected_key = NULL; pi->check_cb_arg = &arg; - rc = agent_askpin (ctrl, desc_text, NULL, pi); + rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi); if (!rc) { assert (arg.unprotected_key); diff --git a/agent/genkey.c b/agent/genkey.c index 17d85f77c..e07518d5a 100644 --- a/agent/genkey.c +++ b/agent/genkey.c @@ -120,11 +120,11 @@ agent_genkey (CTRL ctrl, const char *keyparam, size_t keyparamlen, pi2->check_cb_arg = pi->pin; next_try: - rc = agent_askpin (ctrl, text1, initial_errtext, pi); + rc = agent_askpin (ctrl, text1, NULL, initial_errtext, pi); initial_errtext = NULL; if (!rc) { - rc = agent_askpin (ctrl, text2, NULL, pi2); + rc = agent_askpin (ctrl, text2, NULL, NULL, pi2); if (rc == -1) { /* The re-entered one did not match and the user did not hit cancel. */ @@ -228,10 +228,10 @@ agent_protect_and_store (CTRL ctrl, gcry_sexp_t s_skey) pi2->check_cb_arg = pi->pin; next_try: - rc = agent_askpin (ctrl, text1, initial_errtext, pi); + rc = agent_askpin (ctrl, text1, NULL, initial_errtext, pi); if (!rc) { - rc = agent_askpin (ctrl, text2, NULL, pi2); + rc = agent_askpin (ctrl, text2, NULL, NULL, pi2); if (rc == -1) { /* The re-entered one did not match and the user did not hit cancel. */ diff --git a/agent/query.c b/agent/query.c index 622a2662c..d3b42a416 100644 --- a/agent/query.c +++ b/agent/query.c @@ -288,8 +288,9 @@ all_digitsp( const char *s) number here and repeat it as long as we have invalid formed numbers. */ int -agent_askpin (CTRL ctrl, - const char *desc_text, const char *initial_errtext, +agent_askpin (ctrl_t ctrl, + const char *desc_text, const char *prompt_text, + const char *initial_errtext, struct pin_entry_info_s *pininfo) { int rc; @@ -310,7 +311,10 @@ agent_askpin (CTRL ctrl, desc_text = _("Please enter your passphrase, so that the secret key " "can be unlocked for this session"); - is_pin = desc_text && strstr (desc_text, "PIN"); + if (prompt_text) + is_pin = !!strstr (prompt_text, "PIN"); + else + is_pin = desc_text && strstr (desc_text, "PIN"); rc = start_pinentry (ctrl); if (rc) @@ -322,10 +326,10 @@ agent_askpin (CTRL ctrl, if (rc) return unlock_pinentry (map_assuan_err (rc)); - rc = assuan_transact (entry_ctx, - is_pin? "SETPROMPT PIN:" - : "SETPROMPT Passphrase:", - NULL, NULL, NULL, NULL, NULL, NULL); + snprintf (line, DIM(line)-1, "SETPROMPT %s", + prompt_text? prompt_text : is_pin? "PIN:" : "Passphrase:"); + line[DIM(line)-1] = 0; + rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL); if (rc) return unlock_pinentry (map_assuan_err (rc)); diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 91e208a0a..14483869b 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1528,7 +1528,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode, /* Check whether a key already exists. KEYIDX is the index of the key - (0..2). If FORCE is TRUE a diagnositivc will be printed but no + (0..2). If FORCE is TRUE a diagnositic will be printed but no error returned if the key already exists. */ static gpg_error_t does_key_exist (app_t app, int keyidx, int force) @@ -2134,7 +2134,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, { char *prompt; -#define PROMPTSTRING _("PIN [sigs done: %lu]") +#define PROMPTSTRING _("||Please enter the PIN%%0A[sigs done: %lu]") prompt = malloc (strlen (PROMPTSTRING) + 50); if (!prompt)