#!/bin/sh # This is a script to control a virtual server vserver_mknod(){ mknod $1 $2 $3 $4 chmod $5 $1 } mountproc() { mkdir -p $1/proc $1/dev/pts if [ ! -d $1/proc/1 ] ; then mount -t proc none $1/proc mount -t devpts none $1/dev/pts fi } umountproc() { umount $1/proc 2>/dev/null umount $1/dev/pts 2>/dev/null } # Check that the vservers parent directory has permission 000 # This is the key to avoid chroot escape testperm() { PERM=`/usr/lib/vserver/showperm /vservers/$1/..` if [ "$PERM" != 000 ] ; then echo echo "**********************************************************" echo /vservers/$1/.. has insecure permissions. echo A vserver administrator may be able to visit the root server. echo To fix this, do echo " " chmod 000 /vservers/$1/.. echo do it anytime you want, even if vservers are running. echo "**********************************************************" echo fi } # Set the IP alias needed by a vserver ifconfig_iproot() { if [ "$IPROOT" != "" -a "$IPROOT" != "0.0.0.0" -a "$IPROOTDEV" != "" ] ;then # Compute the default netmask, if missing eval `/usr/lib/vserver/ifspec $IPROOTDEV "$IPROOT" "$IPROOTMASK" "$IPROOTBCAST"` IPROOTMASK=$NETMASK IPROOTBCAST=$BCAST /sbin/ifconfig $IPROOTDEV:$1 $IPROOT netmask $IPROOTMASK broadcast $IPROOTBCAST fi if [ "$IPROOTBCAST" = "" ] ; then IPROOTBCAST=255.255.255.255 fi } ifconfig_iproot_off() { if [ "$IPROOT" != "" -a "$IPROOT" != "0.0.0.0" -a "$IPROOTDEV" != "" ] ;then /sbin/ifconfig $IPROOTDEV:$1 down fi } # Extract the initial runlevel from the vserver inittab get_initdefault() { INITDEFAULT=`grep :initdefault /vservers/$1/etc/inittab | sed 's/:/ /g' | ( read a level b; echo $level)` } usage() { echo vserver server-name command ... echo echo server-name is a directory in /vservers echo echo The commands are: echo " build : Create a virtual server by copying the packages" echo " of the root server" echo " enter : Enter in the virtual server context and starts a shell" echo " Same as \"vserver name exec /bin/sh\"" echo " exec : Exec a command in the virtual server context" echo " suexec : Exec a command in the virtual server context uid" echo " service : Control a service inside a vserver" echo " vserver name service service-name start/stop/restart/status" echo " start : Starts the various services in the vserver, runlevel 3" echo " stop : Ends all services and kills the remaining processes" echo " running : Tells if a virtual server is running" echo " It returns proper exit code, so you can use it as a test" } if [ $# -lt 2 ] ; then usage elif [ "$2" = "build" ] ; then # Either the directory does not exist or is empty NBSUB=`ls /vservers/$1 2>/dev/null | grep -v lost+found | wc -l` NBSUB=`expr $NBSUB` if [ "$NBSUB" != 0 ] ; then echo Virtual server /vservers/$1 already exist else if [ ! -d /vservers ] ; then mkdir /vservers || exit 1 chmod 000 /vservers echo Directory /vservers was created with permissions 000 fi mkdir -p /vservers/$1 || exit 1 chmod 755 /vservers/$1 cp -ax /sbin /bin /etc /usr /var /lib /vservers/$1/. || exit 1 cd /vservers/$1 || exit 1 rm -fr lib/modules/* rm -f var/spool/mail/* rm -f `find var/run -type f` rm -f `find var/log -type f` touch var/log/wtmp rm -f var/lock/subsys/* rm -f etc/cron.d/kmod mkdir proc tmp home root boot test -f /root/.bashrc && cp -a /root/.bashrc root/. test -f /root/.bash_profile && cp -a /root/.bash_profile root/. chmod 1777 tmp chmod 750 root # Create a minimal dev so the virtual server can't grab # more privileges mkdir dev dev/pts vserver_mknod dev/null c 1 3 666 vserver_mknod dev/zero c 1 5 666 vserver_mknod dev/full c 1 7 666 vserver_mknod dev/random c 1 8 644 vserver_mknod dev/urandom c 1 9 644 vserver_mknod dev/tty c 5 0 666 vserver_mknod dev/ptmx c 5 2 666 # Turn off some service useless on a vserver # vserver_turnoff apmd network autofs dhcpd gpm ipchains iptables \ # irda isdn keytable kudzu linuxconf-setup netfs nfs nfslock \ # pcmcia portmap pppoe random rawdevices rhnsd rstatd ruserd \ # rwalld rwhod sendmail smb snmpd v_httpd h_xinetd v_sshd vservers \ # xfs ypbind xinetd ( cd etc/rc.d/init.d || cd etc/init.d for serv in * do case $serv in *.bak|*~|functions|killall|halt|single) ;; *) /usr/lib/vserver/capchroot /vservers/$1 /sbin/chkconfig --level 2345 $serv off ;; esac done ) rm -f etc/rc.d/rc6.d/S*reboot # Create a dummy /etc/fstab and /etc/mtab to please # df and linuxconf. We use hdv1, which does not exist # to remind the admin that it is not the real drive echo /dev/hdv1 / ext2 defaults 1 1 >etc/fstab echo /dev/hdv1 / ext2 rw 0 0 >etc/mtab # Install the vreboot utility cp -a /usr/lib/vserver/vreboot sbin/. ln -sf vreboot sbin/vhalt echo Directory /vservers/$1 has been populated if [ ! -d /etc/vservers ] ; then mkdir /etc/vservers chmod 600 /etc/vservers echo Directory /etc/vservers has been created fi if [ ! -f /etc/vservers/$1.conf ] ; then CONF=/etc/vservers/$1.conf cat >$CONF <<-EOF # Select an unused context (this is optional) # The default is to allocate a free context on the fly # In general you don't need to force a context #S_CONTEXT= # Select the IP number assigned to the virtual server # This IP must be one IP of the server, either an interface # or an IP alias IPROOT=1.2.3.4 # The netmask and broadcast are computed by default from IPROOTDEV #IPROOTMASK= #IPROOTBCAST= # You can define on which device the IP alias will be done # The IP alias will be set when the server is started and unset # when the server is stopped #IPROOTDEV=eth0 # Uncomment the onboot line if you want to enable this # virtual server at boot time #ONBOOT=yes # You can set a different host name for the vserver # If empty, the host name of the main server is used S_HOSTNAME= # You can set a different NIS domain for the vserver # If empty, the current on is kept # Set it to "none" to have no NIS domain set S_DOMAINNAME= # You can set the priority level (nice) of all process in the vserver # Even root won't be able to raise it S_NICE= # You can set various flags for the new security context # lock: Prevent the vserver from setting new security context # sched: Merge scheduler priority of all processes in the vserver # so that it acts a like a single one. # nproc: Limit the number of processes in the vserver according to ulimit # (instead of a per user limit, this becomes a per vserver limit) # private: No other process can join this security context. Even root # Do not forget the quotes around the flags S_FLAGS="lock nproc" # You can set various ulimit flags and they will be inherited by the # vserver. You enter here various command line argument of ulimit # ULIMIT="-H -u 200" # The example above, combined with the nproc S_FLAGS will limit the # vserver to a maximum of 200 processes ULIMIT="-H -u 1000" # You can set various capabilities. By default, the vserver are run # with a limited set, so you can let root run in a vserver and not # worry about it. He can't take over the machine. In some cases # you can to give a little more capabilities (such as CAP_NET_RAW) # S_CAPS="CAP_NET_RAW" S_CAPS="" EOF echo $CONF has been created. Look at it\! fi fi elif [ ! -f /etc/vservers/$1.conf ] ; then echo No configuration for this vserver: /etc/vservers/$1.conf exit 1 elif [ ! -d /vservers/$1/. ] ; then echo No directory for this vserver: /vservers/$1 exit 1 elif [ "$2" = "start" ] ; then echo Starting the virtual server $1 testperm $1 if ! /usr/sbin/vserver $1 running then test -x /etc/vservers/$1.sh && /etc/vservers/$1.sh pre-start $1 IPROOT= IPROOTMASK= IPROOTBCAST= IPROOTDEV= S_NICE= S_FLAGS= . /etc/vservers/$1.conf ifconfig_iproot $1 cd /vservers/$1 || exit 1 rm -f `find var/run -type f` touch var/run/utmp rm -f var/lock/subsys/* mountproc /vservers/$1 CTXOPT= HOSTOPT= DOMAINOPT= NICECMD= FLAGS= CAPS= get_initdefault $1 STARTCMD="/etc/rc.d/rc $INITDEFAULT" DISCONNECT= for f in $S_FLAGS dummy do case $f in dummy) ;; fakeinit) FLAGS="$FLAGS --flag $f" STARTCMD=/sbin/init DISCONNECT=--disconnect ;; *) FLAGS="$FLAGS --flag $f" ;; esac done for f in $S_CAPS dummy do case $f in dummy) ;; !CAP_SYS_CHROOT) CHROOTOPT=--nochroot ;; *) CAPS="$CAPS --cap $f" ;; esac done if [ "$S_CONTEXT" != "" ] ; then CTXOPT="--ctx $S_CONTEXT" fi if [ "$S_HOSTNAME" != "" ] ; then HOSTOPT="--hostname $S_HOSTNAME" export HOSTNAME=$S_HOSTNAME fi if [ "$S_DOMAINNAME" != "" ] ; then DOMAINOPT="--domainname $S_DOMAINNAME" fi if [ "$S_NICE" != "" ] ; then NICECMD="nice -$S_NICE" fi mkdir -p /var/run/vservers chmod 700 /var/run/vservers if [ "$ULIMIT" != "" ] ; then ulimit $ULIMIT fi #echo FLAGS=$FLAGS #echo CAPS=$CAPS # We switch to /vservers/$1 now, because after the # security context switch /vservers directory becomes a dead zone. cd /vservers/$1 $NICECMD /usr/sbin/chbind --ip $IPROOT --bcast $IPROOTBCAST \ /usr/sbin/chcontext $DISCONNECT $CAPS $FLAGS $CTXOPT $HOSTOPT $DOMAINOPT --secure \ /usr/lib/vserver/save_s_context /var/run/vservers/$1.ctx \ /usr/lib/vserver/capchroot $CHROOTOPT . $STARTCMD sleep 2 test -x /etc/vservers/$1.sh && /etc/vservers/$1.sh post-start $1 fi elif [ "$2" = "running" ] ; then if [ ! -f /var/run/vservers/$1.ctx ] ; then echo Server $1 is not running exit 1 else . /var/run/vservers/$1.ctx NB=`/usr/sbin/chcontext --silent --ctx $S_CONTEXT ps ax | wc -l` NB=`eval expr $NB + 0` if [ "$NB" -gt 3 ] ; then echo Server $1 is running exit 0 else echo Server $1 is not running exit 1 fi fi elif [ "$2" = "stop" ] ; then echo Stopping the virtual server $1 if /usr/sbin/vserver $1 running then test -x /etc/vservers/$1.sh && /etc/vservers/$1.sh pre-stop $1 IPROOT= IPROOTMASK= IPROOTBCAST= IPROOTDEV= ifconfig_iproot $1 . /etc/vservers/$1.conf . /var/run/vservers/$1.ctx cd /vservers/$1 mountproc /vservers/$1 # The fakeinit flag tell us how to turn off the server STOPCMD="/etc/rc.d/rc 6" for f in $S_FLAGS dummy do case $f in fakeinit) FLAGS="$FLAGS --flag $f" STOPCMD="/sbin/init 6" ;; *) ;; esac done cd /vservers/$1 /usr/sbin/chbind --ip $IPROOT --bcast $IPROOTBCAST \ /usr/sbin/chcontext --secure --ctx $S_CONTEXT \ /usr/lib/vserver/capchroot . $STOPCMD echo sleep 5 sleep 2 echo Killing all processes /usr/sbin/chbind --silent --ip $IPROOT --bcast $IPROOTBCAST \ /usr/sbin/chcontext --secure --silent --ctx $S_CONTEXT \ /usr/lib/vserver/vserverkillall if [ "$IPROOT" != "" -a "$IPROOTDEV" != "" ] ;then /sbin/ifconfig $IPROOTDEV:$1 down fi fi # We umount anyway, because "enter" establish the mount # but when you exit, the server is considered not running umountproc /vservers/$1 test -x /etc/vservers/$1.sh && /etc/vservers/$1.sh post-stop $1 ifconfig_iproot_off elif [ "$2" = "restart" ] ; then if /usr/sbin/vserver $1 running then $0 $1 stop $0 $1 start fi elif [ "$2" = "exec" ] ; then IPROOT= IPROOTMASK= IPROOTBCAST= IPROOTDEV= . /etc/vservers/$1.conf cd /vservers/$1 ifconfig_iproot $1 mountproc /vservers/$1 PS1="[\u@vserver:$1 \W]" export PS1 VSERVER=$1 shift shift CAPS= for f in $S_CAPS dummy do case $f in dummy) ;; !CAP_SYS_CHROOT) CHROOTOPT=--nochroot ;; *) CAPS="$CAPS --cap $f" ;; esac done if $0 $VSERVER running then . /var/run/vservers/$VSERVER.ctx cd /vservers/$VSERVER /usr/sbin/chbind --ip $IPROOT --bcast $IPROOTBCAST \ /usr/sbin/chcontext $CAPS --secure --ctx $S_CONTEXT \ /usr/lib/vserver/capchroot . $* else test -x /etc/vservers/$1.sh && /etc/vservers/$1.sh pre-start $1 CTXOPT= HOSTOPT= DOMAINOPT= if [ "$S_CONTEXT" != "" ] ; then CTXOPT="--ctx $S_CONTEXT" fi if [ "$S_HOSTNAME" != "" ] ; then HOSTOPT="--hostname $S_HOSTNAME" export HOSTNAME=$S_HOSTNAME fi if [ "$S_DOMAINNAME" != "" ] ; then DOMAINOPT="--domainname $S_DOMAINNAME" fi mkdir -p /var/run/vservers cd /vservers/$VSERVER /usr/sbin/chbind --ip $IPROOT --bcast $IPROOTBCAST \ /usr/sbin/chcontext $CAPS --secure $CTXOPT $HOSTOPT $DOMAINOPT \ /usr/lib/vserver/save_s_context /var/run/vservers/$VSERVER.ctx \ /usr/lib/vserver/capchroot $CHROOTOPT . $* fi elif [ "$2" = "suexec" ] ; then IPROOT= IPROOTMASK= IPROOTBCAST= IPROOTDEV= . /etc/vservers/$1.conf cd /vservers/$1 ifconfig_iproot $1 mountproc /vservers/$1 PS1="[\u@vserver:$1 \W]" export PS1 VSERVER=$1 USERID=$3 shift shift shift CAPS= echo $USERID for f in $S_CAPS dummy do case $f in dummy) ;; !CAP_SYS_CHROOT) CHROOTOPT=--nochroot ;; *) CAPS="$CAPS --cap $f" ;; esac done if $0 $VSERVER running then . /var/run/vservers/$VSERVER.ctx cd /vservers/$VSERVER /usr/sbin/chbind --ip $IPROOT --bcast $IPROOTBCAST \ /usr/sbin/chcontext $CAPS --secure --ctx $S_CONTEXT \ /usr/lib/vserver/mycapchroot . -suid $USERID "$*" else test -x /etc/vservers/$1.sh && /etc/vservers/$1.sh pre-start $1 CTXOPT= HOSTOPT= DOMAINOPT= if [ "$S_CONTEXT" != "" ] ; then CTXOPT="--ctx $S_CONTEXT" fi if [ "$S_HOSTNAME" != "" ] ; then HOSTOPT="--hostname $S_HOSTNAME" export HOSTNAME=$S_HOSTNAME fi if [ "$S_DOMAINNAME" != "" ] ; then DOMAINOPT="--domainname $S_DOMAINNAME" fi mkdir -p /var/run/vservers cd /vservers/$VSERVER /usr/sbin/chbind --ip $IPROOT --bcast $IPROOTBCAST \ /usr/sbin/chcontext $CAPS --secure $CTXOPT $HOSTOPT $DOMAINOPT \ /usr/lib/vserver/save_s_context /var/run/vservers/$VSERVER.ctx \ /usr/lib/vserver/mycapchroot $CHROOTOPT . -suid $USERID "$*" fi elif [ "$2" = "enter" ] ; then testperm $1 exec $0 $1 exec /bin/bash -login elif [ "$2" = "service" ] ; then VSERVER=$1 shift shift exec $0 $VSERVER exec /sbin/service $* elif [ "$2" = "chkconfig" ] ; then VSERVER=$1 shift shift exec $0 $VSERVER exec /sbin/chkconfig $* else echo Command unknown $2 echo usage fi