1ce3adf43SDag-Erling Smørgrav /* 2ce3adf43SDag-Erling Smørgrav * Copyright (c) 2000-2002 Damien Miller. All rights reserved. 3ce3adf43SDag-Erling Smørgrav * 4ce3adf43SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 5ce3adf43SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 6ce3adf43SDag-Erling Smørgrav * are met: 7ce3adf43SDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright 8ce3adf43SDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer. 9ce3adf43SDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright 10ce3adf43SDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the 11ce3adf43SDag-Erling Smørgrav * documentation and/or other materials provided with the distribution. 12ce3adf43SDag-Erling Smørgrav * 13ce3adf43SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14ce3adf43SDag-Erling Smørgrav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15ce3adf43SDag-Erling Smørgrav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16ce3adf43SDag-Erling Smørgrav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17ce3adf43SDag-Erling Smørgrav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18ce3adf43SDag-Erling Smørgrav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19ce3adf43SDag-Erling Smørgrav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20ce3adf43SDag-Erling Smørgrav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21ce3adf43SDag-Erling Smørgrav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22ce3adf43SDag-Erling Smørgrav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23ce3adf43SDag-Erling Smørgrav */ 24ce3adf43SDag-Erling Smørgrav 25ce3adf43SDag-Erling Smørgrav /* GTK2 support by Nalin Dahyabhai <nalin@redhat.com> */ 26ce3adf43SDag-Erling Smørgrav 27ce3adf43SDag-Erling Smørgrav /* 28ce3adf43SDag-Erling Smørgrav * This is a simple GNOME SSH passphrase grabber. To use it, set the 29ce3adf43SDag-Erling Smørgrav * environment variable SSH_ASKPASS to point to the location of 30ce3adf43SDag-Erling Smørgrav * gnome-ssh-askpass before calling "ssh-add < /dev/null". 31ce3adf43SDag-Erling Smørgrav * 32ce3adf43SDag-Erling Smørgrav * There is only two run-time options: if you set the environment variable 33ce3adf43SDag-Erling Smørgrav * "GNOME_SSH_ASKPASS_GRAB_SERVER=true" then gnome-ssh-askpass will grab 34ce3adf43SDag-Erling Smørgrav * the X server. If you set "GNOME_SSH_ASKPASS_GRAB_POINTER=true", then the 35ce3adf43SDag-Erling Smørgrav * pointer will be grabbed too. These may have some benefit to security if 36ce3adf43SDag-Erling Smørgrav * you don't trust your X server. We grab the keyboard always. 37ce3adf43SDag-Erling Smørgrav */ 38ce3adf43SDag-Erling Smørgrav 39ce3adf43SDag-Erling Smørgrav #define GRAB_TRIES 16 40ce3adf43SDag-Erling Smørgrav #define GRAB_WAIT 250 /* milliseconds */ 41ce3adf43SDag-Erling Smørgrav 42ce3adf43SDag-Erling Smørgrav /* 43ce3adf43SDag-Erling Smørgrav * Compile with: 44ce3adf43SDag-Erling Smørgrav * 45ce3adf43SDag-Erling Smørgrav * cc -Wall `pkg-config --cflags gtk+-2.0` \ 46ce3adf43SDag-Erling Smørgrav * gnome-ssh-askpass2.c -o gnome-ssh-askpass \ 47ce3adf43SDag-Erling Smørgrav * `pkg-config --libs gtk+-2.0` 48ce3adf43SDag-Erling Smørgrav * 49ce3adf43SDag-Erling Smørgrav */ 50ce3adf43SDag-Erling Smørgrav 51ce3adf43SDag-Erling Smørgrav #include <stdlib.h> 52ce3adf43SDag-Erling Smørgrav #include <stdio.h> 53ce3adf43SDag-Erling Smørgrav #include <string.h> 54ce3adf43SDag-Erling Smørgrav #include <unistd.h> 55ce3adf43SDag-Erling Smørgrav #include <X11/Xlib.h> 56ce3adf43SDag-Erling Smørgrav #include <gtk/gtk.h> 57ce3adf43SDag-Erling Smørgrav #include <gdk/gdkx.h> 58ce3adf43SDag-Erling Smørgrav 59ce3adf43SDag-Erling Smørgrav static void 60*ca86bcf2SDag-Erling Smørgrav report_failed_grab (GtkWidget *parent_window, const char *what) 61ce3adf43SDag-Erling Smørgrav { 62ce3adf43SDag-Erling Smørgrav GtkWidget *err; 63ce3adf43SDag-Erling Smørgrav 64*ca86bcf2SDag-Erling Smørgrav err = gtk_message_dialog_new(GTK_WINDOW(parent_window), 0, 65ce3adf43SDag-Erling Smørgrav GTK_MESSAGE_ERROR, 66ce3adf43SDag-Erling Smørgrav GTK_BUTTONS_CLOSE, 67ce3adf43SDag-Erling Smørgrav "Could not grab %s. " 68ce3adf43SDag-Erling Smørgrav "A malicious client may be eavesdropping " 69ce3adf43SDag-Erling Smørgrav "on your session.", what); 70ce3adf43SDag-Erling Smørgrav gtk_window_set_position(GTK_WINDOW(err), GTK_WIN_POS_CENTER); 71ce3adf43SDag-Erling Smørgrav 72ce3adf43SDag-Erling Smørgrav gtk_dialog_run(GTK_DIALOG(err)); 73ce3adf43SDag-Erling Smørgrav 74ce3adf43SDag-Erling Smørgrav gtk_widget_destroy(err); 75ce3adf43SDag-Erling Smørgrav } 76ce3adf43SDag-Erling Smørgrav 77ce3adf43SDag-Erling Smørgrav static void 78ce3adf43SDag-Erling Smørgrav ok_dialog(GtkWidget *entry, gpointer dialog) 79ce3adf43SDag-Erling Smørgrav { 80ce3adf43SDag-Erling Smørgrav g_return_if_fail(GTK_IS_DIALOG(dialog)); 81ce3adf43SDag-Erling Smørgrav gtk_dialog_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); 82ce3adf43SDag-Erling Smørgrav } 83ce3adf43SDag-Erling Smørgrav 84ce3adf43SDag-Erling Smørgrav static int 85ce3adf43SDag-Erling Smørgrav passphrase_dialog(char *message) 86ce3adf43SDag-Erling Smørgrav { 87ce3adf43SDag-Erling Smørgrav const char *failed; 88ce3adf43SDag-Erling Smørgrav char *passphrase, *local; 89ce3adf43SDag-Erling Smørgrav int result, grab_tries, grab_server, grab_pointer; 90*ca86bcf2SDag-Erling Smørgrav GtkWidget *parent_window, *dialog, *entry; 91ce3adf43SDag-Erling Smørgrav GdkGrabStatus status; 92ce3adf43SDag-Erling Smørgrav 93ce3adf43SDag-Erling Smørgrav grab_server = (getenv("GNOME_SSH_ASKPASS_GRAB_SERVER") != NULL); 94ce3adf43SDag-Erling Smørgrav grab_pointer = (getenv("GNOME_SSH_ASKPASS_GRAB_POINTER") != NULL); 95ce3adf43SDag-Erling Smørgrav grab_tries = 0; 96ce3adf43SDag-Erling Smørgrav 97*ca86bcf2SDag-Erling Smørgrav /* Create an invisible parent window so that GtkDialog doesn't 98*ca86bcf2SDag-Erling Smørgrav * complain. */ 99*ca86bcf2SDag-Erling Smørgrav parent_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 100*ca86bcf2SDag-Erling Smørgrav 101*ca86bcf2SDag-Erling Smørgrav dialog = gtk_message_dialog_new(GTK_WINDOW(parent_window), 0, 102ce3adf43SDag-Erling Smørgrav GTK_MESSAGE_QUESTION, 103ce3adf43SDag-Erling Smørgrav GTK_BUTTONS_OK_CANCEL, 104ce3adf43SDag-Erling Smørgrav "%s", 105ce3adf43SDag-Erling Smørgrav message); 106ce3adf43SDag-Erling Smørgrav 107ce3adf43SDag-Erling Smørgrav entry = gtk_entry_new(); 108*ca86bcf2SDag-Erling Smørgrav gtk_box_pack_start( 109*ca86bcf2SDag-Erling Smørgrav GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), entry, 110*ca86bcf2SDag-Erling Smørgrav FALSE, FALSE, 0); 111ce3adf43SDag-Erling Smørgrav gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); 112ce3adf43SDag-Erling Smørgrav gtk_widget_grab_focus(entry); 113ce3adf43SDag-Erling Smørgrav gtk_widget_show(entry); 114ce3adf43SDag-Erling Smørgrav 115ce3adf43SDag-Erling Smørgrav gtk_window_set_title(GTK_WINDOW(dialog), "OpenSSH"); 116ce3adf43SDag-Erling Smørgrav gtk_window_set_position (GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); 117ce3adf43SDag-Erling Smørgrav gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE); 118ce3adf43SDag-Erling Smørgrav 119ce3adf43SDag-Erling Smørgrav /* Make <enter> close dialog */ 120ce3adf43SDag-Erling Smørgrav gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); 121ce3adf43SDag-Erling Smørgrav g_signal_connect(G_OBJECT(entry), "activate", 122ce3adf43SDag-Erling Smørgrav G_CALLBACK(ok_dialog), dialog); 123ce3adf43SDag-Erling Smørgrav 124ce3adf43SDag-Erling Smørgrav gtk_window_set_keep_above(GTK_WINDOW(dialog), TRUE); 125ce3adf43SDag-Erling Smørgrav 126ce3adf43SDag-Erling Smørgrav /* Grab focus */ 127ce3adf43SDag-Erling Smørgrav gtk_widget_show_now(dialog); 128ce3adf43SDag-Erling Smørgrav if (grab_pointer) { 129ce3adf43SDag-Erling Smørgrav for(;;) { 130ce3adf43SDag-Erling Smørgrav status = gdk_pointer_grab( 131*ca86bcf2SDag-Erling Smørgrav (gtk_widget_get_window(GTK_WIDGET(dialog))), TRUE, 132*ca86bcf2SDag-Erling Smørgrav 0, NULL, NULL, GDK_CURRENT_TIME); 133ce3adf43SDag-Erling Smørgrav if (status == GDK_GRAB_SUCCESS) 134ce3adf43SDag-Erling Smørgrav break; 135ce3adf43SDag-Erling Smørgrav usleep(GRAB_WAIT * 1000); 136ce3adf43SDag-Erling Smørgrav if (++grab_tries > GRAB_TRIES) { 137ce3adf43SDag-Erling Smørgrav failed = "mouse"; 138ce3adf43SDag-Erling Smørgrav goto nograb; 139ce3adf43SDag-Erling Smørgrav } 140ce3adf43SDag-Erling Smørgrav } 141ce3adf43SDag-Erling Smørgrav } 142ce3adf43SDag-Erling Smørgrav for(;;) { 143*ca86bcf2SDag-Erling Smørgrav status = gdk_keyboard_grab( 144*ca86bcf2SDag-Erling Smørgrav gtk_widget_get_window(GTK_WIDGET(dialog)), FALSE, 145*ca86bcf2SDag-Erling Smørgrav GDK_CURRENT_TIME); 146ce3adf43SDag-Erling Smørgrav if (status == GDK_GRAB_SUCCESS) 147ce3adf43SDag-Erling Smørgrav break; 148ce3adf43SDag-Erling Smørgrav usleep(GRAB_WAIT * 1000); 149ce3adf43SDag-Erling Smørgrav if (++grab_tries > GRAB_TRIES) { 150ce3adf43SDag-Erling Smørgrav failed = "keyboard"; 151ce3adf43SDag-Erling Smørgrav goto nograbkb; 152ce3adf43SDag-Erling Smørgrav } 153ce3adf43SDag-Erling Smørgrav } 154ce3adf43SDag-Erling Smørgrav if (grab_server) { 155ce3adf43SDag-Erling Smørgrav gdk_x11_grab_server(); 156ce3adf43SDag-Erling Smørgrav } 157ce3adf43SDag-Erling Smørgrav 158ce3adf43SDag-Erling Smørgrav result = gtk_dialog_run(GTK_DIALOG(dialog)); 159ce3adf43SDag-Erling Smørgrav 160ce3adf43SDag-Erling Smørgrav /* Ungrab */ 161ce3adf43SDag-Erling Smørgrav if (grab_server) 162*ca86bcf2SDag-Erling Smørgrav XUngrabServer(gdk_x11_get_default_xdisplay()); 163ce3adf43SDag-Erling Smørgrav if (grab_pointer) 164ce3adf43SDag-Erling Smørgrav gdk_pointer_ungrab(GDK_CURRENT_TIME); 165ce3adf43SDag-Erling Smørgrav gdk_keyboard_ungrab(GDK_CURRENT_TIME); 166ce3adf43SDag-Erling Smørgrav gdk_flush(); 167ce3adf43SDag-Erling Smørgrav 168ce3adf43SDag-Erling Smørgrav /* Report passphrase if user selected OK */ 169ce3adf43SDag-Erling Smørgrav passphrase = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry))); 170ce3adf43SDag-Erling Smørgrav if (result == GTK_RESPONSE_OK) { 171ce3adf43SDag-Erling Smørgrav local = g_locale_from_utf8(passphrase, strlen(passphrase), 172ce3adf43SDag-Erling Smørgrav NULL, NULL, NULL); 173ce3adf43SDag-Erling Smørgrav if (local != NULL) { 174ce3adf43SDag-Erling Smørgrav puts(local); 175ce3adf43SDag-Erling Smørgrav memset(local, '\0', strlen(local)); 176ce3adf43SDag-Erling Smørgrav g_free(local); 177ce3adf43SDag-Erling Smørgrav } else { 178ce3adf43SDag-Erling Smørgrav puts(passphrase); 179ce3adf43SDag-Erling Smørgrav } 180ce3adf43SDag-Erling Smørgrav } 181ce3adf43SDag-Erling Smørgrav 182ce3adf43SDag-Erling Smørgrav /* Zero passphrase in memory */ 183ce3adf43SDag-Erling Smørgrav memset(passphrase, '\b', strlen(passphrase)); 184ce3adf43SDag-Erling Smørgrav gtk_entry_set_text(GTK_ENTRY(entry), passphrase); 185ce3adf43SDag-Erling Smørgrav memset(passphrase, '\0', strlen(passphrase)); 186ce3adf43SDag-Erling Smørgrav g_free(passphrase); 187ce3adf43SDag-Erling Smørgrav 188ce3adf43SDag-Erling Smørgrav gtk_widget_destroy(dialog); 189ce3adf43SDag-Erling Smørgrav return (result == GTK_RESPONSE_OK ? 0 : -1); 190ce3adf43SDag-Erling Smørgrav 191ce3adf43SDag-Erling Smørgrav /* At least one grab failed - ungrab what we got, and report 192ce3adf43SDag-Erling Smørgrav the failure to the user. Note that XGrabServer() cannot 193ce3adf43SDag-Erling Smørgrav fail. */ 194ce3adf43SDag-Erling Smørgrav nograbkb: 195ce3adf43SDag-Erling Smørgrav gdk_pointer_ungrab(GDK_CURRENT_TIME); 196ce3adf43SDag-Erling Smørgrav nograb: 197ce3adf43SDag-Erling Smørgrav if (grab_server) 198*ca86bcf2SDag-Erling Smørgrav XUngrabServer(gdk_x11_get_default_xdisplay()); 199ce3adf43SDag-Erling Smørgrav gtk_widget_destroy(dialog); 200ce3adf43SDag-Erling Smørgrav 201*ca86bcf2SDag-Erling Smørgrav report_failed_grab(parent_window, failed); 202ce3adf43SDag-Erling Smørgrav 203ce3adf43SDag-Erling Smørgrav return (-1); 204ce3adf43SDag-Erling Smørgrav } 205ce3adf43SDag-Erling Smørgrav 206ce3adf43SDag-Erling Smørgrav int 207ce3adf43SDag-Erling Smørgrav main(int argc, char **argv) 208ce3adf43SDag-Erling Smørgrav { 209ce3adf43SDag-Erling Smørgrav char *message; 210ce3adf43SDag-Erling Smørgrav int result; 211ce3adf43SDag-Erling Smørgrav 212ce3adf43SDag-Erling Smørgrav gtk_init(&argc, &argv); 213ce3adf43SDag-Erling Smørgrav 214ce3adf43SDag-Erling Smørgrav if (argc > 1) { 215ce3adf43SDag-Erling Smørgrav message = g_strjoinv(" ", argv + 1); 216ce3adf43SDag-Erling Smørgrav } else { 217ce3adf43SDag-Erling Smørgrav message = g_strdup("Enter your OpenSSH passphrase:"); 218ce3adf43SDag-Erling Smørgrav } 219ce3adf43SDag-Erling Smørgrav 220ce3adf43SDag-Erling Smørgrav setvbuf(stdout, 0, _IONBF, 0); 221ce3adf43SDag-Erling Smørgrav result = passphrase_dialog(message); 222ce3adf43SDag-Erling Smørgrav g_free(message); 223ce3adf43SDag-Erling Smørgrav 224ce3adf43SDag-Erling Smørgrav return (result); 225ce3adf43SDag-Erling Smørgrav } 226