gnome-ssh-askpass1.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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. * This is a simple GNOME SSH passphrase grabber. To use it, set the
  26. * environment variable SSH_ASKPASS to point to the location of
  27. * gnome-ssh-askpass before calling "ssh-add < /dev/null".
  28. *
  29. * There is only two run-time options: if you set the environment variable
  30. * "GNOME_SSH_ASKPASS_GRAB_SERVER=true" then gnome-ssh-askpass will grab
  31. * the X server. If you set "GNOME_SSH_ASKPASS_GRAB_POINTER=true", then the
  32. * pointer will be grabbed too. These may have some benefit to security if
  33. * you don't trust your X server. We grab the keyboard always.
  34. */
  35. /*
  36. * Compile with:
  37. *
  38. * cc `gnome-config --cflags gnome gnomeui` \
  39. * gnome-ssh-askpass1.c -o gnome-ssh-askpass \
  40. * `gnome-config --libs gnome gnomeui`
  41. *
  42. */
  43. #include <stdlib.h>
  44. #include <stdio.h>
  45. #include <string.h>
  46. #include <gnome.h>
  47. #include <X11/Xlib.h>
  48. #include <gdk/gdkx.h>
  49. void
  50. report_failed_grab (void)
  51. {
  52. GtkWidget *err;
  53. err = gnome_message_box_new("Could not grab keyboard or mouse.\n"
  54. "A malicious client may be eavesdropping on your session.",
  55. GNOME_MESSAGE_BOX_ERROR, "EXIT", NULL);
  56. gtk_window_set_position(GTK_WINDOW(err), GTK_WIN_POS_CENTER);
  57. gtk_object_set(GTK_OBJECT(err), "type", GTK_WINDOW_POPUP, NULL);
  58. gnome_dialog_run_and_close(GNOME_DIALOG(err));
  59. }
  60. int
  61. passphrase_dialog(char *message)
  62. {
  63. char *passphrase;
  64. char **messages;
  65. int result, i, grab_server, grab_pointer;
  66. GtkWidget *dialog, *entry, *label;
  67. grab_server = (getenv("GNOME_SSH_ASKPASS_GRAB_SERVER") != NULL);
  68. grab_pointer = (getenv("GNOME_SSH_ASKPASS_GRAB_POINTER") != NULL);
  69. dialog = gnome_dialog_new("OpenSSH", GNOME_STOCK_BUTTON_OK,
  70. GNOME_STOCK_BUTTON_CANCEL, NULL);
  71. messages = g_strsplit(message, "\\n", 0);
  72. if (messages)
  73. for(i = 0; messages[i]; i++) {
  74. label = gtk_label_new(messages[i]);
  75. gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox),
  76. label, FALSE, FALSE, 0);
  77. }
  78. entry = gtk_entry_new();
  79. gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox), entry, FALSE,
  80. FALSE, 0);
  81. gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
  82. gtk_widget_grab_focus(entry);
  83. /* Center window and prepare for grab */
  84. gtk_object_set(GTK_OBJECT(dialog), "type", GTK_WINDOW_POPUP, NULL);
  85. gnome_dialog_set_default(GNOME_DIALOG(dialog), 0);
  86. gtk_window_set_position (GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
  87. gtk_window_set_policy(GTK_WINDOW(dialog), FALSE, FALSE, TRUE);
  88. gnome_dialog_close_hides(GNOME_DIALOG(dialog), TRUE);
  89. gtk_container_set_border_width(GTK_CONTAINER(GNOME_DIALOG(dialog)->vbox),
  90. GNOME_PAD);
  91. gtk_widget_show_all(dialog);
  92. /* Grab focus */
  93. if (grab_server)
  94. XGrabServer(GDK_DISPLAY());
  95. if (grab_pointer && gdk_pointer_grab(dialog->window, TRUE, 0,
  96. NULL, NULL, GDK_CURRENT_TIME))
  97. goto nograb;
  98. if (gdk_keyboard_grab(dialog->window, FALSE, GDK_CURRENT_TIME))
  99. goto nograbkb;
  100. /* Make <enter> close dialog */
  101. gnome_dialog_editable_enters(GNOME_DIALOG(dialog), GTK_EDITABLE(entry));
  102. /* Run dialog */
  103. result = gnome_dialog_run(GNOME_DIALOG(dialog));
  104. /* Ungrab */
  105. if (grab_server)
  106. XUngrabServer(GDK_DISPLAY());
  107. if (grab_pointer)
  108. gdk_pointer_ungrab(GDK_CURRENT_TIME);
  109. gdk_keyboard_ungrab(GDK_CURRENT_TIME);
  110. gdk_flush();
  111. /* Report passphrase if user selected OK */
  112. passphrase = gtk_entry_get_text(GTK_ENTRY(entry));
  113. if (result == 0)
  114. puts(passphrase);
  115. /* Zero passphrase in memory */
  116. memset(passphrase, '\0', strlen(passphrase));
  117. gtk_entry_set_text(GTK_ENTRY(entry), passphrase);
  118. gnome_dialog_close(GNOME_DIALOG(dialog));
  119. return (result == 0 ? 0 : -1);
  120. /* At least one grab failed - ungrab what we got, and report
  121. the failure to the user. Note that XGrabServer() cannot
  122. fail. */
  123. nograbkb:
  124. gdk_pointer_ungrab(GDK_CURRENT_TIME);
  125. nograb:
  126. if (grab_server)
  127. XUngrabServer(GDK_DISPLAY());
  128. gnome_dialog_close(GNOME_DIALOG(dialog));
  129. report_failed_grab();
  130. return (-1);
  131. }
  132. int
  133. main(int argc, char **argv)
  134. {
  135. char *message;
  136. int result;
  137. gnome_init("GNOME ssh-askpass", "0.1", argc, argv);
  138. if (argc == 2)
  139. message = argv[1];
  140. else
  141. message = "Enter your OpenSSH passphrase:";
  142. setvbuf(stdout, 0, _IONBF, 0);
  143. result = passphrase_dialog(message);
  144. return (result);
  145. }