#!/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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

CONFIGFILE="/etc/cvsd/cvsd.conf"

# 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 /etc/cvsd/cvsd.conf)"
    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) 1.0.7"
    echo "Written by Arthur de Jong."
    echo ""
    echo "Copyright (C) 2004 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 1.0.7 built with:"
echo " "./configure '--build' 'alpha-linux' '--prefix=/usr' '--mandir=${prefix}/share/man' '--infodir=${prefix}/share/info' '--sysconfdir=/etc' '--enable-warnings' '--disable-dependency-tracking' '--with-cvs=/usr/bin/cvs' '--with-perl=/usr/bin/perl' 'build_alias=alpha-linux'
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"`
else
  echo "Error: $CONFIGFILE does not exist!"
  echo ""
  ROOTJAIL=""
  REPOSSES=""
  # 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"/. -maxdepth 0 -print
    find "$ROOTJAIL"{,/bin,/dev,/etc,/lib,/usr,/usr/bin,/usr/lib,/tmp} -mindepth 1 -maxdepth 1 -print
  ) | 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

# TODO: check if all users in $ROOTJAIL/etc/passwd exist in /etc/passwd (or with getent) (see cvsd-buildroot)

# 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
