From 4467fa4d2a6f5d5a2d75a37153e5cef1004c8035 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Mon, 14 May 2018 08:08:34 +0100 Subject: [PATCH] Unix Pageant: option to behave like ssh-askpass. Since Pageant contains its own passphrase prompt system rather than delegating it to another process, it's not trivial to use it in other contexts. But having gone to the effort of coming up with my own askpass system that (I think) does a better job at not revealing the length of the password, I _want_ to use it in other contexts where a GUI passphrase or password prompt is needed. Solution: an --askpass option. --- unix/uxpgnt.c | 69 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/unix/uxpgnt.c b/unix/uxpgnt.c index 1f482efa..63605fb6 100644 --- a/unix/uxpgnt.c +++ b/unix/uxpgnt.c @@ -129,6 +129,7 @@ static void usage(void) printf(" -s -c force POSIX or C shell syntax (in agent mode)\n"); printf(" --tty-prompt force tty-based passphrase prompt (in -a mode)\n"); printf(" --gui-prompt force GUI-based passphrase prompt (in -a mode)\n"); + printf(" --askpass behave like a standalone askpass program\n"); exit(1); } @@ -343,15 +344,13 @@ enum { PROMPT_UNSPEC, PROMPT_TTY, PROMPT_GUI } prompt_type = PROMPT_UNSPEC; -static char *askpass_tty(const char *comment) +static char *askpass_tty(const char *prompt) { int ret; prompts_t *p = new_prompts(NULL); p->to_server = FALSE; p->name = dupstr("Pageant passphrase prompt"); - add_prompt(p, - dupprintf("Enter passphrase to load key '%s': ", comment), - FALSE); + add_prompt(p, dupcat(prompt, ": ", (const char *)NULL), FALSE); ret = console_get_userpass_input(p, NULL, 0); assert(ret >= 0); @@ -366,20 +365,17 @@ static char *askpass_tty(const char *comment) } } -static char *askpass_gui(const char *comment) +static char *askpass_gui(const char *prompt) { - char *prompt, *passphrase; + char *passphrase; int success; /* in gtkask.c */ char *gtk_askpass_main(const char *display, const char *wintitle, const char *prompt, int *success); - prompt = dupprintf("Enter passphrase to load key '%s': ", comment); - passphrase = gtk_askpass_main(display, - "Pageant passphrase prompt", - prompt, &success); - sfree(prompt); + passphrase = gtk_askpass_main( + display, "Pageant passphrase prompt", prompt, &success); if (!success) { /* return value is error message */ fprintf(stderr, "%s\n", passphrase); @@ -389,7 +385,7 @@ static char *askpass_gui(const char *comment) return passphrase; } -static char *askpass(const char *comment) +static char *askpass(const char *prompt) { if (prompt_type == PROMPT_TTY) { if (!have_controlling_tty()) { @@ -397,7 +393,7 @@ static char *askpass(const char *comment) "for passphrase prompt\n"); return NULL; } - return askpass_tty(comment); + return askpass_tty(prompt); } if (prompt_type == PROMPT_GUI) { @@ -406,13 +402,13 @@ static char *askpass(const char *comment) "for passphrase prompt\n"); return NULL; } - return askpass_gui(comment); + return askpass_gui(prompt); } if (have_controlling_tty()) { - return askpass_tty(comment); + return askpass_tty(prompt); } else if (display) { - return askpass_gui(comment); + return askpass_gui(prompt); } else { fprintf(stderr, "no way to read a passphrase without tty or " "X display\n"); @@ -444,8 +440,11 @@ static int unix_add_keyfile(const char *filename_str) * And now try prompting for a passphrase. */ while (1) { - char *passphrase = askpass(err); + char *prompt = dupprintf( + "Enter passphrase to load key '%s'", err); + char *passphrase = askpass(prompt); sfree(err); + sfree(prompt); err = NULL; if (!passphrase) break; @@ -1010,6 +1009,7 @@ int main(int argc, char **argv) { int doing_opts = TRUE; keyact curr_keyact = KEYACT_AGENT_LOAD; + const char *standalone_askpass_prompt = NULL; /* * Process the command line. @@ -1063,6 +1063,14 @@ int main(int argc, char **argv) prompt_type = PROMPT_TTY; } else if (!strcmp(p, "--gui-prompt")) { prompt_type = PROMPT_GUI; + } else if (!strcmp(p, "--askpass")) { + if (--argc > 0) { + standalone_askpass_prompt = *++argv; + } else { + fprintf(stderr, "pageant: expected a prompt message " + "after --askpass\n"); + exit(1); + } } else if (!strcmp(p, "--")) { doing_opts = FALSE; } @@ -1082,6 +1090,27 @@ int main(int argc, char **argv) exit(1); } + if (!display) { + display = getenv("DISPLAY"); + if (display && !*display) + display = NULL; + } + + /* + * Deal with standalone-askpass mode. + */ + if (standalone_askpass_prompt) { + char *passphrase = askpass(standalone_askpass_prompt); + + if (!passphrase) + return 1; + + puts(passphrase); + smemclr(passphrase, strlen(passphrase)); + sfree(passphrase); + return 0; + } + /* * Block SIGPIPE, so that we'll get EPIPE individually on * particular network connections that go wrong. @@ -1091,12 +1120,6 @@ int main(int argc, char **argv) sk_init(); uxsel_init(); - if (!display) { - display = getenv("DISPLAY"); - if (display && !*display) - display = NULL; - } - /* * Now distinguish our two main running modes. Either we're * actually starting up an agent, in which case we should have a