summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJason Stubbs <jstubbs@gentoo.org>2005-08-28 08:37:44 +0000
committerJason Stubbs <jstubbs@gentoo.org>2005-08-28 08:37:44 +0000
commitd9fc4acc572c6647a4f27b838d35d27d805d190e (patch)
tree262a8de35d8c7567312757da5f1f66efdc8cece5 /src
downloadportage-multirepo-d9fc4acc572c6647a4f27b838d35d27d805d190e.tar.gz
portage-multirepo-d9fc4acc572c6647a4f27b838d35d27d805d190e.tar.bz2
portage-multirepo-d9fc4acc572c6647a4f27b838d35d27d805d190e.zip
Migration (without history) of the current stable line to subversion.
svn path=/main/branches/2.0/; revision=1941
Diffstat (limited to 'src')
-rw-r--r--src/bsd-flags/PKG-INFO10
-rw-r--r--src/bsd-flags/chflags.c161
-rw-r--r--src/bsd-flags/setup.cfg6
-rwxr-xr-xsrc/bsd-flags/setup.py24
-rw-r--r--src/python-missingos/ChangeLog16
-rw-r--r--src/python-missingos/PKG-INFO10
-rw-r--r--src/python-missingos/README15
-rw-r--r--src/python-missingos/missingos.c120
-rw-r--r--src/python-missingos/setup.cfg8
-rwxr-xr-xsrc/python-missingos/setup.py24
-rw-r--r--src/sandbox-1.1/ChangeLog265
-rw-r--r--src/sandbox-1.1/Makefile81
-rw-r--r--src/sandbox-1.1/canonicalize.c173
-rwxr-xr-xsrc/sandbox-1.1/create-localdecls115
-rw-r--r--src/sandbox-1.1/getcwd.c511
-rw-r--r--src/sandbox-1.1/libctest.c7
-rw-r--r--src/sandbox-1.1/libsandbox.c1383
-rw-r--r--src/sandbox-1.1/sandbox.bashrc8
-rw-r--r--src/sandbox-1.1/sandbox.c863
-rw-r--r--src/sandbox-1.1/sandbox.h68
-rw-r--r--src/sandbox-1.1/sandbox_futils.c513
-rw-r--r--src/sandbox-dev/ChangeLog91
-rw-r--r--src/sandbox-dev/Makefile62
-rw-r--r--src/sandbox-dev/canonicalize.c194
-rwxr-xr-xsrc/sandbox-dev/create-localdecls95
-rw-r--r--src/sandbox-dev/libctest.c6
-rw-r--r--src/sandbox-dev/libsandbox.c1214
-rw-r--r--src/sandbox-dev/sandbox.bashrc8
-rw-r--r--src/sandbox-dev/sandbox.c816
-rw-r--r--src/sandbox-dev/sandbox.h69
-rw-r--r--src/sandbox-dev/sandbox_futils.c352
-rw-r--r--src/sandbox/Makefile30
-rw-r--r--src/sandbox/libsandbox.c873
-rw-r--r--src/sandbox/problems/Makefile31
-rw-r--r--src/sandbox/problems/libsandbox_emacsbug.c34
-rw-r--r--src/sandbox/problems/libsandbox_muttbug.c24
-rw-r--r--src/sandbox/problems/sandbox_dev_fd_foo.c42
-rw-r--r--src/sandbox/problems/sandbox_muttbug.c43
-rw-r--r--src/sandbox/sandbox.bashrc8
-rw-r--r--src/sandbox/sandbox.c921
-rw-r--r--src/tbz2tool.c228
41 files changed, 9522 insertions, 0 deletions
diff --git a/src/bsd-flags/PKG-INFO b/src/bsd-flags/PKG-INFO
new file mode 100644
index 00000000..f2cb5c58
--- /dev/null
+++ b/src/bsd-flags/PKG-INFO
@@ -0,0 +1,10 @@
+Metadata-Version: 1.0
+Name: bsd-chflags
+Version: 0.1
+Summary: UNKNOWN
+Home-page: UNKNOWN
+Author: Stephen Bennett
+Author-email: spb@gentoo.org
+License: UNKNOWN
+Description: UNKNOWN
+Platform: UNKNOWN
diff --git a/src/bsd-flags/chflags.c b/src/bsd-flags/chflags.c
new file mode 100644
index 00000000..77b89a28
--- /dev/null
+++ b/src/bsd-flags/chflags.c
@@ -0,0 +1,161 @@
+/* $Header: /var/cvsroot/gentoo-src/portage/src/bsd-flags/chflags.c,v 1.1.2.2 2005/02/13 10:48:31 jstubbs Exp $ */
+
+#include "Python.h"
+
+#include <sys/stat.h>
+
+static char chflags_lchflags__doc__[];
+static PyObject * chflags_lchflags(PyObject *self, PyObject *args);
+static char chflags_lgetflags__doc__[];
+static PyObject * chflags_lgetflags(PyObject *self, PyObject *args);
+static char chflags_lhasproblems__doc__[];
+static PyObject * chflags_lhasproblems(PyObject *self, PyObject *args);
+
+static char chflags__doc__[] = "Provide some operations for manipulating" \
+ "FreeBSD's filesystem flags";
+
+static PyMethodDef chflags_methods[] = {
+ {"lchflags", chflags_lchflags, METH_VARARGS, chflags_lchflags__doc__},
+ {"lgetflags", chflags_lgetflags, METH_VARARGS, chflags_lgetflags__doc__},
+ {"lhasproblems", chflags_lhasproblems, METH_VARARGS, chflags_lhasproblems__doc__},
+ {NULL, NULL}
+};
+
+static char chflags_lchflags__doc__[] =
+"lchflags(path, flags) -> None\n\
+Change the flags on path to equal flags.";
+
+static char chflags_lgetflags__doc__[] =
+"lgetflags(path) -> Integer\n\
+Returns the file flags on path.";
+
+static char chflags_lhasproblems__doc__[] =
+"lhasproblems(path) -> Integer\n\
+Returns 1 if path has any flags set that prevent write operations;\n\
+0 otherwise.";
+
+static const unsigned long problemflags=0x00160016;
+
+#if defined __FreeBSD__
+static PyObject *chflags_lchflags(PyObject *self, PyObject *args)
+{
+ char *path = NULL;
+ int flags;
+ int res;
+
+ if (!PyArg_ParseTuple(args, "eti:lchflags",
+ Py_FileSystemDefaultEncoding, &path,
+ &flags))
+ {
+ return NULL;
+ }
+
+ res = lchflags(path, flags);
+
+ PyMem_Free(path);
+ return PyInt_FromLong((long)res);
+}
+
+static PyObject *chflags_lhasproblems(PyObject *self, PyObject *args)
+{
+ char *path = NULL;
+ struct stat sb;
+ int res;
+
+ if (!PyArg_ParseTuple(args, "et:lhasproblems",
+ Py_FileSystemDefaultEncoding, &path))
+ {
+ return NULL;
+ }
+
+ res = lstat(path, &sb);
+
+ PyMem_Free(path);
+
+ if (res < 0)
+ {
+ return PyInt_FromLong((long)res);
+ }
+
+ if (sb.st_flags & problemflags)
+ return PyInt_FromLong(1);
+ else
+ return PyInt_FromLong(0);
+}
+
+static PyObject *chflags_lgetflags(PyObject *self, PyObject *args)
+{
+ char *path = NULL;
+ struct stat sb;
+ int res;
+
+ if (!PyArg_ParseTuple(args, "et:lgetflags",
+ Py_FileSystemDefaultEncoding, &path))
+ {
+ return NULL;
+ }
+
+ res = lstat(path, &sb);
+
+ if (res < 0)
+ {
+ PyMem_Free(path);
+ return PyInt_FromLong((long)res);
+ }
+
+ PyMem_Free(path);
+
+ return PyInt_FromLong((long)sb.st_flags);
+}
+
+#else
+#warning Not on FreeBSD; building dummy lchflags
+
+static PyObject *chflags_lgetflags(PyObject *self, PyObject *args)
+{
+ /* Obviously we can't set flags if the OS/filesystem doesn't support them. */
+ return PyInt_FromLong(0);
+}
+
+static PyObject *chflags_lchflags(PyObject *self, PyObject *args)
+{
+ /* If file system flags aren't supported, just return 0,
+ as the effect is basically the same. */
+ return PyInt_FromLong(0);
+}
+
+static PyObject *chflags_lhasproblems(PyObject *self, PyObject *args)
+{
+ return PyInt_FromLong(0);
+}
+
+#endif
+
+static int ins(PyObject *m, char *symbolname, int value)
+{
+ return PyModule_AddIntConstant(m, symbolname, value);
+}
+
+DL_EXPORT(void) initchflags(void)
+{
+ PyObject *m;
+ m = Py_InitModule4("chflags", chflags_methods, chflags__doc__,
+ (PyObject*)NULL, PYTHON_API_VERSION);
+
+ ins(m, "UF_SETTABLE", 0x0000ffff);
+ ins(m, "UF_NODUMP", 0x00000001);
+ ins(m, "UF_IMMUTABLE", 0x00000002);
+ ins(m, "UF_APPEND", 0x00000004);
+ ins(m, "UF_OPAQUE", 0x00000008);
+ ins(m, "UF_NOUNLINK", 0x00000010);
+
+ ins(m, "SF_SETTABLE", 0xffff0000);
+ ins(m, "SF_NODUMP", 0x00010000);
+ ins(m, "SF_IMMUTABLE", 0x00020000);
+ ins(m, "SF_APPEND", 0x00040000);
+ ins(m, "SF_OPAQUE", 0x00080000);
+ ins(m, "SF_NOUNLINK", 0x00100000);
+ ins(m, "SF_SNAPSHOT", 0x00200000);
+
+ ins(m, "PROBLEM_FLAGS", 0x00160016);
+}
diff --git a/src/bsd-flags/setup.cfg b/src/bsd-flags/setup.cfg
new file mode 100644
index 00000000..7bb13404
--- /dev/null
+++ b/src/bsd-flags/setup.cfg
@@ -0,0 +1,6 @@
+# bsd-flags
+# $Header: /var/cvsroot/gentoo-src/portage/src/bsd-flags/setup.cfg,v 1.1.2.1 2005/02/06 12:56:40 carpaski Exp $
+
+[bdist_rpm]
+release = 1
+python=python2
diff --git a/src/bsd-flags/setup.py b/src/bsd-flags/setup.py
new file mode 100755
index 00000000..6f4a12ba
--- /dev/null
+++ b/src/bsd-flags/setup.py
@@ -0,0 +1,24 @@
+#! /usr/bin/env python
+# $Header: /var/cvsroot/gentoo-src/portage/src/bsd-flags/setup.py,v 1.1.2.1 2005/02/06 12:56:40 carpaski Exp $
+
+from os import chdir, stat
+from distutils.core import setup, Extension
+
+setup (# Distribution meta-data
+ name = "bsd-chflags",
+ version = "0.1",
+ description = "",
+ author = "Stephen Bennett",
+ author_email = "spb@gentoo.org",
+ license = "",
+ long_description = \
+ '''''',
+ ext_modules = [ Extension(
+ "chflags",
+ ["chflags.c"],
+ libraries=[],
+ )
+ ],
+ url = "",
+ )
+
diff --git a/src/python-missingos/ChangeLog b/src/python-missingos/ChangeLog
new file mode 100644
index 00000000..1c80b2e6
--- /dev/null
+++ b/src/python-missingos/ChangeLog
@@ -0,0 +1,16 @@
+# $Header: /var/cvsroot/gentoo-src/portage/src/python-missingos/ChangeLog,v 1.4 2003/03/22 14:24:38 carpaski Exp $
+
+python-missingos ChangeLog
+Jonathon D Nelson <jnelson@gentoo.org>
+2 April 2002
+
+ 2 April 2002 14:15 jnelson
+ * Add optional 'mode' parameter to mknod
+ * Change from missingosmodule to missingos.
+ * Add some __doc__ entries
+ * Remove stupid hack for Python 1.5.2 support,
+ 1.5.2 doesn't have Py_FileSystemDefaultEncoding anyway.
+ * Return description of error when mode not p,b,c,u in mknod
+
+ 2 April 2002 12:10 jnelson
+ * Populate files
diff --git a/src/python-missingos/PKG-INFO b/src/python-missingos/PKG-INFO
new file mode 100644
index 00000000..cb8087f4
--- /dev/null
+++ b/src/python-missingos/PKG-INFO
@@ -0,0 +1,10 @@
+Metadata-Version: 1.0
+Name: python-missingos
+Version: 0.2
+Summary: UNKNOWN
+Home-page: UNKNOWN
+Author: Jonathon D Nelson
+Author-email: jnelson@gentoo.org
+License: UNKNOWN
+Description: UNKNOWN
+Platform: UNKNOWN
diff --git a/src/python-missingos/README b/src/python-missingos/README
new file mode 100644
index 00000000..de3467d5
--- /dev/null
+++ b/src/python-missingos/README
@@ -0,0 +1,15 @@
+# $Header: /var/cvsroot/gentoo-src/portage/src/python-missingos/README,v 1.5.2.1 2004/10/22 16:53:30 carpaski Exp $
+
+python-missingos
+Jonathon D Nelson <jnelson@gentoo.org>
+2 April 2002
+
+INTRO
+=====
+This module provides some missing file operations that don't
+seem to be provided by the standard os and posix modules.
+This list currently includes lchown and mknod.
+
+COPYRIGHT
+=========
+GPL
diff --git a/src/python-missingos/missingos.c b/src/python-missingos/missingos.c
new file mode 100644
index 00000000..cbcde5bf
--- /dev/null
+++ b/src/python-missingos/missingos.c
@@ -0,0 +1,120 @@
+/* $Header: /var/cvsroot/gentoo-src/portage/src/python-missingos/missingos.c,v 1.5.2.1 2004/10/22 16:53:30 carpaski Exp $ */
+
+#include "Python.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+static char missingos_lchown__doc__[];
+static PyObject * missingos_lchown(PyObject *self, PyObject *args);
+static char missingos_mknod__doc__[];
+static PyObject * missingos_mknod(PyObject *self, PyObject *args);
+
+static char missingos__doc__[] = "Provide some operations that\
+ are missing from the standard os / posix modules.";
+
+static PyMethodDef missingos_methods[] = {
+ {"lchown", missingos_lchown, METH_VARARGS, missingos_lchown__doc__},
+ {"mknod", missingos_mknod, METH_VARARGS, missingos_mknod__doc__},
+ {NULL, NULL} /* sentinel */
+};
+
+static PyObject *
+posix_error_with_allocated_filename(char* name)
+{
+ PyObject *rc = PyErr_SetFromErrnoWithFilename(PyExc_OSError, name);
+ PyMem_Free(name);
+ return rc;
+}
+
+static char missingos_lchown__doc__[] =
+"lchown(path, uid, gid) -> None\n\
+Change the owner and group id of path to the numeric uid and gid.";
+
+static PyObject *
+missingos_lchown(PyObject *self, PyObject *args) {
+ char *path = NULL;
+ int uid, gid;
+ int res;
+ if (!PyArg_ParseTuple(args, "etii:lchown",
+ Py_FileSystemDefaultEncoding, &path,
+ &uid, &gid))
+ return NULL;
+ res = lchown(path, (uid_t) uid, (gid_t) gid);
+ if (res < 0)
+ return posix_error_with_allocated_filename(path);
+ PyMem_Free(path);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static char missingos_mknod__doc__[] =
+"mknod(path, type, major, minor [, mode=0600 ]) -> None\n\
+Create a special file. Mode fixed at 0600.\
+Note that for type 'p' major and minor are ignored.\
+";
+
+static PyObject *
+missingos_mknod(PyObject *self, PyObject *args) {
+ char *path = NULL;
+ char *type = NULL;
+ int major = 0;
+ int minor = 0;
+ mode_t real_mode;
+ dev_t real_dev;
+ int mode = 0600;
+
+ int res;
+ if (!PyArg_ParseTuple(args, "etsii|i:mknod",
+ Py_FileSystemDefaultEncoding, &path,
+ &type, &major, &minor, &mode))
+ return NULL;
+ /* type can be *one* of b, c, u, p */
+ /* major/minor are forbidden for p, reqd otherwise */
+ if (!strcmp(type, "p")) {
+ /* pipe */
+ if (major != 0 || minor != 0) {
+ return NULL;
+ }
+ real_mode = S_IFIFO;
+ major = 0;
+ minor = 0;
+ } else if (!strcmp(type, "b")) {
+ /* block */
+ real_mode = S_IFBLK;
+ } else if (!strcmp(type, "c")) {
+ real_mode = S_IFCHR;
+ /* char */
+ } else if (!strcmp(type, "u")) {
+ real_mode = S_IFCHR;
+ /* unbuffered char */
+ } else {
+ /* error */
+ PyErr_SetString(PyExc_ValueError, "type must be one of p,b,c,u");
+ return NULL;
+ }
+
+ real_mode |= mode;
+ real_dev = (major << 8) | minor;
+
+ /* use mode to modify real_mode */
+
+ res = mknod(path, real_mode, real_dev);
+ if (res < 0)
+ return posix_error_with_allocated_filename(path);
+ PyMem_Free(path);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+DL_EXPORT(void)
+initmissingos(void) {
+ PyObject *m;
+
+ m = Py_InitModule4("missingos", missingos_methods,
+ missingos__doc__, (PyObject *)NULL,
+ PYTHON_API_VERSION);
+}
diff --git a/src/python-missingos/setup.cfg b/src/python-missingos/setup.cfg
new file mode 100644
index 00000000..8677f66f
--- /dev/null
+++ b/src/python-missingos/setup.cfg
@@ -0,0 +1,8 @@
+# python-missingos
+# $Header: /var/cvsroot/gentoo-src/portage/src/python-missingos/setup.cfg,v 1.4.2.1 2004/10/22 16:53:30 carpaski Exp $
+
+[bdist_rpm]
+release = 1
+doc_files = ChangeLog
+ README
+python=python2
diff --git a/src/python-missingos/setup.py b/src/python-missingos/setup.py
new file mode 100755
index 00000000..b82e3e51
--- /dev/null
+++ b/src/python-missingos/setup.py
@@ -0,0 +1,24 @@
+#! /usr/bin/env python2.2
+# $Header: /var/cvsroot/gentoo-src/portage/src/python-missingos/setup.py,v 1.5.2.1 2004/10/22 16:53:30 carpaski Exp $
+
+from os import chdir, stat
+from distutils.core import setup, Extension
+
+setup (# Distribution meta-data
+ name = "python-missingos",
+ version = "0.2",
+ description = "",
+ author = "Jonathon D Nelson",
+ author_email = "jnelson@gentoo.org",
+ license = "",
+ long_description = \
+ '''''',
+ ext_modules = [ Extension(
+ "missingos",
+ ["missingos.c"],
+ libraries=[],
+ )
+ ],
+ url = "",
+ )
+
diff --git a/src/sandbox-1.1/ChangeLog b/src/sandbox-1.1/ChangeLog
new file mode 100644
index 00000000..8da8ec9f
--- /dev/null
+++ b/src/sandbox-1.1/ChangeLog
@@ -0,0 +1,265 @@
+# ChangeLog for Path Sandbox
+# Copyright 1999-2004 Gentoo Foundation; Distributed under the GPL v2
+# $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-1.1/Attic/ChangeLog,v 1.37.2.3 2004/12/01 22:14:09 carpaski Exp $
+
+ 01 Dec 2004; Nicholas Jones <carpaski@gentoo.org> libsandbox.c, sandbox.c:
+ Added ferringb's code to handle the sandbox pid overflow problem.
+
+ 07 Nov 2004; Brian Harring <ferringb@gentoo.org> libsandbox.c: c99 standard
+ allowing data and code mixing in code isn't available for gcc 2.95- should fix
+ bug #70351.
+
+ 03 Nov 2004; Brian Harring <ferringb@gentoo.org> libsandbox.c, sandbox_futils.c:
+ Fixups, and a hole closed regarding verifying SANDBOX_(|DEBUG_)LOG is sane.
+
+ 02 Aug 2004; Nicholas Jones <carpaski@gentoo.org> libsandbox.c: Code from
+ Seth Robertson that tracked down all adjuct flags for read operations that
+ do not invoke a write operation.
+
+ 04 Apr 2004; Nicholas Jones <carpaski@gentoo.org> libsandbox.c, sandbox.c:
+ Another fix from jstubbs regarding a free() on a stack variable for the
+ environment -- tracking now prevents extraneous free()'s segfault.
+
+ 04 Apr 2004; Nicholas Jones <carpaski@gentoo.org> libsandbox.c, sandbox.c:
+ J. Stubbs tracked down a new bug where mkdir was failing to the patch on
+ the lstat in mkdir... it now only returns 0 or -1 as documented for mkdir.
+ Also remove the errno = ESUCCESS settings as documentation points out that
+ a library isn't allowed to do that.
+
+ 04 Apr 2004; Nicholas Jones <carpaski@gentoo.org> libsandbox.c: Added a
+ file_security_check() function to check random potential exploits on files
+ that sandbox is to load and read -- Normally sandboxpids.tmp. This fixes
+ the 'system-crippling' exploits (bug 21923) and catches a few other
+ potential problems.
+
+ 20 Mar 2004; Nicholas Jones <carpaski@gentoo.org> Makefile: Updates for
+ 32/64 bit sandbox. Made CC and LD '?=' values to allow passed in CC to work.
+
+ 20 Mar 2004; Nicholas Jones <carpaski@gentoo.org> libsandbox.c:
+ bug 42048 -- Fixed the lstat/errno conditions for mkdir <caleb@g.o>.
+ Added the 64/32 bit sandbox patch for AMD64 bug 32963 <brad/azarah>.
+
+ 29 Feb 2004; Martin Schlemmer <azarah@gentoo.org> sandbox.c, sandbox_futils.c :
+ Fix permissions and group of pids file and logs. Permissions should be 0664
+ and group should be 'portage'. Bug #34260.
+
+ 28 Feb 2004; Martin Schlemmer <azarah@gentoo.org> libsandbox.c :
+ Besides a small cleanup, redo how we replace LD_PRELOAD in the environ passed
+ to the real execve (in our execve wrapper). Seems that on some arches (sparc
+ among others) do not allow us to tamper with the readonly copy passed to
+ execve, so pass our own copy of the environment. Bug #42290.
+
+ 11 Jan 2004; Nicholas Jones <carpaski@gentoo.org> create-decls:
+ Changed tail to head and added a notice about duration of glibc check.
+
+ 21 Dec 2003; Nicholas Jones <carpaski@gentoo.org> create-decls:
+ Changed the glibc subversion check to use /usr/bin/* instead of /bin/sh
+ as there isn't a guarentee that it is dynamic.
+
+ 02 Nov 2003; Martin Schlemmer <azarah@gentoo.org> libsandbox.c :
+ If 'file' passed to before_syscall(const char *func, const char *file) is
+ invalid, we should set errno to ENOENT, and not EINVAL. This should
+ close bug #32238.
+
+ 14 Oct 2003; Martin Schlemmer <azarah@gentoo.org> libsandbox.c :
+ Fix a bug that occurs mainly on 64bit arch, where the file passed to
+ the functions we wrap, is invalid, and then cause canonicalize to pass
+ garbage to before_syscall(), thanks to great detective work from
+ Andrea Luzzardi <al@sig11.org> (bug #29846).
+
+ 13 Oct 2003; Martin Schlemmer <azarah@gentoo.org> create-localdecls :
+ Add a uClibc detection patch from Peter S. Mazinger <ps.m@gmx.net>.
+
+ 13 Oct 2003; Martin Schlemmer <azarah@gentoo.org> libsandbox.c :
+ Fix a bug in libsandbox.c 's checking in the rename wrapper - it basically
+ only checked the destination patch, and not the source, so we could move
+ a protected file to a unprotected directory, and then delete/modify it.
+ Thanks to Andrea Luzzardi (scox) <al@sig11.org>, bug #30992, for this fix.
+
+ 12 Oct 2003; Nicholas Jones <carpaski@gentoo.org> sandbox.c :
+ Added python2.3 to the predict section/variable.
+
+ 28 Sep 2003; Martin Schlemmer <azarah@gentoo.org> libsandbox.c, sandbox.c,
+ sandbox.h, sandbox_futils.c :
+ Add support to set the pids file via SANDBOX_PIDS_FILE at startup. If
+ it is not set, it will revert to its old value.
+
+ 27 Sep 2003; Martin Schlemmer <azarah@gentoo.org> libsandbox.c :
+ Fix our mkdir wrapper to check if the dir exist, and return EEXIST if so,
+ rather than failing with a violation, bug #29748.
+
+ 27 Jul 2003; Martin Schlemmer <azarah@gentoo.org> libsandbox.c :
+ Fix canonicalize() to ignore calls with path = "".
+
+ 27 Jul 2003; Martin Schlemmer <azarah@gentoo.org> getcwd.c, libsandbox.c,
+ sandbox_futils.c, canonicalize.c :
+ Once again coreutils fails, as my systems had 2.5 kernel, the getcwd system
+ call handled strings larger than PATH_MAX (bug #21766). It however does not
+ work the same on 2.4 kernels.
+
+ To fix, I added the posix implementation of getcwd() (from glibc cvs) that
+ do not need the system call. We use the default getcwd() function via a
+ wrapper (egetcwd), and then lstat the returned path. If lstat fails, it
+ means the current directory was removed, OR that the the system call for
+ getcwd failed (curious is that it do not fail and return NULL or set
+ errno, but rather just truncate the retured directory - usually from the
+ start), and if so, we use the generic getcwd() function (__egetcwd). Note
+ that we do not use the generic version all the time, as it calls lstat()
+ a great number of times, and performance degrade much.
+
+ 29 Jun 2003; Martin Schlemmer <azarah@gentoo.org> create-localdecls,
+ libsandbox.c :
+ Make sure SB_PATH_MAX will not wrap. Fix two possible memory leaks.
+
+ 22 Jun 2003; Martin Schlemmer <azarah@gentoo.org> libsandbox.c, canonicalize.c
+ create-localdecls :
+ When checking path names of files accessed, we need to canonicalize it, else
+ it may be a symlink in a 'write allowed' directory pointing to a file in a
+ directory we should not have write access to.
+
+ With something like coreutils-5.0, we have two problems:
+ 1) One of the tests checks if getcwd() can return a path longer than
+ PATH_MAX. This test then tries to create a dir which even while
+ created local (mkdir("conftest2")), it ends up being resolved with
+ a name that is much larger than PATH_MAX. The problem now is that
+ canonicalize() have undefined behaviour when the path was too long
+ (returned wrongly truncated paths, etc), and pass the wrong path to
+ before_syscall() (causing the bogus sandbox violations).
+ 2) The ecanonicalize() function we used, along with the canonicalize()
+ function did not support longer than PATH_MAX. This is partly a
+ cause for 1), but the error checking (rather lack of it) of calls
+ to erealpath() in canonicalize() was the prime reason for 1).
+
+ As we do not use this canonicalized name to call the function, we resolve this
+ by fixing canonicalize() to do better error checking, and ecanonicalize() as
+ well as all functions in libsandbox.c to use a PATH_MAX of 'PATH_MAX * 2'.
+ While they will resolve paths properly now, and can check if a write/read is
+ allowed, the functions called from the sandboxed environment will still work
+ as expected.
+
+ This should resolve bug #21766.
+
+ 06 Apr 2003; Martin Schlemmer <azarah@gentoo.org> libsandbox.c :
+ For some reason sandbox fails with a 'open_wr' if you run 'locale -a' under
+ it (bug #16298).
+
+ Problem is that for some reason locale fopen's locale.alias with mode "rm".
+
+ -------------------------------------------------------
+ nosferatu root # grep fopen locale.log
+ fopen("/usr/share/locale/locale.alias", "rm"ACCESS DENIED open_wr: /usr/share/locale/locale.alias
+ nosferatu root #
+ --------------------------------------------------------
+
+ I checked the source of locale, but it have fopen with mode 'r', so
+ not sure where the "rm" mode comes from. Anyhow, changed the check in
+ before_syscall_open_char() to also see mode "rm" as readonly.
+
+ 23 Feb 2003; Martin Schlemmer <azarah@gentoo.org> create-localdecls :
+
+ Add glibc-2.3 support.
+
+ 22 Feb 2003; Martin Schlemmer <azarah@gentoo.org> sandbox.c :
+
+ Some /etc/ld.so.preload fixes. Just changed the #if defines to cover all
+ operations releated to preload, as well as only try to modify ld.so.preload
+ if we can. Also modify to write the pid to /tmp/sandboxpids.tmp even when
+ not using ld.so.preload. Fix to not write this instance of sandbox's pid
+ to /tmp/sandboxpids.tmp on exit if this is not the last sandbox running.
+
+ 22 Feb 2003; Nicholas Jones <carpaski@gentoo.org> Makefile :
+
+ Changed the LD to CC for hppa.
+
+ 22 Feb 2003; Nicholas Jones <carpaski@gentoo.org> create-localdecls :
+
+ Killed the previous changes I made.
+
+ 17 Feb 2003; Nicholas Jones <carpaski@gentoo.org> create-localdecls :
+
+ Added parisc to BROKEN_RTLD_ARCHLIST to see if it we can fix the relocation probs.
+
+ 09 Jan 2003; J Robert Ray <jrray@gentoo.org> sandbox.c :
+
+ Don't segfault if $HOME isn't set, set $HOME to "/" instead. Fixes bug 10868.
+
+ 16 Dec 2002; Martin Schlemmer <azarah@gentoo.org> create-localdecls :
+
+ Fix memory leak for mips, bug #12236. Thanks to Torgeir Hansen <torgeir@trenger.ro>
+ for this fix.
+
+ 4 Dec 2002; J Robert Ray <jrray@gentoo.org> sandbox.h sandbox_futils.c :
+
+ sandbox_futils defined a dirname() function that was masking the same
+ function in glibc and was broken (e.g.: SANDBOX_DIR was being set to
+ '/usr/lib/portage/bi/'). Fixed function to return expected results and
+ renamed it to sb_dirname() to no longer mask the glibc function. Closes bug
+ 11231.
+
+ 4 Dec 2002; Martin Schlemmer <azarah@gentoo.org> :
+
+ Fix a segfault in libsandbox.c if canonicalize() was called with
+ first parameter = NULL.
+
+ 1 Sep 2002; Martin Schlemmer <azarah@gentoo.org> :
+
+ Fix my braindead 'return 1;' in a void function. Updated sandbox.c,
+ cleanup() for this.
+
+ Change cleanup() in sandbox.c not to exit with fail status if
+ the pidsfile is missing. We really should still display sandbox
+ violations if they occured.
+
+ 31 Aug 2002; Martin Schlemmer <azarah@gentoo.org> :
+
+ Update cleanup() in sandbox.c to remove the PIDSFILE if this is
+ the last sandbox running.
+
+ 25 Aug 2002; Martin Schlemmer <azarah@gentoo.org> :
+
+ Major cleanups to mainly libsandbox.c again.
+
+ 22 Aug 2002; Martin Schlemmer <azarah@gentoo.org> :
+
+ Add copyrights to sandbox.h and sandbox_futils.h. If wrong, the
+ parties involved should please contact me so that we can fix it.
+
+ Add opendir wrapper to libsandbox.c.
+
+ 21 Aug 2002; Martin Schlemmer <azarah@gentoo.org> :
+
+ Do some more cleanups to ecanonicalize(), as it dropped filenames in
+ rare cases (after my symlink cleanups), and caused glibc to bork.
+ These fixes went into canonicalize.c.
+
+ 20 Aug 2002; Martin Schlemmer <azarah@gentoo.org> :
+
+ Fix spawn_shell() and main() in sandbox.c to properly return fail
+ status.
+
+ 19 Aug 2002; Martin Schlemmer <azarah@gentoo.org> :
+
+ The new canonicalize() function in libsandbox.c also resolved symlinks,
+ which caused on cleaning sandbox errors if the symlink pointed to a
+ file in the live root. Ripped out canonicalize() and realpath() from
+ glibc; removed the symlink stuff, and changed them to ecanonicalize()
+ and erealpath().
+
+ 18 Aug 2002; Martin Schlemmer <azarah@gentoo.org> :
+
+ Ripped out all the wrappers, and implemented those of InstallWatch.
+ Losts of cleanups and bugfixes. Implement a execve that forces
+ $LIBSANDBOX in $LD_PRELOAD. We can now thus do away with the feared
+ /etc/ld.so.preload (*g*) ... Made the needed changes to sandbox.c,
+ sandbox.h and sandbox_futils.c. Rewrote the Makefile for most
+ parts; it now have an install target.
+
+ Reformat the whole thing to look somewhat like the reworked sandbox.c
+ and new sandbox.h and sandbox_futils.c from:
+
+ Brad House <brad@mainstreetsoftworks.com>.
+
+ Additional Copyrights now due to the InstallWatch code:
+
+ Copyright (C) 1998-9 Pancrazio `Ezio' de Mauro <p@demauro.net>
+
diff --git a/src/sandbox-1.1/Makefile b/src/sandbox-1.1/Makefile
new file mode 100644
index 00000000..b451676a
--- /dev/null
+++ b/src/sandbox-1.1/Makefile
@@ -0,0 +1,81 @@
+# Copyright (C) 2001 Geert Bevin, Uwyn, http://www.uwyn.com
+# Distributed under the terms of the GNU General Public License, v2 or later
+# Author : Geert Bevin <gbevin@uwyn.com>
+#
+# Modified 15 Apr 2002 Jon Nelson <jnelson@gentoo.org>
+# Clean up Makefile somewhat, and use make's implicit rules
+#
+# Modified 19 Aug 2002; Martin Schlemmer <azarah@gentoo.org>
+# Major rewrite to support new stuff
+#
+# Indent: indent -kr -i2 -ts2 -sob -l80 -ss -bs -psl
+#
+# $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-1.1/Attic/Makefile,v 1.7.2.2 2004/11/29 08:41:28 carpaski Exp $
+
+CC ?= gcc
+LD ?= ld
+CFLAGS =
+ARCH_CFLAGS =
+OBJ_CFLAGS = -D_GNU_SOURCE -DPIC -fPIC -D_REENTRANT
+LIBS =
+LDFLAGS =
+DESTDIR =
+
+HAVE_64BIT_ARCH =
+
+ifneq ($(HAVE_64BIT_ARCH),)
+ TARGETS = libsandbox.so libsandbox32.so sandbox
+ ARCH_CFLAGS += -m64
+ OBJ_CFLAGS += -DSB_HAVE_64BIT_ARCH
+else
+ TARGETS = libsandbox.so sandbox
+endif
+
+all: $(TARGETS)
+
+sandbox: sandbox.o sandbox_futils.o getcwd.c
+ $(CC) $(CFLAGS) $(ARCH_CFLAGS) $(OBJ_CFLAGS) -Wall $^ -ldl -lc -o $@
+
+sandbox.o: sandbox.c sandbox.h
+ $(CC) $(CFLAGS) $(ARCH_CFLAGS) $(OBJ_CFLAGS) -Wall -c sandbox.c -o $@
+
+sandbox_futils.o: localdecls.h sandbox_futils.c sandbox.h
+ $(CC) $(CFLAGS) $(ARCH_CFLAGS) $(OBJ_CFLAGS) -Wall -c sandbox_futils.c -o $@
+
+libsandbox.so: libsandbox.o sandbox_futils.o
+ $(CC) $^ -shared $(ARCH_CFLAGS) -fPIC -ldl -lc -nostdlib -lgcc -o $@
+
+libsandbox.o: localdecls.h libsandbox.c canonicalize.c getcwd.c
+ $(CC) $(CFLAGS) $(ARCH_CFLAGS) $(OBJ_CFLAGS) -Wall -c libsandbox.c
+
+sandbox_futils32.o: sandbox_futils.c sandbox.h
+ $(CC) $(CFLAGS) -m32 $(OBJ_CFLAGS) -Wall -c sandbox_futils.c -o $@
+
+libsandbox32.so: libsandbox32.o sandbox_futils32.o
+ $(CC) $^ -shared -m32 -fPIC -ldl -lc -nostdlib -lgcc -o $@
+
+libsandbox32.o: libsandbox.c localdecls.h canonicalize.c getcwd.c
+ $(CC) $(CFLAGS) -m32 $(OBJ_CFLAGS) -Wall -c libsandbox.c -o $@
+
+localdecls.h: create-localdecls libctest.c
+ ./create-localdecls
+
+
+install: all
+ install -d -m 0755 $(DESTDIR)/lib
+ $(if $(HAVE_64BIT_ARCH),install -d -m 0755 $(DESTDIR)/lib32)
+ install -d -m 0755 $(DESTDIR)/usr/lib/portage/bin
+ install -d -m 0755 $(DESTDIR)/usr/lib/portage/lib
+ install -m 0755 libsandbox.so $(DESTDIR)/lib
+ $(if $(HAVE_64BIT_ARCH),install -m 0755 libsandbox32.so $(DESTDIR)/lib32/libsandbox.so)
+ install -m 0755 sandbox $(DESTDIR)/usr/lib/portage/bin
+ install -m 0644 sandbox.bashrc $(DESTDIR)/usr/lib/portage/lib
+
+
+clean:
+ rm -f $(TARGETS)
+ rm -f *.o *~ core
+ rm -f localdecls.h
+
+
+# vim:expandtab noai:cindent ai
diff --git a/src/sandbox-1.1/canonicalize.c b/src/sandbox-1.1/canonicalize.c
new file mode 100644
index 00000000..85ca77f7
--- /dev/null
+++ b/src/sandbox-1.1/canonicalize.c
@@ -0,0 +1,173 @@
+/* Return the canonical absolute name of a given file.
+ Copyright (C) 1996-2001, 2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/*
+ * $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-1.1/Attic/canonicalize.c,v 1.5.2.1 2004/10/22 16:53:30 carpaski Exp $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stddef.h>
+
+#ifndef __set_errno
+# define __set_errno(val) errno = (val)
+#endif
+
+/* Return the canonical absolute name of file NAME. A canonical name
+ does not contain any `.', `..' components nor any repeated path
+ separators ('/') or symlinks. All path components must exist. If
+ RESOLVED is null, the result is malloc'd; otherwise, if the
+ canonical name is SB_PATH_MAX chars or more, returns null with `errno'
+ set to ENAMETOOLONG; if the name fits in fewer than SB_PATH_MAX chars,
+ returns the name in RESOLVED. If the name cannot be resolved and
+ RESOLVED is non-NULL, it contains the path of the first component
+ that cannot be resolved. If the path can be resolved, RESOLVED
+ holds the same value as the value returned. */
+
+/* Modified: 19 Aug 2002; Martin Schlemmer <azarah@gentoo.org>
+ *
+ * Cleaned up unneeded stuff, and change so that it will not
+ * resolve symlinks. Also prepended a 'e' to functions that
+ * I did not rip out.
+ *
+ */
+
+char *
+erealpath(const char *name, char *resolved)
+{
+ char *rpath, *dest;
+ const char *start, *end, *rpath_limit;
+ long int path_max;
+
+ if (name == NULL) {
+ /* As per Single Unix Specification V2 we must return an error if
+ either parameter is a null pointer. We extend this to allow
+ the RESOLVED parameter to be NULL in case the we are expected to
+ allocate the room for the return value. */
+ __set_errno(EINVAL);
+ return NULL;
+ }
+
+ if (name[0] == '\0') {
+ /* As per Single Unix Specification V2 we must return an error if
+ the name argument points to an empty string. */
+ __set_errno(ENOENT);
+ return NULL;
+ }
+#ifdef SB_PATH_MAX
+ path_max = SB_PATH_MAX;
+#else
+ path_max = pathconf(name, _PC_PATH_MAX);
+ if (path_max <= 0)
+ path_max = 1024;
+#endif
+
+ if (resolved == NULL) {
+ rpath = malloc(path_max);
+ if (rpath == NULL)
+ return NULL;
+ } else
+ rpath = resolved;
+ rpath_limit = rpath + path_max;
+
+ if (name[0] != '/') {
+ if (!egetcwd(rpath, path_max)) {
+ rpath[0] = '\0';
+ goto error;
+ }
+ dest = strchr(rpath, '\0');
+ } else {
+ rpath[0] = '/';
+ dest = rpath + 1;
+ }
+
+ for (start = end = name; *start; start = end) {
+ /* Skip sequence of multiple path-separators. */
+ while (*start == '/')
+ ++start;
+
+ /* Find end of path component. */
+ for (end = start; *end && *end != '/'; ++end)
+ /* Nothing. */ ;
+
+ if (end - start == 0)
+ break;
+ else if (end - start == 1 && start[0] == '.')
+ /* nothing */ ;
+ else if (end - start == 2 && start[0] == '.' && start[1] == '.') {
+ /* Back up to previous component, ignore if at root already. */
+ if (dest > rpath + 1)
+ while ((--dest)[-1] != '/') ;
+ } else {
+ size_t new_size;
+
+ if (dest[-1] != '/')
+ *dest++ = '/';
+
+ if (dest + (end - start) >= rpath_limit) {
+ ptrdiff_t dest_offset = dest - rpath;
+ char *new_rpath;
+
+ if (resolved) {
+ __set_errno(ENAMETOOLONG);
+ if (dest > rpath + 1)
+ dest--;
+ *dest = '\0';
+ goto error;
+ }
+ new_size = rpath_limit - rpath;
+ if (end - start + 1 > path_max)
+ new_size += end - start + 1;
+ else
+ new_size += path_max;
+ new_rpath = (char *) realloc(rpath, new_size);
+ if (new_rpath == NULL)
+ goto error;
+ rpath = new_rpath;
+ rpath_limit = rpath + new_size;
+
+ dest = rpath + dest_offset;
+ }
+
+ dest = __mempcpy(dest, start, end - start);
+ *dest = '\0';
+ }
+ }
+#if 1
+ if (dest > rpath + 1 && dest[-1] == '/')
+ --dest;
+#endif
+ *dest = '\0';
+
+ return resolved ? memcpy(resolved, rpath, dest - rpath + 1) : rpath;
+
+error:
+ if (resolved)
+ strcpy(resolved, rpath);
+ else
+ free(rpath);
+ return NULL;
+}
+
+// vim:expandtab noai:cindent ai
diff --git a/src/sandbox-1.1/create-localdecls b/src/sandbox-1.1/create-localdecls
new file mode 100755
index 00000000..816723d5
--- /dev/null
+++ b/src/sandbox-1.1/create-localdecls
@@ -0,0 +1,115 @@
+#!/bin/sh
+
+# This is a quick'n'dirty hack to make the program behave correctly
+# under different systems.
+# Example:
+# when using libc5, (f)trucate's offset argument type is size_t with
+# libc5, but it's off_t with libc6 (glibc2).
+#
+# Uhm... time to learn GNU autoconf :-)
+#
+# $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-1.1/Attic/create-localdecls,v 1.11.2.1 2004/10/22 16:53:30 carpaski Exp $
+
+OUTFILE='localdecls.h'
+
+# if your arch needs to dlopen() glibc, add it here separated by space :]
+BROKEN_RTLD_ARCHLIST="mips"
+
+echo '/* This file is automatically generated *' > $OUTFILE
+echo ' * Modify create-localdecls instead of this */' >> $OUTFILE
+echo >> $OUTFILE
+echo '#ifndef __LOCALDECLS_H_' >> $OUTFILE
+echo '#define __LOCALDECLS_H_' >> $OUTFILE
+echo >> $OUTFILE
+
+###
+###
+###
+
+echo -n 'Checking truncate argument type... '
+if grep -q 'truncate.*size_t' /usr/include/unistd.h ; then
+ echo 'size_t'
+ echo '#define TRUNCATE_T size_t' >> $OUTFILE
+else
+ echo 'off_t' # At least, I HOPE it's off_t :-)
+ echo '#define TRUNCATE_T off_t' >> $OUTFILE
+fi
+
+###
+###
+###
+
+echo -n 'Checking libc version... '
+gcc -Wall -o libctest libctest.c
+VERSION=`ldd libctest | grep libc\\.so | grep -v 'ld-uClibc' | awk '{print $1}'`
+
+echo $VERSION
+echo "#define LIBC_VERSION \"$VERSION\"" >> $OUTFILE
+if test "$VERSION" = 'libc.so.5' ; then
+ echo '#define BROKEN_RTLD_NEXT' >> $OUTFILE
+ echo '#define LIBC 5' >> $OUTFILE
+else
+ # for the arch's that need to dlopen() libc to fetch real funcs!
+ # 16.12.02 -Torgeir Hansen <torgeir@trenger.ro>
+ MYARCH=`/bin/uname -m`
+ for x in $BROKEN_RTLD_ARCHLIST; do
+ if [ $x = $MYARCH ]; then
+ echo '#define BROKEN_RTLD_NEXT' >> $OUTFILE
+ fi
+ done
+
+fi
+
+if test "$VERSION" = 'libc.so.6' ; then
+ echo -n 'Checking glibc subversion...'
+ tmp="$(ldd libctest 2>/dev/null | grep libc.so 2>/dev/null | head -n 1)"
+ LibcPath=`expr "$tmp" : '[^/]*\(/[^ ]*\)'`
+ tmp="`strings $LibcPath | grep -i 'c library'`"
+ OsLibcMajor=`expr "$tmp" : '.* \([0-9][0-9]*\)'`
+ OsLibcMinor=`expr "$tmp" : '.* [0-9][0-9]*\.\([0-9][0-9]*\)'`
+ echo " ${OsLibcMajor}.${OsLibcMinor}"
+ case "$OsLibcMajor" in
+ 2)
+ # 2 is the glibc version
+ case "$OsLibcMinor" in
+ 0)
+ echo '#define GLIBC_MINOR 0' >> $OUTFILE
+ SUBVERSION='glibc-2.0' ;;
+ 1)
+ echo '#define GLIBC_MINOR 1' >> $OUTFILE
+ SUBVERSION='glibc-2.1' ;;
+ 2)
+ echo '#define GLIBC_MINOR 2' >> $OUTFILE
+ SUBVERSION='glibc-2.2' ;;
+ 3)
+ echo '#define GLIBC_MINOR 3' >> $OUTFILE
+ SUBVERSION='glibc-2.3' ;;
+ *)
+ echo 'Treated as glibc >= 2.1 (finger crossed)'
+ echo '#define GLIBC_MINOR 1' >> $OUTFILE
+ SUBVERSION='glibc-2.1' ;;
+ esac
+ ;;
+ esac
+fi
+
+rm libctest
+
+echo '
+#ifdef PATH_MAX
+# define SB_PATH_MAX PATH_MAX * 2
+# if (SB_PATH_MAX >= INT_MAX) || (SB_PATH_MAX < PATH_MAX)
+# undef SB_PATH_MAX
+# define SB_PATH_MAX PATH_MAX + 25
+# if (SB_PATH_MAX >= INT_MAX) || (SB_PATH_MAX < PATH_MAX)
+# error SB_PATH_MAX too big!
+# endif
+# endif
+#else
+# error PATH_MAX not defined!
+#endif' >> $OUTFILE
+
+echo >> $OUTFILE
+echo '#endif' >> $OUTFILE
+echo
+
diff --git a/src/sandbox-1.1/getcwd.c b/src/sandbox-1.1/getcwd.c
new file mode 100644
index 00000000..552e41a0
--- /dev/null
+++ b/src/sandbox-1.1/getcwd.c
@@ -0,0 +1,511 @@
+/* Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* Wants:
+ AC_STDC_HEADERS
+ AC_DIR_HEADER
+ AC_UNISTD_H
+ AC_MEMORY_H
+ AC_CONST
+ AC_ALLOCA
+ */
+
+/*
+ * $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-1.1/Attic/getcwd.c,v 1.1.2.1 2004/10/22 16:53:30 carpaski Exp $
+ */
+
+/* Modified: 26 July 2003; Martin Schlemmer <azarah@gentoo.org>
+ *
+ * Cleaned up unneeded stuff. Add a wrapper to try and detect when
+ * we have a kernel whose getcwd system call do not handle directory
+ * names longer than PATH_MAX, and if so, use our generic version.
+ * To work truly with > PATH_MAX lengh CWDs, I had to increase the
+ * size of the dots[] array. Also prepended a 'e' to functions that
+ * I did not rip out.
+ *
+ */
+
+/* AIX requires this to be the first thing in the file. */
+#if defined _AIX && !defined __GNUC__
+#pragma alloca
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef STDC_HEADERS
+# include <stddef.h>
+#endif
+
+#if !defined __GNU_LIBRARY__ && !defined STDC_HEADERS
+extern int errno;
+#endif
+#ifndef __set_errno
+# define __set_errno(val) errno = (val)
+#endif
+
+#ifndef NULL
+# define NULL 0
+#endif
+
+#if defined USGr3 && !defined DIRENT
+# define DIRENT
+#endif /* USGr3 */
+#if defined Xenix && !defined SYSNDIR
+# define SYSNDIR
+#endif /* Xenix */
+
+#if defined POSIX || defined DIRENT || defined __GNU_LIBRARY__
+# include <dirent.h>
+# ifndef __GNU_LIBRARY__
+# define D_NAMLEN(d) strlen((d)->d_name)
+# else
+# define HAVE_D_NAMLEN
+# define D_NAMLEN(d) ((d)->d_namlen)
+# endif
+#else /* not POSIX or DIRENT */
+# define dirent direct
+# define D_NAMLEN(d) ((d)->d_namlen)
+# define HAVE_D_NAMLEN
+# if defined USG && !defined sgi
+# if defined SYSNDIR
+# include <sys/ndir.h>
+# else /* Not SYSNDIR */
+# include "ndir.h"
+# endif /* SYSNDIR */
+# else /* not USG */
+# include <sys/dir.h>
+# endif /* USG */
+#endif /* POSIX or DIRENT or __GNU_LIBRARY__ */
+
+#if defined HAVE_UNISTD_H || defined __GNU_LIBRARY__
+# include <unistd.h>
+#endif
+
+#if defined STDC_HEADERS || defined __GNU_LIBRARY__ || defined POSIX
+# include <stdlib.h>
+# include <string.h>
+# define ANSI_STRING
+#else /* No standard headers. */
+
+# ifdef USG
+
+# include <string.h>
+# ifdef NEED_MEMORY_H
+# include <memory.h>
+# endif
+# define ANSI_STRING
+
+# else /* Not USG. */
+
+# ifdef NeXT
+
+# include <string.h>
+
+# else /* Not NeXT. */
+
+# include <strings.h>
+
+# ifndef bcmp
+extern int bcmp();
+# endif
+# ifndef bzero
+extern void bzero();
+# endif
+# ifndef bcopy
+extern void bcopy();
+# endif
+
+# endif /* NeXT. */
+
+# endif /* USG. */
+
+extern char *malloc(), *realloc();
+extern void free();
+
+#endif /* Standard headers. */
+
+#ifndef ANSI_STRING
+# define memcpy(d, s, n) bcopy((s), (d), (n))
+# define memmove memcpy
+#endif /* Not ANSI_STRING. */
+
+#ifndef MAX
+# define MAX(a, b) ((a) < (b) ? (b) : (a))
+#endif
+
+#ifdef _LIBC
+# ifndef mempcpy
+# define mempcpy __mempcpy
+# endif
+# define HAVE_MEMPCPY 1
+#endif
+
+#if !defined __alloca && !defined __GNU_LIBRARY__
+
+# ifdef __GNUC__
+# undef alloca
+# define alloca(n) __builtin_alloca (n)
+# else /* Not GCC. */
+# if defined sparc || defined HAVE_ALLOCA_H
+# include <alloca.h>
+# else /* Not sparc or HAVE_ALLOCA_H. */
+# ifndef _AIX
+extern char *alloca();
+# endif /* Not _AIX. */
+# endif /* sparc or HAVE_ALLOCA_H. */
+# endif /* GCC. */
+
+# define __alloca alloca
+
+#endif
+
+#if defined HAVE_LIMITS_H || defined STDC_HEADERS || defined __GNU_LIBRARY__
+# include <limits.h>
+#else
+# include <sys/param.h>
+#endif
+
+#ifndef PATH_MAX
+# ifdef MAXPATHLEN
+# define PATH_MAX MAXPATHLEN
+# else
+# define PATH_MAX 1024
+# endif
+#endif
+
+#if !defined STDC_HEADERS && !defined __GNU_LIBRARY__
+# undef size_t
+# define size_t unsigned int
+#endif
+
+#if !__STDC__ && !defined const
+# define const
+#endif
+
+#ifndef __GNU_LIBRARY__
+# define __lstat stat
+#endif
+
+#ifndef _LIBC
+# define __getcwd getcwd
+#endif
+
+#ifndef GETCWD_RETURN_TYPE
+# define GETCWD_RETURN_TYPE char *
+#endif
+
+#ifndef SB_PATH_MAX
+# include "localdecls.h"
+# define OUTSIDE_LIBSANDBOX
+#endif
+
+#ifndef __LIBC
+# define __lstat lstat
+# define __readdir readdir
+# define __closedir closedir
+#endif
+
+/* Get the pathname of the current working directory, and put it in SIZE
+ bytes of BUF. Returns NULL if the directory couldn't be determined or
+ SIZE was too small. If successful, returns BUF. In GNU, if BUF is
+ NULL, an array is allocated with `malloc'; the array is SIZE bytes long,
+ unless SIZE == 0, in which case it is as big as necessary. */
+
+GETCWD_RETURN_TYPE
+__egetcwd(buf, size)
+char *buf;
+size_t size;
+{
+ static const char dots[]
+ = "../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../../\
+../../../../../../../../../../../../../../../../../../../../../../../../../..";
+ const char *dotp = &dots[sizeof (dots)];
+ const char *dotlist = dots;
+ size_t dotsize = sizeof (dots) - 1;
+ dev_t rootdev, thisdev;
+ ino_t rootino, thisino;
+ char *path;
+ register char *pathp;
+ struct stat st;
+ int prev_errno = errno;
+ size_t allocated = size;
+
+ if (size == 0) {
+ if (buf != NULL) {
+ __set_errno(EINVAL);
+ return NULL;
+ }
+
+ allocated = SB_PATH_MAX + 1;
+ }
+
+ if (buf != NULL)
+ path = buf;
+ else {
+ path = malloc(allocated);
+ if (path == NULL)
+ return NULL;
+ }
+
+ pathp = path + allocated;
+ *--pathp = '\0';
+
+ if (__lstat(".", &st) < 0)
+ goto lose2;
+ thisdev = st.st_dev;
+ thisino = st.st_ino;
+
+ if (__lstat("/", &st) < 0)
+ goto lose2;
+ rootdev = st.st_dev;
+ rootino = st.st_ino;
+
+ while (!(thisdev == rootdev && thisino == rootino)) {
+ register DIR *dirstream;
+ struct dirent *d;
+ dev_t dotdev;
+ ino_t dotino;
+ char mount_point;
+
+ /* Look at the parent directory. */
+ if (dotp == dotlist) {
+ /* My, what a deep directory tree you have, Grandma. */
+ char *new;
+ if (dotlist == dots) {
+ new = malloc(dotsize * 2 + 1);
+ if (new == NULL)
+ goto lose;
+#ifdef HAVE_MEMPCPY
+ dotp = mempcpy(new, dots, dotsize);
+#else
+ memcpy(new, dots, dotsize);
+ dotp = &new[dotsize];
+#endif
+ } else {
+ new = realloc((__ptr_t) dotlist, dotsize * 2 + 1);
+ if (new == NULL)
+ goto lose;
+ dotp = &new[dotsize];
+ }
+#ifdef HAVE_MEMPCPY
+ *((char *) mempcpy((char *) dotp, new, dotsize)) = '\0';
+ dotsize *= 2;
+#else
+ memcpy((char *) dotp, new, dotsize);
+ dotsize *= 2;
+ new[dotsize] = '\0';
+#endif
+ dotlist = new;
+ }
+
+ dotp -= 3;
+
+ /* Figure out if this directory is a mount point. */
+ if (__lstat(dotp, &st) < 0)
+ goto lose;
+ dotdev = st.st_dev;
+ dotino = st.st_ino;
+ mount_point = dotdev != thisdev;
+
+ /* Search for the last directory. */
+#ifdef OUTSIDE_LIBSANDBOX
+ dirstream = opendir(dotp);
+#else
+ dirstream = true_opendir(dotp);
+#endif
+ if (dirstream == NULL)
+ goto lose;
+ /* Clear errno to distinguish EOF from error if readdir returns
+ NULL. */
+ __set_errno(0);
+ while ((d = __readdir(dirstream)) != NULL) {
+ if (d->d_name[0] == '.' &&
+ (d->d_name[1] == '\0'
+ || (d->d_name[1] == '.' && d->d_name[2] == '\0')))
+ continue;
+ if (mount_point || (ino_t) d->d_ino == thisino) {
+ char name[dotlist + dotsize - dotp + 1 + _D_ALLOC_NAMLEN(d)];
+#ifdef HAVE_MEMPCPY
+ char *tmp = mempcpy(name, dotp,
+ dotlist + dotsize - dotp);
+ *tmp++ = '/';
+ strcpy(tmp, d->d_name);
+#else
+ memcpy(name, dotp, dotlist + dotsize - dotp);
+ name[dotlist + dotsize - dotp] = '/';
+ strcpy(&name[dotlist + dotsize - dotp + 1], d->d_name);
+#endif
+ /* We don't fail here if we cannot stat() a directory entry.
+ This can happen when (network) filesystems fail. If this
+ entry is in fact the one we are looking for we will find
+ out soon as we reach the end of the directory without
+ having found anything. */
+ if (__lstat(name, &st) >= 0 && st.st_dev == thisdev
+ && st.st_ino == thisino)
+ break;
+ }
+ }
+ if (d == NULL) {
+ int save = errno;
+ (void) __closedir(dirstream);
+ if (save == 0)
+ /* EOF on dirstream, which means that the current directory
+ has been removed. */
+ save = ENOENT;
+ __set_errno(save);
+ goto lose;
+ } else {
+ size_t namlen = _D_EXACT_NAMLEN(d);
+
+ if ((size_t) (pathp - path) <= namlen) {
+ if (size != 0) {
+ (void) __closedir(dirstream);
+ __set_errno(ERANGE);
+ goto lose;
+ } else {
+ char *tmp;
+ size_t oldsize = allocated;
+
+ allocated = 2 * MAX(allocated, namlen);
+ tmp = realloc(path, allocated);
+ if (tmp == NULL) {
+ (void) __closedir(dirstream);
+ __set_errno(ENOMEM); /* closedir might have changed it. */
+ goto lose;
+ }
+
+ /* Move current contents up to the end of the buffer.
+ This is guaranteed to be non-overlapping. */
+ pathp =
+ memcpy(tmp + allocated -
+ (path + oldsize - pathp),
+ tmp + (pathp - path), path + oldsize - pathp);
+ path = tmp;
+ }
+ }
+ pathp -= namlen;
+ (void) memcpy(pathp, d->d_name, namlen);
+ *--pathp = '/';
+ (void) __closedir(dirstream);
+ }
+
+ thisdev = dotdev;
+ thisino = dotino;
+ }
+
+ if (pathp == &path[allocated - 1])
+ *--pathp = '/';
+
+ if (dotlist != dots)
+ free((__ptr_t) dotlist);
+
+ memmove(path, pathp, path + allocated - pathp);
+
+ /* Restore errno on successful return. */
+ __set_errno(prev_errno);
+
+ return path;
+
+lose:
+ if (dotlist != dots)
+ free((__ptr_t) dotlist);
+lose2:
+ if (buf == NULL)
+ free(path);
+ return NULL;
+}
+
+GETCWD_RETURN_TYPE
+egetcwd(buf, size)
+char *buf;
+size_t size;
+{
+ struct stat st;
+ char *tmpbuf;
+
+ __set_errno(0);
+ tmpbuf = getcwd(buf, size);
+
+ if (tmpbuf) {
+ __lstat(buf, &st);
+ } else {
+ return tmpbuf;
+ }
+
+ if (errno) {
+ /* If lstat() failed with eerror = ENOENT, then its
+ * possible that we are running on an older kernel,
+ * so use our generic version which *should* not fail.
+ */
+ if (errno == ENOENT) {
+ return __egetcwd(buf, size);
+ } else {
+ return tmpbuf;
+ }
+ }
+
+ return tmpbuf;
+}
+
+// vim:expandtab noai:cindent ai
diff --git a/src/sandbox-1.1/libctest.c b/src/sandbox-1.1/libctest.c
new file mode 100644
index 00000000..5365a20c
--- /dev/null
+++ b/src/sandbox-1.1/libctest.c
@@ -0,0 +1,7 @@
+/* Dummy program to check your libc version */
+
+int
+main(void)
+{
+ return 0;
+}
diff --git a/src/sandbox-1.1/libsandbox.c b/src/sandbox-1.1/libsandbox.c
new file mode 100644
index 00000000..be4efc4f
--- /dev/null
+++ b/src/sandbox-1.1/libsandbox.c
@@ -0,0 +1,1383 @@
+/*
+ * Path sandbox for the gentoo linux portage package system, initially
+ * based on the ROCK Linux Wrapper for getting a list of created files
+ *
+ * to integrate with bash, bash should have been built like this
+ *
+ * ./configure --prefix=<prefix> --host=<host> --without-gnu-malloc
+ *
+ * it's very important that the --enable-static-link option is NOT specified
+ *
+ * Copyright (C) 2001 Geert Bevin, Uwyn, http://www.uwyn.com
+ * Distributed under the terms of the GNU General Public License, v2 or later
+ * Author : Geert Bevin <gbevin@uwyn.com>
+ *
+ * Post Bevin leaving Gentoo ranks:
+ * --------------------------------
+ * Ripped out all the wrappers, and implemented those of InstallWatch.
+ * Losts of cleanups and bugfixes. Implement a execve that forces $LIBSANDBOX
+ * in $LD_PRELOAD. Reformat the whole thing to look somewhat like the reworked
+ * sandbox.c from Brad House <brad@mainstreetsoftworks.com>.
+ *
+ * Martin Schlemmer <azarah@gentoo.org> (18 Aug 2002)
+ *
+ * Partly Copyright (C) 1998-9 Pancrazio `Ezio' de Mauro <p@demauro.net>,
+ * as some of the InstallWatch code was used.
+ *
+ *
+ * $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-1.1/Attic/libsandbox.c,v 1.22.2.3 2004/12/01 22:14:09 carpaski Exp $
+ *
+ */
+
+/* Uncomment below to enable wrapping of mknod().
+ * This is broken currently. */
+/* #define WRAP_MKNOD 1 */
+
+/* Uncomment below to enable the use of strtok_r(). */
+#define REENTRANT_STRTOK 1
+
+/* Uncomment below to enable memory debugging. */
+/* #define SB_MEM_DEBUG 1 */
+
+#define open xxx_open
+#define open64 xxx_open64
+
+/* Wrapping mknod, do not have any effect, and
+ * wrapping __xmknod causes calls to it to segfault
+ */
+#ifdef WRAP_MKNOD
+# define __xmknod xxx___xmknod
+#endif
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <utime.h>
+
+#ifdef SB_MEM_DEBUG
+# include <mcheck.h>
+#endif
+
+#ifdef WRAP_MKNOD
+# undef __xmknod
+#endif
+
+#undef open
+#undef open64
+
+#include "localdecls.h"
+#include "sandbox.h"
+
+/* Macros to check if a function should be executed */
+#define FUNCTION_SANDBOX_SAFE(func, path) \
+ ((0 == is_sandbox_on()) || (1 == before_syscall(func, path)))
+
+#define FUNCTION_SANDBOX_SAFE_INT(func, path, flags) \
+ ((0 == is_sandbox_on()) || (1 == before_syscall_open_int(func, path, flags)))
+
+#define FUNCTION_SANDBOX_SAFE_CHAR(func, path, mode) \
+ ((0 == is_sandbox_on()) || (1 == before_syscall_open_char(func, path, mode)))
+
+/* Macro to check if a wrapper is defined, if not
+ * then try to resolve it again. */
+#define check_dlsym(name) \
+{ \
+ int old_errno=errno; \
+ if (!true_ ## name) true_ ## name=get_dlsym(#name); \
+ errno=old_errno; \
+}
+
+/* Macro to check if we could canonicalize a path. It returns an integer on
+ * failure. */
+#define canonicalize_int(path, resolved_path) \
+{ \
+ if (0 != canonicalize(path, resolved_path)) \
+ return -1; \
+}
+
+/* Macro to check if we could canonicalize a path. It returns a NULL pointer on
+ * failure. */
+#define canonicalize_ptr(path, resolved_path) \
+{ \
+ if (0 != canonicalize(path, resolved_path)) \
+ return NULL; \
+}
+
+static char sandbox_lib[255];
+//static char sandbox_pids_file[255];
+static char *sandbox_pids_file;
+
+typedef struct {
+ int show_access_violation;
+ char **deny_prefixes;
+ int num_deny_prefixes;
+ char **read_prefixes;
+ int num_read_prefixes;
+ char **write_prefixes;
+ int num_write_prefixes;
+ char **predict_prefixes;
+ int num_predict_prefixes;
+ char **write_denied_prefixes;
+ int num_write_denied_prefixes;
+} sbcontext_t;
+
+/* glibc modified realpath() functions */
+char *erealpath(const char *name, char *resolved);
+/* glibc modified getcwd() functions */
+char *egetcwd(char *, size_t);
+
+static void init_wrappers(void);
+static void *get_dlsym(const char *);
+static int canonicalize(const char *, char *);
+static int check_access(sbcontext_t *, const char *, const char *);
+static int check_syscall(sbcontext_t *, const char *, const char *);
+static int before_syscall(const char *, const char *);
+static int before_syscall_open_int(const char *, const char *, int);
+static int before_syscall_open_char(const char *, const char *, const char *);
+static void clean_env_entries(char ***, int *);
+static void init_context(sbcontext_t *);
+static void init_env_entries(char ***, int *, char *, int);
+static char *filter_path(const char *);
+static int is_sandbox_on();
+static int is_sandbox_pid();
+
+/* Wrapped functions */
+
+extern int chmod(const char *, mode_t);
+static int (*true_chmod) (const char *, mode_t);
+extern int chown(const char *, uid_t, gid_t);
+static int (*true_chown) (const char *, uid_t, gid_t);
+extern int creat(const char *, mode_t);
+static int (*true_creat) (const char *, mode_t);
+extern FILE *fopen(const char *, const char *);
+static FILE *(*true_fopen) (const char *, const char *);
+extern int lchown(const char *, uid_t, gid_t);
+static int (*true_lchown) (const char *, uid_t, gid_t);
+extern int link(const char *, const char *);
+static int (*true_link) (const char *, const char *);
+extern int mkdir(const char *, mode_t);
+static int (*true_mkdir) (const char *, mode_t);
+extern DIR *opendir(const char *);
+static DIR *(*true_opendir) (const char *);
+#ifdef WRAP_MKNOD
+extern int __xmknod(const char *, mode_t, dev_t);
+static int (*true___xmknod) (const char *, mode_t, dev_t);
+#endif
+extern int open(const char *, int, ...);
+static int (*true_open) (const char *, int, ...);
+extern int rename(const char *, const char *);
+static int (*true_rename) (const char *, const char *);
+extern int rmdir(const char *);
+static int (*true_rmdir) (const char *);
+extern int symlink(const char *, const char *);
+static int (*true_symlink) (const char *, const char *);
+extern int truncate(const char *, TRUNCATE_T);
+static int (*true_truncate) (const char *, TRUNCATE_T);
+extern int unlink(const char *);
+static int (*true_unlink) (const char *);
+
+#if (GLIBC_MINOR >= 1)
+
+extern int creat64(const char *, __mode_t);
+static int (*true_creat64) (const char *, __mode_t);
+extern FILE *fopen64(const char *, const char *);
+static FILE *(*true_fopen64) (const char *, const char *);
+extern int open64(const char *, int, ...);
+static int (*true_open64) (const char *, int, ...);
+extern int truncate64(const char *, __off64_t);
+static int (*true_truncate64) (const char *, __off64_t);
+
+#endif
+
+extern int execve(const char *filename, char *const argv[], char *const envp[]);
+static int (*true_execve) (const char *, char *const[], char *const[]);
+
+/*
+ * Initialize the shabang
+ */
+
+static void
+init_wrappers(void)
+{
+ void *libc_handle = NULL;
+
+#ifdef BROKEN_RTLD_NEXT
+// printf ("RTLD_LAZY");
+ libc_handle = dlopen(LIBC_VERSION, RTLD_LAZY);
+#else
+// printf ("RTLD_NEXT");
+ libc_handle = RTLD_NEXT;
+#endif
+
+ true_chmod = dlsym(libc_handle, "chmod");
+ true_chown = dlsym(libc_handle, "chown");
+ true_creat = dlsym(libc_handle, "creat");
+ true_fopen = dlsym(libc_handle, "fopen");
+ true_lchown = dlsym(libc_handle, "lchown");
+ true_link = dlsym(libc_handle, "link");
+ true_mkdir = dlsym(libc_handle, "mkdir");
+ true_opendir = dlsym(libc_handle, "opendir");
+#ifdef WRAP_MKNOD
+ true___xmknod = dlsym(libc_handle, "__xmknod");
+#endif
+ true_open = dlsym(libc_handle, "open");
+ true_rename = dlsym(libc_handle, "rename");
+ true_rmdir = dlsym(libc_handle, "rmdir");
+ true_symlink = dlsym(libc_handle, "symlink");
+ true_truncate = dlsym(libc_handle, "truncate");
+ true_unlink = dlsym(libc_handle, "unlink");
+
+#if (GLIBC_MINOR >= 1)
+ true_creat64 = dlsym(libc_handle, "creat64");
+ true_fopen64 = dlsym(libc_handle, "fopen64");
+ true_open64 = dlsym(libc_handle, "open64");
+ true_truncate64 = dlsym(libc_handle, "truncate64");
+#endif
+
+ true_execve = dlsym(libc_handle, "execve");
+}
+
+void
+_fini(void)
+{
+ free(sandbox_pids_file);
+}
+
+void
+_init(void)
+{
+ int old_errno = errno;
+ char *tmp_string = NULL;
+
+#ifdef SB_MEM_DEBUG
+ mtrace();
+#endif
+
+ init_wrappers();
+
+ /* Get the path and name to this library */
+ tmp_string = get_sandbox_lib("/");
+ strncpy(sandbox_lib, tmp_string, sizeof(sandbox_lib)-1);
+ if (tmp_string)
+ free(tmp_string);
+ tmp_string = NULL;
+
+ /* Generate sandbox pids-file path */
+ sandbox_pids_file = get_sandbox_pids_file();
+
+ errno = old_errno;
+}
+
+static int
+canonicalize(const char *path, char *resolved_path)
+{
+ int old_errno = errno;
+ char *retval;
+
+ *resolved_path = '\0';
+
+ /* If path == NULL, return or we get a segfault */
+ if (NULL == path) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Do not try to resolve an empty path */
+ if ('\0' == path[0]) {
+ errno = old_errno;
+ return 0;
+ }
+
+ retval = erealpath(path, resolved_path);
+
+ if ((!retval) && (path[0] != '/')) {
+ /* The path could not be canonicalized, append it
+ * to the current working directory if it was not
+ * an absolute path
+ */
+ if (errno == ENAMETOOLONG)
+ return -1;
+
+ egetcwd(resolved_path, SB_PATH_MAX - 2);
+ strcat(resolved_path, "/");
+ strncat(resolved_path, path, SB_PATH_MAX - 1);
+
+ if (!erealpath(resolved_path, resolved_path)) {
+ if (errno == ENAMETOOLONG) {
+ /* The resolved path is too long for the buffer to hold */
+ return -1;
+ } else {
+ /* Whatever it resolved, is not a valid path */
+ errno = ENOENT;
+ return -1;
+ }
+ }
+
+ } else if ((!retval) && (path[0] == '/')) {
+ /* Whatever it resolved, is not a valid path */
+ errno = ENOENT;
+ return -1;
+ }
+
+ errno = old_errno;
+ return 0;
+}
+
+static void *
+get_dlsym(const char *symname)
+{
+ void *libc_handle = NULL;
+ void *symaddr = NULL;
+
+#ifdef BROKEN_RTLD_NEXT
+ libc_handle = dlopen(LIBC_VERSION, RTLD_LAZY);
+ if (!libc_handle) {
+ printf("libsandbox.so: Can't dlopen libc: %s\n", dlerror());
+ abort();
+ }
+#else
+ libc_handle = RTLD_NEXT;
+#endif
+
+ symaddr = dlsym(libc_handle, symname);
+ if (!symaddr) {
+ printf("libsandbox.so: Can't resolve %s: %s\n", symname, dlerror());
+ abort();
+ }
+
+ return symaddr;
+}
+
+/*
+ * Wrapper Functions
+ */
+
+int
+chmod(const char *path, mode_t mode)
+{
+ int result = -1;
+ char canonic[SB_PATH_MAX];
+
+ canonicalize_int(path, canonic);
+
+ if FUNCTION_SANDBOX_SAFE
+ ("chmod", canonic) {
+ check_dlsym(chmod);
+ result = true_chmod(path, mode);
+ }
+
+ return result;
+}
+
+int
+chown(const char *path, uid_t owner, gid_t group)
+{
+ int result = -1;
+ char canonic[SB_PATH_MAX];
+
+ canonicalize_int(path, canonic);
+
+ if FUNCTION_SANDBOX_SAFE
+ ("chown", canonic) {
+ check_dlsym(chown);
+ result = true_chown(path, owner, group);
+ }
+
+ return result;
+}
+
+int
+creat(const char *pathname, mode_t mode)
+{
+/* Is it a system call? */
+ int result = -1;
+ char canonic[SB_PATH_MAX];
+
+ canonicalize_int(pathname, canonic);
+
+ if FUNCTION_SANDBOX_SAFE
+ ("creat", canonic) {
+ check_dlsym(open);
+ result = true_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
+ }
+
+ return result;
+}
+
+FILE *
+fopen(const char *pathname, const char *mode)
+{
+ FILE *result = NULL;
+ char canonic[SB_PATH_MAX];
+
+ canonicalize_ptr(pathname, canonic);
+
+ if FUNCTION_SANDBOX_SAFE_CHAR
+ ("fopen", canonic, mode) {
+ check_dlsym(fopen);
+ result = true_fopen(pathname, mode);
+ }
+
+ return result;
+}
+
+int
+lchown(const char *path, uid_t owner, gid_t group)
+{
+ int result = -1;
+ char canonic[SB_PATH_MAX];
+
+ canonicalize_int(path, canonic);
+
+ if FUNCTION_SANDBOX_SAFE
+ ("lchown", canonic) {
+ check_dlsym(lchown);
+ result = true_lchown(path, owner, group);
+ }
+
+ return result;
+}
+
+int
+link(const char *oldpath, const char *newpath)
+{
+ int result = -1;
+ char old_canonic[SB_PATH_MAX], new_canonic[SB_PATH_MAX];
+
+ canonicalize_int(oldpath, old_canonic);
+ canonicalize_int(newpath, new_canonic);
+
+ if FUNCTION_SANDBOX_SAFE
+ ("link", new_canonic) {
+ check_dlsym(link);
+ result = true_link(oldpath, newpath);
+ }
+
+ return result;
+}
+
+int
+mkdir(const char *pathname, mode_t mode)
+// returns 0 success, or -1 if an error occurred
+{
+ int result = -1, my_errno = errno;
+ char canonic[SB_PATH_MAX];
+ struct stat st;
+
+ canonicalize_int(pathname, canonic);
+
+ /* Check if the directory exist, return EEXIST rather than failing */
+ if (0 == lstat(canonic, &st)) {
+ errno = EEXIST;
+ return -1;
+ }
+ errno = my_errno;
+
+ if FUNCTION_SANDBOX_SAFE
+ ("mkdir", canonic) {
+ check_dlsym(mkdir);
+ result = true_mkdir(pathname, mode);
+ }
+
+ return result;
+}
+
+DIR *
+opendir(const char *name)
+{
+ DIR *result = NULL;
+ char canonic[SB_PATH_MAX];
+
+ canonicalize_ptr(name, canonic);
+
+ if FUNCTION_SANDBOX_SAFE
+ ("opendir", canonic) {
+ check_dlsym(opendir);
+ result = true_opendir(name);
+ }
+
+ return result;
+}
+
+#ifdef WRAP_MKNOD
+
+int
+__xmknod(const char *pathname, mode_t mode, dev_t dev)
+{
+ int result = -1;
+ char canonic[SB_PATH_MAX];
+
+ canonicalize_int(pathname, canonic);
+
+ if FUNCTION_SANDBOX_SAFE
+ ("__xmknod", canonic) {
+ check_dlsym(__xmknod);
+ result = true___xmknod(pathname, mode, dev);
+ }
+
+ return result;
+}
+
+#endif
+
+int
+open(const char *pathname, int flags, ...)
+{
+/* Eventually, there is a third parameter: it's mode_t mode */
+ va_list ap;
+ mode_t mode = 0;
+ int result = -1;
+ char canonic[SB_PATH_MAX];
+
+ if (flags & O_CREAT) {
+ va_start(ap, flags);
+ mode = va_arg(ap, mode_t);
+ va_end(ap);
+ }
+
+ canonicalize_int(pathname, canonic);
+
+ if FUNCTION_SANDBOX_SAFE_INT
+ ("open", canonic, flags) {
+ /* We need to resolve open() realtime in some cases,
+ * else we get a segfault when running /bin/ps, etc
+ * in a sandbox */
+ check_dlsym(open);
+ result = true_open(pathname, flags, mode);
+ }
+
+ return result;
+}
+
+int
+rename(const char *oldpath, const char *newpath)
+{
+ int result = -1;
+ char old_canonic[SB_PATH_MAX], new_canonic[SB_PATH_MAX];
+
+ canonicalize_int(oldpath, old_canonic);
+ canonicalize_int(newpath, new_canonic);
+
+ if (FUNCTION_SANDBOX_SAFE("rename", old_canonic) &&
+ FUNCTION_SANDBOX_SAFE("rename", new_canonic)) {
+ check_dlsym(rename);
+ result = true_rename(oldpath, newpath);
+ }
+
+ return result;
+}
+
+int
+rmdir(const char *pathname)
+{
+ int result = -1;
+ char canonic[SB_PATH_MAX];
+
+ canonicalize_int(pathname, canonic);
+
+ if FUNCTION_SANDBOX_SAFE
+ ("rmdir", canonic) {
+ check_dlsym(rmdir);
+ result = true_rmdir(pathname);
+ }
+
+ return result;
+}
+
+int
+symlink(const char *oldpath, const char *newpath)
+{
+ int result = -1;
+ char old_canonic[SB_PATH_MAX], new_canonic[SB_PATH_MAX];
+
+ canonicalize_int(oldpath, old_canonic);
+ canonicalize_int(newpath, new_canonic);
+
+ if FUNCTION_SANDBOX_SAFE
+ ("symlink", new_canonic) {
+ check_dlsym(symlink);
+ result = true_symlink(oldpath, newpath);
+ }
+
+ return result;
+}
+
+int
+truncate(const char *path, TRUNCATE_T length)
+{
+ int result = -1;
+ char canonic[SB_PATH_MAX];
+
+ canonicalize_int(path, canonic);
+
+ if FUNCTION_SANDBOX_SAFE
+ ("truncate", canonic) {
+ check_dlsym(truncate);
+ result = true_truncate(path, length);
+ }
+
+ return result;
+}
+
+int
+unlink(const char *pathname)
+{
+ int result = -1;
+ char canonic[SB_PATH_MAX];
+
+ canonicalize_int(pathname, canonic);
+
+ if FUNCTION_SANDBOX_SAFE
+ ("unlink", canonic) {
+ check_dlsym(unlink);
+ result = true_unlink(pathname);
+ }
+
+ return result;
+}
+
+#if (GLIBC_MINOR >= 1)
+
+int
+creat64(const char *pathname, __mode_t mode)
+{
+/* Is it a system call? */
+ int result = -1;
+ char canonic[SB_PATH_MAX];
+
+ canonicalize_int(pathname, canonic);
+
+ if FUNCTION_SANDBOX_SAFE
+ ("creat64", canonic) {
+ check_dlsym(open64);
+ result = true_open64(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
+ }
+
+ return result;
+}
+
+FILE *
+fopen64(const char *pathname, const char *mode)
+{
+ FILE *result = NULL;
+ char canonic[SB_PATH_MAX];
+
+ canonicalize_ptr(pathname, canonic);
+
+ if FUNCTION_SANDBOX_SAFE_CHAR
+ ("fopen64", canonic, mode) {
+ check_dlsym(fopen64);
+ result = true_fopen(pathname, mode);
+ }
+
+ return result;
+}
+
+int
+open64(const char *pathname, int flags, ...)
+{
+/* Eventually, there is a third parameter: it's mode_t mode */
+ va_list ap;
+ mode_t mode = 0;
+ int result = -1;
+ char canonic[SB_PATH_MAX];
+
+ if (flags & O_CREAT) {
+ va_start(ap, flags);
+ mode = va_arg(ap, mode_t);
+ va_end(ap);
+ }
+
+ canonicalize_int(pathname, canonic);
+
+ if FUNCTION_SANDBOX_SAFE_INT
+ ("open64", canonic, flags) {
+ check_dlsym(open64);
+ result = true_open64(pathname, flags, mode);
+ }
+
+ return result;
+}
+
+int
+truncate64(const char *path, __off64_t length)
+{
+ int result = -1;
+ char canonic[SB_PATH_MAX];
+
+ canonicalize_int(path, canonic);
+
+ if FUNCTION_SANDBOX_SAFE
+ ("truncate64", canonic) {
+ check_dlsym(truncate64);
+ result = true_truncate64(path, length);
+ }
+
+ return result;
+}
+
+#endif /* GLIBC_MINOR >= 1 */
+
+/*
+ * Exec Wrappers
+ */
+
+int
+execve(const char *filename, char *const argv[], char *const envp[])
+{
+ int old_errno = errno;
+ int result = -1;
+ int count = 0;
+ int env_len = 0;
+ char canonic[SB_PATH_MAX];
+ char **my_env = NULL;
+ int kill_env = 1;
+ /* We limit the size LD_PRELOAD can be here, but it should be enough */
+ char tmp_str[4096];
+
+ canonicalize_int(filename, canonic);
+
+ if FUNCTION_SANDBOX_SAFE
+ ("execve", canonic) {
+ while (envp[count] != NULL) {
+ if (strstr(envp[count], "LD_PRELOAD=") == envp[count]) {
+ if (NULL != strstr(envp[count], sandbox_lib)) {
+ my_env = (char **) envp;
+ kill_env = 0;
+ break;
+ } else {
+ int i = 0;
+ const int max_envp_len =
+ strlen(envp[count]) + strlen(sandbox_lib) + 1;
+
+ /* Fail safe ... */
+ if (max_envp_len > 4096) {
+ fprintf(stderr, "sandbox: max_envp_len too big!\n");
+ errno = ENOMEM;
+ return result;
+ }
+
+ /* Calculate envp size */
+ my_env = (char **) envp;
+ do
+ env_len += 1;
+ while (*my_env++);
+
+ my_env = (char **) malloc((env_len + 2) * sizeof (char *));
+ if (NULL == my_env) {
+ errno = ENOMEM;
+ return result;
+ }
+ /* Copy envp to my_env */
+ do
+ my_env[i] = envp[i];
+ while (envp[i++]);
+
+ /* Set tmp_str to envp[count] */
+ strncpy(tmp_str, envp[count], max_envp_len - 1);
+
+ /* LD_PRELOAD already have variables other than sandbox_lib,
+ * thus we have to add sandbox_lib seperated via a whitespace. */
+ if (0 != strncmp(envp[count], "LD_PRELOAD=", max_envp_len - 1)) {
+ strncat(tmp_str, " ", max_envp_len - strlen(tmp_str));
+ strncat(tmp_str, sandbox_lib, max_envp_len - strlen(tmp_str));
+ } else {
+ strncat(tmp_str, sandbox_lib, max_envp_len - strlen(tmp_str));
+ }
+
+ /* Valid string? */
+ tmp_str[max_envp_len] = '\0';
+
+ /* Ok, replace my_env[count] with our version that contains
+ * sandbox_lib ... */
+ my_env[count] = tmp_str;
+
+ break;
+ }
+ }
+ count++;
+ }
+
+ errno = old_errno;
+ check_dlsym(execve);
+ result = true_execve(filename, argv, my_env);
+ old_errno = errno;
+
+ if (my_env && kill_env) {
+ free(my_env);
+ my_env = NULL;
+ }
+ }
+
+ errno = old_errno;
+
+ return result;
+}
+
+/*
+ * Internal Functions
+ */
+
+#if (GLIBC_MINOR == 1)
+
+/* This hack is needed for glibc 2.1.1 (and others?)
+ * (not really needed, but good example) */
+extern int fclose(FILE *);
+static int (*true_fclose) (FILE *) = NULL;
+int
+fclose(FILE * file)
+{
+ int result = -1;
+
+ check_dlsym(fclose);
+ result = true_fclose(file);
+
+ return result;
+}
+
+#endif /* GLIBC_MINOR == 1 */
+
+static void
+init_context(sbcontext_t * context)
+{
+ context->show_access_violation = 1;
+ context->deny_prefixes = NULL;
+ context->num_deny_prefixes = 0;
+ context->read_prefixes = NULL;
+ context->num_read_prefixes = 0;
+ context->write_prefixes = NULL;
+ context->num_write_prefixes = 0;
+ context->predict_prefixes = NULL;
+ context->num_predict_prefixes = 0;
+ context->write_denied_prefixes = NULL;
+ context->num_write_denied_prefixes = 0;
+}
+
+static int
+is_sandbox_pid()
+{
+ int old_errno = errno;
+ int result = 0;
+ FILE *pids_stream = NULL;
+ int pids_file = -1;
+ int current_pid = 0;
+ int tmp_pid = 0;
+
+ init_wrappers();
+
+ pids_stream = true_fopen(sandbox_pids_file, "r");
+
+ if (NULL == pids_stream) {
+ perror(">>> pids file fopen");
+ } else {
+ pids_file = fileno(pids_stream);
+
+ if (pids_file < 0) {
+ perror(">>> pids file fileno");
+ } else {
+ current_pid = getpid();
+
+ while (EOF != fscanf(pids_stream, "%d\n", &tmp_pid)) {
+ if (tmp_pid == current_pid) {
+ result = 1;
+ break;
+ }
+ }
+ }
+ if (EOF == fclose(pids_stream)) {
+ perror(">>> pids file fclose");
+ }
+ pids_stream = NULL;
+ pids_file = -1;
+ }
+
+ errno = old_errno;
+
+ return result;
+}
+
+static void
+clean_env_entries(char ***prefixes_array, int *prefixes_num)
+{
+ int old_errno = errno;
+ int i = 0;
+
+ if (NULL != *prefixes_array) {
+ for (i = 0; i < *prefixes_num; i++) {
+ if (NULL != (*prefixes_array)[i]) {
+ free((*prefixes_array)[i]);
+ (*prefixes_array)[i] = NULL;
+ }
+ }
+ if (*prefixes_array)
+ free(*prefixes_array);
+ *prefixes_array = NULL;
+ *prefixes_num = 0;
+ }
+
+ errno = old_errno;
+}
+
+static void
+init_env_entries(char ***prefixes_array, int *prefixes_num, char *env, int warn)
+{
+ int old_errno = errno;
+ char *prefixes_env = getenv(env);
+
+ if (NULL == prefixes_env) {
+ fprintf(stderr,
+ "Sandbox error : the %s environmental variable should be defined.\n",
+ env);
+ } else {
+ char *buffer = NULL;
+ int prefixes_env_length = strlen(prefixes_env);
+ int i = 0;
+ int num_delimiters = 0;
+ char *token = NULL;
+ char *prefix = NULL;
+
+ for (i = 0; i < prefixes_env_length; i++) {
+ if (':' == prefixes_env[i]) {
+ num_delimiters++;
+ }
+ }
+
+ if (num_delimiters > 0) {
+ *prefixes_array =
+ (char **) malloc((num_delimiters + 1) * sizeof (char *));
+ buffer = strndupa(prefixes_env, prefixes_env_length);
+
+#ifdef REENTRANT_STRTOK
+ token = strtok_r(buffer, ":", &buffer);
+#else
+ token = strtok(buffer, ":");
+#endif
+
+ while ((NULL != token) && (strlen(token) > 0)) {
+ prefix = strndup(token, strlen(token));
+ (*prefixes_array)[(*prefixes_num)++] = filter_path(prefix);
+
+#ifdef REENTRANT_STRTOK
+ token = strtok_r(NULL, ":", &buffer);
+#else
+ token = strtok(NULL, ":");
+#endif
+
+ if (prefix)
+ free(prefix);
+ prefix = NULL;
+ }
+ } else if (prefixes_env_length > 0) {
+ (*prefixes_array) = (char **) malloc(sizeof (char *));
+
+ (*prefixes_array)[(*prefixes_num)++] = filter_path(prefixes_env);
+ }
+ }
+
+ errno = old_errno;
+}
+
+static char *
+filter_path(const char *path)
+{
+ int old_errno = errno;
+ char *filtered_path = (char *) malloc(SB_PATH_MAX * sizeof (char));
+
+ canonicalize_ptr(path, filtered_path);
+
+ errno = old_errno;
+
+ return filtered_path;
+}
+
+static int
+check_access(sbcontext_t * sbcontext, const char *func, const char *path)
+{
+ int old_errno = errno;
+ int result = -1;
+ int i = 0;
+ char *filtered_path = filter_path(path);
+
+ if ('/' != filtered_path[0]) {
+ errno = old_errno;
+
+ if (filtered_path)
+ free(filtered_path);
+ filtered_path = NULL;
+
+ return 0;
+ }
+
+ if ((0 == strncmp(filtered_path, "/etc/ld.so.preload", 18))
+ && (is_sandbox_pid())) {
+ result = 1;
+ }
+
+ if (-1 == result) {
+ if (NULL != sbcontext->deny_prefixes) {
+ for (i = 0; i < sbcontext->num_deny_prefixes; i++) {
+ if (NULL != sbcontext->deny_prefixes[i]) {
+ if (0 == strncmp(filtered_path,
+ sbcontext->
+ deny_prefixes[i],
+ strlen(sbcontext->deny_prefixes[i]))) {
+ result = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ if (-1 == result) {
+ if ((NULL != sbcontext->read_prefixes) &&
+ ((0 == strncmp(func, "open_rd", 7)) ||
+ (0 == strncmp(func, "popen", 5)) ||
+ (0 == strncmp(func, "opendir", 7)) ||
+ (0 == strncmp(func, "system", 6)) ||
+ (0 == strncmp(func, "execl", 5)) ||
+ (0 == strncmp(func, "execlp", 6)) ||
+ (0 == strncmp(func, "execle", 6)) ||
+ (0 == strncmp(func, "execv", 5)) ||
+ (0 == strncmp(func, "execvp", 6)) ||
+ (0 == strncmp(func, "execve", 6))
+ )
+ ) {
+ for (i = 0; i < sbcontext->num_read_prefixes; i++) {
+ if (NULL != sbcontext->read_prefixes[i]) {
+ if (0 == strncmp(filtered_path,
+ sbcontext->
+ read_prefixes[i],
+ strlen(sbcontext->read_prefixes[i]))) {
+ result = 1;
+ break;
+ }
+ }
+ }
+ } else if ((NULL != sbcontext->write_prefixes) &&
+ ((0 == strncmp(func, "open_wr", 7)) ||
+ (0 == strncmp(func, "creat", 5)) ||
+ (0 == strncmp(func, "creat64", 7)) ||
+ (0 == strncmp(func, "mkdir", 5)) ||
+ (0 == strncmp(func, "mknod", 5)) ||
+ (0 == strncmp(func, "mkfifo", 6)) ||
+ (0 == strncmp(func, "link", 4)) ||
+ (0 == strncmp(func, "symlink", 7)) ||
+ (0 == strncmp(func, "rename", 6)) ||
+ (0 == strncmp(func, "utime", 5)) ||
+ (0 == strncmp(func, "utimes", 6)) ||
+ (0 == strncmp(func, "unlink", 6)) ||
+ (0 == strncmp(func, "rmdir", 5)) ||
+ (0 == strncmp(func, "chown", 5)) ||
+ (0 == strncmp(func, "lchown", 6)) ||
+ (0 == strncmp(func, "chmod", 5)) ||
+ (0 == strncmp(func, "truncate", 8)) ||
+ (0 == strncmp(func, "ftruncate", 9)) ||
+ (0 == strncmp(func, "truncate64", 10)) ||
+ (0 == strncmp(func, "ftruncate64", 11))
+ )
+ ) {
+ struct stat tmp_stat;
+
+ for (i = 0; i < sbcontext->num_write_denied_prefixes; i++) {
+ if (NULL != sbcontext->write_denied_prefixes[i]) {
+ if (0 ==
+ strncmp(filtered_path,
+ sbcontext->
+ write_denied_prefixes
+ [i], strlen(sbcontext->write_denied_prefixes[i]))) {
+ result = 0;
+ break;
+ }
+ }
+ }
+
+ if (-1 == result) {
+ for (i = 0; i < sbcontext->num_write_prefixes; i++) {
+ if (NULL != sbcontext->write_prefixes[i]) {
+ if (0 ==
+ strncmp
+ (filtered_path,
+ sbcontext->write_prefixes[i],
+ strlen(sbcontext->write_prefixes[i]))) {
+ result = 1;
+ break;
+ }
+ }
+ }
+
+ if (-1 == result) {
+ /* hack to prevent mkdir of existing dirs to show errors */
+ if (0 == strncmp(func, "mkdir", 5)) {
+ if (0 == stat(filtered_path, &tmp_stat)) {
+ sbcontext->show_access_violation = 0;
+ result = 0;
+ }
+ }
+
+ if (-1 == result) {
+ for (i = 0; i < sbcontext->num_predict_prefixes; i++) {
+ if (NULL != sbcontext->predict_prefixes[i]) {
+ if (0 ==
+ strncmp
+ (filtered_path,
+ sbcontext->
+ predict_prefixes[i],
+ strlen(sbcontext->predict_prefixes[i]))) {
+ sbcontext->show_access_violation = 0;
+ result = 0;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (-1 == result) {
+ result = 0;
+ }
+
+ if (filtered_path)
+ free(filtered_path);
+ filtered_path = NULL;
+
+ errno = old_errno;
+
+ return result;
+}
+
+static int
+check_syscall(sbcontext_t * sbcontext, const char *func, const char *file)
+{
+ int old_errno = errno;
+ int result = 1;
+ struct stat log_stat;
+ char *log_path = NULL;
+ char *absolute_path = NULL;
+ char *tmp_buffer = NULL;
+ int log_file = 0;
+ struct stat debug_log_stat;
+ char *debug_log_env = NULL;
+ char *debug_log_path = NULL;
+ int debug_log_file = 0;
+ char buffer[512];
+ char *dpath = NULL;
+
+ init_wrappers();
+
+ if ('/' == file[0]) {
+ absolute_path = (char *) malloc((strlen(file) + 1) * sizeof (char));
+ sprintf(absolute_path, "%s", file);
+ } else {
+ tmp_buffer = (char *) malloc(SB_PATH_MAX * sizeof (char));
+ egetcwd(tmp_buffer, SB_PATH_MAX - 1);
+ absolute_path = (char *) malloc((strlen(tmp_buffer) + 1 + strlen(file) + 1) * sizeof (char));
+ sprintf(absolute_path, "%s/%s", tmp_buffer, file);
+ if (tmp_buffer)
+ free(tmp_buffer);
+ tmp_buffer = NULL;
+ }
+
+ log_path = getenv("SANDBOX_LOG");
+ debug_log_env = getenv("SANDBOX_DEBUG");
+ debug_log_path = getenv("SANDBOX_DEBUG_LOG");
+
+ if (((NULL == log_path) ||
+ (0 != strncmp(absolute_path, log_path, strlen(log_path)))) &&
+ ((NULL == debug_log_env) ||
+ (NULL == debug_log_path) ||
+ (0 != strncmp(absolute_path, debug_log_path, strlen(debug_log_path))))
+ && (0 == check_access(sbcontext, func, absolute_path))
+ ) {
+ if (1 == sbcontext->show_access_violation) {
+ fprintf(stderr,
+ "\e[31;01mACCESS DENIED\033[0m %s:%*s%s\n",
+ func, (int) (10 - strlen(func)), "", absolute_path);
+
+ if (NULL != log_path) {
+ sprintf(buffer, "%s:%*s%s\n", func, (int) (10 - strlen(func)), "",
+ absolute_path);
+ // log_path somehow gets corrupted. figuring out why would be good.
+ dpath = strdup(log_path);
+ if ((0 == lstat(log_path, &log_stat))
+ && (0 == S_ISREG(log_stat.st_mode))
+ ) {
+ fprintf(stderr,
+ "\e[31;01mSECURITY BREACH\033[0m %s already exists and is not a regular file.\n",
+ dpath);
+ } else if (0 == check_access(sbcontext, "open_wr", dpath)) {
+ unsetenv("SANDBOX_LOG");
+ fprintf(stderr,
+ "\e[31;01mSECURITY BREACH\033[0m SANDBOX_LOG %s isn't allowed via SANDBOX_WRITE\n",
+ dpath);
+ } else {
+ log_file = true_open(dpath,
+ O_APPEND | O_WRONLY
+ | O_CREAT,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (log_file >= 0) {
+ write(log_file, buffer, strlen(buffer));
+ close(log_file);
+ }
+ }
+ free(dpath);
+ }
+ }
+
+ result = 0;
+ } else if (NULL != debug_log_env) {
+ if (NULL != debug_log_path) {
+ if (0 != strncmp(absolute_path, debug_log_path, strlen(debug_log_path))) {
+ sprintf(buffer, "%s:%*s%s\n", func, (int) (10 - strlen(func)), "",
+ absolute_path);
+ //debug_log_path somehow gets corupted, same thing as log_path above.
+ dpath = strdup(debug_log_path);
+ if ((0 == lstat(debug_log_path, &debug_log_stat))
+ && (0 == S_ISREG(debug_log_stat.st_mode))
+ ) {
+ fprintf(stderr,
+ "\e[31;01mSECURITY BREACH\033[0m %s already exists and is not a regular file.\n",
+ debug_log_path);
+ } else if (0 == check_access(sbcontext, "open_wr", dpath)) {
+ unsetenv("SANDBOX_DEBUG");
+ unsetenv("SANDBOX_DEBUG_LOG");
+ fprintf(stderr,
+ "\e[31;01mSECURITY BREACH\033[0m SANDBOX_DEBUG_LOG %s isn't allowed by SANDBOX_WRITE.\n",
+ dpath);
+ } else {
+ debug_log_file =
+ true_open(dpath,
+ O_APPEND | O_WRONLY |
+ O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (debug_log_file >= 0) {
+ write(debug_log_file, buffer, strlen(buffer));
+ close(debug_log_file);
+ }
+ }
+ free(dpath);
+ }
+ } else {
+ fprintf(stderr,
+ "\e[32;01mACCESS ALLOWED\033[0m %s:%*s%s\n",
+ func, (int) (10 - strlen(func)), "", absolute_path);
+ }
+ }
+
+ if (absolute_path)
+ free(absolute_path);
+ absolute_path = NULL;
+
+ errno = old_errno;
+
+ return result;
+}
+
+static int
+is_sandbox_on()
+{
+ int old_errno = errno;
+
+ /* $SANDBOX_ACTIVE is an env variable that should ONLY
+ * be used internal by sandbox.c and libsanbox.c. External
+ * sources should NEVER set it, else the sandbox is enabled
+ * in some cases when run in parallel with another sandbox,
+ * but not even in the sandbox shell.
+ *
+ * Azarah (3 Aug 2002)
+ */
+ if ((NULL != getenv("SANDBOX_ON")) &&
+ (0 == strncmp(getenv("SANDBOX_ON"), "1", 1)) &&
+ (NULL != getenv("SANDBOX_ACTIVE")) &&
+ (0 == strncmp(getenv("SANDBOX_ACTIVE"), "armedandready", 13))
+ ) {
+ errno = old_errno;
+
+ return 1;
+ } else {
+ errno = old_errno;
+
+ return 0;
+ }
+}
+
+static int
+before_syscall(const char *func, const char *file)
+{
+ int old_errno = errno;
+ int result = 1;
+ sbcontext_t sbcontext;
+
+ if (!strlen(file)) {
+ /* The file/directory does not exist */
+ errno = ENOENT;
+ return 0;
+ }
+
+ init_context(&sbcontext);
+
+ init_env_entries(&(sbcontext.deny_prefixes),
+ &(sbcontext.num_deny_prefixes), "SANDBOX_DENY", 1);
+ init_env_entries(&(sbcontext.read_prefixes),
+ &(sbcontext.num_read_prefixes), "SANDBOX_READ", 1);
+ init_env_entries(&(sbcontext.write_prefixes),
+ &(sbcontext.num_write_prefixes), "SANDBOX_WRITE", 1);
+ init_env_entries(&(sbcontext.predict_prefixes),
+ &(sbcontext.num_predict_prefixes), "SANDBOX_PREDICT", 1);
+
+ result = check_syscall(&sbcontext, func, file);
+
+ clean_env_entries(&(sbcontext.deny_prefixes), &(sbcontext.num_deny_prefixes));
+ clean_env_entries(&(sbcontext.read_prefixes), &(sbcontext.num_read_prefixes));
+ clean_env_entries(&(sbcontext.write_prefixes),
+ &(sbcontext.num_write_prefixes));
+ clean_env_entries(&(sbcontext.predict_prefixes),
+ &(sbcontext.num_predict_prefixes));
+
+ errno = old_errno;
+
+ if (0 == result) {
+ errno = EACCES;
+ }
+
+ return result;
+}
+
+static int
+before_syscall_open_int(const char *func, const char *file, int flags)
+{
+ if ((flags & O_WRONLY) || (flags & O_RDWR)) {
+ return before_syscall("open_wr", file);
+ } else {
+ return before_syscall("open_rd", file);
+ }
+}
+
+static int
+before_syscall_open_char(const char *func, const char *file, const char *mode)
+{
+ if (*mode == 'r' && ((strcmp(mode, "r") == 0) ||
+ /* The strspn accept args are known non-writable modifiers */
+ (strlen(++mode) == strspn(mode, "xbtmc")))) {
+ return before_syscall("open_rd", file);
+ } else {
+ return before_syscall("open_wr", file);
+ }
+}
+
+#include "getcwd.c"
+#include "canonicalize.c"
+
+// vim:expandtab noai:cindent ai
diff --git a/src/sandbox-1.1/sandbox.bashrc b/src/sandbox-1.1/sandbox.bashrc
new file mode 100644
index 00000000..5986f726
--- /dev/null
+++ b/src/sandbox-1.1/sandbox.bashrc
@@ -0,0 +1,8 @@
+# Copyright (C) 2001 Geert Bevin, Uwyn, http://www.uwyn.com
+# Distributed under the terms of the GNU General Public License, v2 or later
+# Author : Geert Bevin <gbevin@uwyn.com>
+# $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-1.1/Attic/sandbox.bashrc,v 1.2.4.1 2004/10/22 16:53:30 carpaski Exp $
+source /etc/profile
+export LD_PRELOAD="$SANDBOX_LIB"
+alias make="make LD_PRELOAD=$SANDBOX_LIB"
+alias su="su -c '/bin/bash -rcfile $SANDBOX_DIR/sandbox.bashrc'"
diff --git a/src/sandbox-1.1/sandbox.c b/src/sandbox-1.1/sandbox.c
new file mode 100644
index 00000000..f7a2a320
--- /dev/null
+++ b/src/sandbox-1.1/sandbox.c
@@ -0,0 +1,863 @@
+/*
+** Path sandbox for the gentoo linux portage package system, initially
+** based on the ROCK Linux Wrapper for getting a list of created files
+**
+** to integrate with bash, bash should have been built like this
+**
+** ./configure --prefix=<prefix> --host=<host> --without-gnu-malloc
+**
+** it's very important that the --enable-static-link option is NOT specified
+**
+** Copyright (C) 2001 Geert Bevin, Uwyn, http://www.uwyn.com
+** Distributed under the terms of the GNU General Public License, v2 or later
+** Author : Geert Bevin <gbevin@uwyn.com>
+** $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-1.1/Attic/sandbox.c,v 1.20.2.1 2004/12/01 22:14:09 carpaski Exp $
+*/
+
+/* #define _GNU_SOURCE */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "sandbox.h"
+
+int preload_adaptable = 1;
+int cleaned_up = 0;
+int print_debug = 0;
+int stop_called = 0;
+
+/* Read pids file, and load active pids into an array. Return number of pids in array */
+int
+load_active_pids(int fd, int **pids)
+{
+ char *data = NULL;
+ char *ptr = NULL, *ptr2 = NULL;
+ int my_pid;
+ int num_pids = 0;
+ long len;
+
+ pids[0] = NULL;
+
+ len = file_length(fd);
+
+ /* Allocate and zero datablock to read pids file */
+ data = (char *) malloc((len + 1) * sizeof (char));
+ memset(data, 0, len + 1);
+
+ /* Start at beginning of file */
+ lseek(fd, 0L, SEEK_SET);
+
+ /* read entire file into a buffer */
+ read(fd, data, len);
+
+ ptr = data;
+
+ /* Loop and read all pids */
+ while (1) {
+ /* Find new line */
+ ptr2 = strchr(ptr, '\n');
+ if (ptr2 == NULL)
+ break; /* No more PIDs */
+
+ /* Clear the \n. And ptr should have a null-terminated decimal string */
+ ptr2[0] = 0;
+
+ my_pid = atoi(ptr);
+
+ /* If the PID is still alive, add it to our array */
+ if ((0 != my_pid) && (0 == kill(my_pid, 0))) {
+ pids[0] = (int *) realloc(pids[0], (num_pids + 1) * sizeof (int));
+ pids[0][num_pids] = my_pid;
+ num_pids++;
+ }
+
+ /* Put ptr past the NULL we just wrote */
+ ptr = ptr2 + 1;
+ }
+
+ if (data)
+ free(data);
+ data = NULL;
+
+ return num_pids;
+}
+
+/* Read ld.so.preload file, and loads dirs into an array. Return number of entries in array */
+int
+load_preload_libs(int fd, char ***preloads)
+{
+ char *data = NULL;
+ char *ptr = NULL, *ptr2 = NULL;
+ int num_entries = 0;
+ long len;
+
+ preloads[0] = NULL;
+
+ len = file_length(fd);
+
+ /* Allocate and zero datablock to read pids file */
+ data = (char *) malloc((len + 1) * sizeof (char));
+ memset(data, 0, len + 1);
+
+ /* Start at beginning of file */
+ lseek(fd, 0L, SEEK_SET);
+
+ /* read entire file into a buffer */
+ read(fd, data, len);
+
+ ptr = data;
+
+ /* Loop and read all pids */
+ while (1) {
+ /* Find new line */
+ ptr2 = strchr(ptr, '\n');
+
+ /* Clear the \n. And ptr should have a null-terminated decimal string
+ * Don't break from the loop though because the last line may not
+ * terminated with a \n
+ */
+ if (NULL != ptr2)
+ ptr2[0] = 0;
+
+ /* If listing does not match our libname, add it to the array */
+ if ((strlen(ptr)) && (NULL == strstr(ptr, LIB_NAME))) {
+ preloads[0] =
+ (char **) realloc(preloads[0], (num_entries + 1) * sizeof (char **));
+ preloads[0][num_entries] = strdup(ptr);
+ num_entries++;
+ }
+
+ if (NULL == ptr2)
+ break; /* No more PIDs */
+
+ /* Put ptr past the NULL we just wrote */
+ ptr = ptr2 + 1;
+ }
+
+ if (data)
+ free(data);
+ data = NULL;
+
+ return num_entries;
+}
+
+void
+cleanup()
+{
+ int i = 0;
+ int success = 1;
+ int pids_file = -1, num_of_pids = 0;
+ int *pids_array = NULL;
+ char pid_string[255];
+ char *sandbox_pids_file;
+#ifdef USE_LD_SO_PRELOAD
+ int preload_file = -1, num_of_preloads = 0;
+ char preload_entry[255];
+ char **preload_array = NULL;
+#endif
+
+ /* Generate sandbox pids-file path */
+ sandbox_pids_file = get_sandbox_pids_file();
+
+ /* Remove this sandbox's bash pid from the global pids
+ * file if it has rights to adapt the ld.so.preload file */
+ if ((1 == preload_adaptable) && (0 == cleaned_up)) {
+ cleaned_up = 1;
+ success = 1;
+
+ if (print_debug)
+ printf("Cleaning up pids file.\n");
+
+ /* Stat the PIDs file, make sure it exists and is a regular file */
+ if (file_exist(sandbox_pids_file, 1) <= 0) {
+ fprintf(stderr, ">>> pids file is not a regular file");
+ success = 0;
+ /* We should really not fail if the pidsfile is missing here, but
+ * rather just exit cleanly, as there is still some cleanup to do */
+ return;
+ }
+
+ pids_file = file_open(sandbox_pids_file, "r+", 1, 0664, "portage");
+ if (-1 == pids_file) {
+ success = 0;
+ /* Nothing more to do here */
+ return;
+ }
+
+ /* Load "still active" pids into an array */
+ num_of_pids = load_active_pids(pids_file, &pids_array);
+ //printf("pids: %d\r\n", num_of_pids);
+
+#ifdef USE_LD_SO_PRELOAD
+ /* clean the /etc/ld.so.preload file if no other sandbox
+ * processes are running anymore */
+ if (1 == num_of_pids) {
+ success = 1;
+
+ if (print_debug)
+ printf("Cleaning up /etc/ld.so.preload.\n");
+
+ preload_file = file_open("/etc/ld.so.preload", "r+", 1, 0644);
+ if (-1 != preload_file) {
+ /* Load all the preload libraries into an array */
+ num_of_preloads = load_preload_libs(preload_file, &preload_array);
+ //printf("num preloads: %d\r\n", num_of_preloads);
+ /* Clear file */
+ file_truncate(preload_file);
+
+ /* store the other preload libraries back into the /etc/ld.so.preload file */
+ if (num_of_preloads > 0) {
+ for (i = 0; i < num_of_preloads; i++) {
+ sprintf(preload_entry, "%s\n", preload_array[i]);
+ if (write
+ (preload_file,
+ preload_entry,
+ strlen(preload_entry)) != strlen(preload_entry)) {
+ perror(">>> /etc/ld.so.preload file write");
+ success = 0;
+ break;
+ }
+ }
+ }
+
+ /* Free memory used to store preload array */
+ for (i = 0; i < num_of_preloads; i++) {
+ if (preload_array[i])
+ free(preload_array[i]);
+ preload_array[i] = NULL;
+ }
+ if (preload_array)
+ free(preload_array);
+ preload_array = NULL;
+
+ file_close(preload_file);
+ preload_file = -1;
+ }
+ }
+#endif
+
+ file_truncate(pids_file);
+
+ /* if pids are still running, write only the running pids back to the file */
+ if (num_of_pids > 1) {
+ for (i = 0; i < num_of_pids; i++) {
+ if (pids_array[i] != getpid()) {
+ sprintf(pid_string, "%d\n", pids_array[i]);
+
+ if (write(pids_file, pid_string, strlen(pid_string)) !=
+ strlen(pid_string)) {
+ perror(">>> pids file write");
+ success = 0;
+ break;
+ }
+ }
+ }
+
+ file_close(pids_file);
+ pids_file = -1;
+ } else {
+
+ file_close(pids_file);
+ pids_file = -1;
+
+ /* remove the pidsfile, as this was the last sandbox */
+ unlink(sandbox_pids_file);
+ }
+
+ if (pids_array != NULL)
+ free(pids_array);
+ pids_array = NULL;
+ }
+
+ free(sandbox_pids_file);
+ if (0 == success)
+ return;
+}
+
+void
+stop(int signum)
+{
+ if (stop_called == 0) {
+ stop_called = 1;
+ printf("Caught signal %d in pid %d\r\n", signum, getpid());
+ cleanup();
+ } else {
+ fprintf(stderr, "Pid %d alreadly caught signal and is still cleaning up\n", getpid());
+ }
+}
+
+void
+setenv_sandbox_write(char *home_dir, char *portage_tmp_dir, char *var_tmp_dir,
+ char *tmp_dir)
+{
+ char buf[1024];
+
+ /* bzero out entire buffer then append trailing 0 */
+ memset(buf, 0, sizeof(buf));
+
+ if (!getenv(ENV_SANDBOX_WRITE)) {
+ /* these could go into make.globals later on */
+ snprintf(buf, sizeof(buf),
+ "%s:%s/.gconfd/lock:%s/.bash_history:", \
+ "/dev/zero:/dev/fd/:/dev/null:/dev/pts/:" \
+ "/dev/vc/:/dev/tty:/tmp/:" \
+ "/dev/shm/ngpt:/var/log/scrollkeeper.log:" \
+ "/usr/tmp/conftest:/usr/lib/conftest:" \
+ "/usr/lib32/conftest:/usr/lib64/conftest:" \
+ "/usr/tmp/cf:/usr/lib/cf:/usr/lib32/cf:/usr/lib64/cf",
+ home_dir, home_dir);
+
+ if (NULL == portage_tmp_dir) {
+ strncat(buf, tmp_dir, sizeof(buf));
+ strncat(buf, ":", sizeof(buf));
+ strncat(buf, var_tmp_dir, sizeof(buf));
+ strncat(buf, ":/tmp/:/var/tmp/", sizeof(buf));
+ } else {
+ strncat(buf, portage_tmp_dir, sizeof(buf));
+ strncat(buf, ":", sizeof(buf));
+ strncat(buf, tmp_dir, sizeof(buf));
+ strncat(buf, ":", sizeof(buf));
+ strncat(buf, var_tmp_dir, sizeof(buf));
+ strncat(buf, ":/tmp/:/var/tmp/", sizeof(buf));
+ }
+ buf[sizeof(buf) - 1] = '\0';
+ setenv(ENV_SANDBOX_WRITE, buf, 1);
+ }
+}
+
+void
+setenv_sandbox_predict(char *home_dir)
+{
+ char buf[1024];
+
+ memset(buf, 0, sizeof(buf));
+
+ if (!getenv(ENV_SANDBOX_PREDICT)) {
+ /* these should go into make.globals later on */
+ snprintf(buf, sizeof(buf), "%s/.:" \
+ "/usr/lib/python2.0/:" \
+ "/usr/lib/python2.1/:" \
+ "/usr/lib/python2.2/:" \
+ "/usr/lib/python2.3/:" \
+ "/usr/lib/python2.4/:" \
+ "/usr/lib/python2.5/:" \
+ "/usr/lib/python3.0/:",
+ home_dir);
+
+ buf[sizeof(buf) - 1] = '\0';
+ setenv(ENV_SANDBOX_PREDICT, buf, 1);
+ }
+}
+
+int
+print_sandbox_log(char *sandbox_log)
+{
+ int sandbox_log_file = -1;
+ char *beep_count_env = NULL;
+ int i, color, beep_count = 0;
+ long len = 0;
+ char *buffer = NULL;
+
+ sandbox_log_file = file_open(sandbox_log, "r", 1, 0664, "portage");
+ if (-1 == sandbox_log_file)
+ return 0;
+
+ len = file_length(sandbox_log_file);
+ buffer = (char *) malloc((len + 1) * sizeof (char));
+ memset(buffer, 0, len + 1);
+ read(sandbox_log_file, buffer, len);
+ file_close(sandbox_log_file);
+
+ color = ( (getenv("NOCOLOR") != NULL) ? 0 : 1);
+
+ if (color) printf("\e[31;01m");
+ printf("--------------------------- ACCESS VIOLATION SUMMARY ---------------------------");
+ if (color) printf("\033[0m");
+ if (color) printf("\e[31;01m");
+ printf("\nLOG FILE = \"%s\"", sandbox_log);
+ if (color) printf("\033[0m");
+ printf("\n\n");
+ printf("%s", buffer);
+ if (buffer)
+ free(buffer);
+ buffer = NULL;
+ printf
+ ("\e[31;01m--------------------------------------------------------------------------------\033[0m\n");
+
+ beep_count_env = getenv(ENV_SANDBOX_BEEP);
+ if (beep_count_env)
+ beep_count = atoi(beep_count_env);
+ else
+ beep_count = DEFAULT_BEEP_COUNT;
+
+ for (i = 0; i < beep_count; i++) {
+ fputc('\a', stderr);
+ if (i < beep_count - 1)
+ sleep(1);
+ }
+ return 1;
+}
+
+int
+spawn_shell(char *argv_bash[])
+{
+#ifdef USE_SYSTEM_SHELL
+ int i = 0;
+ char *sh = NULL;
+ int first = 1;
+ int ret;
+ long len = 0;
+
+ while (1) {
+ if (NULL == argv_bash[i])
+ break;
+ if (NULL != sh)
+ len = strlen(sh);
+ sh = (char *) realloc(sh, len + strlen(argv_bash[i]) + 5);
+ if (first) {
+ sh[0] = 0;
+ first = 0;
+ }
+ strcat(sh, "\"");
+ strcat(sh, argv_bash[i]);
+ strcat(sh, "\" ");
+
+ //printf("%s\n", argv_bash[i]);
+ i++;
+ }
+ printf("%s\n", sh);
+ ret = system(sh);
+ if (sh)
+ free(sh);
+ sh = NULL;
+
+ if (-1 == ret)
+ return 0;
+ return 1;
+
+#else
+# ifndef NO_FORK
+ int pid;
+ int status = 0;
+ int ret = 0;
+
+ pid = fork();
+
+ /* Child's process */
+ if (0 == pid) {
+# endif
+ execv(argv_bash[0], argv_bash);
+# ifndef NO_FORK
+ return 0;
+ } else if (pid < 0) {
+ return 0;
+ }
+ ret = waitpid(pid, &status, 0);
+ if ((-1 == ret) || (status > 0))
+ return 0;
+# endif
+ return 1;
+#endif
+}
+
+int
+main(int argc, char **argv)
+{
+ int i = 0, success = 1;
+#ifdef USE_LD_SO_PRELOAD
+ int preload_file = -1;
+#endif
+ int sandbox_log_presence = 0;
+ int sandbox_log_file = -1;
+ int pids_file = -1;
+ long len;
+
+ int *pids_array = NULL;
+ int num_of_pids = 0;
+
+ // char run_arg[255];
+ char portage_tmp_dir[PATH_MAX];
+ char var_tmp_dir[PATH_MAX];
+ char tmp_dir[PATH_MAX];
+ char sandbox_log[255];
+ char sandbox_debug_log[255];
+ char sandbox_dir[255];
+ char sandbox_lib[255];
+ char *sandbox_pids_file;
+ char sandbox_rc[255];
+ char pid_string[255];
+ char **argv_bash = NULL;
+
+ char *run_str = "-c";
+ char *home_dir = NULL;
+ char *tmp_string = NULL;
+#ifdef USE_LD_SO_PRELOAD
+ char **preload_array = NULL;
+ int num_of_preloads = 0;
+#endif
+
+ /* Only print info if called with no arguments .... */
+ if (argc < 2)
+ print_debug = 1;
+
+ if (print_debug)
+ printf
+ ("========================== Gentoo linux path sandbox ===========================\n");
+
+ /* check if a sandbox is already running */
+ if (NULL != getenv(ENV_SANDBOX_ON)) {
+ fprintf(stderr,
+ "Not launching a new sandbox instance\nAnother one is already running in this process hierarchy.\n");
+ exit(1);
+ } else {
+
+ /* determine the location of all the sandbox support files */
+ if (print_debug)
+ printf("Detection of the support files.\n");
+
+ /* Generate base sandbox path */
+ tmp_string = get_sandbox_path(argv[0]);
+ strncpy(sandbox_dir, tmp_string, 254);
+ if (tmp_string)
+ free(tmp_string);
+ tmp_string = NULL;
+ strcat(sandbox_dir, "/");
+
+ /* Generate sandbox lib path */
+ tmp_string = get_sandbox_lib(sandbox_dir);
+ strncpy(sandbox_lib, tmp_string, 254);
+ if (tmp_string)
+ free(tmp_string);
+ tmp_string = NULL;
+
+ /* Generate sandbox pids-file path */
+ sandbox_pids_file = get_sandbox_pids_file();
+
+ /* Generate sandbox bashrc path */
+ tmp_string = get_sandbox_rc(sandbox_dir);
+ strncpy(sandbox_rc, tmp_string, 254);
+ if (tmp_string)
+ free(tmp_string);
+ tmp_string = NULL;
+
+ /* verify the existance of required files */
+ if (print_debug)
+ printf("Verification of the required files.\n");
+
+#ifndef SB_HAVE_64BIT_ARCH
+ if (file_exist(sandbox_lib, 0) <= 0) {
+ fprintf(stderr, "Could not open the sandbox library at '%s'.\n",
+ sandbox_lib);
+ return -1;
+ }
+#endif
+ if (file_exist(sandbox_rc, 0) <= 0) {
+ fprintf(stderr, "Could not open the sandbox rc file at '%s'.\n",
+ sandbox_rc);
+ return -1;
+ }
+#ifdef USE_LD_SO_PRELOAD
+ /* ensure that the /etc/ld.so.preload file contains an entry for the sandbox lib */
+ if (print_debug)
+ printf("Setting up the ld.so.preload file.\n");
+
+ /* check if the /etc/ld.so.preload is a regular file */
+ if (file_exist("/etc/ld.so.preload", 1) < 0) {
+ fprintf(stderr, ">>> /etc/ld.so.preload file is not a regular file\n");
+ exit(1);
+ }
+
+ if (getuid() == 0) {
+ /* Our r+ also will create the file if it doesn't exist */
+ preload_file = file_open("/etc/ld.so.preload", "r+", 1, 0644);
+ if (-1 == preload_file) {
+ preload_adaptable = 0;
+/* exit(1);*/
+ }
+ } else {
+ /* Avoid permissions warnings if we're not root */
+ preload_adaptable = 0;
+ }
+
+ /* Only update /etc/ld.so.preload if we can write to it ... */
+ if (1 == preload_adaptable) {
+ /* Load entries of preload table */
+ num_of_preloads = load_preload_libs(preload_file, &preload_array);
+
+ /* Zero out our ld.so.preload file */
+ file_truncate(preload_file);
+
+ /* Write contents of preload file */
+ for (i = 0; i < num_of_preloads + 1; i++) {
+ /* First entry should be our sandbox library */
+ if (0 == i) {
+ if (write
+ (preload_file, sandbox_lib,
+ strlen(sandbox_lib)) != strlen(sandbox_lib)) {
+ perror(">>> /etc/ld.so.preload file write");
+ success = 0;
+ break;
+ }
+ } else {
+ /* Output all other preload entries */
+ if (write
+ (preload_file, preload_array[i - 1],
+ strlen(preload_array[i - 1])) != strlen(preload_array[i - 1])) {
+ perror(">>> /etc/ld.so.preload file write");
+ success = 0;
+ break;
+ }
+ }
+ /* Don't forget the return character after each line! */
+ if (1 != write(preload_file, "\n", 1)) {
+ perror(">>> /etc/ld.so.preload file write");
+ success = 0;
+ break;
+ }
+ }
+
+ for (i = 0; i < num_of_preloads; i++) {
+ if (preload_array[i])
+ free(preload_array[i]);
+ preload_array[i] = NULL;
+ }
+ if (preload_array)
+ free(preload_array);
+ num_of_preloads = 0;
+ preload_array = NULL;
+ }
+
+ /* That's all we needed to do with the preload file */
+ if (0 < preload_file)
+ file_close(preload_file);
+ preload_file = -1;
+#endif
+
+ /* set up the required environment variables */
+ if (print_debug)
+ printf("Setting up the required environment variables.\n");
+
+ /* Generate sandbox log full path */
+ tmp_string = get_sandbox_log();
+ strncpy(sandbox_log, tmp_string, 254);
+ if (tmp_string)
+ free(tmp_string);
+ tmp_string = NULL;
+
+ setenv(ENV_SANDBOX_LOG, sandbox_log, 1);
+
+ snprintf(sandbox_debug_log, sizeof(sandbox_debug_log), "%s%s%s",
+ DEBUG_LOG_FILE_PREFIX, pid_string, LOG_FILE_EXT);
+ setenv(ENV_SANDBOX_DEBUG_LOG, sandbox_debug_log, 1);
+
+ home_dir = getenv("HOME");
+ if (!home_dir) {
+ home_dir = "/tmp";
+ setenv("HOME", home_dir, 1);
+ }
+
+ /* drobbins: we need to expand these paths using realpath() so that PORTAGE_TMPDIR
+ * can contain symlinks (example, /var is a symlink, /var/tmp is a symlink.) Without
+ * this, access is denied to /var/tmp, hurtin' ebuilds.
+ */
+
+ { char *e;
+ e = getenv("PORTAGE_TMPDIR");
+ if ( e && ( strlen(e) < sizeof(portage_tmp_dir)-1 ) && (strlen(e) > 1) )
+ realpath(e, portage_tmp_dir);
+
+ }
+ realpath("/var/tmp", var_tmp_dir);
+ realpath("/tmp", tmp_dir);
+
+ setenv(ENV_SANDBOX_DIR, sandbox_dir, 1);
+ setenv(ENV_SANDBOX_LIB, sandbox_lib, 1);
+ setenv("LD_PRELOAD", sandbox_lib, 1);
+
+ if (!getenv(ENV_SANDBOX_DENY))
+ setenv(ENV_SANDBOX_DENY, LD_PRELOAD_FILE, 1);
+
+ if (!getenv(ENV_SANDBOX_READ))
+ setenv(ENV_SANDBOX_READ, "/", 1);
+
+ /* Set up Sandbox Write path */
+ setenv_sandbox_write(home_dir, portage_tmp_dir, var_tmp_dir, tmp_dir);
+ setenv_sandbox_predict(home_dir);
+
+ setenv(ENV_SANDBOX_ON, "1", 0);
+
+ /* if the portage temp dir was present, cd into it */
+ if (NULL != portage_tmp_dir)
+ chdir(portage_tmp_dir);
+
+ argv_bash = (char **) malloc(6 * sizeof (char *));
+ argv_bash[0] = strdup("/bin/bash");
+ argv_bash[1] = strdup("-rcfile");
+ argv_bash[2] = strdup(sandbox_rc);
+
+ if (argc < 2)
+ argv_bash[3] = NULL;
+ else
+ argv_bash[3] = strdup(run_str); /* "-c" */
+
+ argv_bash[4] = NULL; /* strdup(run_arg); */
+ argv_bash[5] = NULL;
+
+ if (argc >= 2) {
+ for (i = 1; i < argc; i++) {
+ if (NULL == argv_bash[4])
+ len = 0;
+ else
+ len = strlen(argv_bash[4]);
+
+ argv_bash[4] =
+ (char *) realloc(argv_bash[4],
+ (len + strlen(argv[i]) + 2) * sizeof (char));
+
+ if (0 == len)
+ argv_bash[4][0] = 0;
+ if (1 != i)
+ strcat(argv_bash[4], " ");
+
+ strcat(argv_bash[4], argv[i]);
+ }
+ }
+
+ /* set up the required signal handlers */
+ signal(SIGHUP, &stop);
+ signal(SIGINT, &stop);
+ signal(SIGQUIT, &stop);
+ signal(SIGTERM, &stop);
+
+ /* this one should NEVER be set in ebuilds, as it is the one
+ * private thing libsandbox.so use to test if the sandbox
+ * should be active for this pid, or not.
+ *
+ * azarah (3 Aug 2002)
+ */
+
+ setenv("SANDBOX_ACTIVE", "armedandready", 1);
+
+ /* Load our PID into PIDs file */
+ success = 1;
+ if (file_exist(sandbox_pids_file, 1) < 0) {
+ success = 0;
+ fprintf(stderr, ">>> %s is not a regular file\n", sandbox_pids_file);
+ } else {
+ pids_file = file_open(sandbox_pids_file, "r+", 1, 0664, "portage");
+ if (-1 == pids_file)
+ success = 0;
+ }
+ if (1 == success) {
+ /* Grab still active pids */
+ num_of_pids = load_active_pids(pids_file, &pids_array);
+
+ /* Zero out file */
+ file_truncate(pids_file);
+
+ /* Output active pids, and append our pid */
+ for (i = 0; i < num_of_pids + 1; i++) {
+ /* Time for our entry */
+ if (i == num_of_pids)
+ sprintf(pid_string, "%d\n", getpid());
+ else
+ sprintf(pid_string, "%d\n", pids_array[i]);
+
+ if (write(pids_file, pid_string, strlen(pid_string)) !=
+ strlen(pid_string)) {
+ perror(">>> pids file write");
+ success = 0;
+ break;
+ }
+ }
+ /* Clean pids_array */
+ if (pids_array)
+ free(pids_array);
+ pids_array = NULL;
+ num_of_pids = 0;
+
+ /* We're done with the pids file */
+ file_close(pids_file);
+ }
+
+ /* Something went wrong, bail out */
+ if (0 == success) {
+ perror(">>> pids file write");
+ exit(1);
+ }
+
+ /* STARTING PROTECTED ENVIRONMENT */
+ if (print_debug) {
+ printf("The protected environment has been started.\n");
+ printf
+ ("--------------------------------------------------------------------------------\n");
+ }
+
+ if (print_debug)
+ printf("Shell being started in forked process.\n");
+
+ /* Start Bash */
+ if (!spawn_shell(argv_bash)) {
+ if (print_debug)
+ fprintf(stderr, ">>> shell process failed to spawn\n");
+ success = 0;
+ }
+
+ /* Free bash stuff */
+ for (i = 0; i < 6; i++) {
+ if (argv_bash[i])
+ free(argv_bash[i]);
+ argv_bash[i] = NULL;
+ }
+ if (argv_bash)
+ free(argv_bash);
+ argv_bash = NULL;
+
+ if (print_debug)
+ printf("Cleaning up sandbox process\n");
+
+ cleanup();
+
+ if (print_debug) {
+ printf
+ ("========================== Gentoo linux path sandbox ===========================\n");
+ printf("The protected environment has been shut down.\n");
+ }
+
+ if (file_exist(sandbox_log, 0)) {
+ sandbox_log_presence = 1;
+ success = 1;
+ if (!print_sandbox_log(sandbox_log))
+ success = 0;
+
+#if 0
+ if (!success)
+ exit(1);
+#endif
+
+ sandbox_log_file = -1;
+ } else if (print_debug) {
+ printf
+ ("--------------------------------------------------------------------------------\n");
+ }
+
+ if ((sandbox_log_presence) || (!success))
+ return 1;
+ else
+ return 0;
+ }
+}
+
+// vim:expandtab noai:cindent ai
diff --git a/src/sandbox-1.1/sandbox.h b/src/sandbox-1.1/sandbox.h
new file mode 100644
index 00000000..67a415dd
--- /dev/null
+++ b/src/sandbox-1.1/sandbox.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2002 Brad House <brad@mainstreetsoftworks.com>,
+ * Possibly based on code from Geert Bevin, Uwyn, http://www.uwyn.com
+ * Distributed under the terms of the GNU General Public License, v2 or later
+ * Author: Brad House <brad@mainstreetsoftworks.com>
+ *
+ * $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-1.1/Attic/sandbox.h,v 1.5.2.1 2004/10/22 16:53:30 carpaski Exp $
+ */
+
+#ifndef __SANDBOX_H__
+#define __SANDBOX_H__
+
+/* Uncomment below to use flock instead of fcntl (POSIX way) to lock/unlock files */
+/* #define USE_FLOCK */
+
+/* Uncomment below to use system() to execute the shell rather than execv */
+/* #define USE_SYSTEM_SHELL */
+
+/* Uncomment below to use /etc/ld.so.preload (could be very intrusive!!) */
+/* #define USE_LD_SO_PRELOAD */
+
+/* Uncommend to not have the protected shell forked, just run in parent process */
+/* ONLY FOR DEBUGGING PURPOSES!! (strace needs it like that) */
+/* #define NO_FORK */
+
+#define LD_PRELOAD_FILE "/etc/ld.so.preload"
+#define LIB_NAME "libsandbox.so"
+#define BASHRC_NAME "sandbox.bashrc"
+#define PIDS_FILE "/tmp/sandboxpids.tmp"
+#define LOG_FILE_PREFIX "/tmp/sandbox-"
+#define DEBUG_LOG_FILE_PREFIX "/tmp/sandbox-debug-"
+#define LOG_FILE_EXT ".log"
+
+#define ENV_SANDBOX_DEBUG_LOG "SANDBOX_DEBUG_LOG"
+#define ENV_SANDBOX_LOG "SANDBOX_LOG"
+#define ENV_SANDBOX_DIR "SANDBOX_DIR"
+#define ENV_SANDBOX_LIB "SANDBOX_LIB"
+
+#define ENV_SANDBOX_DENY "SANDBOX_DENY"
+#define ENV_SANDBOX_READ "SANDBOX_READ"
+#define ENV_SANDBOX_WRITE "SANDBOX_WRITE"
+#define ENV_SANDBOX_PREDICT "SANDBOX_PREDICT"
+
+#define ENV_SANDBOX_ON "SANDBOX_ON"
+#define ENV_SANDBOX_BEEP "SANDBOX_BEEP"
+
+#define DEFAULT_BEEP_COUNT 3
+
+char *get_sandbox_path(char *argv0);
+char *get_sandbox_lib(char *sb_path);
+char *get_sandbox_pids_file(void);
+char *get_sandbox_rc(char *sb_path);
+char *get_sandbox_log();
+char *sb_dirname(const char *path);
+int file_getmode(char *mode);
+long file_tell(int fp);
+int file_lock(int fd, int lock, char *filename);
+int file_unlock(int fd);
+int file_locktype(char *mode);
+int file_open(char *filename, char *mode, int perm_specified, ...);
+void file_close(int fd);
+long file_length(int fd);
+int file_truncate(int fd);
+int file_exist(char *filename, int checkmode);
+
+#endif
+
+// vim:expandtab noai:cindent ai
diff --git a/src/sandbox-1.1/sandbox_futils.c b/src/sandbox-1.1/sandbox_futils.c
new file mode 100644
index 00000000..f9ddb342
--- /dev/null
+++ b/src/sandbox-1.1/sandbox_futils.c
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2002 Brad House <brad@mainstreetsoftworks.com>
+ * Distributed under the terms of the GNU General Public License, v2 or later
+ * Author: Brad House <brad@mainstreetsoftworks.com>
+ *
+ * $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-1.1/Attic/sandbox_futils.c,v 1.11.2.1 2004/11/03 13:12:55 ferringb Exp $
+ *
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <grp.h>
+#include <pwd.h>
+
+#include "sandbox.h"
+
+/* BEGIN Prototypes */
+int file_security_check(char *filename);
+/* END Prototypes */
+
+
+/* glibc modified getcwd() functions */
+char *egetcwd(char *, size_t);
+
+char *
+get_sandbox_path(char *argv0)
+{
+ char path[255];
+ char *cwd = NULL;
+
+ memset(path, 0, sizeof(path));
+ /* ARGV[0] specifies full path */
+ if (argv0[0] == '/') {
+ strncpy(path, argv0, sizeof(path)-1);
+
+ /* ARGV[0] specifies relative path */
+ } else {
+ egetcwd(cwd, sizeof(path)-2);
+ snprintf(path, sizeof(path), "%s/%s", cwd, argv0);
+ if (cwd)
+ free(cwd);
+ cwd = NULL;
+ }
+
+ /* Return just directory */
+ return (sb_dirname(path));
+}
+
+char *
+get_sandbox_lib(char *sb_path)
+{
+ char path[255];
+
+#ifdef SB_HAVE_64BIT_ARCH
+ snprintf(path, sizeof(path), "%s", LIB_NAME);
+#else
+ snprintf(path, sizeof(path), "/lib/%s", LIB_NAME);
+ if (file_exist(path, 0) <= 0) {
+ snprintf(path, sizeof(path), "%s%s", sb_path, LIB_NAME);
+ }
+#endif
+ return (strdup(path));
+}
+
+char *
+get_sandbox_pids_file(void)
+{
+ if (0 < getenv("SANDBOX_PIDS_FILE")) {
+ return (strdup(getenv("SANDBOX_PIDS_FILE")));
+ }
+ return (strdup(PIDS_FILE));
+}
+
+char *
+get_sandbox_rc(char *sb_path)
+{
+ char path[255];
+
+ snprintf(path, sizeof(path), "/usr/lib/portage/lib/%s", BASHRC_NAME);
+ if (file_exist(path, 0) <= 0) {
+ snprintf(path, sizeof(path), "%s%s", sb_path, BASHRC_NAME);
+ }
+ return (strdup(path));
+}
+
+char *
+get_sandbox_log()
+{
+ char path[255];
+ char *sandbox_log_env = NULL;
+
+ /* THIS CHUNK BREAK THINGS BY DOING THIS:
+ * SANDBOX_LOG=/tmp/sandbox-app-admin/superadduser-1.0.7-11063.log
+ */
+
+ sandbox_log_env = getenv(ENV_SANDBOX_LOG);
+ snprintf(path, sizeof(path)-1, "%s%s%s%d%s", LOG_FILE_PREFIX,
+ ( sandbox_log_env == NULL ? "" : sandbox_log_env ),
+ ( sandbox_log_env == NULL ? "" : "-" ),
+ getpid(), LOG_FILE_EXT);
+ return (strdup(path));
+}
+
+/* Obtain base directory name. Do not allow trailing / */
+char *
+sb_dirname(const char *path)
+{
+ char *ret = NULL;
+ char *ptr = NULL;
+ int loc = 0, i;
+ int cut_len = -1;
+
+ /* don't think NULL will ever be passed, but just in case */
+ if (NULL == path)
+ return (strdup("."));
+
+ /* Grab pointer to last slash */
+ ptr = strrchr(path, '/');
+ if (NULL == ptr) {
+ return (strdup("."));
+ }
+
+ /* decimal location of pointer */
+ loc = ptr - path;
+
+ /* Remove any trailing slash */
+ for (i = loc - 1; i >= 0; i--) {
+ if (path[i] != '/') {
+ cut_len = i + 1; /* make cut_len the length of the string to keep */
+ break;
+ }
+ }
+
+ /* It could have been just a plain /, return a 1byte 0 filled string */
+ if (-1 == cut_len)
+ return (strdup(""));
+
+ /* Allocate memory, and return the directory */
+ ret = (char *) malloc((cut_len + 1) * sizeof (char));
+ memcpy(ret, path, cut_len);
+ ret[cut_len] = 0;
+
+ return (ret);
+}
+
+/*
+char* dirname(const char* path)
+{
+ char* base = NULL;
+ unsigned int length = 0;
+
+ base = strrchr(path, '/');
+ if (NULL == base)
+ {
+ return strdup(".");
+ }
+ while (base > path && *base == '/')
+ {
+ base--;
+ }
+ length = (unsigned int) 1 + base - path;
+
+ base = malloc(sizeof(char)*(length+1));
+ memmove(base, path, length);
+ base[length] = 0;
+
+ return base;
+}*/
+
+/* Convert text (string) modes to integer values */
+int
+file_getmode(char *mode)
+{
+ int mde = 0;
+ if (0 == strcasecmp(mode, "r+")) {
+ mde = O_RDWR | O_CREAT;
+ } else if (0 == strcasecmp(mode, "w+")) {
+ mde = O_RDWR | O_CREAT | O_TRUNC;
+ } else if (0 == strcasecmp(mode, "a+")) {
+ mde = O_RDWR | O_CREAT | O_APPEND;
+ } else if (0 == strcasecmp(mode, "r")) {
+ mde = O_RDONLY;
+ } else if (0 == strcasecmp(mode, "w")) {
+ mde = O_WRONLY | O_CREAT | O_TRUNC;
+ } else if (0 == strcasecmp(mode, "a")) {
+ mde = O_WRONLY | O_APPEND | O_CREAT;
+ } else {
+ mde = O_RDONLY;
+ }
+ return (mde);
+}
+
+/* Get current position in file */
+long
+file_tell(int fp)
+{
+ return (lseek(fp, 0L, SEEK_CUR));
+}
+
+/* lock the file, preferrably the POSIX way */
+int
+file_lock(int fd, int lock, char *filename)
+{
+ int err;
+#ifdef USE_FLOCK
+ if (flock(fd, lock) < 0) {
+ err = errno;
+ fprintf(stderr, ">>> %s flock file lock: %s\n", filename, strerror(err));
+ return 0;
+ }
+#else
+ struct flock fl;
+ fl.l_type = lock;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0L;
+ fl.l_len = 0L;
+ fl.l_pid = getpid();
+ if (fcntl(fd, F_SETLKW, &fl) < 0) {
+ err = errno;
+ fprintf(stderr, ">>> %s fcntl file lock: %s\n", filename, strerror(err));
+ return 0;
+ }
+#endif
+ return 1;
+}
+
+/* unlock the file, preferrably the POSIX way */
+int
+file_unlock(int fd)
+{
+#ifdef USE_FLOCK
+ if (flock(fd, LOCK_UN) < 0) {
+ perror(">>> flock file unlock");
+ return 0;
+ }
+#else
+ struct flock fl;
+ fl.l_type = F_UNLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0L;
+ fl.l_len = 0L;
+ fl.l_pid = getpid();
+ if (fcntl(fd, F_SETLKW, &fl) < 0) {
+ perror(">>> fcntl file unlock");
+ return 0;
+ }
+#endif
+ return 1;
+}
+
+/* Auto-determine from how the file was opened, what kind of lock to lock
+ * the file with
+ */
+int
+file_locktype(char *mode)
+{
+#ifdef USE_FLOCK
+ if (NULL != (strchr(mode, 'w')) || (NULL != strchr(mode, '+'))
+ || (NULL != strchr(mode, 'a')))
+ return (LOCK_EX);
+ return (LOCK_SH);
+#else
+ if (NULL != (strchr(mode, 'w')) || (NULL != strchr(mode, '+'))
+ || (NULL != strchr(mode, 'a')))
+ return (F_WRLCK);
+ return (F_RDLCK);
+#endif
+}
+
+/* Use standard fopen style modes to open the specified file. Also auto-determines and
+ * locks the file either in shared or exclusive mode depending on opening mode
+ */
+int
+file_open(char *filename, char *mode, int perm_specified, ...)
+{
+ int fd;
+ char error[250];
+ va_list ap;
+ int perm;
+ char *group = NULL;
+ struct group *group_struct;
+
+ file_security_check(filename);
+
+ if (perm_specified) {
+ va_start(ap, perm_specified);
+ perm = va_arg(ap, int);
+ group = va_arg(ap, char *);
+ va_end(ap);
+ }
+ fd = open(filename, file_getmode(mode));
+ file_security_check(filename);
+ if (-1 == fd) {
+ snprintf(error, sizeof(error), ">>> %s file mode: %s open", filename, mode);
+ perror(error);
+ return (fd);
+ }
+ if (perm_specified) {
+ if (fchmod(fd, 0664) && (0 == getuid())) {
+ snprintf(error, sizeof(error), ">>> Could not set mode: %s", filename);
+ perror(error);
+ }
+ }
+ if (NULL != group) {
+ group_struct = getgrnam(group);
+ if (NULL == group) {
+ snprintf(error, sizeof(error), ">>> Could not get grp number: %s", group);
+ perror(error);
+ } else {
+ if (fchown(fd, -1, group_struct->gr_gid) && (0 == getuid())) {
+ snprintf(error, sizeof(error), ">>> Could not set group: %s", filename);
+ perror(error);
+ }
+ }
+ }
+ /* Only lock the file if opening succeeded */
+ if (-1 != fd) {
+ if(file_security_check(filename) != 0) {
+ /* Security violation occured between the last check and the */
+ /* creation of the file. As SpanKY pointed out there is a race */
+ /* condition here, so if there is a problem here we'll mesg and */
+ /* bail out to avoid it until we can work and test a better fix. */
+ fprintf(stderr, "\n\nSECURITY RACE CONDITION: Problem recurred after creation!\nBAILING OUT\n\n");
+ exit(127);
+ }
+
+ if (0 == file_lock(fd, file_locktype(mode), filename)) {
+ close(fd);
+ return -1;
+ }
+ } else {
+ snprintf(error, sizeof(error), ">>> %s file mode:%s open", filename, mode);
+ perror(error);
+ }
+ return (fd);
+}
+
+/* Close and unlock file */
+void
+file_close(int fd)
+{
+ if (-1 != fd) {
+ file_unlock(fd);
+ close(fd);
+ }
+}
+
+/* Return length of file */
+long
+file_length(int fd)
+{
+ long pos, len;
+ pos = file_tell(fd);
+ len = lseek(fd, 0L, SEEK_END);
+ lseek(fd, pos, SEEK_SET);
+ return (len);
+}
+
+/* Zero out file */
+int
+file_truncate(int fd)
+{
+ lseek(fd, 0L, SEEK_SET);
+ if (ftruncate(fd, 0) < 0) {
+ perror(">>> file truncate");
+ return 0;
+ }
+ return 1;
+}
+
+/* Check to see if a file exists Return: 1 success, 0 file not found, -1 error */
+int
+file_exist(char *filename, int checkmode)
+{
+ struct stat mystat;
+
+ /* Verify file exists and is regular file (not sym link) */
+ if (checkmode) {
+ if (-1 == lstat(filename, &mystat)) {
+ /* file doesn't exist */
+ if (ENOENT == errno) {
+ return 0;
+ } else { /* permission denied or other error */
+ perror(">>> stat file");
+ return -1;
+ }
+ }
+ if (!S_ISREG(mystat.st_mode))
+ return -1;
+
+ /* Just plain verify the file exists */
+ } else {
+ if (-1 == stat(filename, &mystat)) {
+ /* file does not exist */
+ if (ENOENT == errno) {
+ return 0;
+ } else { /* permission denied or other error */
+ perror(">>> stat file");
+ return -1;
+ }
+ }
+ }
+
+ return 1;
+}
+
+int file_security_check(char *filename) { /* 0 == fine, >0 == problem */
+ struct stat stat_buf;
+ struct group *group_buf;
+ struct passwd *passwd_buf;
+
+ passwd_buf = getpwnam("portage");
+ group_buf = getgrnam("portage");
+
+ if((lstat(filename, &stat_buf) == -1) && (errno == ENOENT)) {
+ /* Doesn't exist. */
+ return 0;
+ }
+ else {
+ if((stat_buf.st_nlink) > 1) { /* Security: We are handlinked... */
+ if(unlink(filename)) {
+ fprintf(stderr,
+ "Unable to delete file in security violation (hardlinked): %s\n",
+ filename);
+ exit(127);
+ }
+ fprintf(stderr,
+ "File in security violation (hardlinked): %s\n",
+ filename);
+ return 1;
+ }
+ else if(S_ISLNK(stat_buf.st_mode)) { /* Security: We are a symlink? */
+ fprintf(stderr,
+ "File in security violation (symlink): %s\n",
+ filename);
+ exit(127);
+ }
+ else if(0 == S_ISREG(stat_buf.st_mode)) { /* Security: special file */
+ fprintf(stderr,
+ "File in security violation (not regular): %s\n",
+ filename);
+ exit(127);
+ }
+ else if(stat_buf.st_mode & S_IWOTH) { /* Security: We are o+w? */
+ if(unlink(filename)) {
+ fprintf(stderr,
+ "Unable to delete file in security violation (world write): %s\n",
+ filename);
+ exit(127);
+ }
+ fprintf(stderr,
+ "File in security violation (world write): %s\n",
+ filename);
+ return 1;
+ }
+ else if(
+ !((stat_buf.st_uid == 0) || (stat_buf.st_uid == getuid()) || ((passwd_buf!=NULL) && (stat_buf.st_uid == passwd_buf->pw_uid))) ||
+ !((stat_buf.st_gid == 0) || (stat_buf.st_gid == getgid()) || ((group_buf !=NULL) && (stat_buf.st_gid == group_buf->gr_gid)))
+ ) { /* Security: Owner/Group isn't right. */
+
+ /* uid = 0 or myuid or portage */
+ /* gid = 0 or mygid or portage */
+
+ if(0) {
+ fprintf(stderr, "--1: %d,%d,%d,%d\n--2: %d,%d,%d,%d\n",
+
+ (stat_buf.st_uid == 0),
+ (stat_buf.st_uid == getuid()),
+ (passwd_buf!=NULL),
+ (passwd_buf!=NULL)? (stat_buf.st_uid == passwd_buf->pw_uid) : -1,
+
+ (stat_buf.st_gid == 0),
+ (stat_buf.st_gid == getgid()),
+ (group_buf !=NULL),
+ (group_buf !=NULL)? (stat_buf.st_gid == group_buf->gr_gid) : -1);
+ }
+
+ /* manpage: "The return value may point to static area" */
+ /* DO NOT ACTUALLY FREE THIS... It'll segfault. */
+ /* if(passwd_buf != NULL) { free(passwd_buf); } */
+ /* if(group_buf != NULL) { free(group_buf); } */
+
+ if(unlink(filename)) {
+ fprintf(stderr,
+ "Unable to delete file in security violation (bad owner/group): %s\n",
+ filename);
+ exit(127);
+ }
+ fprintf(stderr,
+ "File in security violation (bad owner/group): %s\n",
+ filename);
+ return 1;
+ }
+ } /* Stat */
+ return 0;
+}
+
+// vim:expandtab noai:cindent ai
diff --git a/src/sandbox-dev/ChangeLog b/src/sandbox-dev/ChangeLog
new file mode 100644
index 00000000..3a052a12
--- /dev/null
+++ b/src/sandbox-dev/ChangeLog
@@ -0,0 +1,91 @@
+# ChangeLog for Path Sandbox
+# Copyright 1999-2004 Gentoo Foundation; Distributed under the GPL v2
+# $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-dev/Attic/ChangeLog,v 1.9 2004/10/04 14:08:46 vapier Exp $
+
+ 16 Dec 2002; J Robert Ray <jrray@gentoo.org> Makefile libsandbox.c :
+
+ Instead of parsing the SANDBOX_* env variables on each syscall, save the
+ result in a global sbcontext pointer and cache the value of the env vars
+ to detect later on if they have changed and need to be re-parsed. Works
+ around bug 233.
+
+ 16 Dec 2002; Martin Schlemmer <azarah@gentoo.org> create-localdecls :
+
+ Fix memory leak for mips, bug #12236. Thanks to Torgeir Hansen <torgeir@trenger.ro>
+ for this fix.
+
+ 4 Dec 2002; J Robert Ray <jrray@gentoo.org> sandbox.h sandbox_futils.c :
+
+ sandbox_futils defined a dirname() function that was masking the same
+ function in glibc and was broken (e.g.: SANDBOX_DIR was being set to
+ '/usr/lib/portage/bi/'). Fixed function to return expected results and
+ renamed it to sb_dirname() to no longer mask the glibc function. Closes bug
+ 11231.
+
+ 4 Dec 2002; Martin Schlemmer <azarah@gentoo.org> :
+
+ Fix a segfault in libsandbox.c if canonicalize() was called with
+ first parameter = NULL.
+
+ 1 Sep 2002; Martin Schlemmer <azarah@gentoo.org> :
+
+ Fix my braindead 'return 1;' in a void function. Updated sandbox.c,
+ cleanup() for this.
+
+ Change cleanup() in sandbox.c not to exit with fail status if
+ the pidsfile is missing. We really should still display sandbox
+ violations if they occured.
+
+ 31 Aug 2002; Martin Schlemmer <azarah@gentoo.org> :
+
+ Update cleanup() in sandbox.c to remove the PIDSFILE if this is
+ the last sandbox running.
+
+ 25 Aug 2002; Martin Schlemmer <azarah@gentoo.org> :
+
+ Major cleanups to mainly libsandbox.c again.
+
+ 22 Aug 2002; Martin Schlemmer <azarah@gentoo.org> :
+
+ Add copyrights to sandbox.h and sandbox_futils.h. If wrong, the
+ parties involved should please contact me so that we can fix it.
+
+ Add opendir wrapper to libsandbox.c.
+
+ 21 Aug 2002; Martin Schlemmer <azarah@gentoo.org> :
+
+ Do some more cleanups to ecanonicalize(), as it dropped filenames in
+ rare cases (after my symlink cleanups), and caused glibc to bork.
+ These fixes went into canonicalize.c.
+
+ 20 Aug 2002; Martin Schlemmer <azarah@gentoo.org> :
+
+ Fix spawn_shell() and main() in sandbox.c to properly return fail
+ status.
+
+ 19 Aug 2002; Martin Schlemmer <azarah@gentoo.org> :
+
+ The new canonicalize() function in libsandbox.c also resolved symlinks,
+ which caused on cleaning sandbox errors if the symlink pointed to a
+ file in the live root. Ripped out canonicalize() and realpath() from
+ glibc; removed the symlink stuff, and changed them to ecanonicalize()
+ and erealpath().
+
+ 18 Aug 2002; Martin Schlemmer <azarah@gentoo.org> :
+
+ Ripped out all the wrappers, and implemented those of InstallWatch.
+ Losts of cleanups and bugfixes. Implement a execve that forces
+ $LIBSANDBOX in $LD_PRELOAD. We can now thus do away with the feared
+ /etc/ld.so.preload (*g*) ... Made the needed changes to sandbox.c,
+ sandbox.h and sandbox_futils.c. Rewrote the Makefile for most
+ parts; it now have an install target.
+
+ Reformat the whole thing to look somewhat like the reworked sandbox.c
+ and new sandbox.h and sandbox_futils.c from:
+
+ Brad House <brad@mainstreetsoftworks.com>.
+
+ Additional Copyrights now due to the InstallWatch code:
+
+ Copyright (C) 1998-9 Pancrazio `Ezio' de Mauro <p@demauro.net>
+
diff --git a/src/sandbox-dev/Makefile b/src/sandbox-dev/Makefile
new file mode 100644
index 00000000..83b00e30
--- /dev/null
+++ b/src/sandbox-dev/Makefile
@@ -0,0 +1,62 @@
+# Copyright (C) 2001 Geert Bevin, Uwyn, http://www.uwyn.com
+# Distributed under the terms of the GNU General Public License, v2 or later
+# Author : Geert Bevin <gbevin@uwyn.com>
+#
+# Modified 15 Apr 2002 Jon Nelson <jnelson@gentoo.org>
+# Clean up Makefile somewhat, and use make's implicit rules
+#
+# Modified 19 Aug 2002; Martin Schlemmer <azarah@gentoo.org>
+# Major rewrite to support new stuff
+#
+# $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-dev/Attic/Makefile,v 1.3 2002/12/16 22:28:05 jrray Exp $
+
+CC = gcc
+LD = ld
+CFLAGS =
+OBJ_DEFINES = -D_GNU_SOURCE -DPIC -fPIC -D_REENTRANT
+LIBS =
+LDFLAGS =
+DESTDIR =
+
+TARGETS = libsandbox.so sandbox
+
+all: $(TARGETS)
+
+sandbox: sandbox.o sandbox_futils.o
+ $(CC) $^ -ldl -lc -o $@
+
+sandbox.o: sandbox.c sandbox.h
+ $(CC) $(CFLAGS) -Wall -c sandbox.c
+
+sandbox_futils.o: sandbox_futils.c sandbox.h
+ $(CC) $(CFLAGS) -Wall -c $(OBJ_DEFINES) sandbox_futils.c
+
+libsandbox.so: libsandbox.o sandbox_futils.o canonicalize.o
+ $(LD) $^ -shared -fPIC -ldl -lc -lpthread -o $@
+
+libsandbox.o: libsandbox.c localdecls.h
+ $(CC) $(CFLAGS) -Wall -c $(OBJ_DEFINES) libsandbox.c
+
+canonicalize.o: canonicalize.c
+ $(CC) $(CFLAGS) -Wall -c $(OBJ_DEFINES) canonicalize.c
+
+localdecls.h: create-localdecls libctest.c
+ ./create-localdecls
+
+
+install: all
+ install -d -m 0755 $(DESTDIR)/lib
+ install -d -m 0755 $(DESTDIR)/usr/lib/portage/bin
+ install -d -m 0755 $(DESTDIR)/usr/lib/portage/lib
+ install -m 0755 libsandbox.so $(DESTDIR)/lib
+ install -m 0755 sandbox $(DESTDIR)/usr/lib/portage/bin
+ install -m 0644 sandbox.bashrc $(DESTDIR)/usr/lib/portage/lib
+
+
+clean:
+ rm -f $(TARGETS)
+ rm -f *.o *~ core
+ rm -f localdecls.h
+
+
+# vim:expandtab noai:cindent ai
diff --git a/src/sandbox-dev/canonicalize.c b/src/sandbox-dev/canonicalize.c
new file mode 100644
index 00000000..7ecd57ec
--- /dev/null
+++ b/src/sandbox-dev/canonicalize.c
@@ -0,0 +1,194 @@
+/* Return the canonical absolute name of a given file.
+ Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/*
+ * $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-dev/Attic/canonicalize.c,v 1.2 2002/08/26 03:28:30 azarah Exp $
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stddef.h>
+
+#ifndef __set_errno
+# define __set_errno(val) errno = (val)
+#endif
+
+/* Return the canonical absolute name of file NAME. A canonical name
+ does not contain any `.', `..' components nor any repeated path
+ separators ('/') or symlinks. All path components must exist. If
+ RESOLVED is null, the result is malloc'd; otherwise, if the
+ canonical name is PATH_MAX chars or more, returns null with `errno'
+ set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars,
+ returns the name in RESOLVED. If the name cannot be resolved and
+ RESOLVED is non-NULL, it contains the path of the first component
+ that cannot be resolved. If the path can be resolved, RESOLVED
+ holds the same value as the value returned. */
+
+/* Modified: 19 Aug 2002; Martin Schlemmer <azarah@gentoo.org>
+ *
+ * Cleaned up unneeded stuff, and change so that it will not
+ * resolve symlinks. Also prepended a 'e' to functions that
+ * I did not rip out.
+ *
+ */
+
+static char *
+ecanonicalize (const char *name, char *resolved)
+{
+ char *rpath, *dest;
+ const char *start, *end, *rpath_limit;
+ long int path_max;
+
+ if (name == NULL)
+ {
+ /* As per Single Unix Specification V2 we must return an error if
+ either parameter is a null pointer. We extend this to allow
+ the RESOLVED parameter to be NULL in case the we are expected to
+ allocate the room for the return value. */
+ __set_errno (EINVAL);
+ return NULL;
+ }
+
+ if (name[0] == '\0')
+ {
+ /* As per Single Unix Specification V2 we must return an error if
+ the name argument points to an empty string. */
+ __set_errno (ENOENT);
+ return NULL;
+ }
+
+#ifdef PATH_MAX
+ path_max = PATH_MAX;
+#else
+ path_max = pathconf (name, _PC_PATH_MAX);
+ if (path_max <= 0)
+ path_max = 1024;
+#endif
+
+ rpath = resolved ? alloca (path_max) : malloc (path_max);
+ rpath_limit = rpath + path_max;
+
+ if (name[0] != '/')
+ {
+ if (!getcwd (rpath, path_max))
+ {
+ rpath[0] = '\0';
+ goto error;
+ }
+ dest = strchr (rpath, '\0');
+ }
+ else
+ {
+ rpath[0] = '/';
+ dest = rpath + 1;
+ }
+
+ for (start = end = name; *start; start = end)
+ {
+ /* Skip sequence of multiple path-separators. */
+ while (*start == '/')
+ ++start;
+
+ /* Find end of path component. */
+ for (end = start; *end && *end != '/'; ++end)
+ /* Nothing. */;
+
+ if (end - start == 0)
+ break;
+ else if (end - start == 1 && start[0] == '.')
+ /* nothing */;
+ else if (end - start == 2 && start[0] == '.' && start[1] == '.')
+ {
+ /* Back up to previous component, ignore if at root already. */
+ if (dest > rpath + 1)
+ while ((--dest)[-1] != '/');
+ }
+ else
+ {
+ size_t new_size;
+
+ if (dest[-1] != '/')
+ *dest++ = '/';
+
+ if (dest + (end - start) >= rpath_limit)
+ {
+ ptrdiff_t dest_offset = dest - rpath;
+
+ if (resolved)
+ {
+ __set_errno (ENAMETOOLONG);
+ if (dest > rpath + 1)
+ dest--;
+ *dest = '\0';
+ goto error;
+ }
+ new_size = rpath_limit - rpath;
+ if (end - start + 1 > path_max)
+ new_size += end - start + 1;
+ else
+ new_size += path_max;
+ rpath = realloc (rpath, new_size);
+ rpath_limit = rpath + new_size;
+ if (rpath == NULL)
+ return NULL;
+
+ dest = rpath + dest_offset;
+ }
+
+ dest = __mempcpy (dest, start, end - start);
+ *dest = '\0';
+
+ }
+ }
+#if 0
+ if (dest > rpath + 1 && dest[-1] == '/')
+ --dest;
+#endif
+ *dest = '\0';
+
+ return resolved ? memcpy (resolved, rpath, dest - rpath + 1) : rpath;
+
+error:
+ if (resolved)
+ strcpy (resolved, rpath);
+ else
+ free (rpath);
+ return NULL;
+}
+
+
+char *
+erealpath (const char *name, char *resolved)
+{
+ if (resolved == NULL)
+ {
+ __set_errno (EINVAL);
+ return NULL;
+ }
+
+ return ecanonicalize (name, resolved);
+}
+
+
+// vim:expandtab noai:cindent ai
diff --git a/src/sandbox-dev/create-localdecls b/src/sandbox-dev/create-localdecls
new file mode 100755
index 00000000..5cb1a4d0
--- /dev/null
+++ b/src/sandbox-dev/create-localdecls
@@ -0,0 +1,95 @@
+#!/bin/sh
+
+# This is a quick'n'dirty hack to make the program behave correctly
+# under different systems.
+# Example:
+# when using libc5, (f)trucate's offset argument type is size_t with
+# libc5, but it's off_t with libc6 (glibc2).
+#
+# Uhm... time to learn GNU autoconf :-)
+#
+# $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-dev/Attic/create-localdecls,v 1.2 2002/12/16 19:19:27 azarah Exp $
+
+OUTFILE='localdecls.h'
+
+# if your arch needs to dlopen() glibc, add it here separated by space :]
+BROKEN_RTLD_ARCHLIST="mips"
+
+echo '/* This file is automatically generated *' > $OUTFILE
+echo ' * Modify create-localdecls instead of this */' >> $OUTFILE
+echo >> $OUTFILE
+echo '#ifndef __LOCALDECLS_H_' >> $OUTFILE
+echo '#define __LOCALDECLS_H_' >> $OUTFILE
+echo >> $OUTFILE
+
+###
+###
+###
+
+echo -n 'Checking truncate argument type... '
+if grep -q 'truncate.*size_t' /usr/include/unistd.h ; then
+ echo 'size_t'
+ echo '#define TRUNCATE_T size_t' >> $OUTFILE
+else
+ echo 'off_t' # At least, I HOPE it's off_t :-)
+ echo '#define TRUNCATE_T off_t' >> $OUTFILE
+fi
+
+###
+###
+###
+
+echo -n 'Checking libc version... '
+gcc -Wall -o libctest libctest.c
+VERSION=`ldd libctest | grep libc\\.so | awk '{print $1}'`
+rm libctest
+echo $VERSION
+echo "#define LIBC_VERSION \"$VERSION\"" >> $OUTFILE
+if test "$VERSION" = 'libc.so.5' ; then
+ echo '#define BROKEN_RTLD_NEXT' >> $OUTFILE
+ echo '#define LIBC 5' >> $OUTFILE
+else
+ # for the arch's that need to dlopen() libc to fetch real funcs!
+ # 16.12.02 -Torgeir Hansen <torgeir@trenger.ro>
+ MYARCH=`/bin/uname -m`
+ for x in $BROKEN_RTLD_ARCHLIST; do
+ if [ $x = $MYARCH ]; then
+ echo '#define BROKEN_RTLD_NEXT' >> $OUTFILE
+ fi
+ done
+
+fi
+
+if test "$VERSION" = 'libc.so.6' ; then
+ echo -n 'Checking glibc subversion... '
+ tmp="`ldd /bin/sh | grep libc.so 2> /dev/null`"
+ LibcPath=`expr "$tmp" : '[^/]*\(/[^ ]*\)'`
+ tmp="`strings $LibcPath | grep -i 'c library'`"
+ OsLibcMajor=`expr "$tmp" : '.* \([0-9][0-9]*\)'`
+ OsLibcMinor=`expr "$tmp" : '.* [0-9][0-9]*\.\([0-9][0-9]*\)'`
+ case "$OsLibcMajor" in
+ 2)
+ # 2 is the glibc version
+ case "$OsLibcMinor" in
+ 0)
+ echo '#define GLIBC_MINOR 0' >> $OUTFILE
+ SUBVERSION='glibc-2.0' ;;
+ 1)
+ echo '#define GLIBC_MINOR 1' >> $OUTFILE
+ SUBVERSION='glibc-2.1' ;;
+ 2)
+ echo '#define GLIBC_MINOR 2' >> $OUTFILE
+ SUBVERSION='glibc-2.2' ;;
+ *)
+ echo 'Treated as glibc >= 2.1 (finger crossed)'
+ echo '#define GLIBC_MINOR 1' >> $OUTFILE
+ SUBVERSION='glibc-2.1' ;;
+ esac
+ ;;
+ esac
+fi
+
+echo >> $OUTFILE
+echo '#endif' >> $OUTFILE
+echo
+
diff --git a/src/sandbox-dev/libctest.c b/src/sandbox-dev/libctest.c
new file mode 100644
index 00000000..5fc92b50
--- /dev/null
+++ b/src/sandbox-dev/libctest.c
@@ -0,0 +1,6 @@
+/* Dummy program to check your libc version */
+
+int main(void) {
+ return 0;
+}
+
diff --git a/src/sandbox-dev/libsandbox.c b/src/sandbox-dev/libsandbox.c
new file mode 100644
index 00000000..ffb50359
--- /dev/null
+++ b/src/sandbox-dev/libsandbox.c
@@ -0,0 +1,1214 @@
+/*
+ * Path sandbox for the gentoo linux portage package system, initially
+ * based on the ROCK Linux Wrapper for getting a list of created files
+ *
+ * to integrate with bash, bash should have been built like this
+ *
+ * ./configure --prefix=<prefix> --host=<host> --without-gnu-malloc
+ *
+ * it's very important that the --enable-static-link option is NOT specified
+ *
+ * Copyright (C) 2001 Geert Bevin, Uwyn, http://www.uwyn.com
+ * Distributed under the terms of the GNU General Public License, v2 or later
+ * Author : Geert Bevin <gbevin@uwyn.com>
+ *
+ * Post Bevin leaving Gentoo ranks:
+ * --------------------------------
+ * Ripped out all the wrappers, and implemented those of InstallWatch.
+ * Losts of cleanups and bugfixes. Implement a execve that forces $LIBSANDBOX
+ * in $LD_PRELOAD. Reformat the whole thing to look somewhat like the reworked
+ * sandbox.c from Brad House <brad@mainstreetsoftworks.com>.
+ *
+ * Martin Schlemmer <azarah@gentoo.org> (18 Aug 2002)
+ *
+ * Partly Copyright (C) 1998-9 Pancrazio `Ezio' de Mauro <p@demauro.net>,
+ * as some of the InstallWatch code was used.
+ *
+ *
+ * $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-dev/Attic/libsandbox.c,v 1.4 2002/12/16 22:28:05 jrray Exp $
+ *
+ */
+
+/* Uncomment below to enable wrapping of mknod().
+ * This is broken currently. */
+/* #define WRAP_MKNOD */
+
+
+#define open xxx_open
+#define open64 xxx_open64
+
+/* Wrapping mknod, do not have any effect, and
+ * wrapping __xmknod causes calls to it to segfault
+ */
+#ifdef WRAP_MKNOD
+# define __xmknod xxx___xmknod
+#endif
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <utime.h>
+#include <semaphore.h>
+
+#ifdef WRAP_MKNOD
+# undef __xmknod
+#endif
+
+#undef open
+#undef open64
+
+#include "localdecls.h"
+#include "sandbox.h"
+
+#define PIDS_FILE "/tmp/sandboxpids.tmp"
+
+#define FUNCTION_SANDBOX_SAFE(func, path) \
+ ((0 == is_sandbox_on()) || (1 == before_syscall(func, path)))
+
+#define FUNCTION_SANDBOX_SAFE_INT(func, path, flags) \
+ ((0 == is_sandbox_on()) || (1 == before_syscall_open_int(func, path, flags)))
+
+#define FUNCTION_SANDBOX_SAFE_CHAR(func, path, mode) \
+ ((0 == is_sandbox_on()) || (1 == before_syscall_open_char(func, path, mode)))
+
+
+/* Macro to check if a wrapper is defined, if not
+ * then try to resolve it again. */
+#define check_dlsym(name) \
+{ \
+ int old_errno=errno; \
+ if (!true_ ## name) true_ ## name=get_dlsym(#name); \
+ errno=old_errno; \
+}
+
+static char sandbox_lib[255];
+
+typedef struct {
+ char *last_env;
+ int count;
+ char **strs;
+} sbprefix_t;
+
+typedef struct {
+ int show_access_violation;
+ sbprefix_t deny;
+ sbprefix_t read;
+ sbprefix_t write;
+ sbprefix_t predict;
+} sbcontext_t;
+
+/* glibc modified realpath() functions */
+char *erealpath (const char *name, char *resolved);
+
+static void init_wrappers(void);
+static void *get_dlsym(const char *);
+static void canonicalize(const char *, char *);
+static int check_access(sbcontext_t *, const char *, const char *);
+static int check_syscall(sbcontext_t *, const char *, const char *);
+static int before_syscall(const char *, const char *);
+static int before_syscall_open_int(const char *, const char *, int);
+static int before_syscall_open_char(const char *, const char *, const char *);
+static void clean_env_entries(sbprefix_t *);
+static void init_context(sbcontext_t *);
+static void init_env_entries(sbprefix_t *, char *);
+static char* filter_path(const char*);
+static int is_sandbox_on();
+static int is_sandbox_pid();
+
+/* Wrapped functions */
+
+extern int chmod(const char *, mode_t);
+static int(*true_chmod)(const char *, mode_t);
+extern int chown(const char *, uid_t, gid_t);
+static int(*true_chown)(const char *, uid_t, gid_t);
+extern int creat(const char *, mode_t);
+static int(*true_creat)(const char *, mode_t);
+extern FILE *fopen(const char *,const char*);
+static FILE *(*true_fopen)(const char *,const char*);
+extern int lchown(const char *, uid_t, gid_t);
+static int(*true_lchown)(const char *, uid_t, gid_t);
+extern int link(const char *, const char *);
+static int(*true_link)(const char *, const char *);
+extern int mkdir(const char *, mode_t);
+static int(*true_mkdir)(const char *, mode_t);
+extern DIR *opendir(const char *);
+static DIR *(*true_opendir)(const char *);
+#ifdef WRAP_MKNOD
+extern int __xmknod(const char *, mode_t, dev_t);
+static int(*true___xmknod)(const char *, mode_t, dev_t);
+#endif
+extern int open(const char *, int, ...);
+static int(*true_open)(const char *, int, ...);
+extern int rename(const char *, const char *);
+static int(*true_rename)(const char *, const char *);
+extern int rmdir(const char *);
+static int(*true_rmdir)(const char *);
+extern int symlink(const char *, const char *);
+static int(*true_symlink)(const char *, const char *);
+extern int truncate(const char *, TRUNCATE_T);
+static int(*true_truncate)(const char *, TRUNCATE_T);
+extern int unlink(const char *);
+static int(*true_unlink)(const char *);
+
+#if (GLIBC_MINOR >= 1)
+
+extern int creat64(const char *, __mode_t);
+static int(*true_creat64)(const char *, __mode_t);
+extern FILE *fopen64(const char *,const char *);
+static FILE *(*true_fopen64)(const char *,const char *);
+extern int open64(const char *, int, ...);
+static int(*true_open64)(const char *, int, ...);
+extern int truncate64(const char *, __off64_t);
+static int(*true_truncate64)(const char *, __off64_t);
+
+#endif
+
+extern int execve(const char *filename, char *const argv [], char *const envp[]);
+static int (*true_execve)(const char *, char *const [], char *const []);
+
+static sbcontext_t* sbcontext = NULL;
+static sem_t ctxsem;
+
+/*
+ * Initialize the shabang
+ */
+
+static void init_wrappers(void)
+{
+ void *libc_handle = NULL;
+
+#ifdef BROKEN_RTLD_NEXT
+// printf ("RTLD_LAZY");
+ libc_handle = dlopen(LIBC_VERSION, RTLD_LAZY);
+#else
+// printf ("RTLD_NEXT");
+ libc_handle = RTLD_NEXT;
+#endif
+
+ true_chmod = dlsym(libc_handle, "chmod");
+ true_chown = dlsym(libc_handle, "chown");
+ true_creat = dlsym(libc_handle, "creat");
+ true_fopen = dlsym(libc_handle, "fopen");
+ true_lchown = dlsym(libc_handle, "lchown");
+ true_link = dlsym(libc_handle, "link");
+ true_mkdir = dlsym(libc_handle, "mkdir");
+ true_opendir = dlsym(libc_handle, "opendir");
+#ifdef WRAP_MKNOD
+ true___xmknod = dlsym(libc_handle, "__xmknod");
+#endif
+ true_open = dlsym(libc_handle, "open");
+ true_rename = dlsym(libc_handle, "rename");
+ true_rmdir = dlsym(libc_handle, "rmdir");
+ true_symlink = dlsym(libc_handle, "symlink");
+ true_truncate = dlsym(libc_handle, "truncate");
+ true_unlink = dlsym(libc_handle, "unlink");
+
+#if (GLIBC_MINOR >= 1)
+ true_creat64 = dlsym(libc_handle, "creat64");
+ true_fopen64 = dlsym(libc_handle, "fopen64");
+ true_open64 = dlsym(libc_handle, "open64");
+ true_truncate64 = dlsym(libc_handle, "truncate64");
+#endif
+
+ true_execve = dlsym(libc_handle, "execve");
+}
+
+void _init(void)
+{
+ int old_errno = errno;
+ char *tmp_string = NULL;
+
+ if (sem_init(&ctxsem, 0, 1)) {
+ fprintf(stderr, "Failed to create semaphore\n");
+ abort();
+ }
+
+ init_wrappers();
+
+ /* Get the path and name to this library */
+ tmp_string = get_sandbox_lib("/");
+ strncpy(sandbox_lib, tmp_string, 254);
+
+ if (tmp_string) free(tmp_string);
+ tmp_string = NULL;
+
+ errno = old_errno;
+}
+
+void _fini(void)
+{
+ if (sbcontext) {
+ clean_env_entries(&sbcontext->deny);
+ clean_env_entries(&sbcontext->read);
+ clean_env_entries(&sbcontext->write);
+ clean_env_entries(&sbcontext->predict);
+ free(sbcontext);
+ sbcontext = NULL;
+ }
+
+ /* free the semaphore */
+ sem_destroy(&ctxsem);
+}
+
+static void canonicalize(const char *path, char *resolved_path)
+{
+ int old_errno = errno;
+
+ /* If path == NULL, return or we get a segfault */
+ if (NULL == path) return;
+
+ if(!erealpath(path, resolved_path) && (path[0] != '/')) {
+ /* The path could not be canonicalized, append it
+ * to the current working directory if it was not
+ * an absolute path
+ */
+ getcwd(resolved_path, MAXPATHLEN - 2);
+ strcat(resolved_path, "/");
+ strncat(resolved_path, path, MAXPATHLEN - 1 - strlen(resolved_path));
+ erealpath(resolved_path, resolved_path);
+ }
+
+ errno = old_errno;
+}
+
+static void *get_dlsym(const char *symname)
+{
+ void *libc_handle = NULL;
+ void *symaddr = NULL;
+
+#ifdef BROKEN_RTLD_NEXT
+ libc_handle = dlopen(LIBC_VERSION, RTLD_LAZY);
+ if (!libc_handle) {
+ printf("libsandbox.so: Can't dlopen libc: %s\n", dlerror());
+ abort();
+ }
+#else
+ libc_handle = RTLD_NEXT;
+#endif
+
+ symaddr = dlsym(libc_handle, symname);
+ if (!symaddr) {
+ printf("libsandbox.so: Can't resolve %s: %s\n", symname, dlerror());
+ abort();
+ }
+
+ return symaddr;
+}
+
+/*
+ * Wrapper Functions
+ */
+
+int chmod(const char *path, mode_t mode)
+{
+ int result = -1;
+ char canonic[MAXPATHLEN];
+
+ canonicalize(path, canonic);
+
+ if FUNCTION_SANDBOX_SAFE("chmod", canonic) {
+ check_dlsym(chmod);
+ result = true_chmod(path, mode);
+ }
+
+ return result;
+}
+
+int chown(const char *path, uid_t owner, gid_t group)
+{
+ int result = -1;
+ char canonic[MAXPATHLEN];
+
+ canonicalize(path, canonic);
+
+ if FUNCTION_SANDBOX_SAFE("chown", canonic) {
+ check_dlsym(chown);
+ result = true_chown(path, owner, group);
+ }
+
+ return result;
+}
+
+int creat(const char *pathname, mode_t mode)
+{
+/* Is it a system call? */
+ int result = -1;
+ char canonic[MAXPATHLEN];
+
+ canonicalize(pathname, canonic);
+
+ if FUNCTION_SANDBOX_SAFE("creat", canonic) {
+ check_dlsym(open);
+ result = true_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
+ }
+
+ return result;
+}
+
+FILE *fopen(const char *pathname, const char *mode)
+{
+ FILE *result = NULL;
+ char canonic[MAXPATHLEN];
+
+ canonicalize(pathname, canonic);
+
+ if FUNCTION_SANDBOX_SAFE_CHAR("fopen", canonic, mode) {
+ check_dlsym(fopen);
+ result = true_fopen(pathname,mode);
+ }
+
+ return result;
+}
+
+int lchown(const char *path, uid_t owner, gid_t group)
+{
+/* Linux specific? */
+ int result = -1;
+ char canonic[MAXPATHLEN];
+
+ canonicalize(path, canonic);
+
+ if FUNCTION_SANDBOX_SAFE("lchown", canonic) {
+ check_dlsym(chown);
+ result = true_chown(path, owner, group);
+ }
+
+ return result;
+}
+
+int link(const char *oldpath, const char *newpath)
+{
+ int result = -1;
+ char old_canonic[MAXPATHLEN], new_canonic[MAXPATHLEN];
+
+ canonicalize(oldpath, old_canonic);
+ canonicalize(newpath, new_canonic);
+
+ if FUNCTION_SANDBOX_SAFE("link", new_canonic) {
+ check_dlsym(link);
+ result = true_link(oldpath, newpath);
+ }
+
+ return result;
+}
+
+int mkdir(const char *pathname, mode_t mode)
+{
+ int result = -1;
+ char canonic[MAXPATHLEN];
+
+ canonicalize(pathname, canonic);
+
+ if FUNCTION_SANDBOX_SAFE("mkdir", canonic) {
+ check_dlsym(mkdir);
+ result = true_mkdir(pathname, mode);
+ }
+
+ return result;
+}
+
+DIR *opendir(const char *name)
+{
+ DIR *result = NULL;
+ char canonic[MAXPATHLEN];
+
+ canonicalize(name, canonic);
+
+ if FUNCTION_SANDBOX_SAFE("opendir", canonic) {
+ check_dlsym(opendir);
+ result = true_opendir(name);
+ }
+
+ return result;
+}
+
+#ifdef WRAP_MKNOD
+
+int __xmknod(const char *pathname, mode_t mode, dev_t dev)
+{
+ int result = -1;
+ char canonic[MAXPATHLEN];
+
+ canonicalize(pathname, canonic);
+
+ if FUNCTION_SANDBOX_SAFE("__xmknod", canonic) {
+ check_dlsym(__xmknod);
+ result = true___xmknod(pathname, mode, dev);
+ }
+
+ return result;
+}
+
+#endif
+
+int open(const char *pathname, int flags, ...)
+{
+/* Eventually, there is a third parameter: it's mode_t mode */
+ va_list ap;
+ mode_t mode = 0;
+ int result = -1;
+ char canonic[MAXPATHLEN];
+
+ if (flags & O_CREAT) {
+ va_start(ap, flags);
+ mode = va_arg(ap, mode_t);
+ va_end(ap);
+ }
+
+ canonicalize(pathname, canonic);
+
+ if FUNCTION_SANDBOX_SAFE_INT("open", canonic, flags) {
+ /* We need to resolve open() realtime in some cases,
+ * else we get a segfault when running /bin/ps, etc
+ * in a sandbox */
+ check_dlsym(open);
+ result=true_open(pathname, flags, mode);
+ }
+
+ return result;
+}
+
+int rename(const char *oldpath, const char *newpath)
+{
+ int result = -1;
+ char old_canonic[MAXPATHLEN], new_canonic[MAXPATHLEN];
+
+ canonicalize(oldpath, old_canonic);
+ canonicalize(newpath, new_canonic);
+
+ if FUNCTION_SANDBOX_SAFE("rename", new_canonic) {
+ check_dlsym(rename);
+ result = true_rename(oldpath, newpath);
+ }
+
+ return result;
+}
+
+int rmdir(const char *pathname)
+{
+ int result = -1;
+ char canonic[MAXPATHLEN];
+
+ canonicalize(pathname, canonic);
+
+ if FUNCTION_SANDBOX_SAFE("rmdir", canonic) {
+ check_dlsym(rmdir);
+ result = true_rmdir(pathname);
+ }
+
+ return result;
+}
+
+int symlink(const char *oldpath, const char *newpath)
+{
+ int result = -1;
+ char old_canonic[MAXPATHLEN], new_canonic[MAXPATHLEN];
+
+ canonicalize(oldpath, old_canonic);
+ canonicalize(newpath, new_canonic);
+
+ if FUNCTION_SANDBOX_SAFE("symlink", new_canonic) {
+ check_dlsym(symlink);
+ result = true_symlink(oldpath, newpath);
+ }
+
+ return result;
+}
+
+int truncate(const char *path, TRUNCATE_T length)
+{
+ int result = -1;
+ char canonic[MAXPATHLEN];
+
+ canonicalize(path, canonic);
+
+ if FUNCTION_SANDBOX_SAFE("truncate", canonic) {
+ check_dlsym(truncate);
+ result = true_truncate(path, length);
+ }
+
+ return result;
+}
+
+int unlink(const char *pathname)
+{
+ int result = -1;
+ char canonic[MAXPATHLEN];
+
+ canonicalize(pathname, canonic);
+
+ if FUNCTION_SANDBOX_SAFE("unlink", canonic) {
+ check_dlsym(unlink);
+ result = true_unlink(pathname);
+ }
+
+ return result;
+}
+
+#if (GLIBC_MINOR >= 1)
+
+int creat64(const char *pathname, __mode_t mode)
+{
+/* Is it a system call? */
+ int result = -1;
+ char canonic[MAXPATHLEN];
+
+ canonicalize(pathname, canonic);
+
+ if FUNCTION_SANDBOX_SAFE("creat64", canonic) {
+ check_dlsym(open64);
+ result = true_open64(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
+ }
+
+ return result;
+}
+
+FILE *fopen64(const char *pathname, const char *mode)
+{
+ FILE *result = NULL;
+ char canonic[MAXPATHLEN];
+
+ canonicalize(pathname, canonic);
+
+ if FUNCTION_SANDBOX_SAFE_CHAR("fopen64", canonic, mode) {
+ check_dlsym(fopen64);
+ result = true_fopen(pathname,mode);
+ }
+
+ return result;
+}
+
+int open64(const char *pathname, int flags, ...)
+{
+/* Eventually, there is a third parameter: it's mode_t mode */
+ va_list ap;
+ mode_t mode = 0;
+ int result = -1;
+ char canonic[MAXPATHLEN];
+
+ if (flags & O_CREAT) {
+ va_start(ap, flags);
+ mode = va_arg(ap, mode_t);
+ va_end(ap);
+ }
+
+ canonicalize(pathname, canonic);
+
+ if FUNCTION_SANDBOX_SAFE_INT("open64", canonic, flags) {
+ check_dlsym(open64);
+ result=true_open64(pathname, flags, mode);
+ }
+
+ return result;
+}
+
+int truncate64(const char *path, __off64_t length)
+{
+ int result = -1;
+ char canonic[MAXPATHLEN];
+
+ canonicalize(path, canonic);
+
+ if FUNCTION_SANDBOX_SAFE("truncate64", canonic) {
+ check_dlsym(truncate64);
+ result = true_truncate64(path, length);
+ }
+
+ return result;
+}
+
+#endif /* GLIBC_MINOR >= 1 */
+
+/*
+ * Exec Wrappers
+ */
+
+int execve(const char *filename, char *const argv [], char *const envp[])
+{
+ int old_errno = errno;
+ int result = -1;
+ int count = 0;
+ char canonic[MAXPATHLEN];
+ char *old_envp = NULL;
+ char *new_envp = NULL;
+
+ canonicalize(filename, canonic);
+
+ if FUNCTION_SANDBOX_SAFE("execve", canonic) {
+ while (envp[count] != NULL) {
+ if (strstr(envp[count], "LD_PRELOAD=") == envp[count]) {
+ if (NULL != strstr(envp[count], sandbox_lib)) {
+ break;
+ } else {
+ const int max_envp_len = strlen(envp[count]) + strlen(sandbox_lib) + 1;
+
+ /* Backup envp[count], and set it to our own one which
+ * contains sandbox_lib */
+ old_envp = envp[count];
+ new_envp = strndupa(old_envp, max_envp_len - 1);
+
+ /* LD_PRELOAD already have variables other than sandbox_lib,
+ * thus we have to add sandbox_lib via a white space. */
+ if (0 != strcmp(envp[count], "LD_PRELOAD=")) {
+ strncpy(new_envp + strlen(old_envp), ":",
+ max_envp_len - strlen(new_envp));
+ strncpy(new_envp + strlen(old_envp) + 1, sandbox_lib,
+ max_envp_len - strlen(new_envp));
+ } else {
+ strncpy(new_envp + strlen(old_envp), sandbox_lib,
+ max_envp_len - strlen(new_envp));
+ }
+
+ /* Valid string? */
+ new_envp[max_envp_len] = '\0';
+
+ /* envp[count] = new_envp;
+ *
+ * Get rid of the "read-only" warnings */
+ memcpy((void *)&envp[count], &new_envp, sizeof(new_envp));
+
+ break;
+ }
+ }
+ count++;
+ }
+
+ errno = old_errno;
+ check_dlsym(execve);
+ result = true_execve(filename, argv, envp);
+ old_errno = errno;
+
+ if (old_envp) {
+ /* Restore envp[count] again.
+ *
+ * envp[count] = old_envp; */
+ memcpy((void *)&envp[count], &old_envp, sizeof(old_envp));
+ old_envp = NULL;
+ }
+ }
+
+ errno = old_errno;
+
+ return result;
+}
+
+/*
+ * Internal Functions
+ */
+
+#if (GLIBC_MINOR == 1)
+
+/* This hack is needed for glibc 2.1.1 (and others?)
+ * (not really needed, but good example) */
+extern int fclose(FILE *);
+static int (*true_fclose)(FILE *) = NULL;
+int fclose(FILE *file)
+{
+ int result = - 1;
+
+ check_dlsym(fclose);
+ result = true_fclose(file);
+
+ return result;
+}
+
+#endif /* GLIBC_MINOR == 1 */
+
+static void init_context(sbcontext_t* context)
+{
+ memset(context, 0, sizeof(sbcontext_t));
+ context->show_access_violation = 1;
+}
+
+static int is_sandbox_pid()
+{
+ int old_errno = errno;
+ int result = 0;
+ FILE* pids_stream = NULL;
+ int pids_file = -1;
+ int current_pid = 0;
+ int tmp_pid = 0;
+
+ init_wrappers();
+
+ pids_stream = true_fopen(PIDS_FILE, "r");
+
+ if (NULL == pids_stream) {
+ perror(">>> pids file fopen");
+ }
+ else
+ {
+ pids_file = fileno(pids_stream);
+
+ if (pids_file < 0) {
+ perror(">>> pids file fileno");
+ } else {
+ current_pid = getpid();
+
+ while (EOF != fscanf(pids_stream, "%d\n", &tmp_pid)) {
+ if (tmp_pid == current_pid) {
+ result = 1;
+ break;
+ }
+ }
+ }
+ if (EOF == fclose(pids_stream)) {
+ perror(">>> pids file fclose");
+ }
+ pids_stream = NULL;
+ pids_file = -1;
+ }
+
+ errno = old_errno;
+
+ return result;
+}
+
+static void clean_env_entries(sbprefix_t* prefix)
+{
+ int old_errno = errno;
+ int i = 0;
+
+ if (NULL != prefix->strs) {
+ for (i = 0; i < prefix->count; i++) {
+ if (NULL != prefix->strs[i]) {
+ free(prefix->strs[i]);
+ prefix->strs[i] = NULL;
+ }
+ }
+ free(prefix->strs);
+ prefix->strs = NULL;
+ prefix->count = 0;
+ }
+ if (prefix->last_env) {
+ free(prefix->last_env);
+ prefix->last_env = NULL;
+ }
+
+ errno = old_errno;
+}
+
+static void init_env_entries(sbprefix_t* prefix, char* env)
+{
+ int old_errno = errno;
+ char* prefixes_env = getenv(env);
+
+ if (NULL == prefixes_env) {
+ fprintf(stderr,
+ "Sandbox error : the %s environmental variable should be defined.\n",
+ env);
+ } else {
+ char *ptr;
+ int num_colons = 0;
+
+ /* Check to see if the env value has changed since the
+ last time this was initalized, don't do the work again
+ if it hasn't.
+ */
+
+ if (prefix->last_env && !strcmp(prefix->last_env, prefixes_env)) {
+ errno = old_errno;
+ return;
+ }
+
+ /* Clean any existing entries */
+ clean_env_entries(prefix);
+
+ /* Env value is different, update the cached copy */
+ prefix->last_env = strdup(prefixes_env);
+
+ ptr = prefixes_env;
+ while (*ptr) {
+ if (*ptr++ == ':') ++num_colons;
+ }
+
+ if (prefix->strs) {
+ free(prefix->strs);
+ prefix->strs = 0;
+ }
+ prefix->strs = (char**)malloc((num_colons+1) * sizeof(char*));
+ if (!prefix->strs) return;
+ memset(prefix->strs, 0, (num_colons+1) * sizeof(char*));
+ prefix->count = 0;
+
+ ptr = prefixes_env;
+ while (*ptr) {
+ char *next_colon = strchr(ptr, ':');
+ if (next_colon) {
+ if (next_colon != ptr) {
+ char *str = strndup(ptr, next_colon-ptr);
+ if (!str) return;
+ prefix->strs[prefix->count++] = filter_path(str);
+ free(str);
+ }
+ } else {
+ prefix->strs[prefix->count++] = filter_path(ptr);
+ break;
+ }
+
+ ptr = next_colon+1;
+ }
+ }
+ errno = old_errno;
+}
+
+static char* filter_path(const char* path)
+{
+ int old_errno = errno;
+ char* filtered_path = (char *)malloc(MAXPATHLEN * sizeof(char));
+ filtered_path[0] = 0;
+
+ canonicalize(path, filtered_path);
+
+ errno = old_errno;
+
+ return filtered_path;
+}
+
+static int check_access(sbcontext_t* sbcontext, const char* func, const char* path)
+{
+ int old_errno = errno;
+ int result = -1;
+ int i = 0;
+ char* filtered_path = filter_path(path);
+
+ if (!filtered_path) {
+ errno = old_errno;
+ return 0;
+ }
+
+ if ('/' != filtered_path[0]) {
+ free(filtered_path);
+ errno = old_errno;
+ return 0;
+ }
+
+ if ((0 == strncmp(filtered_path, "/etc/ld.so.preload", 18)) && (is_sandbox_pid())) {
+ result = 1;
+ }
+
+ if (-1 == result) {
+ if (NULL != sbcontext->deny.strs) {
+ for (i = 0; i < sbcontext->deny.count; i++) {
+ if (NULL != sbcontext->deny.strs[i]) {
+ if (0 == strncmp(filtered_path,
+ sbcontext->deny.strs[i],
+ strlen(sbcontext->deny.strs[i]))) {
+ result = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ if (-1 == result) {
+ if ((NULL != sbcontext->read.strs) &&
+ ((0 == strncmp(func, "open_rd", 7)) ||
+ (0 == strncmp(func, "popen", 5)) ||
+ (0 == strncmp(func, "opendir", 7)) ||
+ (0 == strncmp(func, "system", 6)) ||
+ (0 == strncmp(func, "execl", 5)) ||
+ (0 == strncmp(func, "execlp", 6)) ||
+ (0 == strncmp(func, "execle", 6)) ||
+ (0 == strncmp(func, "execv", 5)) ||
+ (0 == strncmp(func, "execvp", 6)) ||
+ (0 == strncmp(func, "execve", 6))
+ )
+ ) {
+ for (i = 0; i < sbcontext->read.count; i++) {
+ if (NULL != sbcontext->read.strs[i]) {
+ if (0 == strncmp(filtered_path,
+ sbcontext->read.strs[i],
+ strlen(sbcontext->read.strs[i]))) {
+ result = 1;
+ break;
+ }
+ }
+ }
+ }
+ else if ((NULL != sbcontext->write.strs) &&
+ ((0 == strncmp(func, "open_wr", 7)) ||
+ (0 == strncmp(func, "creat", 5)) ||
+ (0 == strncmp(func, "creat64", 7)) ||
+ (0 == strncmp(func, "mkdir", 5)) ||
+ (0 == strncmp(func, "mknod", 5)) ||
+ (0 == strncmp(func, "mkfifo", 6)) ||
+ (0 == strncmp(func, "link", 4)) ||
+ (0 == strncmp(func, "symlink", 7)) ||
+ (0 == strncmp(func, "rename", 6)) ||
+ (0 == strncmp(func, "utime", 5)) ||
+ (0 == strncmp(func, "utimes", 6)) ||
+ (0 == strncmp(func, "unlink", 6)) ||
+ (0 == strncmp(func, "rmdir", 5)) ||
+ (0 == strncmp(func, "chown", 5)) ||
+ (0 == strncmp(func, "lchown", 6)) ||
+ (0 == strncmp(func, "chmod", 5)) ||
+ (0 == strncmp(func, "truncate", 8)) ||
+ (0 == strncmp(func, "ftruncate", 9)) ||
+ (0 == strncmp(func, "truncate64", 10)) ||
+ (0 == strncmp(func, "ftruncate64", 11))
+ )
+ ) {
+ struct stat tmp_stat;
+
+#if 0 // write_denied is never set
+
+ for (i = 0; i < sbcontext->write_denied.count; i++) {
+ if (NULL != sbcontext->write_denied.strs[i]) {
+ if (0 == strncmp(filtered_path,
+ sbcontext->write_denied.strs[i],
+ strlen(sbcontext->write_denied.strs[i]))) {
+ result = 0;
+ break;
+ }
+ }
+ }
+#endif
+
+ if (-1 == result) {
+ for (i = 0; i < sbcontext->write.count; i++) {
+ if (NULL != sbcontext->write.strs[i]) {
+ if (0 == strncmp(filtered_path,
+ sbcontext->write.strs[i],
+ strlen(sbcontext->write.strs[i]))) {
+ result = 1;
+ break;
+ }
+ }
+ }
+
+ if (-1 == result) {
+ /* hack to prevent mkdir of existing dirs to show errors */
+ if (0 == strncmp(func, "mkdir", 5)) {
+ if (0 == stat(filtered_path, &tmp_stat)) {
+ sbcontext->show_access_violation = 0;
+ result = 0;
+ }
+ }
+
+ if (-1 == result) {
+ for (i = 0; i < sbcontext->predict.count; i++) {
+ if (NULL != sbcontext->predict.strs[i]) {
+ if (0 == strncmp(filtered_path,
+ sbcontext->predict.strs[i],
+ strlen(sbcontext->predict.strs[i]))) {
+ sbcontext->show_access_violation = 0;
+ result = 0;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (-1 == result) {
+ result = 0;
+ }
+
+ if (filtered_path) free(filtered_path);
+ filtered_path = NULL;
+
+ errno = old_errno;
+
+ return result;
+}
+
+static int check_syscall(sbcontext_t* sbcontext, const char* func, const char* file)
+{
+ int old_errno = errno;
+ int result = 1;
+ struct stat log_stat;
+ char* log_path = NULL;
+ char* absolute_path = NULL;
+ char* tmp_buffer = NULL;
+ int log_file = 0;
+ struct stat debug_log_stat;
+ char* debug_log_env = NULL;
+ char* debug_log_path = NULL;
+ int debug_log_file = 0;
+ char buffer[512];
+
+ init_wrappers();
+
+ if ('/' == file[0]) {
+ absolute_path = (char *)malloc((strlen(file) + 1) * sizeof(char));
+ sprintf(absolute_path, "%s", file);
+ } else {
+ tmp_buffer = get_current_dir_name();
+ absolute_path = (char *)malloc((strlen(tmp_buffer) + 1 + strlen(file) + 1) * sizeof(char));
+ sprintf(absolute_path,"%s/%s", tmp_buffer, file);
+
+ if (tmp_buffer) free(tmp_buffer);
+ tmp_buffer = NULL;
+ }
+
+ log_path = getenv("SANDBOX_LOG");
+ debug_log_env = getenv("SANDBOX_DEBUG");
+ debug_log_path = getenv("SANDBOX_DEBUG_LOG");
+
+ if (((NULL == log_path) ||
+ (0 != strncmp(absolute_path, log_path, strlen(log_path)))) &&
+ ((NULL == debug_log_env) ||
+ (NULL == debug_log_path) ||
+ (0 != strncmp(absolute_path, debug_log_path, strlen(debug_log_path)))) &&
+ (0 == check_access(sbcontext, func, absolute_path))
+ ) {
+ if (1 == sbcontext->show_access_violation) {
+ fprintf(stderr, "\e[31;01mACCESS DENIED\033[0m %s:%*s%s\n",
+ func, (int)(10 - strlen(func)), "", absolute_path);
+
+ if (NULL != log_path) {
+ sprintf(buffer, "%s:%*s%s\n", func, (int)(10 - strlen(func)), "", absolute_path);
+
+ if ((0 == lstat(log_path, &log_stat)) &&
+ (0 == S_ISREG(log_stat.st_mode))
+ ) {
+ fprintf(stderr,
+ "\e[31;01mSECURITY BREACH\033[0m %s already exists and is not a regular file.\n",
+ log_path);
+ } else {
+ log_file = true_open(log_path,
+ O_APPEND | O_WRONLY | O_CREAT,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if(log_file >= 0) {
+ write(log_file, buffer, strlen(buffer));
+ close(log_file);
+ }
+ }
+ }
+ }
+
+ result = 0;
+ }
+ else if (NULL != debug_log_env) {
+ if (NULL != debug_log_path) {
+ if (0 != strncmp(absolute_path, debug_log_path, strlen(debug_log_path))) {
+ sprintf(buffer, "%s:%*s%s\n", func, (int)(10 - strlen(func)), "", absolute_path);
+
+ if ((0 == lstat(debug_log_path, &debug_log_stat)) &&
+ (0 == S_ISREG(debug_log_stat.st_mode))
+ ) {
+ fprintf(stderr,
+ "\e[31;01mSECURITY BREACH\033[0m %s already exists and is not a regular file.\n",
+ log_path);
+ } else {
+ debug_log_file = true_open(debug_log_path,
+ O_APPEND | O_WRONLY | O_CREAT,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if(debug_log_file >= 0) {
+ write(debug_log_file, buffer, strlen(buffer));
+ close(debug_log_file);
+ }
+ }
+ }
+ } else {
+ fprintf(stderr, "\e[32;01mACCESS ALLOWED\033[0m %s:%*s%s\n",
+ func, (int)(10 - strlen(func)), "", absolute_path);
+ }
+ }
+
+ if (absolute_path) free(absolute_path);
+ absolute_path = NULL;
+
+ errno = old_errno;
+
+ return result;
+}
+
+static int is_sandbox_on()
+{
+ int old_errno = errno;
+
+ /* $SANDBOX_ACTIVE is an env variable that should ONLY
+ * be used internal by sandbox.c and libsanbox.c. External
+ * sources should NEVER set it, else the sandbox is enabled
+ * in some cases when run in parallel with another sandbox,
+ * but not even in the sandbox shell.
+ *
+ * Azarah (3 Aug 2002)
+ */
+ if ((NULL != getenv("SANDBOX_ON")) &&
+ (0 == strncmp(getenv("SANDBOX_ON"), "1", 1)) &&
+ (NULL != getenv("SANDBOX_ACTIVE")) &&
+ (0 == strncmp(getenv("SANDBOX_ACTIVE"), "armedandready", 13))
+ ) {
+ errno = old_errno;
+
+ return 1;
+ } else {
+ errno = old_errno;
+
+ return 0;
+ }
+}
+
+static int before_syscall(const char* func, const char* file)
+{
+ int old_errno = errno;
+ int result = 1;
+
+ /* Only allow one thread to access sbcontext at a time */
+ sem_wait(&ctxsem);
+
+ if (!sbcontext) {
+ sbcontext = (sbcontext_t*)malloc(sizeof(sbcontext_t));
+ init_context(sbcontext);
+ } else {
+ /* sometimes this value gets set to 0 */
+ sbcontext->show_access_violation = 1;
+ }
+
+ init_env_entries(&sbcontext->deny, "SANDBOX_DENY");
+ init_env_entries(&sbcontext->read, "SANDBOX_READ");
+ init_env_entries(&sbcontext->write, "SANDBOX_WRITE");
+ init_env_entries(&sbcontext->predict, "SANDBOX_PREDICT");
+
+ result = check_syscall(sbcontext, func, file);
+
+ if (sem_post(&ctxsem)) {
+ fprintf(stderr, "Failed trying to release semaphore\n");
+ }
+
+ errno = old_errno;
+
+ if (0 == result) {
+ errno = EACCES;
+ }
+
+ return result;
+}
+
+static int before_syscall_open_int(const char* func, const char* file, int flags)
+{
+ if ((flags & O_WRONLY) || (flags & O_RDWR)) {
+ return before_syscall("open_wr", file);
+ } else {
+ return before_syscall("open_rd", file);
+ }
+}
+
+static int before_syscall_open_char(const char* func, const char* file, const char* mode)
+{
+ if ((strcmp(mode, "r") == 0) || (strcmp(mode, "rb") == 0)) {
+ return before_syscall("open_rd", file);
+ } else {
+ return before_syscall("open_wr", file);
+ }
+}
+
+
+// vim:expandtab noai:cindent ai
diff --git a/src/sandbox-dev/sandbox.bashrc b/src/sandbox-dev/sandbox.bashrc
new file mode 100644
index 00000000..35fa89b6
--- /dev/null
+++ b/src/sandbox-dev/sandbox.bashrc
@@ -0,0 +1,8 @@
+# Copyright (C) 2001 Geert Bevin, Uwyn, http://www.uwyn.com
+# Distributed under the terms of the GNU General Public License, v2 or later
+# Author : Geert Bevin <gbevin@uwyn.com>
+# $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-dev/Attic/sandbox.bashrc,v 1.1 2002/08/25 06:09:05 azarah Exp $
+source /etc/profile
+export LD_PRELOAD="$SANDBOX_LIB"
+alias make="make LD_PRELOAD=$SANDBOX_LIB"
+alias su="su -c '/bin/bash -rcfile $SANDBOX_DIR/sandbox.bashrc'"
diff --git a/src/sandbox-dev/sandbox.c b/src/sandbox-dev/sandbox.c
new file mode 100644
index 00000000..7dccf62b
--- /dev/null
+++ b/src/sandbox-dev/sandbox.c
@@ -0,0 +1,816 @@
+/*
+** Path sandbox for the gentoo linux portage package system, initially
+** based on the ROCK Linux Wrapper for getting a list of created files
+**
+** to integrate with bash, bash should have been built like this
+**
+** ./configure --prefix=<prefix> --host=<host> --without-gnu-malloc
+**
+** it's very important that the --enable-static-link option is NOT specified
+**
+** Copyright (C) 2001 Geert Bevin, Uwyn, http://www.uwyn.com
+** Distributed under the terms of the GNU General Public License, v2 or later
+** Author : Geert Bevin <gbevin@uwyn.com>
+** $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-dev/Attic/sandbox.c,v 1.4 2002/10/20 21:37:30 azarah Exp $
+*/
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "sandbox.h"
+
+int preload_adaptable = 1;
+int cleaned_up = 0;
+int print_debug = 0;
+
+/* Read pids file, and load active pids into an array. Return number of pids in array */
+int load_active_pids(int fd, int **pids)
+{
+ char *data = NULL;
+ char *ptr = NULL, *ptr2 = NULL;
+ int my_pid;
+ int num_pids = 0;
+ long len;
+
+ pids[0] = NULL;
+
+ len = file_length(fd);
+
+ /* Allocate and zero datablock to read pids file */
+ data = (char *)malloc((len + 1)*sizeof(char));
+ memset(data, 0, len + 1);
+
+ /* Start at beginning of file */
+ lseek(fd, 0L, SEEK_SET);
+
+ /* read entire file into a buffer */
+ read(fd, data, len);
+
+ ptr = data;
+
+ /* Loop and read all pids */
+ while (1) {
+ /* Find new line */
+ ptr2 = strchr(ptr, '\n');
+ if (ptr2 == NULL) break; /* No more PIDs */
+
+ /* clear the \n. And ptr should have a null-terminated decimal string */
+ ptr2[0] = 0;
+
+ my_pid = atoi(ptr);
+
+ /* If the PID is still alive, add it to our array */
+ if ((0 != my_pid) && (0 == kill(my_pid, 0))) {
+ pids[0] = (int *)realloc(pids[0], (num_pids + 1)*sizeof(int));
+ pids[0][num_pids] = my_pid;
+ num_pids++;
+ }
+
+ /* Put ptr past the NULL we just wrote */
+ ptr = ptr2 + 1;
+ }
+
+ if (data) free(data);
+
+ return num_pids;
+}
+
+/* Read ld.so.preload file, and loads dirs into an array. Return number of entries in array */
+int load_preload_libs(int fd, char ***preloads)
+{
+ char *data = NULL;
+ char *ptr = NULL, *ptr2 = NULL;
+ int num_entries = 0;
+ long len;
+
+ preloads[0] = NULL;
+
+ len = file_length(fd);
+
+ /* Allocate and zero datablock to read pids file */
+ data = (char *)malloc((len + 1)*sizeof(char));
+ memset(data, 0, len + 1);
+
+ /* Start at beginning of file */
+ lseek(fd, 0L, SEEK_SET);
+
+ /* read entire file into a buffer */
+ read(fd, data, len);
+
+ ptr = data;
+
+ /* Loop and read all pids */
+ while (1) {
+ /* Find new line */
+ ptr2 = strchr(ptr, '\n');
+
+ /* clear the \n. And ptr should have a null-terminated decimal string
+ * Don't break from the loop though because the last line may not
+ * terminated with a \n
+ */
+ if (NULL != ptr2) ptr2[0] = 0;
+
+ /* If listing does not match our libname, add it to the array */
+ if ((strlen(ptr)) && (NULL == strstr(ptr, LIB_NAME))) {
+ preloads[0] = (char **)realloc(preloads[0], (num_entries + 1)*sizeof(char **));
+ preloads[0][num_entries] = strdup(ptr);
+ num_entries++;
+ }
+
+ if (NULL == ptr2) break; /* No more PIDs */
+
+ /* Put ptr past the NULL we just wrote */
+ ptr = ptr2 + 1;
+ }
+
+ if (data) free(data);
+
+ return num_entries;
+}
+
+
+void cleanup()
+{
+ int i = 0;
+ int success = 1;
+ int pids_file = -1, num_of_pids = 0;
+ int *pids_array = NULL;
+ char pid_string[255];
+#ifdef USE_LD_SO_PRELOAD
+ int preload_file = -1, num_of_preloads = 0;
+ char preload_entry[255];
+ char **preload_array = NULL;
+#endif
+
+
+ /* remove this sandbox's bash pid from the global pids
+ * file if it has rights to adapt the ld.so.preload file */
+ if ((1 == preload_adaptable) && (0 == cleaned_up)) {
+ cleaned_up = 1;
+ success = 1;
+
+ if (print_debug) printf("Cleaning up pids file.\n");
+
+ /* Stat the PIDs file, make sure it exists and is a regular file */
+ if (file_exist(PIDS_FILE, 1) <= 0) {
+ perror(">>> pids file is not a regular file");
+ success = 0;
+ /* We should really not fail if the pidsfile is missing here, but
+ * rather just exit cleanly, as there is still some cleanup to do */
+ return;
+ }
+
+ pids_file = file_open(PIDS_FILE, "r+", 0);
+ if (-1 == pids_file) {
+ success = 0;
+ /* Nothing more to do here */
+ return;
+ }
+
+ /* Load "still active" pids into an array */
+ num_of_pids = load_active_pids(pids_file, &pids_array);
+ //printf("pids: %d\r\n", num_of_pids);
+
+#ifdef USE_LD_SO_PRELOAD
+ /* clean the /etc/ld.so.preload file if no other sandbox
+ * processes are running anymore */
+ if (1 == num_of_pids) {
+ success = 1;
+
+ if (print_debug) printf("Cleaning up /etc/ld.so.preload.\n");
+
+ preload_file = file_open("/etc/ld.so.preload", "r+", 0);
+ if (-1 != preload_file) {
+ /* Load all the preload libraries into an array */
+ num_of_preloads = load_preload_libs(preload_file, &preload_array);
+ //printf("num preloads: %d\r\n", num_of_preloads);
+ /* Clear file */
+ file_truncate(preload_file);
+
+ /* store the other preload libraries back into the /etc/ld.so.preload file */
+ if(num_of_preloads > 0) {
+ for (i = 0; i < num_of_preloads; i++) {
+ sprintf(preload_entry, "%s\n", preload_array[i]);
+ if (write(preload_file, preload_entry, strlen(preload_entry)) != strlen(preload_entry)) {
+ perror(">>> /etc/ld.so.preload file write");
+ success = 0;
+ break;
+ }
+ }
+ }
+
+ /* Free memory used to store preload array */
+ for (i = 0; i < num_of_preloads; i++) {
+ if (preload_array[i]) free(preload_array[i]);
+ preload_array[i] = NULL;
+ }
+ if (preload_array) free(preload_array);
+ preload_array = NULL;
+
+ file_close(preload_file);
+ preload_file = -1;
+ }
+ }
+#endif
+
+ file_truncate(pids_file);
+
+ /* if pids are still running, write only the running pids back to the file */
+ if(num_of_pids > 1) {
+ for (i = 0; i < num_of_pids; i++) {
+ sprintf(pid_string, "%d\n", pids_array[i]);
+ if (write(pids_file, pid_string, strlen(pid_string)) != strlen(pid_string)) {
+ perror(">>> pids file write");
+ success = 0;
+ break;
+ }
+ }
+
+ file_close(pids_file);
+ pids_file = -1;
+ } else {
+
+ file_close(pids_file);
+ pids_file = -1;
+
+ /* remove the pidsfile, as this was the last sandbox */
+ unlink(PIDS_FILE);
+ }
+
+ if (pids_array != NULL) {
+ free(pids_array);
+ pids_array = NULL;
+ }
+ }
+
+ if (0 == success) {
+ return;
+ }
+}
+
+void stop(int signum)
+{
+ printf("Caught signal %d\r\n", signum);
+ cleanup();
+}
+
+void setenv_sandbox_write(char *home_dir, char *portage_tmp_dir, char *var_tmp_dir, char *tmp_dir)
+{
+ char sandbox_write_var[1024];
+
+ if (!getenv(ENV_SANDBOX_WRITE)) {
+ /* these should go into make.globals later on */
+ strcpy(sandbox_write_var, "");
+ strcat(sandbox_write_var, "/dev/zero:/dev/fd/:/dev/null:/dev/pts/:/dev/vc/:/dev/tty:/tmp/");
+ strcat(sandbox_write_var, ":");
+ /* NGPT support */
+ strcat(sandbox_write_var, "/dev/shm/ngpt");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/var/log/scrollkeeper.log");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, home_dir);
+ strcat(sandbox_write_var, "/.gconfd/lock");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, home_dir);
+ strcat(sandbox_write_var, "/.bash_history");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/usr/tmp/conftest");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/usr/lib/conftest");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/usr/tmp/cf");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/usr/lib/cf");
+ strcat(sandbox_write_var, ":");
+ if (NULL == portage_tmp_dir) {
+ strcat(sandbox_write_var, tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, var_tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/tmp/");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/var/tmp/");
+
+ /* How the heck is this possible?? we just set it above! */
+ } else if (0 == strcmp(sandbox_write_var, "/var/tmp/")) {
+ strcat(sandbox_write_var, portage_tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/tmp/");
+
+ /* Still don't think this is possible, am I just stupid or something? */
+ } else if (0 == strcmp(sandbox_write_var, "/tmp/")) {
+ strcat(sandbox_write_var, portage_tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, var_tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/var/tmp/");
+
+ /* Amazing, one I think is possible */
+ } else {
+ strcat(sandbox_write_var, portage_tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, var_tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/tmp/");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/var/tmp/");
+ }
+
+ setenv(ENV_SANDBOX_WRITE, sandbox_write_var, 1);
+ }
+}
+
+
+void setenv_sandbox_predict(char *home_dir)
+{
+ char sandbox_predict_var[1024];
+
+ if (!getenv(ENV_SANDBOX_PREDICT)) {
+ /* these should go into make.globals later on */
+ strcpy(sandbox_predict_var, "");
+ strcat(sandbox_predict_var, home_dir);
+ strcat(sandbox_predict_var, "/.");
+ strcat(sandbox_predict_var, ":");
+ strcat(sandbox_predict_var, "/usr/lib/python2.0/");
+ strcat(sandbox_predict_var, ":");
+ strcat(sandbox_predict_var, "/usr/lib/python2.1/");
+ strcat(sandbox_predict_var, ":");
+ strcat(sandbox_predict_var, "/usr/lib/python2.2/");
+ setenv(ENV_SANDBOX_PREDICT, sandbox_predict_var, 1);
+ }
+}
+
+int print_sandbox_log(char *sandbox_log)
+{
+ int sandbox_log_file = -1;
+ char *beep_count_env = NULL;
+ int i, beep_count = 0;
+ long len = 0;
+ char *buffer = NULL;
+
+ sandbox_log_file=file_open(sandbox_log, "r", 0);
+ if (-1 == sandbox_log_file) {
+ return 0;
+ }
+
+ len = file_length(sandbox_log_file);
+ buffer = (char *)malloc((len + 1)*sizeof(char));
+ memset(buffer, 0, len + 1);
+ read(sandbox_log_file, buffer, len);
+ file_close(sandbox_log_file);
+
+ printf("\e[31;01m--------------------------- ACCESS VIOLATION SUMMARY ---------------------------\033[0m\n");
+ printf("\e[31;01mLOG FILE = \"%s\"\033[0m\n", sandbox_log);
+ printf("\n");
+ printf("%s", buffer);
+ if (buffer) free(buffer); buffer = NULL;
+ printf("\e[31;01m--------------------------------------------------------------------------------\033[0m\n");
+
+ beep_count_env = getenv(ENV_SANDBOX_BEEP);
+ if (beep_count_env) {
+ beep_count = atoi(beep_count_env);
+ } else {
+ beep_count = DEFAULT_BEEP_COUNT;
+ }
+
+ for (i = 0; i < beep_count; i++) {
+ fputc('\a', stderr);
+ if (i < beep_count -1) {
+ sleep(1);
+ }
+ }
+ return 1;
+}
+
+int spawn_shell(char *argv_bash[])
+{
+#ifdef USE_SYSTEM_SHELL
+ int i = 0;
+ char *sh = NULL;
+ int first = 1;
+ int ret;
+ long len = 0;
+
+ while (1) {
+ if (NULL == argv_bash[i]) break;
+ if (NULL != sh) len = strlen(sh);
+ sh = (char *)realloc(sh, len+strlen(argv_bash[i]) + 5);
+ if (first) {
+ sh[0] = 0;
+ first = 0;
+ }
+ strcat(sh, "\"");
+ strcat(sh, argv_bash[i]);
+ strcat(sh, "\" ");
+
+ //printf("%s\n", argv_bash[i]);
+ i++;
+ }
+ printf("%s\n", sh);
+ ret = system(sh);
+ if (sh) free(sh);
+ sh = NULL;
+
+ if (-1 == ret) return 0;
+ return 1;
+
+#else
+# ifndef NO_FORK
+ int pid;
+ int status = 0;
+ int ret = 0;
+
+ pid = fork();
+
+ /* Child's process */
+ if (0 == pid) {
+# endif
+ execv(argv_bash[0], argv_bash);
+# ifndef NO_FORK
+ return 0;
+ } else if (pid < 0) {
+ return 0;
+ }
+ ret = waitpid(pid, &status, 0);
+ if ((-1 == ret) || (status > 0)) return 0;
+# endif
+ return 1;
+#endif
+}
+
+int main(int argc, char** argv)
+{
+ int i = 0, success = 1;
+ int preload_file = -1;
+ int sandbox_log_presence = 0;
+ int sandbox_log_file = -1;
+ int pids_file = -1;
+ long len;
+
+ int *pids_array = NULL;
+ int num_of_pids = 0;
+
+ // char run_arg[255];
+ char portage_tmp_dir[PATH_MAX];
+ char var_tmp_dir[PATH_MAX];
+ char tmp_dir[PATH_MAX];
+ char sandbox_log[255];
+ char sandbox_debug_log[255];
+ char sandbox_dir[255];
+ char sandbox_lib[255];
+ char sandbox_rc[255];
+ char pid_string[255];
+ char **argv_bash = NULL;
+
+ char *run_str = "-c";
+ char *home_dir = NULL;
+ char *tmp_string = NULL;
+#ifdef USE_LD_SO_PRELOAD
+ char **preload_array = NULL;
+ int num_of_preloads = 0;
+#endif
+
+ /* Only print info if called with no arguments .... */
+ if (argc < 2) {
+ print_debug = 1;
+ }
+
+ if (print_debug) printf("========================== Gentoo linux path sandbox ===========================\n");
+
+
+ /* check if a sandbox is already running */
+ if (NULL != getenv(ENV_SANDBOX_ON)) {
+ fprintf(stderr, "Not launching a new sandbox instance\nAnother one is already running in this process hierarchy.\n");
+ exit(1);
+ } else {
+
+ /* determine the location of all the sandbox support files */
+ if (print_debug) printf("Detection of the support files.\n");
+
+ /* Generate base sandbox path */
+ tmp_string = get_sandbox_path(argv[0]);
+ strncpy(sandbox_dir, tmp_string, 254);
+ if (tmp_string) free(tmp_string);
+ tmp_string = NULL;
+ strcat(sandbox_dir, "/");
+
+ /* Generate sandbox lib path */
+ tmp_string = get_sandbox_lib(sandbox_dir);
+ strncpy(sandbox_lib, tmp_string, 254);
+ if (tmp_string) free(tmp_string);
+ tmp_string = NULL;
+
+ /* Generate sandbox bashrc path */
+ tmp_string = get_sandbox_rc(sandbox_dir);
+ strncpy(sandbox_rc, tmp_string, 254);
+ if (tmp_string) free(tmp_string);
+ tmp_string = NULL;
+
+ /* verify the existance of required files */
+ if (print_debug) printf("Verification of the required files.\n");
+
+ if (file_exist(sandbox_lib, 0) <= 0) {
+ fprintf(stderr, "Could not open the sandbox library at '%s'.\n", sandbox_lib);
+ return -1;
+ } else if (file_exist(sandbox_rc, 0) <= 0) {
+ fprintf(stderr, "Could not open the sandbox rc file at '%s'.\n", sandbox_rc);
+ return -1;
+ }
+
+#ifdef USE_LD_SO_PRELOAD
+ /* ensure that the /etc/ld.so.preload file contains an entry for the sandbox lib */
+ if (print_debug) printf("Setting up the ld.so.preload file.\n");
+#endif
+
+ /* check if the /etc/ld.so.preload is a regular file */
+ if (file_exist("/etc/ld.so.preload", 1) < 0) {
+ fprintf(stderr, ">>> /etc/ld.so.preload file is not a regular file\n");
+ exit(1);
+ }
+
+ /* Our r+ also will create the file if it doesn't exist */
+ preload_file=file_open("/etc/ld.so.preload", "r+", 1, 0644);
+ if (-1 == preload_file) {
+ preload_adaptable = 0;
+/* exit(1);*/
+ }
+
+#ifdef USE_LD_SO_PRELOAD
+ /* Load entries of preload table */
+ num_of_preloads = load_preload_libs(preload_file, &preload_array);
+
+ /* Zero out our ld.so.preload file */
+ file_truncate(preload_file);
+
+ /* Write contents of preload file */
+ for (i = 0; i < num_of_preloads + 1; i++) {
+ /* First entry should be our sandbox library */
+ if (0 == i) {
+ if (write(preload_file, sandbox_lib, strlen(sandbox_lib)) != strlen(sandbox_lib)) {
+ perror(">>> /etc/ld.so.preload file write");
+ success = 0;
+ break;
+ }
+ } else {
+ /* Output all other preload entries */
+ if (write(preload_file, preload_array[i - 1], strlen(preload_array[i - 1])) != strlen(preload_array[i - 1])) {
+ perror(">>> /etc/ld.so.preload file write");
+ success = 0;
+ break;
+ }
+ }
+ /* Don't forget the return character after each line! */
+ if (1 != write(preload_file, "\n", 1)) {
+ perror(">>> /etc/ld.so.preload file write");
+ success = 0;
+ break;
+ }
+ }
+
+ for (i = 0; i < num_of_preloads; i++) {
+ if (preload_array[i]) free(preload_array[i]);
+ preload_array[i] = NULL;
+ }
+ if (preload_array) free(preload_array);
+ num_of_preloads = 0;
+ preload_array = NULL;
+#endif
+
+ /* That's all we needed to do with the preload file */
+ file_close(preload_file);
+ preload_file = -1;
+
+ /* set up the required environment variables */
+ if (print_debug) printf("Setting up the required environment variables.\n");
+
+ /* Generate sandbox log full path */
+ tmp_string=get_sandbox_log();
+ strncpy(sandbox_log, tmp_string, 254);
+ if (tmp_string) free(tmp_string);
+ tmp_string = NULL;
+
+ setenv(ENV_SANDBOX_LOG, sandbox_log, 1);
+
+ snprintf(sandbox_debug_log, 254, "%s%s%s", DEBUG_LOG_FILE_PREFIX, pid_string, LOG_FILE_EXT);
+ setenv(ENV_SANDBOX_DEBUG_LOG, sandbox_debug_log, 1);
+
+ home_dir = getenv("HOME");
+
+ /* drobbins: we need to expand these paths using realpath() so that PORTAGE_TMPDIR
+ * can contain symlinks (example, /var is a symlink, /var/tmp is a symlink.) Without
+ * this, access is denied to /var/tmp, hurtin' ebuilds.
+ */
+
+ realpath(getenv("PORTAGE_TMPDIR"),portage_tmp_dir);
+ realpath("/var/tmp",var_tmp_dir);
+ realpath("/tmp",tmp_dir);
+
+ setenv(ENV_SANDBOX_DIR, sandbox_dir, 1);
+ setenv(ENV_SANDBOX_LIB, sandbox_lib, 1);
+ setenv("LD_PRELOAD", sandbox_lib, 1);
+
+ if (!getenv(ENV_SANDBOX_DENY)) {
+ setenv(ENV_SANDBOX_DENY, LD_PRELOAD_FILE, 1);
+ }
+
+ if (!getenv(ENV_SANDBOX_READ)) {
+ setenv(ENV_SANDBOX_READ, "/", 1);
+ }
+
+ /* Set up Sandbox Write path */
+ setenv_sandbox_write(home_dir, portage_tmp_dir, var_tmp_dir, tmp_dir);
+ setenv_sandbox_predict(home_dir);
+
+ setenv(ENV_SANDBOX_ON, "1", 0);
+
+ /* if the portage temp dir was present, cd into it */
+ if (NULL != portage_tmp_dir) {
+ chdir(portage_tmp_dir);
+ }
+
+ argv_bash=(char **)malloc(6 * sizeof(char *));
+ argv_bash[0] = strdup("/bin/bash");
+ argv_bash[1] = strdup("-rcfile");
+ argv_bash[2] = strdup(sandbox_rc);
+ if (argc < 2) {
+ argv_bash[3] = NULL;
+ } else {
+ argv_bash[3] = strdup(run_str); /* "-c" */
+ }
+ argv_bash[4] = NULL; /* strdup(run_arg); */
+ argv_bash[5] = NULL;
+
+ if (argc >= 2) {
+ for (i = 1; i< argc; i++) {
+ if (NULL == argv_bash[4]) len = 0;
+ else len = strlen(argv_bash[4]);
+ argv_bash[4]=(char *)realloc(argv_bash[4], (len + strlen(argv[i]) + 2) * sizeof(char));
+ if (0 == len) argv_bash[4][0] = 0;
+ if (1 != i) strcat(argv_bash[4], " ");
+ strcat(argv_bash[4], argv[i]);
+ }
+ }
+#if 0
+ char* argv_bash[] = {
+ "/bin/bash",
+ "-rcfile",
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ };
+
+ /* adding additional bash arguments */
+ for (i = 1; i < argc; i++) {
+ if (1 == i) {
+ argv_bash[3] = run_str;
+ argv_bash[4] = run_arg;
+ strcpy(argv_bash[4], argv[i]);
+ } else {
+ strcat(argv_bash[4], " ");
+ strcat(argv_bash[4], argv[i]);
+ }
+ }
+#endif
+
+ /* set up the required signal handlers */
+ signal(SIGHUP, &stop);
+ signal(SIGINT, &stop);
+ signal(SIGQUIT, &stop);
+ signal(SIGTERM, &stop);
+
+ /* this one should NEVER be set in ebuilds, as it is the one
+ * private thing libsandbox.so use to test if the sandbox
+ * should be active for this pid, or not.
+ *
+ * azarah (3 Aug 2002)
+ */
+
+ setenv("SANDBOX_ACTIVE", "armedandready", 1);
+
+
+ /* Load our PID into PIDs file if environment is adaptable */
+ if (preload_adaptable) {
+ success = 1;
+ if (file_exist(PIDS_FILE, 1) < 0) {
+ success = 0;
+ fprintf(stderr, ">>> pids file is not a regular file");
+ } else {
+ pids_file=file_open(PIDS_FILE, "r+", 1, 0644);
+ if (-1 == pids_file) {
+ success = 0;
+ } else {
+ /* Grab still active pids */
+ num_of_pids = load_active_pids(pids_file, &pids_array);
+
+ /* Zero out file */
+ file_truncate(pids_file);
+
+ /* Output active pids, and append our pid */
+ for (i = 0; i < num_of_pids + 1; i++) {
+ /* Time for our entry */
+ if (i == num_of_pids) {
+ sprintf(pid_string, "%d\n", getpid());
+ } else {
+ sprintf(pid_string, "%d\n", pids_array[i]);
+ }
+ if (write(pids_file, pid_string, strlen(pid_string)) != strlen(pid_string)) {
+ perror(">>> /etc/ld.so.preload file write");
+ success = 0;
+ break;
+ }
+ }
+ /* Clean pids_array */
+ if (pids_array) free(pids_array);
+ pids_array = NULL;
+ num_of_pids = 0;
+
+ /* We're done with the pids file */
+ file_close(pids_file);
+ }
+ }
+
+ /* Something went wrong, bail out */
+ if (success == 0)
+ exit(1);
+ }
+
+ /* STARTING PROTECTED ENVIRONMENT */
+ if (print_debug) {
+ printf("The protected environment has been started.\n");
+ printf("--------------------------------------------------------------------------------\n");
+ }
+
+ if (print_debug) printf("Shell being started in forked process.\n");
+
+ /* Start Bash */
+ if (!spawn_shell(argv_bash)) {
+ if (print_debug) fprintf(stderr, ">>> shell process failed to spawn\n");
+ success = 0;
+ }
+
+ /* Free bash stuff */
+ for (i = 0; i < 6; i++) {
+ if (argv_bash[i]) free(argv_bash[i]);
+ argv_bash[i] = NULL;
+ }
+ if (argv_bash) free(argv_bash);
+ argv_bash = NULL;
+
+ if (print_debug) {
+ printf("Cleaning up sandbox process\n");
+ }
+
+ cleanup();
+
+ if (print_debug) {
+ printf("========================== Gentoo linux path sandbox ===========================\n");
+ printf("The protected environment has been shut down.\n");
+ }
+
+ if (file_exist(sandbox_log, 0)) {
+ sandbox_log_presence = 1;
+ success = 1;
+ if (!print_sandbox_log(sandbox_log)) {
+ success = 0;
+ }
+
+#if 0
+ if (!success) {
+ exit(1);
+ }
+#endif
+ sandbox_log_file = -1;
+ } else if (print_debug) {
+ printf("--------------------------------------------------------------------------------\n");
+ }
+
+ if ((sandbox_log_presence) || (!success)) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+}
+
+
+
+// vim:expandtab noai:cindent ai
diff --git a/src/sandbox-dev/sandbox.h b/src/sandbox-dev/sandbox.h
new file mode 100644
index 00000000..d750fdd7
--- /dev/null
+++ b/src/sandbox-dev/sandbox.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2002 Brad House <brad@mainstreetsoftworks.com>,
+ * Possibly based on code from Geert Bevin, Uwyn, http://www.uwyn.com
+ * Distributed under the terms of the GNU General Public License, v2 or later
+ * Author: Brad House <brad@mainstreetsoftworks.com>
+ *
+ * $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-dev/Attic/sandbox.h,v 1.2 2002/12/04 18:11:32 azarah Exp $
+ */
+
+#ifndef __SANDBOX_H__
+#define __SANDBOX_H__
+
+/* Uncomment below to use flock instead of fcntl (POSIX way) to lock/unlock files */
+/* #define USE_FLOCK */
+
+/* Uncomment below to use system() to execute the shell rather than execv */
+/* #define USE_SYSTEM_SHELL */
+
+/* Uncomment below to use /etc/ld.so.preload (could be very intrusive!!) */
+/* #define USE_LD_SO_PRELOAD */
+
+/* Uncommend to not have the protected shell forked, just run in parent process */
+/* ONLY FOR DEBUGGING PURPOSES!! (strace needs it like that) */
+/* #define NO_FORK */
+
+
+#define LD_PRELOAD_FILE "/etc/ld.so.preload"
+#define LIB_NAME "libsandbox.so"
+#define BASHRC_NAME "sandbox.bashrc"
+#define PIDS_FILE "/tmp/sandboxpids.tmp"
+#define LOG_FILE_PREFIX "/tmp/sandbox-"
+#define DEBUG_LOG_FILE_PREFIX "/tmp/sandbox-debug-"
+#define LOG_FILE_EXT ".log"
+
+#define ENV_SANDBOX_DEBUG_LOG "SANDBOX_DEBUG_LOG"
+#define ENV_SANDBOX_LOG "SANDBOX_LOG"
+#define ENV_SANDBOX_DIR "SANDBOX_DIR"
+#define ENV_SANDBOX_LIB "SANDBOX_LIB"
+
+#define ENV_SANDBOX_DENY "SANDBOX_DENY"
+#define ENV_SANDBOX_READ "SANDBOX_READ"
+#define ENV_SANDBOX_WRITE "SANDBOX_WRITE"
+#define ENV_SANDBOX_PREDICT "SANDBOX_PREDICT"
+
+#define ENV_SANDBOX_ON "SANDBOX_ON"
+#define ENV_SANDBOX_BEEP "SANDBOX_BEEP"
+
+#define DEFAULT_BEEP_COUNT 3
+
+char *get_sandbox_path(char *argv0);
+char *get_sandbox_lib(char *sb_path);
+char *get_sandbox_rc(char *sb_path);
+char *get_sandbox_log();
+char *sb_dirname(const char *path);
+int file_getmode(char *mode);
+long file_tell(int fp);
+int file_lock(int fd, int lock, char *filename);
+int file_unlock(int fd);
+int file_locktype(char *mode);
+int file_open(char *filename, char *mode, int perm_specified, ...);
+void file_close(int fd);
+long file_length(int fd);
+int file_truncate(int fd);
+int file_exist(char *filename, int checkmode);
+
+#endif
+
+
+// vim:expandtab noai:cindent ai
diff --git a/src/sandbox-dev/sandbox_futils.c b/src/sandbox-dev/sandbox_futils.c
new file mode 100644
index 00000000..e2aab3f6
--- /dev/null
+++ b/src/sandbox-dev/sandbox_futils.c
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 2002 Brad House <brad@mainstreetsoftworks.com>
+ * Distributed under the terms of the GNU General Public License, v2 or later
+ * Author: Brad House <brad@mainstreetsoftworks.com>
+ *
+ * $Header: /var/cvsroot/gentoo-src/portage/src/sandbox-dev/Attic/sandbox_futils.c,v 1.3 2002/12/04 18:11:32 azarah Exp $
+ *
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "sandbox.h"
+
+
+char *get_sandbox_path(char *argv0)
+{
+ char path[255];
+ char *cwd = NULL;
+
+ /* ARGV[0] specifies full path */
+ if (argv0[0] == '/') {
+ strncpy(path, argv0, 254);
+
+ /* ARGV[0] specifies relative path */
+ } else {
+ getcwd(cwd, 253);
+ sprintf(path, "%s/%s", cwd, argv0);
+ if (cwd) free(cwd);
+ cwd = NULL;
+ }
+
+ /* Return just directory */
+ return(sb_dirname(path));
+}
+
+char *get_sandbox_lib(char *sb_path)
+{
+ char path[255];
+
+ snprintf(path, 254, "/lib/%s", LIB_NAME);
+ if (file_exist(path, 0) <= 0) {
+ snprintf(path, 254, "%s%s", sb_path, LIB_NAME);
+ }
+ return(strdup(path));
+}
+
+char *get_sandbox_rc(char *sb_path)
+{
+ char path[255];
+
+ snprintf(path, 254, "/usr/lib/portage/lib/%s", BASHRC_NAME);
+ if (file_exist(path, 0) <= 0) {
+ snprintf(path, 254, "%s%s", sb_path, BASHRC_NAME);
+ }
+ return(strdup(path));
+}
+
+char *get_sandbox_log()
+{
+ char path[255];
+ char pid_string[20];
+ char *sandbox_log_env = NULL;
+
+ sprintf(pid_string, "%d", getpid());
+
+ strcpy(path, LOG_FILE_PREFIX);
+ sandbox_log_env = getenv(ENV_SANDBOX_LOG);
+ if (sandbox_log_env) {
+ strcat(path, sandbox_log_env);
+ strcat(path, "-");
+ }
+ strcat(path, pid_string);
+ strcat(path, LOG_FILE_EXT);
+ return(strdup(path));
+}
+
+/* Obtain base directory name. Do not allow trailing / */
+char *sb_dirname(const char *path)
+{
+ char *ret = NULL;
+ char *ptr = NULL;
+ int loc = 0, i;
+ int cut_len = -1;
+
+ /* don't think NULL will ever be passed, but just in case */
+ if (NULL == path) return(strdup("."));
+
+ /* Grab pointer to last slash */
+ ptr = strrchr(path, '/');
+ if (NULL == ptr) {
+ return(strdup("."));
+ }
+
+ /* decimal location of pointer */
+ loc = ptr - path;
+
+ /* Remove any trailing slash */
+ for (i = loc-1; i >= 0; i--) {
+ if (path[i] != '/') {
+ cut_len = i + 1; /* make cut_len the length of the string to keep */
+ break;
+ }
+ }
+
+ /* It could have been just a plain /, return a 1byte 0 filled string */
+ if (-1 == cut_len) return(strdup(""));
+
+ /* Allocate memory, and return the directory */
+ ret = (char *)malloc((cut_len + 1) * sizeof(char));
+ memcpy(ret, path, cut_len);
+ ret[cut_len] = 0;
+
+ return(ret);
+}
+
+/*
+char* dirname(const char* path)
+{
+ char* base = NULL;
+ unsigned int length = 0;
+
+ base = strrchr(path, '/');
+ if (NULL == base)
+ {
+ return strdup(".");
+ }
+ while (base > path && *base == '/')
+ {
+ base--;
+ }
+ length = (unsigned int) 1 + base - path;
+
+ base = malloc(sizeof(char)*(length+1));
+ memmove(base, path, length);
+ base[length] = 0;
+
+ return base;
+}*/
+
+/* Convert text (string) modes to integer values */
+int file_getmode(char *mode)
+{
+ int mde = 0;
+ if (0 == strcasecmp(mode, "r+")) {
+ mde = O_RDWR | O_CREAT;
+ } else if (0 == strcasecmp(mode, "w+")) {
+ mde = O_RDWR | O_CREAT | O_TRUNC;
+ } else if (0 == strcasecmp(mode, "a+")) {
+ mde = O_RDWR | O_CREAT | O_APPEND;
+ } else if (0 == strcasecmp(mode, "r")) {
+ mde = O_RDONLY;
+ } else if (0 == strcasecmp(mode, "w")) {
+ mde = O_WRONLY | O_CREAT | O_TRUNC;
+ } else if (0 == strcasecmp(mode, "a")) {
+ mde = O_WRONLY | O_APPEND | O_CREAT;
+ } else {
+ mde = O_RDONLY;
+ }
+ return(mde);
+}
+
+/* Get current position in file */
+long file_tell(int fp)
+{
+ return(lseek(fp, 0L, SEEK_CUR));
+}
+
+/* lock the file, preferrably the POSIX way */
+int file_lock(int fd, int lock, char *filename)
+{
+ int err;
+#ifdef USE_FLOCK
+ if (flock(fd, lock) < 0) {
+ err = errno;
+ fprintf(stderr, ">>> %s flock file lock: %s\n", filename, strerror(err));
+ return 0;
+ }
+#else
+ struct flock fl;
+ fl.l_type = lock;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0L;
+ fl.l_len = 0L;
+ fl.l_pid = getpid();
+ if (fcntl(fd, F_SETLKW, &fl) < 0) {
+ err = errno;
+ fprintf(stderr, ">>> %s fcntl file lock: %s\n", filename, strerror(err));
+ return 0;
+ }
+#endif
+ return 1;
+}
+
+/* unlock the file, preferrably the POSIX way */
+int file_unlock(int fd)
+{
+#ifdef USE_FLOCK
+ if (flock(fd, LOCK_UN) < 0) {
+ perror(">>> flock file unlock");
+ return 0;
+ }
+#else
+ struct flock fl;
+ fl.l_type = F_UNLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0L;
+ fl.l_len = 0L;
+ fl.l_pid = getpid();
+ if (fcntl(fd, F_SETLKW, &fl) < 0) {
+ perror(">>> fcntl file unlock");
+ return 0;
+ }
+#endif
+ return 1;
+}
+
+/* Auto-determine from how the file was opened, what kind of lock to lock
+ * the file with
+ */
+int file_locktype(char *mode)
+{
+#ifdef USE_FLOCK
+ if (NULL != (strchr(mode, 'w')) || (NULL != strchr(mode, '+')) || (NULL != strchr(mode, 'a')))
+ return(LOCK_EX);
+ return(LOCK_SH);
+#else
+ if (NULL != (strchr(mode, 'w')) || (NULL != strchr(mode, '+')) || (NULL != strchr(mode, 'a')))
+ return(F_WRLCK);
+ return(F_RDLCK);
+#endif
+}
+
+/* Use standard fopen style modes to open the specified file. Also auto-determines and
+ * locks the file either in shared or exclusive mode depending on opening mode
+ */
+int file_open(char *filename, char *mode, int perm_specified, ...)
+{
+ int fd;
+ char error[250];
+ va_list ap;
+ int perm;
+
+ if (perm_specified) {
+ va_start(ap, perm_specified);
+ perm = va_arg(ap, int);
+ va_end(ap);
+ }
+ if (perm_specified) {
+ fd = open(filename, file_getmode(mode), perm);
+ } else {
+ fd = open(filename, file_getmode(mode));
+ }
+ if (-1 == fd) {
+ snprintf(error, 249, ">>> %s file mode: %s open", filename, mode);
+ perror(error);
+ return(fd);
+ }
+ /* Only lock the file if opening succeeded */
+ if (-1 != fd) {
+ if (0 == file_lock(fd, file_locktype(mode), filename)) {
+ close(fd);
+ return -1;
+ }
+ } else {
+ snprintf(error, 249, ">>> %s file mode:%s open", filename, mode);
+ perror(error);
+ }
+ return(fd);
+}
+
+/* Close and unlock file */
+void file_close(int fd)
+{
+ if (-1 != fd) {
+ file_unlock(fd);
+ close(fd);
+ }
+}
+
+/* Return length of file */
+long file_length(int fd)
+{
+ long pos, len;
+ pos = file_tell(fd);
+ len = lseek(fd, 0L, SEEK_END);
+ lseek(fd, pos, SEEK_SET);
+ return(len);
+}
+
+/* Zero out file */
+int file_truncate(int fd)
+{
+ lseek(fd, 0L, SEEK_SET);
+ if (ftruncate(fd, 0) < 0) {
+ perror(">>> file truncate");
+ return 0;
+ }
+ return 1;
+}
+
+/* Check to see if a file exists Return: 1 success, 0 file not found, -1 error */
+int file_exist(char *filename, int checkmode)
+{
+ struct stat mystat;
+
+ /* Verify file exists and is regular file (not sym link) */
+ if (checkmode) {
+ if (-1 == lstat(filename, &mystat)) {
+ /* file doesn't exist */
+ if (ENOENT == errno) {
+ return 0;
+ } else { /* permission denied or other error */
+ perror(">>> stat file");
+ return -1;
+ }
+ }
+ if (!S_ISREG(mystat.st_mode))
+ return -1;
+
+ /* Just plain verify the file exists */
+ } else {
+ if (-1 == stat(filename, &mystat)) {
+ /* file does not exist */
+ if (ENOENT == errno) {
+ return 0;
+ } else { /* permission denied or other error */
+ perror(">>> stat file");
+ return -1;
+ }
+ }
+ }
+
+ return 1;
+}
+
+
+// vim:expandtab noai:cindent ai
diff --git a/src/sandbox/Makefile b/src/sandbox/Makefile
new file mode 100644
index 00000000..9c8fe960
--- /dev/null
+++ b/src/sandbox/Makefile
@@ -0,0 +1,30 @@
+# Copyright (C) 2001 Geert Bevin, Uwyn, http://www.uwyn.com
+# Distributed under the terms of the GNU General Public License, v2 or later
+# Author : Geert Bevin <gbevin@uwyn.com>
+#
+# Modified 15 Apr 2002 Jon Nelson <jnelson@gentoo.org>
+# Clean up Makefile somewhat, and use make's implicit rules
+#
+# $Header: /var/cvsroot/gentoo-src/portage/src/sandbox/Attic/Makefile,v 1.5 2002/08/05 16:44:34 drobbins Exp $
+
+.SUFFIXES:
+.SUFFIXES: .c .o .so
+.PRECIOUS: %.o
+
+%.so: LIBS=-ldl
+%.so: LDFLAGS=--shared
+%.so: %.o
+ $(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ $(LIBS) $(LDFLAGS)
+
+CC = gcc
+CFLAGS = -Wall -O0 -fPIC
+LIBS =
+LDFLAGS =
+
+TARGETS = sandbox libsandbox.so
+
+all: $(TARGETS)
+
+clean:
+ rm -f $(TARGETS)
+ rm -f *.o *~
diff --git a/src/sandbox/libsandbox.c b/src/sandbox/libsandbox.c
new file mode 100644
index 00000000..d850554c
--- /dev/null
+++ b/src/sandbox/libsandbox.c
@@ -0,0 +1,873 @@
+/*
+** Path sandbox for the gentoo linux portage package system, initially
+** based on the ROCK Linux Wrapper for getting a list of created files
+**
+** to integrate with bash, bash should have been built like this
+**
+** ./configure --prefix=<prefix> --host=<host> --without-gnu-malloc
+**
+** it's very important that the --enable-static-link option is NOT specified
+**
+** Copyright (C) 2001 Geert Bevin, Uwyn, http://www.uwyn.com
+** Distributed under the terms of the GNU General Public License, v2 or later
+** Author : Geert Bevin <gbevin@uwyn.com>
+** $Header: /var/cvsroot/gentoo-src/portage/src/sandbox/Attic/libsandbox.c,v 1.8 2002/08/05 05:51:39 drobbins Exp $
+*/
+
+#define _GNU_SOURCE
+#define _REENTRANT
+
+#define open xxx_open
+#define open64 xxx_open64
+# include <dirent.h>
+# include <dlfcn.h>
+# include <errno.h>
+# include <fcntl.h>
+# include <stdarg.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# include <sys/file.h>
+# include <sys/stat.h>
+# include <sys/types.h>
+# include <unistd.h>
+# include <utime.h>
+#undef open
+#undef open64
+
+#define PIDS_FILE "/tmp/sandboxpids.tmp"
+
+typedef struct {
+ int show_access_violation;
+ char** deny_prefixes;
+ int num_deny_prefixes;
+ char** read_prefixes;
+ int num_read_prefixes;
+ char** write_prefixes;
+ int num_write_prefixes;
+ char** predict_prefixes;
+ int num_predict_prefixes;
+ char** write_denied_prefixes;
+ int num_write_denied_prefixes;
+} sbcontext_t;
+
+int check_access(sbcontext_t*, const char*, const char*);
+int check_syscall(sbcontext_t*, const char*, const char*);
+int before_syscall(const char*, const char*);
+int before_syscall_open_int(const char*, const char*, int);
+int before_syscall_open_char(const char*, const char*, const char*);
+void clean_env_entries(char***, int*);
+char* filter_path(const char*);
+void* get_dl_symbol(char*);
+void init_context(sbcontext_t*);
+void init_env_entries(char***, int*, char*, int);
+int is_sandbox_on();
+int is_sandbox_pid();
+
+/* Wrapper macros and functions */
+
+/* macro definition to wrap functions before and after the
+ execution of basic file related system-calls.
+
+ nr : the argument number of the system-call's argument that
+ contains the file name to monitor
+ rt : the return type of the system call
+ name : the name of the function call
+ arg1, arg2, arg3 : the types of the function call's arguments
+ fl : the argument number of the system-call's argument that
+ contains the file access flags
+ md : the argument number of the system-call's argument that
+ contains the file access mode
+*/
+#define wrsysc3(nr, rt, name, arg1, arg2, arg3) \
+ \
+/* the function call is defined externally from this file */ \
+extern rt name(arg1, arg2, arg3); \
+ \
+/* orig_ ## name is a pointer to a function with three arguments and the
+ return type of the system call. This will be used to store the pointer
+ to the system call function and call it. */ \
+rt (*orig_ ## name)(arg1, arg2, arg3) = NULL; \
+ \
+rt name(arg1 a1, arg2 a2, arg3 a3) \
+{ \
+ rt result = -1; \
+ int old_errno = errno; \
+ if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
+ { \
+ if (!orig_ ## name) \
+ { \
+ orig_ ## name = get_dl_symbol(#name); \
+ } \
+ errno = old_errno; \
+ result = orig_ ## name(a1, a2, a3); \
+ } \
+ return result; \
+}
+
+#define wrsysc2(nr, rt, name, arg1, arg2) \
+extern rt name(arg1, arg2); \
+rt (*orig_ ## name)(arg1, arg2) = NULL; \
+ \
+rt name(arg1 a1, arg2 a2) \
+{ \
+ rt result = -1; \
+ int old_errno = errno; \
+ if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
+ { \
+ if (!orig_ ## name) \
+ { \
+ orig_ ## name = get_dl_symbol(#name); \
+ } \
+ errno = old_errno; \
+ result = orig_ ## name(a1, a2); \
+ } \
+ return result; \
+}
+
+#define wrsysc1(nr, rt, name, arg1) \
+extern rt name(arg1); \
+rt (*orig_ ## name)(arg1) = NULL; \
+ \
+rt name(arg1 a1) \
+{ \
+ rt result = -1; \
+ int old_errno = errno; \
+ if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
+ { \
+ if (!orig_ ## name) \
+ { \
+ orig_ ## name = get_dl_symbol(#name); \
+ } \
+ errno = old_errno; \
+ result = orig_ ## name(a1); \
+ } \
+ return result; \
+}
+
+#define wrsysc1ptr(nr, rt, name, arg1) \
+extern rt name(arg1); \
+rt (*orig_ ## name)(arg1) = NULL; \
+ \
+rt name(arg1 a1) \
+{ \
+ rt result = NULL; \
+ int old_errno = errno; \
+ if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
+ { \
+ if (!orig_ ## name) \
+ { \
+ orig_ ## name = get_dl_symbol(#name); \
+ } \
+ errno = old_errno; \
+ result = orig_ ## name(a1); \
+ } \
+ return result; \
+}
+
+#define wropenint3(nr, fl, rt, name, arg1, arg2, arg3) \
+extern rt name(arg1, arg2, arg3); \
+rt (*orig_ ## name)(arg1, arg2, arg3) = NULL; \
+ \
+rt name(arg1 a1, arg2 a2, arg3 a3) \
+{ \
+ rt result = -1; \
+ int old_errno = errno; \
+ if (0 == is_sandbox_on() || \
+ 1 == before_syscall_open_int(#name, a ## nr, a ## fl)) \
+ { \
+ if (!orig_ ## name) \
+ { \
+ orig_ ## name = get_dl_symbol(#name); \
+ } \
+ errno = old_errno; \
+ result = orig_ ## name(a1, a2, a3); \
+ } \
+ return result; \
+}
+
+#define wropenchar2(nr, md, rt, name, arg1, arg2) \
+extern rt name(arg1, arg2); \
+rt (*orig_ ## name)(arg1, arg2) = NULL; \
+ \
+rt name(arg1 a1, arg2 a2) \
+{ \
+ rt result = NULL; \
+ int old_errno = errno; \
+ if (0 == is_sandbox_on() || \
+ 1 == before_syscall_open_char(#name, a ## nr, a ## md)) \
+ { \
+ if (!orig_ ## name) \
+ { \
+ orig_ ## name = get_dl_symbol(#name); \
+ } \
+ errno = old_errno; \
+ result = orig_ ## name(a1, a2); \
+ } \
+ return result; \
+}
+
+#define wropenchar3(nr, md, rt, name, arg1, arg2, arg3) \
+extern rt name(arg1, arg2, arg3); \
+rt (*orig_ ## name)(arg1, arg2, arg3) = NULL; \
+ \
+rt name(arg1 a1, arg2 a2, arg3 a3) \
+{ \
+ rt result = NULL; \
+ int old_errno = errno; \
+ if (0 == is_sandbox_on() || \
+ 1 == before_syscall_open_char(#name, a ## nr, a ## md)) \
+ { \
+ if (!orig_ ## name) \
+ { \
+ orig_ ## name = get_dl_symbol(#name); \
+ } \
+ errno = old_errno; \
+ result = orig_ ## name(a1, a2, a3); \
+ } \
+ return result; \
+}
+
+#define wrexec3(nr, rt, name, arg1, arg2, arg3) \
+extern rt name(arg1, arg2, arg3); \
+rt (*orig_ ## name)(arg1, arg2, arg3) = NULL; \
+ \
+rt name(arg1 a1, arg2 a2, arg3 a3) \
+{ \
+ rt result = -1; \
+ int old_errno = errno; \
+ if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
+ { \
+ if (!orig_ ## name) \
+ { \
+ orig_ ## name = get_dl_symbol(#name); \
+ } \
+ errno = old_errno; \
+ result = orig_ ## name(a1, a2, a3); \
+ } \
+ return result; \
+}
+
+#define wrexec2(nr, rt, name, arg1, arg2) \
+extern rt name(arg1, arg2); \
+rt (*orig_ ## name)(arg1, arg2) = NULL; \
+ \
+rt name(arg1 a1, arg2 a2) \
+{ \
+ rt result = -1; \
+ int old_errno = errno; \
+ if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
+ { \
+ if (!orig_ ## name) \
+ { \
+ orig_ ## name = get_dl_symbol(#name); \
+ } \
+ errno = old_errno; \
+ result = orig_ ## name(a1, a2); \
+ } \
+ return result; \
+}
+
+#define wrexec2va(nr, rt, name, arg1, arg2) \
+extern rt name(arg1, arg2, ...); \
+rt (*orig_ ## name)(arg1, arg2, ...) = NULL; \
+ \
+rt name(arg1 a1, arg2 a2, ...) \
+{ \
+ void* result = NULL; \
+ int old_errno = errno; \
+ if (0 == is_sandbox_on() || 1 == before_syscall(#name, a ## nr)) \
+ { \
+ if (!orig_ ## name) \
+ { \
+ orig_ ## name = get_dl_symbol(#name); \
+ } \
+ errno = old_errno; \
+ result = __builtin_apply( (void(*)()) orig_ ## name, \
+ __builtin_apply_args(), 32 ); \
+ old_errno = errno; \
+ } \
+ if (NULL == result) \
+ { \
+ return -1; \
+ } \
+ else \
+ { \
+ __builtin_return(result); \
+ } \
+}
+
+wropenint3(1, 2, int, open, const char*, int, mode_t)
+wropenint3(1, 2, int, open64, const char*, int, mode_t)
+
+wropenchar2(1, 2, FILE*, fopen, const char*, const char*)
+wropenchar2(1, 2, FILE*, fopen64, const char*, const char*)
+wropenchar3(1, 2, FILE*, freopen, const char*, const char*, FILE*)
+
+wropenchar2(1, 2, FILE*, popen, const char*, const char*)
+
+// write syscalls
+
+wrsysc2(1, int, creat, const char*, mode_t)
+wrsysc2(1, int, creat64, const char*, mode_t)
+
+wrsysc2(1, int, mkdir, const char*, mode_t)
+wrsysc3(1, int, mknod, const char*, mode_t, dev_t)
+wrsysc2(1, int, mkfifo, const char*, mode_t)
+
+wrsysc2(2, int, link, const char*, const char*)
+wrsysc2(2, int, symlink, const char*, const char*)
+wrsysc2(2, int, rename, const char*, const char*)
+
+wrsysc2(1, int, utime, const char*, const struct utimbuf*)
+wrsysc2(1, int, utimes, const char*, struct timeval*)
+
+wrsysc1(1, int, unlink, const char*)
+wrsysc1(1, int, rmdir, const char*)
+
+wrsysc3(1, int, chown, const char*, uid_t, gid_t)
+wrsysc3(1, int, lchown, const char*, uid_t, gid_t)
+
+wrsysc2(1, int, chmod, const char*, mode_t)
+
+/* read syscalls */
+
+wrsysc1ptr(1, DIR*, opendir, const char*)
+
+/* execution syscalls */
+wrsysc1(1, int, system, const char*)
+
+wrexec2va(1, int, execl, const char*, const char*)
+wrexec2va(1, int, execle, const char*, const char*)
+wrexec2(1, int, execv, const char*, char* const*)
+wrexec3(1, int, execve, const char*, char* const*, char* const*)
+/* execlp is redirected to execvp */
+/* execvp is special since it should search the PATH var entries */
+extern int execvp(const char*, char* const*);
+int(*orig_execvp)(const char*, char* const*) = NULL;
+int execvp(const char* file, char* const* argv)
+{
+ int result = -1;
+ int old_errno = errno;
+ int i = 0;
+ int allowed = 1;
+ char** path_entries = NULL;
+ int num_path_entries = 0;
+ char constructed_path[255];
+
+ if (1 == is_sandbox_on())
+ {
+ init_env_entries(&path_entries, &num_path_entries, "PATH", 0);
+ for (i = 0; i < num_path_entries; i++)
+ {
+ strcpy(constructed_path, path_entries[i]);
+ strcat(constructed_path, "/");
+ strcat(constructed_path, file);
+ if (0 == before_syscall("execvp", constructed_path))
+ {
+ allowed = 0;
+ break;
+ }
+ }
+ clean_env_entries(&path_entries, &num_path_entries);
+ }
+
+ if (1 == allowed)
+ {
+ if (!orig_execvp)
+ {
+ orig_execvp = get_dl_symbol("execvp");
+ }
+ errno = old_errno;
+ result = orig_execvp(file, argv);
+ old_errno = errno;
+ }
+ errno = old_errno;
+ return result;
+}
+
+/* lseek, lseek64, fdopen, fchown, fchmod, fcntl, lockf
+ are not wrapped since they can't be used if open is wrapped correctly
+ and unaccessible file descriptors are not possible to create */
+
+void* get_dl_symbol(char* symname)
+{
+ void* result = dlsym(RTLD_NEXT, symname);
+ if (0 == result)
+ {
+ fprintf(stderr, "Sandbox : can't resolve %s: %s.\n", symname, dlerror());
+ abort();
+ }
+ return result;
+}
+
+void init_context(sbcontext_t* context)
+{
+ context->show_access_violation = 1;
+ context->deny_prefixes = NULL;
+ context->num_deny_prefixes = 0;
+ context->read_prefixes = NULL;
+ context->num_read_prefixes = 0;
+ context->write_prefixes = NULL;
+ context->num_write_prefixes = 0;
+ context->predict_prefixes = NULL;
+ context->num_predict_prefixes = 0;
+ context->write_denied_prefixes = NULL;
+ context->num_write_denied_prefixes = 0;
+}
+
+int is_sandbox_pid()
+{
+ int result = 0;
+ FILE* pids_stream = NULL;
+ int pids_file = -1;
+ int current_pid = 0;
+ int tmp_pid = 0;
+
+ pids_stream = fopen(PIDS_FILE, "r");
+ if (NULL == pids_stream)
+ {
+ perror(">>> pids file fopen");
+ }
+ else
+ {
+ pids_file = fileno(pids_stream);
+ if (pids_file < 0)
+ {
+ perror(">>> pids file fileno");
+ }
+ else
+ {
+ current_pid = getpid();
+
+ while (EOF != fscanf(pids_stream, "%d\n", &tmp_pid))
+ {
+ if (tmp_pid == current_pid)
+ {
+ result = 1;
+ break;
+ }
+ }
+ }
+ if (EOF == fclose(pids_stream))
+ {
+ perror(">>> pids file fclose");
+ }
+ pids_stream = NULL;
+ pids_file = -1;
+ }
+
+ return result;
+}
+
+void clean_env_entries(char*** prefixes_array, int* prefixes_num)
+{
+ int i = 0;
+ if (NULL != *prefixes_array)
+ {
+ for (i = 0; i < *prefixes_num; i++)
+ {
+ if (NULL != (*prefixes_array)[i])
+ {
+ free((*prefixes_array)[i]);
+ (*prefixes_array)[i] = NULL;
+ }
+ }
+ free(*prefixes_array);
+ *prefixes_array = NULL;
+
+ *prefixes_num = 0;
+ }
+}
+
+void init_env_entries(char*** prefixes_array, int* prefixes_num, char* env, int warn)
+{
+ char* prefixes_env = getenv(env);
+
+ if (NULL == prefixes_env)
+ {
+ fprintf(stderr, "Sandbox error : the %s environmental variable should be defined.\n", env);
+ }
+ else
+ {
+ char* buffer = NULL;
+ int prefixes_env_length = strlen(prefixes_env);
+ int i = 0;
+ int num_delimiters = 0;
+ char* token = NULL;
+ char* prefix = NULL;
+
+ for (i = 0; i < prefixes_env_length; i++)
+ {
+ if (':' == prefixes_env[i])
+ {
+ num_delimiters++;
+ }
+ }
+
+ if (num_delimiters > 0)
+ {
+ buffer = (char*)malloc(sizeof(char)*(prefixes_env_length+1));
+ *prefixes_array = (char**)malloc(sizeof(char*)*(num_delimiters+1));
+
+ strcpy(buffer, prefixes_env);
+ token = strtok(buffer, ":");
+ while (NULL != token &&
+ strlen(token) > 0)
+ {
+ prefix = (char*)malloc(sizeof(char)*(strlen(token)+1));
+ strcpy(prefix, token);
+ (*prefixes_array)[(*prefixes_num)++] = filter_path(prefix);
+ free(prefix);
+ token = strtok(NULL, ":");
+ }
+ free(buffer);
+ buffer = NULL;
+ }
+ else if(prefixes_env_length > 0)
+ {
+ (*prefixes_array) = (char**)malloc(sizeof(char*));
+
+ prefix = (char*)malloc(sizeof(char)*(prefixes_env_length+1));
+ strcpy(prefix, prefixes_env);
+ (*prefixes_array)[(*prefixes_num)++] = filter_path(prefix);
+ free(prefix);
+ }
+ }
+}
+
+char* filter_path(const char* path)
+{
+ int initial_path_length = strlen(path);
+ char* filtered_path = (char*)malloc(sizeof(char)*(initial_path_length+1));
+ int i = 0;
+ int j = 0;
+
+ for (i = 0, j = 0; i < initial_path_length;)
+ {
+ filtered_path[j] = path[i];
+ if ('/' == filtered_path[j])
+ {
+ while ('/' == path[i] &&
+ i < initial_path_length)
+ {
+ i++;
+ }
+ }
+ else
+ {
+ i++;
+ }
+ j++;
+ }
+ filtered_path[j] = 0;
+
+ return filtered_path;
+}
+
+int check_access(sbcontext_t* sbcontext, const char* func, const char* path)
+{
+ int result = -1;
+ int i = 0;
+ char* filtered_path = filter_path(path);
+
+ if ('/' != path[0])
+ {
+ return 0;
+ }
+
+ if (0 == strcmp(filtered_path, "/etc/ld.so.preload") &&
+ is_sandbox_pid())
+ {
+ result = 1;
+ }
+
+ if (-1 == result)
+ {
+ if (NULL != sbcontext->deny_prefixes)
+ {
+ for (i = 0; i < sbcontext->num_deny_prefixes; i++)
+ {
+ if (0 == strncmp(filtered_path, sbcontext->deny_prefixes[i], strlen(sbcontext->deny_prefixes[i])))
+ {
+ result = 0;
+ break;
+ }
+ }
+ }
+
+ if (-1 == result)
+ {
+ if (NULL != sbcontext->read_prefixes &&
+ (0 == strcmp(func, "open_rd") ||
+ 0 == strcmp(func, "popen") ||
+ 0 == strcmp(func, "opendir") ||
+ 0 == strcmp(func, "system") ||
+ 0 == strcmp(func, "execl") ||
+ 0 == strcmp(func, "execlp") ||
+ 0 == strcmp(func, "execle") ||
+ 0 == strcmp(func, "execv") ||
+ 0 == strcmp(func, "execvp") ||
+ 0 == strcmp(func, "execve")))
+ {
+ for (i = 0; i < sbcontext->num_read_prefixes; i++)
+ {
+ if (0 == strncmp(filtered_path, sbcontext->read_prefixes[i], strlen(sbcontext->read_prefixes[i])))
+ {
+ result = 1;
+ break;
+ }
+ }
+ }
+ else if (NULL != sbcontext->write_prefixes &&
+ (0 == strcmp(func, "open_wr") ||
+ 0 == strcmp(func, "creat") ||
+ 0 == strcmp(func, "creat64") ||
+ 0 == strcmp(func, "mkdir") ||
+ 0 == strcmp(func, "mknod") ||
+ 0 == strcmp(func, "mkfifo") ||
+ 0 == strcmp(func, "link") ||
+ 0 == strcmp(func, "symlink") ||
+ 0 == strcmp(func, "rename") ||
+ 0 == strcmp(func, "utime") ||
+ 0 == strcmp(func, "utimes") ||
+ 0 == strcmp(func, "unlink") ||
+ 0 == strcmp(func, "rmdir") ||
+ 0 == strcmp(func, "chown") ||
+ 0 == strcmp(func, "lchown") ||
+ 0 == strcmp(func, "chmod")))
+ {
+ struct stat tmp_stat;
+
+ for (i = 0; i < sbcontext->num_write_denied_prefixes; i++)
+ {
+ if (0 == strncmp(filtered_path, sbcontext->write_denied_prefixes[i], strlen(sbcontext->write_denied_prefixes[i])))
+ {
+ result = 0;
+ break;
+ }
+ }
+ if (-1 == result)
+ {
+ for (i = 0; i < sbcontext->num_write_prefixes; i++)
+ {
+ if (0 == strncmp(filtered_path, sbcontext->write_prefixes[i], strlen(sbcontext->write_prefixes[i])))
+ {
+ result = 1;
+ break;
+ }
+ }
+
+ if (-1 == result)
+ {
+ /* hack to prevent mkdir of existing dirs to show errors */
+ if (strcmp(func, "mkdir") == 0)
+ {
+ if (0 == stat(filtered_path, &tmp_stat))
+ {
+ sbcontext->show_access_violation = 0;
+ result = 0;
+ }
+ }
+
+ if (-1 == result)
+ {
+ for (i = 0; i < sbcontext->num_predict_prefixes; i++)
+ {
+ if (0 == strncmp(filtered_path, sbcontext->predict_prefixes[i], strlen(sbcontext->predict_prefixes[i])))
+ {
+ sbcontext->show_access_violation = 0;
+ result = 0;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (-1 == result)
+ {
+ result = 0;
+ }
+
+ free(filtered_path);
+
+ return result;
+}
+
+int check_syscall(sbcontext_t* sbcontext, const char* func, const char* file)
+{
+ int result = 1;
+ char* absolute_path = NULL;
+ char* tmp_buffer = NULL;
+ struct stat log_stat;
+ char* log_path = NULL;
+ int log_file = 0;
+ struct stat debug_log_stat;
+ char* debug_log_env = NULL;
+ char* debug_log_path = NULL;
+ int debug_log_file = 0;
+ char buffer[512];
+
+ if ('/' == file[0])
+ {
+ absolute_path = (char*)malloc(sizeof(char)*(strlen(file)+1));
+ sprintf(absolute_path, "%s", file);
+ }
+ else
+ {
+ tmp_buffer = get_current_dir_name();
+ absolute_path = (char*)malloc(sizeof(char)*(strlen(tmp_buffer)+1+strlen(file)+1));
+ sprintf(absolute_path,"%s/%s", tmp_buffer, file);
+ free(tmp_buffer);
+ tmp_buffer = NULL;
+ }
+
+ log_path = getenv("SANDBOX_LOG");
+ debug_log_env = getenv("SANDBOX_DEBUG");
+ debug_log_path = getenv("SANDBOX_DEBUG_LOG");
+
+ if ((NULL == log_path || 0 != strcmp(absolute_path, log_path)) &&
+ (NULL == debug_log_env || NULL == debug_log_path || 0 != strcmp(absolute_path, debug_log_path)) &&
+ 0 == check_access(sbcontext, func, absolute_path))
+ {
+ if (1 == sbcontext->show_access_violation)
+ {
+ fprintf(stderr, "\e[31;01mACCESS DENIED\033[0m %s:%*s%s\n", func, (int)(10-strlen(func)), "", absolute_path);
+
+ if (NULL != log_path)
+ {
+ sprintf(buffer, "%s:%*s%s\n", func, (int)(10-strlen(func)), "", absolute_path);
+ if (0 == lstat(log_path, &log_stat) &&
+ 0 == S_ISREG(log_stat.st_mode))
+ {
+ fprintf(stderr, "\e[31;01mSECURITY BREACH\033[0m %s already exists and is not a regular file.\n", log_path);
+ }
+ else
+ {
+ log_file = open(log_path, O_APPEND|O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if(log_file >= 0)
+ {
+ write(log_file, buffer, strlen(buffer));
+ close(log_file);
+ }
+ }
+ }
+ }
+
+ result = 0;
+ }
+ else if (NULL != debug_log_env)
+ {
+ if (NULL != debug_log_path)
+ {
+ if (0 != strcmp(absolute_path, debug_log_path))
+ {
+ sprintf(buffer, "%s:%*s%s\n", func, (int)(10-strlen(func)), "", absolute_path);
+ if (0 == lstat(debug_log_path, &debug_log_stat) &&
+ 0 == S_ISREG(debug_log_stat.st_mode))
+ {
+ fprintf(stderr, "\e[31;01mSECURITY BREACH\033[0m %s already exists and is not a regular file.\n", log_path);
+ }
+ else
+ {
+ debug_log_file = open(debug_log_path, O_APPEND|O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if(debug_log_file >= 0)
+ {
+ write(debug_log_file, buffer, strlen(buffer));
+ close(debug_log_file);
+ }
+ }
+ }
+ }
+ else
+ {
+ fprintf(stderr, "\e[32;01mACCESS ALLOWED\033[0m %s:%*s%s\n", func, (int)(10-strlen(func)), "", absolute_path);
+ }
+ }
+
+ free(absolute_path);
+ absolute_path = NULL;
+
+ return result;
+}
+
+int is_sandbox_on()
+{
+ /* $SANDBOX_ACTIVE is an env variable that should ONLY
+ * be used internal by sandbox.c and libsanbox.c. External
+ * sources should NEVER set it, else the sandbox is enabled
+ * in some cases when run in parallel with another sandbox,
+ * but not even in the sandbox shell.
+ *
+ * Azarah (3 Aug 2002)
+ */
+ if (NULL != getenv("SANDBOX_ON") &&
+ 0 == strcmp(getenv("SANDBOX_ON"), "1") &&
+ NULL != getenv("SANDBOX_ACTIVE") &&
+ 0 == strcmp(getenv("SANDBOX_ACTIVE"), "armedandready"))
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+int before_syscall(const char* func, const char* file)
+{
+ int result = 1;
+
+ sbcontext_t sbcontext;
+
+ init_context(&sbcontext);
+
+ init_env_entries(&(sbcontext.deny_prefixes), &(sbcontext.num_deny_prefixes), "SANDBOX_DENY", 1);
+ init_env_entries(&(sbcontext.read_prefixes), &(sbcontext.num_read_prefixes), "SANDBOX_READ", 1);
+ init_env_entries(&(sbcontext.write_prefixes), &(sbcontext.num_write_prefixes), "SANDBOX_WRITE", 1);
+ init_env_entries(&(sbcontext.predict_prefixes), &(sbcontext.num_predict_prefixes), "SANDBOX_PREDICT", 1);
+
+ result = check_syscall(&sbcontext, func, file);
+
+ clean_env_entries(&(sbcontext.deny_prefixes), &(sbcontext.num_deny_prefixes));
+ clean_env_entries(&(sbcontext.read_prefixes), &(sbcontext.num_read_prefixes));
+ clean_env_entries(&(sbcontext.write_prefixes), &(sbcontext.num_write_prefixes));
+ clean_env_entries(&(sbcontext.predict_prefixes), &(sbcontext.num_predict_prefixes));
+
+ if (0 == result)
+ {
+ errno = EACCES;
+ }
+
+ return result;
+}
+
+int before_syscall_open_int(const char* func, const char* file, int flags)
+{
+ if (flags & O_WRONLY ||
+ flags & O_RDWR)
+ {
+ return before_syscall("open_wr", file);
+ }
+ else
+ {
+ return before_syscall("open_rd", file);
+ }
+}
+
+int before_syscall_open_char(const char* func, const char* file, const char* mode)
+{
+ if (strcmp(mode, "r") == 0 ||
+ strcmp(mode, "rb") == 0)
+ {
+ return before_syscall("open_rd", file);
+ }
+ else
+ {
+ return before_syscall("open_wr", file);
+ }
+}
diff --git a/src/sandbox/problems/Makefile b/src/sandbox/problems/Makefile
new file mode 100644
index 00000000..b44189bd
--- /dev/null
+++ b/src/sandbox/problems/Makefile
@@ -0,0 +1,31 @@
+# Copyright (C) 2001 Geert Bevin, Uwyn, http://www.uwyn.com
+# Distributed under the terms of the GNU General Public License, v2 or later
+# Author : Geert Bevin <gbevin@uwyn.com>
+#
+# Modified 15 Apr 2002 Jon Nelson <jnelson@gentoo.org>
+# Clean up Makefile somewhat, and use make's implicit rules
+#
+# $Header: /var/cvsroot/gentoo-src/portage/src/sandbox/problems/Attic/Makefile,v 1.2 2002/04/16 01:06:55 jnelson Exp $
+
+.SUFFIXES:
+.SUFFIXES: .c .o .so
+.PRECIOUS: %.o
+
+%.so: LIBS=-ldl
+%.so: LDFLAGS=--shared
+%.so: %.o
+ $(CC) $(CFLAGS) $(CPPFLAGS) $< -o $@ $(LIBS) $(LDFLAGS)
+
+CC = gcc
+CFLAGS = -Wall -O2
+LIBS =
+LDFLAGS =
+
+TARGETS = sandbox_muttbug sandbox_dev_fd_foo \
+ libsandbox_muttbug.so libsandbox_emacsbug.so
+
+all: $(TARGETS)
+
+clean:
+ rm -f $(TARGETS)
+ rm -f *.o *~
diff --git a/src/sandbox/problems/libsandbox_emacsbug.c b/src/sandbox/problems/libsandbox_emacsbug.c
new file mode 100644
index 00000000..11e861b9
--- /dev/null
+++ b/src/sandbox/problems/libsandbox_emacsbug.c
@@ -0,0 +1,34 @@
+/* $Header: /var/cvsroot/gentoo-src/portage/src/sandbox/problems/Attic/libsandbox_emacsbug.c,v 1.2 2003/03/22 14:24:38 carpaski Exp $ */
+
+#define _GNU_SOURCE
+#define _REENTRANT
+
+#define open xxx_open
+# include <dlfcn.h>
+# include <errno.h>
+# include <fcntl.h>
+# include <stdlib.h>
+# include <sys/stat.h>
+# include <sys/types.h>
+#undef open
+
+extern int open(const char*, int, mode_t);
+int (*orig_open)(const char*, int, mode_t) = NULL;
+int open(const char* pathname, int flags, mode_t mode)
+{
+ int old_errno = errno;
+
+ /* code that makes xemacs' compilation produce a segfaulting executable */
+/* char** test = NULL;
+ test = (char**)malloc(sizeof(char*));
+ free(test);*/
+ /* end of that code */
+
+ if (!orig_open)
+ {
+ orig_open = dlsym(RTLD_NEXT, "open");
+ }
+ errno = old_errno;
+ return orig_open(pathname, flags, mode);
+}
+
diff --git a/src/sandbox/problems/libsandbox_muttbug.c b/src/sandbox/problems/libsandbox_muttbug.c
new file mode 100644
index 00000000..1d6e18c4
--- /dev/null
+++ b/src/sandbox/problems/libsandbox_muttbug.c
@@ -0,0 +1,24 @@
+/* $Header: /var/cvsroot/gentoo-src/portage/src/sandbox/problems/Attic/libsandbox_muttbug.c,v 1.2 2003/03/22 14:24:38 carpaski Exp $ */
+
+#define _GNU_SOURCE
+#define _REENTRANT
+
+#define open xxx_open
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdio.h>
+#undef open
+
+extern FILE* fopen(const char*, const char*);
+FILE* (*orig_fopen)(const char*, const char*) = 0;
+FILE* fopen(const char* a1, const char* a2)
+{
+ int old_errno = errno;
+ if (!orig_fopen)
+ {
+ orig_fopen = dlsym(RTLD_NEXT, "fopen");
+ }
+ errno = old_errno;
+ return orig_fopen(a1, a2);
+}
+
diff --git a/src/sandbox/problems/sandbox_dev_fd_foo.c b/src/sandbox/problems/sandbox_dev_fd_foo.c
new file mode 100644
index 00000000..c36a095c
--- /dev/null
+++ b/src/sandbox/problems/sandbox_dev_fd_foo.c
@@ -0,0 +1,42 @@
+/* $Header: /var/cvsroot/gentoo-src/portage/src/sandbox/problems/Attic/sandbox_dev_fd_foo.c,v 1.2 2003/03/22 14:24:38 carpaski Exp $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+void cleanup_1(void)
+{
+ puts("Unlinking file...");
+ unlink("/tmp/_sandbox_test.file");
+}
+
+int main(void)
+{
+ struct stat s1, s2;
+ FILE *fp1, *fp2;
+ char *file = "/tmp/_sandbox_test.file";
+ char devfd[32];
+
+ printf("Opening file...\n");
+ if (!(fp1 = fopen(file, "w")))
+ exit(1);
+ atexit(cleanup_1);
+ printf("fstat'ing file...\n");
+ if (fstat(fileno(fp1), &s1) < 0)
+ exit(2);
+ sprintf(devfd, "/dev/fd/%d", fileno(fp1));
+ printf("fopening %s...\n", devfd);
+ if (!(fp2 = fopen(devfd, "w")))
+ exit(3);
+ printf("fstat'ing %s...\n", devfd);
+ if (fstat(fileno(fp2), &s2) < 0)
+ exit(4);
+ printf("Checking %ld == %ld and %ld == %ld...\n",
+ (long int) s1.st_dev, (long int) s2.st_dev, s1.st_ino, s2.st_ino);
+ if (s1.st_dev != s2.st_dev || s1.st_ino != s2.st_ino)
+ exit(5);
+ printf("Success!\n");
+ return(0);
+}
diff --git a/src/sandbox/problems/sandbox_muttbug.c b/src/sandbox/problems/sandbox_muttbug.c
new file mode 100644
index 00000000..cccdc43e
--- /dev/null
+++ b/src/sandbox/problems/sandbox_muttbug.c
@@ -0,0 +1,43 @@
+/* $Header: /var/cvsroot/gentoo-src/portage/src/sandbox/problems/Attic/sandbox_muttbug.c,v 1.3 2003/03/22 14:24:38 carpaski Exp $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+ FILE *fd ;
+
+ printf("unlink\n");
+ unlink("/tmp/test");
+ printf("... done\n");
+
+ printf("fopen\n");
+ fd = fopen("/tmp/test", "a+");
+ printf("... done\n");
+
+ printf("fputc\n");
+ fputc('7', fd);
+ printf("... done\n");
+
+ printf("fseek\n");
+ fseek(fd, 0, SEEK_SET);
+ printf("... done\n");
+
+ printf("freopen\n");
+ fd = freopen("/tmp/test", "r", fd);
+ printf("... done\n");
+
+ printf("fgetc ");
+ printf("%c\n", fgetc(fd));
+ printf("... done\n");
+
+ printf("fseek\n");
+ fseek(fd, 0, SEEK_SET);
+ printf("... done\n");
+
+ printf("fclose\n");
+ fclose(fd);
+ printf("... done\n");
+ return 0;
+}
diff --git a/src/sandbox/sandbox.bashrc b/src/sandbox/sandbox.bashrc
new file mode 100644
index 00000000..be25349d
--- /dev/null
+++ b/src/sandbox/sandbox.bashrc
@@ -0,0 +1,8 @@
+# Copyright (C) 2001 Geert Bevin, Uwyn, http://www.uwyn.com
+# Distributed under the terms of the GNU General Public License, v2 or later
+# Author : Geert Bevin <gbevin@uwyn.com>
+# $Header: /var/cvsroot/gentoo-src/portage/src/sandbox/Attic/sandbox.bashrc,v 1.2 2002/03/06 09:51:02 gbevin Exp $
+source /etc/profile
+export LD_PRELOAD="$SANDBOX_LIB"
+alias make="make LD_PRELOAD=$SANDBOX_LIB"
+alias su="su -c '/bin/bash -rcfile $SANDBOX_DIR/sandbox.bashrc'"
diff --git a/src/sandbox/sandbox.c b/src/sandbox/sandbox.c
new file mode 100644
index 00000000..5a2295e7
--- /dev/null
+++ b/src/sandbox/sandbox.c
@@ -0,0 +1,921 @@
+/*
+** Path sandbox for the gentoo linux portage package system, initially
+** based on the ROCK Linux Wrapper for getting a list of created files
+**
+** to integrate with bash, bash should have been built like this
+**
+** ./configure --prefix=<prefix> --host=<host> --without-gnu-malloc
+**
+** it's very important that the --enable-static-link option is NOT specified
+**
+** Copyright (C) 2001 Geert Bevin, Uwyn, http://www.uwyn.com
+** Distributed under the terms of the GNU General Public License, v2 or later
+** Author : Geert Bevin <gbevin@uwyn.com>
+** $Header: /var/cvsroot/gentoo-src/portage/src/sandbox/Attic/sandbox.c,v 1.13 2002/08/05 05:51:39 drobbins Exp $
+*/
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#define LD_PRELOAD_FILE "/etc/ld.so.preload"
+#define LIB_NAME "libsandbox.so"
+#define BASHRC_NAME "sandbox.bashrc"
+#define PIDS_FILE "/tmp/sandboxpids.tmp"
+#define LOG_FILE_PREFIX "/tmp/sandbox-"
+#define DEBUG_LOG_FILE_PREFIX "/tmp/sandbox-debug-"
+#define LOG_FILE_EXT ".log"
+
+#define ENV_SANDBOX_DEBUG_LOG "SANDBOX_DEBUG_LOG"
+#define ENV_SANDBOX_LOG "SANDBOX_LOG"
+#define ENV_SANDBOX_DIR "SANDBOX_DIR"
+#define ENV_SANDBOX_LIB "SANDBOX_LIB"
+
+#define ENV_SANDBOX_DENY "SANDBOX_DENY"
+#define ENV_SANDBOX_READ "SANDBOX_READ"
+#define ENV_SANDBOX_WRITE "SANDBOX_WRITE"
+#define ENV_SANDBOX_PREDICT "SANDBOX_PREDICT"
+
+#define ENV_SANDBOX_ON "SANDBOX_ON"
+#define ENV_SANDBOX_BEEP "SANDBOX_BEEP"
+
+#define DEFAULT_BEEP_COUNT 3
+
+int preload_adaptable = 1;
+int cleaned_up = 0;
+
+char* dirname(const char* path)
+{
+ char* base = NULL;
+ unsigned int length = 0;
+
+ base = strrchr(path, '/');
+ if (NULL == base)
+ {
+ return strdup(".");
+ }
+ while (base > path &&
+ *base == '/')
+ {
+ base--;
+ }
+ length = (unsigned int) 1 + base - path;
+
+ base = malloc(sizeof(char)*(length+1));
+ memmove(base, path, length);
+ base[length] = 0;
+
+ return base;
+}
+
+void cleanup()
+{
+ int i = 0;
+ int success = 1;
+
+ FILE* preload_stream = NULL;
+ int preload_file = -1;
+ char preload_entry[255];
+ char** preload_array = NULL;
+ int num_of_preloads = 0;
+
+ FILE* pids_stream = NULL;
+ struct stat pids_stat;
+ int pids_file = -1;
+ char pid_string[255];
+ int tmp_pid = 0;
+ int* pids_array = NULL;
+ int num_of_pids = 0;
+
+ /* remove this sandbox's bash pid from the global pids file if it has rights to adapt the ld.so.preload file*/
+ if (1 == preload_adaptable &&
+ 0 == cleaned_up)
+ {
+ cleaned_up = 1;
+ success = 1;
+ if (0 == lstat(PIDS_FILE, &pids_stat) &&
+ 0 == S_ISREG(pids_stat.st_mode))
+ {
+ perror(">>> pids file is not a regular file");
+ success = 0;
+ }
+ else
+ {
+ pids_stream = fopen(PIDS_FILE, "r+");
+ if (NULL == pids_stream)
+ {
+ perror(">>> pids file fopen");
+ success = 0;
+ }
+ else
+ {
+ pids_file = fileno(pids_stream);
+ if (pids_file < 0)
+ {
+ perror(">>> pids file fileno");
+ success = 0;
+ }
+ else
+ {
+ if (flock(pids_file, LOCK_EX) < 0)
+ {
+ perror(">>> pids file lock");
+ success = 0;
+ }
+ else
+ {
+ /* check which sandbox pids are still running */
+ while (EOF != fscanf(pids_stream, "%d\n", &tmp_pid))
+ {
+ if (0 == kill(tmp_pid, 0))
+ {
+ if (NULL == pids_array)
+ {
+ pids_array = (int*)malloc(sizeof(int));
+ }
+ else
+ {
+ pids_array = (int*)realloc(pids_array, sizeof(int)*(num_of_pids+1));
+ }
+ pids_array[num_of_pids++] = tmp_pid;
+ }
+ }
+
+ /* clean the /etc/ld.so.preload file if no other sandbox processes are running anymore*/
+ if(num_of_pids == 1)
+ {
+ success = 1;
+ preload_stream = fopen("/etc/ld.so.preload", "r+");
+ if (NULL == preload_stream)
+ {
+ perror(">>> /etc/ld.so.preload file fopen");
+ success = 0;
+ }
+ else
+ {
+ preload_file = fileno(preload_stream);
+ if (preload_file < 0)
+ {
+ perror(">>> /etc/ld.so.preload file fileno");
+ success = 0;
+ }
+ else
+ {
+ if (flock(preload_file, LOCK_EX) < 0)
+ {
+ perror(">>> /etc/ld.so.preload file lock");
+ success = 0;
+ }
+ else
+ {
+ /* only get the entries that don't contain the sandbox library from the /etc/ld.so.preload file */
+ while (EOF != fscanf(preload_stream, "%s\n", preload_entry))
+ {
+ if (NULL == strstr(preload_entry, LIB_NAME))
+ {
+ if (NULL == preload_array)
+ {
+ preload_array = (char**)malloc(sizeof(char*));
+ }
+ else
+ {
+ preload_array = (char**)realloc(pids_array, sizeof(char*)*(num_of_preloads+1));
+ }
+ preload_array[num_of_preloads++] = strdup(preload_entry);
+ }
+ }
+
+ if (fseek(preload_stream, 0, SEEK_SET) < 0)
+ {
+ perror(">>> /etc/ld.so.preload file fseek");
+ success = 0;
+ }
+ else
+ {
+ /* empty the /etc/ld.so.preload file */
+ if (ftruncate(preload_file, 0) < 0)
+ {
+ perror(">>> /etc/ld.so.preload file ftruncate");
+ success = 0;
+ }
+ else
+ {
+ /* store the other preload libraries back into the /etc/ld.so.preload file */
+ if(num_of_preloads > 0)
+ {
+ for (i = 0; i < num_of_preloads; i++)
+ {
+ sprintf(preload_entry, "%s\n", preload_array[i]);
+ if (write(preload_file, preload_entry, strlen(preload_entry)) != strlen(preload_entry))
+ {
+ perror(">>> /etc/ld.so.preload file write");
+ success = 0;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (NULL != preload_array)
+ {
+ for (i = 0; i < num_of_preloads; i++)
+ {
+ free(preload_array[i]);
+ preload_array[i] = NULL;
+ }
+ free(preload_array);
+ preload_array = NULL;
+ }
+
+ if (flock(preload_file, LOCK_UN) < 0)
+ {
+ perror(">>> /etc/ld.so.preload file unlock");
+ success = 0;
+ }
+ }
+ }
+ if (EOF == fclose(preload_stream))
+ {
+ perror(">>> /etc/ld.so.preload file fclose");
+ success = 0;
+ }
+ preload_stream = NULL;
+ preload_file = -1;
+ }
+ }
+
+ if (fseek(pids_stream, 0, SEEK_SET) < 0)
+ {
+ perror(">>> pids file fseek");
+ success = 0;
+ }
+ else
+ {
+ /* empty the pids file */
+ if (ftruncate(pids_file, 0) < 0)
+ {
+ perror(">>> pids file ftruncate");
+ success = 0;
+ }
+ else
+ {
+ /* if pids are still running, write only the running pids back to the file */
+ if(num_of_pids > 1)
+ {
+ for (i = 0; i < num_of_pids; i++)
+ {
+ sprintf(pid_string, "%d\n", pids_array[i]);
+ if (write(pids_file, pid_string, strlen(pid_string)) != strlen(pid_string))
+ {
+ perror(">>> pids file write");
+ success = 0;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (NULL != pids_array)
+ {
+ free(pids_array);
+ pids_array = NULL;
+ }
+
+ if (flock(pids_file, LOCK_UN) < 0)
+ {
+ perror(">>> pids file unlock");
+ success = 0;
+ }
+ }
+ }
+ if (EOF == fclose(pids_stream))
+ {
+ perror(">>> pids file fclose");
+ success = 0;
+ }
+ pids_stream = NULL;
+ pids_file = -1;
+ }
+ }
+ if (0 == success)
+ {
+ exit(1);
+ }
+ }
+}
+
+void stop(int signum)
+{
+ cleanup();
+}
+
+int main(int argc, char** argv)
+{
+ int i = 0;
+ int success = 1;
+ int status = 0;
+ char* run_str = "-c";
+ char run_arg[255];
+
+ struct stat preload_stat;
+ FILE* preload_stream = NULL;
+ int preload_file = -1;
+ char preload_entry[255];
+ int preload_lib_present = 0;
+
+ int bash_pid = 0;
+ char* home_dir = NULL;
+ char portage_tmp_dir[PATH_MAX];
+ char var_tmp_dir[PATH_MAX];
+ char tmp_dir[PATH_MAX];
+ char sandbox_write_var[255];
+ char sandbox_predict_var[255];
+ char* tmp_string = NULL;
+ char full_sandbox_path[255];
+ char sandbox_log[255];
+ char* sandbox_log_env;
+ struct stat sandbox_log_stat;
+ int sandbox_log_presence = 0;
+ int sandbox_log_file = -1;
+ char sandbox_debug_log[255];
+ char sandbox_dir[255];
+ char sandbox_lib[255];
+ struct stat sandbox_lib_stat;
+ char sandbox_rc[255];
+ struct stat sandbox_rc_stat;
+
+ struct stat pids_stat;
+ int pids_file = -1;
+ char pid_string[255];
+
+ // Only print info if called with no arguments ....
+ if (argc < 2)
+ {
+ printf("========================== Gentoo linux path sandbox ===========================\n");
+ }
+
+ /* check if a sandbox is already running */
+ if (NULL != getenv(ENV_SANDBOX_ON))
+ {
+ fprintf(stderr, "Not launching a new sandbox instance\nAnother one is already running in this process hierarchy.\n");
+
+ exit(1);
+ }
+ else
+ {
+ char* argv_bash[] =
+ {
+ "/bin/bash",
+ "-rcfile",
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ };
+
+ /* determine the location of all the sandbox support files */
+ if (argc < 2)
+ printf("Detection of the support files.\n");
+ if ('/' == argv[0][0])
+ {
+ strcpy(full_sandbox_path, argv[0]);
+ }
+ else
+ {
+ tmp_string = get_current_dir_name();
+ strcpy(full_sandbox_path, tmp_string);
+ free(tmp_string);
+ tmp_string = NULL;
+ strcat(full_sandbox_path, "/");
+ strcat(full_sandbox_path, argv[0]);
+ }
+ tmp_string = dirname(full_sandbox_path);
+ strcpy(sandbox_dir, tmp_string);
+ free(tmp_string);
+ tmp_string = NULL;
+ strcat(sandbox_dir, "/");
+ strcpy(sandbox_lib, "/lib/");
+ strcat(sandbox_lib, LIB_NAME);
+ if (-1 == stat(sandbox_lib, &sandbox_lib_stat))
+ {
+ strcpy(sandbox_lib, sandbox_dir);
+ strcat(sandbox_lib, LIB_NAME);
+ }
+ strcpy(sandbox_rc, "/usr/lib/portage/lib/");
+ strcat(sandbox_rc, BASHRC_NAME);
+ if (-1 == stat(sandbox_rc, &sandbox_rc_stat))
+ {
+ strcpy(sandbox_rc, sandbox_dir);
+ strcat(sandbox_rc, BASHRC_NAME);
+ }
+
+ /* verify the existance of required files */
+ if (argc < 2)
+ {
+ printf("Verification of the required files.\n");
+ }
+ if (-1 == stat(sandbox_lib, &sandbox_lib_stat))
+ {
+ fprintf(stderr, "Could not open the sandbox library at '%s'.\n", sandbox_lib);
+ return -1;
+ }
+ else if (-1 == stat(sandbox_rc, &sandbox_rc_stat))
+ {
+ fprintf(stderr, "Could not open the sandbox rc file at '%s'.\n", sandbox_rc);
+ return -1;
+ }
+ else
+ {
+ /* ensure that the /etc/ld.so.preload file contains an entry for the sandbox lib */
+ if (argc < 2)
+ {
+ printf("Setting up the ld.so.preload file.\n");
+ }
+
+ /* check if the /etc/ld.so.preload file exists */
+ if (stat("/etc/ld.so.preload", &preload_stat) < 0 &&
+ ENOENT == errno)
+ {
+ /* if not, try to create it and write the path of the sandbox lib to it */
+ success = 1;
+ preload_file = open("/etc/ld.so.preload", O_WRONLY|O_CREAT, 0644);
+ if (preload_file < 0)
+ {
+ /* if access was denied, warn the user about it */
+ if (EACCES == errno)
+ {
+ preload_adaptable = 0;
+ printf(">>> Couldn't adapt the /etc/ld.so.preload file.\n>>> It's possible that not all function calls are trapped\n");
+ }
+ else
+ {
+ perror(">>> /etc/ld.so.preload file open");
+ success = 0;
+ }
+ }
+ else
+ {
+ if (flock(preload_file, LOCK_EX) < 0)
+ {
+ perror(">>> /etc/ld.so.preload file lock");
+ success = 0;
+ }
+ else
+ {
+ if (write(preload_file, sandbox_lib, strlen(sandbox_lib)) != strlen(sandbox_lib))
+ {
+ perror(">>> /etc/ld.so.preload file write");
+ success = 0;
+ }
+
+ if (flock(preload_file, LOCK_UN) < 0)
+ {
+ perror(">>> /etc/ld.so.preload file unlock");
+ success = 0;
+ }
+ }
+ if (close(preload_file) < 0)
+ {
+ perror(">>> /etc/ld.so.preload file close");
+ success = 0;
+ }
+ pids_file = -1;
+ }
+ if (0 == success)
+ {
+ exit(1);
+ }
+ }
+ else
+ {
+ /* if the /etc/ld.so.preload file exists, try to open it in read/write mode */
+ success = 1;
+ if (0 == S_ISREG(preload_stat.st_mode))
+ {
+ perror(">>> /etc/ld.so.preload file is not a regular file");
+ success = 0;
+ }
+ else
+ {
+ preload_stream = fopen("/etc/ld.so.preload", "r+");
+ if (NULL == preload_stream)
+ {
+ if (EACCES == errno)
+ {
+ /* if access was denied, warn the user about it */
+ preload_adaptable = 0;
+ printf(">>> Couldn't adapt the /etc/ld.so.preload file.\n>>> It's possible that not all function calls are trapped\n");
+ }
+ else
+ {
+ perror(">>> /etc/ld.so.preload file fopen");
+ success = 0;
+ }
+ }
+ else
+ {
+ preload_file = fileno(preload_stream);
+ if (preload_file < 0)
+ {
+ perror(">>> /etc/ld.so.preload file fileno");
+ success = 0;
+ }
+ else
+ {
+ if (flock(preload_file, LOCK_EX) < 0)
+ {
+ perror(">>> /etc/ld.so.preload file lock");
+ success = 0;
+ }
+ else
+ {
+ /* check if the sandbox library is already present in the /etc/ld.so.preload file */
+ while (EOF != fscanf(preload_stream, "%s\n", preload_entry))
+ {
+ if (NULL != strstr(preload_entry, LIB_NAME))
+ {
+ preload_lib_present = 1;
+ break;
+ }
+ }
+
+ /* if it's not present, add the sandbox lib path to the end of the /etc/ld.so.preload file */
+ if (0 == preload_lib_present)
+ {
+ if (fseek(preload_stream, 0, SEEK_END) < 0)
+ {
+ perror(">>> /etc/ld.so.preload file fseek");
+ success = 0;
+ }
+ else
+ {
+ if (write(preload_file, sandbox_lib, strlen(sandbox_lib)) != strlen(sandbox_lib))
+ {
+ perror(">>> /etc/ld.so.preload file write");
+ success = 0;
+ }
+ }
+ }
+
+ if (flock(preload_file, LOCK_UN) < 0)
+ {
+ perror(">>> /etc/ld.so.preload file unlock");
+ success = 0;
+ }
+ }
+ }
+ if (EOF == fclose(preload_stream))
+ {
+ perror(">>> /etc/ld.so.preload file fclose");
+ success = 0;
+ }
+ preload_stream = NULL;
+ preload_file = -1;
+ }
+ }
+ if (0 == success)
+ {
+ exit(1);
+ }
+ }
+
+ /* set up the required environment variables */
+ if (argc < 2)
+ {
+ printf("Setting up the required environment variables.\n");
+ }
+ argv_bash[2] = sandbox_rc;
+
+ sprintf(pid_string, "%d", getpid());
+ strcpy(sandbox_log, LOG_FILE_PREFIX);
+ sandbox_log_env = getenv(ENV_SANDBOX_LOG);
+ if (sandbox_log_env)
+ {
+ strcat(sandbox_log, sandbox_log_env);
+ strcat(sandbox_log, "-");
+ }
+ strcat(sandbox_log, pid_string);
+ strcat(sandbox_log, LOG_FILE_EXT);
+ setenv(ENV_SANDBOX_LOG, sandbox_log, 1);
+ strcpy(sandbox_debug_log, DEBUG_LOG_FILE_PREFIX);
+ strcat(sandbox_debug_log, pid_string);
+ strcat(sandbox_debug_log, LOG_FILE_EXT);
+ setenv(ENV_SANDBOX_DEBUG_LOG, sandbox_debug_log, 1);
+ home_dir = getenv("HOME");
+
+ // drobbins: we need to expand these paths using realpath() so that PORTAGE_TMPDIR
+ // can contain symlinks (example, /var is a symlink, /var/tmp is a symlink.) Without
+ // this, access is denied to /var/tmp, hurtin' ebuilds.
+
+ realpath(getenv("PORTAGE_TMPDIR"),portage_tmp_dir);
+ realpath("/var/tmp",var_tmp_dir);
+ realpath("/tmp",tmp_dir);
+
+ setenv(ENV_SANDBOX_DIR, sandbox_dir, 1);
+ setenv(ENV_SANDBOX_LIB, sandbox_lib, 1);
+ setenv("LD_PRELOAD", sandbox_lib, 1);
+ if (NULL == getenv(ENV_SANDBOX_DENY))
+ {
+ setenv(ENV_SANDBOX_DENY, LD_PRELOAD_FILE, 1);
+ }
+ if (NULL == getenv(ENV_SANDBOX_READ))
+ {
+ setenv(ENV_SANDBOX_READ, "/", 1);
+ }
+ if (NULL == getenv(ENV_SANDBOX_WRITE))
+ {
+ /* these should go into make.globals later on */
+ strcpy(sandbox_write_var, "");
+ strcat(sandbox_write_var, "/dev/zero:/dev/fd/:/dev/null:/dev/pts/:/dev/vc/:/dev/tty:/tmp/");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/var/log/scrollkeeper.log");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, home_dir);
+ strcat(sandbox_write_var, "/.gconfd/lock");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, home_dir);
+ strcat(sandbox_write_var, "/.bash_history");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/usr/tmp/conftest");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/usr/lib/conftest");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/usr/tmp/cf");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/usr/lib/cf");
+ strcat(sandbox_write_var, ":");
+ if (NULL == portage_tmp_dir)
+ {
+ strcat(sandbox_write_var, tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, var_tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/tmp/");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/var/tmp/");
+ }
+ else if (0 == strcmp(sandbox_write_var, "/var/tmp/"))
+ {
+ strcat(sandbox_write_var, portage_tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/tmp/");
+ }
+ else if (0 == strcmp(sandbox_write_var, "/tmp/"))
+ {
+ strcat(sandbox_write_var, portage_tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, var_tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/var/tmp/");
+ }
+ else
+ {
+ strcat(sandbox_write_var, portage_tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, var_tmp_dir);
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/tmp/");
+ strcat(sandbox_write_var, ":");
+ strcat(sandbox_write_var, "/var/tmp/");
+ }
+ /* */
+ setenv(ENV_SANDBOX_WRITE, sandbox_write_var, 1);
+ }
+ if (NULL == getenv(ENV_SANDBOX_PREDICT))
+ {
+ /* these should go into make.globals later on */
+ strcpy(sandbox_predict_var, "");
+ strcat(sandbox_predict_var, home_dir);
+ strcat(sandbox_predict_var, "/.");
+ strcat(sandbox_predict_var, ":");
+ strcat(sandbox_predict_var, "/usr/lib/python2.0/");
+ strcat(sandbox_predict_var, ":");
+ strcat(sandbox_predict_var, "/usr/lib/python2.1/");
+ strcat(sandbox_predict_var, ":");
+ strcat(sandbox_predict_var, "/usr/lib/python2.2/");
+ setenv(ENV_SANDBOX_PREDICT, sandbox_predict_var, 1);
+ /* */
+ }
+ setenv(ENV_SANDBOX_ON, "1", 0);
+
+ /* if the portage temp dir was present, cd into it */
+ if (NULL != portage_tmp_dir)
+ {
+ chdir(portage_tmp_dir);
+ }
+
+ /* adding additional bash arguments */
+ for (i = 1; i < argc; i++)
+ {
+ if (1 == i)
+ {
+ argv_bash[3] = run_str;
+ argv_bash[4] = run_arg;
+ strcpy(argv_bash[4], argv[i]);
+ }
+ else
+ {
+ strcat(argv_bash[4], " ");
+ strcat(argv_bash[4], argv[i]);
+ }
+ }
+
+ /* set up the required signal handlers */
+ signal(SIGHUP, &stop);
+ signal(SIGINT, &stop);
+ signal(SIGQUIT, &stop);
+ signal(SIGTERM, &stop);
+
+ /* this one should NEVER be set in ebuilds, as it is the one
+ * private thing libsandbox.so use to test if the sandbox
+ * should be active for this pid, or not.
+ *
+ * azarah (3 Aug 2002)
+ */
+ setenv("SANDBOX_ACTIVE", "armedandready", 1);
+
+ /* fork to executing bash */
+ if (argc < 2)
+ {
+ printf("Creating a seperate process the run the shell in.\n");
+ }
+ bash_pid = fork();
+
+ if (0 == bash_pid)
+ {
+ /* launch bash */
+ execv(argv_bash[0], argv_bash);
+ }
+ else
+ {
+ int wait_pid = 0;
+
+ if (argc < 2)
+ {
+ printf("The protected environment has been started.\n");
+ printf("--------------------------------------------------------------------------------\n");
+ }
+
+ /* store his sandbox's bash pid in the global pids file if it has rights to adapt the ld.so.preload file*/
+ if (1 == preload_adaptable)
+ {
+ success = 1;
+ if (0 == lstat(PIDS_FILE, &pids_stat) &&
+ 0 == S_ISREG(pids_stat.st_mode))
+ {
+ perror(">>> pids file is not a regular file");
+ success = 0;
+ }
+ else
+ {
+ pids_file = open(PIDS_FILE, O_WRONLY|O_CREAT|O_APPEND, 0644);
+ if (pids_file < 0)
+ {
+ perror(">>> pids file open");
+ success = 0;
+ }
+ else
+ {
+ if (flock(pids_file, LOCK_EX) < 0)
+ {
+ perror(">>> pids file lock");
+ success = 0;
+ }
+ else
+ {
+ sprintf(pid_string, "%d\n", getpid());
+ if (write(pids_file, pid_string, strlen(pid_string)) != strlen(pid_string))
+ {
+ perror(">>> pids file write");
+ success = 0;
+ }
+
+ if (flock(pids_file, LOCK_UN) < 0)
+ {
+ perror(">>> pids file unlock");
+ success = 0;
+ }
+ }
+ if (close(pids_file) < 0)
+ {
+ perror(">>> pids file close");
+ success = 0;
+ }
+ pids_file = -1;
+ }
+ }
+ if (0 == success)
+ {
+ exit(1);
+ }
+ }
+
+ /* wait until bash exits */
+ wait_pid = waitpid(bash_pid, &status, 0);
+ }
+ }
+
+ cleanup();
+
+ if (argc < 2)
+ {
+ printf("========================== Gentoo linux path sandbox ===========================\n");
+ printf("The protected environment has been shut down.\n");
+ }
+ if (0 == stat(sandbox_log, &sandbox_log_stat))
+ {
+ sandbox_log_presence = 1;
+ success = 1;
+ sandbox_log_file = open(sandbox_log, O_RDONLY, 0);
+ if (sandbox_log_file < 0)
+ {
+ perror(">>> sandbox log file open");
+ success = 0;
+ }
+ else
+ {
+ int i = 0;
+ char* beep_count_env = NULL;
+ int beep_count = 0;
+ int length = 0;
+ char buffer[255];
+
+ printf("\e[31;01m--------------------------- ACCESS VIOLATION SUMMARY ---------------------------\033[0m\n");
+ printf("\e[31;01mLOG FILE = \"%s\"\033[0m\n", sandbox_log);
+ printf("\n");
+ while ((length = read(sandbox_log_file, buffer, sizeof(buffer)-1)) > 0)
+ {
+ if (length < sizeof(buffer))
+ {
+ buffer[length] = 0;
+ }
+ printf("%s", buffer);
+ }
+ printf("\e[31;01m--------------------------------------------------------------------------------\033[0m\n");
+
+ if (close(sandbox_log_file) < 0)
+ {
+ perror(">>> sandbox log close");
+ success = 0;
+ }
+
+ beep_count_env = getenv(ENV_SANDBOX_BEEP);
+ if (beep_count_env)
+ {
+ beep_count = atoi(beep_count_env);
+ }
+ else
+ {
+ beep_count = DEFAULT_BEEP_COUNT;
+ }
+ for (i = 0; i < beep_count; i++)
+ {
+ fputc('\a', stderr);
+ if (i < beep_count -1)
+ {
+ sleep(1);
+ }
+ }
+
+ }
+ if (0 == success)
+ {
+ exit(1);
+ }
+ sandbox_log_file = -1;
+ }
+ else if (argc < 2)
+ {
+ printf("--------------------------------------------------------------------------------\n");
+ }
+
+ if (status > 0 ||
+ 1 == sandbox_log_presence)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+}
diff --git a/src/tbz2tool.c b/src/tbz2tool.c
new file mode 100644
index 00000000..c740d443
--- /dev/null
+++ b/src/tbz2tool.c
@@ -0,0 +1,228 @@
+/* $Header: /var/cvsroot/gentoo-src/portage/src/tbz2tool.c,v 1.3.2.1 2004/11/05 13:49:22 jstubbs Exp $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+/*buffered reading/writing size*/
+#define BUFLEN 262144
+char *myname="tbz2tool";
+struct stat *mystat=NULL;
+void *mybuf;
+FILE *datafile, *dbfile, *outfile, *infile;
+unsigned char endbuf[8];
+long seekto,insize;
+
+int exists(const char *myfile) {
+ int result;
+ result=stat(myfile,mystat);
+ if (result==-1)
+ return 0;
+ return 1;
+}
+
+void writefile(FILE *src, FILE *dest) {
+ int count=1;
+ while (count) {
+ count=fread(mybuf, 1, BUFLEN, src);
+ fwrite(mybuf, 1, count, dest);
+ }
+}
+
+void writefileto(FILE *src, FILE *dest, int endpos) {
+ int pos=ftell(src);
+ int thiscount;
+ while (pos < endpos) {
+ /* thiscount=how much to read */
+ thiscount=endpos-pos;
+ if (thiscount>BUFLEN)
+ thiscount=BUFLEN;
+ thiscount=fread(mybuf, 1, thiscount , src);
+ /* thiscount=how much we actually did read */
+ if (thiscount==0)
+ /* eof -- shouldn't happen */
+ break;
+ /* update internal position counter */
+ pos+=thiscount;
+ fwrite(mybuf, 1, thiscount, dest);
+ }
+}
+
+int main(int argc, char **argv) {
+ if ((argc==2) && (!(strcmp(argv[1],"--help"))))
+ goto usage;
+ if (argc!=5) {
+ printf("%s: four arguments expected\n",myname);
+ goto error;
+ }
+ if (!(mystat=(struct stat *) malloc(sizeof(struct stat))))
+ goto memalloc;
+
+ if (!(mybuf=(void *) malloc(BUFLEN))) {
+ free(mystat);
+ goto memalloc;
+ }
+
+ /* JOIN MODE */
+ if (!(strcmp(argv[1],"join"))) {
+
+ /* check if datafile exists */
+ if (!(exists(argv[2]))) {
+ printf("%s: %s doesn't exist\n",myname,argv[2]);
+ free(mystat);
+ goto error;
+ }
+
+ /* check if dbfile exists */
+ if (!(exists(argv[3]))) {
+ printf("%s: %s doesn't exist\n",myname,argv[3]);
+ free(mystat);
+ goto error;
+ }
+ /* create end buffer for later use */
+ endbuf[0]=((mystat->st_size) & 0xff000000) >> 24;
+ endbuf[1]=((mystat->st_size) & 0x00ff0000) >> 16;
+ endbuf[2]=((mystat->st_size) & 0x0000ff00) >> 8;
+ endbuf[3]=(mystat->st_size) & 0x000000ff;
+ endbuf[4]='S';
+ endbuf[5]='T';
+ endbuf[6]='O';
+ endbuf[7]='P';
+
+ /* if outfile exists, unlink first (safer) */
+ if (exists(argv[4]))
+ unlink(argv[4]);
+
+ /* open datafile for reading */
+ if ((datafile=fopen(argv[2],"r"))==NULL) {
+ free(mybuf);
+ free(mystat);
+ printf("%s: Error opening %s\n",myname,argv[2]);
+ goto error;
+ }
+
+ /* open dbfile for reading */
+ if ((dbfile=fopen(argv[3],"r"))==NULL) {
+ fclose(datafile);
+ free(mybuf);
+ free(mystat);
+ printf("%s: Error opening %s\n",myname,argv[3]);
+ goto error;
+ }
+
+ /* open outfile for writing */
+ if ((outfile=fopen(argv[4],"a"))==NULL) {
+ fclose(dbfile);
+ fclose(datafile);
+ free(mybuf);
+ free(mystat);
+ printf("%s: Error opening %s\n",myname,argv[4]);
+ goto error;
+ }
+
+ writefile(datafile,outfile);
+ writefile(dbfile,outfile);
+ fwrite(endbuf,1,8,outfile);
+ fclose(outfile);
+ fclose(dbfile);
+ fclose(datafile);
+ free(mybuf);
+ free(mystat);
+ exit(0);
+
+ /* SPLIT MODE */
+ } else if (!(strcmp(argv[1],"split"))) {
+
+ /* check if infile exists */
+ if (!(exists(argv[2]))) {
+ printf("%s: %s doesn't exist\n",myname,argv[2]);
+ free(mystat);
+ goto error;
+ }
+
+ /* store infile size for later use */
+
+ insize=mystat->st_size;
+
+ /* if datafile exists, unlink first (safer) */
+ if (exists(argv[3]))
+ unlink(argv[3]);
+
+ /* if dbfile exists, unlink first (safer) */
+ if (exists(argv[4]))
+ unlink(argv[4]);
+
+ /* open infile for reading */
+ if ((infile=fopen(argv[2],"r"))==NULL) {
+ free(mybuf);
+ free(mystat);
+ printf("%s: Error opening %s\n",myname,argv[2]);
+ goto error;
+ }
+
+ /* read in end buffer */
+ fseek(infile,-8,SEEK_END);
+ fread(endbuf,1,8,infile);
+ /* quick end buffer read and verification */
+ if ( (endbuf[4]!='S') || (endbuf[5]!='T') || (endbuf[6]!='O') || (endbuf[7]!='P') ) {
+ fclose(infile);
+ free(mybuf);
+ free(mystat);
+ printf("%s: %s appears to be corrupt (end buffer invalid)\n",myname,argv[2]);
+ goto error;
+ }
+
+ seekto=0;
+ seekto=seekto+endbuf[0]*256*256*256;
+ seekto=seekto+endbuf[1]*256*256;
+ seekto=seekto+endbuf[2]*256;
+ seekto=seekto+endbuf[3];
+
+ /* open datafile for writing */
+ if ((datafile=fopen(argv[3],"a"))==NULL) {
+ fclose(infile);
+ free(mybuf);
+ free(mystat);
+ printf("%s: Error opening %s\n",myname,argv[3]);
+ goto error;
+ }
+
+ /* open dbfile for writing */
+ if ((dbfile=fopen(argv[4],"a"))==NULL) {
+ fclose(datafile);
+ fclose(infile);
+ free(mybuf);
+ free(mystat);
+ printf("%s: Error opening %s\n",myname,argv[4]);
+ goto error;
+ }
+
+ rewind(infile);
+ writefileto(infile,datafile,insize-(seekto+8));
+ fseek(infile,-(seekto+8),SEEK_END);
+ writefileto(infile,dbfile,insize-8);
+ fclose(infile);
+ fclose(dbfile);
+ fclose(datafile);
+ free(mybuf);
+ free(mystat);
+ exit(0);
+
+ } else {
+ free(mybuf);
+ free(mystat);
+ goto usage;
+ }
+
+ usage:
+ printf("Usage: %s join DATAFILE DBFILE OUTFILE (datafile + dbfile -> outfile)\n %s split INFILE DATAFILE DBFILE (infile -> datafile + dbfile)\n",myname,myname);
+error:
+ exit(1);
+memalloc:
+ printf("%s: memory allocation error\n",myname);
+ exit(2);
+}