144d5b603SDamien Miller /*
244d5b603SDamien Miller  * Copyright (c) 2000-2002 Damien Miller.  All rights reserved.
344d5b603SDamien Miller  *
444d5b603SDamien Miller  * Redistribution and use in source and binary forms, with or without
544d5b603SDamien Miller  * modification, are permitted provided that the following conditions
644d5b603SDamien Miller  * are met:
744d5b603SDamien Miller  * 1. Redistributions of source code must retain the above copyright
844d5b603SDamien Miller  *    notice, this list of conditions and the following disclaimer.
944d5b603SDamien Miller  * 2. Redistributions in binary form must reproduce the above copyright
1044d5b603SDamien Miller  *    notice, this list of conditions and the following disclaimer in the
1144d5b603SDamien Miller  *    documentation and/or other materials provided with the distribution.
1244d5b603SDamien Miller  *
1344d5b603SDamien Miller  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1444d5b603SDamien Miller  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1544d5b603SDamien Miller  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1644d5b603SDamien Miller  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1744d5b603SDamien Miller  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1844d5b603SDamien Miller  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
1944d5b603SDamien Miller  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2044d5b603SDamien Miller  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2144d5b603SDamien Miller  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2244d5b603SDamien Miller  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2344d5b603SDamien Miller  */
2444d5b603SDamien Miller 
2544d5b603SDamien Miller /*
2644d5b603SDamien Miller  * This is a simple GNOME SSH passphrase grabber. To use it, set the
2744d5b603SDamien Miller  * environment variable SSH_ASKPASS to point to the location of
2844d5b603SDamien Miller  * gnome-ssh-askpass before calling "ssh-add < /dev/null".
2944d5b603SDamien Miller  *
3044d5b603SDamien Miller  * There is only two run-time options: if you set the environment variable
3144d5b603SDamien Miller  * "GNOME_SSH_ASKPASS_GRAB_SERVER=true" then gnome-ssh-askpass will grab
3244d5b603SDamien Miller  * the X server. If you set "GNOME_SSH_ASKPASS_GRAB_POINTER=true", then the
3344d5b603SDamien Miller  * pointer will be grabbed too. These may have some benefit to security if
3444d5b603SDamien Miller  * you don't trust your X server. We grab the keyboard always.
3544d5b603SDamien Miller  */
3644d5b603SDamien Miller 
3744d5b603SDamien Miller /*
3844d5b603SDamien Miller  * Compile with:
3944d5b603SDamien Miller  *
4044d5b603SDamien Miller  * cc `gnome-config --cflags gnome gnomeui` \
4110f30851SDamien Miller  *    gnome-ssh-askpass1.c -o gnome-ssh-askpass \
4244d5b603SDamien Miller  *    `gnome-config --libs gnome gnomeui`
4344d5b603SDamien Miller  *
4444d5b603SDamien Miller  */
4544d5b603SDamien Miller 
4644d5b603SDamien Miller #include <stdlib.h>
4744d5b603SDamien Miller #include <stdio.h>
4844d5b603SDamien Miller #include <string.h>
4944d5b603SDamien Miller #include <gnome.h>
5044d5b603SDamien Miller #include <X11/Xlib.h>
5144d5b603SDamien Miller #include <gdk/gdkx.h>
5244d5b603SDamien Miller 
5344d5b603SDamien Miller void
report_failed_grab(void)5444d5b603SDamien Miller report_failed_grab (void)
5544d5b603SDamien Miller {
5644d5b603SDamien Miller 	GtkWidget *err;
5744d5b603SDamien Miller 
5844d5b603SDamien Miller 	err = gnome_message_box_new("Could not grab keyboard or mouse.\n"
5944d5b603SDamien Miller 		"A malicious client may be eavesdropping on your session.",
6044d5b603SDamien Miller 				    GNOME_MESSAGE_BOX_ERROR, "EXIT", NULL);
6144d5b603SDamien Miller 	gtk_window_set_position(GTK_WINDOW(err), GTK_WIN_POS_CENTER);
6244d5b603SDamien Miller 	gtk_object_set(GTK_OBJECT(err), "type", GTK_WINDOW_POPUP, NULL);
6344d5b603SDamien Miller 
6444d5b603SDamien Miller 	gnome_dialog_run_and_close(GNOME_DIALOG(err));
6544d5b603SDamien Miller }
6644d5b603SDamien Miller 
6710f30851SDamien Miller int
passphrase_dialog(char * message)6844d5b603SDamien Miller passphrase_dialog(char *message)
6944d5b603SDamien Miller {
7044d5b603SDamien Miller 	char *passphrase;
7144d5b603SDamien Miller 	char **messages;
7244d5b603SDamien Miller 	int result, i, grab_server, grab_pointer;
7344d5b603SDamien Miller 	GtkWidget *dialog, *entry, *label;
7444d5b603SDamien Miller 
7544d5b603SDamien Miller 	grab_server = (getenv("GNOME_SSH_ASKPASS_GRAB_SERVER") != NULL);
7644d5b603SDamien Miller 	grab_pointer = (getenv("GNOME_SSH_ASKPASS_GRAB_POINTER") != NULL);
7744d5b603SDamien Miller 
7844d5b603SDamien Miller 	dialog = gnome_dialog_new("OpenSSH", GNOME_STOCK_BUTTON_OK,
7944d5b603SDamien Miller 	    GNOME_STOCK_BUTTON_CANCEL, NULL);
8044d5b603SDamien Miller 
8144d5b603SDamien Miller 	messages = g_strsplit(message, "\\n", 0);
8244d5b603SDamien Miller 	if (messages)
8344d5b603SDamien Miller 		for(i = 0; messages[i]; i++) {
8444d5b603SDamien Miller 			label = gtk_label_new(messages[i]);
8544d5b603SDamien Miller 			gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox),
8644d5b603SDamien Miller 			    label, FALSE, FALSE, 0);
8744d5b603SDamien Miller 		}
8844d5b603SDamien Miller 
8944d5b603SDamien Miller 	entry = gtk_entry_new();
9044d5b603SDamien Miller 	gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox), entry, FALSE,
9144d5b603SDamien Miller 	    FALSE, 0);
9244d5b603SDamien Miller 	gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
9344d5b603SDamien Miller 	gtk_widget_grab_focus(entry);
9444d5b603SDamien Miller 
9544d5b603SDamien Miller 	/* Center window and prepare for grab */
9644d5b603SDamien Miller 	gtk_object_set(GTK_OBJECT(dialog), "type", GTK_WINDOW_POPUP, NULL);
9744d5b603SDamien Miller 	gnome_dialog_set_default(GNOME_DIALOG(dialog), 0);
9844d5b603SDamien Miller 	gtk_window_set_position (GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
9944d5b603SDamien Miller 	gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, FALSE, TRUE);
10044d5b603SDamien Miller 	gnome_dialog_close_hides(GNOME_DIALOG(dialog), TRUE);
10144d5b603SDamien Miller 	gtk_container_set_border_width(GTK_CONTAINER(GNOME_DIALOG(dialog)->vbox),
10244d5b603SDamien Miller 	    GNOME_PAD);
10344d5b603SDamien Miller 	gtk_widget_show_all(dialog);
10444d5b603SDamien Miller 
10544d5b603SDamien Miller 	/* Grab focus */
10644d5b603SDamien Miller 	if (grab_server)
10744d5b603SDamien Miller 		XGrabServer(GDK_DISPLAY());
10844d5b603SDamien Miller 	if (grab_pointer && gdk_pointer_grab(dialog->window, TRUE, 0,
10944d5b603SDamien Miller 	    NULL, NULL, GDK_CURRENT_TIME))
11044d5b603SDamien Miller 		goto nograb;
11144d5b603SDamien Miller 	if (gdk_keyboard_grab(dialog->window, FALSE, GDK_CURRENT_TIME))
11244d5b603SDamien Miller 		goto nograbkb;
11344d5b603SDamien Miller 
11444d5b603SDamien Miller 	/* Make <enter> close dialog */
11544d5b603SDamien Miller 	gnome_dialog_editable_enters(GNOME_DIALOG(dialog), GTK_EDITABLE(entry));
11644d5b603SDamien Miller 
11744d5b603SDamien Miller 	/* Run dialog */
11844d5b603SDamien Miller 	result = gnome_dialog_run(GNOME_DIALOG(dialog));
11944d5b603SDamien Miller 
12044d5b603SDamien Miller 	/* Ungrab */
12144d5b603SDamien Miller 	if (grab_server)
12244d5b603SDamien Miller 		XUngrabServer(GDK_DISPLAY());
12344d5b603SDamien Miller 	if (grab_pointer)
12444d5b603SDamien Miller 		gdk_pointer_ungrab(GDK_CURRENT_TIME);
12544d5b603SDamien Miller 	gdk_keyboard_ungrab(GDK_CURRENT_TIME);
12644d5b603SDamien Miller 	gdk_flush();
12744d5b603SDamien Miller 
12844d5b603SDamien Miller 	/* Report passphrase if user selected OK */
12944d5b603SDamien Miller 	passphrase = gtk_entry_get_text(GTK_ENTRY(entry));
13044d5b603SDamien Miller 	if (result == 0)
13144d5b603SDamien Miller 		puts(passphrase);
13244d5b603SDamien Miller 
13344d5b603SDamien Miller 	/* Zero passphrase in memory */
13444d5b603SDamien Miller 	memset(passphrase, '\0', strlen(passphrase));
13544d5b603SDamien Miller 	gtk_entry_set_text(GTK_ENTRY(entry), passphrase);
13644d5b603SDamien Miller 
13744d5b603SDamien Miller 	gnome_dialog_close(GNOME_DIALOG(dialog));
13810f30851SDamien Miller 	return (result == 0 ? 0 : -1);
13944d5b603SDamien Miller 
140*57ed647eSDamien Miller 	/*
141*57ed647eSDamien Miller 	 * At least one grab failed - ungrab what we got, and report the
142*57ed647eSDamien Miller 	 * failure to the user. Note that XGrabServer() cannot fail.
143*57ed647eSDamien Miller 	 */
14444d5b603SDamien Miller  nograbkb:
14544d5b603SDamien Miller 	gdk_pointer_ungrab(GDK_CURRENT_TIME);
14644d5b603SDamien Miller  nograb:
14744d5b603SDamien Miller 	if (grab_server)
14844d5b603SDamien Miller 		XUngrabServer(GDK_DISPLAY());
14944d5b603SDamien Miller 	gnome_dialog_close(GNOME_DIALOG(dialog));
15044d5b603SDamien Miller 
15144d5b603SDamien Miller 	report_failed_grab();
15210f30851SDamien Miller 	return (-1);
15344d5b603SDamien Miller }
15444d5b603SDamien Miller 
15544d5b603SDamien Miller int
main(int argc,char ** argv)15644d5b603SDamien Miller main(int argc, char **argv)
15744d5b603SDamien Miller {
15844d5b603SDamien Miller 	char *message;
15910f30851SDamien Miller 	int result;
16044d5b603SDamien Miller 
16144d5b603SDamien Miller 	gnome_init("GNOME ssh-askpass", "0.1", argc, argv);
16244d5b603SDamien Miller 
16344d5b603SDamien Miller 	if (argc == 2)
16444d5b603SDamien Miller 		message = argv[1];
16544d5b603SDamien Miller 	else
16644d5b603SDamien Miller 		message = "Enter your OpenSSH passphrase:";
16744d5b603SDamien Miller 
16844d5b603SDamien Miller 	setvbuf(stdout, 0, _IONBF, 0);
16910f30851SDamien Miller 	result = passphrase_dialog(message);
17010f30851SDamien Miller 
17110f30851SDamien Miller 	return (result);
17244d5b603SDamien Miller }
173