1180740Sdes/* 2180740Sdes * Copyright (c) 2000-2002 Damien Miller. All rights reserved. 3180740Sdes * 4180740Sdes * Redistribution and use in source and binary forms, with or without 5180740Sdes * modification, are permitted provided that the following conditions 6180740Sdes * are met: 7180740Sdes * 1. Redistributions of source code must retain the above copyright 8180740Sdes * notice, this list of conditions and the following disclaimer. 9180740Sdes * 2. Redistributions in binary form must reproduce the above copyright 10180740Sdes * notice, this list of conditions and the following disclaimer in the 11180740Sdes * documentation and/or other materials provided with the distribution. 12180740Sdes * 13180740Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14180740Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15180740Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16180740Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17180740Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18180740Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19180740Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20180740Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21180740Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22180740Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23180740Sdes */ 24180740Sdes 25180740Sdes/* 26180740Sdes * This is a simple GNOME SSH passphrase grabber. To use it, set the 27180740Sdes * environment variable SSH_ASKPASS to point to the location of 28180740Sdes * gnome-ssh-askpass before calling "ssh-add < /dev/null". 29180740Sdes * 30180740Sdes * There is only two run-time options: if you set the environment variable 31180740Sdes * "GNOME_SSH_ASKPASS_GRAB_SERVER=true" then gnome-ssh-askpass will grab 32180740Sdes * the X server. If you set "GNOME_SSH_ASKPASS_GRAB_POINTER=true", then the 33180740Sdes * pointer will be grabbed too. These may have some benefit to security if 34180740Sdes * you don't trust your X server. We grab the keyboard always. 35180740Sdes */ 36180740Sdes 37180740Sdes/* 38180740Sdes * Compile with: 39180740Sdes * 40180740Sdes * cc `gnome-config --cflags gnome gnomeui` \ 41180740Sdes * gnome-ssh-askpass1.c -o gnome-ssh-askpass \ 42180740Sdes * `gnome-config --libs gnome gnomeui` 43180740Sdes * 44180740Sdes */ 45180740Sdes 46180740Sdes#include <stdlib.h> 47180740Sdes#include <stdio.h> 48180740Sdes#include <string.h> 49180740Sdes#include <gnome.h> 50180740Sdes#include <X11/Xlib.h> 51180740Sdes#include <gdk/gdkx.h> 52180740Sdes 53180740Sdesvoid 54180740Sdesreport_failed_grab (void) 55180740Sdes{ 56180740Sdes GtkWidget *err; 57180740Sdes 58180740Sdes err = gnome_message_box_new("Could not grab keyboard or mouse.\n" 59180740Sdes "A malicious client may be eavesdropping on your session.", 60180740Sdes GNOME_MESSAGE_BOX_ERROR, "EXIT", NULL); 61180740Sdes gtk_window_set_position(GTK_WINDOW(err), GTK_WIN_POS_CENTER); 62180740Sdes gtk_object_set(GTK_OBJECT(err), "type", GTK_WINDOW_POPUP, NULL); 63180740Sdes 64180740Sdes gnome_dialog_run_and_close(GNOME_DIALOG(err)); 65180740Sdes} 66180740Sdes 67180740Sdesint 68180740Sdespassphrase_dialog(char *message) 69180740Sdes{ 70180740Sdes char *passphrase; 71180740Sdes char **messages; 72180740Sdes int result, i, grab_server, grab_pointer; 73180740Sdes GtkWidget *dialog, *entry, *label; 74180740Sdes 75180740Sdes grab_server = (getenv("GNOME_SSH_ASKPASS_GRAB_SERVER") != NULL); 76180740Sdes grab_pointer = (getenv("GNOME_SSH_ASKPASS_GRAB_POINTER") != NULL); 77180740Sdes 78180740Sdes dialog = gnome_dialog_new("OpenSSH", GNOME_STOCK_BUTTON_OK, 79180740Sdes GNOME_STOCK_BUTTON_CANCEL, NULL); 80180740Sdes 81180740Sdes messages = g_strsplit(message, "\\n", 0); 82180740Sdes if (messages) 83180740Sdes for(i = 0; messages[i]; i++) { 84180740Sdes label = gtk_label_new(messages[i]); 85180740Sdes gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox), 86180740Sdes label, FALSE, FALSE, 0); 87180740Sdes } 88180740Sdes 89180740Sdes entry = gtk_entry_new(); 90180740Sdes gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox), entry, FALSE, 91180740Sdes FALSE, 0); 92180740Sdes gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); 93180740Sdes gtk_widget_grab_focus(entry); 94180740Sdes 95180740Sdes /* Center window and prepare for grab */ 96180740Sdes gtk_object_set(GTK_OBJECT(dialog), "type", GTK_WINDOW_POPUP, NULL); 97180740Sdes gnome_dialog_set_default(GNOME_DIALOG(dialog), 0); 98180740Sdes gtk_window_set_position (GTK_WINDOW(dialog), GTK_WIN_POS_CENTER); 99180740Sdes gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, FALSE, TRUE); 100180740Sdes gnome_dialog_close_hides(GNOME_DIALOG(dialog), TRUE); 101180740Sdes gtk_container_set_border_width(GTK_CONTAINER(GNOME_DIALOG(dialog)->vbox), 102180740Sdes GNOME_PAD); 103180740Sdes gtk_widget_show_all(dialog); 104180740Sdes 105180740Sdes /* Grab focus */ 106180740Sdes if (grab_server) 107180740Sdes XGrabServer(GDK_DISPLAY()); 108180740Sdes if (grab_pointer && gdk_pointer_grab(dialog->window, TRUE, 0, 109180740Sdes NULL, NULL, GDK_CURRENT_TIME)) 110180740Sdes goto nograb; 111180740Sdes if (gdk_keyboard_grab(dialog->window, FALSE, GDK_CURRENT_TIME)) 112180740Sdes goto nograbkb; 113180740Sdes 114180740Sdes /* Make <enter> close dialog */ 115180740Sdes gnome_dialog_editable_enters(GNOME_DIALOG(dialog), GTK_EDITABLE(entry)); 116180740Sdes 117180740Sdes /* Run dialog */ 118180740Sdes result = gnome_dialog_run(GNOME_DIALOG(dialog)); 119180740Sdes 120180740Sdes /* Ungrab */ 121180740Sdes if (grab_server) 122180740Sdes XUngrabServer(GDK_DISPLAY()); 123180740Sdes if (grab_pointer) 124180740Sdes gdk_pointer_ungrab(GDK_CURRENT_TIME); 125180740Sdes gdk_keyboard_ungrab(GDK_CURRENT_TIME); 126180740Sdes gdk_flush(); 127180740Sdes 128180740Sdes /* Report passphrase if user selected OK */ 129180740Sdes passphrase = gtk_entry_get_text(GTK_ENTRY(entry)); 130180740Sdes if (result == 0) 131180740Sdes puts(passphrase); 132180740Sdes 133180740Sdes /* Zero passphrase in memory */ 134180740Sdes memset(passphrase, '\0', strlen(passphrase)); 135180740Sdes gtk_entry_set_text(GTK_ENTRY(entry), passphrase); 136180740Sdes 137180740Sdes gnome_dialog_close(GNOME_DIALOG(dialog)); 138180740Sdes return (result == 0 ? 0 : -1); 139180740Sdes 140180740Sdes /* At least one grab failed - ungrab what we got, and report 141180740Sdes the failure to the user. Note that XGrabServer() cannot 142180740Sdes fail. */ 143180740Sdes nograbkb: 144180740Sdes gdk_pointer_ungrab(GDK_CURRENT_TIME); 145180740Sdes nograb: 146180740Sdes if (grab_server) 147180740Sdes XUngrabServer(GDK_DISPLAY()); 148180740Sdes gnome_dialog_close(GNOME_DIALOG(dialog)); 149180740Sdes 150180740Sdes report_failed_grab(); 151180740Sdes return (-1); 152180740Sdes} 153180740Sdes 154180740Sdesint 155180740Sdesmain(int argc, char **argv) 156180740Sdes{ 157180740Sdes char *message; 158180740Sdes int result; 159180740Sdes 160180740Sdes gnome_init("GNOME ssh-askpass", "0.1", argc, argv); 161180740Sdes 162180740Sdes if (argc == 2) 163180740Sdes message = argv[1]; 164180740Sdes else 165180740Sdes message = "Enter your OpenSSH passphrase:"; 166180740Sdes 167180740Sdes setvbuf(stdout, 0, _IONBF, 0); 168180740Sdes result = passphrase_dialog(message); 169180740Sdes 170180740Sdes return (result); 171180740Sdes} 172