patches/gnome-system-tools-02-forkpty.diff
author yippi
Fri, 14 Jan 2011 18:51:32 +0000
branchgnome-2-30
changeset 21308 9a98b77f065c
parent 15569 f5ee708e987d
child 21632 3c9a1f6736f7
permissions -rw-r--r--
2010-01-14 Brian Cameron <[email protected]> * patches/gksu-02-gksu.diff, patches/libgksu-05-rbac-support.diff: Fix so that gksu runs programs with pfexec if possible and fills in the role with a value, if available. * patches/gnome-system-tools-02-forkpty.diff: No longer hardcode user to "root".

--- gnome-system-tools-2.14.0/configure.in-orig	2010-12-10 13:05:34.351438641 -0600
+++ gnome-system-tools-2.14.0/configure.in	2010-12-10 13:05:56.067017722 -0600
@@ -144,8 +144,7 @@ dnl ====================================
 case $host_os in
 solaris*)
 PKG_CHECK_MODULES(GKSU,[
-			   libgksu1.2 >= 1.3.1,
-			   libgksuui1.0 >= 1.0
+			   libgksu2
 			   ],[
 			AC_DEFINE(HAVE_GKSU, 1, [define if you have Gksu library])])
     ;;
--- gnome-system-tools-2.14.0/src/common/gst-auth.c-orig	2010-12-10 11:55:03.932806214 -0600
+++ gnome-system-tools-2.14.0/src/common/gst-auth.c	2010-12-10 13:23:39.583198213 -0600
@@ -44,8 +44,15 @@
 # include <errno.h>
 # include <libutil.h>
 #else
+#ifdef __sun
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#else
 #include <pty.h>
 #endif
+#endif
+
+#include <gksu.h>
 
 #include "gst-auth.h"
 #include "gst-tool.h"
@@ -53,6 +60,10 @@
 
 #define GST_AUTH_RESPONSE_NP 1
 
+#ifdef __sun
+#define EMBEDDED_SU "/usr/lib/embedded_su"
+#endif /* __sun */
+
 static int root;			/* if we are root, no password is
 					   required */
 
@@ -61,7 +72,7 @@ gst_auth_display_error_message (GstTool 
 {
 	GtkWidget *error_dialog;
 
-	error_dialog = gtk_message_dialog_new (GTK_WINDOW (tool->main_dialog),
+	error_dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (tool->main_dialog),
 					       GTK_DIALOG_MODAL,
 					       GTK_MESSAGE_ERROR,
 					       GTK_BUTTONS_CLOSE,
@@ -118,6 +129,122 @@ gst_auth_wait_child (GstTool *tool)
 	return TRUE;	
 }
 
+#ifdef __sun
+/* forkpty() rmplacement for Solaris.
+ * This ignore the last two arguments
+ * for the moment
+ */
+#ifdef NOPTY
+/*
+ * This is implemented using pipes instead of pseudo tty to avoid
+ * bug 4907342.
+ */
+static
+int forkpty (int *amaster, char *name, void *unused1, void *unused2)
+{
+	pid_t pid;
+	int pp[2];
+
+	pipe (pp);
+	pid = fork ();
+	switch (pid)
+	{
+	case -1: /* Error */
+		return -1;
+	case 0: /* Child */
+		if (setsid() < 0)
+			return -1;
+		close (pp[1]);
+		dup2 (pp[0], 0);
+		return 0;
+	default: /* Parent */
+		close (pp[0]);
+		*amaster = pp[1];
+		return pid;
+	}
+
+	return -1;
+}
+#else
+int forkpty (int *amaster, char *name, void *unused1, void *unused2)
+{
+	int master, slave, fd;
+	char *slave_name;
+	pid_t pid;
+	void (*sig_saved)(int);
+
+	master = open("/dev/ptmx", O_RDWR | O_NOCTTY);
+	if (master < 0)
+		return -1;
+
+	sig_saved = signal (SIGCHLD, SIG_DFL);
+	if (grantpt (master) < 0)
+	{
+		signal (SIGCHLD, sig_saved);
+		close (master);
+		return -1;
+	}
+
+	if (unlockpt (master) < 0)
+	{
+		signal (SIGCHLD, sig_saved);
+		close (master);
+		return -1;
+	}
+	signal (SIGCHLD, sig_saved);
+
+	slave_name = ptsname (master);
+	if (slave_name == NULL)
+	{
+		close (master);
+		return -1;
+	}
+
+	slave = open (slave_name, O_RDWR | O_NOCTTY);
+	if (slave < 0)
+	{
+		close (master);
+		return -1;
+	}
+
+	if (ioctl (slave, I_PUSH, "ptem") < 0
+	    || ioctl (slave, I_PUSH, "ldterm") < 0
+	    || ioctl (slave, I_PUSH, "ttcompat") < 0)
+	{
+		close (slave);
+		close (master);
+		return -1;
+	}
+
+	if (amaster)
+		*amaster = master;
+
+	if (name)
+		strcpy (name, slave_name);
+
+	pid = fork ();
+	switch (pid)
+	{
+	case -1: /* Error */
+		return -1;
+	case 0: /* Child */
+		if (setsid() < 0)
+			return -1;
+		close (master);
+		dup2 (slave, STDIN_FILENO);
+		dup2 (slave, STDOUT_FILENO);
+		dup2 (slave, STDERR_FILENO);
+		return 0;
+	default: /* Parent */
+		close (slave);
+		return pid;
+	}
+
+	return -1;
+}
+#endif
+#endif
+
 /* runs a term with su in it */
 static void
 gst_auth_run_term (GstTool *tool, gchar *args[])
@@ -177,8 +304,16 @@ gst_auth_get_auth_required (GstTool *too
 	gchar        *s, *str;
 	gint          ret;
 
+#if defined(__sun) && defined (EMBEDDED_SU)
+        gst_tool_write_to_backend(tool, (gchar*)".\n"); /* Send empty text block to start conversation */
+#endif
+
 	while (!cont) {
+#if defined(__sun) && defined (EMBEDDED_SU)
+		s   = gst_tool_read_from_backend (tool, "SUCCESS", "\n.\n", NULL); /* Look for end of text block - a period (.) on a line by itself */
+#else
 		s   = gst_tool_read_from_backend (tool, "assword:", "/no)?", "\n", NULL);
+#endif /* __sun */
 		str = g_ascii_strup (s, -1);
 
 		/* FIXME: hope that someday we can get rid of this ssh output string parsing */
@@ -189,6 +324,11 @@ gst_auth_get_auth_required (GstTool *too
 			/* it's asking for the password */
 			cont = TRUE;
 			ret  = GST_AUTH_PASSWORD;
+#if defined(__sun) && defined (EMBEDDED_SU)
+		} else if (g_strrstr (str, "SUCCESS") != NULL) {
+			cont = TRUE;
+			ret  = GST_AUTH_PASSWORDLESS;
+#endif /* __sun */
 		} else if (g_strrstr (str, "\n") != NULL) {
 			/* this is the last case to test, it's the CR
 			   used to synchronize communication */
@@ -276,6 +416,216 @@ gst_auth_read_output (GstTool *tool)
 	g_free (b);
 }
 
+#ifdef HAVE_GKSU
+static void
+gk_dialog (GtkMessageType type, gchar *format, ...)
+{
+  GtkWidget *diag_win;
+
+  va_list ap;
+  gchar *msg;
+
+  va_start(ap, format);
+  msg = g_strdup_vprintf(format, ap);
+  va_end(ap);
+
+  diag_win = gtk_message_dialog_new_with_markup (NULL, GTK_DIALOG_MODAL,
+                                                 type, GTK_BUTTONS_CLOSE,
+                                                 msg);
+
+  gtk_signal_connect_object (GTK_OBJECT(diag_win), "delete_event",
+                             GTK_SIGNAL_FUNC(gtk_main_quit),
+                             NULL);
+  gtk_window_set_position (GTK_WINDOW(diag_win), GTK_WIN_POS_CENTER);
+  gtk_window_set_resizable (GTK_WINDOW(diag_win), FALSE);
+
+  gtk_widget_show_all (diag_win);
+
+  // we "raise" the window because there is a race here for
+  // focus-follow-mouse and auto-raise WMs that may put the window
+  // in the background and confuse users
+  gtk_window_set_keep_above(GTK_WINDOW (diag_win), TRUE);
+  // reset cursor
+  gdk_window_set_cursor(diag_win->window, gdk_cursor_new(GDK_LEFT_PTR));
+
+
+  gtk_dialog_run (GTK_DIALOG(diag_win));
+
+  g_free (msg);
+
+  gtk_widget_destroy (diag_win);
+}
+
+void
+response_ok_cb (GtkWidget *w, gpointer data)
+{
+  GtkWidget *dialog = (GtkWidget*)data;
+
+  gtk_dialog_response (GTK_DIALOG(dialog),
+                       GTK_RESPONSE_OK);
+}
+
+static gboolean
+focus_out_cb (GtkWidget *widget, GdkEventFocus *event, gpointer user_data)
+{
+  gtk_window_present (GTK_WINDOW(widget));
+  return TRUE;
+}
+
+void
+request_command_and_user (GksuContext *context)
+{
+  GtkWidget *dialog;
+  GtkWidget *hbox;
+  GtkWidget *lvbox;
+  GtkWidget *rvbox;
+  GtkWidget *image;
+
+  GtkWidget *label_cmd;
+  GtkWidget *entry_cmd;
+
+  GtkWidget *label_user;
+  GtkWidget *entry_user;
+
+  AtkObject *atk_user_label;
+  AtkObject *atk_user_entry;
+  AtkObject *atk_command_label;
+  AtkObject *atk_command_entry;
+
+  /* advanced stuff */
+  GtkWidget *advanced_button;
+
+  gint response;
+
+  gchar *tmp = NULL;
+
+  dialog = gtk_dialog_new_with_buttons (_("Run program"), NULL, 0,
+                                        GTK_STOCK_CANCEL,
+                                        GTK_RESPONSE_CANCEL,
+                                        GTK_STOCK_OK,
+                                        GTK_RESPONSE_OK,
+                                        NULL);
+
+  /* make sure that our window will always have the focus */
+  g_signal_connect (G_OBJECT(dialog), "focus-out-event",
+                    G_CALLBACK(focus_out_cb), NULL);
+
+  gtk_dialog_set_has_separator (GTK_DIALOG(dialog), FALSE);
+
+  /* horizontal box */
+  hbox = gtk_hbox_new (FALSE, 4);
+  gtk_container_set_border_width (GTK_CONTAINER(hbox), 5);
+  gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox),
+                      hbox, TRUE, TRUE, 2);
+
+  /* left vertical box */
+  lvbox = gtk_vbox_new (FALSE, 2);
+  gtk_box_pack_start (GTK_BOX(hbox), lvbox, TRUE, TRUE, 0);
+
+  /* command */
+  label_cmd = gtk_label_new (_("Run:"));
+  gtk_label_set_justify (GTK_LABEL(label_cmd), GTK_JUSTIFY_LEFT);
+  gtk_box_pack_start (GTK_BOX(lvbox), label_cmd, TRUE, TRUE, 0);
+
+  entry_cmd = gtk_entry_new ();
+  gtk_signal_connect (GTK_OBJECT(entry_cmd), "activate",
+                      GTK_SIGNAL_FUNC(response_ok_cb),
+                      dialog);
+  gtk_box_pack_start (GTK_BOX(lvbox), entry_cmd, TRUE, TRUE, 0);
+
+  if (context->command)
+    {
+      gtk_entry_set_text (GTK_ENTRY (entry_cmd), context->command);
+      gtk_editable_set_editable (GTK_EDITABLE (entry_cmd), FALSE);
+      gtk_widget_set_sensitive (entry_cmd, FALSE);
+    }
+
+  atk_command_label = gtk_widget_get_accessible (label_cmd);
+  atk_command_entry = gtk_widget_get_accessible (entry_cmd);
+  atk_object_add_relationship (atk_command_label, ATK_RELATION_LABEL_FOR,
+    atk_command_entry);
+  atk_object_add_relationship (atk_command_entry, ATK_RELATION_LABELLED_BY,
+    atk_command_label);
+
+  /* user name */
+  /* SUN_BRANDING label */
+  label_user = gtk_label_new (_("As user or role:"));
+  gtk_label_set_justify (GTK_LABEL(label_user), GTK_JUSTIFY_LEFT);
+  gtk_box_pack_start (GTK_BOX(lvbox), label_user, TRUE, TRUE, 0);
+
+  entry_user = gtk_entry_new ();
+  gtk_signal_connect (GTK_OBJECT(entry_user), "activate",
+                      GTK_SIGNAL_FUNC(response_ok_cb),
+                      dialog);
+
+  if (context->user)
+    {
+      gtk_entry_set_text (GTK_ENTRY (entry_user), context->user);
+    }
+
+  atk_user_label = gtk_widget_get_accessible (label_user);
+  atk_user_entry = gtk_widget_get_accessible (entry_user);
+  atk_object_add_relationship (atk_user_label, ATK_RELATION_LABEL_FOR,
+    atk_user_entry);
+  atk_object_add_relationship (atk_user_entry, ATK_RELATION_LABELLED_BY,
+    atk_user_label);
+
+  gtk_box_pack_start (GTK_BOX(lvbox), entry_user, TRUE, TRUE, 0);
+
+  /* right vertical box */
+  rvbox = gtk_vbox_new (FALSE, 2);
+  gtk_box_pack_start (GTK_BOX(hbox), rvbox, TRUE, TRUE, 0);
+
+  /* image */
+  image = gtk_image_new_from_file ("/usr/share/pixmaps/gksu-icon.png");
+  gtk_box_pack_start (GTK_BOX(rvbox), image, TRUE, TRUE, 0);
+
+#if 0
+  /* advanced button */
+  advanced_button = gtk_button_new_with_mnemonic (_("_Advanced"));
+  g_signal_connect (G_OBJECT(advanced_button), "clicked",
+                    G_CALLBACK(show_hide_advanced), context);
+  gtk_box_pack_start (GTK_BOX(rvbox), advanced_button, TRUE, FALSE, 0);
+#endif
+
+  /* let the magic begin! */
+  gtk_widget_show_all (dialog);
+
+  while (TRUE)
+    {
+      response = gtk_dialog_run (GTK_DIALOG(dialog));
+
+      switch (response)
+        {
+        case GTK_RESPONSE_CANCEL:
+        case GTK_RESPONSE_DELETE_EVENT:
+        case GTK_RESPONSE_NONE:
+          exit (0);
+        }
+
+      tmp = gtk_editable_get_chars (GTK_EDITABLE(entry_cmd), 0, -1);
+      if (tmp)
+        {
+          gksu_context_set_command (context, tmp);
+          g_free (tmp);
+        }
+
+      tmp = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry_user)));
+      if (tmp)
+        {
+          gksu_context_set_user (context, tmp);
+          g_free (tmp);
+        }
+
+      if (strcmp (gksu_context_get_user (context), ""))
+        {
+          gtk_widget_destroy (dialog);
+          break;
+        }
+    }
+}
+#endif /* HAVE_GKSU */
+
 /* it does authentication, first of all it runs su (just to ensure that it's completely run
  * when password is sent), then asks for password and sends it to su (if you want to run it
  * with root privileges)
@@ -286,7 +636,115 @@ gst_auth_do_authentication (GstTool *too
 	gchar *password;
 	gint result;
 	struct termios t;
+	GksuContext *context;
+	gint8 exit_status = -1;
+	GError *error = NULL;
+	gint response;
+	gchar *primary_text = NULL;
+	gchar *secondary_text = NULL;
+	gint count;
+
+	char **gconf_argv;
+	char *gconf_cmd;
+	char *std_output;
+	char *std_error;
+    	struct passwd *pwentry;
+
+#ifdef HAVE_GKSU
+	context = gksu_context_new ();
+	gksu_context_set_child_no_a11y (context, TRUE);
+#ifdef GST_DEBUG
+	gksu_context_set_debug (context, TRUE);
+#endif
 
+	/*
+	 * Disable the grab if accessibility is on, since it causes issues
+	 * for GOK, dasher and other AT programs where the user may need to interact
+	 * with other GUI programs.  Note that we call gconftool-2 instead of using
+	 * GConf interfaces since it seems using GConf in gksu causes problems for
+	 * a11y if you run a program with gksu that has a GUI.  The launched program
+	 * will not work with a11y if gksu uses GConf, but calling gconftool-2 works.
+	 */
+	gconf_cmd = g_strdup ("/usr/bin/gconftool-2 --get /desktop/gnome/interface/accessibility");
+	error = NULL;
+	std_output = NULL;
+	std_error = NULL;
+
+	g_shell_parse_argv (gconf_cmd, NULL, &gconf_argv, &error);
+
+	error = NULL;
+
+	g_spawn_sync (NULL,
+                gconf_argv,
+                NULL,
+                0,
+                NULL,
+                NULL,
+                &std_output,
+                &std_error,
+                NULL,
+                &error);
+
+	g_strchomp (std_output);
+
+	if (std_output != NULL && strcmp (std_output, "true") == 0)
+		gksu_context_set_grab (context, FALSE);
+	else
+		gksu_context_set_grab (context, TRUE);
+
+	gksu_context_set_wait_for_child_to_exit (context, FALSE);
+
+	context->command = g_strdup (args[3]);
+	if (gksu_context_try_need_password (context))
+	{
+		request_command_and_user (context);
+	}
+
+	pwentry = getpwnam (gksu_context_get_user (context));
+
+	if (!pwentry)
+	{
+		primary_text   = g_strdup_printf (_("User %s does not exist"), gksu_context_get_user (context));
+		gst_auth_display_error_message (tool, primary_text, NULL);
+
+		g_free (primary_text);
+		exit (0);
+	}
+
+	gksu_su_fuller (context,
+			NULL, NULL,
+			NULL, NULL,
+			&exit_status,
+			&error);
+
+	if (error && (error->code != GKSU_ERROR_CANCELED))
+	{
+		if (context->alert != NULL)
+		{
+			primary_text = context->alert;
+		} else {
+			primary_text   = g_strdup_printf (_("Authentication failed"));
+		}
+
+		secondary_text = g_strdup (error->message);
+
+		gst_auth_display_error_message (tool, primary_text, secondary_text);
+
+		free (primary_text);
+		g_free (secondary_text);
+		exit (0);
+	}
+
+	tool->read_fd = gksu_context_get_child_stdin_fd (context);
+	tool->write_fd = gksu_context_get_child_stdout_fd (context);
+	tool->backend_pid = gksu_context_get_child_pid (context);
+	tool->timeout_id   = g_timeout_add (1000, (GSourceFunc) gst_auth_wait_child, tool);
+#ifdef GST_DEBUG
+	fprintf (stderr, "read_fd = %d, write_fd = %d\n", tool->read_fd, tool->write_fd);
+#endif
+	tool->read_stream = gksu_context_get_child_stdin_file (context);
+	tool->write_stream = gksu_context_get_child_stdout_file (context);
+#else
 	gst_auth_run_term (tool, args);
 	result = gst_auth_get_auth_required (tool);
 
@@ -296,7 +754,14 @@ gst_auth_do_authentication (GstTool *too
 
 		if (strlen (password) > 0)
 			memset (password, 0, strlen (password));
+#if defined(__sun) && defined (EMBEDDED_SU) && 0
+                {
+                    gchar *s  = gst_tool_read_from_backend (tool, "\n.\n", "SUCCESS", "\n", NULL);
+                    g_free(s);
+                }
+#endif /* __sun */
 	}
+#endif
 
 	tool->root_access = ROOT_ACCESS_REAL;
 
@@ -368,7 +833,7 @@ gst_auth_do_su_authentication (GstTool *
 	GString *command;
 
 	command = g_string_new (NULL);
-	gst_auth_save_locale   (command);
+//	gst_auth_save_locale   (command);
 	command = g_string_append (command, tool->script_path);
 	command = g_string_append (command, " --report");
 
@@ -378,7 +843,11 @@ gst_auth_do_su_authentication (GstTool *
 	}
 
 	/* these are the su args */
+#if defined(__sun) && defined (EMBEDDED_SU)
+	su_args[0] = EMBEDDED_SU;
+#else
 	su_args[0] = SU_PATH;
+#endif /* __sun */
 	su_args[1] = "root";
 	su_args[2] = "-c";
 	su_args[3] = command->str;