#!/bin/bash

### BEGIN INIT INFO
# Provides:        chrooted-CHROOT_JAIL_NAME
# Required-Start:  $network $remote_fs $syslog
# Required-Stop:   $network $remote_fs $syslog
# Default-Start:   2 3 4 5
# Default-Stop:    0 1 6
# Short-Description: Start and stop the chrooted environment 'CHROOT_JAIL_NAME'.
### END INIT INFO
#
${DEBIAN_SCRIPT_DEBUG:+ set -v -x}

. /lib/lsb/init-functions

JAIL_ROOT="CHROOT_JAIL_ROOT"
JAIL_NAME="CHROOT_JAIL_NAME"

CHROOT="/usr/sbin/chroot"

CHROOT_JAIL="$JAIL_ROOT/$JAIL_NAME/system"

INITD_SCRIPTS="cron"

SYSLOG_INIT_FILE="/etc/init.d/sysklogd"

ROOT_STD_OPTIONS="suid,exec,nodev"
DEV_STD_OPTIONS="nosuid,noexec,dev"
TMP_STD_OPTIONS="nosuid,noexec,nodev"
VAR_STD_OPTIONS="nosuid,noexec,nodev"

ROOT_RW_OPTIONS="suid,exec,nodev"
DEV_RW_OPTIONS="nosuid,noexec,dev"
TMP_RW_OPTIONS="nosuid,exec,nodev"
VAR_RW_OPTIONS="nosuid,exec,nodev"

PROC_OPTIONS="ro,noexec,nosuid,nodev"

SYSLOG_CONFIG=/etc/default/syslogd

# Load custom chroot settings
if [ -r $JAIL_ROOT/$JAIL_NAME/chroot-environment ]; then
  . $JAIL_ROOT/$JAIL_NAME/chroot-environment
fi

# Try to detect the valid syslog config file.
if [ ! -e $SYSLOG_CONFIG ]; then
  SYSLOG_CONFIG=$SYSLOG_INIT_FILE
fi

## Remount the chroot filesystems in read write mode (for install and upgrades).
chroot_rw_mode() {
  # root
  if [ -n "`mount | grep \" $CHROOT_JAIL \"`" ]; then
    /bin/mount -o remount,rw,$ROOT_RW_OPTIONS $CHROOT_JAIL
  fi

  # dev
  if [ -n "`mount | grep \" $CHROOT_JAIL/dev \"`" ]; then
    /bin/mount -o remount,rw,$DEV_RW_OPTIONS $CHROOT_JAIL/dev
  fi

  # tmp
  if [ -n "`mount | grep \" $CHROOT_JAIL/tmp \"`" ]; then
    /bin/mount -o remount,rw,$TMP_RW_OPTIONS $CHROOT_JAIL/tmp
  fi

  # var
  if [ -n "`mount | grep \" $CHROOT_JAIL/var \"`" ]; then
    /bin/mount -o remount,rw,$VAR_RW_OPTIONS $CHROOT_JAIL/var
  fi
}

# Remount chroot filesystems in read only mode (default secure mode).
chroot_ro_mode() {
  # root
  if [ -n "`mount | grep \" $CHROOT_JAIL \"`" ]; then
    /bin/mount -o remount,ro,$ROOT_STD_OPTIONS $CHROOT_JAIL
  fi

  # dev
  if [ -n "`mount | grep \" $CHROOT_JAIL/dev \"`" ]; then
    /bin/mount -o remount,ro,$DEV_STD_OPTIONS $CHROOT_JAIL/dev
  fi

  # tmp
  if [ -n "`mount | grep \" $CHROOT_JAIL/tmp \"`" ]; then
    /bin/mount -o remount,$TMP_STD_OPTIONS $CHROOT_JAIL/tmp
  fi

  # var
  if [ -n "`mount | grep \" $CHROOT_JAIL/var \"`" ]; then
    /bin/mount -o remount,$VAR_STD_OPTIONS $CHROOT_JAIL/var
  fi
}

## Mount chroot filesystems
chroot_mount() {
  if [ -z "`mount | grep \" $CHROOT_JAIL \"`" ]; then
    /bin/mount -o loop,rw,$ROOT_RW_OPTIONS $JAIL_ROOT/$JAIL_NAME/root.fs $CHROOT_JAIL
  fi
  if [ -z "`mount | grep \" $CHROOT_JAIL/dev \"`" ]; then
    /bin/mount -o loop,rw,$DEV_RW_OPTIONS $JAIL_ROOT/$JAIL_NAME/dev.fs $CHROOT_JAIL/dev
  fi
  if [ -z "`mount | grep \" $CHROOT_JAIL/tmp \"`" ]; then
    /bin/mount -o loop,rw,$TMP_RW_OPTIONS $JAIL_ROOT/$JAIL_NAME/tmp.fs $CHROOT_JAIL/tmp
  fi
  if [ -z "`mount | grep \" $CHROOT_JAIL/var \"`" ]; then
    /bin/mount -o loop,rw,$VAR_RW_OPTIONS $JAIL_ROOT/$JAIL_NAME/var.fs $CHROOT_JAIL/var
  fi

  if [ -z "`mount | grep \" $CHROOT_JAIL/proc \"`" ]; then
    /bin/mount -o $PROC_OPTIONS -t proc proc $CHROOT_JAIL/proc
  fi

  chroot_ro_mode;
}

## Umount chroot filesystems
chroot_umount() {
  if [ -n "`mount | grep \" $CHROOT_JAIL/proc \"`" ]; then
    /bin/umount $CHROOT_JAIL/proc
  fi

  if [ -n "`mount | grep \" $CHROOT_JAIL/var \"`" ]; then
    /bin/umount $CHROOT_JAIL/var
  fi
  if [ -n "`mount | grep \" $CHROOT_JAIL/tmp \"`" ]; then
    /bin/umount $CHROOT_JAIL/tmp
  fi
  if [ -n "`mount | grep \" $CHROOT_JAIL/dev \"`" ]; then
    /bin/umount $CHROOT_JAIL/dev
  fi
  if [ -n "`mount | grep \" $CHROOT_JAIL \"`" ]; then
    /bin/umount $CHROOT_JAIL
  fi
}

## Check if chroot filesystem is mounted
check_mounted() {
  if [ -n "`mount | grep \" $CHROOT_JAIL \"`" ]; then
    return 0
  fi

  return 1
}

## Configure host syslog to listen chroot log socket.
setup_syslog() {
  /bin/echo $CHROOT_JAIL | sed -e 's/\//\\\\\//g' | \
     xargs -iCHROOT_JAIL sed -i -e \
     "s/^SYSLOGD[^=]*=[^\"]*\"\([^\"]*\)\"/SYSLOGD=\"\1 -a CHROOT_JAIL\/dev\/log\"/g" \
     $SYSLOG_CONFIG

  if [ -x $SYSLOG_INIT_FILE ]; then
    $SYSLOG_INIT_FILE reload
  fi
}

## Remove chroot log socket listening from host syslog configuration.
clean_syslog() {
  /bin/echo $CHROOT_JAIL | sed -e 's/\//\\\\\//g' | \
     xargs -iCHROOT_JAIL sed -i -e \
     "s/^\(SYSLOGD[^=]*=.*\) -a CHROOT_JAIL\/dev\/log\(.*\)$/\1\2/g" \
     $SYSLOG_CONFIG

  if [ -x $SYSLOG_INIT_FILE ]; then
    $SYSLOG_INIT_FILE reload
  fi
}

if [ ! -x $CHROOT ]; then
  /bin/echo "$CHROOT command is not present on your system. This script is useless to you !"
  exit 1
fi

## We process the command line args.
case "$1" in
  help)
    /bin/echo "
This script manage the $JAIL_NAME chroot. You can use the following arguments :

  * /etc/init.d/chrooted-$JAIL_NAME help

    Show this help message.

  * /etc/init.d/chrooted-$JAIL_NAME setup

    Setup the chroot so that it fit the host system. Need to be run each time
    the chroot is moved to another computer.

  * /etc/init.d/chrooted-$JAIL_NAME start

    Mount the chroot filesystems and start the chroot services.

  * /etc/init.d/chrooted-$JAIL_NAME stop

    Stop the chroot services and umount the chroot filesystems.


  * /etc/init.d/chrooted-$JAIL_NAME read-only

    Remount the chroot filesystems in read-only mode (this is the default mode).


  * /etc/init.d/chrooted-$JAIL_NAME read-write

    Remount the chroot filesystems in read-write mode (use with caution).
    You should always remound the chroot filesystems read-only when you are
    done.

  * /etc/init.d/chrooted-$JAIL_NAME mount

    Mount the chroot filesystems without starting chroot services.

  * /etc/init.d/chrooted-$JAIL_NAME umount

    Umount the chroot filesystems.


  * /etc/init.d/chrooted-$JAIL_NAME login {username}

    Run a shell in the chroot environment as root, or as username if specified.


  * /etc/init.d/chrooted-$JAIL_NAME run command_line

    Run the given command_line in the chroot environment.

  * /etc/init.d/chrooted-$JAIL_NAME {restart|reload|force-reload|status}

    Restart, reload, force-reload, or show status of all the init.d scripts of
    the chroot environment.

  * /etc/init.d/chrooted-$JAIL_NAME update

    Run /usr/bin/apt-get update in the chroot environment.

  * /etc/init.d/chrooted-$JAIL_NAME {upgrade|install|remove|autoremove|source}

    Run /usr/bin/apt-get with the given arguments in the chroot environment.

  * /etc/init.d/chrooted-$JAIL_NAME update

    Run /usr/bin/apt-get update in the chroot environment.

  * /etc/init.d/chrooted-$JAIL_NAME init.d_script command

    Run the specified init.d script in the chroot environment with the given
    command line. For example :

    /etc/init.d/chrooted-$JAIL_NAME cron restart

    run this command in the chroot environment :

    /etc/init.d/cron restart

Please use this script with caution. It is not likely to break your system...
...but who knows.

- This script is provided by Pierre-Yves Landuré <pierre-yves@landure.org>.
- This script is sponsored by Dorigo consultants
    (http://www.dorigo-consultants.com/).
- More informations about this script can be found at Lone Wolf Scripts
    (http://howto.landure.fr/).
"
    exit 0
  ;;

  setup)
    if ! check_mounted; then
      /bin/echo "$JAIL_NAME chroot is not mounted."
      exit 1
    fi

    # Setup the chroot on the current computer.
    if [ -e /etc/hosts ]; then
      /bin/cp /etc/hosts $CHROOT_JAIL/etc
    fi

    if [ -e /etc/resolv.conf ]; then
      /bin/cp /etc/resolv.conf $CHROOT_JAIL/etc
    fi

    if [ -e /etc/timezone ]; then
      /bin/cp /etc/timezone $CHROOT_JAIL/etc
    fi

    # Setup the locale
    if [ -e /etc/locale.gen ]; then
      /bin/cp /etc/locale.gen $CHROOT_JAIL/etc
    else
      /bin/echo $LANG | /bin/sed -e 's/\([^.]*\)\.\(.*\)$/\1.\2 \2/' > $CHROOT_JAIL/etc/locale.gen
    fi
    $CHROOT $CHROOT_JAIL locale-gen

    if [ -e $CHROOT_JAIL/etc/environment ]; then
      /bin/sed -i -e '/^LANG=.*$/d' $CHROOT_JAIL/etc/environment
    fi
    /bin/echo "LANG=\"$LANG\"" >> $CHROOT_JAIL/etc/environment

    if [ -e $CHROOT_JAIL/etc/default/locale ]; then
      /bin/sed -i -e '/^LANG=.*$/d' $CHROOT_JAIL/etc/default/locale
    fi
    /bin/echo "LANG=\"$LANG\"" >> $CHROOT_JAIL/etc/default/locale

    # Configure cron-apt
    if [ -d $CHROOT_JAIL/etc/cron-apt/mailmsg.d ]; then
      /bin/echo "###### $(hostname) ######
## Jail : $JAIL_NAME

To upgrade the jail, run this command line :

/etc/init.d/chrooted-$JAIL_NAME upgrade

########################" \
           > $CHROOT_JAIL/etc/cron-apt/mailmsg.d/0-update
      cp $CHROOT_JAIL/etc/cron-apt/mailmsg.d/0-update $CHROOT_JAIL/etc/cron-apt/mailmsg.d/3-download
    fi
  ;;

  start)
    if ! check_mounted; then
      chroot_mount;
    fi

    # Configure host syslog
    setup_syslog;

    for SCRIPT in $INITD_SCRIPTS; do
      $CHROOT $CHROOT_JAIL /etc/init.d/$SCRIPT $1
    done

    exit 0
  ;;

  stop)
    if check_mounted; then
      for SCRIPT in $INITD_SCRIPTS; do
        $CHROOT $CHROOT_JAIL /etc/init.d/$SCRIPT $1
      done
    else
      /bin/echo "$JAIL_NAME chroot is already stopped."
      exit 1
    fi

    # Unconfigure host syslog
    clean_syslog;

    chroot_umount;
    exit 0
  ;;

  read-only)
    if ! check_mounted; then
      /bin/echo "$JAIL_NAME chroot is not started."
      exit 1
    fi

    chroot_ro_mode;
    log_end_msg 0
  ;;

  read-write)
    if ! check_mounted; then
      /bin/echo "$JAIL_NAME chroot is not started."
      exit 1
    fi

    chroot_rw_mode;
    log_end_msg 0
  ;;

  mount)
    chroot_mount;
    log_end_msg 0
  ;;

  umount)
    chroot_umount;
    log_end_msg 0
  ;;

  login)
    if ! check_mounted; then
      /bin/echo "$JAIL_NAME chroot is not started."
      exit 1
    fi

    # We drop the login option
    shift

    # We enter the chroot as root or with the specified user :
    $CHROOT $CHROOT_JAIL /bin/su - $1

    exit 0
  ;;

  run)
    if ! check_mounted; then
      /bin/echo "$JAIL_NAME chroot is not started."
      exit 1
    fi

    # We drop the run option
    shift

    if [ -n "$1" ]; then
      $CHROOT $CHROOT_JAIL $@
    fi

    exit 0
  ;;

  restart|reload|force-reload|status)
    if ! check_mounted; then
      /bin/echo "$JAIL_NAME chroot is not started."
      exit 1
    fi

    for SCRIPT in $INITD_SCRIPTS; do
      $CHROOT $CHROOT_JAIL /etc/init.d/$SCRIPT $1
    done

    exit 0
  ;;

  update)
    if ! check_mounted; then
      /bin/echo "$JAIL_NAME chroot is not started."
      exit 1
    fi

    $CHROOT $CHROOT_JAIL apt-get $@

    exit 0
  ;;

  upgrade|install|remove|autoremove|source)
    if ! check_mounted; then
      /bin/echo "$JAIL_NAME chroot is not started."
      exit 1
    fi

    chroot_rw_mode;
    $CHROOT $CHROOT_JAIL apt-get $@
    chroot_ro_mode;

    exit 0
  ;;

  *)
    if ! check_mounted; then
      /bin/echo "$JAIL_NAME chroot is not started."
      exit 1
    fi

    if [ -n "$2" ]; then
      if [[ $INITD_SCRIPTS = *$1* ]]; then
        $CHROOT $CHROOT_JAIL /etc/init.d/$1 $2
      else
        /bin/echo "$1 is not a valid init.d script. Please use run to execute a command inside the chroot."
        exit 1
      fi
    else
      /bin/echo "Please use run to execute a command inside the chroot."
      exit 1
    fi
    log_end_msg 0
  ;;
esac

exit 0
