initial checkin
authorEnrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
Tue, 30 Sep 2003 15:59:35 +0000 (15:59 +0000)
committerEnrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
Tue, 30 Sep 2003 15:59:35 +0000 (15:59 +0000)
git-svn-id: http://svn.linux-vserver.org/svn/util-vserver/trunk@10 94cd875c-1c1d-0410-91d2-eb244daf1a30

15 files changed:
util-vserver/lib/.cvsignore [new file with mode: 0644]
util-vserver/scripts/.cvsignore [new file with mode: 0644]
util-vserver/scripts/functions [new file with mode: 0644]
util-vserver/scripts/vapt-get [new file with mode: 0755]
util-vserver/scripts/vapt-get-worker [new file with mode: 0755]
util-vserver/scripts/vrpm-preload [new file with mode: 0755]
util-vserver/scripts/vrpm-worker [new file with mode: 0755]
util-vserver/scripts/vserver-init [new file with mode: 0755]
util-vserver/src/.cvsignore [new file with mode: 0644]
util-vserver/src/new-namespace.c [new file with mode: 0644]
util-vserver/src/rpm-fake.c [new file with mode: 0644]
util-vserver/src/secure-mount.c [new file with mode: 0644]
util-vserver/src/util.h [new file with mode: 0644]
util-vserver/sysv/.cvsignore [new file with mode: 0644]
util-vserver/tests/.cvsignore [new file with mode: 0644]

diff --git a/util-vserver/lib/.cvsignore b/util-vserver/lib/.cvsignore
new file mode 100644 (file)
index 0000000..ec96903
--- /dev/null
@@ -0,0 +1,2 @@
+.deps
+.dirstamp
diff --git a/util-vserver/scripts/.cvsignore b/util-vserver/scripts/.cvsignore
new file mode 100644 (file)
index 0000000..7f4fdef
--- /dev/null
@@ -0,0 +1,2 @@
+.deps
+util-vserver-vars
diff --git a/util-vserver/scripts/functions b/util-vserver/scripts/functions
new file mode 100644 (file)
index 0000000..959a2aa
--- /dev/null
@@ -0,0 +1,216 @@
+# $Id$ --*- sh -*--
+
+# Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+#  
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#  
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#  
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+function findObject
+{
+    local mod=$1
+    local var=$2
+    local file=
+    local i=X
+    shift 2
+    
+    for i; do
+       test "$i"        || continue
+       test ! $mod "$i" || { file=$i; break; }
+    done
+
+    test -z "$i" -o "$file" || {
+       echo "Can not find file for '$var'; aborting"
+       exit 1
+    } >&2
+
+    eval "$var=\"$file\""
+}
+
+function findFile
+{
+    findObject -f "$@"
+}
+
+function findDir
+{
+    findObject -d "$@"
+}
+
+function getPhysicalDir
+{
+    ( set -P && cd "$1" && pwd )
+}
+
+function _pkgMountBindDir()
+{
+    test "$1" != "$2" || return 0
+
+    mount -n --bind "$1" "$2"
+}
+
+function _pkgSetVarsBase
+{
+    case "$vserver" in
+       /*)
+           echo "not supported yet"
+           exit 1
+           ;;
+        *)
+           BASEDIR=$CONFDIR/$vserver
+           test -d "$BASEDIR" || {
+               echo "Can not find configuration-directory"
+               exit 1
+           }
+           
+           VDIR=$BASEDIR/vdir
+           test -d "$VDIR"   || VDIR=/vservers/$vserver
+           VDIR=$(getPhysicalDir "$VDIR")
+           
+           PKGDIR=$BASEDIR/apps/pkgmgmt
+           test -d "$PKGDIR" || {
+               echo "Can not find configuration-directory for package-managment tools"
+               exit 1
+           }
+
+           findDir EXECDIR      $PKGDIR/execdir     /
+
+           ;;
+    esac
+}
+
+function _pkgSetVarsRPM
+{
+    case "$vserver" in
+       /*)
+           echo "not supported yet"
+           exit 1
+           ;;
+           
+        *)
+           findDir RPMETCDIR    $PKGDIR/rpmetc      $PKGDIR/base/rpm/etc       /etc/rpm
+           findDir RPMSTATEDIR  $PKGDIR/rpmstate    $PKGDIR/base/rpm/state
+
+           findDir RPMLIBDIR    $PKGDIR/rpmlib  /
+
+           RPMSTATEDIR=$(getPhysicalDir "$RPMSTATEDIR")
+           RPMETCDIR=$(getPhysicalDir "$RPMETCDIR")
+           ;;
+    esac
+}
+
+function _pkgSetVarsApt
+{
+    case "$vserver" in
+       /*)
+           echo "not supported yet"
+           exit 1
+           ;;
+           
+        *)
+           findDir APTETCDIR    $PKGDIR/aptetc      $PKGDIR/base/apt/etc       /etc/apt
+           findDir APTSTATEDIR  $PKGDIR/aptstate    $PKGDIR/base/apt/state
+           findDir APTCACHEDIR  $PKGDIR/aptcache    $PKGDIR/base/apt/cache
+           findDir APTARCHIVDIR $PKGDIR/aptarchives $PKGDIR/base/apt/archives  /var/cache/apt/archives
+           ;;
+    esac
+}
+
+function _pkgMountBase
+{
+    :
+}
+
+function _pkgMountApt
+{
+    :
+}
+
+function _pkgMountRPM
+{
+    _pkgMountBindDir "$RPMETCDIR" /etc/rpm
+    test "$RPMLIBDIR" = "/" || _pkgMountBindDir "$RPMLIBDIR" /usr/lib/rpm
+    "$_SECURE_MOUNT" "$VDIR" "$RPMSTATEDIR" /var/lib/rpm
+}
+
+function _pkgSetEnvBase
+{
+    test "$EXECDIR"   = "/" || {
+       PATH=$EXECDIR:$PATH
+       LD_LIBRARY_PATH=$EXECDIR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
+    }
+
+    export PATH LD_LIBRARY_PATH
+}
+
+function _pkgSetEnvApt
+{
+    :
+}
+
+function _pkgSetEnvRPM
+{
+    CUR_VSERVER=$vserver
+    RPM_FAKE_NAMESPACE_MOUNTS=/var/lib/rpm
+    RPM_BINARY=$_VRPM_PRELOAD
+
+    export CUR_VSERVER RPM_FAKE_NAMESPACE_MOUNTS RPM_BINARY
+}
+
+function pkgInit
+{
+    local i
+    local vserver=$1
+    shift
+    
+    _pkgSetVarsBase
+    for i; do
+       case "$i" in
+           rpm)        _pkgSetVarsRPM;;
+           apt)        _pkgSetVarsApt;;
+           *)          echo "Unknown packaging flavor"; exit 1;;
+       esac
+    done
+
+    _pkgMountBase
+    for i; do
+       case "$i" in
+           rpm)        _pkgMountRPM;;
+           apt)        _pkgMountApt;;
+       esac
+    done
+
+    _pkgSetEnvBase
+    for i; do
+       case "$i" in
+           rpm)        _pkgSetEnvRPM;;
+           apt)        _pkgSetEnvApt;;
+       esac
+    done
+
+    _PKG_FLAVORS="$@"
+    _PKG_VSERVER=$vserver
+}
+
+function getAllVservers
+{
+    local i
+    local var=$1
+
+    for i in $CONFDIR/*; do
+       test   -d "$i"          || continue
+       test ! -e "$i"/disabled || continue
+       test   -d "$i"/vdir     || continue
+
+       eval "$var=\"$var ${i##$CONFDIR/}\""
+    done
+}
diff --git a/util-vserver/scripts/vapt-get b/util-vserver/scripts/vapt-get
new file mode 100755 (executable)
index 0000000..0820003
--- /dev/null
@@ -0,0 +1,73 @@
+#! /bin/bash
+
+# Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+#  
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#  
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#  
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+: ${UTIL_VSERVER_VARS:=$(dirname $0)/util-vserver-vars}
+test -e "$UTIL_VSERVER_VARS" || {
+    echo "Can not find util-vserver installation; aborting..."
+    exit 1
+}
+. "$UTIL_VSERVER_VARS"
+. "$_LIB_FUNCTIONS"
+
+function showHelp()
+{
+    echo "Usage: $0 <vserver-name>* [--all] -- <params>+"
+    exit $1
+}
+
+function showVersion()
+{
+    cat <<EOF 
+vapt-get 0.23.5 -- apt-get for vservers
+Copyright (C) 2003 Enrico Scholz
+This program is free software; you may redistribute it under the terms of
+the GNU General Public License.  This program has absolutely no warranty.
+EOF
+    exit $1
+}
+
+vservers=
+
+while test "$#" -ge 1; do
+    case "$1" in
+       --all)
+           getAllVservers tmp
+           vservers="$vservers $tmp";;
+       --)
+           shift; break;;
+       --help)
+           showHelp 0;;
+       --version)
+           showVersion 0;;
+       *)  vservers="$vservers $1";;
+     esac
+     shift
+done
+
+test "$#" -ge 1 || showHelp 1 >&2
+
+cnt=0
+res=255
+for i in $vservers; do
+    cnt=$[ cnt + 1 ]
+    _APT_GET=apt-get \
+    "$_NEW_NAMESPACE" "$_VAPT_GET_WORKER" "$i" "$@"
+    res=$?
+done
+
+test "$cnt" -ge 0 || echo "No vservers specified" >&2
+exit $res
\ No newline at end of file
diff --git a/util-vserver/scripts/vapt-get-worker b/util-vserver/scripts/vapt-get-worker
new file mode 100755 (executable)
index 0000000..260381e
--- /dev/null
@@ -0,0 +1,53 @@
+#! /bin/bash -e
+# $Id$
+
+# Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+#  
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#  
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#  
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+: ${UTIL_VSERVER_VARS:=$(dirname $0)/util-vserver-vars}
+test -e "$UTIL_VSERVER_VARS" || {
+    echo "Can not find util-vserver installation; aborting..."
+    exit 1
+}
+. "$UTIL_VSERVER_VARS"
+. "$_LIB_FUNCTIONS"
+
+
+function createAptFileSys()
+{
+    mkdir -p /var/state/apt/lists/partial
+    mkdir -p /var/cache/apt/archives/partial
+}
+
+vserver="$1"
+shift
+
+pkgInit "$vserver" rpm apt
+
+createAptFileSys
+
+$_APT_GET -o "RPM::RootDir=$VDIR" \
+          -o "Dir=$VDIR" \
+         -o "Dir::State=$APTSTATEDIR" \
+         -o "Dir::Cache=$APTCACHEDIR" \
+         -o "Dir::Cache::archives=$APTARCHIVDIR" \
+         -o "Dir::Bin::rpm=$RPM_BINARY" \
+         -o "Dir::Etc=$APTETCDIR" \
+         -o "RPM::Order=true" \
+         "$@"
+
+export PS1='@@ '
+exec bash
diff --git a/util-vserver/scripts/vrpm-preload b/util-vserver/scripts/vrpm-preload
new file mode 100755 (executable)
index 0000000..50a5f5c
--- /dev/null
@@ -0,0 +1,55 @@
+#! /bin/bash -x
+
+: ${UTIL_VSERVER_VARS:=$(dirname $0)/util-vserver-vars}
+test -e "$UTIL_VSERVER_VARS" || {
+    echo "Can not find util-vserver installation; aborting..."
+    exit 1
+}
+. "$UTIL_VSERVER_VARS"
+
+lib=$_RPM_FAKE_SO
+
+function getSyscallParams
+{
+    set -- `grep '^__NR_new_s_context:' /proc/self/status`
+    scall_nr=$2
+    test "$3" && scall_rev=${3##rev}
+}
+
+need_cfg=
+case "$CUR_VSERVER" in
+    /*)        vdir=$CUR_VSERVER;;
+    *)  vdir=$CONFDIR/$CUR_VSERVER/vdir
+       need_cfg=1;;
+esac
+
+test "$CUR_VSERVER" -a -d "$vdir" || {
+    echo "No or invalid vserver-name given"
+    exit 1
+}
+
+ctxfile=/var/run/vservers/${CUR_VSERVER}.ctx
+if test -f "$ctxfile"; then
+    . "$ctxfile"
+else
+    S_CONTEXT=
+fi
+
+for bin in `which rpm` /bin/rpm /usr/lib/rpm/rpmi ""; do
+    ldd "$bin" &>/dev/null && break
+done
+
+test "$bin" || {
+    echo "No dynamically linked rpm binary found; exiting..."
+    exit 1
+}
+
+
+getSyscallParams
+
+RPM_FAKE_S_CONTEXT_REV=$scall_rev \
+RPM_FAKE_S_CONTEXT_NR=$scall_nr \
+RPM_FAKE_CTX=$S_CONTEXT \
+RPM_FAKE_CAP=$[ ~0x3404040f ] \
+LD_PRELOAD=$lib${LD_PRELOAD:+:$LD_PRELOAD} \
+exec $bin "$@"
diff --git a/util-vserver/scripts/vrpm-worker b/util-vserver/scripts/vrpm-worker
new file mode 100755 (executable)
index 0000000..85cfd28
--- /dev/null
@@ -0,0 +1,34 @@
+#! /bin/bash -e
+# $Id$
+
+# Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+#  
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#  
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#  
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+set -x
+
+: ${UTIL_VSERVER_VARS:=$(dirname $0)/util-vserver-vars}
+test -e "$UTIL_VSERVER_VARS" || {
+    echo "Can not find util-vserver installation; aborting..."
+    exit 1
+}
+. "$UTIL_VSERVER_VARS"
+. "$_LIB_FUNCTIONS"
+
+vserver=$1
+shift
+
+pkgInit "$vserver" rpm
+
+exec $RPM_BINARY --root "$VDIR" "$@"
\ No newline at end of file
diff --git a/util-vserver/scripts/vserver-init b/util-vserver/scripts/vserver-init
new file mode 100755 (executable)
index 0000000..e3ad989
--- /dev/null
@@ -0,0 +1,170 @@
+#! /bin/bash -e
+
+# Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+#  
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#  
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#  
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+: ${UTIL_VSERVER_VARS:=$(dirname $0)/util-vserver-vars}
+test -e "$UTIL_VSERVER_VARS" || {
+    echo "Can not find util-vserver installation; aborting..."
+    exit 1
+}
+. "$UTIL_VSERVER_VARS"
+. "$PKGLIBDIR/functions"
+
+tmp=$(getopt -o d:r: --long force,dir:,pkgcfg:,hostname:,iproot:,iprootmask:,iprootbcast:,iprootdev:,help,version \
+      -n "$0" -- "$@") || exit 1
+
+eval set -- "$tmp"
+
+distrib=
+root=/vservers
+dir=
+name=
+hostname=
+iproot=
+iprootmask=
+iprootbcast=
+iprootdev=
+force=
+pkgcfg=
+
+
+function makeInode
+{
+    mknod -m$6 $1/$2 $3 $4 $5
+}
+
+function installBasePackages
+{
+    local name="$1"
+    local dir="$2"
+
+    test "$dir" != / || return
+    for filelist in "$dir"/*; do
+       test -e "$filelist" || continue
+       local idx=0
+       local can_fail=false
+       local flags=
+
+       set -- $(<$filelist)
+       while test "$#" -gt 0; do
+           case "$1" in
+               --reinstall) flags='--reinstall';;
+               --can-fail)  can_fail=true;;
+               *)           break;;
+           esac
+           shift
+       done
+       "$_VAPT_GET" "$name" -- install $flags "$@"  || $can_fail
+    done
+}
+
+while true; do
+    case "$1" in
+       -d)             distrib="$2"; shift 2;;
+       -r)             root="$2";    shift 2;;
+       --pkgcfg)       pkgcfg="$2";  shift 2;;
+       --force)        force=1;      shift;;
+       --dir)          dir="$2";     shift 2;;
+       --hostname)     hostname="$2"; shift 2;;
+       --iproot)       iproot="$2";   shift 2;;
+       --iprootmask)   iprootmask="$2";  shift 2;;
+       --iprootbcast)  iprootbcast="$2"; shift 2;;
+       --iprootdev)    iprootdev="$2";   shift 2;;
+       --help)         showHelp;         exit 0;;
+       --version)      showVersion;      exit 0;;
+       --)             shift; break;;
+       *)              echo "Internal error!"; exit 1;;
+    esac
+done
+
+test "$#" != 0 || {
+    echo "No vserver name given" >&2
+    exit 1
+}
+
+test "$#" = 1 || {
+    echo "Too much parameters" >&2
+    exit 1
+}
+
+name=$1
+test "$dir"    || dir=$name
+test "$pkgcfg" || pkgcfg=$root/.pkg/$name
+
+vdir=$root/$dir
+test ! -d "$vdir"  || {
+    test "$force" && mv "$vdir"    "$vdir".bak
+}
+
+confdir="$CONFDIR/$name"
+test ! -d "$confdir" || {
+    test "$force" && mv "$confdir" "$confdir".bak
+}
+
+test ! -d "$vdir" -a ! -d "$confdir" || {
+    echo "vserver-topdirectory and/or configuration exist already; "
+    echo "please try to use '--force', or remove them manually"
+    exit 1
+} >&2
+
+test "$distrib" || {
+    if test -e /etc/redhat-release; then
+       set -- $(cat /etc/redhat-release)
+       distrib=rh$5
+    else
+       echo "Can not determine distribution; please specify it manually"
+       echo "with the '-d' option"
+       exit 1
+    fi >&2
+}
+
+findFile INITPRE  $CONFDIR/.distributions/$distrib/initpre  $DISTRIBDIR/$distrib/initpre       ""
+findFile INITPOST $CONFDIR/.distributions/$distrib/initpost $DISTRIBDIR/$distrib/initpost      ""
+findFile DEVDESCR $CONFDIR/.distributions/$distrib/devs     $DISTRIBDIR/$distrib/devs          $DISTRIBDIR/defaults/devs
+findDir  APTTMPL  $CONFDIR/.distributions/$distrib/apt      $DISTRIBDIR/$distrib/apt
+findDir  RPMTMPL  $CONFDIR/.distributions/$distrib/rpm      $DISTRIBDIR/$distrib/rpm           $DISTRIBDIR/defaults/rpm
+findDir  EXECDIR  $CONFDIR/.distributions/$distrib/execdir  $DISTRIBDIR/$distrib/execdir       /
+findDir  RPMLIB   $CONFDIR/.distributions/$distrib/rpmlib   $DISTRIBDIR/$distrib/rpmlib        /
+findDir  PKGDIR   $CONFDIR/.distributions/$distrib/pkgs     $DISTRIBDIR/$distrib/pkgs          /
+
+mkdir -p "$confdir"/apps/pkgmgmt "$vdir"/{dev,/var/lib/rpm,/etc} \
+         "$pkgcfg"/{rpm/{etc,state},apt/{etc,archives/partial,cache,state/lists/partial}}
+while read spec; do
+    makeInode "$vdir"/dev $spec
+done <$DEVDESCR
+
+ln -s "$vdir" "$confdir"/vdir
+for i in hostname iproot iprootmask iprootbcast iprootdev; do
+    i_=\$$i
+    eval "v=$i_"
+    test -z "$v" || echo $v >"$confdir/$i"
+done
+
+ln -s "$pkgcfg" "$confdir/apps/pkgmgmt/base"
+test "$EXECDIR" = / || ln -s "$EXECDIR" "$confdir/apps/pkgmgmt/execdir"
+test "$RPMLIB"  = / || ln -s "$RPMLIB"  "$confdir/apps/pkgmgmt/rpmlib"
+
+cp -a "$RPMTMPL/"* "$pkgcfg/rpm/etc/"
+cp -a "$APTTMPL/"* "$pkgcfg/apt/etc/"
+
+
+test -z "$INITPRE" || "$INITPRE" "$name"
+"$_VAPT_GET" "$name" -- update
+installBasePackages "$name" "$PKGDIR"
+"$_VAPT_GET" "$name" -- dist-upgrade
+test -z "$INITPOST" || "$INITPOST" "$name"
diff --git a/util-vserver/src/.cvsignore b/util-vserver/src/.cvsignore
new file mode 100644 (file)
index 0000000..8b8bc7b
--- /dev/null
@@ -0,0 +1,25 @@
+.deps
+.dirstamp
+capchroot
+chbind
+chcontext
+fakerunlevel
+filetime
+ifspec
+listdevip
+new-namespace
+parserpmdump
+readlink
+rebootmgr
+reducecap
+secure-mount
+setctxlimit
+showattr
+showperm
+vbuild
+vcheck
+vdu
+vfiles
+vreboot
+vserver-stat
+vunify
diff --git a/util-vserver/src/new-namespace.c b/util-vserver/src/new-namespace.c
new file mode 100644 (file)
index 0000000..5684f1e
--- /dev/null
@@ -0,0 +1,103 @@
+// $Id$    --*- c++ -*--
+
+// Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or (at your option)
+// any later version.
+//  
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//  
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+// Executes a program in a new namespace
+// Based on http://www.win.tue.nl/~aeb/linux/lk/lk-6.html
+
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "util.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sched.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sched.h>
+
+#ifndef CLONE_NEWNS
+#  define CLONE_NEWNS 0x00020000
+#endif
+
+static int
+childFunc(void *argv_v)
+{
+  char **      argv = argv_v;
+  
+  execvp(argv[0], argv);
+  perror("execvp()");
+  exit(255);
+}
+
+static void
+usage(int fd, char const *cmd, int exit_code)
+{
+  WRITE_MSG(fd,        "Usage:  ");
+  WRITE_STR(fd, cmd);
+  WRITE_MSG(fd,
+           " [--help] [--version] <cmd> <args*>\n"
+           "\n"
+           "Executes <cmd> in a new namespace.\n"
+           "\n"
+           "Report bugs to " PACKAGE_BUGREPORT "\n");
+
+  exit(exit_code);
+}
+
+static void
+showVersion()
+{
+  WRITE_MSG(1,
+           "new-namespace 0.1\n"
+           "Copyright (C) 2003 Enrico Scholz\n"
+           VERSION_COPYRIGHT_DISCLAIMER);
+  exit(0);
+}
+  
+int main(int argc, char *argv[])
+{
+  char                 buf[128];
+  int                  status;
+  pid_t                        pid, p;
+
+  if (argc==1) usage(2, argv[0], 255);
+  if (!strcmp(argv[1], "--help"))    usage(1, argv[0], 0);
+  if (!strcmp(argv[1], "--version")) showVersion();
+  if (!strcmp(argv[1], "--"))        ++argv;
+
+  pid = clone(childFunc, buf+sizeof(buf)/2, CLONE_NEWNS|CLONE_VFORK|SIGCHLD, argv+1);
+  if (pid==-1) {
+    perror("clone()");
+    exit(255);
+  }
+
+  p   = wait4(pid, &status, 0,0);
+  if (p==-1) {
+    perror("waitpid()");
+    exit(255);
+  }
+
+  if (WIFEXITED(status)) return WEXITSTATUS(status);
+  else                   return 255;
+}
diff --git a/util-vserver/src/rpm-fake.c b/util-vserver/src/rpm-fake.c
new file mode 100644 (file)
index 0000000..ffd26ef
--- /dev/null
@@ -0,0 +1,258 @@
+// $Id$    --*- c++ -*--
+
+// Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//  
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//  
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//  
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <asm/unistd.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <sys/mount.h>
+#include <linux/fs.h>
+#include <sched.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#define LIBNAME                "rpm-fake.so"
+#define PLATFORM_FILE  "/etc/rpm/platform"
+
+#define INIT(FILE,FUNC)        FUNC##_func = dlsym(FILE, #FUNC)
+#define DECLARE(FUNC)  static __typeof__(FUNC) *       FUNC##_func = 0
+
+static bool            is_initialized = false;
+DECLARE(execv);
+  //DECLARE(open);
+
+static int def_NR_new_s_context = 259;
+#undef __NR_new_s_context
+static int __NR_new_s_context_rev0;
+static int __NR_new_s_context_rev1;
+
+static int new_s_context_rev0(int, int, int);
+static int new_s_context_rev1(int, int *, int, int);
+
+_syscall3(int, new_s_context_rev0, int, newctx,              int, remove_cap, int, flags)
+_syscall4(int, new_s_context_rev1, int, nbctx,  int *, ctxs, int, remove_cap, int, flags)
+
+static int
+new_s_context(int rev,
+             int nbctx,  int *ctxs, int remove_cap, int flags)
+{
+  int          ret;
+  
+  switch (rev) {
+    case 0     :
+    {
+      int      ctx;
+      
+      switch (nbctx) {
+       case 0  :  ctx = -1;      break;
+       case 1  :  ctx = ctxs[0]; break;
+       default :  errno = EINVAL; return -1;
+      }
+
+      ret = new_s_context_rev0(ctx, remove_cap, flags);
+
+      break;
+    }
+
+    case 1     :
+      ret = new_s_context_rev1(nbctx, ctxs, remove_cap, flags);
+      break;
+
+    default    :
+      errno = EINVAL; return -1;
+  }
+
+  return ret;
+}
+
+static void
+initVserverSyscalls(int s_context_NR)
+{
+  int  nr = (s_context_NR!=-1) ? s_context_NR : def_NR_new_s_context;
+
+  __NR_new_s_context_rev0 = __NR_new_s_context_rev1 = nr;
+}
+
+static int
+getAndClearEnv(char const *key, int dflt)
+{
+  char *env = getenv(key);
+  int          res;
+
+  if (env==0 || env[0]=='\0') res = dflt;
+  else {
+    res = atoi(env);
+    unsetenv(key);
+  }
+
+  return res;
+}
+
+static void
+initLib()
+{
+  if (is_initialized) return;
+
+  initVserverSyscalls(getAndClearEnv("RPM_FAKE_S_CONTEXT_NR", -1));
+  INIT(RTLD_NEXT, execv);
+    //INIT(RTLD_NEXT, open);
+
+  is_initialized = true;
+}
+
+static void
+fixPreloadEnv()
+{
+  char                 *env = getenv("LD_PRELOAD");
+  char                 *pos;
+
+    // the const <-> non-const assignment is not an issue since the following modifying operations
+    // will not be executed in the const-case
+  env = env ? env : "";
+  pos = strstr(env, LIBNAME);
+
+  if (pos!=0) {
+    char       *end_pos = pos + sizeof(LIBNAME);
+    bool       is_end = (end_pos[-1]=='\0');
+    char       *start_pos;
+    
+    end_pos[-1] = '\0';
+    start_pos   = strrchr(env, ':');
+    if (start_pos==0) start_pos = env;
+    else if (!is_end) ++start_pos;
+
+    if (is_end) *start_pos = '\0';
+    else        memmove(start_pos, end_pos, strlen(end_pos)+1);
+  }
+
+#ifdef DEBUG
+  printf("env='%s'\n", env);
+#endif
+
+  if (*env=='\0') unsetenv("LD_PRELOAD");
+}
+
+static int
+execvWorker(char const *path, char * const argv[])
+{
+  int          res;
+  int          ctx;
+
+  printf("+execvWorker\n");
+  ctx = getAndClearEnv("RPM_FAKE_CTX",  -1);
+  if ( (res=new_s_context(getAndClearEnv("RPM_FAKE_S_CONTEXT_REV", 0),
+                         ctx==-1 ? 0 : 1,
+                         &ctx,
+                         getAndClearEnv("RPM_FAKE_CAP",  ~0x3404040f),
+                         getAndClearEnv("RPM_FAKE_FLAGS", 0)))!=-1 &&
+       (res=execv_func(path, argv)!=-1) ) {}
+  printf("-execvWorker -> res=%u, err=%s\n",res,strerror(errno));
+
+  return res;
+}
+
+struct ExecvParams
+{
+    char const *       path;
+    char * const *     argv;
+    char const *       mnts;
+};
+
+static int
+removeNamespaceMountsChild(void *params_v)
+{
+  struct ExecvParams * params = params_v;
+  char                 buf[strlen(params->mnts)+1], *ptr;
+
+  strcpy(buf, params->mnts);
+  ptr = strtok(buf, ":");
+  while (ptr) {
+    system("cat /proc/mounts");
+    system("pstree -h");
+    system("ls -l /proc/self/ /proc/self/fd/ /var/lib /var/lib/rpm/");
+    if (umount2(ptr, 0)==-1) { dprintf(2, "ptr='%s' -> ", ptr); perror("umount2()"); return -1; }
+    ptr = strtok(0, ":");
+  }
+
+  unsetenv("RPM_FAKE_NAMESPACE_MOUNTS");
+  return execvWorker(params->path, params->argv);
+}
+
+static int
+removeNamespaceMounts(char const *path, char * const argv[])
+{
+  char const * mnts = getenv("RPM_FAKE_NAMESPACE_MOUNTS");
+
+  printf("mnts='%s'\n", mnts);
+  if (mnts==0) return execvWorker(path, argv);
+
+  {
+    printf("l=%u\n", __LINE__);
+    char       buf[512 + 2*strlen(mnts)];
+    int                status;
+    pid_t      p;
+    struct ExecvParams         params = {
+      .path = path,
+      .argv = argv,
+      .mnts = mnts,
+    };
+    
+    printf("l=%u\n", __LINE__);
+
+    
+    system("mount -t proc none /proc");
+    system("cat /proc/mounts");
+      //system("pstree -h");
+    system("ls -l /proc/self/ /proc/self/fd/ /var/lib /var/lib/rpm/");
+    pid_t      pid = clone(removeNamespaceMountsChild, buf+sizeof(buf)/2,
+                           CLONE_NEWNS|SIGCHLD|CLONE_VFORK, &params);
+
+    printf("l=%u\n", __LINE__);
+    if (pid==-1) return -1;
+    while ((p=waitpid(pid, &status, 0))==-1 &&
+          (errno==EINTR || errno==EAGAIN)) ;
+    if (p==-1)   return -1;
+
+    printf("removeNamespaceMountsChild() -> status=%u\n", status);
+
+    if (WIFEXITED(status))   exit(WEXITSTATUS(status));
+    if (WIFSIGNALED(status)) kill(getpid(), WTERMSIG(status));
+
+    return -1;
+  }
+}
+
+int
+execv(char const *path, char * const argv[]) __THROW
+{
+  initLib();
+  fixPreloadEnv();
+  return removeNamespaceMounts(path, argv);
+}
diff --git a/util-vserver/src/secure-mount.c b/util-vserver/src/secure-mount.c
new file mode 100644 (file)
index 0000000..194cc41
--- /dev/null
@@ -0,0 +1,153 @@
+// $Id$    --*- c++ -*--
+
+// Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//  
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//  
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+  // secure-mount <chroot-base> <src> <dst>
+  //
+  // mounts <src> into the chroot <chroot-base> at destination <dst> in a way
+  // that prevents symlink attacks
+
+  // algorithm:
+  //   enter chroot
+  //     mount tmpfs-directory
+  //   leave chroot
+  //   mount --bind <src> tmpfs
+  //   enter chroot
+  //     mount --move tmpfs <dst>
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#define VERSION_COPYRIGHT_YEAR         "2003"
+#define VERSION_COPYRIGHT_AUTHOR       "Enrico Scholz"
+#include "util.h"
+
+#include <unistd.h>
+#include <sys/mount.h>
+#include <linux/fs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#define MNTPOINT       "/etc"
+
+static void
+showHelp(int fd, char const *cmd, int res)
+{
+  WRITE_MSG(fd, "Usage:  ");
+  WRITE_STR(fd, cmd);
+  WRITE_MSG(fd,
+           " <chroot-base> <src> <dst>\n\n"
+           "Please report bugs to " PACKAGE_BUGREPORT "\n");
+
+  exit(res);
+}
+
+static void
+showVersion()
+{
+  WRITE_MSG(1,
+           "secure-mount 0.23.5\n"
+           "Copyright (C) 2003 Enrico Scholz\n"
+           VERSION_COPYRIGHT_DISCLAIMER);
+  exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+  int  fd = open("/", O_RDONLY);
+    // HACK: sanity checks should be done before declaration, but this does
+    // not work with C89 compilers
+  char path[strlen(argc==1 ? "" : argv[1]) + sizeof(MNTPOINT) + 3];
+
+  if (argc>=2) {
+    if (!strcmp(argv[1], "--help"))    showHelp(1, argv[0], 0);
+    if (!strcmp(argv[1], "--version")) showVersion();
+  }
+  if (argc!=4) {
+    WRITE_MSG(2, "Bad parameter count; use --help for further information.\n");
+    exit(255);
+  }
+
+  if (chroot(argv[1]) == -1 ||
+      chdir("/")      == -1) {
+    perror("chroot()/chdir()");
+    exit(1);
+  }
+  
+  if (mount("none", MNTPOINT, "tmpfs", 0, "size=4k")==-1) {
+    perror("mount()");
+    exit(1);
+  }
+
+  if (mkdir(MNTPOINT "/x",0600) == -1) {
+    perror("mkdir()/fchdir()");
+    goto err1;
+  }
+  
+  if (fchdir(fd)      == -1 ||
+      chroot(".")     == -1) {
+    perror("chroot()");
+    goto err2;
+  }
+
+  strcpy(path, argv[1]);
+  strcat(path, MNTPOINT "/x");
+  
+  if (mount(argv[2], path, "", MS_BIND, 0)==-1) {
+    perror("mount()");
+    goto err3;
+  }
+
+  if (chroot(argv[1]) == -1) {
+    perror("chroot()");
+    goto err4;
+  }
+
+  if (chdir("/")      == -1 ||
+      mount(MNTPOINT "/x", argv[3], "", MS_MOVE, 0) == -1) {
+    perror("chdir()/mount()");
+    goto err5;
+  }
+
+  if (umount(MNTPOINT) == -1) {
+    perror("umount()");
+  }
+
+  return 0;
+
+  err5:
+  err4:
+  if (umount(path)==-1)   perror("umount(path)");
+  
+  err3:
+  if (chdir(argv[1])==-1) {
+    perror("chdir()");
+    return 1;
+  }
+
+  err2:
+  err1:
+  if (umount("mnt")==-1)  perror("umount(\"mnt\")");
+
+  return 1;
+}
diff --git a/util-vserver/src/util.h b/util-vserver/src/util.h
new file mode 100644 (file)
index 0000000..ebf6ee0
--- /dev/null
@@ -0,0 +1,44 @@
+// $Id$    --*- c++ -*--
+
+// Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//  
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//  
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#ifndef H_UTIL_VSERVER_SRC_UTIL_H
+#define H_UTIL_VSERVER_SRC_UTIL_H
+
+#include <unistd.h>
+#include <string.h>
+
+#ifndef PACKAGE_BUGREPORT
+#  define PACKAGE_BUGREPORT    "???"
+#endif
+
+#ifndef VERSION_COPYRIGHT_DISCLAIMER
+#  define VERSION_COPYRIGHT_DISCLAIMER \
+  "This program is free software; you may redistribute it under the terms of\n" \
+  "the GNU General Public License.  This program has absolutely no warranty.\n"
+#endif
+
+inline static void
+writeStr(int fd, char const *cmd)
+{
+  (void)write(fd, cmd, strlen(cmd));
+}
+
+#define WRITE_MSG(FD,X)                (void)(write(FD,X,sizeof(X)))
+#define WRITE_STR(FD,X)                writeStr(FD,X)
+
+#endif //  H_UTIL_VSERVER_SRC_UTIL_H
diff --git a/util-vserver/sysv/.cvsignore b/util-vserver/sysv/.cvsignore
new file mode 100644 (file)
index 0000000..80bab4b
--- /dev/null
@@ -0,0 +1,10 @@
+rebootmgr
+v_gated
+v_httpd
+v_named
+v_portmap
+v_sendmail
+v_smb
+v_sshd
+v_xinetd
+vservers
diff --git a/util-vserver/tests/.cvsignore b/util-vserver/tests/.cvsignore
new file mode 100644 (file)
index 0000000..0667ff3
--- /dev/null
@@ -0,0 +1,8 @@
+.deps
+.dirstamp
+chrootsafe
+escaperoot
+forkbomb
+testipc
+testlimit
+testopenf