aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile50
-rw-r--r--conf/perm.036
-rw-r--r--conf/perm.132
-rw-r--r--conf/perm.232
-rw-r--r--conf/perm.334
-rw-r--r--conf/perm.436
-rw-r--r--conf/perm.546
-rw-r--r--conf/perm.snf38
-rwxr-xr-xcron-sh/diff_check.sh56
-rwxr-xr-xcron-sh/security.sh36
-rwxr-xr-xcron-sh/security_check.sh24
-rwxr-xr-xinit-sh/cleanold.sh133
-rwxr-xr-xmsec.sh2
-rw-r--r--msec.spec105
-rw-r--r--share/.cvsignore2
-rw-r--r--share/CHANGES40
-rw-r--r--share/Config.py46
-rw-r--r--share/ConfigFile.py376
-rw-r--r--share/Log.py53
-rwxr-xr-xshare/Perms.py173
-rw-r--r--share/README66
-rwxr-xr-xshare/compile.py17
-rw-r--r--share/libmsec.py488
-rwxr-xr-xshare/msec48
-rwxr-xr-xshare/msec.py195
25 files changed, 1955 insertions, 209 deletions
diff --git a/Makefile b/Makefile
index 0cd5b13..fd1fe5d 100644
--- a/Makefile
+++ b/Makefile
@@ -3,11 +3,10 @@ VERSION := $(shell grep 'Version:' $(PACKAGE).spec| cut -f 2)
RELEASE := $(shell grep 'Release:' $(PACKAGE).spec| cut -f 2)
TAG := $(shell echo "V$(VERSION)_$(RELEASE)" | tr -- '-.' '__')
-all: promisc_check msec_find
+all: promisc_check msec_find python
clean:
- -find . -name '*.o' -exec rm -f {} \;
- -find . -name '*~' -exec rm -f {} \;
+ -find . -name '*.o' -o -name '*.pyc' -o -name '*~' -exec rm -f {} \;
rm -f src/promisc_check/promisc_check
rm -f src/msec_find/msec_find
@@ -17,29 +16,30 @@ promisc_check:
msec_find:
(cd src/msec_find && make)
+python:
+ -cd share; ./msec.py -h
+
install:
- (mkdir -p $(RPM_BUILD_ROOT)/etc/security/msec)
- (mkdir -p $(RPM_BUILD_ROOT)/usr/share/msec)
- (mkdir -p $(RPM_BUILD_ROOT)/usr/sbin)
- (cp init-sh/*.sh $(RPM_BUILD_ROOT)/usr/share/msec)
- (cp cron-sh/*.sh $(RPM_BUILD_ROOT)/usr/share/msec)
- (cp init-sh/msec $(RPM_BUILD_ROOT)/usr/sbin)
- (cp conf/perm.* conf/server.* $(RPM_BUILD_ROOT)/etc/security/msec)
-
- (mkdir -p $(RPM_BUILD_ROOT)/var/log)
- (mkdir -p $(RPM_BUILD_ROOT)/var/log/security)
- (touch $(RPM_BUILD_ROOT)/etc/security/msec/security.conf)
- (touch $(RPM_BUILD_ROOT)/var/log/security.log)
- (cd src/promisc_check && make install)
- (cd src/msec_find && make install)
- (mkdir -p $(RPM_BUILD_ROOT)/usr/man/man8/)
- install -d $(RPM_BUILD_ROOT)/usr/man/man8/
- install -m644 man/C/*8 $(RPM_BUILD_ROOT)/usr/man/man8/
- bzip2 -9f $(RPM_BUILD_ROOT)/usr/man/man8/*8
+ mkdir -p $RPM_BUILD_ROOT/etc/security/msec
+ mkdir -p $RPM_BUILD_ROOT/usr/share/msec
+ mkdir -p $RPM_BUILD_ROOT/usr/sbin
+ cp init-sh/*.sh $RPM_BUILD_ROOT/usr/share/msec
+ cp cron-sh/*.sh $RPM_BUILD_ROOT/usr/share/msec
+ cp init-sh/msec $RPM_BUILD_ROOT/usr/sbin
+ cp conf/perm.* conf/server.* $RPM_BUILD_ROOT/etc/security/msec
+
+ mkdir -p $RPM_BUILD_ROOT/var/log
+ mkdir -p $RPM_BUILD_ROOT/var/log/security
+ touch $RPM_BUILD_ROOT/etc/security/msec/security.conf
+ touch $RPM_BUILD_ROOT/var/log/security.log
+ cd src/promisc_check && make install
+ cd src/msec_find && make install
+ mkdir -p $RPM_BUILD_ROOT/usr/share/man/man8/
+ install -d $(RPM_BUILD_ROOT)/usr/share/man/man8/
+ install -m644 man/C/*8 $(RPM_BUILD_ROOT)/usr/share/man/man8/
for i in man/??* ; do \
- install -d $(RPM_BUILD_ROOT)/usr/man/`basename $$i`/man8 ; \
- install -m 644 $$i/*.8 $(RPM_BUILD_ROOT)/usr/man/`basename $$i`/man8 ; \
- bzip2 -9f $(RPM_BUILD_ROOT)/usr/man/`basename $$i`/man8/*8 ; \
+ install -d $(RPM_BUILD_ROOT)/usr/share/man/`basename $$i`/man8 ; \
+ install -m 644 $$i/*.8 $(RPM_BUILD_ROOT)/usr/share/man/`basename $$i`/man8 ; \
done
version:
@@ -47,7 +47,7 @@ version:
# rules to build a test rpm
-localrpm: localdist buildrpm
+localrpm: clean localdist buildrpm
localdist: cleandist dir localcopy tar
diff --git a/conf/perm.0 b/conf/perm.0
index 1cc7203..92adab5 100644
--- a/conf/perm.0
+++ b/conf/perm.0
@@ -1,10 +1,9 @@
-# Welcome in Level 1
+# Welcome in Level 0
###
+/ root.root 755
/bin/ root.root 755
/boot/ root.root 755
/dev/ root.root 755
-/dev/audio* root.audio 660
-/dev/dsp* root.audio 660
/etc/ root.root 755
/etc/conf.modules root.root 644
/etc/cron.daily/ root.root 755
@@ -14,7 +13,6 @@
/etc/crontab root.root 644
/etc/dhcpcd/ root.root 755
/etc/dhcpcd/* root.root 644
-/etc/esd.conf root.root 644
/etc/ftpaccess root.root 644
/etc/ftpconversions root.root 644
/etc/ftpgroups root.root 644
@@ -26,28 +24,31 @@
/etc/hosts.equiv root.root 644
/etc/inetd.conf root.root 644
/etc/init.d/ root.root 755
-/etc/rc.d/init.d/syslog root.root 744
/etc/inittab root.root 644
/etc/ld.so.conf root.root 644
/etc/lilo.conf root.root 644
+/etc/mandrake-release root.root 644
/etc/modules.conf root.root 644
/etc/motd root.root 644
/etc/printcap root.root 644
/etc/profile.d/* root.root 755
/etc/rc.d/ root.root 755
+/etc/rc.d/init.d/syslog root.root 744
/etc/securetty root.root 644
/etc/sendmail.cf root.root 644
/etc/shutdown.allow root.root 644
-/etc/ssh_config root.root 644
-/etc/ssh_host_key root.root 644
-/etc/ssh_host_key.pub root.root 644
-/etc/sshd_config root.root 644
+/etc/ssh/ssh_config root.root 644
+/etc/ssh/ssh_host_*key root.root 600
+/etc/ssh/ssh_host_*key.pub root.root 644
+/etc/ssh/sshd_config root.root 644
+/etc/sysconfig root.root 755
/etc/syslog.conf root.root 644
/etc/updatedb.conf root.root 644
/home/ root.root 755
/home/* current 755
/lib/ root.root 755
/mnt/ root.root 755
+/proc root.root 555
/root/ root.root 755
/sbin/ root.root 755
/tmp/ root.root 1777
@@ -55,18 +56,17 @@
/usr/* root.root 755
/usr/X11R6/ root.root 755
/usr/bin/ root.root 755
-/usr/sbin/ root.root 755
/usr/lib/rpm/rpm? rpm.rpm 755
+/usr/sbin/ root.root 755
/usr/share/doc root.root 755
+/usr/share/man root.root 755
+/usr/tmp root.root 1777
/var/ root.root 755
-/var/tmp root.root 1777
+/var/lock/subsys root.root 755
/var/log/ root.root 755
/var/log/* root.adm 644
-/var/log/squidGuard squid.squid 755
-/var/log/squid squid.squid 755
-/var/log/snort snort.snort 755
-/var/log/uucp uucp.uucp 755
-/var/log/news news.news 755
-/var/log/security/ root.root 700
-/var/log/security/* root.root 600
+/var/log/*/* current 644
+/var/log/*/*/* current 644
+/var/log/*/. current 755
/var/spool/mail/ root.mail 771
+/var/tmp root.root 1777
diff --git a/conf/perm.1 b/conf/perm.1
index a0ade08..52a9067 100644
--- a/conf/perm.1
+++ b/conf/perm.1
@@ -1,10 +1,9 @@
# Welcome in Level 1
###
+/ root.root 755
/bin/ root.root 755
/boot/ root.root 755
/dev/ root.root 755
-/dev/audio* root.audio 660
-/dev/dsp* root.audio 660
/etc/ root.root 755
/etc/conf.modules root.root 644
/etc/cron.daily/ root.root 755
@@ -14,7 +13,6 @@
/etc/crontab root.root 644
/etc/dhcpcd/ root.root 755
/etc/dhcpcd/* root.root 644
-/etc/esd.conf root.root 644
/etc/ftpaccess root.root 644
/etc/ftpconversions root.root 644
/etc/ftpgroups root.root 644
@@ -26,46 +24,48 @@
/etc/hosts.equiv root.root 644
/etc/inetd.conf root.root 644
/etc/init.d/ root.root 755
-/etc/rc.d/init.d/syslog root.root 744
/etc/inittab root.root 644
/etc/ld.so.conf root.root 644
/etc/lilo.conf root.root 644
+/etc/mandrake-release root.root 644
/etc/modules.conf root.root 644
/etc/motd root.root 644
/etc/printcap root.root 644
/etc/profile.d/* root.root 755
/etc/rc.d/ root.root 755
+/etc/rc.d/init.d/syslog root.root 744
/etc/securetty root.root 644
/etc/sendmail.cf root.root 644
/etc/shutdown.allow root.root 644
-/etc/ssh_config root.root 644
-/etc/ssh_host_key root.root 644
-/etc/ssh_host_key.pub root.root 644
-/etc/sshd_config root.root 644
+/etc/ssh/ssh_config root.root 644
+/etc/ssh/ssh_host_*key root.root 600
+/etc/ssh/ssh_host_*key.pub root.root 644
+/etc/ssh/sshd_config root.root 644
+/etc/sysconfig root.root 755
/etc/syslog.conf root.root 644
/etc/updatedb.conf root.root 644
/home/ root.root 755
/home/* current 755
/lib/ root.root 755
/mnt/ root.root 755
+/proc root.root 555
/root/ root.root 755
/sbin/ root.root 755
/tmp/ root.root 1777
/usr/ root.root 755
/usr/X11R6/ root.root 755
/usr/bin/ root.root 755
-/usr/sbin/ root.root 755
/usr/lib/rpm/rpm? rpm.rpm 755
+/usr/sbin/ root.root 755
/usr/share/doc root.root 755
+/usr/share/man root.root 755
+/usr/tmp root.root 2777
/var/ root.root 755
+/var/lock/subsys root.root 755
/var/log/ root.root 755
/var/log/* root.adm 644
-/var/log/squidGuard squid.squid 755
-/var/log/squid squid.squid 755
-/var/log/snort snort.snort 755
-/var/log/uucp uucp.uucp 755
-/var/log/news news.news 755
-/var/log/security/ root.root 700
-/var/log/security/* root.root 600
+/var/log/*/* current 644
+/var/log/*/*/* current 644
+/var/log/*/. current 755
/var/spool/mail/ root.mail 2775
/var/tmp root.root 2777
diff --git a/conf/perm.2 b/conf/perm.2
index 82052de..51e183f 100644
--- a/conf/perm.2
+++ b/conf/perm.2
@@ -1,10 +1,9 @@
# Welcome in Level 2
###
+/ root.root 755
/bin/ root.root 755
/boot/ root.root 755
/dev/ root.root 755
-/dev/audio* root.audio 660
-/dev/dsp* root.audio 660
/etc/ root.root 755
/etc/conf.modules root.root 644
/etc/cron.daily/ root.root 755
@@ -14,7 +13,6 @@
/etc/crontab root.root 644
/etc/dhcpcd/ root.root 755
/etc/dhcpcd/* root.root 644
-/etc/esd.conf root.root 644
/etc/ftpaccess root.root 644
/etc/ftpconversions root.root 644
/etc/ftpgroups root.root 644
@@ -26,28 +24,31 @@
/etc/hosts.equiv root.root 644
/etc/inetd.conf root.root 644
/etc/init.d/ root.root 755
-/etc/rc.d/init.d/syslog root.root 744
/etc/inittab root.root 644
/etc/ld.so.conf root.root 644
/etc/lilo.conf root.root 644
+/etc/mandrake-release root.root 644
/etc/modules.conf root.root 644
/etc/motd root.root 644
/etc/printcap root.root 644
/etc/profile.d/* root.root 755
/etc/rc.d/ root.root 755
+/etc/rc.d/init.d/* root.root 744
/etc/securetty root.root 644
/etc/sendmail.cf root.root 644
/etc/shutdown.allow root.root 644
-/etc/ssh_config root.root 644
-/etc/ssh_host_key root.root 644
-/etc/ssh_host_key.pub root.root 644
-/etc/sshd_config root.root 644
+/etc/ssh/ssh_config root.root 644
+/etc/ssh/ssh_host_*key root.root 600
+/etc/ssh/ssh_host_*key.pub root.root 644
+/etc/ssh/sshd_config root.root 644
+/etc/sysconfig root.root 755
/etc/syslog.conf root.root 644
/etc/updatedb.conf root.root 644
/home/ root.root 755
/home/* current 755
/lib/ root.root 755
/mnt/ root.root 755
+/proc root.root 555
/root/ root.root 700
/sbin/ root.root 755
/tmp/ root.root 1777
@@ -55,18 +56,17 @@
/usr/* root.root 755
/usr/X11R6/ root.root 755
/usr/bin/ root.root 755
-/usr/sbin/ root.root 755
/usr/lib/rpm/rpm? rpm.rpm 755
+/usr/sbin/ root.root 755
/usr/share/doc root.root 755
+/usr/share/man root.root 755
+/usr/tmp root.root 1777
/var/ root.root 755
+/var/lock/subsys root.root 755
/var/log/ root.root 755
/var/log/* root.adm 640
-/var/log/squidGuard squid.squid 755
-/var/log/squid squid.squid 755
-/var/log/snort snort.snort 755
-/var/log/uucp uucp.uucp 755
-/var/log/news news.news 755
-/var/log/security/ root.root 700
-/var/log/security/* root.root 600
+/var/log/*/* current 640
+/var/log/*/*/* current 640
+/var/log/*/. current 755
/var/spool/mail/ root.mail 2775
/var/tmp root.root 1777
diff --git a/conf/perm.3 b/conf/perm.3
index 1d78f10..798adb5 100644
--- a/conf/perm.3
+++ b/conf/perm.3
@@ -1,10 +1,9 @@
# Welcome in Level 3
###
+/ root.adm 755
/bin/ root.root 755
/boot/ root.root 755
/dev/ root.root 755
-/dev/audio* root.audio 660
-/dev/dsp* root.audio 660
/etc/ root.root 755
/etc/conf.modules root.root 644
/etc/cron.daily/ root.root 755
@@ -14,7 +13,6 @@
/etc/crontab root.root 644
/etc/dhcpcd/ root.root 755
/etc/dhcpcd/* root.root 644
-/etc/esd.conf root.root 644
/etc/ftpaccess root.root 644
/etc/ftpconversions root.root 644
/etc/ftpgroups root.root 644
@@ -26,28 +24,31 @@
/etc/hosts.equiv root.root 644
/etc/inetd.conf root.root 644
/etc/init.d/ root.root 755
-/etc/rc.d/init.d/syslog root.root 700
/etc/inittab root.root 644
/etc/ld.so.conf root.root 644
/etc/lilo.conf root.root 644
+/etc/mandrake-release root.root 644
/etc/modules.conf root.root 644
/etc/motd root.root 644
/etc/printcap root.root 644
/etc/profile.d/* root.root 755
/etc/rc.d/ root.root 755
+/etc/rc.d/init.d/* root.root 700
/etc/securetty root.root 644
/etc/sendmail.cf root.root 644
/etc/shutdown.allow root.root 644
-/etc/ssh_config root.root 644
-/etc/ssh_host_key root.root 644
-/etc/ssh_host_key.pub root.root 644
-/etc/sshd_config root.root 644
+/etc/ssh/ssh_config root.root 644
+/etc/ssh/ssh_host_*key root.root 600
+/etc/ssh/ssh_host_*key.pub root.root 644
+/etc/ssh/sshd_config root.root 644
+/etc/sysconfig root.root 755
/etc/syslog.conf root.adm 640
/etc/updatedb.conf root.root 644
/home/ root.root 755
/home/* current 700
/lib/ root.root 755
/mnt/ root.root 755
+/proc root.root 555
/root/ root.root 700
/sbin/ root.root 755
/tmp/ root.root 1777
@@ -55,18 +56,17 @@
/usr/* root.root 755
/usr/X11R6/ root.root 755
/usr/bin/ root.root 755
-/usr/sbin/ root.root 755
/usr/lib/rpm/rpm? rpm.rpm 755
+/usr/sbin/ root.root 755
/usr/share/doc root.root 755
+/usr/share/man root.root 755
+/usr/tmp root.root 1777
/var/ root.root 755
+/var/lock/subsys root.root 755
/var/log/ root.root 755
-/var/log/* root.root 600
-/var/log/squidGuard squid.squid 755
-/var/log/squid squid.squid 755
-/var/log/snort snort.snort 755
-/var/log/uucp uucp.uucp 755
-/var/log/news news.news 755
-/var/log/security/ root.root 700
-/var/log/security/* root.root 600
+/var/log/* root.root 640
+/var/log/*/* current 640
+/var/log/*/*/* current 640
+/var/log/*/. current 755
/var/spool/mail/ root.mail 2775
/var/tmp root.root 1777
diff --git a/conf/perm.4 b/conf/perm.4
index 45b3fdc..41a00b2 100644
--- a/conf/perm.4
+++ b/conf/perm.4
@@ -1,11 +1,10 @@
# Welcome in Level 4, aka secure & usable.
###
+/ root.adm 751
/bin/ root.root 711
/bin/rpm rpm.rpm 750
/boot/ root.root 700
/dev/ root.root 711
-/dev/audio* root.audio 600
-/dev/dsp* root.audio 600
/etc/ root.adm 711
/etc/conf.modules root.adm 640
/etc/cron.daily/ root.adm 750
@@ -15,7 +14,6 @@
/etc/crontab root.adm 640
/etc/dhcpcd/ root.adm 750
/etc/dhcpcd/* root.adm 640
-/etc/esd.conf root.audio 640
/etc/ftpaccess root.adm 640
/etc/ftpconversions root.adm 640
/etc/ftpgroups root.adm 640
@@ -26,29 +24,32 @@
/etc/hosts.deny root.adm 640
/etc/hosts.equiv root.adm 640
/etc/inetd.conf root.adm 640
-/etc/rc.d/init.d/ root.adm 750
-/etc/rc.d/init.d/syslog root.adm 740
/etc/inittab root.adm 640
/etc/ld.so.conf root.adm 640
/etc/lilo.conf root.adm 600
+/etc/mandrake-release root.adm 640
/etc/modules.conf root.adm 640
/etc/motd root.adm 644
/etc/printcap root.lp 640
/etc/profile.d/* root.root 755
-/etc/rc.d/ root.adm 640
+/etc/rc.d/ root.adm 750
+/etc/rc.d/init.d/ root.adm 750
+/etc/rc.d/init.d/* root.adm 740
/etc/securetty root.root 640
/etc/sendmail.cf root.adm 640
/etc/shutdown.allow root.root 600
-/etc/ssh_config root.root 644
-/etc/ssh_host_key root.adm 640
-/etc/ssh_host_key.pub root.adm 644
-/etc/sshd_config root.adm 640
+/etc/ssh/ssh_config root.root 644
+/etc/ssh/ssh_host_*key root.adm 600
+/etc/ssh/ssh_host_*key.pub root.adm 644
+/etc/ssh/sshd_config root.adm 640
+/etc/sysconfig root.adm 751
/etc/syslog.conf root.adm 640
/etc/updatedb.conf root.adm 640
/home/ root.adm 751
/home/* current 700
/lib/ root.adm 751
/mnt/ root.adm 750
+/proc root.kmem 550
/root/ root.root 700
/sbin/ root.adm 751
/tmp/ root.root 1777
@@ -56,18 +57,17 @@
/usr/* root.adm 751
/usr/X11R6/ root.xgrp 751
/usr/bin/ root.adm 751
-/usr/sbin/ root.adm 751
/usr/lib/rpm/rpm? rpm.rpm 750
+/usr/sbin/ root.adm 751
/usr/share/doc rpm.rpm 750
+/usr/share/man rpm.rpm 750
+/usr/tmp root.root 1777
/var/ root.root 755
+/var/lock/subsys root.root 700
/var/log/ root.root 711
/var/log/* root.root 600
-/var/log/squidGuard squid.squid 751
-/var/log/squid squid.squid 751
-/var/log/snort snort.snort 750
-/var/log/uucp uucp.uucp 750
-/var/log/news news.news 750
-/var/log/security/ root.root 700
-/var/log/security/* root.root 600
+/var/log/*/* current 600
+/var/log/*/*/* current 600
+/var/log/*/. current 700
/var/spool/mail/ root.mail 771
/var/tmp root.root 1777
diff --git a/conf/perm.5 b/conf/perm.5
index 8ba96d7..84797ed 100644
--- a/conf/perm.5
+++ b/conf/perm.5
@@ -1,11 +1,10 @@
# Welcome in Level 5, aka paranoid.
###
+/ root.root 711
/bin/ root.root 711
/bin/rpm rpm.rpm 750
/boot/ root.root 700
/dev/ root.root 711
-/dev/audio* root.audio 600
-/dev/dsp* root.audio 600
/etc/ root.root 711
/etc/conf.modules root.root 600
/etc/cron.daily/ root.root 700
@@ -15,7 +14,6 @@
/etc/crontab root.root 600
/etc/dhcpcd/ root.root 700
/etc/dhcpcd/* root.root 600
-/etc/esd.conf root.audio 640
/etc/ftpaccess root.root 600
/etc/ftpconversions root.root 600
/etc/ftpgroups root.root 600
@@ -26,29 +24,32 @@
/etc/hosts.deny root.root 600
/etc/hosts.equiv root.root 600
/etc/inetd.conf root.root 600
-/etc/rc.d/init.d/ root.root 700
-/etc/rc.d/init.d/syslog root.root 700
/etc/inittab root.root 600
/etc/ld.so.conf root.root 600
/etc/lilo.conf root.root 600
+/etc/mandrake-release root.root 600
/etc/modules.conf root.root 600
/etc/motd root.root 644
-/etc/printcap root.lp 640
+/etc/printcap root.lp 640
/etc/profile.d/* root.root 755
-/etc/rc.d/ root.root 600
+/etc/rc.d/ root.root 700
+/etc/rc.d/init.d/ root.root 700
+/etc/rc.d/init.d/* root.root 700
/etc/securetty root.root 600
/etc/sendmail.cf root.root 600
-/etc/shutdown.allow root.root 600
-/etc/ssh_config root.root 644
-/etc/ssh_host_key root.root 600
-/etc/ssh_host_key.pub root.root 644
-/etc/sshd_config root.root 600
+/etc/shutdown.allow root.root 600
+/etc/ssh/ssh_config root.root 644
+/etc/ssh/ssh_host_*key root.root 600
+/etc/ssh/ssh_host_*key.pub root.root 644
+/etc/ssh/sshd_config root.root 600
+/etc/sysconfig root.root 711
/etc/syslog.conf root.root 600
/etc/updatedb.conf root.root 600
/home/ root.root 711
/home/* current 700
/lib/ root.root 711
/mnt/ root.root 710
+/proc root.kmem 550
/root/ root.root 700
/sbin/ root.root 711
/tmp/ root.root 1777
@@ -58,27 +59,26 @@
/usr/bin/ root.root 711
/usr/bin/cc root.ctools 750
/usr/bin/finger root.ntools 750
-/usr/bin/gcc root.ctools 750
-/usr/bin/g++ root.ctools 750
+/usr/bin/g++* root.ctools 750
+/usr/bin/gcc* root.ctools 750
/usr/bin/ping root.ntools 750
+/usr/bin/ssh root.ntools 750
/usr/bin/telnet root.ntools 750
/usr/bin/w root.ntools 750
/usr/bin/who root.ntools 750
-/usr/bin/ssh root.ntools 750
+/usr/lib/rpm/rpm? rpm.rpm 750
/usr/sbin/ root.root 711
/usr/sbin/sendmail root.root 755
/usr/sbin/traceroute root.ntools 750
-/usr/lib/rpm/rpm? rpm.rpm 750
/usr/share/doc rpm.rpm 710
+/usr/share/man rpm.rpm 710
+/usr/tmp root.root 1777
/var/ root.root 755
+/var/lock/subsys root.root 700
/var/log/ root.root 711
/var/log/* root.root 600
-/var/log/squidGuard squid.squid 751
-/var/log/squid squid.squid 751
-/var/log/snort snort.snort 750
-/var/log/uucp uucp.uucp 750
-/var/log/news news.news 750
-/var/log/security/ root.root 700
-/var/log/security/* root.root 600
+/var/log/*/* current 600
+/var/log/*/*/* current 600
+/var/log/*/. current 700
/var/spool/mail/ root.mail 771
/var/tmp root.root 1777
diff --git a/conf/perm.snf b/conf/perm.snf
index 33bc189..3b12650 100644
--- a/conf/perm.snf
+++ b/conf/perm.snf
@@ -1,11 +1,10 @@
# Welcome in Level 4, aka secure & usable.
###
+/ root.adm 751
/bin/ root.root 711
/bin/rpm rpm.rpm 750
/boot/ root.root 700
/dev/ root.root 711
-/dev/audio* root.audio 600
-/dev/dsp* root.audio 600
/etc/ root.adm 711
/etc/conf.modules root.adm 640
/etc/cron.daily/ root.adm 750
@@ -15,7 +14,6 @@
/etc/crontab root.adm 640
/etc/dhcpcd/ root.adm 750
/etc/dhcpcd/* root.adm 640
-/etc/esd.conf root.audio 640
/etc/ftpaccess root.adm 640
/etc/ftpconversions root.adm 640
/etc/ftpgroups root.adm 640
@@ -26,29 +24,31 @@
/etc/hosts.deny root.adm 640
/etc/hosts.equiv root.adm 640
/etc/inetd.conf root.adm 640
-/etc/rc.d/init.d/ root.adm 750
-/etc/rc.d/init.d/syslog root.adm 740
/etc/inittab root.adm 640
/etc/ld.so.conf root.adm 640
/etc/lilo.conf root.adm 600
+/etc/mandrake-release root.adm 640
/etc/modules.conf root.adm 640
/etc/motd root.adm 644
/etc/printcap root.lp 640
/etc/profile.d/* root.root 755
/etc/rc.d/ root.adm 640
+/etc/rc.d/init.d/ root.adm 750
+/etc/rc.d/init.d/syslog root.adm 740
/etc/securetty root.root 640
/etc/sendmail.cf root.adm 640
/etc/shutdown.allow root.root 600
-/etc/ssh_config root.root 644
-/etc/ssh_host_key root.adm 640
-/etc/ssh_host_key.pub root.adm 644
-/etc/sshd_config root.adm 640
+/etc/ssh/ssh_config root.root 644
+/etc/ssh/ssh_host_*key root.adm 600
+/etc/ssh/ssh_host_*key.pub root.adm 644
+/etc/ssh/sshd_config root.adm 640
/etc/syslog.conf root.adm 640
/etc/updatedb.conf root.adm 640
/home/ root.adm 751
/home/* current 700
/lib/ root.adm 751
/mnt/ root.adm 750
+/proc root.kmem 550
/root/ root.root 700
/sbin/ root.adm 751
/tmp/ root.root 1777
@@ -56,22 +56,20 @@
/usr/* root.adm 751
/usr/X11R6/ root.xgrp 751
/usr/bin/ root.adm 751
-/usr/sbin/ root.adm 751
/usr/lib/rpm/rpm? rpm.rpm 750
+/usr/sbin/ root.adm 751
/usr/share/doc rpm.rpm 750
+/usr/share/man rpm.rpm 750
+/usr/tmp root.root 1777
/var/ root.root 755
+/var/lib/monitoring root.root 751
+/var/lib/naat root.admin 2770
+/var/lock/subsys root.root 700
/var/log/ root.root 711
/var/log/* root.root 600
-/var/log/squidGuard squid.squid 751
-/var/log/squid squid.squid 751
-/var/log/uucp uucp.uucp 750
-/var/log/news news.news 750
-/var/log/security/ root.root 700
-/var/log/security/* root.root 600
+/var/log/*/* current 600
+/var/log/*/*/* current 600
+/var/log/*/. current 700
/var/spool/mail/ root.mail 771
/var/tmp root.root 1777
-/var/lib/monitoring root.root 751
-/var/lib/naat root.admin 2770
-/var/log/httpd-naat httpd-naat.admin 750
/var/www-naat httpd-naat.admin 750
-/var/log/snort snort.snort 750
diff --git a/cron-sh/diff_check.sh b/cron-sh/diff_check.sh
index 1b6f9e4..f93c754 100755
--- a/cron-sh/diff_check.sh
+++ b/cron-sh/diff_check.sh
@@ -55,7 +55,8 @@ fi
if [[ ${CHECK_WRITEABLE} == yes ]]; then
if [[ -f ${WRITEABLE_YESTERDAY} ]]; then
- if ! diff -u ${WRITEABLE_YESTERDAY} ${WRITEABLE_TODAY} > ${WRITEABLE_DIFF}; then
+ diff -u ${WRITEABLE_YESTERDAY} ${WRITEABLE_TODAY} > ${WRITEABLE_DIFF}
+ if [ -s ${WRITEABLE_DIFF} ]; then
printf "\nSecurity Warning: Change in World Writeable Files found :\n" >> ${TMP}
grep '^+' ${WRITEABLE_DIFF} | grep -vw "^+++ " | sed 's|^.||' | while read file; do
printf "\t\t- Added writables files : ${file}\n"
@@ -72,7 +73,8 @@ fi
if [[ ${CHECK_UNOWNED} == yes ]]; then
if [[ -f ${UNOWNED_USER_YESTERDAY} ]]; then
- if ! diff -u ${UNOWNED_USER_YESTERDAY} ${UNOWNED_USER_TODAY} > ${UNOWNED_USER_DIFF}; then
+ diff -u ${UNOWNED_USER_YESTERDAY} ${UNOWNED_USER_TODAY} > ${UNOWNED_USER_DIFF}
+ if [ -s ${UNOWNED_USER_DIFF} ]; then
printf "\nSecurity Warning: the following files aren't owned by an user :\n" >> ${TMP}
grep '^+' ${UNOWNED_USER_DIFF} | grep -vw "^+++ " | sed 's|^.||' | while read file; do
printf "\t\t- Added un-owned files : ${file}\n"
@@ -84,7 +86,8 @@ if [[ ${CHECK_UNOWNED} == yes ]]; then
fi
if [[ -f ${UNOWNED_GROUP_YESTERDAY} ]]; then
- if ! diff -u ${UNOWNED_GROUP_YESTERDAY} ${UNOWNED_GROUP_TODAY} > ${UNOWNED_GROUP_DIFF}; then
+ diff -u ${UNOWNED_GROUP_YESTERDAY} ${UNOWNED_GROUP_TODAY} > ${UNOWNED_GROUP_DIFF}
+ if [ -s ${UNOWNED_GROUP_DIFF} ]; then
printf "\nSecurity Warning: the following files aren't owned by a group :\n" >> ${TMP}
grep '^+' ${UNOWNED_GROUP_DIFF} | grep -vw "^+++ " | sed 's|^.||' | while read file; do
printf "\t\t- Added un-owned files : ${file}\n"
@@ -102,7 +105,8 @@ if [[ ${CHECK_SUID_MD5} == yes ]]; then
ctrl_md5=0;
if [[ -f ${SUID_MD5_YESTERDAY} ]]; then
- if ! diff -u ${SUID_MD5_YESTERDAY} ${SUID_MD5_TODAY} > ${SUID_MD5_DIFF}; then
+ diff -u ${SUID_MD5_YESTERDAY} ${SUID_MD5_TODAY} > ${SUID_MD5_DIFF}
+ if [ -s ${SUID_MD5_DIFF} ]; then
grep '^+' ${SUID_MD5_DIFF} | grep -vw "^+++ " | sed 's|^.||' | awk '{print $2}' | while read file; do
if cat ${SUID_MD5_YESTERDAY} | awk '{print $2}' | grep -qw ${file}; then
if [[ ${ctrl_md5} == 0 ]]; then
@@ -122,8 +126,9 @@ fi
if [[ ${CHECK_OPEN_PORT} == yes ]]; then
if [[ -f ${OPEN_PORT_YESTERDAY} ]]; then
- if ! diff -u ${OPEN_PORT_YESTERDAY} ${OPEN_PORT_TODAY} 1> ${OPEN_PORT_DIFF}; then
- printf "\nSecurity Warning: There is modifications for port listening on your machine :\n" >> ${TMP}
+ diff -u ${OPEN_PORT_YESTERDAY} ${OPEN_PORT_TODAY} 1> ${OPEN_PORT_DIFF}
+ if [ -s ${OPEN_PORT_DIFF} ]; then
+ printf "\nSecurity Warning: There are modifications for port listening on your machine :\n" >> ${TMP}
grep '^+' ${OPEN_PORT_DIFF} | grep -vw "^+++ " | sed 's|^.||' | while read file; do
printf "\t\t- Opened ports : ${file}\n"
done >> ${TMP}
@@ -135,26 +140,47 @@ if [[ ${CHECK_OPEN_PORT} == yes ]]; then
fi
+### rpm database
+if [[ ${RPM_CHECK} == yes ]]; then
+ if [[ -f ${RPM_VA_YESTERDAY} ]]; then
+ diff -u ${RPM_VA_YESTERDAY} ${RPM_VA_TODAY} > ${RPM_VA_DIFF}
+ if [ -s ${RPM_VA_DIFF} ]; then
+ printf "\nSecurity Warning: These files have been modified on the system :\n" >> ${TMP}
+ grep '^+' ${RPM_VA_DIFF} | grep -vw "^+++ " | sed 's|^.||' | while read file; do
+ printf "\t\t- newly modified : ${file}\n"
+ done >> ${TMP}
+ grep '^-' ${RPM_VA_DIFF} | grep -vw "^--- " | sed 's|^.||' | while read file; do
+ printf "\t\t- no more modified : ${file}\n"
+ done >> ${TMP}
+ fi
+ fi
+ if [[ -f ${RPM_QA_YESTERDAY} ]]; then
+ diff -u ${RPM_QA_YESTERDAY} ${RPM_QA_TODAY} > ${RPM_QA_DIFF}
+ if [ -s ${RPM_QA_DIFF} ]; then
+ printf "\nSecurity Warning: These packages have changed on the system :\n" >> ${TMP}
+ grep '^+' ${RPM_QA_DIFF} | grep -vw "^+++ " | sed 's|^.||' | while read file; do
+ printf "\t\t- added package : ${file}\n"
+ done >> ${TMP}
+ grep '^-' ${RPM_QA_DIFF} | grep -vw "^--- " | sed 's|^.||' | while read file; do
+ printf "\t\t- removed package : ${file}\n"
+ done >> ${TMP}
+ fi
+ fi
+fi
+
######## Report ######
if [[ -s ${TMP} ]]; then
Syslog ${TMP}
Ttylog ${TMP}
date=`date`
+ hostname=`hostname`
echo -e "\n\n*** Diff Check, ${date} ***\n" >> ${SECURITY_LOG}
cat ${TMP} >> ${SECURITY_LOG}
- Maillog "*** Diff Check, ${date} ***" "${TMP}"
+ Maillog "*** Diff Check on ${hostname}, ${date} ***" "${TMP}"
fi
if [[ -f ${TMP} ]]; then
rm -f ${TMP}
fi
-
-
-
-
-
-
-
-
diff --git a/cron-sh/security.sh b/cron-sh/security.sh
index 01d3e4c..5b974a4 100755
--- a/cron-sh/security.sh
+++ b/cron-sh/security.sh
@@ -30,6 +30,12 @@ UNOWNED_USER_DIFF="/var/log/security/unowned_user.diff"
export UNOWNED_GROUP_TODAY="/var/log/security/unowned_group.today"
UNOWNED_GROUP_YESTERDAY="/var/log/security/unowned_group.yesterday"
UNOWNED_GROUP_DIFF="/var/log/security/unowned_group.diff"
+export RPM_VA_TODAY="/var/log/security/rpm-va.today"
+RPM_VA_YESTERDAY="/var/log/security/rpm-va.yesterday"
+RPM_VA_DIFF="/var/log/security/rpm-va.diff"
+export RPM_QA_TODAY="/var/log/security/rpm-qa.today"
+RPM_QA_YESTERDAY="/var/log/security/rpm-qa.yesterday"
+RPM_QA_DIFF="/var/log/security/rpm-qa.diff"
# Modified filters coming from debian security scripts.
CS_NFSAFS='(nfs|afs|xfs|coda)'
@@ -72,6 +78,13 @@ if [[ -f ${SUID_MD5_TODAY} ]]; then
mv ${SUID_MD5_TODAY} ${SUID_MD5_YESTERDAY};
fi
+if [[ -f ${RPM_VA_TODAY} ]]; then
+ mv -f ${RPM_VA_TODAY} ${RPM_VA_YESTERDAY}
+fi
+
+if [[ -f ${RPM_QA_TODAY} ]]; then
+ mv -f ${RPM_QA_TODAY} ${RPM_QA_YESTERDAY}
+fi
netstat -pvlA inet 2> /dev/null > ${OPEN_PORT_TODAY};
@@ -109,6 +122,19 @@ if [[ -f ${SUID_ROOT_TODAY} ]]; then
done < ${SUID_ROOT_TODAY} > ${SUID_MD5_TODAY}
fi
+### rpm database check
+
+if [[ ${RPM_CHECK} == yes ]]; then
+ if [ -f /var/lib/rpm/__db.001 -o -f /var/lib/rpm/__db.002 ]; then
+ rm -f /var/lib/rpm/__db.00*
+ rpm --rebuilddb
+ fi
+
+ rpm -qa --qf "%{NAME}-%{VERSION}-%{RELEASE}\t%{INSTALLTIME}\n" | sort > ${RPM_QA_TODAY}
+
+ nice --adjustment=+19 rpm -V `cut -f 1 < ${RPM_QA_TODAY} | grep -v '^dev-[0-9]'` | grep '^..5' | sed 's/...........//' | sort > ${RPM_VA_TODAY}
+fi
+
### Functions ###
Syslog() {
@@ -121,7 +147,7 @@ Syslog() {
Ttylog() {
if [[ ${TTY_WARN} == yes ]]; then
- for i in `w | grep -v "load\|TTY" | awk '{print $2}'` ; do
+ for i in `w | grep -v "load\|TTY" | grep '^root' | awk '{print $2}'` ; do
cat ${1} > /dev/$i
done
fi
@@ -146,11 +172,3 @@ Maillog() {
. /usr/share/msec/diff_check.sh
. /usr/share/msec/security_check.sh
-
-
-
-
-
-
-
-
diff --git a/cron-sh/security_check.sh b/cron-sh/security_check.sh
index 5055b52..9ffc469 100755
--- a/cron-sh/security_check.sh
+++ b/cron-sh/security_check.sh
@@ -36,7 +36,7 @@ fi
if [[ ${CHECK_UNOWNED} == yes ]]; then
if [[ -s ${UNOWNED_USER_TODAY} ]]; then
printf "\nSecurity Warning : User Unowned files found :\n" >> ${SECURITY}
- printf "\t( theses files now have user \"nobody\" as their owner. )\n" >> ${SECURITY_LOG}
+ printf "\t( theses files now have user \"nobody\" as their owner. )\n" >> ${SECURITY}
cat ${UNOWNED_USER_TODAY} | awk '{print "\t\t- " $0}' >> ${SECURITY}
cat ${UNOWNED_USER_TODAY} | while read line; do
chown nobody "${line}"; # Use quote if filename contain space.
@@ -135,6 +135,8 @@ if [[ ${CHECK_PASSWD} == yes ]]; then
printf("\t\t- /etc/passwd:%d: User \"%s\" has no password !\n", FNR, $1);
else if ($2 !~ /^[x*!]+$/)
printf("\t\t- /etc/passwd:%d: User \"%s\" has a real password (it is not shadowed).\n", FNR, $1);
+ else if ( $3 == 0 && $1 != "root" )
+ printf("\t\t- /etc/passwd:%d: User \"%s\" has id 0 !\n", FNR, $1);
}' < /etc/passwd > ${TMP}
if [[ -s ${TMP} ]]; then
@@ -245,17 +247,29 @@ if [[ ${CHECK_OPEN_PORT} == yes ]]; then
fi
+### rpm database checks
+if [[ ${RPM_CHECK} == yes ]]; then
+
+ if [[ -s ${RPM_VA_TODAY} ]]; then
+ printf "\nSecurity Warning: These files belonging to packages are modified on the system :\n" >> ${SECURITY}
+ cat ${RPM_VA_TODAY} | while read f; do
+ printf "\t\t- $f\n"
+ done >> ${SECURITY}
+ fi
+fi
+
### Report
if [[ -s ${SECURITY} ]]; then
Syslog ${SECURITY}
Ttylog ${SECURITY}
date=`date`
-
+ hostname=`hostname`
+
echo -e "\n\n*** Security Check, ${date} ***\n" >> ${SECURITY_LOG}
cat ${SECURITY} >> ${SECURITY_LOG}
cat ${INFOS} >> ${SECURITY_LOG}
- Maillog "*** Security Check, ${date} ***" "${SECURITY} ${INFOS}"
+ Maillog "*** Security Check on ${hostname}, ${date} ***" "${SECURITY} ${INFOS}"
fi
if [[ -f ${SECURITY} ]]; then
@@ -269,7 +283,3 @@ fi
if [[ -f ${INFOS} ]]; then
rm -f ${INFOS};
fi
-
-
-
-
diff --git a/init-sh/cleanold.sh b/init-sh/cleanold.sh
new file mode 100755
index 0000000..90c2df8
--- /dev/null
+++ b/init-sh/cleanold.sh
@@ -0,0 +1,133 @@
+#
+# Security level implementation...
+# Writen by Vandoorselaere Yoann <yoann@mandrakesoft.com>
+#
+
+# Need root access
+if [[ ${UID} != 0 ]]; then
+ echo "You need to be root in order to change secure level."
+ exit 1
+fi
+
+export COMMENT="# Mandrake-Security : if you remove this comment, remove the next line too."
+
+AddRules() {
+ string=$1
+ file=$2
+ quiet=$3
+
+ if [[ -z ${string} ]]; then
+ return;
+ fi
+
+ if [[ -z ${quiet} ]]; then
+ echo "Modifying config in ${file}..."
+ fi
+
+ if ! grep -qEx "^${string}" ${file}; then
+ echo -e "${COMMENT}" >> ${file};
+ echo -e "${string}" >> ${file};
+ fi
+
+ if [[ -z ${3} ]]; then
+ echo -e "done.\n"
+ fi
+}
+
+CleanRules() {
+ echo -en "\t- Cleaning msec appended line in $1 : "
+
+ perl -ni -e '$_ eq "$ENV{COMMENT}\n" ... // or print' $1
+
+ echo "done."
+}
+
+CommentUserRules() {
+ file=$1
+
+ if [[ ! -f ${file} ]]; then
+ return;
+ fi
+
+ echo -en "\t- Cleaning user appended line in ${file} : "
+
+ tmpfile=`mktemp /tmp/secure.XXXXXX`
+ cp -f ${file} ${tmpfile}
+
+ while read line; do
+ if ! echo "${line}" | grep -qE "^#"; then
+ echo "# ${line}"
+ else
+ echo "${line}"
+ fi
+ done < ${tmpfile} > ${file}
+
+ rm -f ${tmpfile}
+
+ echo "done."
+}
+
+RestoreIssues () {
+ if [ ! -f /etc/issue.net -a -f /etc/issue.net.msec ]; then
+ mv -f /etc/issue.net.msec /etc/issue.net
+ fi
+
+ if [ ! -f /etc/issue -a -f /etc/issue.msec ]; then
+ mv -f /etc/issue.msec /etc/issue
+ fi
+}
+
+# If we are currently installing our
+# system with DrakX, we don't ask anything to the user...
+# Instead, DrakX do it and give us a file with some variable.
+if [[ -f /etc/security/msec/security.conf ]]; then
+ . /etc/security/msec/security.conf
+fi
+
+CleanRules /etc/syslog.conf
+CleanRules /etc/hosts.deny
+CleanRules /etc/hosts.allow
+CleanRules /etc/securetty
+CleanRules /etc/security/msec/security.conf
+CleanRules /etc/ld.so.preload
+CleanRules /etc/host.conf
+CleanRules /etc/sysctl.conf
+
+CleanRules /etc/logrotate.conf
+CleanRules /etc/rc.d/rc.local
+CleanRules /etc/rc.d/rc.firewall
+CleanRules /etc/crontab
+CleanRules /etc/profile
+CleanRules /etc/zprofile
+
+RestoreIssues
+
+if [[ -f /etc/X11/xinit.d/msec ]]; then
+ CleanRules /etc/X11/xinit.d/msec
+else
+ touch /etc/X11/xinit.d/msec
+ chmod 755 /etc/X11/xinit.d/msec
+fi
+
+if [[ -f /etc/sysconfig/msec ]]; then
+ CleanRules /etc/sysconfig/msec
+fi
+
+if [[ -f /etc/profile.d/msec.sh && -f /etc/profile.d/msec.csh ]]; then
+ CleanRules /etc/profile.d/msec.sh
+ CleanRules /etc/profile.d/msec.csh
+else
+ chmod 755 /etc/profile.d/msec.sh
+ chmod 755 /etc/profile.d/msec.csh
+fi
+
+# default group which must exist on the system
+# groupadd already check for their existance...
+groupadd nogroup >& /dev/null
+groupadd audio >& /dev/null
+groupadd xgrp >& /dev/null
+groupadd ntools >& /dev/null
+groupadd ctools >& /dev/null
+
+usermod -G xgrp xfs
+
diff --git a/msec.sh b/msec.sh
index 759fc18..d01e68b 100755
--- a/msec.sh
+++ b/msec.sh
@@ -11,3 +11,5 @@ if ! echo ${PATH} |grep -q /usr/games ; then
fi
export SECURE_LEVEL=${SECURE_LEVEL}
+
+[ -n "$TMOUT" ] && typeset -r TMOUT
diff --git a/msec.spec b/msec.spec
index 29bd4a6..546e414 100644
--- a/msec.spec
+++ b/msec.spec
@@ -1,9 +1,9 @@
Summary: Security Level & Program for the Mandrake Linux distribution
Name: msec
-Version: 0.16
-Release: 4mdk
+Version: 0.17
+Release: 12mdk
Url: http://www.linux-mandrake.com
-Source0: %{name}-%{version}.tar.bz2
+Source0: %{name}-%{version}.tar.bz2
Source1: msec.logrotate
Source2: msec.sh
Source3: msec.csh
@@ -11,7 +11,8 @@ Source3: msec.csh
License: GPL
Group: System/Base
BuildRoot: %_tmppath/%name-%version-%release-root
-Requires: /bin/bash /bin/touch setup chkconfig >= 0.9-6
+Requires: /bin/bash /bin/touch perl diffutils textutils /usr/bin/python /usr/bin/chage gawk
+Requires: setup >= 2.2.0-19mdk
Requires: chkconfig >= 1.2.24-3mdk
%description
@@ -29,6 +30,9 @@ in order to test the security of your system and alert you if needed.
%build
make CFLAGS="$RPM_OPT_FLAGS"
+cd share; ./compile.py '/usr/share/msec/' *.py
+rm -f msec.pyo
+
%install
#make install RPM_BUILD_ROOT=$RPM_BUILD_ROOT
@@ -39,8 +43,8 @@ install -d $RPM_BUILD_ROOT/usr/sbin $RPM_BUILD_ROOT/usr/bin
install -d $RPM_BUILD_ROOT/var/log/security
install -d $RPM_BUILD_ROOT%{_mandir}/man8
-install -m 755 init-sh/*.sh cron-sh/*.sh $RPM_BUILD_ROOT/usr/share/msec
-install -m 755 init-sh/msec $RPM_BUILD_ROOT/usr/sbin
+cp -p init-sh/cleanold.sh share/*.py share/*.pyo cron-sh/*.sh $RPM_BUILD_ROOT/usr/share/msec
+install -m 755 share/msec $RPM_BUILD_ROOT/usr/sbin
install -m 644 conf/perm.* conf/server.* $RPM_BUILD_ROOT/etc/security/msec
install -m 755 src/promisc_check/promisc_check src/msec_find/msec_find $RPM_BUILD_ROOT/usr/bin
@@ -62,26 +66,17 @@ install -m 755 %{SOURCE2} $RPM_BUILD_ROOT/etc/profile.d
install -m 755 %{SOURCE3} $RPM_BUILD_ROOT/etc/profile.d
touch $RPM_BUILD_ROOT/var/log/security.log
-%post
+%post -p /bin/sh
touch /var/log/security.log
-# create the /etc/security/msec/server
-# the /usr/share/msec/current-level.sh and
-# /etc/security/msec/current.perm files
-if [[ ${SECURE_LEVEL} == 4 || ${SECURE_LEVEL} == 5 || ${SECURE_LEVEL} == snf ]]; then
- ln -sf /etc/security/msec/server.${SECURE_LEVEL} /etc/security/msec/server
- else
- rm -rf /etc/security/msec/server
- chkconfig --list |awk ' {print $1}' | grep -v ":" | sort -u > /etc/security/msec/server
-fi
-
-ln -sf /usr/share/msec/level${SECURE_LEVEL}.sh /usr/share/msec/current-level.sh
-echo
-echo "You might need to logout of your terminal session in order to update your environment variables."
-echo
-if [[ -f /etc/security/msec/perm.${SECURE_LEVEL} ]]; then
- ln -sf /etc/security/msec/perm.${SECURE_LEVEL} /etc/security/msec/current.perm
- /usr/share/msec/file_perm.sh /etc/security/msec/current.perm
+if [ $1 != 1 -a -f /etc/security/msec/security.conf ]; then
+ if grep -q "# Mandrake-Security : if you remove this comment" /etc/security/msec/security.conf; then
+ SL=`sed -n 's/SECURE_LEVEL=//p' < /etc/sysconfig/msec` || :
+ /usr/share/msec/cleanold.sh || :
+ msec $SL < /dev/null || :
+ else
+ msec < /dev/null || :
+ fi
fi
%clean
@@ -89,7 +84,7 @@ rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
-%doc AUTHORS COPYING Makefile README
+%doc AUTHORS COPYING Makefile share/README share/CHANGES
%doc doc/*txt ChangeLog doc/*ps
%_bindir/promisc_check
%_bindir/msec_find
@@ -108,6 +103,66 @@ rm -rf $RPM_BUILD_ROOT
# MAKE THE CHANGES IN CVS: NO PATCH OR SOURCE ALLOWED
%changelog
+* Thu Jan 17 2002 Frederic Lepied <flepied@mandrakesoft.com> 0.17-12mdk
+- report cron log to tty only on root ttys.
+- better layout of rpm modified files report.
+
+* Wed Jan 9 2002 Frederic Lepied <flepied@mandrakesoft.com> 0.17-11mdk
+- added hostname to the subject of the mail report for better information
+when you receive multiple reports
+
+- really added rpm-va check to the mail report
+
+- fix handling of the owner/group of subdirectories of /var/log in a
+generic manner.
+
+- oops put back periodic filesystems check
+
+* Mon Jan 7 2002 Frederic Lepied <flepied@mandrakesoft.com> 0.17-10mdk
+- corrected first invocation.
+
+* Sun Jan 6 2002 Frederic Lepied <flepied@mandrakesoft.com> 0.17-9mdk
+- oops: corrected broken security.sh script
+
+* Fri Jan 4 2002 Frederic Lepied <flepied@mandrakesoft.com> 0.17-8mdk
+- TMOUT is now a read only variable
+- allow/forbid reboot/shutdown by [kg]dm
+
+* Thu Jan 3 2002 Frederic Lepied <flepied@mandrakesoft.com> 0.17-7mdk
+- rpm -qa check now logs install time too
+- corrected the way we install the byte compiled python files to avoid
+false rpm -V warnings.
+- added a CHANGES file to document what has changed between 0.16 and 0.17
+- send complete rpm -va check to the main mail
+- perm.*: added handling of /etc/rc.d/init.d/*
+- changed the way /etc/security/msec/perm.local is used to avoid flip/flap changes
+- reworked output in diff rpm check to be more coherent
+
+* Sat Dec 29 2001 Frederic Lepied <flepied@mandrakesoft.com> 0.17-6mdk
+- added doc of the features of the msec utility
+- corrected enable_at_crontab
+- password_aging only takes care of /etc/shadow users and avoid the users
+with a deactivated password.
+
+* Fri Dec 28 2001 Frederic Lepied <flepied@mandrakesoft.com> 0.17-5mdk
+- added rpm database checks
+- added check of accounts with the 0 id that aren't root.
+
+* Thu Dec 27 2001 Frederic Lepied <flepied@mandrakesoft.com> 0.17-4mdk
+- disable root login in xdm,kdm,gdm the same way as in Bastille (via pam).
+- manage password aging.
+- manage crontab and at authorization.
+
+* Thu Dec 27 2001 Frederic Lepied <flepied@mandrakesoft.com> 0.17-3mdk
+- avoid changing permissions twice in the same run (to avoid unneeded logging).
+- when run in non-interactive mode, the output goes to the auth facility.
+
+* Fri Dec 14 2001 Frederic Lepied <flepied@mandrakesoft.com> 0.17-2mdk
+- fixed sysctl.conf handling
+
+* Thu Dec 13 2001 Frederic Lepied <flepied@mandrakesoft.com> 0.17-1mdk
+- rewritten file modifications part in python
+
* Wed Dec 05 2001 Florin <florin@mandrakesoft.com> 0.16-4mdk
- oups, use %{_sysconfdir}/sysconfig/%{name} instead of %{_sysconfdir}/%{name}
- fix the msec.csh file (thks again to Konrad Bernlohr)
diff --git a/share/.cvsignore b/share/.cvsignore
new file mode 100644
index 0000000..34fcef1
--- /dev/null
+++ b/share/.cvsignore
@@ -0,0 +1,2 @@
+*.pyo
+*.pyc
diff --git a/share/CHANGES b/share/CHANGES
new file mode 100644
index 0000000..0e66020
--- /dev/null
+++ b/share/CHANGES
@@ -0,0 +1,40 @@
+changes between version 0.16 and 0.17
+=====================================
+
+msec utility changes:
+
+ * handle shell timeout (level 4 and 5)
+ * limit shell history (level 4 and 5)
+ * su only for wheel group (level 5)
+ * sulogin for single user mode (level 4 and 5)
+ * various sysctl.conf settings for icmp and network parameters
+ * password aging (level 4 and 5)
+ * suppress /etc/issue.net (level 4 and 5) and /etc/issue (level 5)
+ * removed manipulation of the groups of users
+ * removed removal of services
+ * logging in syslog according to the guideline for explanations in tools
+ * rewritten in python
+
+msec can be used to change level and it's also run hourly by cron to
+maintain the security level on the system. Only the minimum of changes
+on the filesystem are applied and the minimum of programs started.
+
+Periodic security checks changes:
+
+ * added an rpm database check (rpm -va and rpm -qa)
+ * report when a user other than root is at uid 0
+
+Permissions settings changes:
+
+ * /
+ * removed audio group handling because it has always conflicted with pam_console
+ * handle /var/log sub-directories in a generic manner
+ * /etc/rc.d/init.d/*
+ * corrected ssh related paths
+ * /etc/sysconfig
+ * /proc
+ * corrected gcc files
+ * rpm related files to avoid exposing what is installed
+ * /var/lock/subsys
+ * added a local.perm to allow modifications without modifying level perms
+ * rewritten in python
diff --git a/share/Config.py b/share/Config.py
new file mode 100644
index 0000000..ee2c10e
--- /dev/null
+++ b/share/Config.py
@@ -0,0 +1,46 @@
+#---------------------------------------------------------------
+# Project : Linux-Mandrake
+# Module : msec2
+# File : Config.py
+# Version : $Id$
+# Author : Frederic Lepied
+# Created On : Thu Dec 6 19:54:35 2001
+# Purpose : configuration settings
+#---------------------------------------------------------------
+
+import sys
+
+CONFIG='/etc/security/msec2.conf'
+
+_config={ 'root' : '',
+ 'run_commands': 1,
+ 'log': 'syslog',
+ }
+try:
+ execfile(CONFIG, _config)
+except IOError:
+ #sys.stderr.write("no config file in %s. Using default values.\n" % CONFIG)
+ pass
+
+def get_config(name, default=None):
+ try:
+ return _config[name]
+ except KeyError:
+ return default
+
+def set_config(name, value):
+ _config[name] = value
+
+def converthexa(array):
+ result=""
+ for c in array:
+ o=ord(c)
+ d=o/16
+ u=o-(d*16)
+ result=result + "%x%x" % (d, u)
+ return result
+
+def hashstring(str):
+ return converthexa(md5.new(str).digest())
+
+# Config.py ends here
diff --git a/share/ConfigFile.py b/share/ConfigFile.py
new file mode 100644
index 0000000..3e24b9b
--- /dev/null
+++ b/share/ConfigFile.py
@@ -0,0 +1,376 @@
+#---------------------------------------------------------------
+# Project : Mandrake Linux
+# Module : msec2
+# File : ConfigFile.py
+# Version : $Id$
+# Author : Frederic Lepied
+# Created On : Wed Dec 5 21:42:49 2001
+# Purpose : class abstraction to handle configuration
+# files.
+#---------------------------------------------------------------
+
+import re
+import string
+import os
+import stat
+import Config
+import commands
+from Log import *
+import gettext
+
+try:
+ cat = gettext.Catalog('msec')
+ _ = cat.gettext
+except IOError:
+ _ = str
+
+BEFORE=0
+INSIDE=1
+AFTER=2
+
+space = re.compile('\s')
+
+class ConfigFiles:
+ def __init__(self):
+ self.files = {}
+ self.modified_files = []
+ self.action_assoc = []
+
+ def add(self, file, path):
+ self.files[path] = file
+
+ def modified(self, path):
+ if not path in self.modified_files:
+ self.modified_files.append(path)
+
+ def get_config_file(self, path, suffix):
+ try:
+ return self.files[path]
+ except KeyError:
+ return ConfigFile(path, suffix, self)
+
+ def add_config_assoc(self, regex, action):
+ self.action_assoc.append((re.compile(regex), action))
+
+all_files=ConfigFiles()
+
+def move(old, new):
+ try:
+ os.unlink(new)
+ except OSError:
+ pass
+ os.rename(old, new)
+
+class ConfigFile:
+ def __init__(self, path, suffix=None, meta=all_files):
+ self.meta=meta
+ self.path = Config.get_config('root', '') + path
+ self.is_modified = 0
+ self.is_touched = 0
+ self.is_deleted = 0
+ self.is_moved = 0
+ self.suffix = suffix
+ self.lines = None
+ self.sym_link = None
+ self.meta.add(self, path)
+
+ def get_lines(self):
+ if self.lines == None:
+ file=None
+ try:
+ file = open(self.path, 'r')
+ except IOError:
+ if self.suffix:
+ try:
+ moved = self.path + self.suffix
+ file = open(moved, 'r')
+ move(moved, self.path)
+ self.meta.modified(self.path)
+ except IOError:
+ self.lines = []
+ else:
+ self.lines = []
+ if file:
+ self.lines = string.split(file.read(), "\n")
+ file.close()
+ return self.lines
+
+ def append(self, value):
+ lines = self.lines
+ l = len(lines)
+ if l > 0 and lines[l - 1] == '':
+ lines.insert(l - 1, value)
+ else:
+ lines.append(value)
+ lines.append('')
+
+ def modified(self):
+ self.is_modified = 1
+ return self
+
+ def touch(self):
+ self.is_touched = 1
+ return self
+
+ def symlink(self, link):
+ self.sym_link = link
+ return self
+
+ def exists(self):
+ return os.path.exists(self.path) or (self.suffix and os.path.exists(self.path + self.suffix))
+
+ def move(self, suffix):
+ self.suffix = suffix
+ self.is_moved = 1
+
+ def unlink(self):
+ self.is_deleted = 1
+ self.lines=[]
+ return self
+
+ def write(self):
+ if self.is_deleted:
+ if self.exists():
+ os.unlink(self.path)
+ log(_('deleted %s') % (self.path,))
+ elif self.is_modified:
+ content = string.join(self.lines, "\n")
+ file = open(self.path, 'w')
+ file.write(content)
+ file.close()
+ self.meta.modified(self.path)
+ elif self.is_touched:
+ if os.path.exists(self.path):
+ os.utime(self.path, None)
+ elif self.suffix and os.path.exists(self.path + self.suffix):
+ move(self.path + self.suffix, self.path)
+ os.utime(self.path, None)
+ else:
+ self.lines = []
+ self.is_modified = 1
+ file = open(self.path, 'w')
+ file.close()
+ log(_('touched file %s') % (self.path,))
+ elif self.sym_link:
+ done = 0
+ if self.exists():
+ full = os.lstat(self.path)
+ if stat.S_ISLNK(full[stat.ST_MODE]):
+ link = os.readlink(self.path)
+ # to be fixed: resolv relative symlink
+ done = (link == self.sym_link)
+ if not done:
+ os.unlink(self.path)
+ log(_('deleted %s') % (self.path,))
+ if not done:
+ os.symlink(self.sym_link, self.path)
+ log(_('made symbolic link from %s to %s') % (self.sym_link, self.path))
+
+ if self.is_moved:
+ move(self.path, self.path + self.suffix)
+ log(_('moved file %s to %s') % (self.path, self.path + self.suffix))
+ self.meta.modified(self.path)
+ self.is_touched = 0
+ self.is_modified = 0
+ self.is_deleted = 0
+ self.is_moved = 0
+
+ def set_shell_variable(self, var, value, start=None, end=None):
+ regex = re.compile('^' + var + '="?([^#"]+)"?(.*)')
+ lines = self.get_lines()
+ idx=0
+ value=str(value)
+
+ if start:
+ status = BEFORE
+ start = re.compile(start)
+ else:
+ status = INSIDE
+
+ if end:
+ end = re.compile(end)
+
+ idx = None
+ for idx in range(0, len(lines)):
+ line = lines[idx]
+ if status == BEFORE:
+ if start.search(line):
+ status = INSIDE
+ else:
+ continue
+ elif end and end.search(line):
+ break
+ res = regex.search(line)
+ if res:
+ if res.group(1) != value:
+ if space.search(value):
+ lines[idx] = var + '="' + value + '"' + res.group(2)
+ else:
+ lines[idx] = var + '=' + value + res.group(2)
+ self.modified()
+ log(_('set variable %s to %s in %s') % (var, value, self.path,))
+ return self
+ if space.search(value):
+ s = var + '="' + value + '"'
+ else:
+ s = var + '=' + value
+ if idx == None or idx == len(lines):
+ self.append(s)
+ else:
+ lines.insert(idx, s)
+
+ self.modified()
+ log(_('set variable %s to %s in %s') % (var, value, self.path,))
+ return self
+
+ def get_shell_variable(self, var):
+ regex = re.compile('^' + var + '="?([^#"]+)"?(.*)')
+ lines = self.get_lines()
+ for idx in range(0, len(lines)):
+ res = regex.search(lines[idx])
+ if res:
+ return res.group(1)
+ return None
+
+ def get_match(self, regex, replace=None):
+ r=re.compile(regex)
+ lines = self.get_lines()
+ matches = 0
+ for idx in range(0, len(lines)):
+ res = r.search(lines[idx])
+ if res:
+ s = substitute_re_result(res, replace)
+ return s
+ return None
+
+ def replace_line_matching(self, regex, value, at_end_if_not_found=0, all=0, start=None, end=None):
+ r=re.compile(regex)
+ lines = self.get_lines()
+ matches = 0
+
+ if start:
+ status = BEFORE
+ start = re.compile(start)
+ else:
+ status = INSIDE
+
+ if end:
+ end = re.compile(end)
+
+ idx = None
+ for idx in range(0, len(lines)):
+ line = lines[idx]
+ if status == BEFORE:
+ if start.search(line):
+ status = INSIDE
+ else:
+ continue
+ elif end and end.search(line):
+ break
+ res = r.search(line)
+ if res:
+ s = substitute_re_result(res, value)
+ matches = matches + 1
+ if s != line:
+ log(_("replaced in %s the line %d:\n%s\nwith the line:\n%s") % (self.path, idx, line, s))
+ lines[idx] = s
+ self.modified()
+ if not all:
+ return matches
+ if matches == 0 and at_end_if_not_found:
+ log(_("appended in %s the line:\n%s") % (self.path, value))
+ if idx == None or idx == len(lines):
+ self.append(value)
+ else:
+ lines.insert(idx, value)
+ self.modified()
+ matches = matches + 1
+ return matches
+
+ def insert_after(self, regex, value, at_end_if_not_found=0, all=0):
+ matches = 0
+ r=re.compile(regex)
+ lines = self.get_lines()
+ for idx in range(0, len(lines)):
+ res = r.search(lines[idx])
+ if res:
+ s = substitute_re_result(res, value)
+ log(_("inserted in %s after the line %d:\n%s\nthe line:\n%s") % (self.path, idx, lines[idx], s))
+ lines.insert(idx+1, s)
+ self.modified()
+ matches = matches + 1
+ if not all:
+ return matches
+ if matches == 0 and at_end_if_not_found:
+ log(_("appended in %s the line:\n%s") % (self.path, value))
+ self.append(value)
+ self.modified()
+ matches = matches + 1
+ return matches
+
+ def insert_at(self, idx, value):
+ lines = self.get_lines()
+ try:
+ lines.insert(idx, value)
+ log(_("inserted in %s at the line %d:\n%s") % (self.path, idx, value))
+ self.modified()
+ return 1
+ except KeyError:
+ return 0
+
+ def remove_line_matching(self, regex, all=0):
+ matches = 0
+ r=re.compile(regex)
+ lines = self.get_lines()
+ for idx in range(len(lines) - 1, -1, -1):
+ res = r.search(lines[idx])
+ if res:
+ log(_("removing in %s the line %d:\n%s") % (self.path, idx, lines[idx]))
+ lines.pop(idx)
+ self.modified()
+ matches = matches + 1
+ if not all:
+ return matches
+ return matches
+
+# utility funtions
+
+def substitute_re_result(res, s):
+ for idx in range(0, (res.lastindex or 0) + 1):
+ subst = res.group(idx) or ''
+ s = string.replace(s, '@' + str(idx), subst)
+ return s
+
+def write_files():
+ global all_files
+
+ run_commands = Config.get_config('run_commands', 0)
+ for f in all_files.files.values():
+ f.write()
+
+ for f in all_files.modified_files:
+ for a in all_files.action_assoc:
+ res = a[0].search(f)
+ if res:
+ s = substitute_re_result(res, a[1])
+ if run_commands != '0':
+ log(_('%s modified so launched command: %s') % (f, s))
+ cmd = commands.getstatusoutput(s)
+ if cmd[0] == 0:
+ log(cmd[1])
+ else:
+ error(cmd[1])
+ else:
+ log(_('%s modified so should have run command: %s') % (f, s))
+
+def get_config_file(path, suffix=None):
+ global all_files
+
+ return all_files.get_config_file(path, suffix)
+
+def add_config_assoc(regex, action):
+ global all_files
+
+ return all_files.add_config_assoc(regex, action)
+
+# ConfigFile.py ends here
diff --git a/share/Log.py b/share/Log.py
new file mode 100644
index 0000000..bcda819
--- /dev/null
+++ b/share/Log.py
@@ -0,0 +1,53 @@
+#---------------------------------------------------------------
+# Project : Mandrake Linux
+# Module : msec2
+# File : Log.py
+# Version : $Id$
+# Author : Frederic Lepied
+# Created On : Wed Dec 5 23:50:29 2001
+# Purpose : write log through syslog conforming to
+# the Mandrake Linux guideline for the explanations
+# in tools. Errors are reported to stderr.
+#---------------------------------------------------------------
+
+import syslog
+import sys
+import string
+import Config
+
+_name = ''
+_use_syslog = 1
+
+def initlog(name, facility = syslog.LOG_AUTH):
+ global _name
+ global _use_syslog
+
+ _use_syslog = (Config.get_config('log', 'syslog') == 'syslog')
+
+ if _use_syslog:
+ syslog.openlog(name, 0, facility)
+
+ _name = name
+
+def log(s, level = syslog.LOG_INFO):
+ global _use_syslog
+
+ if _use_syslog:
+ for l in string.split(s, '\n'):
+ syslog.syslog(level, l)
+ else:
+ sys.stderr.write(s + '\n')
+ return 1
+
+def closelog():
+ global _use_syslog
+
+ if _use_syslog:
+ syslog.closelog()
+
+def error(s):
+ global _name
+
+ sys.stderr.write(_name + ': ' + s + '\n')
+
+# Log.py ends here
diff --git a/share/Perms.py b/share/Perms.py
new file mode 100755
index 0000000..8a8c983
--- /dev/null
+++ b/share/Perms.py
@@ -0,0 +1,173 @@
+#!/usr/bin/python -O
+#---------------------------------------------------------------
+# Project : Mandrake Linux
+# Module : msec
+# File : Perms.py
+# Version : $Id$
+# Author : Frederic Lepied
+# Created On : Fri Dec 7 23:33:49 2001
+# Purpose : fix permissions and owner/group of files
+# and directories.
+#---------------------------------------------------------------
+
+import glob
+import re
+import string
+import os
+import stat
+import pwd
+import grp
+import Config
+from Log import *
+import gettext
+
+try:
+ cat = gettext.Catalog('msec')
+ _ = cat.gettext
+except IOError:
+ _ = str
+
+comment_regex = re.compile('^\s*#|^\s*$')
+
+user = {}
+group = {}
+userid = {}
+groupid = {}
+
+def get_user_id(name):
+ try:
+ return user[name]
+ except KeyError:
+ try:
+ user[name] = pwd.getpwnam(name)[2]
+ except KeyError:
+ error(_('user name %s not found') % name)
+ user[name] = -1
+ return user[name]
+
+def get_user_name(id):
+ try:
+ return userid[id]
+ except KeyError:
+ try:
+ userid[id] = pwd.getpwuid(id)[0]
+ except KeyError:
+ error(_('user name not found for id %d') % id)
+ userid[id] = str(id)
+ return userid[id]
+
+def get_group_id(name):
+ try:
+ return group[name]
+ except KeyError:
+ try:
+ group[name] = grp.getgrnam(name)[2]
+ except KeyError:
+ error(_('group name %s not found') % name)
+ group[name] = -1
+ return group[name]
+
+def get_group_name(id):
+ try:
+ return groupid[id]
+ except KeyError:
+ try:
+ groupid[id] = grp.getgrgid(id)[0]
+ except KeyError:
+ error(_('group name not found for id %d') % id)
+ groupid[id] = str(id)
+ return groupid[id]
+
+assoc = {}
+
+def fix_perms(path):
+ try:
+ file = open(path, 'r')
+ except IOError:
+ return
+ root = Config.get_config('root', '')
+ lineno = 0
+ for line in file.readlines():
+ lineno = lineno + 1
+ if comment_regex.search(line):
+ continue
+ fields = re.split('\s*', line)
+ newmode = int(fields[2], 8)
+ if fields[1] == 'current':
+ user = group = -1
+ user_str = group_str = ''
+ else:
+ (user_str, group_str) = string.split(fields[1], '.')
+ user = get_user_id(user_str)
+ group = get_group_id(group_str)
+ if len(fields) == 4:
+ for f in glob.glob(fields[0]):
+ try:
+ full = os.stat(f)
+ except OSError:
+ continue
+ mode = stat.S_IMODE(full[stat.ST_MODE])
+ newperm = newmode
+ if stat.S_ISDIR(full[stat.ST_MODE]):
+ if newperm & 0400:
+ newperm = newperm | 0100
+ if newperm & 0040:
+ newperm = newperm | 0010
+ if newperm & 0004:
+ newperm = newperm | 0001
+ uid = full[stat.ST_UID]
+ gid = full[stat.ST_GID]
+ if f != '/' and f[-1] == '/':
+ f = f[:-1]
+ if f[-2:] == '/.':
+ f = f[:-2]
+ assoc[f] = (mode, uid, gid, newperm, user, group, user_str, group_str)
+ else:
+ error(_('invalid syntax in %s line %d') % (path, lineno))
+ file.close()
+
+def act():
+ for f in assoc.keys():
+ (mode, uid, gid, newperm, user, group, user_str, group_str) = assoc[f]
+ #print f, (mode, uid, gid, newperm, user, group)
+ if mode != newperm:
+ log(_('changed mode of %s from %o to %o') % (f, mode, newperm))
+ os.chmod(f, newperm)
+ if user != -1:
+ if user != uid:
+ log(_('changed owner of %s from %s to %s') % (f, get_user_name(uid), user_str))
+ os.chown(f, user, -1)
+ if group != -1:
+ if group != gid:
+ log(_('changed group of %s from %s to %s') % (f, get_group_name(gid), group_str))
+ os.chown(f, -1, group)
+
+def chmod(f, newperm):
+ try:
+ full = os.stat(f)
+ except OSError:
+ return 0
+ mode = stat.S_IMODE(full[stat.ST_MODE])
+ if stat.S_ISDIR(full[stat.ST_MODE]):
+ if newperm & 0400:
+ newperm = newperm | 0100
+ if newperm & 0040:
+ newperm = newperm | 0010
+ if newperm & 0004:
+ newperm = newperm | 0001
+ if mode != newperm:
+ log(_('changed mode of %s from %o to %o') % (f, mode, newperm))
+ os.chmod(f, newperm)
+ return 1
+
+if __name__ == '__main__':
+ import sys
+
+ initlog('msec')
+
+ for p in sys.argv[1:]:
+ fix_perms(p)
+
+ act()
+
+# Perms.py ends here
diff --git a/share/README b/share/README
new file mode 100644
index 0000000..76b6a8f
--- /dev/null
+++ b/share/README
@@ -0,0 +1,66 @@
+******************
+Configurations files in /etc/security/msec/
+Shell scripts in /usr/share/msec.
+******************
+
+Suggest & Comment :
+yoann@mandrakesoft.com
+
+******************
+Doc of the rewritting in python:
+
+ 0 1 2 3 4 5
+root umask 022 022 022 022 022 077
+shell timeout 0 0 0 0 3600 900
+deny services none none none none local all
+su only for wheel grp no no no no no yes
+user umask 022 022 022 022 077 077
+shell history size default default default default 0 0
+direct root login yes yes yes yes no no
+sulogin for single user no no no no yes yes
+user list in [kg]dm yes yes yes yes no no
+promisc check no no no no yes yes
+ignore icmp echo no no no no yes yes
+ignore bogus error responses no no no no yes yes
+enable libasfe no no no no yes yes
+allow reboot by user yes yes yes yes no no
+allow crontab/at yes yes yes yes no no
+password aging no no no no 60 30
+allow autologin yes yes yes no no no
+console log no no no yes yes yes
+issues yes yes yes local local no
+ip spoofing protection no no no yes yes yes
+log stange ip packets no no no yes yes yes
+periodic security check no yes yes yes yes yes
+allow X connections yes local local no no no
+run msec by cron yes yes yes yes yes yes
+
+Periodic security checks by level:
+
+ 0 1 2 3 4 5
+CHECK_SECURITY no yes yes yes yes yes
+CHECK_PERMS no no no yes yes yes
+CHECK_SUID_ROOT no no yes yes yes yes
+CHECK_SUID_MD5 no no yes yes yes yes
+CHECK_SUID_GROUP no no yes yes yes yes
+CHECK_WRITEABLE no no yes yes yes yes
+CHECK_UNOWNED no no no no yes yes
+CHECK_PROMISC no no no no yes yes
+CHECK_OPEN_PORT no no no yes yes yes
+CHECK_PASSWD no no no yes yes yes
+CHECK_SHADOW no no no yes yes yes
+TTY_WARN no no no no yes yes
+MAIL_WARN no no no yes yes yes
+SYSLOG_WARN no no yes yes yes yes
+RPM_CHECK no no no yes yes yes
+
+These variables are configured by the user:
+
+MAIL_USER the user to send the dayly reports. If not set, the email is
+sent to root.
+
+PERM_LEVEL is used to determine which file to use to fix
+permissions/owners/groups (in /etc/security/msec/perm.$PERM_LEVEL). If
+not set, the SECURE_LEVEL is used instead. If the file
+/etc/security/msec/perm.local exists, it's used too.
+
diff --git a/share/compile.py b/share/compile.py
new file mode 100755
index 0000000..a325016
--- /dev/null
+++ b/share/compile.py
@@ -0,0 +1,17 @@
+#!/usr/bin/python -O
+#############################################################################
+# File : compile.py
+# Package : rpmlint
+# Author : Frederic Lepied
+# Created on : Sat Oct 23 23:40:21 1999
+# Version : $Id$
+# Purpose : byte compile all python files given in arguments.
+#############################################################################
+
+import py_compile
+import sys
+
+for f in sys.argv[2:]:
+ py_compile.compile(f, f+"o", sys.argv[1] + f)
+
+# compile.py ends here
diff --git a/share/libmsec.py b/share/libmsec.py
new file mode 100644
index 0000000..330244a
--- /dev/null
+++ b/share/libmsec.py
@@ -0,0 +1,488 @@
+#---------------------------------------------------------------
+# Project : Mandrake Linux
+# Module : share
+# File : libmsec.py
+# Version : $Id$
+# Author : Frederic Lepied
+# Created On : Mon Dec 10 22:52:17 2001
+#---------------------------------------------------------------
+
+import ConfigFile
+import Config
+from Log import *
+import os
+import grp
+import Perms
+import gettext
+import pwd
+import re
+import string
+import commands
+
+try:
+ cat = gettext.Catalog('msec')
+ _ = cat.gettext
+except IOError:
+ _ = str
+
+SUFFIX='.msec'
+_interactive=0
+
+# list of config files
+
+ATALLOW = '/etc/at.allow'
+AUTOLOGIN = '/etc/sysconfig/autologin'
+BASTILLENOLOGIN = '/etc/bastille-no-login'
+CRON = '/etc/cron.d/msec'
+CRONALLOW = '/etc/cron.allow'
+GDM = '/etc/pam.d/gdm'
+GDMCONF = '/etc/X11/gdm/gdm.conf'
+HALT = '/etc/security/console.apps/halt'
+HOSTCONF = '/etc/host.conf'
+HOSTSDENY = '/etc/hosts.deny'
+INITTAB = '/etc/inittab'
+ISSUE = '/etc/issue'
+ISSUENET = '/etc/issue.net'
+KDE = '/etc/pam.d/kde'
+KDMRC = '/usr/share/config/kdm/kdmrc'
+LDSOPRELOAD = '/etc/ld.so.preload'
+LILOCONF = '/etc/lilo.conf'
+LOGINDEFS = '/etc/login.defs'
+MENULST = '/boot/grub/menu.lst'
+MSEC = '/etc/sysconfig/msec'
+MSECBIN = '/usr/sbin/msec'
+MSECCRON = '/etc/cron.hourly/msec'
+MSEC_XINIT = '/etc/X11/xinit.d/msec'
+PASSWD = '/etc/pam.d/passwd'
+POWEROFF = '/etc/security/console.apps/poweroff'
+REBOOT = '/etc/security/console.apps/reboot'
+SECURETTY = '/etc/securetty'
+SHADOW = '/etc/shadow'
+SHUTDOWN = '/etc/security/console.apps/shutdown'
+SHUTDOWNALLOW = '/etc/shutdown.allow'
+SSHDCONFIG = '/etc/ssh/sshd_config'
+SU = '/etc/pam.d/su'
+SYSCTLCONF = '/etc/sysctl.conf'
+SYSLOGCONF = '/etc/syslog.conf'
+XDM = '/etc/pam.d/xdm'
+
+# config files => actions
+
+ConfigFile.add_config_assoc(INITTAB, '/sbin/telinit q')
+ConfigFile.add_config_assoc('/etc(?:/rc.d)?/init.d/(.+)', '[ -f /var/lock/subsys/@1 ] && @0 reload')
+ConfigFile.add_config_assoc(SYSCTLCONF, '/sbin/sysctl -e -p /etc/sysctl.conf; service network restart')
+ConfigFile.add_config_assoc(SSHDCONFIG, '[ -f /var/lock/subsys/sshd ] && /etc/rc.d/init.d/sshd restart')
+ConfigFile.add_config_assoc(LILOCONF, '[ `/usr/sbin/detectloader` = LILO ] && /sbin/lilo')
+ConfigFile.add_config_assoc(SYSLOGCONF, '[ -f /var/lock/subsys/syslog ] && service syslog reload')
+ConfigFile.add_config_assoc('^/etc/issue$', '/usr/bin/killall mingetty')
+
+# configuration rules
+
+def set_secure_level(level):
+ _interactive and log(_('Setting secure level to %s') % level)
+ msec = ConfigFile.get_config_file(MSEC)
+ msec.set_shell_variable('SECURE_LEVEL', level)
+
+def get_secure_level():
+ msec = ConfigFile.get_config_file(MSEC)
+ return msec.get_shell_variable('SECURE_LEVEL')
+
+def set_root_umask(umask):
+ _interactive and log(_('Setting root umask to %s') % umask)
+ msec = ConfigFile.get_config_file(MSEC)
+ msec.set_shell_variable('UMASK_ROOT', umask)
+
+def set_user_umask(umask):
+ _interactive and log(_('Setting users umask to %s') % umask)
+ msec = ConfigFile.get_config_file(MSEC)
+ msec.set_shell_variable('UMASK_USER', umask)
+
+def allow_x_connections():
+ _interactive and log(_('Allowing users to connect X server from everywhere'))
+ msec = ConfigFile.get_config_file(MSEC_XINIT)
+ msec.replace_line_matching('/usr/X11R6/bin/xhost', '/usr/X11R6/bin/xhost +', 1)
+
+def allow_local_x_connections():
+ _interactive and log(_('Allowing users to connect X server from localhost'))
+ msec = ConfigFile.get_config_file(MSEC_XINIT)
+ msec.replace_line_matching('/usr/X11R6/bin/xhost', '/usr/X11R6/bin/xhost + localhost', 1)
+
+def restrict_x_connections():
+ _interactive and log(_('Restricting X server connection to the console user'))
+ msec = ConfigFile.get_config_file(MSEC_XINIT)
+ msec.remove_line_matching('/usr/X11R6/bin/xhost', 1)
+
+def set_shell_timeout(val):
+ _interactive and log(_('Setting shell timeout to %s') % val)
+ msec = ConfigFile.get_config_file(MSEC)
+ msec.set_shell_variable('TMOUT', val)
+
+def set_shell_history_size(size):
+ if size >= 0:
+ _interactive and log(_('Setting shell history size to %s') % size)
+ msec = ConfigFile.get_config_file(MSEC)
+ msec.set_shell_variable('HISTFILESIZE', size)
+ else:
+ _interactive and log(_('Removing limit on shell history size'))
+ msec = ConfigFile.get_config_file(MSEC)
+ msec. remove_line_matching('^HISTFILESIZE=')
+
+def allow_reboot():
+ _interactive and log(_('Allowing reboot to the console user'))
+ shutdownallow = ConfigFile.get_config_file(SHUTDOWNALLOW)
+ shutdownallow.exists() and shutdownallow.move(SUFFIX)
+ for f in [SHUTDOWN, POWEROFF, REBOOT, HALT]:
+ ConfigFile.get_config_file(f).touch()
+ sysctlconf = ConfigFile.get_config_file(SYSCTLCONF)
+ sysctlconf.set_shell_variable('kernel.sysrq', 1)
+ kdmrc = ConfigFile.get_config_file(KDMRC)
+ kdmrc.exists() and kdmrc.set_shell_variable('AllowShutdown', 'All', 'X-:\*-Greeter', '^\s*$')
+ gdmconf = ConfigFile.get_config_file(GDMCONF)
+ gdmconf.exists() and gdmconf.set_shell_variable('SystemMenu', 'true', '\[greeter\]', '^\s*$')
+
+def forbid_reboot():
+ _interactive and log(_('Forbidding reboot to the console user'))
+ ConfigFile.get_config_file(SHUTDOWNALLOW, SUFFIX).touch()
+ for f in [SHUTDOWN, POWEROFF, REBOOT, HALT]:
+ ConfigFile.get_config_file(f).unlink()
+ sysctlconf = ConfigFile.get_config_file(SYSCTLCONF)
+ sysctlconf.set_shell_variable('kernel.sysrq', 0)
+ kdmrc = ConfigFile.get_config_file(KDMRC)
+ kdmrc.exists() and kdmrc.set_shell_variable('AllowShutdown', 'None', 'X-:\*-Greeter', '^\s*$')
+ gdmconf = ConfigFile.get_config_file(GDMCONF)
+ gdmconf.exists() and gdmconf.set_shell_variable('SystemMenu', 'false', '\[greeter\]', '^\s*$')
+
+def allow_user_list():
+ _interactive and log(_('Allowing the listing of users in display managers'))
+ kdmrc = ConfigFile.get_config_file(KDMRC)
+ kdmrc.exists() and kdmrc.set_shell_variable('ShowUsers', 'All')
+ gdmconf = ConfigFile.get_config_file(GDMCONF)
+ gdmconf.exists() and gdmconf.set_shell_variable('Browser', '1')
+
+def forbid_user_list():
+ _interactive and log(_('Disabling the listing of users in display managers'))
+ kdmrc = ConfigFile.get_config_file(KDMRC)
+ kdmrc.exists() and kdmrc.set_shell_variable('ShowUsers', 'None')
+ gdmconf = ConfigFile.get_config_file(GDMCONF)
+ gdmconf.exists() and gdmconf.set_shell_variable('Browser', '0')
+
+def allow_root_login():
+ _interactive and log(_('Allowing root login'))
+ sshd_config = ConfigFile.get_config_file(SSHDCONFIG)
+ sshd_config.exists() and sshd_config.replace_line_matching('^\s*PermitRootLogin\s+no',
+ 'PermitRootLogin yes')
+
+ kde = ConfigFile.get_config_file(KDE)
+ gdm = ConfigFile.get_config_file(GDM)
+ xdm = ConfigFile.get_config_file(XDM)
+
+ for cnf in (kde, gdm, xdm):
+ cnf.exists() and cnf.remove_line_matching('^auth\s*required\s*/lib/security/pam_listfile.so.*bastille-no-login', 1)
+
+ securetty = ConfigFile.get_config_file(SECURETTY)
+ for n in range(1, 7):
+ s = 'tty' + str(n)
+ securetty.replace_line_matching(s, s, 1)
+ s = 'vc/' + str(n)
+ securetty.replace_line_matching(s, s, 1)
+
+def forbid_root_login():
+ _interactive and log(_('Forbidding root login'))
+ sshd_config = ConfigFile.get_config_file(SSHDCONFIG)
+ sshd_config.exists() and sshd_config.replace_line_matching('^\s*PermitRootLogin\s+yes',
+ 'PermitRootLogin no')
+
+ bastillenologin = ConfigFile.get_config_file(BASTILLENOLOGIN)
+ bastillenologin.replace_line_matching('^\s*root', 'root', 1)
+
+ kde = ConfigFile.get_config_file(KDE)
+ gdm = ConfigFile.get_config_file(GDM)
+ xdm = ConfigFile.get_config_file(XDM)
+
+ for cnf in (kde, gdm, xdm):
+ cnf.exists() and (cnf.replace_line_matching('^auth\s*required\s*/lib/security/pam_listfile.so.*bastille-no-login', 'auth required /lib/security/pam_listfile.so onerr=succeed item=user sense=deny file=/etc/bastille-no-login') or \
+ cnf.insert_at(0, 'auth required /lib/security/pam_listfile.so onerr=succeed item=user sense=deny file=/etc/bastille-no-login'))
+
+ # TODO xdm support
+ securetty = ConfigFile.get_config_file(SECURETTY)
+ securetty.remove_line_matching('.+', 1)
+
+def enable_pam_wheel_for_su():
+ _interactive and log(_('Allowing su only from wheel group members'))
+ try:
+ ent = grp.getgrnam('wheel')
+ except KeyError:
+ error(_('no wheel group'))
+ return
+ members = ent[3]
+ if members == [] or members == ['root']:
+ error(_('wheel group is empty'))
+ return
+ su = ConfigFile.get_config_file(SU)
+ su.exists() and (su.replace_line_matching('^auth\s+required\s+/lib/security/pam_wheel.so\s+use_uid\s*$',
+ 'auth required /lib/security/pam_wheel.so use_uid') or \
+ su.insert_after('^auth\s+required',
+ 'auth required /lib/security/pam_wheel.so use_uid'))
+
+def disable_pam_wheel_for_su():
+ _interactive and log(_('Allowing su for all'))
+ su = ConfigFile.get_config_file(SU)
+ su.exists() and su.remove_line_matching('^auth\s+required\s+/lib/security/pam_wheel.so\s+use_uid\s*$')
+
+def forbid_issues(allow_local=0):
+ if not allow_local:
+ _interactive and log(_('Disabling pre-login message'))
+ issue = ConfigFile.get_config_file(ISSUE)
+ issue.exists() and issue.move(SUFFIX) and issue.modified()
+ else:
+ _interactive and log(_('Allowing pre-login message'))
+ issue = ConfigFile.get_config_file(ISSUE, SUFFIX)
+ issue.exists() and issue.get_lines()
+ _interactive and log(_('Disabling network pre-login message'))
+ issuenet = ConfigFile.get_config_file(ISSUENET)
+ issuenet.exists() and issuenet.move(SUFFIX)
+
+def allow_issues():
+ _interactive and log(_('Allowing RemoteRoot pre-login messages'))
+ issue = ConfigFile.get_config_file(ISSUE, SUFFIX)
+ issue.exists() and issue.get_lines()
+ issuenet = ConfigFile.get_config_file(ISSUENET, SUFFIX)
+ issuenet.exists() and issuenet.get_lines()
+
+def allow_autologin():
+ _interactive and log(_('Allowing autologin'))
+ autologin = ConfigFile.get_config_file(AUTOLOGIN)
+ autologin.exists() and autologin.set_shell_variable('AUTOLOGIN', 'yes')
+
+def forbid_autologin():
+ _interactive and log(_('Forbidding autologin'))
+ autologin = ConfigFile.get_config_file(AUTOLOGIN)
+ autologin.exists() and autologin.set_shell_variable('AUTOLOGIN', 'no')
+
+def password_loader(value):
+ _interactive and log(_('Activating password in boot loader'))
+ liloconf = ConfigFile.get_config_file(LILOCONF)
+ liloconf.exists() and (liloconf.replace_line_matching('^password=', 'password="' + value + '"', 0, 1) or \
+ liloconf.insert_after('^boot=', 'password="' + value + '"')) and \
+ Perms.chmod(liloconf.path, 0600)
+ # TODO encrypt password in grub
+ menulst = ConfigFile.get_config_file(MENULST)
+ menulst.exists() and (menulst.replace_line_matching('^password\s', 'password "' + value + '"') or \
+ menulst.insert_at(0, 'password "' + value + '"')) and \
+ Perms.chmod(menulst.path, 0600)
+ # TODO add yaboot support
+
+def nopassword_loader():
+ _interactive and log(_('Removing password in boot loader'))
+ liloconf = ConfigFile.get_config_file(LILOCONF)
+ liloconf.exists() and liloconf.remove_line_matching('^password=', 1)
+ menulst = ConfigFile.get_config_file(MENULST)
+ menulst.exists() and menulst.remove_line_matching('^password\s')
+
+def enable_console_log():
+ _interactive and log(_('Enabling log on console 12'))
+ syslogconf = ConfigFile.get_config_file(SYSLOGCONF)
+ syslogconf.exists() and syslogconf.replace_line_matching('\s*[^#]+/dev/tty12', '*.* /dev/tty12', 1)
+
+def disable_console_log():
+ _interactive and log(_('Disabling log on console 12'))
+ syslogconf = ConfigFile.get_config_file(SYSLOGCONF)
+ syslogconf.exists() and syslogconf.remove_line_matching('\*\.\*\s*/dev/tty12')
+
+def enable_promisc_check():
+ _interactive and log(_('Activating periodic promiscuity check'))
+ cron = ConfigFile.get_config_file(CRON)
+ cron.replace_line_matching('[^#]+/usr/share/msec/promisc_check.sh', '*/1 * * * * root /usr/share/msec/promisc_check.sh', 1)
+
+def disable_promisc_check():
+ _interactive and log(_('Disabling periodic promiscuity check'))
+ cron = ConfigFile.get_config_file(CRON)
+ cron.remove_line_matching('[^#]+/usr/share/msec/promisc_check.sh')
+
+def enable_security_check():
+ _interactive and log(_('Activating daily security check'))
+ cron = ConfigFile.get_config_file(CRON)
+ cron.replace_line_matching('[^#]+/usr/share/msec/security.sh', '0 4 * * * root /usr/share/msec/security.sh', 1)
+
+def disable_security_check():
+ _interactive and log(_('Disabling daily security check'))
+ cron = ConfigFile.get_config_file(CRON)
+ cron.remove_line_matching('[^#]+/usr/share/msec/security.sh')
+
+def deny_all_services():
+ _interactive and log(_('Disabling all services'))
+ hostsdeny = ConfigFile.get_config_file(HOSTSDENY)
+ hostsdeny.remove_line_matching('^ALL:ALL EXCEPT localhost:DENY', 1)
+ hostsdeny.replace_line_matching('^ALL:ALL:DENY$', 'ALL:ALL:DENY', 1)
+
+def deny_non_local_services():
+ _interactive and log(_('Disabling non local services'))
+ hostsdeny = ConfigFile.get_config_file(HOSTSDENY)
+ hostsdeny.remove_line_matching('^ALL:ALL:DENY', 1)
+ hostsdeny.replace_line_matching('^ALL:ALL EXCEPT localhost:DENY$', 'ALL:ALL EXCEPT localhost:DENY', 1)
+
+def authorize_all_services():
+ _interactive and log(_('Authorizing all services'))
+ hostsdeny = ConfigFile.get_config_file(HOSTSDENY)
+ hostsdeny.remove_line_matching('^ALL:ALL:DENY', 1)
+ hostsdeny.remove_line_matching('^ALL:ALL EXCEPT localhost:DENY', 1)
+
+def enable_ip_spoofing_protection(alert):
+ _interactive and log(_('Enabling ip spoofing protection'))
+ hostconf = ConfigFile.get_config_file(HOSTCONF)
+ hostconf.replace_line_matching('nospoof', 'nospoof on', 1)
+ hostconf.replace_line_matching('spoofalert', 'spoofalert on', (alert != 0))
+ sysctlconf = ConfigFile.get_config_file(SYSCTLCONF)
+ sysctlconf.set_shell_variable('net.ipv4.conf.all.rp_filter', 1)
+
+def disable_ip_spoofing_protection():
+ _interactive and log(_('Disabling ip spoofing protection'))
+ hostconf = ConfigFile.get_config_file(HOSTCONF)
+ hostconf.remove_line_matching('nospoof')
+ hostconf.remove_line_matching('spoofalert')
+
+def ignore_icmp_echo():
+ _interactive and log(_('Ignoring icmp echo'))
+ sysctlconf = ConfigFile.get_config_file(SYSCTLCONF)
+ sysctlconf.set_shell_variable('net.ipv4.icmp_echo_ignore_all', 1)
+ sysctlconf.set_shell_variable('net.ipv4.icmp_echo_ignore_broadcasts', 1)
+
+def accept_icmp_echo():
+ _interactive and log(_('Accepting icmp echo'))
+ sysctlconf = ConfigFile.get_config_file(SYSCTLCONF)
+ sysctlconf.set_shell_variable('net.ipv4.icmp_echo_ignore_all', 0)
+ sysctlconf.set_shell_variable('net.ipv4.icmp_echo_ignore_broadcasts', 0)
+
+def ignore_bogus_error_responses():
+ _interactive and log(_('Ignoring bogus icmp error responses'))
+ sysctlconf = ConfigFile.get_config_file(SYSCTLCONF)
+ sysctlconf.set_shell_variable('net.ipv4.icmp_ignore_bogus_error_responses', 1)
+
+def accept_bogus_error_responses():
+ _interactive and log(_('Accepting bogus icmp error responses'))
+ sysctlconf = ConfigFile.get_config_file(SYSCTLCONF)
+ sysctlconf.set_shell_variable('net.ipv4.icmp_ignore_bogus_error_responses', 0)
+
+def enable_log_strange_packets():
+ _interactive and log(_('Enabling logging of strange packets'))
+ sysctlconf = ConfigFile.get_config_file(SYSCTLCONF)
+ sysctlconf.set_shell_variable('net.ipv4.conf.all.log_martians', 1)
+
+def disable_log_strange_packets():
+ _interactive and log(_('Disabling logging of strange packets'))
+ sysctlconf = ConfigFile.get_config_file(SYSCTLCONF)
+ sysctlconf.set_shell_variable('net.ipv4.conf.all.log_martians', 0)
+
+def enable_libsafe():
+ if os.path.exists(Config.get_config('root', '') + '/lib/libsafe.so.2'):
+ _interactive and log(_('Enabling libsafe'))
+ ldsopreload = ConfigFile.get_config_file(LDSOPRELOAD)
+ ldsopreload.replace_line_matching('[^#]*libsafe', '/lib/libsafe.so.2', 1)
+
+def disable_libsafe():
+ _interactive and log(_('Disabling libsafe'))
+ ldsopreload = ConfigFile.get_config_file(LDSOPRELOAD)
+ ldsopreload.remove_line_matching('[^#]*libsafe')
+
+def password_length(length, ndigits=0, nupper=0):
+ _interactive and log(_('Setting minimum password length %d') % length)
+ passwd = ConfigFile.get_config_file(PASSWD)
+ passwd.exists() and (passwd.replace_line_matching('^(password\s+required\s+/lib/security/pam_cracklib.so.*?)(\sminlen=[0-9]+\s)(.*)',
+ '@1 minlen=%s @3' % length) or \
+ passwd.replace_line_matching('^password\s+required\s+/lib/security/pam_cracklib.so.*',
+ '@0 minlen=%s ' % length))
+
+ passwd.exists() and (passwd.replace_line_matching('^(password\s+required\s+/lib/security/pam_cracklib.so.*?)(\sdcredit=[0-9]+\s)(.*)',
+ '@1 dcredit=%s @3' % ndigits) or \
+ passwd.replace_line_matching('^password\s+required\s+/lib/security/pam_cracklib.so.*',
+ '@0 dcredit=%s ' % ndigits))
+
+ passwd.exists() and (passwd.replace_line_matching('^(password\s+required\s+/lib/security/pam_cracklib.so.*?)(\sucredit=[0-9]+\s)(.*)',
+ '@1 ucredit=%s @3' % nupper) or \
+ passwd.replace_line_matching('^password\s+required\s+/lib/security/pam_cracklib.so.*',
+ '@0 ucredit=%s ' % nupper))
+
+def enable_sulogin():
+ _interactive and log(_('Enabling sulogin in single user runlevel'))
+ inittab = ConfigFile.get_config_file(INITTAB)
+ inittab.replace_line_matching('[^#]+:S:', '~~:S:wait:/sbin/sulogin', 1)
+
+def disable_sulogin():
+ _interactive and log(_('Disabling sulogin in single user runlevel'))
+ inittab = ConfigFile.get_config_file(INITTAB)
+ inittab.remove_line_matching('~~:S:wait:/sbin/sulogin')
+
+def enable_msec_cron():
+ _interactive and log(_('Enabling msec periodic runs'))
+ mseccron = ConfigFile.get_config_file(MSECCRON)
+ mseccron.symlink(MSECBIN)
+
+def disable_msec_cron():
+ _interactive and log(_('Disabling msec periodic runs'))
+ mseccron = ConfigFile.get_config_file(MSECCRON)
+ mseccron.unlink()
+
+def disable_at_crontab():
+ _interactive and log(_('Disabling crontab and at'))
+ cronallow = ConfigFile.get_config_file(CRONALLOW, SUFFIX)
+ cronallow.replace_line_matching('root', 'root', 1)
+ atallow = ConfigFile.get_config_file(ATALLOW, SUFFIX)
+ atallow.replace_line_matching('root', 'root', 1)
+
+def enable_at_crontab():
+ _interactive and log(_('Enabling crontab and at'))
+ cronallow = ConfigFile.get_config_file(CRONALLOW)
+ cronallow.exists() and cronallow.move(SUFFIX)
+ atallow = ConfigFile.get_config_file(ATALLOW)
+ atallow.exists() and atallow.move(SUFFIX)
+
+maximum_regex = re.compile('^Maximum:\s*([0-9]+)', re.MULTILINE)
+
+# TODO FL Sat Dec 29 20:18:20 2001
+# replace chage calls and /etc/shadow parsing by a python API to the shadow functions.
+def password_aging(max):
+ uid_min = 500
+ _interactive and log(_('Setting password maximum aging for new user to %d') % max)
+ logindefs = ConfigFile.get_config_file(LOGINDEFS)
+ if logindefs.exists():
+ logindefs.replace_line_matching('^\s*PASS_MAX_DAYS', 'PASS_MAX_DAYS ' + str(max))
+ uid_min = logindefs.get_match('^\s*UID_MIN\s+([0-9]+)', '@1')
+ if uid_min:
+ uid_min = int(uid_min)
+ shadow = ConfigFile.get_config_file(SHADOW)
+ if shadow.exists():
+ _interactive and log(_('Setting password maximum aging for users with id greater than %d to %d') % (uid_min, max))
+ for line in shadow.get_lines():
+ field = string.split(line, ':')
+ if len(field) < 2:
+ continue
+ name = field[0]
+ password = field[1]
+ entry = pwd.getpwnam(name)
+ if (len(password) > 0 and password[0] != '!') and password != '*' and password != 'x' and entry[2] >= uid_min:
+ cmd = '/usr/bin/chage -l %s' % entry[0]
+ ret = commands.getstatusoutput(cmd)
+ _interactive and log(_('got current maximum password aging for user %s with command \'%s\'') % (entry[0], cmd))
+ if ret[0] == 0:
+ res = maximum_regex.search(ret[1])
+ if res:
+ current_max = int(res.group(1))
+ if max != current_max:
+ cmd = '/usr/bin/chage -M %d %s' % (max, entry[0])
+ ret = commands.getstatusoutput(cmd)
+ log(_('changed maximum password aging for user %s with command %s') % (entry[0], cmd))
+ if ret[0] != 0:
+ error(ret[1])
+ else:
+ error(_('unable to parse chage output'))
+ else:
+ error(_('unable to run chage: %s') % ret[1])
+
+# various
+
+def set_interactive(v):
+ global _interactive
+
+ _interactive = v
+
+# libmsec.py ends here
diff --git a/share/msec b/share/msec
new file mode 100755
index 0000000..423766c
--- /dev/null
+++ b/share/msec
@@ -0,0 +1,48 @@
+#!/bin/sh
+#---------------------------------------------------------------
+# Project : Mandrake Linux
+# Module : share
+# File : msec
+# Version : $Id$
+# Author : Frederic Lepied
+# Created On : Thu Dec 13 11:36:50 2001
+#---------------------------------------------------------------
+
+MSEC=/usr/share/msec/msec.py
+
+for a in "$@"; do
+ last="$a"
+done
+
+if [ -n "$last" ]; then
+ case $last in
+ [0-5]) ;;
+ *) [ -x /usr/share/msec/$last.py ] && MSEC=/usr/share/msec/$last.py;;
+ esac
+else
+ # no args so try to guess if a custom msec is needed
+ . /etc/sysconfig/msec
+
+ case "$SECURE_LEVEL" in
+ [0-5]) ;;
+ *) MSEC=/usr/share/msec/$SECURE_LEVEL.py;;
+ esac
+fi
+
+if [ ! -x $MSEC ]; then
+ echo "/usr/share/msec/$last.py not found or not executable. Aborting" 1>&2
+ exit 1
+fi
+
+if $MSEC "$@"; then
+ . /etc/sysconfig/msec
+
+ [ -z "$PERM_LEVEL" ] && PERM_LEVEL=$SECURE_LEVEL
+
+ LOCAL=
+ [ -f /etc/security/msec/perm.local ] && LOCAL=/etc/security/msec/perm.local
+
+ /usr/share/msec/Perms.py /etc/security/msec/perm.$PERM_LEVEL $LOCAL
+fi
+
+# msec.sh ends here
diff --git a/share/msec.py b/share/msec.py
new file mode 100755
index 0000000..8ab0a3f
--- /dev/null
+++ b/share/msec.py
@@ -0,0 +1,195 @@
+#!/usr/bin/python -O
+#---------------------------------------------------------------
+# Project : Mandrake Linux
+# Module : msec/share
+# File : msec.py
+# Version : $Id$
+# Author : Frederic Lepied
+# Created On : Wed Dec 5 20:20:21 2001
+#---------------------------------------------------------------
+
+from libmsec import *
+from Log import *
+from Log import _name
+import Config
+import sys
+import os
+import string
+import getopt
+import gettext
+
+try:
+ cat = gettext.Catalog('msec')
+ _ = cat.gettext
+except IOError:
+ _ = str
+
+# program
+_name = 'msec'
+
+sys.argv[0] = os.path.basename(sys.argv[0])
+
+try:
+ (opt, args) = getopt.getopt(sys.argv[1:], 'o:',
+ ['option'])
+except getopt.error:
+ error(_('Invalid option. Use %s (-o var=<val>...) ([0-5])') % sys.argv[0])
+ sys.exit(1)
+
+
+for o in opt:
+ if o[0] == '-o' or o[0] == '--option':
+ pair = string.split(o[1], '=')
+ if len(pair) != 2:
+ error(_('Invalid option format %s %s: use -o var=<val>') % (o[0], o[1]))
+ sys.exit(1)
+ else:
+ Config.set_config(pair[0], pair[1])
+
+interactive = sys.stdin.isatty()
+set_interactive(interactive)
+
+# initlog must be done after processing the option because we can change
+# the way to report log with options...
+if interactive:
+ import syslog
+
+ initlog('msec', syslog.LOG_LOCAL1)
+else:
+ initlog('msec')
+
+if len(args) == 0:
+ level = get_secure_level()
+ if level == None:
+ error(_('Secure level not set. Use %s <secure level> to set it.') % sys.argv[0])
+ sys.exit(1)
+else:
+ level = args[0]
+
+try:
+ level = int(level)
+except ValueError:
+ error(_('Invalid secure level %s. Use %s [0-5] to set it.') % (level, sys.argv[0]))
+ sys.exit(1)
+
+if level < 0 or level > 5:
+ error(_('Invalid secure level %s. Use %s [0-5] to set it.') % (level, sys.argv[0]))
+ sys.exit(1)
+
+set_secure_level(level)
+
+server=(level in range(3, 6))
+
+# for all levels: min length = 2 * (level - 1) and for level 4,5 makes mandatory
+# to have at least one upper case character and one digit.
+if level > 1:
+ password_length = (level - 1) * 2
+else:
+ password_length = 0
+
+password_length(password_length, level / 4, level / 4)
+
+enable_ip_spoofing_protection(server)
+
+# differences between level 5 and others
+if level == 5:
+ set_root_umask('077')
+ set_shell_timeout(900)
+ deny_all_services()
+ enable_pam_wheel_for_su()
+else:
+ set_root_umask('022')
+ if level == 4:
+ set_shell_timeout(3600)
+ deny_non_local_services()
+ else:
+ set_shell_timeout(0)
+ authorize_all_services()
+ disable_pam_wheel_for_su()
+
+# differences between level 4,5 and others
+if level >= 4:
+ set_user_umask('077')
+ set_shell_history_size(10)
+ forbid_root_login()
+ enable_sulogin()
+ forbid_user_list()
+ enable_promisc_check()
+ ignore_icmp_echo()
+ ignore_bogus_error_responses()
+ enable_libsafe()
+ forbid_reboot()
+ disable_at_crontab()
+ if level == 4:
+ password_aging(60)
+ else:
+ password_aging(30)
+else:
+ set_user_umask('022')
+ set_shell_history_size(-1)
+ allow_root_login()
+ disable_sulogin()
+ allow_user_list()
+ disable_promisc_check()
+ accept_icmp_echo()
+ accept_bogus_error_responses()
+ disable_libsafe()
+ allow_reboot()
+ enable_at_crontab()
+ password_aging(99999)
+
+# differences between level 3,4,5 and others
+if server:
+ forbid_autologin()
+ enable_console_log()
+ forbid_issues((level != 5))
+ enable_log_strange_packets()
+else:
+ allow_autologin()
+ disable_console_log()
+ allow_issues()
+ disable_log_strange_packets()
+
+# differences between level 0 and others
+if level != 0:
+ enable_security_check()
+ if level < 3:
+ allow_local_x_connections()
+ else:
+ restrict_x_connections()
+else:
+ disable_security_check()
+ allow_x_connections()
+
+# msec cron
+enable_msec_cron()
+
+# 0 1 2 3 4 5
+FILE_CHECKS = {'CHECK_SECURITY' : ('no', 'yes', 'yes', 'yes', 'yes', 'yes', ),
+ 'CHECK_PERMS' : ('no', 'no', 'no', 'yes', 'yes', 'yes', ),
+ 'CHECK_SUID_ROOT' : ('no', 'no', 'yes', 'yes', 'yes', 'yes', ),
+ 'CHECK_SUID_MD5' : ('no', 'no', 'yes', 'yes', 'yes', 'yes', ),
+ 'CHECK_SUID_GROUP' : ('no', 'no', 'yes', 'yes', 'yes', 'yes', ),
+ 'CHECK_WRITEABLE' : ('no', 'no', 'yes', 'yes', 'yes', 'yes', ),
+ 'CHECK_UNOWNED' : ('no', 'no', 'no', 'no', 'yes', 'yes', ),
+ 'CHECK_PROMISC' : ('no', 'no', 'no', 'no', 'yes', 'yes', ),
+ 'CHECK_OPEN_PORT' : ('no', 'no', 'no', 'yes', 'yes', 'yes', ),
+ 'CHECK_PASSWD' : ('no', 'no', 'no', 'yes', 'yes', 'yes', ),
+ 'CHECK_SHADOW' : ('no', 'no', 'no', 'yes', 'yes', 'yes', ),
+ 'TTY_WARN' : ('no', 'no', 'no', 'no', 'yes', 'yes', ),
+ 'MAIL_WARN' : ('no', 'no', 'no', 'yes', 'yes', 'yes', ),
+ 'SYSLOG_WARN' : ('no', 'no', 'yes', 'yes', 'yes', 'yes', ),
+ 'RPM_CHECK' : ('no', 'no', 'no', 'yes', 'yes', 'yes', ),
+ }
+
+interactive and log(_('Configuring periodic files checks'))
+securityconf = ConfigFile.get_config_file('/etc/security/msec/security.conf')
+for k in FILE_CHECKS.keys():
+ securityconf.set_shell_variable(k, FILE_CHECKS[k][level])
+
+interactive and log(_('Writing config files and then taking needed actions'))
+ConfigFile.write_files()
+
+closelog()
+
+# msec.py ends here