--- gnome-session-2.30.2/egg/eggdesktopfile.c-orig 2011-03-14 16:05:27.567087180 -0500
+++ gnome-session-2.30.2/egg/eggdesktopfile.c 2011-03-14 16:07:41.020838521 -0500
@@ -29,6 +29,17 @@
#include <string.h>
#include <unistd.h>
+#include <user_attr.h>
+#include <exec_attr.h>
+#include <stdlib.h>
+#include <secdb.h>
+#include <dlfcn.h>
+#include <pwd.h>
+
+#include <tsol/label.h>
+#include <sys/tsol/label_macro.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/Xtsol.h>
#include <glib/gi18n.h>
#include <gdk/gdkx.h>
@@ -1066,6 +1077,451 @@ array_putenv (GPtrArray *env, char *vari
return env;
}
+/*
+ * Note that the following code is in three patches:
+ * - gnome-panel-XX-rbac.diff (filter_with_rbac)
+ * - gnome-menus-XX-rbac.diff (filter_with_rbac)
+ * - glib-XX-gio-rbac.diff (get_gksu_role)
+ * - gnome-session-XX-rbac.diff (get_gksu_role)
+ *
+ * So if there is a need to fix this code, it is probably necessary to fix the
+ * code in these other two places as well. Though the functions are a bit
+ * different.
+ */
+static
+void * dlopen_tsol (void)
+{
+ void *handle = NULL;
+
+ /*
+ * No 64-bit version of libwnck so we can get away with hardcoding
+ * to a single path on this occasion
+ */
+ if ((handle = dlopen ("/usr/lib/libtsol.so.2", RTLD_LAZY)) != NULL)
+ return handle;
+
+ return handle;
+}
+
+static
+void * dlopen_xtsol (void)
+{
+ void *handle = NULL;
+
+ if ((handle = dlopen ("/usr/lib/libXtsol.so.1", RTLD_LAZY)) != NULL)
+ return handle;
+ if ((handle = dlopen ("/usr/openwin/lib/libXtsol.so.1", RTLD_LAZY)) != NULL)
+ return handle;
+
+ return handle;
+}
+
+static
+void * dlopen_gnometsol (void)
+{
+ void *handle = NULL;
+
+ if ((handle = dlopen ("/usr/lib/libgnometsol.so", RTLD_LAZY)) != NULL)
+ return handle;
+
+ return handle;
+}
+
+/* Libtsol functions */
+
+typedef int (*tsol_blequal) (const m_label_t *label1, const m_label_t *label2);
+typedef int (*tsol_label_to_str) (const m_label_t *label, char **string,
+ const m_label_str_t conversion_type,
+ uint_t flags);
+typedef int (*tsol_str_to_label) (const char *string, m_label_t **label,
+ const m_label_type_t label_type, uint_t flags,
+ int *error);
+typedef void (*tsol_m_label_dup) (m_label_t **dst, const m_label_t *src);
+typedef void (*tsol_m_label_free) (m_label_t *label);
+
+/* Other misc. libtsol functions that seem to be stable */
+typedef blrange_t* (*tsol_getuserrange) (const char *username);
+typedef int (*tsol_blinrange) (const m_label_t *label,
+ const blrange_t *range);
+typedef void (*tsol_blminimum) (m_label_t *minimum_label,
+ const m_label_t *bounding_label);
+typedef void (*tsol_blmaximum) (m_label_t *maximum_label,
+ const m_label_t *bounding_label);
+typedef m_label_t* (*tsol_blabel_alloc) (void);
+typedef void (*tsol_blabel_free) (m_label_t *label_p);
+typedef void (*tsol_bsllow) (m_label_t *label);
+typedef void (*tsol_bslhigh) (m_label_t *label);
+
+/* libXtsol functions */
+typedef Status (*xtsol_XTSOLgetClientLabel) (Display *dpy, XID xid,
+ bslabel_t *sl);
+typedef Bool (*xtsol_XTSOLIsWindowTrusted) (Display *dpy, Window win);
+
+/* libgnometsol functions */
+typedef gpointer (*gnometsol_gnome_label_builder_new) (char *msg,
+ blevel_t *upper, blevel_t *lower, int mode);
+typedef GType (*gnometsol_gnome_label_builder_get_type) (void);
+
+/* libtsol functions */
+tsol_blequal libtsol_blequal;
+tsol_label_to_str libtsol_label_to_str;
+tsol_str_to_label libtsol_str_to_label;
+tsol_m_label_dup libtsol_m_label_dup;
+tsol_m_label_free libtsol_m_label_free;
+/* Other misc. libtsol functions */
+tsol_blminimum libtsol_blminimum;
+tsol_blmaximum libtsol_blmaximum;
+tsol_blinrange libtsol_blinrange;
+tsol_getuserrange libtsol_getuserrange;
+tsol_blabel_alloc libtsol_blabel_alloc;
+tsol_blabel_free libtsol_blabel_free;
+tsol_bsllow libtsol_bsllow;
+tsol_bslhigh libtsol_bslhigh;
+
+xtsol_XTSOLgetClientLabel libxtsol_XTSOLgetClientLabel;
+xtsol_XTSOLIsWindowTrusted libxtsol_XTSOLIsWindowTrusted;
+
+gnometsol_gnome_label_builder_new libgnometsol_gnome_label_builder_new;
+gnometsol_gnome_label_builder_get_type libgnometsol_gnome_label_builder_get_type;
+
+gboolean
+use_trusted_extensions (void)
+{
+ static int trusted = -1;
+
+ /*
+ * Sun Trusted Extensions (tm) for Solaris (tm) support. (Damn I should be a lawyer).
+ *
+ * It is necessary to use dlopen because the label aware extensions to libwnck work
+ * only on systems with the trusted extensions installed and with the SUN_TSOL
+ * xserver extension present
+ */
+
+ if (trusted < 0) {
+ static gpointer tsol_handle = NULL;
+ static gpointer xtsol_handle = NULL;
+ static gpointer gnometsol_handle = NULL;
+
+ if (getenv ("TRUSTED_SESSION") == NULL) {
+ trusted = 0;
+ return 0;
+ }
+
+ tsol_handle = dlopen_tsol ();
+ if (tsol_handle != NULL)
+ xtsol_handle = dlopen_xtsol ();
+ if (tsol_handle && xtsol_handle) {
+
+ /* libtsol functions */
+ libtsol_blequal = (tsol_blequal) dlsym (tsol_handle, "blequal");
+ libtsol_label_to_str = (tsol_label_to_str) dlsym (tsol_handle, "label_to_str");
+ libtsol_str_to_label = (tsol_str_to_label) dlsym (tsol_handle, "str_to_label");
+ libtsol_m_label_dup = (tsol_m_label_dup) dlsym (tsol_handle, "m_label_dup");
+ libtsol_m_label_free = (tsol_m_label_free) dlsym (tsol_handle, "m_label_free");
+
+
+ /* Other misc. libtsol functions */
+ libtsol_blminimum = (tsol_blminimum) dlsym (tsol_handle, "blminimum");
+ libtsol_blmaximum = (tsol_blmaximum) dlsym (tsol_handle, "blmaximum");
+ libtsol_blinrange = (tsol_blinrange) dlsym (tsol_handle, "blinrange");
+ libtsol_getuserrange = (tsol_getuserrange) dlsym (tsol_handle, "getuserrange");
+ libtsol_blabel_alloc = (tsol_blabel_alloc) dlsym (tsol_handle, "blabel_alloc");
+ libtsol_blabel_free = (tsol_blabel_free) dlsym (tsol_handle, "blabel_free");
+ libtsol_bsllow = (tsol_bsllow) dlsym (tsol_handle, "bsllow");
+ libtsol_bslhigh = (tsol_bslhigh) dlsym (tsol_handle, "bslhigh");
+
+ /* libXtsol functions */
+ libxtsol_XTSOLgetClientLabel = (xtsol_XTSOLgetClientLabel) dlsym (xtsol_handle,
+ "XTSOLgetClientLabel");
+ libxtsol_XTSOLIsWindowTrusted = (xtsol_XTSOLIsWindowTrusted) dlsym (xtsol_handle,
+ "XTSOLIsWindowTrusted");
+
+ if (libtsol_label_to_str == NULL ||
+ libtsol_str_to_label == NULL ||
+ libtsol_m_label_dup == NULL ||
+ libtsol_m_label_free == NULL ||
+ libtsol_blminimum == NULL ||
+ libtsol_blmaximum == NULL ||
+ libtsol_blinrange == NULL ||
+ libtsol_getuserrange == NULL ||
+ libtsol_blabel_alloc == NULL ||
+ libtsol_blabel_free == NULL ||
+ libtsol_bsllow == NULL ||
+ libtsol_bslhigh == NULL ||
+ libxtsol_XTSOLgetClientLabel == NULL ||
+ libxtsol_XTSOLIsWindowTrusted == NULL) {
+ dlclose (tsol_handle);
+ dlclose (xtsol_handle);
+ tsol_handle = NULL;
+ xtsol_handle = NULL;
+ }
+ }
+
+ gnometsol_handle = dlopen_gnometsol ();
+ if (gnometsol_handle != NULL) {
+ libgnometsol_gnome_label_builder_new =
+ (gnometsol_gnome_label_builder_new) dlsym (gnometsol_handle,
+ "gnome_label_builder_new");
+ libgnometsol_gnome_label_builder_get_type =
+ (gnometsol_gnome_label_builder_get_type) dlsym (gnometsol_handle,
+ "gnome_label_builder_get_type");
+ if (libgnometsol_gnome_label_builder_new == NULL ||
+ libgnometsol_gnome_label_builder_get_type == NULL)
+ gnometsol_handle = NULL;
+
+ }
+ trusted = ((tsol_handle != NULL) && (xtsol_handle != NULL) && (gnometsol_handle != NULL)) ? 1 : 0;
+ }
+ return trusted ? TRUE : FALSE;
+}
+
+static gchar *
+get_stripped_exec (const gchar *full_exec)
+{
+ gchar *str1, *str2, *retval, *p;
+
+ str1 = g_strdup (full_exec);
+ p = strtok (str1, " ");
+
+ if (p != NULL)
+ str2 = g_strdup (p);
+ else
+ str2 = g_strdup (full_exec);
+
+ g_free (str1);
+
+ if (g_path_is_absolute (str2)) {
+ retval = g_strdup (str2);
+ } else {
+ retval = g_strdup (g_find_program_in_path ((const gchar *)str2));
+ }
+ g_free (str2);
+
+ return retval;
+}
+
+static
+char * get_validated_stripped_exec (const char *command)
+{
+ const char *username = NULL;
+ char *stripped_cmd;
+ char *path;
+
+ username = g_get_user_name ();
+
+ /* Do not use pfexec for root */
+ if (strcmp (username, "root") == 0) {
+ return NULL;
+ }
+
+ stripped_cmd = get_stripped_exec (command);
+ if (stripped_cmd == NULL) {
+ return NULL;
+ }
+
+ path = g_find_program_in_path (g_strstrip (stripped_cmd));
+ if (path == NULL)
+ return NULL;
+
+ return stripped_cmd;
+}
+
+static gboolean
+command_has_profile (const char *command)
+{
+ execattr_t *exec = NULL;
+ gboolean rc = FALSE;
+
+ /* Check if the program is in any profile. */
+ exec = getexecprof (NULL, KV_COMMAND, command, GET_ONE);
+ if (exec == NULL) {
+ return rc;
+ }
+
+ while (exec != NULL) {
+ if (exec->attr != NULL) {
+ rc = TRUE;
+ break;
+ }
+ exec = exec->next;
+ }
+
+ free_execattr (exec);
+
+ return rc;
+}
+
+static gboolean
+use_pfexec (char *command)
+{
+ execattr_t *exec = NULL;
+ const char *username = NULL;
+ char *stripped_cmd;
+ gboolean trusted;
+ gboolean has_profile;
+ gboolean rc;
+
+ rc = FALSE;
+
+ /* Never use pfexec in Trusted mode */
+ trusted = use_trusted_extensions ();
+ if (trusted) {
+ goto out;
+ }
+
+ stripped_cmd = get_validated_stripped_exec (command);
+ if (stripped_cmd == NULL) {
+ goto out;
+ }
+
+ has_profile = command_has_profile (stripped_cmd);
+
+ username = g_get_user_name ();
+
+ /* Check if the user can run the command. */
+ exec = getexecuser (username, KV_COMMAND, stripped_cmd, GET_ONE);
+
+ /*
+ * If the program is not associated with any profile, then do not
+ * use pfexec.
+ */
+ if (exec == NULL)
+ goto out;
+
+ /*
+ * If getexecuser does not return NULL and the program is not
+ * associated with any profile, then pfexec is not needed.
+ */
+ if (has_profile == FALSE) {
+ goto out;
+ }
+
+ /*
+ * Does the user have a profile that can run the command?
+ */
+ while (exec != NULL) {
+ if (exec->attr != NULL) {
+ rc = TRUE;
+ break;
+ }
+ exec = exec->next;
+ }
+out:
+ if (exec != NULL)
+ free_execattr (exec);
+
+ if (stripped_cmd)
+ g_free (stripped_cmd);
+
+ return rc;
+}
+
+/*
+ * Checks RBAC and if the user can run the command with gksu, the role is
+ * passed back, otherwise NULL.
+ */
+gchar *
+get_gksu_role (char *command)
+{
+ execattr_t *exec;
+ userattr_t *user;
+ const char *username = NULL;
+ char *rc = NULL;
+ char *stripped_cmd;
+ char *path;
+ int i;
+ gboolean has_profile;
+ gboolean trusted;
+
+ /* Never use gksu in Trusted mode */
+ trusted = use_trusted_extensions ();
+ if (trusted) {
+ goto out;
+ }
+
+ stripped_cmd = get_validated_stripped_exec (command);
+ if (stripped_cmd == NULL) {
+ goto out;
+ }
+
+ /* If pfexec should be used, then do not use gksu. */
+ if (use_pfexec (command) == TRUE) {
+ goto out;
+ }
+
+ has_profile = command_has_profile (stripped_cmd);
+ username = g_get_user_name ();
+
+ /* Check if the user can run the command. */
+ exec = getexecuser (username, KV_COMMAND, stripped_cmd, GET_ONE);
+
+ /*
+ * If the program is not associated with any profile, then do not
+ * use gksu.
+ */
+ if (exec == NULL)
+ goto out;
+
+ free_execattr (exec);
+
+ /*
+ * If getexecuser does not return NULL and the program is not
+ * associated with any profile, then gksu is not needed.
+ */
+ if (has_profile == FALSE) {
+ goto out;
+ }
+
+ /* If no gksu is available, then do not try to use it */
+ path = g_find_program_in_path ("/usr/bin/gksu");
+ if (path == NULL)
+ goto out;
+
+ /* Check if the user is in a role that can run the command. */
+ /* If so, use gksu with that role */
+ if ((user = getusernam (username)) != NULL) {
+ const char *rolelist = NULL;
+ char **v = NULL;
+ char *role = NULL;
+
+ /* Use roles associated with the user. */
+ rolelist = kva_match (user->attr, USERATTR_ROLES_KW);
+
+ if (rolelist != NULL)
+ v = g_strsplit (rolelist, ",", -1);
+
+ for (i=0; v != NULL && v[i] != NULL; i++) {
+ role = g_strdup (v[i]);
+ g_strstrip (role);
+
+ exec = getexecuser (role, KV_COMMAND, stripped_cmd, GET_ONE);
+ while (exec != NULL) {
+ if ((strcmp (role, "root") == 0) ||
+ (exec->attr != NULL)) {
+ rc = g_strdup (role);
+ break;
+ }
+ exec = exec->next;
+ }
+
+ g_free (role);
+ free_execattr (exec);
+
+ if (rc != NULL) {
+ break;
+ }
+ }
+ if (v != NULL)
+ g_strfreev (v);
+ }
+
+out:
+ if (stripped_cmd)
+ g_free (stripped_cmd);
+
+ return (rc);
+}
+
static gboolean
egg_desktop_file_launchv (EggDesktopFile *desktop_file,
GSList *documents, va_list args,
@@ -1078,6 +1532,9 @@ egg_desktop_file_launchv (EggDesktopFile
gboolean success, current_success;
GdkDisplay *display;
char *startup_id;
+ char *gksu_role, *final_cmd;
+ struct passwd *pw;
+ uid_t uid;
GPtrArray *env = NULL;
char **variables = NULL;
@@ -1200,11 +1657,42 @@ egg_desktop_file_launchv (EggDesktopFile
if (!command)
goto out;
- if (!g_shell_parse_argv (command, &argc, &argv, error))
- {
+ /* Only use a prefix if not in Trusted mode */
+ gksu_role = NULL;
+ if (!use_trusted_extensions ())
+ gksu_role = get_gksu_role (command);
+
+ final_cmd = NULL;
+ if (command != NULL)
+ {
+ /* Only use a prefix if not in Trusted mode */
+ gksu_role = NULL;
+ if (!use_trusted_extensions ())
+ gksu_role = get_gksu_role (command);
+
+ uid = getuid ();
+ pw = getpwuid (uid);
+
+ if (gksu_role)
+ final_cmd = g_strdup_printf ("/usr/bin/gksu -u %s %s", gksu_role, command);
+ else if (use_pfexec (command) == TRUE ||
+ (pw != NULL && pw->pw_shell != NULL &&
+ strncmp (pw->pw_shell, "/usr/bin/pf", strlen ("/usr/bin/pf")) == 0))
+ final_cmd = g_strdup_printf ("/usr/bin/pfexec %s", command);
+ else
+ final_cmd = g_strdup_printf ("%s", command);
+ }
+
+ if (gksu_role)
+ g_free (gksu_role);
+
+ if (!g_shell_parse_argv (final_cmd, &argc, &argv, error))
+ {
+ g_free (final_cmd);
g_free (command);
goto out;
}
+ g_free (final_cmd);
g_free (command);
#if GTK_CHECK_VERSION (2, 12, 0)