Skip to content

Commit

Permalink
Teach the GTK2/3 ssh-askpass the new prompt hints
Browse files Browse the repository at this point in the history
ssh/ssh-agent now sets a hint environment variable $SSH_ASKPASS_PROMPT
when running the askpass program. This is intended to allow the
askpass to vary its UI across the three cases it supports: asking for
a passphrase, confirming the use of a key and (recently) reminding
a user to touch their security key.

This adapts the gnome-ssh-askpass[23] to use these hints. Specifically,
for SSH_ASKPASS_PROMPT=confirm it will skip the text input box and show
only "yes"/"no" buttons. For SSH_ASKPASS_PROMPT=none (used to remind
users to tap their security key), it shows only a "close" button.

Help wanted: adapt the other askpass programs in active use, including
x11-ssh-askpass, lxqt-openssh-askpass, etc.
  • Loading branch information
djmdjm committed Nov 18, 2019
1 parent 857f49e commit b497e92
Showing 1 changed file with 72 additions and 43 deletions.
115 changes: 72 additions & 43 deletions contrib/gnome-ssh-askpass2.c
Expand Up @@ -39,6 +39,10 @@
#define GRAB_TRIES 16
#define GRAB_WAIT 250 /* milliseconds */

#define PROMPT_ENTRY 0
#define PROMPT_CONFIRM 1
#define PROMPT_NONE 2

/*
* Compile with:
*
Expand Down Expand Up @@ -82,11 +86,12 @@ ok_dialog(GtkWidget *entry, gpointer dialog)
}

static int
passphrase_dialog(char *message)
passphrase_dialog(char *message, int prompt_type)
{
const char *failed;
char *passphrase, *local;
int result, grab_tries, grab_server, grab_pointer;
int buttons, default_response;
GtkWidget *parent_window, *dialog, *entry;
GdkGrabStatus status;

Expand All @@ -98,31 +103,43 @@ passphrase_dialog(char *message)
* complain. */
parent_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

switch (prompt_type) {
case PROMPT_CONFIRM:
buttons = GTK_BUTTONS_YES_NO;
default_response = GTK_RESPONSE_YES;
break;
case PROMPT_NONE:
buttons = GTK_BUTTONS_CLOSE;
default_response = GTK_RESPONSE_CLOSE;
break;
default:
buttons = GTK_BUTTONS_OK_CANCEL;
default_response = GTK_RESPONSE_OK;
break;
}

dialog = gtk_message_dialog_new(GTK_WINDOW(parent_window), 0,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_OK_CANCEL,
"%s",
message);

entry = gtk_entry_new();
gtk_box_pack_start(
GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), entry,
FALSE, FALSE, 0);
gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
gtk_widget_grab_focus(entry);
gtk_widget_show(entry);
GTK_MESSAGE_QUESTION, buttons, "%s", message);

gtk_window_set_title(GTK_WINDOW(dialog), "OpenSSH");
gtk_window_set_position (GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);

/* Make <enter> close dialog */
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
g_signal_connect(G_OBJECT(entry), "activate",
G_CALLBACK(ok_dialog), dialog);

gtk_dialog_set_default_response(GTK_DIALOG(dialog), default_response);
gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE);

if (prompt_type == PROMPT_ENTRY) {
entry = gtk_entry_new();
gtk_box_pack_start(
GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
entry, FALSE, FALSE, 0);
gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
gtk_widget_grab_focus(entry);
gtk_widget_show(entry);
/* Make <enter> close dialog */
g_signal_connect(G_OBJECT(entry), "activate",
G_CALLBACK(ok_dialog), dialog);
}

/* Grab focus */
gtk_widget_show_now(dialog);
if (grab_pointer) {
Expand Down Expand Up @@ -166,32 +183,37 @@ passphrase_dialog(char *message)
gdk_flush();

/* Report passphrase if user selected OK */
passphrase = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
if (result == GTK_RESPONSE_OK) {
local = g_locale_from_utf8(passphrase, strlen(passphrase),
NULL, NULL, NULL);
if (local != NULL) {
puts(local);
memset(local, '\0', strlen(local));
g_free(local);
} else {
puts(passphrase);
if (prompt_type == PROMPT_ENTRY) {
passphrase = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
if (result == GTK_RESPONSE_OK) {
local = g_locale_from_utf8(passphrase,
strlen(passphrase), NULL, NULL, NULL);
if (local != NULL) {
puts(local);
memset(local, '\0', strlen(local));
g_free(local);
} else {
puts(passphrase);
}
}
/* Zero passphrase in memory */
memset(passphrase, '\b', strlen(passphrase));
gtk_entry_set_text(GTK_ENTRY(entry), passphrase);
memset(passphrase, '\0', strlen(passphrase));
g_free(passphrase);
}

/* Zero passphrase in memory */
memset(passphrase, '\b', strlen(passphrase));
gtk_entry_set_text(GTK_ENTRY(entry), passphrase);
memset(passphrase, '\0', strlen(passphrase));
g_free(passphrase);


gtk_widget_destroy(dialog);
return (result == GTK_RESPONSE_OK ? 0 : -1);
if (result != GTK_RESPONSE_OK && result != GTK_RESPONSE_YES)
return -1;
return 0;

/* At least one grab failed - ungrab what we got, and report
the failure to the user. Note that XGrabServer() cannot
fail. */
nograbkb:
/*
* At least one grab failed - ungrab what we got, and report
* the failure to the user. Note that XGrabServer() cannot
* fail.
*/
gdk_pointer_ungrab(GDK_CURRENT_TIME);
nograb:
if (grab_server)
Expand All @@ -206,8 +228,8 @@ passphrase_dialog(char *message)
int
main(int argc, char **argv)
{
char *message;
int result;
char *message, *prompt_mode;
int result, prompt_type = PROMPT_ENTRY;

gtk_init(&argc, &argv);

Expand All @@ -217,8 +239,15 @@ main(int argc, char **argv)
message = g_strdup("Enter your OpenSSH passphrase:");
}

if ((prompt_mode = getenv("SSH_ASKPASS_PROMPT")) != NULL) {
if (strcasecmp(prompt_mode, "confirm") == 0)
prompt_type = PROMPT_CONFIRM;
else if (strcasecmp(prompt_mode, "none") == 0)
prompt_type = PROMPT_NONE;
}

setvbuf(stdout, 0, _IONBF, 0);
result = passphrase_dialog(message);
result = passphrase_dialog(message, prompt_type);
g_free(message);

return (result);
Expand Down

0 comments on commit b497e92

Please sign in to comment.