13666N/A@@ -3,7 +3,7 @@ INCLUDES = ${LIBGKSU_CFLAGS}
10139N/A AM_CPPFLAGS = -DLOCALEDIR=\"$(datadir)/locale\" -DDATA_DIR=\"$(datadir)\" -DPREFIX=\"$(prefix)\"
10139N/A # major -> breaks backward compatibility (changes to existing ABI)
10139N/A # minor -> keeps compatibility (additions to the API)
10139N/A@@ -71,6 +84,25 @@ struct _GksuContext
10139N/A+ struct pam_message *pam_message;
10139N/A+ struct pam_response *pam_response;
10139N/A+ gboolean wait_for_child_to_exit;
10139N/A+ gboolean sn_context_initiated;
10139N/A #define GKSU_TYPE_CONTEXT gksu_context_get_type()
10139N/A@@ -130,11 +162,13 @@ gksu_context_set_login_shell (GksuContex
10139N/A gksu_context_get_login_shell (GksuContext *context);
10139N/A gksu_context_set_keep_env (GksuContext *context, gboolean value);
10139N/A gksu_context_get_keep_env (GksuContext *context);
10139N/A gksu_context_set_description (GksuContext *context, gchar *description);
10139N/A@@ -252,6 +286,93 @@ gksu_ask_password_full (GksuContext *con
10139N/A gksu_ask_password (GError **error);
10139N/A+gksu_context_embedded_su_try_need_password (GksuContext *context);
10139N/A+gksu_context_embedded_su_run (GksuContext *context,
10139N/A+gksu_context_pfexec_try_run (GksuContext *context);
10139N/A+gksu_context_pfexec_run (GksuContext *context, GError **error);
10139N/A+gksu_context_set_role (GksuContext *context);
10139N/A+gksu_context_get_child_stdin_fd (GksuContext *context);
10139N/A+gksu_context_get_child_stdout_fd (GksuContext *context);
10139N/A+gksu_context_get_child_stdin_file (GksuContext *context);
10139N/A+gksu_context_get_child_stdout_file (GksuContext *context);
10139N/A+gksu_context_get_child_pid (GksuContext *context);
10139N/A+gksu_context_set_wait_for_child_to_exit (GksuContext *context, gboolean value);
+gksu_context_get_wait_for_child_to_exit (GksuContext *context);
+gksu_context_set_elevated_privilege (GksuContext *context, gboolean value);
+gksu_context_get_elevated_privilege (GksuContext *context);
+gksu_context_set_elevated_role (GksuContext *context, gboolean value);
+gksu_context_get_elevated_role (GksuContext *context);
+gksu_context_set_privspec (GksuContext *context, gchar *privspec);
+gksu_context_get_privspec (GksuContext *context);
+gksu_context_get_num_msg (GksuContext *context);
+gksu_context_get_pam_message (GksuContext *context, gint index);
+gksu_context_get_pam_response (GksuContext *context, gint index);
+gksu_context_set_pam_response (GksuContext *context, gint index, gchar *response);
+gksu_context_get_pfexec_mode (GksuContext *context);
+gksu_context_set_need_pipe (GksuContext *context, gboolean value);
+gksu_context_set_child_no_a11y (GksuContext *context, gboolean value);
+gksu_context_get_need_pipe (GksuContext *context);
+gboolean sudo_prepare_xauth (GksuContext *context);
+void sudo_reset_xauth (GksuContext *context, gchar *xauth, gchar *xauth_env);
@@ -532,7 +540,7 @@ report_failed_grab (FailedGrabWhat what)
-grab_keyboard_and_mouse (GtkWidget *dialog)
+grab_keyboard_and_mouse (GksuContext *context, GtkWidget *dialog)
@@ -541,7 +549,7 @@ grab_keyboard_and_mouse (GtkWidget *dial
gchar *fname = g_strdup (getenv ("GKSU_LOCK_FILE"));
- fname = g_strdup_printf ("%s/
.gksu.lock", getenv ("HOME"));
+ fname = g_strdup_printf ("%s/
.gksu.lock", context->saved_home);
@@ -628,6 +636,7 @@ ungrab_keyboard_and_mouse (int lock)
get_gnome_keyring_password (GksuContext *context)
@@ -805,10 +814,12 @@ unset_gnome_keyring_password (GksuContex
get_configuration_options (GksuContext *context)
GConfClient *gconf_client = context->gconf_client;
@@ -821,6 +832,10 @@ get_configuration_options (GksuContext *
context->sudo_mode = gconf_client_get_bool (gconf_client, BASE_PATH "sudo-mode",
+ context->sudo_mode = FALSE;
@@ -910,7 +925,7 @@ su_ask_password (GksuContext *context, g
gksuui_dialog_set_alert (GKSUUI_DIALOG(dialog), context->alert);
- lock = grab_keyboard_and_mouse (dialog);
+ lock = grab_keyboard_and_mouse (context, dialog);
retvalue = gtk_dialog_run (GTK_DIALOG(dialog));
gtk_widget_hide (dialog);
@@ -953,6 +968,7 @@ su_ask_password (GksuContext *context, g
cb_toggled_cb (GtkWidget *button, gpointer data)
GConfClient *gconf_client;
@@ -981,6 +997,7 @@ cb_toggled_cb (GtkWidget *button, gpoint
g_object_unref (gconf_client);
@@ -1084,235 +1101,6 @@ get_process_name (pid_t pid)
-get_xauth_token (GksuContext *context, gchar *display)
- gchar *xauth_bin = NULL;
- gchar *xauth = g_new0 (gchar, 256);
- /* find out where the xauth binary is located */
- "Failed to obtain xauth key: xauth binary not found "
- /* get the authorization token */
- tmp = g_strdup_printf ("%s list %s | "
- "head -1 | awk '{ print $3 }'",
- if ((xauth_output = popen (tmp, "r")) == NULL)
- "Failed to obtain xauth key: %s",
- fread (xauth, sizeof(char), 255, xauth_output);
- * Sets up the variables with values for the $DISPLAY
- * environment variable and xauth-related stuff. Also
- * creates a temporary directory to hold a .Xauthority
- * Returns: TRUE if it suceeds, FALSE if it fails.
-prepare_xauth (GksuContext *context)
- display = g_strdup (getenv ("DISPLAY"));
- xauth = get_xauth_token (context, display);
- /* If xauth is the empty string, then try striping the
- * hostname part of the DISPLAY string for getting the
- * auth token; this is needed for ssh-forwarded usage
- if (!strcmp ("", xauth))
- gchar *cut_display = NULL;
- cut_display = g_strdup (g_strrstr (display, ":"));
- xauth = get_xauth_token (context, cut_display);
- context->xauth = xauth;
- context->display = display;
- "final display: -%s-\n",
- context->xauth, context->display);
-/* Write all of buf, even if write(2) is interrupted. */
-full_write (int d, const char *buf, size_t nbytes)
- /* Loop until nbytes of buf have been written. */
- /* Keep trying until write succeeds without interruption. */
- r = write(d, buf + w, nbytes - w);
- } while (r < 0 && errno == EINTR);
-copy (const char *fn, const char *dir)
- newfn = g_strdup_printf("%s/.Xauthority", dir);
- out = open(newfn, O_WRONLY | O_CREAT | O_EXCL, 0600);
- "Impossible to create the .Xauthority file: a file "
- "already exists. This might be a security issue; "
- "please investigate.");
- "Error copying '%s' to '%s': %s",
- fn, dir, strerror(errno));
- in = open(fn, O_RDONLY);
- "Error copying '%s' to '%s': %s",
- fn, dir, strerror(errno));
- while ((r = read(in, buf, BUFSIZ)) > 0)
- if (full_write(out, buf, r) == -1)
- "Error copying '%s' to '%s': %s",
- fn, dir, strerror(errno));
- "Error copying '%s' to '%s': %s",
- fn, dir, strerror(errno));
-sudo_prepare_xauth (GksuContext *context)
- gchar template[] = "/tmp/" PACKAGE "-XXXXXX";
- gboolean error_copying = FALSE;
- context->dir = g_strdup (mkdtemp(template));
- fprintf (stderr, strerror(errno));
- xauth = g_strdup(g_getenv ("XAUTHORITY"));
- xauth = g_strdup_printf ("%s/.Xauthority", g_get_home_dir());
- error_copying = !copy (xauth, context->dir);
-sudo_reset_xauth (GksuContext *context, gchar *xauth,
- /* reset the env var as it was before or clean it */
- setenv ("XAUTHORITY", xauth_env, TRUE);
- unsetenv ("XAUTHORITY");
- fprintf (stderr, "xauth: %s\nxauth_env: %s\ndir: %s\n",
- xauth, xauth_env, context->dir);
startup_notification_initialize (GksuContext *context)
@@ -1344,11 +1132,13 @@ gksu_context_new ()
context->gconf_client = gconf_client_get_default ();
context->sudo_mode = FALSE;
- context->user = g_strdup ("root");
context->login_shell = FALSE;
@@ -1362,10 +1152,27 @@ gksu_context_new ()
+ context->pam_message = NULL;
+ context->pam_response = NULL;
+ context->privspec = NULL;
+ context->pfexec_mode = FALSE;
+ context->elevated_privilege = TRUE;
+ context->elevated_role = TRUE;
+ context->wait_for_child_to_exit = TRUE;
+ context->need_pipe = TRUE;
+ context->child_pid = 0;
+ context->stdout_fd = 0;
context->sn_context = NULL;
+ context->saved_home = NULL;
+ context->sn_context_initiated = FALSE;
+ context->child_no_a11y = FALSE;
get_configuration_options (context);
startup_notification_initialize (context);
@@ -1485,7 +1292,9 @@ gksu_context_get_login_shell (GksuContex
gksu_context_set_keep_env (GksuContext *context, gboolean value)
context->keep_env = value;
@@ -1737,6 +1546,7 @@ gksu_context_launch_initiate (GksuContex
gksu_context_get_command (context),
+ context->sn_context_initiated = TRUE;
sid = g_strdup_printf ("%s", sn_launcher_context_get_startup_id (context->sn_context));
gksu_context_set_launcher_id (context, sid);
@@ -1757,7 +1567,10 @@ gksu_context_launch_initiate (GksuContex
gksu_context_launch_complete (GksuContext *context)
- sn_launcher_context_complete(context->sn_context);
+ if (context->sn_context_initiated)
+ sn_launcher_context_complete(context->sn_context);
@@ -1801,7 +1614,9 @@ gksu_context_free (GksuContext *context)
g_free (context->display);
g_object_unref (context->gconf_client);
g_free (context->description);
g_free (context->message);
@@ -1810,6 +1625,14 @@ gksu_context_free (GksuContext *context)
g_free (context->command);
+ for ( int i = 0; i<context->msg_num; i++ ) {
+ g_free (context->pam_message[i].msg);
+ g_free (context->pam_response[i].resp);
+ g_free (context->pam_message);
+ g_free (context->pam_response);
+ g_free (context->privspec);
@@ -1855,6 +1678,45 @@ gksu_context_get_type (void)
return type_gksu_context;
+setup_xauth (XHostAddress *host_entry, XServerInterpretedAddress *si_entry, char *rolename)
+ si_entry->type = "localuser";
+ si_entry->typelength = strlen ("localuser");
+ si_entry->value = rolename;
+ si_entry->valuelength = strlen (rolename);
+ host_entry->family = FamilyServerInterpreted;
+ host_entry->address = (char *) si_entry;
+ host_entry->length = sizeof (XServerInterpretedAddress);
+prepare_xauth (GksuContext *context)
+ XServerInterpretedAddress si_entry;
+ XHostAddress host_entry;
+ display = gdk_x11_get_default_xdisplay ();
+ setup_xauth (&host_entry, &si_entry, context->user);
+ XAddHost (display, &host_entry);
+ XSync (display, False);
+reset_xauth (GksuContext *context)
+ XServerInterpretedAddress si_entry;
+ XHostAddress host_entry;
+ display = gdk_x11_get_default_xdisplay ();
+ setup_xauth (&host_entry, &si_entry, context->user);
+ XRemoveHost (display, &host_entry);
+ XSync (display, False);
@@ -1934,6 +1796,10 @@ gksu_su_fuller (GksuContext *context,
gchar auxcommand[] = PREFIX "/lib/" PACKAGE "/gksu-run-helper";
@@ -1942,10 +1808,11 @@ gksu_su_fuller (GksuContext *context,
context->sudo_mode = FALSE;
gksu_quark = g_quark_from_string (PACKAGE);
+ if (!context->command || context->command[0] == '\0')
g_set_error (error, gksu_quark, GKSU_ERROR_NOCOMMAND,
_("gksu_run needs a command to be run, "
@@ -1953,9 +1820,54 @@ gksu_su_fuller (GksuContext *context,
- context->user = g_strdup ("root");
+ if (context->saved_home == NULL)
+ home_env = getenv ("HOME");
+ context->saved_home = home_env;
+ if (!prepare_xauth (context))
+ g_set_error (error, gksu_quark, GKSU_ERROR_XAUTH,
+ _("Unable to copy the user's Xauthorization file."));
+ if (context->pfexec_mode) {
+ rc = gksu_context_pfexec_run (context, error);
+ for (count = 0; count < 3; count++)
+ if (*error) /* wrong password was given */
+ if (context->alert == NULL) {
+ gksu_context_set_alert (context, (*error)->message);
+ rc = gksu_context_embedded_su_run (context, su_ask_password, NULL, error);
+ rc = gksu_context_embedded_su_run (context, ask_pass, ask_pass_data, error);
+ if ((*error == NULL) || ((*error)->code != GKSU_ERROR_WRONGPASS))
if (!g_file_test (auxcommand, G_FILE_TEST_IS_EXECUTABLE))
g_set_error (error, gksu_quark, GKSU_ERROR_HELPER,
@@ -2347,6 +2259,7 @@ gksu_su_fuller (GksuContext *context,
@@ -2368,8 +2281,15 @@ gksu_su (gchar *command_line, GError **e
GksuContext *context = gksu_context_new ();
- context->command = g_strdup (command_line);
+ /* Set defaults to use embedded_su */
context->user = g_strdup ("root");
+ context->command = g_strdup (command_line);
+ context->elevated_privilege = FALSE;
+ context->elevated_role = TRUE;
+ context->wait_for_child_to_exit = FALSE;
+ context->privspec = g_strdup ("All");
retval = gksu_su_full (context,
@@ -2433,6 +2353,29 @@ gksu_sudo_full (GksuContext *context,
+get_sudo_tok (GksuContext *context, FILE *inf, const char *delimiter)
+ token = g_string_new ("");
+ while ((c[0] = fgetc(inf)) != EOF) {
+ token = g_string_append (token, c);
+ if (g_strrstr (token->str, delimiter) ||
+ strncmp (token->str, "GNOME_SUDO_PASS", 15) == 0) {
+ return g_string_free (token, FALSE);
* @context: a #GksuContext
@@ -2472,7 +2415,7 @@ gksu_sudo_fuller (GksuContext *context,
- char buffer[256] = {0};
char *child_stderr = NULL;
/* This command is used to gain a token */
char *const verifycmd[] =
@@ -2481,22 +2424,21 @@ gksu_sudo_fuller (GksuContext *context,
+ int parent_pipe[2]; /* For talking to the parent */
+ int child_pipe[2]; /* For talking to the child */
+ FILE *infile, *outfile;
context->sudo_mode = TRUE;
gksu_quark = g_quark_from_string (PACKAGE);
+ if (!context->command || context->command[0] == '\0')
g_set_error (error, gksu_quark, GKSU_ERROR_NOCOMMAND,
_("gksu_sudo_run needs a command to be run, "
@@ -2504,8 +2446,11 @@ gksu_sudo_fuller (GksuContext *context,
- context->user = g_strdup ("root");
+ if (context->saved_home == NULL)
+ home_env = getenv ("HOME");
+ context->saved_home = home_env;
@@ -2524,24 +2469,16 @@ gksu_sudo_fuller (GksuContext *context,
g_spawn_command_line_sync("
/usr/bin/sudo -K", NULL, NULL, &exit_status, NULL);
FIXME: need to set GError in a more detailed way
- if (!sudo_prepare_xauth (context))
+ if (!prepare_xauth (context))
g_set_error (error, gksu_quark, GKSU_ERROR_XAUTH,
- _("Unable to copy the user's Xauthorization file."));
+ _("Unable to setup the user's Xauthorization file."));
- xauth = g_strdup_printf ("%s/.Xauthority", context->dir);
- xauth_env = getenv ("XAUTHORITY");
- setenv ("XAUTHORITY", xauth, TRUE);
- fprintf (stderr, "xauth: %s\n", xauth);
gksu_context_launch_initiate (context);
@@ -2647,18 +2584,39 @@ gksu_sudo_fuller (GksuContext *context,
fprintf (stderr, "cmd[%d]: %s\n", i, cmd[i]);
- pid = forkpty(&fdpty, NULL, NULL, NULL);
+ if ((pipe(parent_pipe)) == -1)
+ if ((pipe(child_pipe)) == -1)
setsid(); // make us session leader
+ dup2(child_pipe[0], STDIN_FILENO);
+ dup2(parent_pipe[1], STDERR_FILENO);
execv(verifycmd[0], verifycmd);
g_set_error (error, gksu_quark, GKSU_ERROR_EXEC,
_("Failed to exec new process: %s"),
- sudo_reset_xauth (context, xauth, xauth_env);
@@ -2666,29 +2624,45 @@ gksu_sudo_fuller (GksuContext *context,
g_set_error (error, gksu_quark, GKSU_ERROR_FORK,
_("Failed to fork new process: %s"),
- sudo_reset_xauth (context, xauth, xauth_env);
+ gboolean had_error = FALSE;
- fdfile = fdopen(fdpty, "w+");
+ infile = fdopen(parent_pipe[0], "r");
+ outfile = fdopen(child_pipe[1], "w");
/* make sure we notice that ECHO is turned off, if it gets
- tcgetattr (fdpty, &tio);
+ tcgetattr (parent_pipe[0], &tio);
for (counter = 0; (
tio.c_lflag & ECHO) && counter < 15; counter++)
- tcgetattr (fdpty, &tio);
+ tcgetattr (parent_pipe[0], &tio);
- fcntl (fdpty, F_SETFL, O_NONBLOCK);
+ fcntl (parent_pipe[0], F_SETFL, O_NONBLOCK);
{ /* no matter if we can read, since we're using
O_NONBLOCK; this is just to avoid the prompt
@@ -2697,12 +2671,17 @@ gksu_sudo_fuller (GksuContext *context,
+ FD_SET(parent_pipe[0], &rfds);
- select (fdpty + 1, &rfds, NULL, NULL, &tv);
+ select (parent_pipe[0] + 1, &rfds, NULL, NULL, &tv);
+ buffer = get_sudo_tok (context, infile, "\n");
/* Try hard to find the prompt; it may happen that we're
* seeing sudo's lecture, or that some pam module is spitting
@@ -2710,30 +2689,42 @@ gksu_sudo_fuller (GksuContext *context,
for (counter = 0; counter < 50; counter++)
+ fprintf (stderr, "buffer: -%s-\n", buffer);
+ if (g_str_has_prefix (buffer, "Sorry, try again."))
if (strncmp (buffer, "GNOME_SUDO_PASS", 15) == 0)
- read_line (fdpty, buffer, 256);
- fprintf (stderr, "buffer: -%s-\n", buffer);
+ buffer = get_sudo_tok (context, infile, "\n");
- fprintf (stderr, "brute force GNOME_SUDO_PASS ended...\n");
+ fprintf (stderr, "brute force GNOME_SUDO_PASS ended - count %d...\n", counter);
+ /* If we tried 50 times, stop trying. */
if (strncmp(buffer, "GNOME_SUDO_PASS", 15) == 0)
- fprintf (stderr, "Yeah, we're in...\n");
+ fprintf (stderr, "Asking for password.\n");
prompt_grab = gconf_client_get_bool (context->gconf_client, BASE_PATH "prompt",
gksu_prompt_grab (context);
@@ -2742,22 +2733,28 @@ gksu_sudo_fuller (GksuContext *context,
if (password == NULL || (*error))
nullify_password (password);
- write (fdpty, password, strlen(password) + 1);
- write (fdpty, "\n", 1);
+ write (child_pipe[1], password, strlen(password));
+ write (child_pipe[1], "\n", strlen("\n"));
nullify_password (password);
- fcntl(fdpty, F_SETFL, fcntl(fdpty, F_GETFL) & ~O_NONBLOCK);
+ fcntl(parent_pipe[0], F_SETFL, fcntl(parent_pipe[0], F_GETFL) & ~O_NONBLOCK);
/* ignore the first newline that comes right after sudo receives
- fgets (buffer, 255, fdfile);
- /* this is the status we are interested in */
- fgets (buffer, 255, fdfile);
+ read_line (parent_pipe[0], buffer, 256);
+ fprintf (stderr, "buffer: -%s-\n", buffer);
+ read_line (parent_pipe[0], buffer, 256);
+ fprintf (stderr, "buffer: -%s-\n", buffer);
@@ -2766,10 +2763,15 @@ gksu_sudo_fuller (GksuContext *context,
fprintf (stderr, "No password prompt found; we'll assume we don't need a password.\n");
/* turn NONBLOCK off, also if have no prompt */
- fcntl(fdpty, F_SETFL, fcntl(fdpty, F_GETFL) & ~O_NONBLOCK);
+ fcntl(parent_pipe[0], F_SETFL, fcntl(infile, F_GETFL) & ~O_NONBLOCK);
should_display = gconf_client_get_bool (context->gconf_client,
BASE_PATH "display-no-pass-info", NULL);
+ should_display = FALSE;
/* configuration tells us to show this message */
@@ -2784,30 +2786,17 @@ gksu_sudo_fuller (GksuContext *context,
fprintf (stderr, "%s", buffer);
- if (g_str_has_prefix (buffer, "Sorry, try again."))
- g_set_error (error, gksu_quark, GKSU_ERROR_WRONGPASS,
- gchar *haystack = buffer;
- needle = g_strstr_len (haystack, strlen (haystack), " ");
- if (needle && (needle + 1))
- if (!strncmp (needle, "is not in", 9))
- g_set_error (error, gksu_quark, GKSU_ERROR_NOT_ALLOWED,
- _("The underlying authorization mechanism (sudo) "
- "does not allow you to run this program. Contact "
- "the system administrator."));
+ if (*error == NULL && had_error == TRUE)
+ g_set_error (error, gksu_quark, GKSU_ERROR_WRONGPASS,
/* If we have an error, let's just stop sudo right there. */
cmdline = g_strdup("sudo");
/* wait for the child process to end or become something other
@@ -2828,7 +2817,6 @@ gksu_sudo_fuller (GksuContext *context,
/* if the process is still active waitpid() on it */
waitpid(pid, &status, 0);
- sudo_reset_xauth (context, xauth, xauth_env);
* Did token acquisition succeed? If so, spawn sudo in
@@ -2841,6 +2829,11 @@ gksu_sudo_fuller (GksuContext *context,
NULL, &child_stderr, &status,
+ g_set_error (error, gksu_quark, GKSU_ERROR_NOT_ALLOWED,
@@ -2853,7 +2846,7 @@ gksu_sudo_fuller (GksuContext *context,
- if (g_str_has_prefix(child_stderr, "Sorry, user "))
+ if (child_stderr != NULL && g_str_has_prefix(child_stderr, "Sorry, user "))
g_set_error (error, gksu_quark, GKSU_ERROR_NOT_ALLOWED,
_("The underlying authorization mechanism (sudo) "
@@ -2869,6 +2862,7 @@ gksu_sudo_fuller (GksuContext *context,
@@ -2881,7 +2875,7 @@ gksu_sudo_fuller (GksuContext *context,
- fprintf(stderr, child_stderr);
/* if error is set we have found an error condition */
@@ -2908,8 +2902,14 @@ gksu_sudo (gchar *command_line,
GksuContext *context = gksu_context_new ();
- context->command = g_strdup (command_line);
context->user = g_strdup ("root");
+ context->command = g_strdup (command_line);
+ context->elevated_privilege = FALSE;
+ context->elevated_role = TRUE;
+ context->wait_for_child_to_exit = FALSE;
+ context->privspec = g_strdup ("All");
retval = gksu_sudo_full (context,
@@ -2989,13 +2989,18 @@ gksu_run_fuller (GksuContext *context,
GConfClient *gconf_client;
gconf_client = gconf_client_get_default ();
sudo_mode = gconf_client_get_bool (gconf_client, BASE_PATH "sudo-mode",
g_object_unref (gconf_client);
return gksu_sudo_fuller (context, ask_pass, ask_pass_data,
@@ -3024,13 +3029,18 @@ gboolean
gksu_run (gchar *command_line,
GConfClient *gconf_client;
gconf_client = gconf_client_get_default ();
sudo_mode = gconf_client_get_bool (gconf_client, BASE_PATH "sudo-mode",
g_object_unref (gconf_client);
return gksu_sudo (command_line, error);
@@ -46,6 +46,9 @@ main (int argc, char **argv)
gboolean try_sudo = TRUE;
+ int stdin_fd, stdout_fd;
+ FILE *infile, *outfile;
@@ -62,13 +65,25 @@ main (int argc, char **argv)
context = gksu_context_new ();
+ gksu_context_set_user (context, "root");
+ gksu_context_set_debug (context, TRUE);
+ gksu_context_set_elevated_privilege (context, FALSE);
+ gksu_context_set_elevated_role (context, TRUE);
+ gksu_context_set_wait_for_child_to_exit (context, FALSE);
+ gksu_context_set_privspec (context, "All");
+ if ( gksu_context_get_wait_for_child_to_exit (context) ) {
+ gksu_context_set_command (context, "
/usr/bin/ids --nowait");
printf ("Testing gksu_su...\n");
fprintf (stderr, "gksu_su failed: %s\n", error->message);
@@ -80,6 +95,7 @@ main (int argc, char **argv)
/* of course you need to set up
/etc/sudoers for this to work */
@@ -116,6 +132,7 @@ main (int argc, char **argv)
fprintf (stderr, "gksu_run_full failed: %s\n", error->message);
---
/dev/null 2010-12-10 01:34:03.000000000 -0600
+#define MAX_BUFFER_SIZE 1024
+#define CONTEXT_DEBUG_ON(context) (context->debug)
+sudo_get_home_dir (GksuContext *context)
+ struct passwd *pwentry;
+ pwentry = getpwnam (gksu_context_get_user (context));
+ return g_strdup (pwentry->pw_dir);
+sudo_reset_home_dir (gchar *home_env)
+ /* reset the env var as it was before or clear it */
+ setenv ("HOME", home_env, TRUE);
+get_tok (GksuContext *context, FILE *inf, const char *delimiter)
+ token = g_string_new ("");
+ while ((c[0] = fgetc(inf)) != EOF) {
+ token = g_string_append (token, c);
+ * If embedded_su returns SUCCESS, then turn off a11y in gksu
+ * immediatly so that a11y works for child. We cannot wait
+ * for the while loop to exit since this loop hangs until the
+ * the child process completes to get any stdout from child.
+ if (strcmp (token->str, "SUCCESS\n") == 0) {
+ if (atk_get_root() != NULL &&
+ context->child_no_a11y == FALSE)
+ void (*exit_func)(void);
+ exit_func = (void (*)(void))dlsym(handle,
+ "gnome_accessibility_module_shutdown");
+ if (g_strrstr (token->str, delimiter)) {
+ return g_string_free (token, FALSE);
+set_embedded_su_alert (GksuContext *context)
+ if (strncmp (context->pam_message->msg, "embedded_su: ", strlen ("embedded_su: ")) == 0) {
+ msg = g_strdup_printf ("<b>%s %s</b>",
+ _("Issue with password."),
+ context->pam_message->msg + strlen ("embedded_su: "));
+ msg = g_strdup_printf ("<b>%s %s</b>",
+ _("Issue with password."),
+ context->pam_message->msg);
+ gksu_context_set_alert (context, msg);
+parse_embedded_su_output (GksuContext *context, FILE *infile)
+ const char *block_delimiter = ".\n";
+ while ((block = get_tok (context, infile, block_delimiter)) != NULL) {
+ char *message_p = NULL;
+ const char *message_delimiter = "\n";
+ if (CONTEXT_DEBUG_ON(context))
+ fprintf (stderr, "Output from Child: %s\n", block);
+ childoutput = g_strdup (block);
+ message = strtok_r(block, message_delimiter, &message_p);
+ if (context->msg_type == ES_ERROR)
+ if (strncmp (message, "SUCCESS", strlen("SUCCESS")) == 0) {
+ context->msg_type = ES_SUCCESS;
+ /* The message contains "SUCCESS\n" followed by the
+ * command output so if you run "gksu ls" this will
+ * cause the ls output to echo to the terminal.
+ message = childoutput + strlen ("SUCCESS\n");
+ context->pam_message = (struct pam_message *)g_malloc (sizeof(struct pam_message));
+ context->pam_message->msg_style = PAM_TEXT_INFO;
+ context->pam_message->msg = strdup(message);
+ } else if (strncmp(message, "ERROR", strlen("ERROR")) == 0) {
+ if (CONTEXT_DEBUG_ON(context))
+ fprintf (stderr, "There are errors...\n");
+ context->msg_type = ES_ERROR;
+ /* Due embedded_su(1M) there is one TEXT BLOCK
+ message = strtok_r(NULL, message_delimiter, &message_p);
+ context->pam_message = (struct pam_message *)g_malloc (sizeof(struct pam_message));
+ /* Consider all other output as a message. We
+ * treat it like an error message because we
+ * show error messages to users.
+ context->pam_message->msg_style = PAM_ERROR_MSG;
+ context->pam_message->msg = strdup(message);
+ if (context->alert == NULL) {
+ set_embedded_su_alert (context);
+ } else if (strncmp (message, "CONV", strlen("CONV")) == 0) {
+ /* Get message number, then parse CONV block. */
+ /* Ignore all other info in the same
+ * line according to the manpage.
+ sscanf(message, "CONV %d", &(context->msg_num));
+ /* Read all messages. */
+ context->pam_message = (struct pam_message *)g_malloc ( sizeof(struct pam_message)*context->msg_num );
+ context->pam_response = (struct pam_response *)g_malloc ( sizeof(struct pam_response)*context->msg_num );
+ for (int i = 0; i < context->msg_num; i++) {
+ message_header = strtok_r(NULL, message_delimiter, &message_p);
+ message = strtok_r(NULL, message_delimiter, &message_p);
+ context->pam_message[i].msg = strdup(message);
+ if (CONTEXT_DEBUG_ON(context)) {
+ fprintf (stderr, "Got message %d: %s\n", i, message);
+ if (strncmp(message_header, "PAM_PROMPT_ECHO_ON", strlen("PAM_PROMPT_ECHO_ON")) == 0) {
+ context->pam_message[i].msg_style = PAM_PROMPT_ECHO_ON;
+ context->msg_type = ES_PASSWORD;
+ } else if (strncmp(message_header, "PAM_PROMPT_ECHO_OFF", strlen("PAM_PROMPT_ECHO_OFF")) == 0) {
+ context->pam_message[i].msg_style = PAM_PROMPT_ECHO_OFF;
+ context->msg_type = ES_PASSWORD;
+ } else if (strncmp(message_header, "PAM_ERROR_MSG", strlen("PAM_ERROR_MSG")) == 0) {
+ context->pam_message[i].msg_style = PAM_ERROR_MSG;
+ if (context->alert == NULL) {
+ set_embedded_su_alert (context);
+ } else if (strncmp(message_header, "PAM_TEXT_INFO", strlen("PAM_TEXT_INFO")) == 0) {
+ context->pam_message[i].msg_style = PAM_TEXT_INFO;
+ if (CONTEXT_DEBUG_ON(context)) {
+ fprintf (stderr, "Output: %s\n", message);
+ bzero(block, strlen(block));
+ * try_embedded_su_validation
+ * @context: a #GksuContext
+ * Checks if we need to ask for a password or if we have ways of
+ * getting the password for ourselves or we simply don't need it.
+ * Returns: TRUE if requesting a password is needed, FALSE otherwise.
+try_embedded_su_validation (GksuContext *context)
+ char buffer[MAX_BUFFER_SIZE];
+ FILE *infile, *outfile;
+ int parent_pipe[2]; /* For talking to the parent */
+ int child_pipe[2]; /* For talking to the child */
+ gboolean need_pass = TRUE;
+ bzero(buffer, MAX_BUFFER_SIZE);
+ if ((pipe(parent_pipe)) == -1)
+ if ((pipe(child_pipe)) == -1)
+ cmd = g_new (gchar *, argcount + 1);
+ /* embedded_su binary */
+ if (context->login_shell)
+ cmd[argcount] = g_strdup ("-"); argcount++;
+ cmd[argcount] = g_strdup (context->user);
+ cmd[argcount] = g_strdup ("-c");
+ cmd[argcount] = g_strdup ("echo >
/dev/null");
+ dup2(child_pipe[0], STDIN_FILENO);
+ dup2(parent_pipe[1], STDOUT_FILENO);
+ infile = fdopen(parent_pipe[0], "r");
+ outfile = fdopen(child_pipe[1], "w");
+ // start conversation with embedded_su
+ write (child_pipe[1], ".\n", 2);
+ we are expecting to receive a GNOME_SUDO_PASS
+ if we don't there are two possibilities: an error
+ or a password is not needed
+ parse_embedded_su_output(context, infile);
+ switch (context->msg_type) {
+ if (CONTEXT_DEBUG_ON(context))
+ fprintf (stderr, "Success!\n");
+ if (CONTEXT_DEBUG_ON(context))
+ fprintf (stderr, "Asking for password...\n");
+ while (!waitpid (pid, &status, WNOHANG)) {
+ write (child_pipe[1], "\n", 1);
+ * gksu_context_embedded_su_run:
+ * @context: a #GksuContext
+ * @error: a #GError object to be filled with the error code or NULL
+ * This could be considered one of the main functions in GKSu.
+ * it is responsible for doing the 'user changing' magic by
+ * calling gksu_ask_password() if it needs the user's password
+ * it behaves like sudo.
+ * Returns: the child's error status, TRUE if all went fine, FALSE if failed
+gksu_context_embedded_su_run (GksuContext *context,
+ GksuAskPassFunc ask_pass,
+ gpointer ask_pass_data,
+ char buffer[MAX_BUFFER_SIZE];
+ FILE *infile, *outfile;
+ int parent_pipe[2]; /* For talking to the parent */
+ int child_pipe[2]; /* For talking to the child */
+ gksu_quark = g_quark_from_string (PACKAGE_NAME);
+ g_set_error (error, gksu_quark, GKSU_ERROR_NOCOMMAND,
+ _("gksu_sudo_run needs a command to be run, "
+ "none was provided."));
+ * Check if the HOME environment variable is set in the user's
+ * environment. If so unset it:
+ * This will ensure that apps that require write
+ * permission eg. gconf client applications, will work.
+ home_env = getenv ("HOME");
+ home = sudo_get_home_dir (context);
+ setenv ("HOME", home, TRUE);
+ if (CONTEXT_DEBUG_ON(context))
+ fprintf (stderr, "HOME: %s\n", home);
+ cmd = g_new (gchar *, argcount + 1);
+ /* embedded_su binary */
+ if (context->login_shell)
+ cmd[argcount] = g_strdup("-");
+ cmd[argcount] = g_strdup(context->user);
+ cmd[argcount] = g_strdup("-c");
+ cmd[argcount] = g_strdup_printf("%s", context->command);
+ if (CONTEXT_DEBUG_ON(context))
+ for (i = 0; cmd[i] != NULL; i++)
+ fprintf (stderr, "cmd[%d]: %s\n", i, cmd[i]);
+ if ((pipe(parent_pipe)) == -1)
+ g_set_error (error, gksu_quark, GKSU_ERROR_PIPE,
+ _("Error creating pipe: %s"),
+ sudo_reset_home_dir (home_env);
+ if ((pipe(child_pipe)) == -1)
+ g_set_error (error, gksu_quark, GKSU_ERROR_PIPE,
+ _("Error creating pipe: %s"),
+ sudo_reset_home_dir (home_env);
+ g_set_error (error, gksu_quark, GKSU_ERROR_FORK,
+ _("Failed to fork new process: %s"),
+ sudo_reset_home_dir (home_env);
+ setsid(); // make us session leader
+ dup2(child_pipe[0], STDIN_FILENO);
+ dup2(parent_pipe[1], STDERR_FILENO);
+ dup2(parent_pipe[1], STDOUT_FILENO);
+ g_set_error (error, gksu_quark, GKSU_ERROR_EXEC,
+ _("Failed to exec new process: %s"),
+ sudo_reset_home_dir (home_env);
+ gboolean more_data = TRUE;
+ infile = fdopen(parent_pipe[0], "r");
+ g_set_error (error, gksu_quark, GKSU_ERROR_PIPE,
+ _("Error opening pipe: %s"),
+ sudo_reset_home_dir (home_env);
+ outfile = fdopen(child_pipe[1], "w");
+ g_set_error (error, gksu_quark, GKSU_ERROR_PIPE,
+ _("Error opening pipe: %s"),
+ sudo_reset_home_dir (home_env);
+ context->stdin_fd = parent_pipe[0];
+ context->stdout_fd = child_pipe[1];
+ context->stdin_file = infile;
+ context->stdout_file = outfile;
+ setvbuf (context->stdin_file, NULL, _IONBF, 0);
+ fcntl (context->stdin_fd, F_SETFL, 0);
+ context->child_pid = pid;
+ // start conversation with embedded_su
+ write (child_pipe[1], ".\n", 2);
+ we are expecting to receive a GNOME_SUDO_PASS
+ if we don't there are two possibilities: an error
+ or a password is not needed
+ /* 6995127 Gksu does not report expired password. We are in PAM
+ * conversation, we need handle change the expired password. */
+ more_data = parse_embedded_su_output(context, infile);
+ switch (context->msg_type) {
+ if (CONTEXT_DEBUG_ON(context))
+ fprintf (stderr, "Success!\n");
+ if (CONTEXT_DEBUG_ON(context))
+ fprintf (stderr, "Asking for password...\n");
+ if ( context->pam_message[0].msg != NULL ) {
+ buf = context->pam_message[0].msg;
+ password = ask_pass (context, buf, ask_pass_data, error);
+ if (password == NULL || (!strcmp (password, ""))) {
+ password = g_strchomp (password);
+ write (child_pipe[1], password, strlen(password));
+ write (child_pipe[1], "\n", strlen("\n"));
+ /* Reset flag so it does not get stuck */
+ } while (context->msg_type != ES_SUCCESS && more_data);
+ if (CONTEXT_DEBUG_ON(context))
+ fprintf (stderr, "Done parsing embedded_su output!\n");
+ if (context->msg_type == ES_ERROR && context->msg_num > 0 && context->pam_message[0].msg != NULL)
+ utf8 = g_locale_to_utf8 (context->pam_message[0].msg, -1,
+ utf8 = g_strdup (context->pam_message[0].msg);
+ g_set_error (error, gksu_quark, GKSU_ERROR_WRONGPASS,
+ if (context->msg_type == ES_SUCCESS && context->pam_message[0].msg)
+ fprintf (stdout, "%s", context->pam_message[0].msg);
+ if (!context->wait_for_child_to_exit) {
+ /* make sure we did read everything */
+ while (!waitpid (pid, &status, WNOHANG)) {
+ if (context->msg_type == ES_ERROR) {
+ write (child_pipe[1], "\n", 1);
+ sudo_reset_home_dir (home_env);
+ /* Do not reset error if already set to WRONGPASS */
+ if (*error == NULL || (*error)->code != GKSU_ERROR_WRONGPASS)
+ if (WEXITSTATUS(status))
+ g_set_error (error, gksu_quark, GKSU_ERROR_CHILDFAILED,
+ _("Child terminated with %d status"),
+gksu_context_try_need_password (GksuContext *context)
+ if ( (context->elevated_privilege) && (gksu_context_pfexec_try_run (context)))
+ if (CONTEXT_DEBUG_ON(context))
+ fprintf (stderr, "Enter pfexec mode!\n");
+ context->pfexec_mode = TRUE;
+ context->pfexec_mode = FALSE;
+ if ( CONTEXT_DEBUG_ON(context) )
+ fprintf (stderr, "Enter embedded_su mode!\n");
+ if ( context->elevated_role )
+ gksu_context_set_role (context);
+ if (CONTEXT_DEBUG_ON(context))
+ fprintf (stderr, "Current role = %s\n", context->user);
+ return try_embedded_su_validation (context);
+gksu_context_pfexec_try_run (GksuContext *context)
+ char command_line[MAX_BUFFER_SIZE];
+ char *path, *dir, full_cmd[MAX_BUFFER_SIZE];
+ /* fail if we cannot get password entry */
+ if (context->command[i] == ' ' || context->command[i] == '\0') {
+ command_line[i] = '\0';
+ command_line[i] = context->command[i];
+ if (strchr(command_line, '/') != NULL) {
+ exec = getexecuser (pwd->pw_name, KV_COMMAND, command_line, GET_ALL);
+ /* we need to copy $PATH because our sub processes may need it. */
+ for (dir= strtok(path, ":"); dir; dir = strtok(NULL, ":")) {
+ if (snprintf(full_cmd, sizeof(full_cmd), "%s/%s", dir, command_line) >= sizeof(full_cmd)) {
+ if (access(full_cmd, X_OK) == 0) {
+ exec = getexecuser (pwd->pw_name, KV_COMMAND, full_cmd, GET_ALL);
+ if (CONTEXT_DEBUG_ON(context)) fprintf (stderr, "Error getting exec attr\n");
+ if (CONTEXT_DEBUG_ON(context))
+ fprintf (stderr, "Exec Name: %s\n", exec->name);
+ fprintf (stderr, "Policy Name: %s\n", exec->policy);
+ fprintf (stderr, "Exec Type: %s\n", exec->type);
+ fprintf (stderr, "Exec Id: %s\n", exec->id);
+ if ((exec->attr != NULL) && (exec->attr->length != 0)) {
+gksu_context_set_role (GksuContext *context)
+ char command_line[MAX_BUFFER_SIZE];
+ if ( !strncmp (context->user, "root", 4) ) {
+ username = strdup (pwd->pw_name);
+ user = getusernam (username);
+ user = getusernam (context->user);
+ rolelist = kva_match (user->attr, USERATTR_ROLES_KW);
+ if (rolelist != NULL) {
+ if (context->command[i] == ' ' || context->command[i] == '\0') {
+ command_line[i] = '\0';
+ command_line[i] = context->command[i];
+ /* Parse the rolename from the list and check execution profiles for
+ rolename = strtok (rolelist, ",");
+ exec = getexecuser (rolename, KV_COMMAND, command_line, GET_ALL);
+ if ((exec->attr != NULL) && (exec->attr->length != 0)) {
+ if (CONTEXT_DEBUG_ON(context)) {
+ printf ("Command in profile and has attributes\n");
+ printf ("Exec Name: %s\n", exec->name);
+ printf ("Policy Name: %s\n", exec->policy);
+ printf ("Exec Type: %s\n", exec->type);
+ printf ("Exec Id: %s\n", exec->id);
+ if (context->user != NULL) g_free (context->user);
+ context->user = g_strdup (rolename);
+ rolename = strtok (NULL, ",");
+gksu_context_pfexec_run (GksuContext *context, GError **error)
+ char buffer[MAX_BUFFER_SIZE];
+ FILE *infile, *outfile;
+ int parent_pipe[2]; /* For talking to the parent */
+ int child_pipe[2]; /* For talking to the child */
+ int was_quoted = FALSE;
+ gksu_quark = g_quark_from_string (PACKAGE_NAME);
+ g_set_error (error, gksu_quark, GKSU_ERROR_NOCOMMAND,
+ _("gksu_sudo_run needs a command to be run, "
+ "none was provided."));
+ * Check if the HOME environment variable is set in the user's
+ * environment. If so unset it:
+ * This will ensure that apps that require write
+ * permission eg. gconf client applications, will work.
+ home_env = getenv ("HOME");
+ home = sudo_get_home_dir (context);
+ setenv ("HOME", home, TRUE);
+ if (CONTEXT_DEBUG_ON(context))
+ fprintf (stderr, "HOME: %s\n", home);
+ cmd = g_new (gchar *, argcount + 1);
+ if (context->privspec != NULL)
+ cmd[argcount] = g_strdup("-P");
+ cmd[argcount] = g_strdup(context->privspec);
+ if (context->command[i] == ' ' || context->command[i] == '\0')
+ /* Strip the previously added quoting '<arg>' */
+ if (was_quoted && j > 1 && buffer[j-1] == '\'')
+ cmd = g_realloc (cmd, sizeof(gchar*) * (argcount + 1));
+ cmd[argcount] = g_strdup (buffer);
+ bzero (buffer, MAX_BUFFER_SIZE);
+ argcount = argcount + 1;
+ if (context->command[i] == '\0')
+ else if ( j == 0 && context->command[i] == '\'' )
+ /* Skip initial quote */
+ if (context->command[i] == '\\')
+ buffer[j] = context->command[i];
+ cmd = g_realloc (cmd, sizeof(gchar*) * (argcount + 1));
+ if (CONTEXT_DEBUG_ON(context))
+ for (i = 0; cmd[i] != NULL; i++)
+ fprintf (stderr, "cmd[%d]: %s\n", i, cmd[i]);
+ if (context->need_pipe)
+ if ((pipe(parent_pipe)) == -1)
+ g_set_error (error, gksu_quark, GKSU_ERROR_PIPE,
+ _("Error creating pipe: %s"),
+ sudo_reset_home_dir (home_env);
+ if ((pipe(child_pipe)) == -1)
+ g_set_error (error, gksu_quark, GKSU_ERROR_PIPE,
+ _("Error creating pipe: %s"),
+ sudo_reset_home_dir (home_env);
+ g_set_error (error, gksu_quark, GKSU_ERROR_FORK,
+ _("Failed to fork new process: %s"),
+ sudo_reset_home_dir (home_env);
+ setsid(); // make us session leader
+ if (context->need_pipe)
+ dup2(child_pipe[0], STDIN_FILENO);
+ dup2(parent_pipe[1], STDERR_FILENO);
+ dup2(parent_pipe[1], STDOUT_FILENO);
+ sudo_reset_home_dir (home_env);
+ if (!context->need_pipe)
+ infile = fdopen(parent_pipe[0], "r");
+ g_set_error (error, gksu_quark, GKSU_ERROR_PIPE,
+ _("Error opening pipe: %s"),
+ sudo_reset_home_dir (home_env);
+ outfile = fdopen(child_pipe[1], "w");
+ g_set_error (error, gksu_quark, GKSU_ERROR_PIPE,
+ _("Error opening pipe: %s"),
+ sudo_reset_home_dir (home_env);
+ context->stdin_fd = parent_pipe[0];
+ context->stdout_fd = child_pipe[1];
+ context->stdin_file = infile;
+ context->stdout_file = outfile;
+ setvbuf (context->stdin_file, NULL, _IONBF, 0);
+ fcntl (context->stdin_fd, F_SETFL, 0);
+ context->child_pid = pid;
+ if (!context->wait_for_child_to_exit)
+ /* make sure we did read everything */
+ bzero(buffer, MAX_BUFFER_SIZE);
+ if(!fread (buffer, sizeof(gchar), MAX_BUFFER_SIZE-1, infile))
+ fprintf (stderr, "%s", buffer);
+ sudo_reset_home_dir (home_env);
+ if (WEXITSTATUS(status))
+ g_set_error (error, gksu_quark, GKSU_ERROR_CHILDFAILED,
+ _("Child terminated with %d status"),
+gksu_context_get_child_stdin_fd (GksuContext *context)
+ return context->stdin_fd;
+gksu_context_get_child_stdout_fd (GksuContext *context)
+ return context->stdout_fd;
+gksu_context_get_child_stdin_file (GksuContext *context)
+ return context->stdin_file;
+gksu_context_get_child_stdout_file (GksuContext *context)
+ return context->stdout_file;
+gksu_context_get_child_pid (GksuContext *context)
+ return context->child_pid;
+gksu_context_set_wait_for_child_to_exit (GksuContext *context, gboolean value)
+ context->wait_for_child_to_exit = value;
+gksu_context_get_wait_for_child_to_exit (GksuContext *context)
+ return context->wait_for_child_to_exit;
+gksu_context_set_elevated_privilege (GksuContext *context, gboolean value)
+ context->elevated_privilege = value;
+gksu_context_get_elevated_privilege (GksuContext *context)
+ return context->elevated_privilege;
+gksu_context_set_elevated_role (GksuContext *context, gboolean value)
+ context->elevated_role = value;
+gksu_context_get_elevated_role (GksuContext *context)
+ return context->elevated_role;
+ * gksu_context_set_privspec:
+ * @context: the #GksuContext you want to modify
+ * @privspec: the target privileges specification
+ * Sets up privileges specification used by pfexec .
+gksu_context_set_privspec (GksuContext *context, gchar *privspec)
+ g_assert (privspec != NULL);
+ g_free (context->privspec);
+ context->privspec = g_strdup (privspec);
+ * gksu_context_get_privspec:
+ * @context: the #GksuContext from which to grab the information
+ * Gets the privileges specification used by pfexec, as set
+ * by gksu_context_set_privspec.
+ * Returns: a pointer to the string containing the privileges specification.
+gksu_context_get_privspec (GksuContext *context)
+ return context->privspec;
+ * gksu_context_get_pam_num_msg:
+ * @context: the #GksuContext from which to grab the information
+ * Gets the privileges specificddation used by pfexec, as set
+ * by gksu_context_set_privspec.
+ * Returns: number of pam conversation.
+gksu_context_get_pam_msg_num (GksuContext *context)
+ return context->msg_num;
+ * gksu_context_get_pam_message:
+ * @context: the #GksuContext from which to grab the information
+ * Returns: a pointer to the string containing the specific pam message.
+gksu_context_get_pam_message (GksuContext *context, gint index)
+ return context->pam_message[index].msg;
+ * gksu_context_get_pam_response:
+ * @context: the #GksuContext from which to grab the information
+ * Returns: a pointer to the string containing the specified pam response.
+gksu_context_get_pam_response (GksuContext *context, gint index)
+ return context->pam_response[index].resp;
+ * gksu_context_set_pam_response:
+ * @context: the #GksuContext from which to grab the information
+gksu_context_set_pam_response (GksuContext *context, gint index, gchar *response)
+ context->pam_response[index].resp = g_strdup (response);
+gksu_context_get_pfexec_mode (GksuContext *context)
+ return context->pfexec_mode;
+gksu_context_set_need_pipe (GksuContext *context, gboolean value)
+ context->need_pipe = value;
+gksu_context_get_need_pipe (GksuContext *context)
+ return context->need_pipe;
+gksu_context_set_child_no_a11y (GksuContext *context, gboolean value)
+ context->child_no_a11y = value;