Home | History | Annotate | Download | only in contrib
      1 /*
      2  * Copyright (c) 2000-2002 Damien Miller.  All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     23  */
     24 
     25 /*
     26  * This is a simple GNOME SSH passphrase grabber. To use it, set the
     27  * environment variable SSH_ASKPASS to point to the location of
     28  * gnome-ssh-askpass before calling "ssh-add < /dev/null".
     29  *
     30  * There is only two run-time options: if you set the environment variable
     31  * "GNOME_SSH_ASKPASS_GRAB_SERVER=true" then gnome-ssh-askpass will grab
     32  * the X server. If you set "GNOME_SSH_ASKPASS_GRAB_POINTER=true", then the
     33  * pointer will be grabbed too. These may have some benefit to security if
     34  * you don't trust your X server. We grab the keyboard always.
     35  */
     36 
     37 /*
     38  * Compile with:
     39  *
     40  * cc `gnome-config --cflags gnome gnomeui` \
     41  *    gnome-ssh-askpass1.c -o gnome-ssh-askpass \
     42  *    `gnome-config --libs gnome gnomeui`
     43  *
     44  */
     45 
     46 #include <stdlib.h>
     47 #include <stdio.h>
     48 #include <string.h>
     49 #include <gnome.h>
     50 #include <X11/Xlib.h>
     51 #include <gdk/gdkx.h>
     52 
     53 void
     54 report_failed_grab (void)
     55 {
     56 	GtkWidget *err;
     57 
     58 	err = gnome_message_box_new("Could not grab keyboard or mouse.\n"
     59 		"A malicious client may be eavesdropping on your session.",
     60 				    GNOME_MESSAGE_BOX_ERROR, "EXIT", NULL);
     61 	gtk_window_set_position(GTK_WINDOW(err), GTK_WIN_POS_CENTER);
     62 	gtk_object_set(GTK_OBJECT(err), "type", GTK_WINDOW_POPUP, NULL);
     63 
     64 	gnome_dialog_run_and_close(GNOME_DIALOG(err));
     65 }
     66 
     67 int
     68 passphrase_dialog(char *message)
     69 {
     70 	char *passphrase;
     71 	char **messages;
     72 	int result, i, grab_server, grab_pointer;
     73 	GtkWidget *dialog, *entry, *label;
     74 
     75 	grab_server = (getenv("GNOME_SSH_ASKPASS_GRAB_SERVER") != NULL);
     76 	grab_pointer = (getenv("GNOME_SSH_ASKPASS_GRAB_POINTER") != NULL);
     77 
     78 	dialog = gnome_dialog_new("OpenSSH", GNOME_STOCK_BUTTON_OK,
     79 	    GNOME_STOCK_BUTTON_CANCEL, NULL);
     80 
     81 	messages = g_strsplit(message, "\\n", 0);
     82 	if (messages)
     83 		for(i = 0; messages[i]; i++) {
     84 			label = gtk_label_new(messages[i]);
     85 			gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox),
     86 			    label, FALSE, FALSE, 0);
     87 		}
     88 
     89 	entry = gtk_entry_new();
     90 	gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox), entry, FALSE,
     91 	    FALSE, 0);
     92 	gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
     93 	gtk_widget_grab_focus(entry);
     94 
     95 	/* Center window and prepare for grab */
     96 	gtk_object_set(GTK_OBJECT(dialog), "type", GTK_WINDOW_POPUP, NULL);
     97 	gnome_dialog_set_default(GNOME_DIALOG(dialog), 0);
     98 	gtk_window_set_position (GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
     99 	gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, FALSE, TRUE);
    100 	gnome_dialog_close_hides(GNOME_DIALOG(dialog), TRUE);
    101 	gtk_container_set_border_width(GTK_CONTAINER(GNOME_DIALOG(dialog)->vbox),
    102 	    GNOME_PAD);
    103 	gtk_widget_show_all(dialog);
    104 
    105 	/* Grab focus */
    106 	if (grab_server)
    107 		XGrabServer(GDK_DISPLAY());
    108 	if (grab_pointer && gdk_pointer_grab(dialog->window, TRUE, 0,
    109 	    NULL, NULL, GDK_CURRENT_TIME))
    110 		goto nograb;
    111 	if (gdk_keyboard_grab(dialog->window, FALSE, GDK_CURRENT_TIME))
    112 		goto nograbkb;
    113 
    114 	/* Make <enter> close dialog */
    115 	gnome_dialog_editable_enters(GNOME_DIALOG(dialog), GTK_EDITABLE(entry));
    116 
    117 	/* Run dialog */
    118 	result = gnome_dialog_run(GNOME_DIALOG(dialog));
    119 
    120 	/* Ungrab */
    121 	if (grab_server)
    122 		XUngrabServer(GDK_DISPLAY());
    123 	if (grab_pointer)
    124 		gdk_pointer_ungrab(GDK_CURRENT_TIME);
    125 	gdk_keyboard_ungrab(GDK_CURRENT_TIME);
    126 	gdk_flush();
    127 
    128 	/* Report passphrase if user selected OK */
    129 	passphrase = gtk_entry_get_text(GTK_ENTRY(entry));
    130 	if (result == 0)
    131 		puts(passphrase);
    132 
    133 	/* Zero passphrase in memory */
    134 	memset(passphrase, '\0', strlen(passphrase));
    135 	gtk_entry_set_text(GTK_ENTRY(entry), passphrase);
    136 
    137 	gnome_dialog_close(GNOME_DIALOG(dialog));
    138 	return (result == 0 ? 0 : -1);
    139 
    140 	/* At least one grab failed - ungrab what we got, and report
    141 	   the failure to the user.  Note that XGrabServer() cannot
    142 	   fail.  */
    143  nograbkb:
    144 	gdk_pointer_ungrab(GDK_CURRENT_TIME);
    145  nograb:
    146 	if (grab_server)
    147 		XUngrabServer(GDK_DISPLAY());
    148 	gnome_dialog_close(GNOME_DIALOG(dialog));
    149 
    150 	report_failed_grab();
    151 	return (-1);
    152 }
    153 
    154 int
    155 main(int argc, char **argv)
    156 {
    157 	char *message;
    158 	int result;
    159 
    160 	gnome_init("GNOME ssh-askpass", "0.1", argc, argv);
    161 
    162 	if (argc == 2)
    163 		message = argv[1];
    164 	else
    165 		message = "Enter your OpenSSH passphrase:";
    166 
    167 	setvbuf(stdout, 0, _IONBF, 0);
    168 	result = passphrase_dialog(message);
    169 
    170 	return (result);
    171 }
    172