#!/bin/sh

# Shell script to collect system data.
# Copyright (C) 2001-2004 Open Challenge B.V.
# Copyright (C) 2004-2005 OpenEyeT Professional Services.
# Copyright (C) 2005-2009 QNH.
#
# 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, 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; see the file COPYING.
# If not, write to the Free Software Foundation,
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# Contact information: http://scc.qnh-infrastructure.nl/index.html 

# This is a system module of scc, to call it separately in the
# proper environment, use: scc-collect -i -e <module_name>

# SCC-release:	1.9.28
# file-version:	$Revision: 1.72 $
 
set -u

. ${SCC_BIN}/scc_modules/scc_utils

# Make sure to show only data for symbolic links (indicated by Paul te Vaanholt).
ls -l /etc/alternatives 2>/dev/null			|
sed -n -e 's@^.* \([^ 	][^ 	]*\) -> @fix:system:/etc/alternatives::\1 -> @p'

if [ -x /usr/sbin/audevent ]
then
	/usr/sbin/audevent				|
	sed -e 's/^/fix:system:audevent::/'
fi

for file in	/etc/audit/audit.conf	\
		/etc/audit/audit.rules
do
	scc_check_file "${file}" "fix:system:audit:${file}::" "#"
done

if [ -x /sbin/crashconf ]
then
	/sbin/crashconf		|
	awk '/^$/		{ next }
		/^DEVICE/	{ fixed=1;	}
				{
					if ( fixed )
					{
						print "fix:system:crashconf::" $0;
					}
					else
					{
						print "var:system:crashconf::" $0;
					}
				}'
fi

for file in /etc/cups/*.conf /etc/cups/*.convs /etc/cups/*.types 
do
	scc_check_file "${file}" "fix:system:CUPS:${file}::" "#"
done

scc_check_file /etc/coreadm.conf "fix:system:/etc/coreadm.conf::" "#"
scc_check_file /etc/dumpadm.conf "fix:system:/etc/dumpadm.conf::" "#"
scc_check_file /etc/debconf.conf "fix:system:/etc/debconf.conf::" "#"

for file in /etc/dbus-1/*.conf /etc/dbus-1/system.d/*.conf
do
	scc_check_file --xml "${file}" "fix:system:dbus:${file}::" 
done

# Avoid binary characters in snapshot and logbook.
dmesg 2>/dev/null					|
strings							|
sed -e "s/^/var:system:log:dmesg::/"

scc_check_file /etc/shutdownlog "var:system:log:/etc/shutdownlog::" "#"

for file in					\
		/etc/bashrc			\
		/etc/bash.bashrc		\
		/etc/dt/config/Xaccess		\
		/usr/dt/config/Xaccess		\
		/etc/environment		\
		/etc/issue.net			\
		/etc/.login			\
		/etc/login.access		\
		/etc/login.conf			\
		/etc/login.defs			\
		/etc/profile			\
		/etc/profile.local		\
		/etc/profile.d/*		\
		/etc/shells			\
		/etc/csh.cshrc			\
		/etc/csh.login			\
		/etc/csh.logout			\
		/etc/ksh.kshrc			\
		/etc/changelist			\
		/etc/wsconsctl.conf
do
	scc_check_file "${file}" "fix:system:login:${file}::" "#"
done

# The /etc/motd file on Ubuntu contains variable load data: ignore the file.
if [ "${SCC_LINUX_DISTRO}" != "Ubuntu" ]
then
	scc_check_file "/etc/motd" "fix:system:login:/etc/motd::" "#"
fi

# The /etc/issue file on VectorLinux contains a picture and variable load data: ignore the file.
# On GoboLinux this file contains variable properties of the system: ignore
if [ "${SCC_LINUX_DISTRO}" != "vector" -a "${SCC_LINUX_DISTRO}" != "GoboLinux" ]
then
	scc_check_file "/etc/issue" "fix:system:login:/etc/issue::" "#"
fi

if [ -d /etc/env.d ]
then
	find /etc/env.d -type f 2>/dev/null		|
	sort						|
	while read file
	do
		scc_check_file "${file}" "fix:system:variables:${file}::" "#"
	done
fi

scc_check_file /etc/HOSTNAME "fix:system:host:/etc/HOSTNAME::" "#"
scc_check_file /etc/hostname "fix:system:host:/etc/hostname::" "#"
scc_check_file /etc/mailname "fix:system:host:/etc/mailname::" "#"
scc_check_file /etc/hoststated.conf "fix:system:host:/etc/hoststated.conf::" "#"
scc_check_file /etc/afs/afsd.conf "fix:system:host:/etc/afs/afsd.conf::" "#"

# Often /etc/logingroup is a symbolic link to /etc/group. Check whether these files differ to determine
# incorporating /etc/logingroup in the snapshot.
file="/etc/logingroup"
if [ -f ${file} -a "$(cmp -s ${file} /etc/group 2>/dev/null; echo $?)" -eq 1 ]
then
	# All group-members must be on a single line. Split the line and sort
	# the data for better overview. This also enables us to compare systems
	# where users were added in different order to this file.
	awk -F: '{
		if ( length( $4 ) == 0 )
		{
			printf( "%s::%s:%s:%s:\n", p, $1, $2, $3  );
		}
		else
		{
			cnt = split( $4, parts, "," );
			for ( i = 1; i <= cnt; i++ )
			{
				printf( "%s::%s:%s:%s:%s\n", p, $1, $2, $3, parts[ i ] );
			}
		}
	}' p="fix:system:login:${file}" ${file}		|
	sort
fi

scc_check_file /etc/man.config "fix:system:man::/etc/man.config:	" "#"
scc_check_file /etc/man.conf "fix:system:man::/etc/man.conf:	" "#"
scc_check_file /usr/share/man/man.cf "fix:system:man::/usr/share/man/man.cf:	" "#"

for f in PATH MANPATH SHLIB_PATH
do
	if [ -s /etc/${f} ]
	then
		sed	-e '/^#/d'	\
			-e '/^[ 	]*$/d' /etc/${f}	|
		tr ":" "\012"					|
		sed -e "s@^@fix:system:path::/etc/${f}:	@"
	fi
done
scc_check_file /etc/manpath.config "fix:system:path::/etc/manpath.config:	" "#"

# Add the processes as variabele data.
sed -e 's/^/var:system:processes::/' ${PROC_FILE}
var_class="var:system:process hierarchy"
if [ -x /usr/proc/bin/ptree ]
then
	# Solaris cannot provide hierarchy with ps.
	/usr/proc/bin/ptree 2>/dev/null			|
	sed -e "s/^/${var_class}::ptree	/"
fi

if [ -x /usr/bin/proctree ]
then
	# AIX cannot provide hierarchy with ps.
	/usr/bin/proctree -a				|
	sed -e "s/^/${var_class}::proctree	/"
fi

scc_check_file /etc/qconfig "fix:system:qconfig::" "#"

# AppArmor
if [ -d /sys/kernel/security/apparmor ]
then
	for f in /sys/kernel/security/apparmor/control/*
	do
		if [ -f ${f} ]
		then
			echo "fix:system:security:apparmor:configuration:general::${f##*/}	: $(cat "${f}")"
		fi
	done

	scc_check_file /sys/kernel/security/profiles "fix:system:security:apparmor:configuration:general::" "#"	|
	sort
fi

if [ -x /usr/sbin/aa-status ]
then
	# Number of processes with profiles can change, therefore variable data.
	# Processes in complain/enforce/... mode are reported with their (variable) PID, erase the PID
	/usr/sbin/aa-status 2>&1										|
	awk	'/process/	{ print "var:system:security:apparmor:configuration:aa-status::" $0; next }
				{ print "fix:system:security:apparmor:configuration:aa-status::" $0; next }'	|
	sed	-e 's/^\(fix:.*[ 	]*\)([0-9][0-9]*)[ 	]*$/\1/'
fi
if [ -d /etc/apparmor ]
then
	for file in	logprof.conf	\
			reports.conf	\
			reports.crontab	\
			subdomain.conf
	do
		scc_check_file "/etc/apparmor/${file}" "fix:system:security:apparmor:configuration:/etc/apparmor/${file}::" "#"
	done
fi
for dir in /etc/apparmor.d /etc/subdomain.d
do
	if [ -d ${dir} ]
	then
		find ${dir} -type f					|
		sort							|
		while read file
		do
			if [ -f "${file}" ]
			then
				# To preserve the #include statements, we cannot use scc_check_file.
				sed	-n						\
					-e '/^[ 	]*#include/p'			\
					-e '/^[ 	]*#/d'				\
					-e '/^[ 	]*$/d'				\
					-e '/.*/p'					\
						<${file} 2>/dev/null						|
				sed	-e "s@^@fix:system:security:apparmor:profiles:${file}::@"
			fi
		done
	fi
done

# On some systems /etc/security is a file, on others a directory. 
# To simplify the code, we handle the file-case first.
# Indicated by Doug Probst.
scc_check_file "/etc/security" "fix:system:security:/etc/security::" "#"
for f in				\
		/etc/checksecurity.conf	\
		/etc/clamav.conf	\
		/etc/doprc		\
		/etc/fam.conf		\
		/etc/fbtab		\
		/etc/freshclam.conf	\
		/etc/identd.conf	\
		/etc/logindevperm	\
		/etc/limits		\
		/etc/op.conf		\
		/etc/op.d/*.conf	\
		/etc/permissions*	\
		/etc/privgroup		\
		/etc/securetty		\
		/etc/securettys		\
		/etc/security/*		\
		/etc/security.conf	\
		/etc/sia/matrix.conf	\
		/etc/ttyaction		\
		/etc/ttys		\
		/etc/user_attr		\
		/etc/usertty		\
		/tcb/files/auth/system/default
do
	if [ -d ${f} ]
	then
		for g in ${f}/*
		do
			scc_check_file "${g}" "fix:system:security:${g}::" "#"
		done
	else
		if [ "${OS_NAME}" = "AIX" ]
		then
			if [	"${f}" = /etc/security/passwd -o	\
				"${f}" = /etc/security/opasswd -o	\
				"${f}" = /etc/security/group -o		\
				"${f}" = /etc/security/ogroup -o	\
				"${f}" = /etc/security/lastlog			]
			then
				# These files contain passwords or variable data, do not show them.
				continue;
			fi
		fi
		scc_check_file "${f}" "fix:system:security:${f}::" "#"
	fi
done

if [ -x /usr/sbin/lsrole ]
then
	/usr/sbin/lsrole -f ALL				|
	grep -v '=$'					|
	sed -e 's/^/fix:system:security:lsrole::/'
fi

scc_check_file "/etc/mtree/special" "fix:system:security:/etc/mtree/special::" "#"

if [ -d /usr/lib/security ]
then
	ls -l /usr/lib/security					|
	scc_ls							|
	sed -e 's@^@fix:system:security:/usr/lib/security::@'
fi

# The contents of this file changes often. The order of systems changes.
scc_check_file /etc/krb5.conf	"var:system:security:/etc/krb5.conf::"		"#"
scc_check_file /etc/krb.conf	"var:system:security:/etc/krb.conf::"		"#"
scc_check_file /etc/krb5.keytab	"fix:system:security:/etc/krb5.keytab::"	"#"
scc_check_file /etc/krb5.realms	"fix:system:security:/etc/krb.realms::"		"#"

for d in /etc /etc/portsentry
do
	scc_check_file "${dir}/portsentry.conf" "fix:system:security:${dir}/portsentry.conf::" "#"
done

# SElinux
if [ -x /usr/sbin/sestatus ]
then
	# sestatus also displays the booleans, but in a less pleasant format.
	# Ignore the booleans from sestatus and use getsebool to display the values of the booleans.
	/usr/sbin/sestatus					|
	sed	-e '/booleans/,$d'	\
		-e '/^$/d'		\
		-e 's/^/fix:system:security:selinux:sestatus::/'

	/usr/sbin/getsebool -a 2>/dev/null			|
	sed -e 's/^/fix:system:security:selinux:getsebool::/'

	scc_check_file /etc/selinux/restorecond.conf "fix:system:security:selinux:restorecond.conf::" "#"
	scc_check_file /etc/selinux/semanage.conf "fix:system:security:selinux:semanage.conf::" "#"
	scc_check_file /etc/sestatus.conf "fix:system:security:selinux:sestatus.conf::" "#"
fi

scc_check_file /etc/ld.so.conf "fix:system:ld:/etc/ld.so.conf::" "#"
for file in /etc/ld.so.conf.d/*
do
	scc_check_file "${file}" "fix:system:ld:${file}::" "#"
done

if [ -x /sbin/ldconfig ]
then
	if [ "${OS_NAME}" = "OpenBSD" ]
	then
		/sbin/ldconfig -v 2>/dev/null	|
		sed -n -e "s/^Adding /fix:system:ld:ldconfig::/p"
	else
		/sbin/ldconfig -vN 2>/dev/null	|
		awk '/^	/	{
					printf( "%s:%s::%s\n", l, dir, $0 );
					next
				}
				{
					dir = $1;
					if ( NF > 1 )
					{
						$1 = "	";
						printf( "%s:%s::%s\n", l, dir, $0 );
					}
				}' l="fix:system:ld:ldconfig"		|
		sed -e 's/:	//'		|
		sort
	fi
fi

scc_check_file /etc/prelink.conf "fix:system:ld:/etc/prelink.conf::" "#"

scc_check_file /etc/hosts.allow "fix:system:security:/etc/hosts.allow::" "#"
scc_check_file /etc/hosts.deny "fix:system:security:/etc/hosts.deny::" "#"

if [ -x /usr/bin/getconf ]
then
	for c in POSIX_VERSION POSIX2_VERSION XOPEN_VERSION
	do
		echo "fix:system:standards::${c}:	$(/usr/bin/getconf ${c} 2>/dev/null)"
	done
fi

if [ "${OS_NAME}" = "FreeBSD" -o "${OS_NAME}" = "DragonFly" ]
then
	swapinfo -k 2>/dev/null		|
	awk	'{
			# Show device, size and type
			print "fix:system:swapinfo::" $1, $2, $NF;
		}'

elif [ "${OS_NAME}" = "NetBSD" -o "${OS_NAME}" = "OpenBSD" ]
then
	swapctl -lk 2>/dev/null		|
	awk	'{
			# Show device and size, type and priority`
			print "fix:system:swapinfo::" $1, $2, $NF;
		}'

elif [ -x /usr/sbin/swapinfo ]
then
	# HP-UX
	# Actual swap-usage is not fixed. Remove this info from the output.
	HDR=$(/usr/sbin/swapinfo 2>/dev/null | grep -i "^TYPE")
	start_var=$(echo "${HDR}" | sed -e 's/ *USED.*//' | wc -c)
	stop_var=$(echo "${HDR}" | sed -e 's/ *RESERVE.*//' | wc -c)

	/usr/sbin/swapinfo			|
	cut -c1-${start_var},${stop_var}-100	|
	sed -e 's/^/fix:system:swapinfo::/'
elif [ -x /usr/sbin/lsps ]
then
	# AIX also has /usr/sbin/swap, so put AIX in front of SunOS.
	/usr/sbin/lsps -a -c 2>/dev/null		|
	awk -F:	'{
			printf( "fix:system:swap lsps pag info::" );
			for ( i = 1; i <= NF; i ++ )
			{
				if ( i != ( NF - 3 ) )
				{
					printf( "%-15s", $i );
				}
			}
			print "";
		}'
	awk '{ $(NF-3)=""; printf( "fix:system:swap lsps page info::%s\n", $0 ); }'
elif [ -x /usr/sbin/swap ]
then
	# SunOS
	HDR=$(/usr/sbin/swap -l 2>/dev/null | grep "^swapfile")
	start_var=$(echo "${HDR}" | sed -e 's/ blocks.*//' | wc -c | sed -e 's/^[ 	]*//')
	/usr/sbin/swap -l 2>/dev/null		|
	cut -c1-${start_var}			|
	sed -e 's/^/fix:system:swap::/'
elif [ -x /sbin/swapon ]
then
	if [ "${OS_NAME}" = "OSF1" ]
	then
		#Swap partition /dev/rz8b:
		#    Allocated space:        99568 pages (777MB)
		#    In-use space:            3083 pages (  3%)
		#    Free space:             96485 pages ( 96%)
		/sbin/swapon -s 2>/dev/null		|
		awk	'/^[ 	]*$/	{ next }
			/%\)[ 	]*$/	{ print "var:system:swapon::" $0; next }
					{ print "fix:system:swapon::" $0 }'
	else
		#Filename                        Type            Size    Used    Priority
		#/dev/cciss/c0d0p3               partition       2097136 0       -1
		/sbin/swapon -s 2>/dev/null		|
		awk '{ $(NF-1)=""; print "fix:system:swapon::" $0 }'
	fi
fi

scc_check_file /etc/swapspaces "fix:system:swap devices:/etc/swapspaces::" "\*"

if [ "${OS_NAME}" = "OSF1" ]
then
	if [ -f /sbin/swapdefaults ]
	then
		echo "fix:system:/sbin/swapdefaults::present"
	else
		echo "fix:system:/sbin/swapdefaults::absent"
	fi
fi

if [ -x /usr/bin/sysdumpdev ]
then
	if [ "${OS_NAME}" = "AIX" ]
	then
		/usr/bin/sysdumpdev -L 2>&1			|
		sed -e 's/^/var:system:last system dump::/'
	else
		/usr/bin/sysdumpdev				|
		sed -e 's/^/fix:system:dump::/'
	fi
fi

if [ -x /usr/lib/ras/dumpcheck ]
then
	/usr/lib/ras/dumpcheck -p	|
	sed -e 's/^/var:system:dumpcheck::/'
fi

# Recorded by the general module.
scc_time_zone="$(sed -n -e 's/^fix:general::timezone://p' ${SCC_KEEP_NEW})"
if [ "${scc_time_zone}" ]
then
	if [ -s /usr/lib/tztab ]
	then
		# Specification of the points of change consist of the
		# name of the zone, followed by lines that start with a digit.
		sed -n -e '/^'"${scc_time_zone}"'/,/^[ 	]*$/p' /usr/lib/tztab		|
		sed -e 's@^@fix:system:time::/usr/lib/tztab:	@'
	elif [ -x /usr/sbin/zdump -a "${SCC_LINUX_DISTRO}" != "sabayon" ]
	then
		# zdump gives the current date and time in the first line: ignore.
		# zdump -v <zone> hangs on sabayon, ignore it.
		zdump -v ${scc_time_zone} 2>/dev/null					|
		sed	-e '1 d'	\
			-e 's@^@fix:system:time::zdump:	@'
	fi
fi

for file in	/etc/screenrc			\
		/etc/X11/SecurityPolicy		\
		/etc/X11/X0devices		\
		/etc/X11/X0pointerkeys		\
		/etc/X11/X0screens		\
		/etc/X11/Xconsoles		\
		/etc/X11/xorg.conf		\
		/etc/dt/config/Xsetup
do
	scc_check_file "${file}" "fix:system:X11:${file}::" "#"
done

exit 0
