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