#!/bin/sh

# cvsd-buginfo - output cvsd configuration info for in a bugreport
# Copyright (C) 2004 Arthur de Jong
#
# 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 of the License, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

CONFIGFILE="@CONFIGFILE@"

# make output more predictable
LANG=C
export LANG
LC_ALL=C
export LC_ALL

# default settings
VERBOSITY=1

# parse command-line parameters
while [ $# != 0 ]
do
  case "$1" in
  -q|--quiet|--silent)
    VERBOSITY=0
    ;;
  -f|--config)
    CONFIGFILE="$2"
    shift
    ;;
  -h|--help)
    echo "Usage: cvsd-buginfo [OPTION]..."
    echo "Write cvsd configuration information for a bugreport to standard output."
    echo ""
    echo "  -f, --config=FILE"
    echo "                 use FILE as configfile (default @CONFIGFILE@)"
    echo "  -q, --quiet, --silent"
    echo "                 hide warnings"
    echo "  -h, --help     display this help and exit"
    echo "  -V, --version  output version information and exit"
    exit 0
    ;;
  -V|--version)
    echo "cvsd-buginfo (cvsd) @VERSION@"
    echo "Written by Arthur de Jong."
    echo ""
    echo "Copyright (C) 2004, 2005, 2006 Arthur de Jong."
    echo "This is free software; see the source for copying conditions.  There is NO"
    echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
    exit 0
    ;;
  *)
    echo "cvsd-buginfo: unrecognized option \`$1'"
    echo "Try \`cvsd-buginfo --help' for more information."
    exit 1
    ;;
  esac
  shift
done

# print warning
if [ $VERBOSITY -gt 0 ]
then
  echo "Warning: be sure to review this information to make sure it does"
  echo "         not contain any sensitive data!"
  echo ""
fi

# dump cvsd version
echo "cvsd @VERSION@ built with:"
echo " "@CONFIGURE_CMD@
echo ""

# dump OS info
echo "uname -a output:"
echo " "`uname -`
echo ""

# check if cvs is enabled in /etc/inetd.conf
if grep '^ *cvspserver' /etc/inetd.conf > /dev/null 2>&1 || \
   grep '^ *2401' /etc/inetd.conf > /dev/null 2>&1
then
  if [ $VERBOSITY -gt 0 ]
  then
    echo "Warning: a cvs pserver seems to be configured through inetd"
    echo "         in /etc/inetd.conf."
    echo ""
  fi
fi

# dump configfile without comments
if [ -r "$CONFIGFILE" ]
then
  echo "$CONFIGFILE:"
  sed -n 's/^[[:space:]]*\([^#].*\)[[:space:]]*$/ \1/p' < "$CONFIGFILE"
  echo ""
  # find location of chroot jail
  ROOTJAIL=`sed -n 's/^[[:space:]]*RootJail[[:space:]][[:space:]]*\([^[:space:]]*\)[[:space:]]*$/\1/p' < "$CONFIGFILE"`
  # get list of repositories
  REPOSSES=`sed -n 's/^[[:space:]]*Repos[[:space:]][[:space:]]*\([^[:space:]]*\)[[:space:]]*$/\1/p' < "$CONFIGFILE"`
  # get cvsd user
  CVSDUSER=`sed -n 's/^[[:space:]]*Uid[[:space:]][[:space:]]*\([^[:space:]]*\)[[:space:]]*$/\1/p' < "$CONFIGFILE"`
else
  echo "Error: $CONFIGFILE does not exist!"
  echo ""
  ROOTJAIL=""
  REPOSSES=""
  CVSDUSER=""
  # try this, maybe a chroot jail is there
  [ -d "/var/lib/cvsd" ] && ROOTJAIL="/var/lib/cvsd"
fi

# dump minimal contents of chroot jail
if [ -z "$ROOTJAIL" ]
then
  if [ $VERBOSITY -gt 0 ]
  then
    echo "Warning: no rootjail has been defined. The RootJail option seems to be"
    echo "         missing from the configuration file. This is not a recommended"
    echo "         configuration."
    echo ""
  fi
elif [ -d "$ROOTJAIL" ]
then
  echo "$ROOTJAIL:"
  ( find "$ROOTJAIL" \
         "$ROOTJAIL"/usr \
         "$ROOTJAIL"/tmp \
         "$ROOTJAIL"/var \
          -maxdepth 1 -print 2> /dev/null
    find "$ROOTJAIL"/bin \
         "$ROOTJAIL"/dev \
         "$ROOTJAIL"/etc \
         "$ROOTJAIL"/lib* \
         "$ROOTJAIL"/usr/bin \
         "$ROOTJAIL"/usr/lib* \
         -print  2> /dev/null
  ) | sort -u | xargs ls -ld | \
      sed "s|$ROOTJAIL/||;s/^ *[0-9]* *[0-9]* *\([^ ]*\) *[0-9]* */ \1 /"
  echo ""
else
  echo "Error: $ROOTJAIL does not exist!"
  echo ""
fi

# try to find filesystem chroot jail is on
if [ $VERBOSITY -gt 0 ] && [ -d "$ROOTJAIL" ]
then
  if [ -r /proc/mounts ]
  then
    filesystem=`df -k "$ROOTJAIL" | sed -n 's,^.*\(/[^ ]*\)$,\1,p' | tail -n 1`
    if [ -n "`sed -n "s,^[^ ]* $filesystem .*\(nodev\|noexec\),,p" < /proc/mounts`" ]
    then
      echo "Warning: the fileststem the chroot jail is on ($filesystem)"
      echo "         is mounted with a nodev or noexec option. This will cause"
      echo "         the cvs pserver to fail."
      echo ""
    fi
  fi
fi

# dump cvs info
echo "$(which cvs):"
ls -l $(which cvs) | sed 's/^ *[0-9]* *[0-9]* *\([^ ]*\) *[0-9]* */ \1 /'
echo ""

# dump cvs version
echo "$(which cvs) --version:"
UBVERSION="`cvs --version | grep '^Conc'`"
echo " $UBVERSION"
echo ""

# dump chroot cvs version
if [ -n "$ROOTJAIL" ] && [ -x "$ROOTJAIL/bin/cvs" ]
then
  echo "$ROOTJAIL/bin/cvs --version:"
  RJVERSION="`$ROOTJAIL/bin/cvs --version | grep '^Conc'`"
  echo " $RJVERSION"
  if [ $VERBOSITY -gt 0 ] && [ "$UBVERSION" != "$RJVERSION" ]
  then
    echo "Warning: the version of cvs in your chroot jail does not match the"
    echo "         version of cvs outside your chroot jail!"
  fi
  echo ""
fi

# dump anonymized chroot passwd file
maxlines=6
if [ -n "$ROOTJAIL" ] && [ -r "$ROOTJAIL/etc/passwd" ]
then
  echo "$ROOTJAIL/etc/passwd: (passwds removed)"
  sed 's/^\([^:]*\):[^:]*:\([^:]*:[^:]*\):[^:]*:\(.*\)$/ \1::\2::\3/' < \
    "$ROOTJAIL/etc/passwd" | head -n $maxlines
  if [ `wc -l < "$ROOTJAIL/etc/passwd"` -gt $maxlines ]
  then
    echo " ..."
  fi
  echo ""
fi

# find some users in system passwd file (start with chroot uids)
users="`sed -n 's/^\([^:]*\):.*/\1/p' < $ROOTJAIL/etc/passwd`"
# add configured user
users="$users $CVSDUSER"
# filter out duplicate entries
users="`( for i in $users ; do echo $i ; done ) | sort -u`"

# dump anonymized system passwd file
echo "System passwd file: (passwds removed)"
for i in $users
do
  ( getent passwd $i 2>/dev/null || \
    grep '^'$i: /etc/passwd ) | \
    sed 's/^\([^:]*\):[^:]*:\([^:]*:[^:]*\):[^:]*:\(.*\)$/ \1::\2::\3/'
done
echo ""

# dump some info per repository
maxlines=2
lines=0
for REPOS in $REPOSSES
do
  REPOS="$ROOTJAIL$REPOS"
  if [ -d "$REPOS" ] && [ -d "$REPOS/CVSROOT" ]
  then
    # dump CVSROOT/config without comments
    if [ -r "$REPOS/CVSROOT/config" ]
    then
      echo "$REPOS/CVSROOT/config:"
      sed -n 's/^[[:space:]]*\([^#].*\)[[:space:]]*$/ \1/p' < "$REPOS/CVSROOT/config"
      if [ `sed -n 's/^[[:space:]]*\([^#].*\)[[:space:]]*$/ \1/p' < "$REPOS/CVSROOT/config" | wc -l` -eq 0 ]
      then
        echo " <empty>"
      fi
      # check if lockdir exists if it is specified
      LOCKDIR=`sed -n 's/^[[:space:]]*LockDir=\([^[:space:]]*\)[[:space:]]*$/\1/p' < "$REPOS/CVSROOT/config"`
      if [ -n "$LOCKDIR" ]
      then
        if [ -d "$ROOTJAIL$LOCKDIR" ]
        then
          :
        else
          echo "Warning: a lock directory of $LOCKDIR is specified"
          echo "         but $ROOTJAIL$LOCKDIR does not exist!"
        fi
      fi
      echo ""
    else
      echo "Error: $REPOS/CVSROOT/config does not exist!"
      echo ""
    fi
    # dump anonymized repository passwd file
    maxlines=6
    if [ -r "$REPOS/CVSROOT/passwd" ]
    then
      echo "$REPOS/CVSROOT/passwd: (passwds removed)"
      sed "s/^\([^:]*\):[^:]*/ \1:/" < \
        "$REPOS/CVSROOT/passwd" | head -n $maxlines
      if [ `wc -l < "$REPOS/CVSROOT/passwd"` -gt $maxlines ]
      then
        echo " ..."
      fi
      echo ""
    fi
    # TODO: check for all users if the matching system user is Uid from cvsd.conf or if cvsd.conf does not contain a Uid is in $ROOTJAIL/etc/passwd
    found=""
    # dump readers file
    if [ -r "$REPOS/CVSROOT/readers" ]
    then
      found="readers"
      echo "$REPOS/CVSROOT/readers:"
      sed 's/^/ /' < "$REPOS/CVSROOT/readers"
      if [ `wc -l < "$REPOS/CVSROOT/readers"` -eq 0 ]
      then
        echo " <empty>"
      fi
      echo ""
    fi
    # dump writers file
    if [ -r "$REPOS/CVSROOT/writers" ]
    then
      found="writers"
      echo "$REPOS/CVSROOT/writers:"
      sed 's/^/ /' < "$REPOS/CVSROOT/writers"
      if [ `wc -l < "$REPOS/CVSROOT/writers"` -eq 0 ]
      then
        echo " <empty>"
      fi
      echo ""
    fi
    # print warning on missing readers and writers
    if [ $VERBOSITY -gt 0 ] && [ -z "$found" ]
    then
      echo "Warning: neither a readers file nor a writers file was found inside"
      echo "         $REPOS/CVSROOT. This means that all users have"
      echo "         write access!"
      echo ""
    fi
  elif [ $VERBOSITY -gt 0 ]
  then
    echo "Warning: the repository $REPOS does not exist or does"
    echo "         not look like a cvs repository!"
    echo ""
  fi
done
