bc5dde
#!/bin/bash
bc5dde
4e17de
# Warning: the order is important
4e17de
# If a directory containing $ROOTDIR is listed here,
4e17de
# it MUST be listed last. (/var/named contains /var/named/chroot)
3ce7d3
ROOTDIR="$1"
3ce7d3
CONFIG_FILES="${3:-/etc/named-chroot.files}"
bc5dde
bc5dde
usage()
bc5dde
{
bc5dde
  echo
bc5dde
  echo 'This script setups chroot environment for BIND'
3ce7d3
  echo 'Usage: setup-named-chroot.sh ROOTDIR <on|off> [chroot.files]'
bc5dde
}
bc5dde
3ce7d3
if ! [ "$#" -ge 2 -a "$#" -le 3 ]; then
bc5dde
  echo 'Wrong number of arguments'
bc5dde
  usage
bc5dde
  exit 1
bc5dde
fi
bc5dde
bc5dde
# Exit if ROOTDIR doesn't exist
bc5dde
if ! [ -d "$ROOTDIR" ]; then
bc5dde
  echo "Root directory $ROOTDIR doesn't exist"
bc5dde
  usage
bc5dde
  exit 1
bc5dde
fi
bc5dde
3ce7d3
if ! [ -r "$CONFIG_FILES" ]; then
3ce7d3
  echo "Files list $CONFIG_FILES doesn't exist" 2>&1
3ce7d3
  usage
3ce7d3
  exit 1
3ce7d3
fi
3ce7d3
3ce7d3
dev_create()
3ce7d3
{
3ce7d3
  DEVNAME="$ROOTDIR/dev/$1"
3ce7d3
  shift
3ce7d3
  if ! [ -e "$DEVNAME" ]; then
3ce7d3
    /bin/mknod -m 0664 "$DEVNAME" $@
3ce7d3
    /bin/chgrp named "$DEVNAME"
3ce7d3
    if [ -x /usr/sbin/selinuxenabled -a -x /sbin/restorecon ]; then
3ce7d3
      /usr/sbin/selinuxenabled && /sbin/restorecon "$DEVNAME" > /dev/null || :
3ce7d3
    fi
3ce7d3
  fi
3ce7d3
}
3ce7d3
3ce7d3
dev_chroot_prep()
3ce7d3
{
3ce7d3
  dev_create random c 1 8
3ce7d3
  dev_create zero   c 1 5
3ce7d3
  dev_create null   c 1 3
3ce7d3
}
3ce7d3
3ce7d3
files_comment_filter()
3ce7d3
{
3ce7d3
  if [ -d "$1" ]; then
3ce7d3
    grep -v '^[[:space:]]*#' "$1"/*.files
3ce7d3
  else
3ce7d3
    grep -v '^[[:space:]]*#' "$1"
3ce7d3
  fi
3ce7d3
}
3ce7d3
bc5dde
mount_chroot_conf()
bc5dde
{
bc5dde
  if [ -n "$ROOTDIR" ]; then
3ce7d3
    # Check devices are prepared
3ce7d3
    dev_chroot_prep
3ce7d3
    files_comment_filter "$CONFIG_FILES" | while read -r all; do
bc5dde
      # Skip nonexistant files
bc5dde
      [ -e "$all" ] || continue
bc5dde
bc5dde
      # If mount source is a file
bc5dde
      if ! [ -d "$all" ]; then
bc5dde
        # mount it only if it is not present in chroot or it is empty
bc5dde
        if ! [ -e "$ROOTDIR$all" ] || [ `stat -c'%s' "$ROOTDIR$all"` -eq 0 ]; then
bc5dde
          touch "$ROOTDIR$all"
bc5dde
          mount --bind "$all" "$ROOTDIR$all"
bc5dde
        fi
bc5dde
      else
bc5dde
        # Mount source is a directory. Mount it only if directory in chroot is
bc5dde
        # empty.
bc5dde
        if [ -e "$all" ] && [ `ls -1A $ROOTDIR$all | wc -l` -eq 0 ]; then
fd4b48
          mount --bind --make-private "$all" "$ROOTDIR$all"
bc5dde
        fi
bc5dde
      fi
bc5dde
    done
bc5dde
  fi
bc5dde
}
bc5dde
bc5dde
umount_chroot_conf()
bc5dde
{
bc5dde
  if [ -n "$ROOTDIR" ]; then
3ce7d3
    files_comment_filter "$CONFIG_FILES" | while read -r all; do
bc5dde
      # Check if file is mount target. Do not use /proc/mounts because detecting
bc5dde
      # of modified mounted files can fail.
bc5dde
      if mount | grep -q '.* on '"$ROOTDIR$all"' .*'; then
bc5dde
        umount "$ROOTDIR$all"
bc5dde
        # Remove temporary created files
bc5dde
        [ -f "$all" ] && rm -f "$ROOTDIR$all"
bc5dde
      fi
bc5dde
    done
bc5dde
  fi
bc5dde
}
bc5dde
bc5dde
case "$2" in
bc5dde
  on)
bc5dde
    mount_chroot_conf
bc5dde
    ;;
bc5dde
  off)
bc5dde
    umount_chroot_conf
bc5dde
    ;;
bc5dde
  *)
bc5dde
    echo 'Second argument has to be "on" or "off"'
bc5dde
    usage
bc5dde
    exit 1
bc5dde
esac
bc5dde
bc5dde
exit 0