summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorskvidal <skvidal>2005-05-16 02:44:00 +0000
committerskvidal <skvidal>2005-05-16 02:44:00 +0000
commit4cdcf0d2ec19115d0067a8c6c4e895b6418e3a9e (patch)
treeb5dae5d058c50a17f09bb1fd35586dead94ba5a0 /src
downloadmock-4cdcf0d2ec19115d0067a8c6c4e895b6418e3a9e.tar.gz
mock-4cdcf0d2ec19115d0067a8c6c4e895b6418e3a9e.tar.xz
mock-4cdcf0d2ec19115d0067a8c6c4e895b6418e3a9e.zip
Initial revision
Diffstat (limited to 'src')
-rw-r--r--src/Makefile18
-rw-r--r--src/config.h56
-rw-r--r--src/mock-helper.c371
-rw-r--r--src/selinux-mock.c14
4 files changed, 459 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..7c103f6
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,18 @@
+CC=gcc
+EXECUTABLE=mock-helper
+SBINDIR=/usr/sbin
+MOCKGROUP=mock
+DESTDIR=''
+INSTALL=/usr/bin/install
+MKDIR=/bin/mkdir
+all:
+ $(CC) -o $(EXECUTABLE) mock-helper.c
+
+clean:
+ rm -f $(EXECUTABLE)
+ rm -f *~ *.bak
+
+install:
+ $(MKDIR) -p $(DESTDIR)/$(SBINDIR)
+ $(INSTALL) -m 4750 $(EXECUTABLE) $(DESTDIR)/$(PKGDIR)/$(SBINDIR)/$(EXECUTABLE)
+
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..1bdea48
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,56 @@
+/* config.h. Generated by configure. */
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Location of libraries */
+#define LIBDIR "/usr/lib"
+
+/* Location of local state files */
+#define LOCALSTATEDIR "/var"
+
+/* Define the version */
+#define MOCK "0.1"
+
+/* Name of package */
+#define PACKAGE "mock"
+
+/* Location of mock roots */
+#define ROOTSDIR "/var/lib/mock"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Location of configuration files */
+#define SYSCONFDIR "/etc"
+
+/* Version number of package */
+#define VERSION "0.1"
diff --git a/src/mock-helper.c b/src/mock-helper.c
new file mode 100644
index 0000000..208d6bf
--- /dev/null
+++ b/src/mock-helper.c
@@ -0,0 +1,371 @@
+/*
+ * mock-helper.c: help mock perform tasks needing root privileges
+ */
+
+#define _GNU_SOURCE
+
+#include "config.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+/* pull in configure'd defines */
+char *rootsdir = ROOTSDIR;
+
+static char const * const ALLOWED_ENV[] =
+{
+ "APT_CONFIG",
+ "dist",
+ "ftp_proxy", "http_proxy", "https_proxy", "no_proxy"
+};
+
+#define ALLOWED_ENV_SIZE (sizeof (ALLOWED_ENV) / sizeof (ALLOWED_ENV[0]))
+
+/*
+ * helper functions
+ */
+
+void
+usage ()
+{
+ printf ("Usage: mock-helper [command]\n");
+ exit (1);
+}
+
+/* print formatted string to stderr, print newline and terminate */
+void
+error (const char *format, ...)
+{
+ va_list ap;
+
+ va_start (ap, format);
+ fprintf (stderr, "mock-helper: error: ");
+ vfprintf (stderr, format, ap);
+ va_end (ap);
+ fprintf (stderr, "\n");
+ exit (1);
+}
+
+/*
+ * perform checks on the given dir
+ * - is the given dir under the allowed hierarchy ?
+ * - is it an actual dir ?
+ * - are we not being tricked by using . or .. ?
+ */
+void
+check_dir_allowed (const char *allowed, const char *given)
+{
+ struct stat buf;
+ char last;
+ int retval;
+
+ /* does given start with allowed ? */
+ if (strncmp (given, allowed, strlen (allowed)) != 0)
+ error ("%s: not under allowed directory (%s)", given, allowed);
+
+ /* does it try to fool us by using .. ? */
+ if (strstr (given, "..") != 0)
+ error ("%s: contains '..'", given);
+
+ /* does it try to fool us into following symlinks by having a trailing / ? */
+ last = given[strlen (given) - 1];
+ if (last == '/')
+ error ("%s: ends with '/'", given);
+
+ /* are we chrooting to an actual directory (not a symlink or anything) ? */
+ retval = lstat (given, &buf);
+ if (retval != 0)
+ error ("%s: %s", given, strerror (errno));
+
+ //printf ("DEBUG: mode: %o\n", buf.st_mode);
+ if (S_ISLNK (buf.st_mode))
+ error ("%s: symbolic link", given);
+ if (!(S_ISDIR (buf.st_mode)))
+ error ("%s: not a directory", given);
+}
+
+/*
+ * perform checks on the given file
+ * - is the given file under the allowed hierarchy ?
+ * - is it an actual file ?
+ * - are we not being tricked by using .. ?
+ */
+void
+check_file_allowed (const char *allowed, const char *given)
+{
+ struct stat buf;
+ char last;
+ int retval;
+
+ /* does given start with allowed ? */
+ if (strncmp (given, allowed, strlen (allowed)) != 0)
+ error ("%s: not under allowed directory", given);
+
+ /* does it try to fool us by using .. ? */
+ if (strstr (given, "..") != 0)
+ error ("%s: contains '..'", given);
+
+ /* does it have a trailing / ? */
+ last = given[strlen (given) - 1];
+ if (last == '/')
+ error ("%s: ends with '/'", given);
+
+ /* are we working with an actual file ? */
+ retval = lstat (given, &buf);
+ if (retval != 0)
+ error ("%s: %s", given, strerror (errno));
+
+ //printf ("DEBUG: mode: %o\n", buf.st_mode);
+ if (S_ISLNK (buf.st_mode))
+ error ("%s: symbolic link", given);
+ if (!(S_ISREG (buf.st_mode)))
+ error ("%s: not a regular file", given);
+}
+
+/* argv[0] should by convention be the binary name to be executed */
+void
+do_command (const char *filename, char *const argv[])
+{
+ /* do not trust user environment;
+ * copy over allowed env vars, after setting PATH and HOME ourselves
+ */
+ char *env[3 + ALLOWED_ENV_SIZE] = {
+ [0] = "PATH=/bin:/usr/bin:/usr/sbin",
+ [1] = "HOME=/root"
+ };
+ int retval;
+ char **arg;
+ size_t idx=2;
+ size_t i;
+ char *envvar;
+ char *ld_preload;
+
+ /* elevate privileges */
+ setreuid (geteuid (), geteuid ());
+ //printf ("DEBUG: First argument: %s\n", *argv);
+ //printf ("DEBUG: Executing %s\n", filename);
+ /* FIXME: for a debug option */
+ /*
+ printf ("Executing %s ", filename);
+ for (arg = (char **) &(argv[1]); *arg; ++arg)
+ printf ("%s ", *arg);
+ printf ("\n");
+ */
+
+ /* add LD_PRELOAD for our selinux lib if MOCK_LD_PRELOAD is set */
+ envvar = getenv ("MOCK_LD_PRELOAD");
+ if (envvar != 0)
+ {
+ ld_preload = strdup("LD_PRELOAD=" LIBDIR "/libselinux-mock.so");
+ env[idx++] = ld_preload;
+ }
+
+ for (i = 0; i < ALLOWED_ENV_SIZE; ++i)
+ {
+ char *ptr = getenv (ALLOWED_ENV[i]);
+ if (ptr==0) continue;
+ ptr -= strlen (ALLOWED_ENV[i]) + 1;
+ env[idx++] = ptr;
+ }
+
+ retval = execve (filename, argv, env);
+ error ("executing %s: %s", filename, strerror (errno));
+}
+
+/*
+ * actual command implementations
+ */
+
+
+void
+do_chroot (int argc, char *argv[])
+{
+ if (argc < 3)
+ error ("No directory given for chroot !");
+ //printf ("DEBUG: rootsdir: %s\n", rootsdir);
+
+ /* do we allow this dir ? */
+ check_dir_allowed (rootsdir, argv[2]);
+
+ do_command ("/usr/sbin/chroot", &(argv[1]));
+}
+
+/*
+ * allow proc mounts:
+ * mount -t proc proc (root)/proc
+ * allow devpts mounts:
+ * mount -t devpts -o uid=500,gid=500 devpts (root)/dev/pts
+ */
+void
+do_mount (int argc, char *argv[])
+{
+ /* see if we have enough arguments for it to be what we want, ie. 5 */
+ if (argc < 5)
+ error ("not enough arguments");
+
+ /* see if it's -t proc or -t devpts */
+ if ((strncmp ("-t", argv[2], 2) == 0) &&
+ (strncmp ("proc", argv[3], 4) == 0))
+ {
+ /* see if we're mounting proc to somewhere in rootsdir */
+ if (strncmp (rootsdir, argv[5], strlen (rootsdir)) != 0)
+ error ("proc: mount not allowed on %s", argv[5]);
+ }
+ else if ((strncmp ("-t", argv[2], 2) == 0) &&
+ (strncmp ("devpts", argv[3], 6) == 0))
+ {
+ if (argc < 7)
+ error ("devpts: not enough mount arguments");
+ else if ((strncmp ("-o", argv[4], 2) != 0) ||
+ (strncmp ("uid=500,gid=500", argv[5], 15) != 0))
+ error ("devpts: unallowed mount options");
+ /* see if we're mounting devpts to somewhere in rootsdir */
+ else if (strncmp (rootsdir, argv[7], strlen (rootsdir)) != 0)
+ error ("devpts: mount not allowed on %s", argv[7]);
+ }
+ else
+ error ("unallowed mount type");
+
+ /* all checks passed, execute */
+ do_command ("/bin/mount", &(argv[1]));
+}
+
+/* clean out a chroot dir */
+void
+do_rm (int argc, char *argv[])
+{
+ /* enough arguments ? mock-helper rm -rfv (rootdir), 4 */
+ if (argc < 4)
+ error ("not enough arguments");
+
+ /* see if we're doing rm -rfv */
+ if (strncmp ("-rfv", argv[2], 4) != 0)
+ error ("%s: options not allowed", argv[2]);
+
+ /* see if we're doing -rfv on a dir under rootsdir */
+ check_dir_allowed (rootsdir, argv[3]);
+
+ /* all checks passed, execute */
+ do_command ("/bin/rm", &(argv[1]));
+}
+
+/* perform rpm commands on root */
+void
+do_rpm (int argc, char *argv[])
+{
+ /* enough arguments ? mock-helper rpm --root (rootdir) ... , 4 */
+ if (argc < 4)
+ error ("not enough arguments");
+
+ /* --root */
+ if (strncmp ("--root", argv[2], 6) != 0)
+ error ("%s: options not allowed", argv[2]);
+
+ /* check given dir */
+ check_dir_allowed (rootsdir, argv[3]);
+
+ /* all checks passed, execute */
+ do_command ("/bin/rpm", &(argv[1]));
+}
+
+
+void
+do_yum (int argc, char *argv[])
+{
+ /* enough arguments ? mock-helper yum --installroot (rootdir) ... , 4 */
+ if (argc < 4)
+ error ("not enough arguments");
+
+ /* --root */
+ if (strncmp ("--installroot", argv[2], 6) != 0)
+ error ("%s: options not allowed", argv[2]);
+
+ /* check given dir */
+ check_dir_allowed (rootsdir, argv[3]);
+
+ /* all checks passed, execute */
+ do_command ("/usr/bin/yum", &(argv[1]));
+}
+
+
+/* unmount archivesdir and proc */
+void
+do_umount (int argc, char *argv[])
+{
+ /* enough arguments ? mock-helper umount (dir), 3 */
+ if (argc < 3)
+ error ("not enough arguments");
+
+ /* see if we're unmounting from somewhere in rootsdir */
+ check_dir_allowed (rootsdir, argv[2]);
+
+ /* all checks passed, execute */
+ do_command ("/bin/umount", &(argv[1]));
+}
+
+/* make /dev/ device nodes */
+void
+do_mknod (int argc, char *argv[])
+{
+ /* enough arguments ? mock-helper mknod (name) -m (mode) (type) (major) (minor), 8 */
+ if (argc < 8)
+ error ("not enough arguments");
+
+ /* check given file */
+ if (strncmp (argv[2], rootsdir, strlen (rootsdir)) != 0)
+ error ("%s: not under allowed directory (%s)", argv[2], rootsdir);
+
+ /* does it try to fool us by using .. ? */
+ if (strstr (argv[2], "..") != 0)
+ error ("%s: contains '..'", argv[2]);
+
+ /* does it have a trailing / ? */
+ int last = argv[2][strlen (argv[2]) - 1];
+ if (last == '/')
+ error ("%s: ends with '/'", argv[2]);
+
+ /* -m */
+ if (strncmp ("-m", argv[3], 2) != 0)
+ error ("%s: options not allowed", argv[3]);
+
+ /* removed specific checks so we can make more than just /dev/null */
+ /* all checks passed, execute */
+ do_command ("/bin/mknod", &(argv[1]));
+}
+
+int
+main (int argc, char *argv[])
+{
+
+ /* verify input */
+ if (argc < 2) usage ();
+
+ /* see which command we are trying to run */
+ if (strncmp ("chroot", argv[1], 6) == 0)
+ do_chroot (argc, argv);
+ else if (strncmp ("mount", argv[1], 5) == 0)
+ do_mount (argc, argv);
+ else if (strncmp ("rm", argv[1], 2) == 0)
+ do_rm (argc, argv);
+ else if (strncmp ("umount", argv[1], 6) == 0)
+ do_umount (argc, argv);
+ else if (strncmp ("rpm", argv[1], 3) == 0)
+ do_rpm (argc, argv);
+ else if (strncmp ("mknod", argv[1], 5) == 0)
+ do_mknod (argc, argv);
+ else if (strncmp ("env", argv[1], 3) == 0)
+ do_command ("/bin/env", &(argv[1]));
+ else if (strncmp ("yum", argv[1], 3) == 0)
+ do_yum (argc, argv);
+ else
+ {
+ error ("Command %s not recognized !\n", argv[1]);
+ exit (1);
+ }
+ exit (0);
+}
diff --git a/src/selinux-mock.c b/src/selinux-mock.c
new file mode 100644
index 0000000..6769efc
--- /dev/null
+++ b/src/selinux-mock.c
@@ -0,0 +1,14 @@
+#include <selinux/selinux.h>
+
+extern int is_selinux_enabled(void)
+{
+ /* always return 0; this way we don't trigger any SELINUX calls */
+ return 0;
+}
+
+/* this function gives failures when installing basic rpms in the root;
+ * so we fake it out as well */
+extern int lsetfilecon(const char *path, security_context_t con)
+{
+ return 0;
+}