[glick2] Add glick-session-launcher



commit c6a3a85f691d0aeabac7078b4e83bd3517186d79
Author: Alexander Larsson <alexl redhat com>
Date:   Thu Oct 13 15:02:02 2011 +0200

    Add glick-session-launcher

 Makefile.am |    5 ++
 session.c   |  201 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 206 insertions(+), 0 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 50de9c6..d5ad777 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -14,6 +14,7 @@ AM_CPPFLAGS =					\
 
 bin_PROGRAMS =					\
 	glick-launcher				\
+	glick-session-launcher			\
 	glick-mkbundle				\
 	glick-runner				\
 	glick-fs				\
@@ -31,6 +32,8 @@ glick_helper_LDADD = $(GLIB_LIBS)
 glick_launcher_SOURCES = launcher.c
 glick_launcher_LDADD = $(GLIB_LIBS) $(X11_LIBS)
 
+glick_session_launcher_SOURCES = session.c
+
 glick_makershared_SOURCES = makershared.c
 
 glick_runner_SOURCES = runner.c
@@ -49,6 +52,8 @@ install-data-local:
 install-exec-hook:
 	chown root $(DESTDIR)$(libexecdir)/glick-helper
 	chmod 4755 $(DESTDIR)$(libexecdir)/glick-helper
+	chown root $(DESTDIR)$(libexecdir)/glick-session-launcher
+	chmod 4755 $(DESTDIR)$(libexecdir)/glick-session-launcher
 
 ChangeLog:
 	$(AM_V_GEN) if test -d "$(srcdir)/.git"; then \
diff --git a/session.c b/session.c
new file mode 100644
index 0000000..ab2bb92
--- /dev/null
+++ b/session.c
@@ -0,0 +1,201 @@
+#include "config.h"
+
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <sched.h>
+
+static const char *
+get_homedir (void)
+{
+  const char *home;
+
+  home = getenv ("HOME");
+  if (home == NULL)
+    {
+      /* try from the user database */
+      struct passwd *user = getpwuid (getuid());
+      if (user != NULL)
+	home = user->pw_dir;
+    }
+
+  return home;
+}
+
+static char *
+build_path (const char *dir, const char *file)
+{
+  char *path;
+
+  path = malloc (strlen (dir) + 1 + strlen (file) + 1);
+
+  if (path != NULL)
+    {
+      strcpy (path, dir);
+      strcat (path, "/");
+      strcat (path, file);
+    }
+  return path;
+}
+
+static void
+make_symlink (const char *dest_dir, const char *dest_file,
+	      const char *src_dir, const char *src_file)
+{
+  char *d, *s;
+
+  d = build_path (dest_dir, dest_file);
+  if (d)
+    {
+      s = build_path (src_dir, src_file);
+      if (s)
+	{
+	  if (symlink (s, d) == -1 && errno != EEXIST)
+	    perror ("Failed to symlink");
+	  free (s);
+	}
+      free (d);
+    }
+}
+
+static int
+mount_rprivate (const char *path)
+{
+  return mount (path, path, NULL, MS_PRIVATE|MS_REC, NULL);
+}
+
+static int
+mount_rshared (const char *path)
+{
+  return mount (path, path, NULL, MS_SHARED|MS_REC, NULL);
+}
+
+static int
+mount_bind (const char *src, const char *dest)
+{
+  return mount (src, dest, NULL, MS_BIND, NULL);
+}
+
+int
+main(int argc, char **argv)
+{
+  char *session_dir;
+  const char *runtime_dir;
+  const char *homedir;
+  int res;
+
+  /* The initial code is run with a high permission euid
+     (at least CAP_SYS_ADMIN), so take lots of care. */
+
+  /* Switch effective uid to the user */
+  seteuid (getuid ());
+  
+  if (argc == 1)
+    {
+      fprintf (stderr, "No executable specified\n");
+      return 1;
+    }
+
+
+  homedir = get_homedir ();
+  if (homedir == NULL)
+    goto error;
+  
+  runtime_dir = getenv ("XDG_RUNTIME_DIR");
+  if (runtime_dir != NULL)
+    {
+      session_dir = build_path (runtime_dir, "sessiondir");
+      if (session_dir == NULL)
+	{
+	  fprintf (stderr, "Out of memory\n");
+	  goto error;
+	}
+      
+      if (mkdir (session_dir, 0700) == -1 && errno != EEXIST)
+	{
+	  fprintf (stderr, "Unable to create temporary session directory\n");
+	  goto error;
+	}
+    }
+  else
+    {
+      /* Fall back to /tmp dir */
+      char tmpdir[] = "/tmp/.sessionXXXXXX";
+      session_dir = mkdtemp(tmpdir);
+      if (session_dir == NULL)
+	{
+	  fprintf (stderr, "Unable to create temporary session directory\n");
+	  goto error;
+	}
+    }
+
+  if (setuid (0) == -1)
+    {
+      perror ("Unable to regain root priviledges");
+      goto error;
+    }
+
+  /* Create a new mount namespace for the session */
+  res = unshare (CLONE_NEWNS);
+  if (res != 0)
+    {
+      perror ("Creating new namespace failed");
+      goto error;
+   }
+
+  /* Start with a clean slate, all mounts private */
+  res = mount_rprivate ("/");
+  if (res != 0)
+    {
+      perror ("Failed to make rprivate");
+      goto error;
+     }
+
+  /* Make /opt/session point to the session directory.
+     This will not propagate dure to the rprivate above.  */
+  res = mount_bind (session_dir, SESSION_PREFIX);
+  if (res != 0)
+    {
+      perror ("Failed to bind session dir");
+      goto error;
+    }
+
+  /* Make the whole new namespace rshared so that later session
+     mounts are propagated to child bundle namespaces */
+  res = mount_rshared ("/");
+  if (res != 0)
+    {
+      perror ("Failed to make rshared");
+      goto error;
+    }
+
+  /* Except the session dir. */
+  res = mount (SESSION_PREFIX, SESSION_PREFIX,
+	       NULL, MS_PRIVATE, NULL);
+  if (res != 0)
+    {
+      perror ("Failed to make session dir private");
+      goto error;
+    }
+
+  /* Now we have everything we need CAP_SYS_ADMIN for, so drop setuid */
+  setuid (getuid ());
+
+  make_symlink (session_dir, "bundles",
+		homedir, ".glick/bundles");
+  make_symlink (session_dir, "exports",
+		homedir, ".glick/exports");
+  
+  return execvp (argv[1], argv+1);
+ error:
+  /* Now we have everything we need CAP_SYS_ADMIN for, so drop setuid */
+  setuid (getuid ());
+
+  return execvp (argv[1], argv+1);
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]