summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorWilliam Jon McCann <mccann@jhu.edu>2007-03-02 17:51:37 -0500
committerWilliam Jon McCann <mccann@jhu.edu>2007-03-02 17:51:37 -0500
commit4f0911bf685f51b51d05a69a40d3950debb995a0 (patch)
tree1b5d38a8e52126e200c8954b3c185ca7ff4f3f94 /tools
parent75ad4b862611bd6a39bda06db3db4c9737657dad (diff)
add linux backends for collecting session information
These tools will be used to generate and verify the parameters used to open a session.
Diffstat (limited to 'tools')
-rw-r--r--tools/linux/Makefile.am23
-rw-r--r--tools/linux/ck-collect-session-info.c390
-rw-r--r--tools/linux/ck-get-x11-server-pid.c75
3 files changed, 487 insertions, 1 deletions
diff --git a/tools/linux/Makefile.am b/tools/linux/Makefile.am
index 5091efe..3283b5e 100644
--- a/tools/linux/Makefile.am
+++ b/tools/linux/Makefile.am
@@ -9,6 +9,7 @@ SUBDIRS = \
INCLUDES = \
-I. \
-I$(srcdir) \
+ -I$(top_srcdir)/src \
$(CONSOLE_KIT_CFLAGS) \
$(DISABLE_DEPRECATED_CFLAGS) \
-DPREFIX=\""$(prefix)"\" \
@@ -22,7 +23,27 @@ INCLUDES = \
$(TOOLS_CFLAGS) \
$(NULL)
-libexec_PROGRAMS = \
+libexec_PROGRAMS = \
+ ck-collect-session-info \
+ ck-get-x11-server-pid \
+ $(NULL)
+
+ck_collect_session_info_SOURCES = \
+ $(top_srcdir)/src/proc.h \
+ $(top_srcdir)/src/proc-linux.c \
+ ck-collect-session-info.c \
+ $(NULL)
+
+ck_collect_session_info_LDADD = \
+ $(TOOLS_LIBS) \
+ $(NULL)
+
+ck_get_x11_server_pid_SOURCES = \
+ ck-get-x11-server-pid.c \
+ $(NULL)
+
+ck_get_x11_server_pid_LDADD = \
+ $(TOOLS_LIBS) \
$(NULL)
EXTRA_DIST = \
diff --git a/tools/linux/ck-collect-session-info.c b/tools/linux/ck-collect-session-info.c
new file mode 100644
index 0000000..2979da0
--- /dev/null
+++ b/tools/linux/ck-collect-session-info.c
@@ -0,0 +1,390 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ *
+ * 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.
+ *
+ * Authors: William Jon McCann <mccann@jhu.edu>
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "proc.h"
+
+typedef struct {
+ uid_t uid;
+ pid_t pid;
+ char *display_device;
+ char *x11_display;
+ gboolean x11_can_connect;
+ char *hostname;
+ char *session_type;
+ gboolean is_local;
+ gboolean is_local_is_set;
+} SessionInfo;
+
+static void
+session_info_free (SessionInfo *si)
+{
+ g_free (si->display_device);
+ g_free (si->x11_display);
+ g_free (si->hostname);
+ g_free (si->session_type);
+ g_free (si);
+}
+
+static void
+setuid_child_setup_func (SessionInfo *si)
+{
+ int res;
+ struct passwd *pwent;
+
+ errno = 0;
+ pwent = getpwuid (si->uid);
+ if (pwent == NULL) {
+ g_warning ("Unable to lookup UID: %s", g_strerror (errno));
+ exit (1);
+ }
+
+ /* set the group */
+ errno = 0;
+ res = setgid (pwent->pw_gid);
+ if (res == -1) {
+ g_warning ("Error performing setgid: %s", g_strerror (errno));
+ exit (1);
+ }
+
+ /* become the user */
+ errno = 0;
+ res = setuid (si->uid);
+ if (res == -1) {
+ g_warning ("Error performing setuid: %s", g_strerror (errno));
+ exit (1);
+ }
+}
+
+static GPtrArray *
+get_filtered_environment (pid_t pid)
+{
+ GPtrArray *env;
+ GHashTable *hash;
+ int i;
+ static const char *allowed_env_vars [] = {
+ "DISPLAY",
+ "XAUTHORITY",
+ "XAUTHLOCALHOSTNAME",
+ "SSH_CLIENT",
+ "SSH_CONNECTION",
+ "SSH_TTY",
+ "HOME",
+ };
+
+ env = g_ptr_array_new ();
+
+ g_ptr_array_add (env, g_strdup ("PATH=/bin:/usr/bin"));
+
+ hash = proc_pid_get_env_hash (pid);
+
+ for (i = 0; i < G_N_ELEMENTS (allowed_env_vars); i++) {
+ const char *var;
+ const char *val;
+ var = allowed_env_vars [i];
+ val = g_hash_table_lookup (hash, var);
+ if (val != NULL) {
+ char *str;
+ str = g_strdup_printf ("%s=%s", var, val);
+ g_ptr_array_add (env, str);
+ }
+ }
+
+ g_ptr_array_add (env, NULL);
+
+ g_hash_table_destroy (hash);
+
+ return env;
+}
+
+static void
+get_x11_server_pid (SessionInfo *si,
+ gboolean *can_connect,
+ guint *pid)
+{
+ gboolean res;
+ char *err;
+ char *out;
+ int status;
+ int i;
+ GError *error;
+ guint num;
+ char *argv[4];
+ GPtrArray *env;
+
+ if (can_connect != NULL) {
+ *can_connect = FALSE;
+ }
+ if (pid != NULL) {
+ *pid = 0;
+ }
+
+ /* get the applicable environment */
+ env = get_filtered_environment (si->pid);
+
+ num = 0;
+
+ argv[0] = LIBEXECDIR "/ck-get-x11-server-pid";
+ argv[1] = NULL;
+
+ error = NULL;
+ out = NULL;
+ err = NULL;
+ status = -1;
+ res = g_spawn_sync (NULL,
+ argv,
+ (char **)env->pdata,
+ 0,
+ (GSpawnChildSetupFunc)setuid_child_setup_func,
+ si,
+ &out,
+ &err,
+ &status,
+ &error);
+ for (i = 0; i < env->len; i++) {
+ g_free (g_ptr_array_index (env, i));
+ }
+ g_ptr_array_free (env, TRUE);
+
+ if (error != NULL) {
+ g_warning ("Unable to PID for x11 server: %s", error->message);
+ g_error_free (error);
+ }
+
+ if (status == 0) {
+ if (res && out != NULL) {
+ guint v;
+ char c;
+
+ if (1 == sscanf (out, "%u %c", &v, &c)) {
+ num = v;
+ }
+ }
+
+ if (can_connect != NULL) {
+ *can_connect = TRUE;
+ }
+ }
+
+
+ if (err != NULL && err[0] != '\0') {
+ g_warning ("%s", err);
+ }
+
+ if (pid != NULL) {
+ *pid = num;
+ }
+
+ g_free (out);
+ g_free (err);
+}
+
+/* Looking at the XFree86_VT property on the root window
+ * doesn't work very well because it is difficult to
+ * distinguish local from remote systems and the value
+ * can't necessarily be trusted. So instead we connect
+ * to the server and use peer credentials to find the
+ * local PID and then find its tty.
+ */
+static void
+fill_x11_info (SessionInfo *si)
+{
+ guint xorg_pid;
+ gboolean can_connect;
+ gboolean res;
+ proc_stat_t *xorg_stat;
+ GError *error;
+
+ /* assume this is true then check it */
+ si->x11_display = proc_pid_get_env (si->pid, "DISPLAY");
+
+ if (si->x11_display == NULL) {
+ /* no point continuing */
+ si->x11_can_connect = FALSE;
+ return;
+ }
+
+ xorg_pid = 0;
+ can_connect = FALSE;
+ get_x11_server_pid (si, &can_connect, &xorg_pid);
+
+ si->x11_can_connect = can_connect;
+ if (! can_connect) {
+ g_free (si->x11_display);
+ si->x11_display = NULL;
+ return;
+ }
+
+ if (xorg_pid < 2) {
+ /* keep the tty value */
+ /* if we can connect but don't have a pid
+ * then we're not local */
+
+ si->is_local = FALSE;
+ si->is_local_is_set = TRUE;
+ return;
+ }
+
+ error = NULL;
+ res = proc_stat_new_for_pid (xorg_pid, &xorg_stat, &error);
+ if (! res) {
+ if (error != NULL) {
+ g_warning ("stat on pid %d failed: %s", xorg_pid, error->message);
+ g_error_free (error);
+ }
+ /* keep the tty value */
+ return;
+ }
+
+ /* overwrite the tty value */
+ g_free (si->display_device);
+ si->display_device = proc_stat_get_tty (xorg_stat);
+ proc_stat_free (xorg_stat);
+
+ si->is_local = TRUE;
+ si->is_local_is_set = TRUE;
+
+ g_free (si->hostname);
+ si->hostname = g_strdup ("localhost");
+}
+
+static gboolean
+fill_session_info (SessionInfo *si)
+{
+ proc_stat_t *stat;
+ GError *error;
+ gboolean res;
+
+ error = NULL;
+ res = proc_stat_new_for_pid (si->pid, &stat, &error);
+ if (! res) {
+ if (error != NULL) {
+ g_warning ("stat on pid %d failed: %s", si->pid, error->message);
+ g_error_free (error);
+ }
+
+ return FALSE;
+ }
+
+ si->display_device = proc_stat_get_tty (stat);
+ si->session_type = proc_stat_get_cmd (stat);
+ proc_stat_free (stat);
+
+ fill_x11_info (si);
+
+ return TRUE;
+}
+
+static void
+print_session_info (SessionInfo *si)
+{
+ if (si->display_device != NULL) {
+ printf ("display-device = %s\n", si->display_device);
+ }
+ if (si->x11_display != NULL) {
+ printf ("x11-display = %s\n", si->x11_display);
+ }
+ if (si->session_type != NULL) {
+ printf ("session-type = %s\n", si->session_type);
+ }
+ if (si->hostname != NULL) {
+ printf ("host-name = %s\n", si->hostname);
+ }
+ if (si->is_local_is_set == TRUE) {
+ printf ("is-local = %s\n", si->is_local ? "true" : "false");
+ }
+}
+
+static gboolean
+collect_session_info (uid_t uid,
+ pid_t pid)
+{
+ SessionInfo *si;
+ gboolean ret;
+
+ si = g_new0 (SessionInfo, 1);
+
+ si->uid = uid;
+ si->pid = pid;
+
+ ret = fill_session_info (si);
+ if (ret) {
+ print_session_info (si);
+ }
+
+ session_info_free (si);
+
+ return ret;
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ GOptionContext *context;
+ gboolean ret;
+ GError *error;
+ static int user_id;
+ static int process_id;
+ static GOptionEntry entries [] = {
+ { "uid", 0, 0, G_OPTION_ARG_INT, &user_id, "User ID", NULL },
+ { "pid", 0, 0, G_OPTION_ARG_INT, &process_id, "Process ID", NULL },
+ { NULL }
+ };
+
+ context = g_option_context_new (NULL);
+ g_option_context_add_main_entries (context, entries, NULL);
+ error = NULL;
+ ret = g_option_context_parse (context, &argc, &argv, &error);
+ g_option_context_free (context);
+
+ if (! ret) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ exit (1);
+ }
+
+ if (user_id < 500) {
+ g_warning ("Invalid UID");
+ exit (1);
+ }
+
+ if (process_id < 2) {
+ g_warning ("Invalid PID");
+ exit (1);
+ }
+
+ ret = collect_session_info (user_id, process_id);
+
+ return ret;
+}
diff --git a/tools/linux/ck-get-x11-server-pid.c b/tools/linux/ck-get-x11-server-pid.c
new file mode 100644
index 0000000..4e5d6c5
--- /dev/null
+++ b/tools/linux/ck-get-x11-server-pid.c
@@ -0,0 +1,75 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
+ *
+ * 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.
+ *
+ * Authors: William Jon McCann <mccann@jhu.edu>
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+
+static void
+print_peer_pid (int fd)
+{
+#ifdef SO_PEERCRED
+ struct ucred cr;
+ int cr_len = sizeof (cr);
+
+ if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 && cr_len == sizeof (cr)) {
+ /* paranoia check for peer running as root */
+ if (cr.uid == 0) {
+ printf ("%u\n", cr.pid);
+ }
+ } else {
+ g_warning ("Failed to getsockopt() credentials, returned len %d/%d: %s\n",
+ cr_len,
+ (int) sizeof (cr),
+ g_strerror (errno));
+ }
+#endif
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ int fd;
+ int ret;
+
+ ret = 1;
+
+ gdk_init (&argc, &argv);
+
+ fd = ConnectionNumber (GDK_DISPLAY());
+
+ if (fd > 0) {
+ ret = 0;
+ print_peer_pid (fd);
+ }
+
+ return ret;
+}