#!/sbin/sh
#
# Check if any local file systems are being exported to 'localhost'.
# Check the local host is in a netgroups entry in its own exports file.
#
# See: http://www.cert.org/advisories/CA-1994-15.html
#
# I did not attempt to unroll the netgroup file to see if the host is
# self-referencing.


# Check if /etc/exports file exists
test ! -f /etc/exports && return


# Check export option access list for an instance of 'localhost',
# the host name, the loopback IP, or a netgroup that could contain
# any of these.
#
#  $1  Exported directory
#  $2  Export option
#  $3  Colon-separated export setting
#
function check_access
{
  HOSTNAME=$(hostname)

  echo ${3} |\
  awk -F':' '{
    for ( i=1; i<=NF; i++ ) {
      print $i
    }
  }' |\
  while read ACCESS
  do
    # Check if NFS server is exporting to itself
    if [[ ${ACCESS%%.?*} = "localhost" ]]
    then
      echo "WARNING: export of ${1} uses 'localhost' for ${2} option"
    elif [[ ${ACCESS%%.?*} = ${HOSTNAME} ]]
    then
      echo "WARNING: export of ${1} uses '${HOSTNAME}' for ${2} option"
    elif [[ ${ACCESS} = "127.0.0.1" ]]
    then
      echo "WARNING: export of ${1} uses '127.0.0.1' for ${2} option"
    elif [[ ${ACCESS#@} != ${ACCESS} ]]
    then
      # Use of netgroup would be bad if it allows NFS server to export
      # to itself. So operator needs to check...
      echo "CAUTION: export of ${1} uses netgroup '${ACCESS}' for ${2} option"
    fi
  done
}


# Check the -options- for the exports file entry
#
#  $1  Exported directory
#  $2  Comma-separated export options
#
function check_options
{
  # Parse the individual options
  echo $2 |\
  awk -F',' '{
    for ( i=1; i<=NF; i++ ) {
      print $i
    }
  }' |\
  while read OPTION
  do
    # Process export options that use a host or access entry
    case ${OPTION%%=?*} in
      rw|root|access)
        check_access $1 ${OPTION%%=?*} ${OPTION#?*=} ;;
    esac
  done
}


# Find entries in exports file with 2 or more fields
sed -e "s/#.*$//" /etc/exports |\
awk -F'-' '{
  if ( NF > 1 ) { printf "%s %s\n", $1, $2 }
}'  |\
while read DIRECTORY OPTIONS
do
  # Check arguments for NFS server self-reference
  check_options ${DIRECTORY} ${OPTIONS}
done

