/* * C o p y r i g h t *(also read COPYING)* * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2002 * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "gui.h" static gint exec_su_failed (gpointer user_data) { #ifdef DEBUG printf("static gint exec_su_failed (gpointer user_data)\n"); #endif gnome_dialog_run_and_close (GNOME_DIALOG (gnome_error_dialog ( _("Timeout when trying to execute 'su'.")))); gtk_exit (EXIT_ERROR); return FALSE; } static void su_has_died (GtkWidget *term, gpointer user_data) { gchar *buf; gint len; #ifdef DEBUG printf("static void su_has_died (GtkWidget *widget, gpointer user_data)\n"); #endif buf = zvt_term_get_buffer (ZVT_TERM (term), &len, VT_SELTYPE_CHAR, 3, 1, 200, 1); if (strlen(buf) > 1) { gchar *display; display = g_strdup_printf("Gnome Xsu: %s ", buf); gnome_dialog_run_and_close (GNOME_DIALOG (gnome_error_dialog (_(display)))); gtk_exit(EXIT_ERROR); } else { gtk_exit(EXIT_CORRECT); } while (gtk_events_pending ()) gtk_main_iteration (); gtk_main_quit (); } void xsu_perform() { /* Some code from gnomesu, thanks to Hongli Lai */ GtkWidget *term; guint timeout, su_d13; int i; /* No gint. We will use this in a non-gnome thread */ gchar *password_return, *username=gtk_entry_get_text (GTK_ENTRY (gtk_user_textbox)), *password=gtk_entry_get_text (GTK_ENTRY (gtk_password_textbox)), *command=gtk_entry_get_text (GTK_ENTRY (gtk_command_textbox)); #ifdef DEBUG printf("void xsu_perform()\n"); #endif /* 0.2.1 * Minor security fix. Password would remain in memory if we don't clean the password textbox. */ gtk_entry_set_text(GTK_ENTRY(gtk_password_textbox),""); gtk_widget_hide (gtk_xsu_window); if (password == NULL) return; term = zvt_term_new (); i = zvt_term_forkpty (ZVT_TERM (term), ZVT_TERM_DO_UTMP_LOG | ZVT_TERM_DO_WTMP_LOG); su_d13 = gtk_signal_connect (GTK_OBJECT (term), "child_died", GTK_SIGNAL_FUNC (su_has_died), NULL); if (i == 0) { gchar *buffer; /* xsu 0.2.1 * Option to set the DISPLAY environment system() has been replaced with execlp() xsu 0.2.2 execlp() has been replaced with execl() This also fixes the problem that the zvt widget could not get the child_died signal. */ if (set_display_env) { buffer = g_strdup_printf("%s%s;%s", SET_DISPL_ENV, displ_host, command); /* xsu 0.2.4 * Memleak fix: Free display_host and command */ g_free(displ_host); g_free(command); } else { buffer = g_strdup_printf("%s", command); /* xsu 0.2.4 * Memleak fix: Free command */ g_free(command); } /* xsu 0.2.2 * Security issue noticed by Havoc Security fix, execlp exports the PATH which is a security problem. SU_PATH contains the full path of the su binary found by the configure script. */ /* buffer with " and/or ' gives some problems. */ /* buffer = g_strdup_printf("%s - %s -c %s",SU_PATH, username, buffer); */ /* su - username -c command */ execl(SU_PATH, "-", username, "-c", buffer, NULL); /* We are not a gnome-application anymore but under control of su */ /*username=g_strdup_printf("%s@localhost"); execl("/usr/bin/ssh", username, "-s", buffer, NULL);*/ /* I tried using the SSH client for this. But it then gives an error that it has been put in the background after auth. */ perror ("Could not exec\n"); exit (EXIT_ERROR); } else if (i == -1) { perror ("ERROR: unable to fork:"); gtk_exit (EXIT_ERROR); } /* xsu 0.2.4 * Memleak fix: Free username */ g_free(username); timeout = gtk_timeout_add (SU_DELAY, exec_su_failed, NULL); while (1) { char *buf; int len; buf = zvt_term_get_buffer (ZVT_TERM (term), &len, VT_SELTYPE_CHAR, 0, 0, strlen (SU_PWD_OUT), 0); if (strcmp (buf, SU_PWD_OUT) == 0) { gtk_timeout_remove (timeout); g_free (buf); break; } g_free (buf); while (gtk_events_pending ()) gtk_main_iteration (); usleep (5); } password_return = g_strdup_printf ("%s\n", password); /* 0.2.2 * Minor security fix, clear the password from memory */ password = memset (password, 0, strlen (password)); zvt_term_writechild (ZVT_TERM (term), password_return, strlen (password_return)); password_return = memset (password_return, 0, strlen (password_return)); g_free (password_return); g_free (password); password_return = NULL; password = NULL; gtk_signal_disconnect (GTK_OBJECT (term), su_d13); gtk_signal_connect (GTK_OBJECT (term), "child_died", GTK_SIGNAL_FUNC (su_has_died), NULL); gtk_main(); return; } void on_gtk_password_textbox_activate (GtkButton *button, gpointer user_data) { #ifdef DEBUG printf("on_gtk_user_textbox_activate (GtkButton *button, gpointer user_data)\n"); #endif xsu_perform(); } void on_gtk_user_textbox_activate (GtkButton *button, gpointer user_data) { #ifdef DEBUG printf("on_gtk_user_textbox_activate (GtkButton *button, gpointer user_data)\n"); #endif gtk_widget_grab_focus (gtk_password_textbox); } void on_gtk_command_textbox_activate (GtkButton *button, gpointer user_data) { #ifdef DEBUG printf("on_gtk_command_textbox_activate (GtkButton *button, gpointer user_data)\n"); #endif if (GTK_WIDGET_VISIBLE(gtk_user_textbox)) gtk_widget_grab_focus (gtk_user_textbox); else gtk_widget_grab_focus (gtk_password_textbox); } void on_gtk_cancel_button_clicked (GtkButton *button, gpointer user_data) { #ifdef DEBUG printf("on_gtk_cancel_button_clicked (GtkButton *button, gpointer user_data)\n"); #endif exit(EXIT_ERROR); } void on_gtk_ok_button_clicked (GtkButton *button, gpointer user_data) { #ifdef DEBUG printf("on_gtk_ok_button_clicked (GtkButton *button, gpointer user_data)\n"); #endif xsu_perform(); } GtkWidget* create_gtk_xsu_window (void) { tooltips = gtk_tooltips_new (); gtk_xsu_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_widget_set_name (gtk_xsu_window, "gtk_xsu_window"); gtk_object_set_data (GTK_OBJECT (gtk_xsu_window), "gtk_xsu_window", gtk_xsu_window); gtk_tooltips_set_tip (tooltips, gtk_xsu_window, _(NAME " " VERSION " by " AUTHOR), NULL); if (title_in) gtk_window_set_title (GTK_WINDOW (gtk_xsu_window), arg_title); else gtk_window_set_title (GTK_WINDOW (gtk_xsu_window), _(NAME " " VERSION)); gtk_window_set_position (GTK_WINDOW (gtk_xsu_window), GTK_WIN_POS_CENTER); gtk_window_set_policy (GTK_WINDOW (gtk_xsu_window), FALSE, FALSE, FALSE); gtk_window_table = gtk_table_new (6, 2, FALSE); gtk_widget_set_name (gtk_window_table, "gtk_window_table"); gtk_widget_ref (gtk_window_table); gtk_object_set_data_full (GTK_OBJECT (gtk_xsu_window), "gtk_window_table", gtk_window_table, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (gtk_window_table); gtk_container_add (GTK_CONTAINER (gtk_xsu_window), gtk_window_table); gtk_password_label = gtk_label_new (_("Username : ")); gtk_widget_set_name (gtk_password_label, "gtk_password_label"); gtk_widget_ref (gtk_password_label); gtk_object_set_data_full (GTK_OBJECT (gtk_xsu_window), "gtk_password_label", gtk_password_label, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (gtk_password_label); gtk_table_attach (GTK_TABLE (gtk_window_table), gtk_password_label, 0, 1, 2, 3, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_misc_set_alignment (GTK_MISC (gtk_password_label), 4.91738e-07, 0); gtk_misc_set_padding (GTK_MISC (gtk_password_label), 24, 8); gtk_commandtxt_label = gtk_label_new (_("Command :")); gtk_widget_set_name (gtk_commandtxt_label, "gtk_commandtxt_label"); gtk_widget_ref (gtk_commandtxt_label); gtk_object_set_data_full (GTK_OBJECT (gtk_xsu_window), "gtk_commandtxt_label", gtk_commandtxt_label, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (gtk_commandtxt_label); gtk_table_attach (GTK_TABLE (gtk_window_table), gtk_commandtxt_label, 0, 1, 1, 2, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_misc_set_alignment (GTK_MISC (gtk_commandtxt_label), 0, 7.45058e-09); gtk_misc_set_padding (GTK_MISC (gtk_commandtxt_label), 24, 6); if (message_in) gtk_text_label = gtk_label_new (_(arg_message)); else gtk_text_label = gtk_label_new (_("The action you requested requires root\npriveleges.\nPlease enter the correct password for it\nbelow and press [Return] or click OK.")); gtk_widget_set_name (gtk_text_label, "gtk_text_label"); gtk_widget_ref (gtk_text_label); gtk_object_set_data_full (GTK_OBJECT (gtk_xsu_window), "gtk_text_label", gtk_text_label, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (gtk_text_label); gtk_table_attach (GTK_TABLE (gtk_window_table), gtk_text_label, 1, 2, 0, 1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_label_set_justify (GTK_LABEL (gtk_text_label), GTK_JUSTIFY_LEFT); gtk_misc_set_alignment (GTK_MISC (gtk_text_label), 0, 7.45058e-09); gtk_misc_set_padding (GTK_MISC (gtk_text_label), 9, 14); gtk_keys_pixmap = gnome_pixmap_new_from_xpm_d (keys_xpm); gtk_widget_set_name (gtk_keys_pixmap, "gtk_keys_pixmap"); gtk_widget_ref (gtk_keys_pixmap); gtk_object_set_data_full (GTK_OBJECT (gtk_xsu_window), "gtk_keys_pixmap", gtk_keys_pixmap, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (gtk_keys_pixmap); gtk_table_attach (GTK_TABLE (gtk_window_table), gtk_keys_pixmap, 0, 1, 0, 1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (GTK_FILL), 0, 0); gtk_password_textbox = gtk_entry_new (); gtk_widget_set_name (gtk_password_textbox, "gtk_password_textbox"); gtk_widget_ref (gtk_password_textbox); gtk_object_set_data_full (GTK_OBJECT (gtk_xsu_window), "gtk_password_textbox", gtk_password_textbox, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (gtk_password_textbox); gtk_table_attach (GTK_TABLE (gtk_window_table), gtk_password_textbox, 1, 2, 3, 4, (GtkAttachOptions) (GTK_EXPAND), (GtkAttachOptions) (0), 0, 0); gtk_widget_set_usize (gtk_password_textbox, 230, -2); gtk_tooltips_set_tip (tooltips, gtk_password_textbox, _("Type the password here"), NULL); gtk_entry_set_visibility (GTK_ENTRY (gtk_password_textbox), FALSE); gtk_user_textbox = gtk_entry_new (); gtk_widget_set_name (gtk_user_textbox, "gtk_user_textbox"); gtk_widget_ref (gtk_user_textbox); gtk_object_set_data_full (GTK_OBJECT (gtk_xsu_window), "gtk_user_textbox", gtk_user_textbox, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (gtk_user_textbox); gtk_table_attach (GTK_TABLE (gtk_window_table), gtk_user_textbox, 1, 2, 2, 3, (GtkAttachOptions) (0), (GtkAttachOptions) (0), 0, 0); gtk_widget_set_usize (gtk_user_textbox, 230, -2); gtk_tooltips_set_tip (tooltips, gtk_user_textbox, _("Type the username here"), NULL); gtk_command_textbox = gtk_entry_new (); gtk_widget_set_name (gtk_command_textbox, "gtk_command_textbox"); gtk_widget_ref (gtk_command_textbox); gtk_object_set_data_full (GTK_OBJECT (gtk_xsu_window), "gtk_command_textbox", gtk_command_textbox, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (gtk_command_textbox); gtk_table_attach (GTK_TABLE (gtk_window_table), gtk_command_textbox, 1, 2, 1, 2, (GtkAttachOptions) (GTK_EXPAND), (GtkAttachOptions) (0), 0, 0); gtk_widget_set_usize (gtk_command_textbox, 230, -2); gtk_tooltips_set_tip (tooltips, gtk_command_textbox, _("Type the command here"), NULL); /* xsu 0.2.3 * The buttons and their size in other languages have been fixed. This bug was filed by Robert Millan */ gtk_hbox = gtk_hbox_new (FALSE, 0); gtk_widget_show (gtk_hbox); gtk_table_attach (GTK_TABLE (gtk_window_table), gtk_hbox, 1, 2, 5, 6, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 7); gtk_utilbox = gtk_hbutton_box_new(); gtk_box_pack_start(GTK_BOX(gtk_hbox), gtk_utilbox, FALSE, TRUE, 14); gtk_button_box_set_layout(GTK_BUTTON_BOX(gtk_utilbox), gnome_preferences_get_button_layout()); gtk_button_box_set_spacing(GTK_BUTTON_BOX(gtk_utilbox), GNOME_PAD); gtk_widget_show(gtk_utilbox); gtk_ok_button = gnome_stock_button (GNOME_STOCK_BUTTON_OK); gtk_box_pack_start(GTK_BOX(gtk_utilbox), gtk_ok_button, FALSE, FALSE, 5); GTK_WIDGET_SET_FLAGS(gtk_ok_button, GTK_CAN_DEFAULT); gtk_widget_grab_default(gtk_ok_button); gtk_widget_show (gtk_ok_button); gtk_tooltips_set_tip (tooltips, gtk_ok_button, _("Press this button when finished"), NULL); gtk_cancel_button = gnome_stock_button (GNOME_STOCK_BUTTON_CANCEL); gtk_box_pack_start(GTK_BOX(gtk_utilbox), gtk_cancel_button, FALSE, FALSE, 5); gtk_widget_show (gtk_cancel_button); GTK_WIDGET_SET_FLAGS(gtk_cancel_button, GTK_CAN_DEFAULT); gtk_tooltips_set_tip (tooltips, gtk_cancel_button, _("Press this button to Cancel"), NULL); gtk_password_label = gtk_label_new (_("Password :")); gtk_widget_set_name (gtk_txtuser_label, "gtk_password_label"); gtk_widget_ref (gtk_password_label); gtk_object_set_data_full (GTK_OBJECT (gtk_xsu_window), "gtk_password_label", gtk_password_label, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (gtk_password_label); gtk_table_attach (GTK_TABLE (gtk_window_table), gtk_password_label, 0, 1, 3, 4, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0); gtk_misc_set_alignment (GTK_MISC (gtk_password_label), 0, 7.45058e-09); gtk_misc_set_padding (GTK_MISC (gtk_password_label), 24, 2); gtk_separator_one = gtk_hseparator_new (); gtk_widget_set_name (gtk_separator_one, "gtk_separator_one"); gtk_widget_ref (gtk_separator_one); gtk_object_set_data_full (GTK_OBJECT (gtk_xsu_window), "gtk_separator_one", gtk_separator_one, (GtkDestroyNotify) gtk_widget_unref); gtk_widget_show (gtk_separator_one); gtk_table_attach (GTK_TABLE (gtk_window_table), gtk_separator_one, 0, 2, 4, 5, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (GTK_FILL), 0, 8); gtk_signal_connect (GTK_OBJECT (gtk_user_textbox), "activate", GTK_SIGNAL_FUNC (on_gtk_user_textbox_activate), gtk_user_textbox); gtk_signal_connect (GTK_OBJECT (gtk_password_textbox), "activate", GTK_SIGNAL_FUNC (on_gtk_password_textbox_activate), gtk_password_textbox); gtk_signal_connect (GTK_OBJECT (gtk_command_textbox), "activate", GTK_SIGNAL_FUNC (on_gtk_command_textbox_activate), gtk_command_textbox); gtk_signal_connect (GTK_OBJECT (gtk_cancel_button), "clicked", GTK_SIGNAL_FUNC (on_gtk_cancel_button_clicked), NULL); gtk_signal_connect (GTK_OBJECT (gtk_ok_button), "clicked", GTK_SIGNAL_FUNC (on_gtk_ok_button_clicked), NULL); gtk_object_set_data (GTK_OBJECT (gtk_xsu_window), "tooltips", tooltips); return gtk_xsu_window; } int main (int argc, char *argv[]) { GtkWidget *gtk_xsu_window; gchar *arg_command, *arg_username, *arg_iconfile; gint x; gboolean command_in=FALSE, username_in=FALSE, icon_in=FALSE, dis_textboxes=FALSE, hide_textboxes=FALSE, endofargs=FALSE, first=TRUE; /* Nope..no popt, maybe next time. Oh and getopt stuff is not the same in *BSD as with GNU getopt, so I don't immedialty feel like wanting to change this option parsing :-\. Some problems about parsing the arguments have been filed by Jeff Licquia . I added the "--" option which stops parsing. (Only " and \ have to be escaped of course, this depends on your shell) */ for (x=0; x