Compare commits

...

107 Commits

Author SHA1 Message Date
William Hirigoyen 6762ced399 check_sshallowusers: fix unwanted sterr when /etc/ssh/sshd_condig.d does not exist 2024-03-07 17:11:17 +01:00
Jérémy Lecour 202db682a0
IS_SYSLOGCONF: modern and legacy tests 2024-02-05 19:17:33 +01:00
William Hirigoyen 25b00f6fa7 Fix errors in some LXC checks: list only active LXC containers, add conditions to filter containers that are not in evo-standards. 2024-01-31 14:50:28 +01:00
Jérémy Lecour c4c8dd2112
IS_SYSLOGCONF: better detection 2024-01-26 16:17:34 +01:00
David Prevot 5536e8f6ec Fix recent release dates 2024-01-03 17:41:05 +01:00
David Prevot d14a6d52a3 Linux - Release 24.01 2024-01-03 17:30:13 +01:00
Mathieu Trossevin fba4dc75c3 fix(IS_EVOBACKUP_EXCLUDE_MOUNT): correctly treat old versions of evobackup
This commit fix #150

Prior to this older versions of evobackup without `VERSION=` in them
would be treated as not having any exclude whatsoever as the `else`
block was only inside of the `if grep -q  "^VERSION="
"${evobackup_file}"` block.

Now the treatment of old evobackup scripts is done if there isn't a
`VERSION=` in the script or if the version is older than 22.12.
2024-01-03 15:13:23 +01:00
David Prevot 1fc94ec4f1 Changelog for previous entries 2023-12-13 17:51:10 +01:00
David Prevot 2df62afa21 IS_DEBIANSECURITY_LXC: Don’t test older than Debian 9 containers
We use eLTS for Jessie without security, that has been archived and
signed with an expired key.
2023-12-13 17:49:35 +01:00
David Prevot ff5f7ec399 IS_KERNELUPTODATE: Address false positive in case of kernel removal
If a kernel is removed, then grub is updated. Try to check the actual
kernel files instead of any file in /boot.
2023-12-13 17:06:52 +01:00
David Prevot f64176db21 Add IS_BACKPORTS_VERSION 2023-12-13 17:02:55 +01:00
David Prevot 14e56cd575 check_broadcomfirmware: use apt-policy (making it useful before Debian 10) 2023-12-05 15:17:25 +01:00
Alexis Ben Miloud--Josselin 27347f7342 check_sshpermitrootno: Always specify lport
When sshd listens two ports (usually 22 and another one), the sshd
-T command will fail if lport is not specified.

This commit also simplifies the if-elif block.
2023-12-01 09:45:06 +01:00
Alexis Ben Miloud--Josselin e27bb4124b Chech drbdtwoprimaries: fix false positive
Fix #151
2023-11-29 17:55:00 +01:00
Jérémy Lecour 7041505446
long options are preferred 2023-11-24 16:20:08 +01:00
David Prevot 4dbb3d030d IS_ETCGIT_LXC, IS_GITPERMS_LXC: fix path 2023-11-23 14:58:51 +01:00
Jérémy Lecour fb14549843
long options 2023-11-23 07:31:59 +01:00
Jérémy Lecour 1d995764a9
No need to escape characters if we search for a fixed string 2023-11-23 07:31:48 +01:00
David Prevot 5402fa0dee Linux - Release 23.11.1 2023-11-22 17:25:28 +01:00
David Prevot f024f9d9e8 IS_EVOBACKUP_EXCLUDE_MOUNT: fix another regression introduced in previous release 2023-11-22 17:23:59 +01:00
David Prevot e80a7781c7 Linux - Release 23.11 2023-11-22 17:02:06 +01:00
David Prevot 79a61e3046 CHANGELOG for IS_SSHALLOWUSERS change from ansible-roles 2023-11-22 16:32:35 +01:00
Alexis Ben Miloud--Josselin 95539ea38c evocheck: Fix IS_SSHALLOWUSERS condition 2023-11-22 16:30:30 +01:00
Alexis Ben Miloud--Josselin 77be2c3fe1 evocheck/ssh: add Debian 12 condition 2023-11-22 16:30:21 +01:00
David Prevot f4948b5611 linux/CHANGELOG: Update for latest changes 2023-11-22 15:51:07 +01:00
David Prevot ad85fd9784 IS_MINIFWINCLUDES, IS_NRPEPID: Change Debian release detection logic 2023-11-22 15:46:55 +01:00
David Prevot 668791208a Update IS_PHPEVOLINUXCONF for Bookworm 2023-11-22 15:33:54 +01:00
David Prevot f546fb97f0 Add IS_GITPERMS_LXC 2023-11-22 15:27:47 +01:00
David Prevot be53bce0e5 Add IS_ETCGIT_LXC 2023-11-22 15:20:59 +01:00
David Prevot f2d1f43e85 Add IS_OLDPUB_LXC 2023-11-22 15:08:02 +01:00
David Prevot f5887eb43c CHANGELOG for IS_EVOBACKUP_EXCLUDE_MOUNT fix 2023-11-22 14:38:35 +01:00
Brice Waegeneire 59a14150db fix regressions 2023-11-21 17:02:19 +01:00
David Prevot 3bf5c4fcb7 CHANGELOG for previous commits 2023-11-16 16:25:55 +01:00
David Prevot 5d15f373c2 Add IS_LXC_PHP_BAD_DEBIAN_VERSION 2023-11-16 16:23:02 +01:00
David Prevot 5fe7a88fab Add IS_SURY_LXC 2023-11-16 16:22:57 +01:00
David Prevot ad50601931 Add IS_LXC_OPENSSH 2023-11-16 15:35:00 +01:00
David Prevot 9b1946d9a0 Add IS_DEBIANSECURITY_LXC 2023-11-16 15:20:12 +01:00
David Prevot 443c232b95 [minor] tfix 2023-10-31 09:51:19 +01:00
David Prevot 868fe9d7c0 Add trixie and forky support (Debian 13, 14) 2023-10-31 09:44:46 +01:00
Jérémy Lecour 5b0a011eda
fix CHANGELOG 2023-10-27 10:31:46 +02:00
David Prevot 081a8166cc Linux - Release 23.10 2023-10-26 15:43:09 +02:00
David Prevot 8f58aa00ee IS_SURY: check that if sury is enabled, then a safeguard must be in place 2023-10-17 17:26:44 +02:00
David Prevot d92a8862e8 Add changelog entry for previous commit 2023-10-17 17:24:26 +02:00
David Prevot 1067bc6a27 Don’t recommend preferences for backports anymore
Thanks to “NotAutomatic: yes” and “ButAutomaticUpgrades: yes”, backports
packages are not pulled by default anymore since Squeeze.
2023-10-12 15:25:52 +02:00
William Hirigoyen 42cbd14123 IS_DRBDTWOPRIMARIES: check there are not 2 DRBD primaries at the same time 2023-09-20 11:26:17 +02:00
isaid ed602d9e83 Merge pull request 'fix #148' (#149) from 148 into master
Reviewed-on: #149
reviewed by Brice
2023-09-05 17:23:13 +02:00
Iliane Said b3db84a8f7 fix #148
In check_evobackup_exclude_mount function, add support for new rsync
syntax introduced in evobackup 22.12.
2023-09-05 17:20:49 +02:00
William Hirigoyen 24d3f67718 Typo 2023-08-29 17:26:25 +02:00
Jérémy Lecour 171924d99c
IS_NEWPUB: verify that the new public repository is present 2023-08-10 17:17:47 +02:00
Jérémy Lecour e09e5b3e53
IS_MINIFW: better detection of minifirewall status 2023-08-01 23:21:25 +02:00
David Prevot 7c40af199b Add IS_OLDPUB to check for pub.evolix.net 2023-07-28 09:36:24 +02:00
William Hirigoyen 152653d773 IS_BINDCHROOT: fix /etc/default path for Debian >= 11 (renamed from bind9 to named) 2023-07-17 12:15:45 +02:00
William Hirigoyen 6414a8c70e Linux - Release 23.07 2023-07-07 11:02:01 +02:00
William Hirigoyen 9d011b71b0 IS_REDIS_BACKUP: full rewrite of the check to be more flexible, and also check time of dump 2023-06-21 16:58:36 +02:00
Jérémy Dubois ad9231d9a9 OpenBSD - Release 23.06 2023-06-05 11:42:10 +02:00
Mathieu Trossevin 442d1446b5
fix(check_nrpepid): bookworm should be checked like bullseye 2023-05-04 15:20:32 +02:00
Mathieu Trossevin 90c1f854cf
chore(whitespace) 2023-05-04 15:05:47 +02:00
Mathieu Trossevin 02e2d4c5c0
fix(check_minifw): `iptables -L -n` doesn't tranlate protocol number in bookworm 2023-05-04 15:02:28 +02:00
Jérémy Dubois 4008fb3128 OpenBSD - check_mount: removed useless echo 2023-04-25 11:46:06 +02:00
Jérémy Dubois 0dae32a135 OpenBSD - check_carpadvbase and check_carppreempt: fixed indentation 2023-04-25 11:41:51 +02:00
William Hirigoyen ae797122ad Linux - Release 23.04.01 2023-04-07 11:49:57 +02:00
William Hirigoyen 96ea77b345 Linux - Release 23.04 2023-04-07 10:55:05 +02:00
Jérémy Dubois baf26b23c4 OpenBSD - check_evobackup: zzz_evobackup is now executed with bash 2023-03-22 09:56:13 +01:00
Jérémy Dubois 8d22e5ea85 OpenBSD - Change CHANGELOG format : replace "-" for lists with "*" 2023-03-01 16:02:09 +01:00
Jérémy Dubois 011c62f984 OpenBSD - check_mountfstab and check_mount : make sure all mounted partitions are in fstab and all partitions in fstab are mounted 2023-03-01 16:01:59 +01:00
William Hirigoyen da28729577 Linux - Release 23.03.01 2023-03-01 10:06:52 +01:00
William Hirigoyen 03f9a4eb15 Linux - Release 23.03 2023-03-01 09:53:56 +01:00
William Hirigoyen e21c4e8233 IS_LXC_PHP_FPM_SERVICE_UMASK_SET: fix inverted test condition. 2023-03-01 09:44:48 +01:00
William Hirigoyen 1bb00c10bd Log output and runtime config to /var/log/evocheck.log 2023-02-17 12:54:28 +01:00
William Hirigoyen ff92e3889e Log program exit 2023-02-17 12:53:31 +01:00
William Hirigoyen 97a98c8df3 Log runtime config to /var/log/evocheck.log 2023-02-17 10:48:58 +01:00
William Hirigoyen 32d2a94b71 Log output to /var/log/evocheck.log 2023-02-17 09:52:45 +01:00
William Hirigoyen e5aa1aa323 IS_LOCALHOST_IN_POSTFIX_MYDESTINATION: set grep quiet 2023-02-14 17:31:30 +01:00
William Hirigoyen c852fb188d OpenBSD - Release 23.02 2023-02-10 14:30:45 +01:00
William Hirigoyen c621431e05 OpenBSD - Release 23.02 2023-02-10 12:31:15 +01:00
William Hirigoyen ccb6c3e4f8 Linux - Release 23.02 2023-02-10 12:28:19 +01:00
William Hirigoyen 8db26f1622 OpenBDS - Release 22.12 2023-02-10 11:42:51 +01:00
William Hirigoyen e172c27f63 Linux - Release 22.12 2023-02-10 11:37:33 +01:00
William Hirigoyen 72e4b3f045 README: Add pre-tasks for release 2023-02-10 11:35:54 +01:00
William Hirigoyen 9361e5a9cf #701Update CHANGELOG 2023-02-10 10:08:00 +01:00
William Hirigoyen 6ca6686cb3 #70141 : Corriger evocheck IS_NOTUPGRADED 2023-02-10 10:05:57 +01:00
Jérémy Dubois 8ae087b799 OpenBSD - Replaced check_sudomaint with check_doasmaint and removed check_wheel 2023-02-09 16:07:14 +01:00
Jérémy Dubois 29b546584a OpenBSD - check_pkgmirror: fix openbsd mirror 2023-01-23 16:56:10 +01:00
Jérémy Lecour f1074dea2d use bash array for tmp files to cleanup 2023-01-12 17:03:35 +01:00
Jérémy Lecour f5410be26c shellcheck 2023-01-12 16:56:18 +01:00
Jérémy Lecour 3d7b2a676f whitespace 2023-01-12 16:55:08 +01:00
Jérémy Lecour 289e303801 fix syntax error 2023-01-12 16:54:42 +01:00
Jérémy Lecour be1e303040 improve readability 2023-01-12 16:53:37 +01:00
Jérémy Lecour 653f29e2d8 grep silencieux et optimisé 2023-01-12 16:48:57 +01:00
Jérémy Lecour c8ea1a3744 typos 2023-01-12 16:48:38 +01:00
William Hirigoyen f9fdc2c4ee IS_LOCALHOST_IN_POSTFIX_MYDESTINATION: fix regex and add localhost.$mydomain to check 2022-12-15 12:13:51 +01:00
David Prevot 12681b8259 Fix filename changed in 0ff69e6a07 2022-12-15 11:53:00 +01:00
William Hirigoyen 339afdcec2 Improve commit 2540c6f312 2022-12-07 16:56:01 +01:00
William Hirigoyen 6566193ebc Update CHANGELOG 2022-12-06 11:57:42 +01:00
William Hirigoyen 2540c6f312 - Add checks IS_LOCALHOST_IN_POSTFIX_MYDESTINATION, IS_SSH_FAIL2BAN_JAIL_RENAMED, IS_NO_LXC_CONTAINER, IS_LXC_PHP_FPM_SERVICE_UMASK_SET.
- Fix quote in IS_EVOBACKUP_INCS.
- Fix missing call to IS_PURGE_FAIL2BAN.
2022-12-06 11:45:14 +01:00
William Hirigoyen ff7aee8ea7 IS_REDIS_BACKUP: supports news and old default Redis backup path 2022-12-01 17:31:17 +01:00
Jérémy Dubois 1a2c3e0859 check_history: escape $HOME variable 2022-11-29 10:10:41 +01:00
Jérémy Dubois f7570ec865 check_pkgmirror: use our own openbsd mirror 2022-11-28 14:52:34 +01:00
Jérémy Lecour 8fd10bfeaf fix changelog 2022-11-27 22:06:08 +01:00
Jérémy Lecour 6c1d4f63ac Linux - Release 22.11 2022-11-27 22:01:43 +01:00
Jérémy Lecour 0ff69e6a07 Split versions for Debian 7-, 8 and 9+ 2022-11-27 21:59:05 +01:00
William Hirigoyen 2640bb1b11 Update IS_REDIS_BACKUP path to standard location (used in zzz_evobackup) 2022-11-22 15:48:20 +01:00
Alexis Ben Miloud--Josselin a232eeebcc check_redis: enable multi-instance dump check
To check multiple instances, add something like this in /etc/evocheck.cf:

    REDIS_BACKUP_PATH='/home/backup/redis/dump.rdb /home/backup/redis-instance2/dump.rdb /home/backup/redis-instance3/dump.rdb'
2022-11-14 11:08:40 +01:00
Jérémy Lecour 58a97812c6 Check Debian Security repository from apt-cache policy output
Instead of parsing files,we can ask apt-cache to list the enabled repository
and look for one labeled "Debian-Security" provided by Debian.
2022-11-11 10:18:12 +01:00
Jérémy Dubois 55b08445a7 OpenBSD - Release 22.10 2022-10-14 10:36:37 +02:00
David Prevot f74f1317b4 IS_PHPMYADMINAPACHECONF: check package config
Make sure that package configuration has not been pulled in (e.g.,
/etc/apache2/conf-available/phpmyadmin.conf could be added during an
upgrade and /etc/apache2/conf-enabled/phpmyadmin.conf during an upgrade
a few years later, and thus make phpMyAdmin available in trivial URLs.
2022-10-04 14:03:39 +02:00
Jérémy Dubois 76dfe5fa24 OpenBSD - check_ntp: comply with ntp configuration change on EvoBSD 2022-09-30 14:12:36 +02:00
7 changed files with 3431 additions and 525 deletions

View File

@ -52,7 +52,7 @@ For Debian versions : `is_debian`, `is_debian_stretch`, `is_debian_jessie`…
For packs : `is_pack_web`, `is_pack_samba`.
For installed packages : `is_installed <package> [<package>]`.
### Extact variables
### Extract variables
It's better not to inline function calls inside tests. Instead of this :
@ -72,8 +72,19 @@ test "$expected" = "$actual" || failed "IS_MINIFWPERMS"
It's better to verify that a file, a directory or a command is present before using it, even if it's true in more than 99% of situations.
## How to build the package for a new Debian release
Pre-tasks:
* Execute shellcheck on scripts `*.sh` and fix or disable the relevant checks.
* Prepare `linux/CHANGELOG` and `openbsd/CHANGELOG` for release.
* Update version number is scripts :
```
sed -i 's/VERSION=".*"/VERSION="<MAJOR>.<MINOR>"/g' */evocheck*.sh
```
On the master branch, add the last stable version with a release tag.
```
git tag -s v<VERSION> -m 'New release'

View File

@ -7,14 +7,173 @@ and this project **does not adhere to [Semantic Versioning](http://semver.org/sp
### Changed
* IS_SYSLOGCONF: better detection
### Deprecated
### Removed
### Fixed
* Fix errors in some LXC checks: list only active LXC containers, add conditions to filter containers that are not in evo-standards.
* check_sshallowusers: fix unwanted sterr when /etc/ssh/sshd_condig.d does not exist.
## [24.01] 2024-01-03
### Added
* IS_BACKPORTS_VERSION: check if the Backports release matches the Debian release
### Changed
* IS_BROADCOMFIRMWARE: use apt policy
* Prefer long options
* IS_POSTFIX_MYDESTINATION: use fixed string instead of escaping characters
### Fixed
* IS_EVOBACKUP_EXCLUDE_MOUNT: correctly treat old versions of evobackup
* IS_DEBIANSECURITY_LXC: dont test older than Debian 9 containers
* IS_KERNELUPTODATE: address false positive in case of kernel removal
* IS_SSHPERMITROOTNO: specify lport, avoiding failure if sshd listens to more than one port
* IS_DRBDTWOPRIMARIES: fix false positive (#151)
* IS_ETCGIT_LXC, IS_GITPERMS_LXC: fix path
## [23.11.1] 2023-11-27
### Fixed
* IS_EVOBACKUP_EXCLUDE_MOUNT: fix another regression introduced in previous release
### Security
## [23.11] 2023-11-27
### Added
* trixie and forky support (Debian 13, 14)
* IS_LXC_OPENSSH: check in openssh is installed in containers
* IS_LXC_PHP_BAD_DEBIAN_VERSION: check if php containers use the expected Debian release
* IS_DEBIANSECURITY_LXC: IS_DEBIANSECURITY in containers
* IS_SURY_LXC: IS_SURY in containers
* IS_OLDPUB_LXC: IS_OLDPUB in containers
* IS_ETCGIT_LXC: IS_ETCGIT in containers
* IS_GITPERMS_LXC: IS_GITPERMS in containers
### Changed
* IS_SSHALLOWUSERS: add Debian 12 condition
* IS_PHPEVOLINUXCONF: update for bookworm
* IS_MINIFWINCLUDES, IS_NRPEPID: Change Debian release detection logic
### Fixed
* IS_EVOBACKUP_EXCLUDE_MOUNT: fix regression introduced in previous version
## [23.10] 2023-10-26
### Added
* IS_MINIFW: better detection of minifirewall status
* IS_OLDPUB: pub.evolix.net has been supersed by pub.evolix.org since Stretch
* IS_NEWPUB: verify that the new public repository is present
* IS_DRBDTWOPRIMARIES: check there are not 2 DRBD primaries at the same time.
* IS_SURY: check that if sury is enabled, then a safeguard must be in place
### Changed
* IS_BACKPORTSCONF: does not require preferences anymore
### Fixed
* IS_BINDCHROOT: fix /etc/default path for Debian >= 11 (renamed from bind9 to named)
* IS_EVOBACKUP_EXCLUDE_MOUNT: adapt to new version of evobackup (#148)
## [23.07] 2023-07-07
### Fixed
* IS_REDIS_BACKUP: full rewrite of the check to be more flexible, and also check time of dump.
## [23.04.01] 2023-04-07
### Fixed
* IS_POSTFIX_MYDESTINATION: fix regex not working (again).
## [23.04] 2023-04-07
### Changed
* IS_LOCALHOST_IN_POSTFIX_MYDESTINATION: renamed to IS_POSTFIX_MYDESTINATION
### Fixed
* IS_POSTFIX_MYDESTINATION: fix regex not working.
## [23.03.01] 2023-03-01
### Fixed
* Fix version number.
## [23.03] 2023-03-01
### Added
* Log output and runtime config to /var/log/evocheck.log.
### Changed
### Deprecated
### Removed
### Fixed
* IS_LOCALHOST_IN_POSTFIX_MYDESTINATION: set grep quiet.
* IS_LXC_PHP_FPM_SERVICE_UMASK_SET: fix inverted test condition.
### Security
## [23.02] 2023-02-10
### Fixed
* Release with the correct version number.
## [22.12] 2023-02-10
### Added
New checks :
* IS_LOCALHOST_IN_POSTFIX_MYDESTINATION
* IS_SSH_FAIL2BAN_JAIL_RENAMED
* IS_NO_LXC_CONTAINER
* IS_LXC_PHP_FPM_SERVICE_UMASK_SET
### Changed
* Use bash array for tmp files to cleanup.
### Fixed
* IS_EVOBACKUP_INCS: fix quote.
* IS_PURGE_FAIL2BAN: fix function never called in main().
* IS_NOTUPGRADED: silence "grep: (...) binary file matches" messages.
## [22.11] 2022-11-27
### Added
* New script for Debian 7 and earlier
* New script for Debian 8
* IS_PHPMYADMINAPACHECONF: check that package configuration has not been pulled in
### Changed
* IS_DEBIANSECURITY: check Debian Security repository from apt-cache policy output
### Removed
* Main script is not compatible with Debian 8 and earlier anymore
## [22.09] 2022-09-14
### Fixed

1307
linux/evocheck.jessie.sh Executable file
View File

@ -0,0 +1,1307 @@
#!/bin/bash
# EvoCheck
# Script to verify compliance of a Linux (Debian) server
# powered by Evolix
VERSION="24.01"
readonly VERSION
# base functions
show_version() {
cat <<END
evocheck version ${VERSION} (Jessie)
Copyright 2009-2022 Evolix <info@evolix.fr>,
Romain Dessort <rdessort@evolix.fr>,
Benoit Série <bserie@evolix.fr>,
Gregory Colpart <reg@evolix.fr>,
Jérémy Lecour <jlecour@evolix.fr>,
Tristan Pilat <tpilat@evolix.fr>,
Victor Laborie <vlaborie@evolix.fr>,
Alexis Ben Miloud--Josselin <abenmiloud@evolix.fr>,
and others.
evocheck comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
See the GNU General Public License v3.0 for details.
END
}
show_help() {
cat <<END
evocheck is a script that verifies Evolix conventions on Linux (Debian) servers.
Usage: evocheck
or evocheck --cron
or evocheck --quiet
or evocheck --verbose
Options
--cron disable a few checks
-v, --verbose increase verbosity of checks
-q, --quiet nothing is printed on stdout nor stderr
-h, --help print this message and exit
--version print version and exit
END
}
detect_os() {
# OS detection
DEBIAN_RELEASE=""
LSB_RELEASE_BIN=$(command -v lsb_release)
if [ -e /etc/debian_version ]; then
DEBIAN_MAIN_VERSION=$(cut -d "." -f 1 < /etc/debian_version)
if [ "${DEBIAN_MAIN_VERSION}" -ne "8" ]; then
echo "Debian ${DEBIAN_MAIN_VERSION} is incompatible with this version of evocheck." >&2
echo "This version is built for Debian 8 only." >&2
exit
fi
DEBIAN_RELEASE="jessie"
fi
}
is_pack_web(){
test -e /usr/share/scripts/web-add.sh || test -e /usr/share/scripts/evoadmin/web-add.sh
}
is_pack_samba(){
test -e /usr/share/scripts/add.pl
}
is_installed(){
for pkg in "$@"; do
dpkg -l "$pkg" 2> /dev/null | grep -q -E '^(i|h)i' || return 1
done
}
# logging
failed() {
check_name=$1
shift
check_comments=$*
RC=1
if [ "${QUIET}" != 1 ]; then
if [ -n "${check_comments}" ] && [ "${VERBOSE}" = 1 ]; then
printf "%s FAILED! %s\n" "${check_name}" "${check_comments}" >> "${main_output_file}"
else
printf "%s FAILED!\n" "${check_name}" >> "${main_output_file}"
fi
fi
}
# check functions
check_lsbrelease(){
if [ -x "${LSB_RELEASE_BIN}" ]; then
## only the major version matters
lhs=$(${LSB_RELEASE_BIN} --release --short | cut -d "." -f 1)
rhs=$(cut -d "." -f 1 < /etc/debian_version)
test "$lhs" = "$rhs" || failed "IS_LSBRELEASE" "release is not consistent between lsb_release (${lhs}) and /etc/debian_version (${rhs})"
else
failed "IS_LSBRELEASE" "lsb_release is missing or not executable"
fi
}
# Verifying check_mailq in Nagios NRPE config file. (Option "-M postfix" need to be set if the MTA is Postfix)
check_nrpepostfix() {
if is_installed postfix; then
{ test -e /etc/nagios/nrpe.cfg \
&& grep -qr "^command.*check_mailq -M postfix" /etc/nagios/nrpe.*;
} || failed "IS_NRPEPOSTFIX" "NRPE \"check_mailq\" for postfix is missing"
fi
}
# Check if mod-security config file is present
check_customsudoers() {
grep -E -qr "umask=0077" /etc/sudoers* || failed "IS_CUSTOMSUDOERS" "missing umask=0077 in sudoers file"
}
check_vartmpfs() {
FINDMNT_BIN=$(command -v findmnt)
if [ -x "${FINDMNT_BIN}" ]; then
${FINDMNT_BIN} /var/tmp --type tmpfs --noheadings > /dev/null || failed "IS_VARTMPFS" "/var/tmp is not a tmpfs"
else
df /var/tmp | grep -q tmpfs || failed "IS_VARTMPFS" "/var/tmp is not a tmpfs"
fi
}
check_serveurbase() {
is_installed serveur-base || failed "IS_SERVEURBASE" "serveur-base package is not installed"
}
check_logrotateconf() {
test -e /etc/logrotate.d/zsyslog || failed "IS_LOGROTATECONF" "missing zsyslog in logrotate.d"
}
check_syslogconf() {
grep -q "^# Syslog for Pack Evolix serveur" /etc/*syslog.conf \
|| failed "IS_SYSLOGCONF" "syslog evolix config file missing"
}
check_debiansecurity() {
# Look for enabled "Debian-Security" sources from the "Debian" origin
apt-cache policy | grep "\bl=Debian-Security\b" | grep "\bo=Debian\b" | grep --quiet "\bc=main\b"
test $? -eq 0 || failed "IS_DEBIANSECURITY" "missing Debian-Security repository"
}
check_aptitude() {
test -e /usr/bin/aptitude && failed "IS_APTITUDE" "aptitude may not be installed on Debian >=8"
}
check_aptgetbak() {
test -e /usr/bin/apt-get.bak && failed "IS_APTGETBAK" "prohibit the installation of apt-get.bak with dpkg-divert(1)"
}
check_usrro() {
grep /usr /etc/fstab | grep -qE "\bro\b" || failed "IS_USRRO" "missing ro directive on fstab for /usr"
}
check_tmpnoexec() {
FINDMNT_BIN=$(command -v findmnt)
if [ -x "${FINDMNT_BIN}" ]; then
options=$(${FINDMNT_BIN} --noheadings --first-only --output OPTIONS /tmp)
echo "${options}" | grep -qE "\bnoexec\b" || failed "IS_TMPNOEXEC" "/tmp is not mounted with 'noexec'"
else
mount | grep "on /tmp" | grep -qE "\bnoexec\b" || failed "IS_TMPNOEXEC" "/tmp is not mounted with 'noexec' (WARNING: findmnt(8) is not found)"
fi
}
check_mountfstab() {
# Test if lsblk available, if not skip this test...
LSBLK_BIN=$(command -v lsblk)
if test -x "${LSBLK_BIN}"; then
for mountPoint in $(${LSBLK_BIN} -o MOUNTPOINT -l -n | grep '/'); do
grep -Eq "$mountPoint\W" /etc/fstab \
|| failed "IS_MOUNT_FSTAB" "partition(s) detected mounted but no presence in fstab"
done
fi
}
check_listchangesconf() {
if [ -e "/etc/apt/listchanges.conf" ]; then
lines=$(grep -cE "(which=both|confirm=1)" /etc/apt/listchanges.conf)
if [ "$lines" != 2 ]; then
failed "IS_LISTCHANGESCONF" "apt-listchanges config is incorrect"
fi
else
failed "IS_LISTCHANGESCONF" "apt-listchanges config is missing"
fi
}
check_customcrontab() {
found_lines=$(grep -c -E "^(17 \*|25 6|47 6|52 6)" /etc/crontab)
test "$found_lines" = 4 && failed "IS_CUSTOMCRONTAB" "missing custom field in crontab"
}
check_sshallowusers() {
grep -E -qir "(AllowUsers|AllowGroups)" /etc/ssh/sshd_config /etc/ssh/sshd_config.d \
|| failed "IS_SSHALLOWUSERS" "missing AllowUsers or AllowGroups directive in sshd_config"
}
check_diskperf() {
perfFile="/root/disk-perf.txt"
test -e $perfFile || failed "IS_DISKPERF" "missing ${perfFile}"
}
check_tmoutprofile() {
grep -sq "TMOUT=" /etc/profile /etc/profile.d/evolinux.sh || failed "IS_TMOUTPROFILE" "TMOUT is not set"
}
check_alert5boot() {
if [ -n "$(find /etc/rc2.d/ -name 'S*alert5')" ]; then
grep -q "^date" /etc/rc2.d/S*alert5 || failed "IS_ALERT5BOOT" "boot mail is not sent by alert5 init script"
elif [ -n "$(find /etc/init.d/ -name 'alert5')" ]; then
grep -q "^date" /etc/init.d/alert5 || failed "IS_ALERT5BOOT" "boot mail is not sent by alert5 int script"
else
failed "IS_ALERT5BOOT" "alert5 init script is missing"
fi
}
check_alert5minifw() {
if [ -n "$(find /etc/rc2.d/ -name 'S*alert5')" ]; then
grep -q "^/etc/init.d/minifirewall" /etc/rc2.d/S*alert5 \
|| failed "IS_ALERT5MINIFW" "Minifirewall is not started by alert5 init script"
elif [ -n "$(find /etc/init.d/ -name 'alert5')" ]; then
grep -q "^/etc/init.d/minifirewall" /etc/init.d/alert5 \
|| failed "IS_ALERT5MINIFW" "Minifirewall is not started by alert5 init script"
else
failed "IS_ALERT5MINIFW" "alert5 init script is missing"
fi
}
check_minifw() {
/sbin/iptables -L -n | grep -q -E "^ACCEPT\s*all\s*--\s*31\.170\.8\.4\s*0\.0\.0\.0/0\s*$" \
|| failed "IS_MINIFW" "minifirewall seems not started"
}
check_nrpeperms() {
if [ -d /etc/nagios ]; then
nagiosDir="/etc/nagios"
actual=$(stat --format "%a" $nagiosDir)
expected="750"
test "$expected" = "$actual" || failed "IS_NRPEPERMS" "${nagiosDir} must be ${expected}"
fi
}
check_minifwperms() {
if [ -f "/etc/default/minifirewall" ]; then
actual=$(stat --format "%a" "/etc/default/minifirewall")
expected="600"
test "$expected" = "$actual" || failed "IS_MINIFWPERMS" "/etc/default/minifirewall must be ${expected}"
fi
}
check_nrpedisks() {
NRPEDISKS=$(grep command.check_disk /etc/nagios/nrpe.cfg | grep "^command.check_disk[0-9]" | sed -e "s/^command.check_disk\([0-9]\+\).*/\1/" | sort -n | tail -1)
DFDISKS=$(df -Pl | grep -c -E -v "(^Filesystem|/lib/init/rw|/dev/shm|udev|rpc_pipefs)")
test "$NRPEDISKS" = "$DFDISKS" || failed "IS_NRPEDISKS" "there must be $DFDISKS check_disk in nrpe.cfg"
}
check_nrpepid() {
{ test -e /etc/nagios/nrpe.cfg \
&& grep -q "^pid_file=/var/run/nagios/nrpe.pid" /etc/nagios/nrpe.cfg;
} || failed "IS_NRPEPID" "missing or wrong pid_file directive in nrpe.cfg"
}
check_grsecprocs() {
if uname -a | grep -q grsec; then
{ grep -q "^command.check_total_procs..sudo" /etc/nagios/nrpe.cfg \
&& grep -A1 "^\[processes\]" /etc/munin/plugin-conf.d/munin-node | grep -q "^user root";
} || failed "IS_GRSECPROCS" "missing munin's plugin processes directive for grsec"
fi
}
check_apachemunin() {
if test -e /etc/apache2/apache2.conf; then
pattern="/server-status-[[:alnum:]]{4,}"
{ grep -r -q -s -E "^env.url.*${pattern}" /etc/munin/plugin-conf.d \
&& { grep -q -s -E "${pattern}" /etc/apache2/apache2.conf \
|| grep -q -s -E "${pattern}" /etc/apache2/mods-enabled/status.conf;
};
} || failed "IS_APACHEMUNIN" "server status is not properly configured"
fi
}
# Verification mytop + Munin si MySQL
check_mysqlutils() {
MYSQL_ADMIN=${MYSQL_ADMIN:-mysqladmin}
if is_installed mysql-server; then
# You can configure MYSQL_ADMIN in evocheck.cf
if ! grep -qs "^user *= *${MYSQL_ADMIN}" /root/.my.cnf; then
failed "IS_MYSQLUTILS" "${MYSQL_ADMIN} missing in /root/.my.cnf"
fi
if ! test -x /usr/bin/mytop; then
if ! test -x /usr/local/bin/mytop; then
failed "IS_MYSQLUTILS" "mytop binary missing"
fi
fi
if ! grep -qs '^user *=' /root/.mytop; then
failed "IS_MYSQLUTILS" "credentials missing in /root/.mytop"
fi
fi
}
# Verification de la configuration du raid soft (mdadm)
check_raidsoft() {
if test -e /proc/mdstat && grep -q md /proc/mdstat; then
{ grep -q "^AUTOCHECK=true" /etc/default/mdadm \
&& grep -q "^START_DAEMON=true" /etc/default/mdadm \
&& grep -qv "^MAILADDR ___MAIL___" /etc/mdadm/mdadm.conf;
} || failed "IS_RAIDSOFT" "missing or wrong config for mdadm"
fi
}
# Verification du LogFormat de AWStats
check_awstatslogformat() {
if is_installed apache2 awstats; then
awstatsFile="/etc/awstats/awstats.conf.local"
grep -qE '^LogFormat=1' $awstatsFile \
|| failed "IS_AWSTATSLOGFORMAT" "missing or wrong LogFormat directive in $awstatsFile"
fi
}
# Verification de la présence de la config logrotate pour Munin
check_muninlogrotate() {
{ test -e /etc/logrotate.d/munin-node \
&& test -e /etc/logrotate.d/munin;
} || failed "IS_MUNINLOGROTATE" "missing lorotate file for munin"
}
# Verification de l'activation de Squid dans le cas d'un pack mail
check_squid() {
squidconffile="/etc/squid*/squid.conf"
if is_pack_web && (is_installed squid || is_installed squid3); then
host=$(hostname -i)
# shellcheck disable=SC2086
http_port=$(grep -E "^http_port\s+[0-9]+" $squidconffile | awk '{ print $2 }')
{ grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -m owner --uid-owner proxy -j ACCEPT" "/etc/default/minifirewall" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -d $host -j ACCEPT" "/etc/default/minifirewall" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -d 127.0.0.(1|0/8) -j ACCEPT" "/etc/default/minifirewall" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port.* $http_port" "/etc/default/minifirewall";
} || grep -qE "^PROXY='?on'?" "/etc/default/minifirewall" \
|| failed "IS_SQUID" "missing squid rules in minifirewall"
fi
}
check_evomaintenance_fw() {
if [ -f "/etc/default/minifirewall" ]; then
hook_db=$(grep -E '^\s*HOOK_DB' /etc/evomaintenance.cf | tr -d ' ' | cut -d= -f2)
rulesNumber=$(grep -c "/sbin/iptables -A INPUT -p tcp --sport 5432 --dport 1024:65535 -s .* -m state --state ESTABLISHED,RELATED -j ACCEPT" "/etc/default/minifirewall")
if [ "$hook_db" = "1" ] && [ "$rulesNumber" -lt 2 ]; then
failed "IS_EVOMAINTENANCE_FW" "HOOK_DB is enabled but missing evomaintenance rules in minifirewall"
fi
fi
}
# Verification de la conf et de l'activation de mod-deflate
check_moddeflate() {
f=/etc/apache2/mods-enabled/deflate.conf
if is_installed apache2.2; then
{ test -e $f && grep -q "AddOutputFilterByType DEFLATE text/html text/plain text/xml" $f \
&& grep -q "AddOutputFilterByType DEFLATE text/css" $f \
&& grep -q "AddOutputFilterByType DEFLATE application/x-javascript application/javascript" $f;
} || failed "IS_MODDEFLATE" "missing AddOutputFilterByType directive for apache mod deflate"
fi
}
# Verification de la conf log2mail
check_log2mailrunning() {
if is_pack_web && is_installed log2mail; then
pgrep log2mail >/dev/null || failed "IS_LOG2MAILRUNNING" "log2mail is not running"
fi
}
check_log2mailapache() {
conf=/etc/log2mail/config/default
if is_pack_web && is_installed log2mail; then
grep -s -q "^file = /var/log/apache2/error.log" $conf \
|| failed "IS_LOG2MAILAPACHE" "missing log2mail directive for apache"
fi
}
check_log2mailmysql() {
if is_pack_web && is_installed log2mail; then
grep -s -q "^file = /var/log/syslog" /etc/log2mail/config/{default,mysql,mysql.conf} \
|| failed "IS_LOG2MAILMYSQL" "missing log2mail directive for mysql"
fi
}
check_log2mailsquid() {
if is_pack_web && is_installed log2mail; then
grep -s -q "^file = /var/log/squid.*/access.log" /etc/log2mail/config/* \
|| failed "IS_LOG2MAILSQUID" "missing log2mail directive for squid"
fi
}
# Verification si bind est chroote
check_bindchroot() {
if is_installed bind9; then
if netstat -utpln | grep "/named" | grep :53 | grep -qvE "(127.0.0.1|::1)"; then
if grep -q '^OPTIONS=".*-t' /etc/default/bind9 && grep -q '^OPTIONS=".*-u' /etc/default/bind9; then
md5_original=$(md5sum /usr/sbin/named | cut -f 1 -d ' ')
md5_chrooted=$(md5sum /var/chroot-bind/usr/sbin/named | cut -f 1 -d ' ')
if [ "$md5_original" != "$md5_chrooted" ]; then
failed "IS_BINDCHROOT" "the chrooted bind binary is different than the original binary"
fi
else
failed "IS_BINDCHROOT" "bind process is not chrooted"
fi
fi
fi
}
# /etc/network/interfaces should be present, we don't manage systemd-network yet
check_network_interfaces() {
if ! test -f /etc/network/interfaces; then
IS_AUTOIF=0
IS_INTERFACESGW=0
failed "IS_NETWORK_INTERFACES" "systemd network configuration is not supported yet"
fi
}
# Verify if all if are in auto
check_autoif() {
interfaces=$(/sbin/ifconfig -s | tail -n +2 | grep -E -v "^(lo|vnet|docker|veth|tun|tap|macvtap|vrrp)" | cut -d " " -f 1 |tr "\n" " ")
for interface in $interfaces; do
if grep -Rq "^iface $interface" /etc/network/interfaces* && ! grep -Rq "^auto $interface" /etc/network/interfaces*; then
failed "IS_AUTOIF" "Network interface \`${interface}' is statically defined but not set to auto"
test "${VERBOSE}" = 1 || break
fi
done
}
# Network conf verification
check_interfacesgw() {
number=$(grep -Ec "^[^#]*gateway [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" /etc/network/interfaces)
test "$number" -gt 1 && failed "IS_INTERFACESGW" "there is more than 1 IPv4 gateway"
number=$(grep -Ec "^[^#]*gateway [0-9a-fA-F]+:" /etc/network/interfaces)
test "$number" -gt 1 && failed "IS_INTERFACESGW" "there is more than 1 IPv6 gateway"
}
# Verification de la mise en place d'evobackup
check_evobackup() {
evobackup_found=$(find /etc/cron* -name '*evobackup*' | wc -l)
test "$evobackup_found" -gt 0 || failed "IS_EVOBACKUP" "missing evobackup cron"
}
# Vérification de l'exclusion des montages (NFS) dans les sauvegardes
check_evobackup_exclude_mount() {
excludes_file=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.evobackup_exclude_mount.XXXXX")
files_to_cleanup="${files_to_cleanup} ${excludes_file}"
# shellcheck disable=SC2044
for evobackup_file in $(find /etc/cron* -name '*evobackup*' | grep -v -E ".disabled$"); do
# if the file seems to be a backup script, with an Rsync invocation
if grep -q "^\s*rsync" "${evobackup_file}"; then
# If rsync is not limited by "one-file-system"
# then we verify that every mount is excluded
if ! grep -q -- "^\s*--one-file-system" "${evobackup_file}"; then
grep -- "--exclude " "${evobackup_file}" | grep -E -o "\"[^\"]+\"" | tr -d '"' > "${excludes_file}"
not_excluded=$(findmnt --type nfs,nfs4,fuse.sshfs, -o target --noheadings | grep -v -f "${excludes_file}")
for mount in ${not_excluded}; do
failed "IS_EVOBACKUP_EXCLUDE_MOUNT" "${mount} is not excluded from ${evobackup_file} backup script"
done
fi
fi
done
}
# Verification de la presence du userlogrotate
check_userlogrotate() {
if is_pack_web; then
test -x /etc/cron.weekly/userlogrotate || failed "IS_USERLOGROTATE" "missing userlogrotate cron"
fi
}
# Verification de la syntaxe de la conf d'Apache
check_apachectl() {
if is_installed apache2; then
/usr/sbin/apache2ctl configtest 2>&1 | grep -q "^Syntax OK$" \
|| failed "IS_APACHECTL" "apache errors detected, run a configtest"
fi
}
# Check if there is regular files in Apache sites-enabled.
check_apachesymlink() {
if is_installed apache2; then
apacheFind=$(find /etc/apache2/sites-enabled ! -type l -type f -print)
nbApacheFind=$(wc -m <<< "$apacheFind")
if [[ $nbApacheFind -gt 1 ]]; then
if [[ $VERBOSE == 1 ]]; then
while read -r line; do
failed "IS_APACHESYMLINK" "Not a symlink: $line"
done <<< "$apacheFind"
else
failed "IS_APACHESYMLINK"
fi
fi
fi
}
# Check if there is real IP addresses in Allow/Deny directives (no trailing space, inline comments or so).
check_apacheipinallow() {
# Note: Replace "exit 1" by "print" in Perl code to debug it.
if is_installed apache2; then
grep -IrE "^[^#] *(Allow|Deny) from" /etc/apache2/ \
| grep -iv "from all" \
| grep -iv "env=" \
| perl -ne 'exit 1 unless (/from( [\da-f:.\/]+)+$/i)' \
|| failed "IS_APACHEIPINALLOW" "bad (Allow|Deny) directives in apache"
fi
}
# Check if default Apache configuration file for munin is absent (or empty or commented).
check_muninapacheconf() {
muninconf="/etc/apache2/conf-available/munin.conf"
if is_installed apache2; then
test -e $muninconf && grep -vEq "^( |\t)*#" "$muninconf" \
&& failed "IS_MUNINAPACHECONF" "default munin configuration may be commented or disabled"
fi
}
# Check if default Apache configuration file for phpMyAdmin is absent (or empty or commented).
check_phpmyadminapacheconf() {
phpmyadminconf0="/etc/apache2/conf-available/phpmyadmin.conf"
phpmyadminconf1="/etc/apache2/conf-enabled/phpmyadmin.conf"
if is_installed apache2; then
test -e $phpmyadminconf0 && grep -vEq "^( |\t)*#" "$phpmyadminconf0" \
&& failed "IS_PHPMYADMINAPACHECONF" "default phpmyadmin configuration ($phpmyadminconf0) may be commented or disabled"
test -e $phpmyadminconf1 && grep -vEq "^( |\t)*#" "$phpmyadminconf1" \
&& failed "IS_PHPMYADMINAPACHECONF" "default phpmyadmin configuration ($phpmyadminconf1) may be commented or disabled"
fi
}
# Verification si le système doit redémarrer suite màj kernel.
check_kerneluptodate() {
if is_installed linux-image*; then
# shellcheck disable=SC2012
kernel_installed_at=$(date -d "$(ls --full-time -lcrt /boot | tail -n1 | awk '{print $6}')" +%s)
last_reboot_at=$(($(date +%s) - $(cut -f1 -d '.' /proc/uptime)))
if [ "$kernel_installed_at" -gt "$last_reboot_at" ]; then
failed "IS_KERNELUPTODATE" "machine is running an outdated kernel, reboot advised"
fi
fi
}
# Check if the server is running for more than a year.
check_uptime() {
if is_installed linux-image*; then
limit=$(date -d "now - 2 year" +%s)
last_reboot_at=$(($(date +%s) - $(cut -f1 -d '.' /proc/uptime)))
if [ "$limit" -gt "$last_reboot_at" ]; then
failed "IS_UPTIME" "machine has an uptime of more than 2 years, reboot on new kernel advised"
fi
fi
}
# Check if munin-node running and RRD files are up to date.
check_muninrunning() {
if ! pgrep munin-node >/dev/null; then
failed "IS_MUNINRUNNING" "Munin is not running"
elif [ -d "/var/lib/munin/" ] && [ -d "/var/cache/munin/" ]; then
limit=$(date +"%s" -d "now - 10 minutes")
if [ -n "$(find /var/lib/munin/ -name '*load-g.rrd')" ]; then
updated_at=$(stat -c "%Y" /var/lib/munin/*/*load-g.rrd |sort |tail -1)
[ "$limit" -gt "$updated_at" ] && failed "IS_MUNINRUNNING" "Munin load RRD has not been updated in the last 10 minutes"
else
failed "IS_MUNINRUNNING" "Munin is not installed properly (load RRD not found)"
fi
if [ -n "$(find /var/cache/munin/www/ -name 'load-day.png')" ]; then
updated_at=$(stat -c "%Y" /var/cache/munin/www/*/*/load-day.png |sort |tail -1)
grep -sq "^graph_strategy cron" /etc/munin/munin.conf && [ "$limit" -gt "$updated_at" ] && failed "IS_MUNINRUNNING" "Munin load PNG has not been updated in the last 10 minutes"
else
failed "IS_MUNINRUNNING" "Munin is not installed properly (load PNG not found)"
fi
else
failed "IS_MUNINRUNNING" "Munin is not installed properly (main directories are missing)"
fi
}
# Check if files in /home/backup/ are up-to-date
check_backupuptodate() {
backup_dir="/home/backup"
if [ -d "${backup_dir}" ]; then
if [ -n "$(ls -A ${backup_dir})" ]; then
find "${backup_dir}" -maxdepth 1 -type f | while read -r file; do
limit=$(date +"%s" -d "now - 2 day")
updated_at=$(stat -c "%Y" "$file")
if [ "$limit" -gt "$updated_at" ]; then
failed "IS_BACKUPUPTODATE" "$file has not been backed up"
test "${VERBOSE}" = 1 || break;
fi
done
else
failed "IS_BACKUPUPTODATE" "${backup_dir}/ is empty"
fi
else
failed "IS_BACKUPUPTODATE" "${backup_dir}/ is missing"
fi
}
check_etcgit() {
export GIT_DIR="/etc/.git" GIT_WORK_TREE="/etc"
git rev-parse --is-inside-work-tree > /dev/null 2>&1 \
|| failed "IS_ETCGIT" "/etc is not a git repository"
}
# Check if /etc/.git/ has read/write permissions for root only.
check_gitperms() {
GIT_DIR="/etc/.git"
if test -d $GIT_DIR; then
expected="700"
actual=$(stat -c "%a" $GIT_DIR)
[ "$expected" = "$actual" ] || failed "IS_GITPERMS" "$GIT_DIR must be $expected"
fi
}
# Check if no package has been upgraded since $limit.
check_notupgraded() {
last_upgrade=0
upgraded=false
for log in /var/log/dpkg.log*; do
if zgrep -qsm1 upgrade "$log"; then
# There is at least one upgrade
upgraded=true
break
fi
done
if $upgraded; then
last_upgrade=$(date +%s -d "$(zgrep -h upgrade /var/log/dpkg.log* | sort -n | tail -1 | cut -f1 -d ' ')")
fi
if grep -qs '^mailto="listupgrade-todo@' /etc/evolinux/listupgrade.cnf \
|| grep -qs -E '^[[:digit:]]+[[:space:]]+[[:digit:]]+[[:space:]]+[^\*]' /etc/cron.d/listupgrade; then
# Manual upgrade process
limit=$(date +%s -d "now - 180 days")
else
# Regular process
limit=$(date +%s -d "now - 90 days")
fi
install_date=0
if [ -d /var/log/installer ]; then
install_date=$(stat -c %Z /var/log/installer)
fi
# Check install_date if the system never received an upgrade
if [ "$last_upgrade" -eq 0 ]; then
[ "$install_date" -lt "$limit" ] && failed "IS_NOTUPGRADED" "The system has never been updated"
else
[ "$last_upgrade" -lt "$limit" ] && failed "IS_NOTUPGRADED" "The system hasn't been updated for too long"
fi
}
# Check if reserved blocks for root is at least 5% on every mounted partitions.
check_tune2fs_m5() {
min=5
parts=$(grep -E "ext(3|4)" /proc/mounts | cut -d ' ' -f1 | tr -s '\n' ' ')
FINDMNT_BIN=$(command -v findmnt)
for part in $parts; do
blockCount=$(dumpe2fs -h "$part" 2>/dev/null | grep -e "Block count:" | grep -Eo "[0-9]+")
# If buggy partition, skip it.
if [ -z "$blockCount" ]; then
continue
fi
reservedBlockCount=$(dumpe2fs -h "$part" 2>/dev/null | grep -e "Reserved block count:" | grep -Eo "[0-9]+")
# Use awk to have a rounded percentage
# python is slow, bash is unable and bc rounds weirdly
percentage=$(awk "BEGIN { pc=100*${reservedBlockCount}/${blockCount}; i=int(pc); print (pc-i<0.5)?i:i+1 }")
if [ "$percentage" -lt "${min}" ]; then
if [ -x "${FINDMNT_BIN}" ]; then
mount=$(${FINDMNT_BIN} --noheadings --first-only --output TARGET "${part}")
else
mount="unknown mount point"
fi
failed "IS_TUNE2FS_M5" "Partition ${part} (${mount}) has less than ${min}% reserved blocks (${percentage}%)"
fi
done
}
check_broadcomfirmware() {
LSPCI_BIN=$(command -v lspci)
if [ -x "${LSPCI_BIN}" ]; then
if ${LSPCI_BIN} | grep -q 'NetXtreme II'; then
{ is_installed firmware-bnx2 \
&& grep -q "^deb http://mirror.evolix.org/debian.* non-free" /etc/apt/sources.list;
} || failed "IS_BROADCOMFIRMWARE" "missing non-free repository"
fi
else
failed "IS_BROADCOMFIRMWARE" "lspci not found in ${PATH}"
fi
}
check_hardwareraidtool() {
LSPCI_BIN=$(command -v lspci)
if [ -x "${LSPCI_BIN}" ]; then
if ${LSPCI_BIN} | grep -q 'MegaRAID'; then
# shellcheck disable=SC2015
is_installed megacli && { is_installed megaclisas-status || is_installed megaraidsas-status; } \
|| failed "IS_HARDWARERAIDTOOL" "Mega tools not found"
fi
if ${LSPCI_BIN} | grep -q 'Hewlett-Packard Company Smart Array'; then
is_installed cciss-vol-status || failed "IS_HARDWARERAIDTOOL" "cciss-vol-status not installed"
fi
else
failed "IS_HARDWARERAIDTOOL" "lspci not found in ${PATH}"
fi
}
check_listupgrade() {
test -f /etc/cron.d/listupgrade \
|| failed "IS_LISTUPGRADE" "missing listupgrade cron"
test -x /usr/share/scripts/listupgrade.sh \
|| failed "IS_LISTUPGRADE" "missing listupgrade script or not executable"
}
check_sql_backup() {
if (is_installed "mysql-server" || is_installed "mariadb-server"); then
# You could change the default path in /etc/evocheck.cf
SQL_BACKUP_PATH=${SQL_BACKUP_PATH:-"/home/backup/mysql.bak.gz"}
for backup_path in ${SQL_BACKUP_PATH}; do
if [ ! -f "${backup_path}" ]; then
failed "IS_SQL_BACKUP" "MySQL dump is missing (${backup_path})"
test "${VERBOSE}" = 1 || break
fi
done
fi
}
check_postgres_backup() {
if is_installed "postgresql-9*" || is_installed "postgresql-1*"; then
# If you use something like barman, you should disable this check
# You could change the default path in /etc/evocheck.cf
POSTGRES_BACKUP_PATH=${POSTGRES_BACKUP_PATH:-"/home/backup/pg.dump.bak*"}
for backup_path in ${POSTGRES_BACKUP_PATH}; do
if [ ! -f "${backup_path}" ]; then
failed "IS_POSTGRES_BACKUP" "PostgreSQL dump is missing (${backup_path})"
test "${VERBOSE}" = 1 || break
fi
done
fi
}
check_mongo_backup() {
if is_installed "mongodb-org-server"; then
# You could change the default path in /etc/evocheck.cf
MONGO_BACKUP_PATH=${MONGO_BACKUP_PATH:-"/home/backup/mongodump"}
if [ -d "$MONGO_BACKUP_PATH" ]; then
for file in "${MONGO_BACKUP_PATH}"/*/*.{json,bson}*; do
# Skip indexes file.
if ! [[ "$file" =~ indexes ]]; then
limit=$(date +"%s" -d "now - 2 day")
updated_at=$(stat -c "%Y" "$file")
if [ -f "$file" ] && [ "$limit" -gt "$updated_at" ]; then
failed "IS_MONGO_BACKUP" "MongoDB hasn't been dumped for more than 2 days"
break
fi
fi
done
else
failed "IS_MONGO_BACKUP" "MongoDB dump directory is missing (${MONGO_BACKUP_PATH})"
fi
fi
}
check_ldap_backup() {
if is_installed slapd; then
# You could change the default path in /etc/evocheck.cf
LDAP_BACKUP_PATH=${LDAP_BACKUP_PATH:-"/home/backup/ldap.bak"}
test -f "$LDAP_BACKUP_PATH" || failed "IS_LDAP_BACKUP" "LDAP dump is missing (${LDAP_BACKUP_PATH})"
fi
}
check_redis_backup() {
if is_installed redis-server; then
# You could change the default path in /etc/evocheck.cf
# REDIS_BACKUP_PATH may contain space-separated paths, example:
# REDIS_BACKUP_PATH='/home/backup/redis-instance1/dump.rdb /home/backup/redis-instance2/dump.rdb'
REDIS_BACKUP_PATH=${REDIS_BACKUP_PATH:-"/home/backup/redis/dump.rdb"}
for file in ${REDIS_BACKUP_PATH}; do
test -f "${file}" || failed "IS_REDIS_BACKUP" "Redis dump is missing (${file})"
done
fi
}
check_elastic_backup() {
if is_installed elasticsearch; then
# You could change the default path in /etc/evocheck.cf
ELASTIC_BACKUP_PATH=${ELASTIC_BACKUP_PATH:-"/home/backup-elasticsearch"}
test -d "$ELASTIC_BACKUP_PATH" || failed "IS_ELASTIC_BACKUP" "Elastic snapshot is missing (${ELASTIC_BACKUP_PATH})"
fi
}
check_duplicate_fs_label() {
# Do it only if thereis blkid binary
BLKID_BIN=$(command -v blkid)
if [ -n "$BLKID_BIN" ]; then
tmpFile=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.duplicate_fs_label.XXXXX")
files_to_cleanup="${files_to_cleanup} ${tmpFile}"
parts=$($BLKID_BIN -c /dev/null | grep -ve raid_member -e EFI_SYSPART | grep -Eo ' LABEL=".*"' | cut -d'"' -f2)
for part in $parts; do
echo "$part" >> "$tmpFile"
done
tmpOutput=$(sort < "$tmpFile" | uniq -d)
# If there is no duplicate, uniq will have no output
# So, if $tmpOutput is not null, there is a duplicate
if [ -n "$tmpOutput" ]; then
# shellcheck disable=SC2086
labels=$(echo -n $tmpOutput | tr '\n' ' ')
failed "IS_DUPLICATE_FS_LABEL" "Duplicate labels: $labels"
fi
else
failed "IS_DUPLICATE_FS_LABEL" "blkid not found in ${PATH}"
fi
}
check_evolix_user() {
grep -q -E "^evolix:" /etc/passwd \
&& failed "IS_EVOLIX_USER" "evolix user should be deleted, used only for install"
}
check_evoacme_cron() {
if [ -f "/usr/local/sbin/evoacme" ]; then
# Old cron file, should be deleted
test -f /etc/cron.daily/certbot && failed "IS_EVOACME_CRON" "certbot cron is incompatible with evoacme"
# evoacme cron file should be present
test -f /etc/cron.daily/evoacme || failed "IS_EVOACME_CRON" "evoacme cron is missing"
fi
}
check_evoacme_livelinks() {
EVOACME_BIN=$(command -v evoacme)
if [ -x "$EVOACME_BIN" ]; then
# Sometimes evoacme is installed but no certificates has been generated
numberOfLinks=$(find /etc/letsencrypt/ -type l | wc -l)
if [ "$numberOfLinks" -gt 0 ]; then
for live in /etc/letsencrypt/*/live; do
actualLink=$(readlink -f "$live")
actualVersion=$(basename "$actualLink")
certDir=$(dirname "$live")
certName=$(basename "$certDir")
# shellcheck disable=SC2012
lastCertDir=$(ls -ds "${certDir}"/[0-9]* | tail -1)
lastVersion=$(basename "$lastCertDir")
if [[ "$lastVersion" != "$actualVersion" ]]; then
failed "IS_EVOACME_LIVELINKS" "Certificate \`$certName' hasn't been updated"
test "${VERBOSE}" = 1 || break
fi
done
fi
fi
}
check_apache_confenabled() {
# Starting from Jessie and Apache 2.4, /etc/apache2/conf.d/
# must be replaced by conf-available/ and config files symlinked
# to conf-enabled/
if [ -f /etc/apache2/apache2.conf ]; then
test -d /etc/apache2/conf.d/ \
&& failed "IS_APACHE_CONFENABLED" "apache's conf.d directory must not exists"
grep -q 'Include conf.d' /etc/apache2/apache2.conf \
&& failed "IS_APACHE_CONFENABLED" "apache2.conf must not Include conf.d"
fi
}
check_meltdown_spectre() {
# For Jessie this is quite complicated to verify and we need to use kernel config file
if grep -q "BOOT_IMAGE=" /proc/cmdline; then
kernelPath=$(grep -Eo 'BOOT_IMAGE=[^ ]+' /proc/cmdline | cut -d= -f2)
kernelVer=${kernelPath##*/vmlinuz-}
kernelConfig="config-${kernelVer}"
# Sometimes autodetection of kernel config file fail, so we test if the file really exists.
if [ -f "/boot/${kernelConfig}" ]; then
grep -Eq '^CONFIG_PAGE_TABLE_ISOLATION=y' "/boot/$kernelConfig" \
|| failed "IS_MELTDOWN_SPECTRE" \
"PAGE_TABLE_ISOLATION must be enabled in kernel, outdated kernel?"
grep -Eq '^CONFIG_RETPOLINE=y' "/boot/$kernelConfig" \
|| failed "IS_MELTDOWN_SPECTRE" \
"RETPOLINE must be enabled in kernel, outdated kernel?"
fi
fi
}
check_old_home_dir() {
homeDir=${homeDir:-/home}
for dir in "$homeDir"/*; do
statResult=$(stat -c "%n has owner %u resolved as %U" "$dir" \
| grep -Eve '.bak' -e '\.[0-9]{2}-[0-9]{2}-[0-9]{4}' \
| grep "UNKNOWN")
# There is at least one dir matching
if [[ -n "$statResult" ]]; then
failed "IS_OLD_HOME_DIR" "$statResult"
test "${VERBOSE}" = 1 || break
fi
done
}
check_tmp_1777() {
actual=$(stat --format "%a" /tmp)
expected="1777"
test "$expected" = "$actual" || failed "IS_TMP_1777" "/tmp must be $expected"
}
check_root_0700() {
actual=$(stat --format "%a" /root)
expected="700"
test "$expected" = "$actual" || failed "IS_ROOT_0700" "/root must be $expected"
}
check_usrsharescripts() {
actual=$(stat --format "%a" /usr/share/scripts)
expected="700"
test "$expected" = "$actual" || failed "IS_USRSHARESCRIPTS" "/usr/share/scripts must be $expected"
}
check_sshpermitrootno() {
sshd_args="-C addr=,user=,host=,laddr=,lport=0"
# shellcheck disable=SC2086
if ! (sshd -T ${sshd_args} 2> /dev/null | grep -qi 'permitrootlogin no'); then
failed "IS_SSHPERMITROOTNO" "PermitRoot should be set to no"
fi
}
check_evomaintenanceusers() {
if [ -f /etc/sudoers.d/evolinux ]; then
sudoers="/etc/sudoers.d/evolinux"
else
sudoers="/etc/sudoers"
fi
# combine users from User_Alias and sudo group
users=$({ grep "^User_Alias *ADMIN" $sudoers | cut -d= -f2 | tr -d " "; grep "^sudo" /etc/group | cut -d: -f 4; } | tr "," "\n" | sort -u)
for user in $users; do
user_home=$(getent passwd "$user" | cut -d: -f6)
if [ -n "$user_home" ] && [ -d "$user_home" ]; then
if ! grep -qs "^trap.*sudo.*evomaintenance.sh" "${user_home}"/.*profile; then
failed "IS_EVOMAINTENANCEUSERS" "${user} doesn't have an evomaintenance trap"
test "${VERBOSE}" = 1 || break
fi
fi
done
}
check_evomaintenanceconf() {
f=/etc/evomaintenance.cf
if [ -e "$f" ]; then
perms=$(stat -c "%a" $f)
test "$perms" = "600" || failed "IS_EVOMAINTENANCECONF" "Wrong permissions on \`$f' ($perms instead of 600)"
{ grep "^export PGPASSWORD" $f | grep -qv "your-passwd" \
&& grep "^PGDB" $f | grep -qv "your-db" \
&& grep "^PGTABLE" $f | grep -qv "your-table" \
&& grep "^PGHOST" $f | grep -qv "your-pg-host" \
&& grep "^FROM" $f | grep -qv "jdoe@example.com" \
&& grep "^FULLFROM" $f | grep -qv "John Doe <jdoe@example.com>" \
&& grep "^URGENCYFROM" $f | grep -qv "mama.doe@example.com" \
&& grep "^URGENCYTEL" $f | grep -qv "06.00.00.00.00" \
&& grep "^REALM" $f | grep -qv "example.com"
} || failed "IS_EVOMAINTENANCECONF" "evomaintenance is not correctly configured"
else
failed "IS_EVOMAINTENANCECONF" "Configuration file \`$f' is missing"
fi
}
check_privatekeyworldreadable() {
# a simple globbing fails if directory is empty
if [ -n "$(ls -A /etc/ssl/private/)" ]; then
for f in /etc/ssl/private/*; do
perms=$(stat -L -c "%a" "$f")
if [ "${perms: -1}" != 0 ]; then
failed "IS_PRIVKEYWOLRDREADABLE" "$f is world-readable"
test "${VERBOSE}" = 1 || break
fi
done
fi
}
check_evobackup_incs() {
if is_installed bkctld; then
bkctld_cron_file=${bkctld_cron_file:-/etc/cron.d/bkctld}
if [ -f "${bkctld_cron_file}" ]; then
root_crontab=$(grep -v "^#" "${bkctld_cron_file}")
echo "${root_crontab}" | grep -q "bkctld inc" || failed "IS_EVOBACKUP_INCS" "\`bkctld inc' is missing in ${bkctld_cron_file}"
echo "${root_crontab}" | grep -qE "(check-incs.sh|bkctld check-incs)" || failed "IS_EVOBACKUP_INCS" "\`check-incs.sh' is missing in ${bkctld_cron_file}"
else
failed "IS_EVOBACKUP_INCS" "Crontab \`${bkctld_cron_file}' is missing"
fi
fi
}
check_osprober() {
if is_installed os-prober qemu-kvm; then
failed "IS_OSPROBER" \
"Removal of os-prober package is recommended as it can cause serious issue on KVM server"
fi
}
check_jessie_backports() {
jessieBackports=$(grep -hs "jessie-backports" /etc/apt/sources.list /etc/apt/sources.list.d/*)
if test -n "$jessieBackports"; then
if ! grep -q "archive.debian.org" <<< "$jessieBackports"; then
failed "IS_JESSIE_BACKPORTS" "You must use deb http://archive.debian.org/debian/ jessie-backports main"
fi
fi
}
check_apt_valid_until() {
aptvalidFile="/etc/apt/apt.conf.d/99no-check-valid-until"
aptvalidText="Acquire::Check-Valid-Until no;"
if grep -qs "archive.debian.org" /etc/apt/sources.list /etc/apt/sources.list.d/*; then
if ! grep -qs "$aptvalidText" /etc/apt/apt.conf.d/*; then
failed "IS_APT_VALID_UNTIL" \
"As you use archive.mirror.org you need ${aptvalidFile}: ${aptvalidText}"
fi
fi
}
check_chrooted_binary_uptodate() {
# list of processes to check
process_list="sshd"
for process_name in ${process_list}; do
# what is the binary path?
original_bin=$(command -v "${process_name}")
for pid in $(pgrep ${process_name}); do
process_bin=$(realpath "/proc/${pid}/exe")
# Is the process chrooted?
real_root=$(realpath "/proc/${pid}/root")
if [ "${real_root}" != "/" ]; then
chrooted_md5=$(md5sum "${process_bin}" | cut -f 1 -d ' ')
original_md5=$(md5sum "${original_bin}" | cut -f 1 -d ' ')
# compare md5 checksums
if [ "$original_md5" != "$chrooted_md5" ]; then
failed "IS_CHROOTED_BINARY_UPTODATE" "${process_bin} (${pid}) is different than ${original_bin}."
test "${VERBOSE}" = 1 || break
fi
fi
done
done
}
check_nginx_letsencrypt_uptodate() {
if [ -d /etc/nginx ]; then
snippets=$(find /etc/nginx -type f -name "letsencrypt.conf")
if [ -n "${snippets}" ]; then
while read -r snippet; do
if ! grep -qE "^\s*alias\s+/.+/\.well-known/acme-challenge" "${snippet}"; then
failed "IS_NGINX_LETSENCRYPT_UPTODATE" "Nginx snippet ${snippet} is not compatible with Nginx on Debian 8."
fi
done <<< "${snippets}"
fi
fi
}
check_lxc_container_resolv_conf() {
if is_installed lxc; then
container_list=$(lxc-ls)
current_resolvers=$(grep nameserver /etc/resolv.conf | sed 's/nameserver//g' )
for container in $container_list; do
if [ -f "/var/lib/lxc/${container}/rootfs/etc/resolv.conf" ]; then
while read -r resolver; do
if ! grep -qE "^nameserver\s+${resolver}" "/var/lib/lxc/${container}/rootfs/etc/resolv.conf"; then
failed "IS_LXC_CONTAINER_RESOLV_CONF" "resolv.conf miss-match beween host and container : missing nameserver ${resolver} in container ${container} resolv.conf"
fi
done <<< "${current_resolvers}"
else
failed "IS_LXC_CONTAINER_RESOLV_CONF" "resolv.conf missing in container ${container}"
fi
done
fi
}
download_versions() {
local file
file=${1:-}
## The file is supposed to list programs : each on a line, then its latest version number
## Examples:
# evoacme 21.06
# evomaintenance 0.6.4
versions_url="https://upgrades.evolix.org/versions-${DEBIAN_RELEASE}"
# fetch timeout, in seconds
timeout=10
if command -v curl > /dev/null; then
curl --max-time ${timeout} --fail --silent --output "${versions_file}" "${versions_url}"
elif command -v wget > /dev/null; then
wget --timeout=${timeout} --quiet "${versions_url}" -O "${versions_file}"
elif command -v GET; then
GET -t ${timeout}s "${versions_url}" > "${versions_file}"
else
failed "IS_CHECK_VERSIONS" "failed to find curl, wget or GET"
fi
test "$?" -eq 0 || failed "IS_CHECK_VERSIONS" "failed to download ${versions_url} to ${versions_file}"
}
get_command() {
local program
program=${1:-}
case "${program}" in
## Special cases where the program name is different than the command name
evocheck) echo "${0}" ;;
evomaintenance) command -v "evomaintenance.sh" ;;
listupgrade) command -v "evolistupgrade.sh" ;;
old-kernel-autoremoval) command -v "old-kernel-autoremoval.sh" ;;
mysql-queries-killer) command -v "mysql-queries-killer.sh" ;;
minifirewall) echo "/etc/init.d/minifirewall" ;;
## General case, where the program name is the same as the command name
*) command -v "${program}" ;;
esac
}
get_version() {
local program
local command
program=${1:-}
command=${2:-}
case "${program}" in
## Special case if `command --version => 'command` is not the standard way to get the version
# my_command)
# /path/to/my_command --get-version
# ;;
add-vm)
grep '^VERSION=' "${command}" | head -1 | cut -d '=' -f 2
;;
minifirewall)
${command} version | head -1 | cut -d ' ' -f 3
;;
## Let's try the --version flag before falling back to grep for the constant
kvmstats)
if ${command} --version > /dev/null 2> /dev/null; then
${command} --version 2> /dev/null | head -1 | cut -d ' ' -f 3
else
grep '^VERSION=' "${command}" | head -1 | cut -d '=' -f 2
fi
;;
## General case to get the version
*) ${command} --version 2> /dev/null | head -1 | cut -d ' ' -f 3 ;;
esac
}
check_version() {
local program
local expected_version
program=${1:-}
expected_version=${2:-}
command=$(get_command "${program}")
if [ -n "${command}" ]; then
# shellcheck disable=SC2086
actual_version=$(get_version "${program}" "${command}")
# printf "program:%s expected:%s actual:%s\n" "${program}" "${expected_version}" "${actual_version}"
if [ -z "${actual_version}" ]; then
failed "IS_CHECK_VERSIONS" "failed to lookup actual version of ${program}"
elif dpkg --compare-versions "${actual_version}" lt "${expected_version}"; then
failed "IS_CHECK_VERSIONS" "${program} version ${actual_version} is older than expected version ${expected_version}"
elif dpkg --compare-versions "${actual_version}" gt "${expected_version}"; then
failed "IS_CHECK_VERSIONS" "${program} version ${actual_version} is newer than expected version ${expected_version}, you should update your index."
else
: # Version check OK
fi
fi
}
add_to_path() {
local new_path
new_path=${1:-}
echo "$PATH" | grep -qF "${new_path}" || export PATH="${PATH}:${new_path}"
}
check_versions() {
versions_file=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.versions.XXXXX")
files_to_cleanup="${files_to_cleanup} ${versions_file}"
download_versions "${versions_file}"
add_to_path "/usr/share/scripts"
grep -v '^ *#' < "${versions_file}" | while IFS= read -r line; do
local program
local version
program=$(echo "${line}" | cut -d ' ' -f 1)
version=$(echo "${line}" | cut -d ' ' -f 2)
if [ -n "${program}" ]; then
if [ -n "${version}" ]; then
check_version "${program}" "${version}"
else
failed "IS_CHECK_VERSIONS" "failed to lookup expected version for ${program}"
fi
fi
done
}
main() {
# Default return code : 0 = no error
RC=0
# Detect operating system name, version and release
detect_os
main_output_file=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.main.XXXXX")
files_to_cleanup="${files_to_cleanup} ${main_output_file}"
test "${IS_TMP_1777:=1}" = 1 && check_tmp_1777
test "${IS_ROOT_0700:=1}" = 1 && check_root_0700
test "${IS_USRSHARESCRIPTS:=1}" = 1 && check_usrsharescripts
test "${IS_SSHPERMITROOTNO:=1}" = 1 && check_sshpermitrootno
test "${IS_EVOMAINTENANCEUSERS:=1}" = 1 && check_evomaintenanceusers
# Verification de la configuration d'evomaintenance
test "${IS_EVOMAINTENANCECONF:=1}" = 1 && check_evomaintenanceconf
test "${IS_PRIVKEYWOLRDREADABLE:=1}" = 1 && check_privatekeyworldreadable
test "${IS_LSBRELEASE:=1}" = 1 && check_lsbrelease
test "${IS_NRPEPOSTFIX:=1}" = 1 && check_nrpepostfix
test "${IS_CUSTOMSUDOERS:=1}" = 1 && check_customsudoers
test "${IS_VARTMPFS:=1}" = 1 && check_vartmpfs
test "${IS_SERVEURBASE:=1}" = 1 && check_serveurbase
test "${IS_LOGROTATECONF:=1}" = 1 && check_logrotateconf
test "${IS_SYSLOGCONF:=1}" = 1 && check_syslogconf
test "${IS_DEBIANSECURITY:=1}" = 1 && check_debiansecurity
test "${IS_APTITUDE:=1}" = 1 && check_aptitude
test "${IS_APTGETBAK:=1}" = 1 && check_aptgetbak
test "${IS_USRRO:=1}" = 1 && check_usrro
test "${IS_TMPNOEXEC:=1}" = 1 && check_tmpnoexec
test "${IS_MOUNT_FSTAB:=1}" = 1 && check_mountfstab
test "${IS_LISTCHANGESCONF:=1}" = 1 && check_listchangesconf
test "${IS_CUSTOMCRONTAB:=1}" = 1 && check_customcrontab
test "${IS_SSHALLOWUSERS:=1}" = 1 && check_sshallowusers
test "${IS_DISKPERF:=0}" = 1 && check_diskperf
test "${IS_TMOUTPROFILE:=1}" = 1 && check_tmoutprofile
test "${IS_ALERT5BOOT:=1}" = 1 && check_alert5boot
test "${IS_ALERT5MINIFW:=1}" = 1 && check_alert5minifw
test "${IS_ALERT5MINIFW:=1}" = 1 && test "${IS_MINIFW:=1}" = 1 && check_minifw
test "${IS_NRPEPERMS:=1}" = 1 && check_nrpeperms
test "${IS_MINIFWPERMS:=1}" = 1 && check_minifwperms
test "${IS_NRPEDISKS:=0}" = 1 && check_nrpedisks
test "${IS_NRPEPID:=1}" = 1 && check_nrpepid
test "${IS_GRSECPROCS:=1}" = 1 && check_grsecprocs
test "${IS_APACHEMUNIN:=1}" = 1 && check_apachemunin
test "${IS_MYSQLUTILS:=1}" = 1 && check_mysqlutils
test "${IS_RAIDSOFT:=1}" = 1 && check_raidsoft
test "${IS_AWSTATSLOGFORMAT:=1}" = 1 && check_awstatslogformat
test "${IS_MUNINLOGROTATE:=1}" = 1 && check_muninlogrotate
test "${IS_SQUID:=1}" = 1 && check_squid
test "${IS_EVOMAINTENANCE_FW:=1}" = 1 && check_evomaintenance_fw
test "${IS_MODDEFLATE:=1}" = 1 && check_moddeflate
test "${IS_LOG2MAILRUNNING:=1}" = 1 && check_log2mailrunning
test "${IS_LOG2MAILAPACHE:=1}" = 1 && check_log2mailapache
test "${IS_LOG2MAILMYSQL:=1}" = 1 && check_log2mailmysql
test "${IS_LOG2MAILSQUID:=1}" = 1 && check_log2mailsquid
test "${IS_BINDCHROOT:=1}" = 1 && check_bindchroot
test "${IS_NETWORK_INTERFACES:=1}" = 1 && check_network_interfaces
test "${IS_AUTOIF:=1}" = 1 && check_autoif
test "${IS_INTERFACESGW:=1}" = 1 && check_interfacesgw
test "${IS_EVOBACKUP:=1}" = 1 && check_evobackup
test "${IS_EVOBACKUP_EXCLUDE_MOUNT:=1}" = 1 && check_evobackup_exclude_mount
test "${IS_USERLOGROTATE:=1}" = 1 && check_userlogrotate
test "${IS_APACHECTL:=1}" = 1 && check_apachectl
test "${IS_APACHESYMLINK:=1}" = 1 && check_apachesymlink
test "${IS_APACHEIPINALLOW:=1}" = 1 && check_apacheipinallow
test "${IS_MUNINAPACHECONF:=1}" = 1 && check_muninapacheconf
test "${IS_PHPMYADMINAPACHECONF:=1}" = 1 && check_phpmyadminapacheconf
test "${IS_KERNELUPTODATE:=1}" = 1 && check_kerneluptodate
test "${IS_UPTIME:=1}" = 1 && check_uptime
test "${IS_MUNINRUNNING:=1}" = 1 && check_muninrunning
test "${IS_BACKUPUPTODATE:=1}" = 1 && check_backupuptodate
test "${IS_ETCGIT:=1}" = 1 && check_etcgit
test "${IS_GITPERMS:=1}" = 1 && check_gitperms
test "${IS_NOTUPGRADED:=1}" = 1 && check_notupgraded
test "${IS_TUNE2FS_M5:=1}" = 1 && check_tune2fs_m5
test "${IS_BROADCOMFIRMWARE:=1}" = 1 && check_broadcomfirmware
test "${IS_HARDWARERAIDTOOL:=1}" = 1 && check_hardwareraidtool
test "${IS_LISTUPGRADE:=1}" = 1 && check_listupgrade
test "${IS_SQL_BACKUP:=1}" = 1 && check_sql_backup
test "${IS_POSTGRES_BACKUP:=1}" = 1 && check_postgres_backup
test "${IS_MONGO_BACKUP:=1}" = 1 && check_mongo_backup
test "${IS_LDAP_BACKUP:=1}" = 1 && check_ldap_backup
test "${IS_REDIS_BACKUP:=1}" = 1 && check_redis_backup
test "${IS_ELASTIC_BACKUP:=1}" = 1 && check_elastic_backup
test "${IS_DUPLICATE_FS_LABEL:=1}" = 1 && check_duplicate_fs_label
test "${IS_EVOLIX_USER:=1}" = 1 && check_evolix_user
test "${IS_EVOACME_CRON:=1}" = 1 && check_evoacme_cron
test "${IS_EVOACME_LIVELINKS:=1}" = 1 && check_evoacme_livelinks
test "${IS_APACHE_CONFENABLED:=1}" = 1 && check_apache_confenabled
test "${IS_MELTDOWN_SPECTRE:=1}" = 1 && check_meltdown_spectre
test "${IS_OLD_HOME_DIR:=0}" = 1 && check_old_home_dir
test "${IS_EVOBACKUP_INCS:=1}" = 1 && check_evobackup_incs
test "${IS_OSPROBER:=1}" = 1 && check_osprober
test "${IS_JESSIE_BACKPORTS:=1}" = 1 && check_jessie_backports
test "${IS_APT_VALID_UNTIL:=1}" = 1 && check_apt_valid_until
test "${IS_CHROOTED_BINARY_UPTODATE:=1}" = 1 && check_chrooted_binary_uptodate
test "${IS_NGINX_LETSENCRYPT_UPTODATE:=1}" = 1 && check_nginx_letsencrypt_uptodate
test "${IS_LXC_CONTAINER_RESOLV_CONF:=1}" = 1 && check_lxc_container_resolv_conf
test "${IS_CHECK_VERSIONS:=1}" = 1 && check_versions
if [ -f "${main_output_file}" ]; then
lines_found=$(wc -l < "${main_output_file}")
# shellcheck disable=SC2086
if [ ${lines_found} -gt 0 ]; then
cat "${main_output_file}" 2>&1
fi
fi
exit ${RC}
}
cleanup_temp_files() {
# shellcheck disable=SC2086
rm -f ${files_to_cleanup}
}
PROGNAME=$(basename "$0")
# shellcheck disable=SC2034
readonly PROGNAME
# shellcheck disable=SC2124
ARGS=$@
readonly ARGS
# Disable LANG*
export LANG=C
export LANGUAGE=C
files_to_cleanup=""
# shellcheck disable=SC2064
trap cleanup_temp_files 0
# Source configuration file
# shellcheck disable=SC1091
test -f /etc/evocheck.cf && . /etc/evocheck.cf
# Parse options
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
while :; do
case $1 in
-h|-\?|--help)
show_help
exit 0
;;
--version)
show_version
exit 0
;;
--cron)
IS_KERNELUPTODATE=0
IS_UPTIME=0
IS_MELTDOWN_SPECTRE=0
IS_CHECK_VERSIONS=0
IS_NETWORKING_SERVICE=0
;;
-v|--verbose)
VERBOSE=1
;;
-q|--quiet)
QUIET=1
VERBOSE=0
;;
--)
# End of all options.
shift
break
;;
-?*|[[:alnum:]]*)
# ignore unknown options
if [ "${QUIET}" != 1 ]; then
printf 'WARN: Unknown option (ignored): %s\n' "$1" >&2
fi
;;
*)
# Default case: If no more options then break out of the loop.
break
;;
esac
shift
done
# shellcheck disable=SC2086
main ${ARGS}

View File

@ -4,7 +4,9 @@
# Script to verify compliance of a Linux (Debian) server
# powered by Evolix
VERSION="22.09"
#set -x
VERSION="24.01"
readonly VERSION
# base functions
@ -52,39 +54,29 @@ detect_os() {
LSB_RELEASE_BIN=$(command -v lsb_release)
if [ -e /etc/debian_version ]; then
DEBIAN_VERSION=$(cut -d "." -f 1 < /etc/debian_version)
DEBIAN_MAIN_VERSION=$(cut -d "." -f 1 < /etc/debian_version)
if [ "${DEBIAN_MAIN_VERSION}" -lt "9" ]; then
echo "Debian ${DEBIAN_MAIN_VERSION} is incompatible with this version of evocheck." >&2
echo "This version is built for Debian 9 and later." >&2
exit
fi
if [ -x "${LSB_RELEASE_BIN}" ]; then
DEBIAN_RELEASE=$(${LSB_RELEASE_BIN} --codename --short)
else
case ${DEBIAN_VERSION} in
5) DEBIAN_RELEASE="lenny";;
6) DEBIAN_RELEASE="squeeze";;
7) DEBIAN_RELEASE="wheezy";;
8) DEBIAN_RELEASE="jessie";;
case ${DEBIAN_MAIN_VERSION} in
9) DEBIAN_RELEASE="stretch";;
10) DEBIAN_RELEASE="buster";;
11) DEBIAN_RELEASE="bullseye";;
12) DEBIAN_RELEASE="bookworm";;
13) DEBIAN_RELEASE="trixie";;
14) DEBIAN_RELEASE="forky";;
esac
fi
fi
}
is_debian() {
test -n "${DEBIAN_RELEASE}"
}
is_debian_lenny() {
test "${DEBIAN_RELEASE}" = "lenny"
}
is_debian_squeeze() {
test "${DEBIAN_RELEASE}" = "squeeze"
}
is_debian_wheezy() {
test "${DEBIAN_RELEASE}" = "wheezy"
}
is_debian_jessie() {
test "${DEBIAN_RELEASE}" = "jessie"
}
is_debian_stretch() {
test "${DEBIAN_RELEASE}" = "stretch"
}
@ -97,11 +89,11 @@ is_debian_bullseye() {
is_debian_bookworm() {
test "${DEBIAN_RELEASE}" = "bookworm"
}
debian_release() {
printf "%s" "${DEBIAN_RELEASE}"
is_debian_trixie() {
test "${DEBIAN_RELEASE}" = "trixie"
}
debian_version() {
printf "%s" "${DEBIAN_VERSION}"
is_debian_forky() {
test "${DEBIAN_RELEASE}" = "forky"
}
is_pack_web(){
@ -115,19 +107,20 @@ is_installed(){
dpkg -l "$pkg" 2> /dev/null | grep -q -E '^(i|h)i' || return 1
done
}
minifirewall_file() {
case ${DEBIAN_RELEASE} in
lenny) echo "/etc/firewall.rc" ;;
squeeze) echo "/etc/firewall.rc" ;;
wheezy) echo "/etc/firewall.rc" ;;
jessie) echo "/etc/default/minifirewall" ;;
stretch) echo "/etc/default/minifirewall" ;;
*) echo "/etc/default/minifirewall" ;;
esac
}
# logging
log() {
date=$(/bin/date +"${DATE_FORMAT}")
if [ "${1}" != '' ]; then
printf "[%s] %s: %s\\n" "$date" "${PROGNAME}" "${1}" >> "${LOGFILE}"
else
while read line; do
printf "[%s] %s: %s\\n" "$date" "${PROGNAME}" "${line}" >> "${LOGFILE}"
done < /dev/stdin
fi
}
failed() {
check_name=$1
shift
@ -141,6 +134,9 @@ failed() {
printf "%s FAILED!\n" "${check_name}" >> "${main_output_file}"
fi
fi
# Always log verbose
log "${check_name} FAILED! ${check_comments}"
}
# check functions
@ -156,54 +152,31 @@ check_lsbrelease(){
fi
}
check_dpkgwarning() {
if is_debian_squeeze; then
if [ "$IS_USRRO" = 1 ] || [ "$IS_TMPNOEXEC" = 1 ]; then
count=$(grep -c -E -i "(Pre-Invoke ..echo Are you sure to have rw on|Post-Invoke ..echo Dont forget to mount -o remount)" /etc/apt/apt.conf)
test "$count" = 2 || failed "IS_DPKGWARNING" "Pre/Post-Invoke are missing."
fi
elif is_debian_wheezy; then
if [ "$IS_USRRO" = 1 ] || [ "$IS_TMPNOEXEC" = 1 ]; then
test -e /etc/apt/apt.conf.d/80evolinux \
|| failed "IS_DPKGWARNING" "/etc/apt/apt.conf.d/80evolinux is missing"
test -e /etc/apt/apt.conf \
&& failed "IS_DPKGWARNING" "/etc/apt/apt.conf is missing"
fi
elif is_debian_stretch || is_debian_buster || is_debian_bullseye; then
test -e /etc/apt/apt.conf.d/z-evolinux.conf \
|| failed "IS_DPKGWARNING" "/etc/apt/apt.conf.d/z-evolinux.conf is missing"
fi
}
check_umasksudoers(){
if is_debian_squeeze; then
grep -q "^Defaults.*umask=0077" /etc/sudoers \
|| failed "IS_UMASKSUDOERS" "sudoers must set umask to 0077"
# Check if localhost, localhost.localdomain and localhost.$mydomain are set in Postfix mydestination option.
check_postfix_mydestination() {
# shellcheck disable=SC2016
if ! grep mydestination /etc/postfix/main.cf | grep --quiet --extended-regexp 'localhost([[:blank:]]|$)'; then
failed "IS_POSTFIX_MYDESTINATION" "'localhost' is missing in Postfix mydestination option."
fi
if ! grep mydestination /etc/postfix/main.cf | grep --quiet --fixed-strings 'localhost.localdomain'; then
failed "IS_POSTFIX_MYDESTINATION" "'localhost.localdomain' is missing in Postfix mydestination option."
fi
if ! grep mydestination /etc/postfix/main.cf | grep --quiet --fixed-strings 'localhost.$mydomain'; then
failed "IS_POSTFIX_MYDESTINATION" "'localhost.\$mydomain' is missing in Postfix mydestination option."
fi
}
# Verifying check_mailq in Nagios NRPE config file. (Option "-M postfix" need to be set if the MTA is Postfix)
check_nrpepostfix() {
if is_installed postfix; then
if is_debian_squeeze; then
grep -q "^command.*check_mailq -M postfix" /etc/nagios/nrpe.cfg \
|| failed "IS_NRPEPOSTFIX" "NRPE \"check_mailq\" for postfix is missing"
else
{ test -e /etc/nagios/nrpe.cfg \
&& grep -qr "^command.*check_mailq -M postfix" /etc/nagios/nrpe.*;
} || failed "IS_NRPEPOSTFIX" "NRPE \"check_mailq\" for postfix is missing"
fi
fi
}
# Check if mod-security config file is present
check_modsecurity() {
if is_debian_squeeze; then
if is_installed libapache-mod-security; then
test -e /etc/apache2/conf.d/mod-security2.conf || failed "IS_MODSECURITY" "missing configuration file"
fi
elif is_debian_wheezy; then
if is_installed libapache2-modsecurity; then
test -e /etc/apache2/conf.d/mod-security2.conf || failed "IS_MODSECURITY" "missing configuration file"
fi
fi
}
check_customsudoers() {
grep -E -qr "umask=0077" /etc/sudoers* || failed "IS_CUSTOMSUDOERS" "missing umask=0077 in sudoers file"
}
@ -222,50 +195,91 @@ check_logrotateconf() {
test -e /etc/logrotate.d/zsyslog || failed "IS_LOGROTATECONF" "missing zsyslog in logrotate.d"
}
check_syslogconf() {
grep -q "^# Syslog for Pack Evolix serveur" /etc/*syslog.conf \
|| failed "IS_SYSLOGCONF" "syslog evolix config file missing"
# Test for modern servers
if [ ! -f /etc/rsyslog.d/10-evolinux-default.conf ]; then
# Fallback test for legacy servers
if ! grep --quiet --ignore-case "Syslog for Pack Evolix" /etc/*syslog*/*.conf; then
failed "IS_SYSLOGCONF" "Evolix syslog config is missing"
fi
fi
}
check_debiansecurity() {
if is_debian_bullseye; then
# https://www.debian.org/releases/bullseye/amd64/release-notes/ch-information.html#security-archive
# https://www.debian.org/security/
pattern="^deb ?(\[.*\])? ?http://security\.debian\.org/debian-security/? bullseye-security main"
elif is_debian_buster; then
pattern="^deb ?(\[.*\])? ?http://security\.debian\.org/debian-security/? buster/updates main"
elif is_debian_stretch; then
pattern="^deb ?(\[.*\])? ?http://security\.debian\.org/debian-security/? stretch/updates main"
else
pattern="^deb.*security"
fi
source_file="/etc/apt/sources.list"
grep -qE "${pattern}" "${source_file}" || failed "IS_DEBIANSECURITY" "missing debian security repository"
# Look for enabled "Debian-Security" sources from the "Debian" origin
apt-cache policy | grep "\bl=Debian-Security\b" | grep "\bo=Debian\b" | grep --quiet "\bc=main\b"
test $? -eq 0 || failed "IS_DEBIANSECURITY" "missing Debian-Security repository"
}
check_aptitudeonly() {
if is_debian_squeeze || is_debian_wheezy; then
test -e /usr/bin/apt-get && failed "IS_APTITUDEONLY" \
"only aptitude may be enabled on Debian <=7, apt-get should be disabled"
check_debiansecurity_lxc() {
if is_installed lxc; then
container_list=$(lxc-ls --active)
for container in $container_list; do
if [ -f /var/lib/lxc/${container}/rootfs/etc/debian_version ]; then
DEBIAN_LXC_VERSION=$(cut -d "." -f 1 < /var/lib/lxc/${container}/rootfs/etc/debian_version)
if [ $DEBIAN_LXC_VERSION -ge 9 ]; then
lxc-attach --name $container apt-cache policy | grep "\bl=Debian-Security\b" | grep "\bo=Debian\b" | grep --quiet "\bc=main\b"
test $? -eq 0 || failed "IS_DEBIANSECURITY_LXC" "missing Debian-Security repository in container ${container}"
fi
fi
done
fi
}
check_backports_version() {
# Look for enabled "Debian Backports" sources from the "Debian" origin
apt-cache policy | grep "\bl=Debian Backports\b" | grep "\bo=Debian\b" | grep --quiet "\bc=main\b"
test $? -eq 1 || ( \
apt-cache policy | grep "\bl=Debian Backports\b" | grep --quiet "\bn=${DEBIAN_RELEASE}-backports\b" && \
test $? -eq 0 || failed "IS_BACKPORTS_VERSION" "Debian Backports enabled for another release than ${DEBIAN_RELEASE}" )
}
check_oldpub() {
# Look for enabled pub.evolix.net sources (supersed by pub.evolix.org since Stretch)
apt-cache policy | grep --quiet pub.evolix.net
test $? -eq 1 || failed "IS_OLDPUB" "Old pub.evolix.net repository is still enabled"
}
check_oldpub_lxc() {
# Look for enabled pub.evolix.net sources (supersed by pub.evolix.org since Buster as Sury safeguard)
if is_installed lxc; then
container_list=$(lxc-ls --active)
for container in $container_list; do
APT_CACHE_BIN=$(lxc-attach --name $container -- bash -c "command -v apt-cache")
if [ -x "${APT_CACHE_BIN}" ]; then
lxc-attach --name $container apt-cache policy | grep --quiet pub.evolix.net
test $? -eq 1 || failed "IS_OLDPUB_LXC" "Old pub.evolix.net repository is still enabled in container ${container}"
fi
done
fi
}
check_newpub() {
# Look for enabled pub.evolix.org sources
apt-cache policy | grep "\bl=Evolix\b" | grep --quiet -v php
test $? -eq 0 || failed "IS_NEWPUB" "New pub.evolix.org repository is missing"
}
check_sury() {
# Look for enabled packages.sury.org sources
apt-cache policy | grep --quiet packages.sury.org
if [ $? -eq 0 ]; then
apt-cache policy | grep "\bl=Evolix\b" | grep php --quiet
test $? -eq 0 || failed "IS_SURY" "packages.sury.org is present but our safeguard pub.evolix.org repository is missing"
fi
}
check_sury_lxc() {
if is_installed lxc; then
container_list=$(lxc-ls --active)
for container in $container_list; do
APT_CACHE_BIN=$(lxc-attach --name $container -- bash -c "command -v apt-cache")
if [ -x "${APT_CACHE_BIN}" ]; then
lxc-attach --name $container apt-cache policy | grep --quiet packages.sury.org
if [ $? -eq 0 ]; then
lxc-attach --name $container apt-cache policy | grep "\bl=Evolix\b" | grep php --quiet
test $? -eq 0 || failed "IS_SURY_LXC" "packages.sury.org is present but our safeguard pub.evolix.org repository is missing in container ${container}"
fi
fi
done
fi
}
check_aptitude() {
if is_debian_jessie || is_debian_stretch || is_debian_buster || is_debian_bullseye; then
test -e /usr/bin/aptitude && failed "IS_APTITUDE" "aptitude may not be installed on Debian >=8"
fi
}
check_aptgetbak() {
if is_debian_jessie || is_debian_stretch || is_debian_buster || is_debian_bullseye; then
test -e /usr/bin/apt-get.bak && failed "IS_APTGETBAK" "prohibit the installation of apt-get.bak with dpkg-divert(1)"
fi
}
check_apticron() {
status="OK"
test -e /etc/cron.d/apticron || status="fail"
test -e /etc/cron.daily/apticron && status="fail"
test "$status" = "fail" || test -e /usr/bin/apt-get.bak || status="fail"
if is_debian_squeeze || is_debian_wheezy; then
test "$status" = "fail" && failed "IS_APTICRON" "apticron must be in cron.d not cron.daily"
fi
}
check_usrro() {
grep /usr /etc/fstab | grep -qE "\bro\b" || failed "IS_USRRO" "missing ro directive on fstab for /usr"
@ -290,28 +304,34 @@ check_mountfstab() {
fi
}
check_listchangesconf() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
if is_installed apt-listchanges; then
failed "IS_LISTCHANGESCONF" "apt-listchanges must not be installed on Debian >=9"
fi
else
if [ -e "/etc/apt/listchanges.conf" ]; then
lines=$(grep -cE "(which=both|confirm=1)" /etc/apt/listchanges.conf)
if [ "$lines" != 2 ]; then
failed "IS_LISTCHANGESCONF" "apt-listchanges config is incorrect"
fi
else
failed "IS_LISTCHANGESCONF" "apt-listchanges config is missing"
fi
fi
}
check_customcrontab() {
found_lines=$(grep -c -E "^(17 \*|25 6|47 6|52 6)" /etc/crontab)
test "$found_lines" = 4 && failed "IS_CUSTOMCRONTAB" "missing custom field in crontab"
}
check_sshallowusers() {
grep -E -qir "(AllowUsers|AllowGroups)" /etc/ssh/sshd_config /etc/ssh/sshd_config.d \
if is_debian_bookworm; then
if [ -d /etc/ssh/sshd_config.d/ ]; then
# AllowUsers or AllowGroups should be in /etc/ssh/sshd_config.d/
grep -E -qir "(AllowUsers|AllowGroups)" /etc/ssh/sshd_config.d/ \
|| failed "IS_SSHALLOWUSERS" "missing AllowUsers or AllowGroups directive in sshd_config.d/*"
fi
# AllowUsers or AllowGroups should not be in /etc/ssh/sshd_config
grep -E -qi "(AllowUsers|AllowGroups)" /etc/ssh/sshd_config \
&& failed "IS_SSHALLOWUSERS" "AllowUsers or AllowGroups directive present in sshd_config"
else
# AllowUsers or AllowGroups should be in /etc/ssh/sshd_config or /etc/ssh/sshd_config.d/
if [ -d /etc/ssh/sshd_config.d/ ]; then
grep -E -qir "(AllowUsers|AllowGroups)" /etc/ssh/sshd_config /etc/ssh/sshd_config.d/ \
|| failed "IS_SSHALLOWUSERS" "missing AllowUsers or AllowGroups directive in sshd_config"
else
grep -E -qi "(AllowUsers|AllowGroups)" /etc/ssh/sshd_config \
|| failed "IS_SSHALLOWUSERS" "missing AllowUsers or AllowGroups directive in sshd_config"
fi
fi
}
check_diskperf() {
perfFile="/root/disk-perf.txt"
@ -321,14 +341,7 @@ check_tmoutprofile() {
grep -sq "TMOUT=" /etc/profile /etc/profile.d/evolinux.sh || failed "IS_TMOUTPROFILE" "TMOUT is not set"
}
check_alert5boot() {
if is_debian_buster || is_debian_bullseye; then
grep -qs "^date" /usr/share/scripts/alert5.sh || failed "IS_ALERT5BOOT" "boot mail is not sent by alert5 init script"
if [ -f /etc/systemd/system/alert5.service ]; then
systemctl is-enabled alert5.service -q || failed "IS_ALERT5BOOT" "alert5 unit is not enabled"
else
failed "IS_ALERT5BOOT" "alert5 unit file is missing"
fi
else
if is_debian_stretch; then
if [ -n "$(find /etc/rc2.d/ -name 'S*alert5')" ]; then
grep -q "^date" /etc/rc2.d/S*alert5 || failed "IS_ALERT5BOOT" "boot mail is not sent by alert5 init script"
elif [ -n "$(find /etc/init.d/ -name 'alert5')" ]; then
@ -336,13 +349,17 @@ check_alert5boot() {
else
failed "IS_ALERT5BOOT" "alert5 init script is missing"
fi
else
grep -qs "^date" /usr/share/scripts/alert5.sh || failed "IS_ALERT5BOOT" "boot mail is not sent by alert5 init script"
if [ -f /etc/systemd/system/alert5.service ]; then
systemctl is-enabled alert5.service -q || failed "IS_ALERT5BOOT" "alert5 unit is not enabled"
else
failed "IS_ALERT5BOOT" "alert5 unit file is missing"
fi
fi
}
check_alert5minifw() {
if is_debian_buster || is_debian_bullseye; then
grep -qs "^/etc/init.d/minifirewall" /usr/share/scripts/alert5.sh \
|| failed "IS_ALERT5MINIFW" "Minifirewall is not started by alert5 script or script is missing"
else
if is_debian_stretch; then
if [ -n "$(find /etc/rc2.d/ -name 'S*alert5')" ]; then
grep -q "^/etc/init.d/minifirewall" /etc/rc2.d/S*alert5 \
|| failed "IS_ALERT5MINIFW" "Minifirewall is not started by alert5 init script"
@ -352,16 +369,28 @@ check_alert5minifw() {
else
failed "IS_ALERT5MINIFW" "alert5 init script is missing"
fi
else
grep -qs "^/etc/init.d/minifirewall" /usr/share/scripts/alert5.sh \
|| failed "IS_ALERT5MINIFW" "Minifirewall is not started by alert5 script or script is missing"
fi
}
check_minifw() {
/sbin/iptables -L -n | grep -q -E "^ACCEPT\s*all\s*--\s*31\.170\.8\.4\s*0\.0\.0\.0/0\s*$" \
|| failed "IS_MINIFW" "minifirewall seems not started"
{
if [ -f /etc/systemd/system/minifirewall.service ]; then
systemctl is-active minifirewall > /dev/null 2>&1
else
if test -x /usr/share/scripts/minifirewall_status; then
/usr/share/scripts/minifirewall_status > /dev/null 2>&1
else
/sbin/iptables -L -n 2> /dev/null | grep -q -E "^(DROP\s+(udp|17)|ACCEPT\s+(icmp|1))\s+--\s+0\.0\.0\.0\/0\s+0\.0\.0\.0\/0\s*$"
fi
fi
} || failed "IS_MINIFW" "minifirewall seems not started"
}
check_minifw_includes() {
if is_debian_bullseye; then
if grep -q -e '/sbin/iptables' -e '/sbin/ip6tables' "${MINIFW_FILE}"; then
failed "IS_MINIFWINCLUDES" "minifirewall has direct iptables invocations in ${MINIFW_FILE} that should go in /etc/minifirewall.d/"
if { ! is_debian_stretch && ! is_debian_buster ; }; then
if grep -q -e '/sbin/iptables' -e '/sbin/ip6tables' "/etc/default/minifirewall"; then
failed "IS_MINIFWINCLUDES" "minifirewall has direct iptables invocations in /etc/default/minifirewall that should go in /etc/minifirewall.d/"
fi
fi
}
@ -374,10 +403,10 @@ check_nrpeperms() {
fi
}
check_minifwperms() {
if [ -f "$MINIFW_FILE" ]; then
actual=$(stat --format "%a" "$MINIFW_FILE")
if [ -f "/etc/default/minifirewall" ]; then
actual=$(stat --format "%a" "/etc/default/minifirewall")
expected="600"
test "$expected" = "$actual" || failed "IS_MINIFWPERMS" "${MINIFW_FILE} must be ${expected}"
test "$expected" = "$actual" || failed "IS_MINIFWPERMS" "/etc/default/minifirewall must be ${expected}"
fi
}
check_nrpedisks() {
@ -386,14 +415,14 @@ check_nrpedisks() {
test "$NRPEDISKS" = "$DFDISKS" || failed "IS_NRPEDISKS" "there must be $DFDISKS check_disk in nrpe.cfg"
}
check_nrpepid() {
if is_debian_bullseye; then
{ test -e /etc/nagios/nrpe.cfg \
&& grep -q "^pid_file=/run/nagios/nrpe.pid" /etc/nagios/nrpe.cfg;
} || failed "IS_NRPEPID" "missing or wrong pid_file directive in nrpe.cfg"
elif ! is_debian_squeeze; then
if { is_debian_stretch || is_debian_buster ; }; then
{ test -e /etc/nagios/nrpe.cfg \
&& grep -q "^pid_file=/var/run/nagios/nrpe.pid" /etc/nagios/nrpe.cfg;
} || failed "IS_NRPEPID" "missing or wrong pid_file directive in nrpe.cfg"
else
{ test -e /etc/nagios/nrpe.cfg \
&& grep -q "^pid_file=/run/nagios/nrpe.pid" /etc/nagios/nrpe.cfg;
} || failed "IS_NRPEPID" "missing or wrong pid_file directive in nrpe.cfg"
fi
}
check_grsecprocs() {
@ -405,20 +434,11 @@ check_grsecprocs() {
}
check_apachemunin() {
if test -e /etc/apache2/apache2.conf; then
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
{ test -h /etc/apache2/mods-enabled/status.load \
&& test -h /etc/munin/plugins/apache_accesses \
&& test -h /etc/munin/plugins/apache_processes \
&& test -h /etc/munin/plugins/apache_volume;
} || failed "IS_APACHEMUNIN" "missing munin plugins for Apache"
else
pattern="/server-status-[[:alnum:]]{4,}"
{ grep -r -q -s -E "^env.url.*${pattern}" /etc/munin/plugin-conf.d \
&& { grep -q -s -E "${pattern}" /etc/apache2/apache2.conf \
|| grep -q -s -E "${pattern}" /etc/apache2/mods-enabled/status.conf;
};
} || failed "IS_APACHEMUNIN" "server status is not properly configured"
fi
fi
}
# Verification mytop + Munin si MySQL
@ -426,7 +446,7 @@ check_mysqlutils() {
MYSQL_ADMIN=${MYSQL_ADMIN:-mysqladmin}
if is_installed mysql-server; then
# With Debian 11 and later, root can connect to MariaDB with the socket
if is_debian_wheezy || is_debian_jessie || is_debian_stretch || is_debian_buster; then
if is_debian_stretch || is_debian_buster; then
# You can configure MYSQL_ADMIN in evocheck.cf
if ! grep -qs "^user *= *${MYSQL_ADMIN}" /root/.my.cnf; then
failed "IS_MYSQLUTILS" "${MYSQL_ADMIN} missing in /root/.my.cnf"
@ -467,27 +487,23 @@ check_muninlogrotate() {
}
# Verification de l'activation de Squid dans le cas d'un pack mail
check_squid() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
squidconffile="/etc/squid/evolinux-custom.conf"
else
squidconffile="/etc/squid*/squid.conf"
fi
if is_pack_web && (is_installed squid || is_installed squid3); then
host=$(hostname -i)
# shellcheck disable=SC2086
http_port=$(grep -E "^http_port\s+[0-9]+" $squidconffile | awk '{ print $2 }')
{ grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -m owner --uid-owner proxy -j ACCEPT" "$MINIFW_FILE" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -d $host -j ACCEPT" "$MINIFW_FILE" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -d 127.0.0.(1|0/8) -j ACCEPT" "$MINIFW_FILE" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port.* $http_port" "$MINIFW_FILE";
} || grep -qE "^PROXY='?on'?" "$MINIFW_FILE" \
{ grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -m owner --uid-owner proxy -j ACCEPT" "/etc/default/minifirewall" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -d $host -j ACCEPT" "/etc/default/minifirewall" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -d 127.0.0.(1|0/8) -j ACCEPT" "/etc/default/minifirewall" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port.* $http_port" "/etc/default/minifirewall";
} || grep -qE "^PROXY='?on'?" "/etc/default/minifirewall" \
|| failed "IS_SQUID" "missing squid rules in minifirewall"
fi
}
check_evomaintenance_fw() {
if [ -f "$MINIFW_FILE" ]; then
if [ -f "/etc/default/minifirewall" ]; then
hook_db=$(grep -E '^\s*HOOK_DB' /etc/evomaintenance.cf | tr -d ' ' | cut -d= -f2)
rulesNumber=$(grep -c "/sbin/iptables -A INPUT -p tcp --sport 5432 --dport 1024:65535 -s .* -m state --state ESTABLISHED,RELATED -j ACCEPT" "$MINIFW_FILE")
rulesNumber=$(grep -c "/sbin/iptables -A INPUT -p tcp --sport 5432 --dport 1024:65535 -s .* -m state --state ESTABLISHED,RELATED -j ACCEPT" "/etc/default/minifirewall")
if [ "$hook_db" = "1" ] && [ "$rulesNumber" -lt 2 ]; then
failed "IS_EVOMAINTENANCE_FW" "HOOK_DB is enabled but missing evomaintenance rules in minifirewall"
fi
@ -510,11 +526,7 @@ check_log2mailrunning() {
fi
}
check_log2mailapache() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
conf=/etc/log2mail/config/apache
else
conf=/etc/log2mail/config/default
fi
if is_pack_web && is_installed log2mail; then
grep -s -q "^file = /var/log/apache2/error.log" $conf \
|| failed "IS_LOG2MAILAPACHE" "missing log2mail directive for apache"
@ -536,7 +548,11 @@ check_log2mailsquid() {
check_bindchroot() {
if is_installed bind9; then
if netstat -utpln | grep "/named" | grep :53 | grep -qvE "(127.0.0.1|::1)"; then
if grep -q '^OPTIONS=".*-t' /etc/default/bind9 && grep -q '^OPTIONS=".*-u' /etc/default/bind9; then
default_conf=/etc/default/named
if is_debian_buster || is_debian_stretch; then
default_conf=/etc/default/bind9
fi
if grep -q '^OPTIONS=".*-t' "${default_conf}" && grep -q '^OPTIONS=".*-u' "${default_conf}"; then
md5_original=$(md5sum /usr/sbin/named | cut -f 1 -d ' ')
md5_chrooted=$(md5sum /var/chroot-bind/usr/sbin/named | cut -f 1 -d ' ')
if [ "$md5_original" != "$md5_chrooted" ]; then
@ -548,17 +564,6 @@ check_bindchroot() {
fi
fi
}
# Verification de la présence du depot volatile
check_repvolatile() {
if is_debian_lenny; then
grep -qE "^deb http://volatile.debian.org/debian-volatile" /etc/apt/sources.list \
|| failed "IS_REPVOLATILE" "missing debian-volatile repository"
fi
if is_debian_squeeze; then
grep -qE "^deb.*squeeze-updates" /etc/apt/sources.list \
|| failed "IS_REPVOLATILE" "missing squeeze-updates repository"
fi
}
# /etc/network/interfaces should be present, we don't manage systemd-network yet
check_network_interfaces() {
if ! test -f /etc/network/interfaces; then
@ -569,11 +574,7 @@ check_network_interfaces() {
}
# Verify if all if are in auto
check_autoif() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
interfaces=$(/sbin/ip address show up | grep "^[0-9]*:" | grep -E -v "(lo|vnet|docker|veth|tun|tap|macvtap|vrrp|lxcbr|wg)" | cut -d " " -f 2 | tr -d : | cut -d@ -f1 | tr "\n" " ")
else
interfaces=$(/sbin/ifconfig -s | tail -n +2 | grep -E -v "^(lo|vnet|docker|veth|tun|tap|macvtap|vrrp)" | cut -d " " -f 1 |tr "\n" " ")
fi
for interface in $interfaces; do
if grep -Rq "^iface $interface" /etc/network/interfaces* && ! grep -Rq "^auto $interface" /etc/network/interfaces*; then
failed "IS_AUTOIF" "Network interface \`${interface}' is statically defined but not set to auto"
@ -590,31 +591,37 @@ check_interfacesgw() {
}
# Verification de létat du service networking
check_networking_service() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
if systemctl is-enabled networking.service > /dev/null; then
if ! systemctl is-active networking.service > /dev/null; then
failed "IS_NETWORKING_SERVICE" "networking.service is not active"
fi
fi
fi
}
# Verification de la mise en place d'evobackup
check_evobackup() {
evobackup_found=$(find /etc/cron* -name '*evobackup*' | wc -l)
test "$evobackup_found" -gt 0 || failed "IS_EVOBACKUP" "missing evobackup cron"
}
# Vérification de la mise en place de la purge pour fail2ban
check_purge_fail2ban() {
# Vérification de la mise en place d'un cron de purge de la base SQLite de Fail2ban
check_fail2ban_purge() {
if is_debian_stretch || is_debian_buster; then
if is_installed fail2ban; then
test -f /etc/cron.daily/fail2ban_dbpurge || failed "IS_FAIL2BAN_PURGE" "missing script fail2ban_dbpurge cron"
fi
fi
}
# Vérification qu'il ne reste pas des jails nommées ssh non renommées en sshd
check_ssh_fail2ban_jail_renamed() {
if is_installed fail2ban && [ -f /etc/fail2ban/jail.local ]; then
if grep --quiet --fixed-strings "[ssh]" /etc/fail2ban/jail.local; then
failed "IS_SSH_FAIL2BAN_JAIL_RENAMED" "Jail ssh must be renamed sshd in fail2ban >= 0.9."
fi
fi
}
# Vérification de l'exclusion des montages (NFS) dans les sauvegardes
check_evobackup_exclude_mount() {
excludes_file=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.evobackup_exclude_mount.XXXXX")
files_to_cleanup="${files_to_cleanup} ${excludes_file}"
excludes_file=$(mktemp --tmpdir "evocheck.evobackup_exclude_mount.XXXXX")
files_to_cleanup+=("${excludes_file}")
# shellcheck disable=SC2044
for evobackup_file in $(find /etc/cron* -name '*evobackup*' | grep -v -E ".disabled$"); do
@ -623,7 +630,12 @@ check_evobackup_exclude_mount() {
# If rsync is not limited by "one-file-system"
# then we verify that every mount is excluded
if ! grep -q -- "^\s*--one-file-system" "${evobackup_file}"; then
# old releases of evobackups don't have version
if grep -q "^VERSION=" "${evobackup_file}" && dpkg --compare-versions "$(sed -E -n 's/VERSION="(.*)"/\1/p' "${evobackup_file}")" ge 22.12 ; then
sed -En '/RSYNC_EXCLUDES="/,/"/ {s/(RSYNC_EXCLUDES=|")//g;p}' "${evobackup_file}" > "${excludes_file}"
else
grep -- "--exclude " "${evobackup_file}" | grep -E -o "\"[^\"]+\"" | tr -d '"' > "${excludes_file}"
fi
not_excluded=$(findmnt --type nfs,nfs4,fuse.sshfs, -o target --noheadings | grep -v -f "${excludes_file}")
for mount in ${not_excluded}; do
failed "IS_EVOBACKUP_EXCLUDE_MOUNT" "${mount} is not excluded from ${evobackup_file} backup script"
@ -674,30 +686,28 @@ check_apacheipinallow() {
}
# Check if default Apache configuration file for munin is absent (or empty or commented).
check_muninapacheconf() {
if is_debian_squeeze || is_debian_wheezy; then
muninconf="/etc/apache2/conf.d/munin"
else
muninconf="/etc/apache2/conf-available/munin.conf"
fi
if is_installed apache2; then
test -e $muninconf && grep -vEq "^( |\t)*#" "$muninconf" \
test -e $muninconf && grep --invert-match --extended-regexp --quiet "^( |\t)*#" "$muninconf" \
&& failed "IS_MUNINAPACHECONF" "default munin configuration may be commented or disabled"
fi
}
# Verification de la priorité du package samba si les backports sont utilisés
check_sambainpriority() {
if is_debian_lenny && is_pack_samba; then
if grep -qrE "^[^#].*backport" /etc/apt/sources.list{,.d}; then
priority=$(grep -E -A2 "^Package:.*samba" /etc/apt/preferences | grep -A1 "^Pin: release a=lenny-backports" | grep "^Pin-Priority:" | cut -f2 -d" ")
test "$priority" -gt 500 || failed "IS_SAMBAPINPRIORITY" "bad pinning priority for samba"
fi
# Check if default Apache configuration file for phpMyAdmin is absent (or empty or commented).
check_phpmyadminapacheconf() {
phpmyadminconf0="/etc/apache2/conf-available/phpmyadmin.conf"
phpmyadminconf1="/etc/apache2/conf-enabled/phpmyadmin.conf"
if is_installed apache2; then
test -e $phpmyadminconf0 && grep --invert-match --extended-regexp --quiet "^( |\t)*#" "$phpmyadminconf0" \
&& failed "IS_PHPMYADMINAPACHECONF" "default phpmyadmin configuration ($phpmyadminconf0) should be commented or disabled"
test -e $phpmyadminconf1 && grep --invert-match --extended-regexp --quiet "^( |\t)*#" "$phpmyadminconf1" \
&& failed "IS_PHPMYADMINAPACHECONF" "default phpmyadmin configuration ($phpmyadminconf1) should be commented or disabled"
fi
}
# Verification si le système doit redémarrer suite màj kernel.
check_kerneluptodate() {
if is_installed linux-image*; then
# shellcheck disable=SC2012
kernel_installed_at=$(date -d "$(ls --full-time -lcrt /boot | tail -n1 | awk '{print $6}')" +%s)
kernel_installed_at=$(date -d "$(ls --full-time -lcrt /boot/*lin* | tail -n1 | awk '{print $6}')" +%s)
last_reboot_at=$(($(date +%s) - $(cut -f1 -d '.' /proc/uptime)))
if [ "$kernel_installed_at" -gt "$last_reboot_at" ]; then
failed "IS_KERNELUPTODATE" "machine is running an outdated kernel, reboot advised"
@ -764,6 +774,17 @@ check_etcgit() {
git rev-parse --is-inside-work-tree > /dev/null 2>&1 \
|| failed "IS_ETCGIT" "/etc is not a git repository"
}
check_etcgit_lxc() {
if is_installed lxc; then
container_list=$(lxc-ls --active)
for container in $container_list; do
export GIT_DIR="/var/lib/lxc/${container}/rootfs/etc/.git"
export GIT_WORK_TREE="/var/lib/lxc/${container}/rootfs/etc"
git rev-parse --is-inside-work-tree > /dev/null 2>&1 \
|| failed "IS_ETCGIT_LXC" "/etc is not a git repository in container ${container}"
done
fi
}
# Check if /etc/.git/ has read/write permissions for root only.
check_gitperms() {
GIT_DIR="/etc/.git"
@ -773,6 +794,19 @@ check_gitperms() {
[ "$expected" = "$actual" ] || failed "IS_GITPERMS" "$GIT_DIR must be $expected"
fi
}
check_gitperms_lxc() {
if is_installed lxc; then
container_list=$(lxc-ls --active)
for container in $container_list; do
GIT_DIR="/var/lib/lxc/${container}/rootfs/etc/.git"
if test -d $GIT_DIR; then
expected="700"
actual=$(stat -c "%a" $GIT_DIR)
[ "$expected" = "$actual" ] || failed "IS_GITPERMS_LXC" "$GIT_DIR must be $expected (in container ${container})"
fi
done
fi
}
# Check if no package has been upgraded since $limit.
check_notupgraded() {
last_upgrade=0
@ -785,7 +819,7 @@ check_notupgraded() {
fi
done
if $upgraded; then
last_upgrade=$(date +%s -d "$(zgrep -h upgrade /var/log/dpkg.log* | sort -n | tail -1 | cut -f1 -d ' ')")
last_upgrade=$(date +%s -d "$(zgrep --no-filename --no-messages upgrade /var/log/dpkg.log* | sort -n | tail -1 | cut -f1 -d ' ')")
fi
if grep -qs '^mailto="listupgrade-todo@' /etc/evolinux/listupgrade.cnf \
|| grep -qs -E '^[[:digit:]]+[[:space:]]+[[:digit:]]+[[:space:]]+[^\*]' /etc/cron.d/listupgrade; then
@ -833,17 +867,14 @@ check_tune2fs_m5() {
done
}
check_evolinuxsudogroup() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
if grep -q "^evolinux-sudo:" /etc/group; then
if [ -f /etc/sudoers.d/evolinux ]; then
grep -qE '^%evolinux-sudo +ALL ?= ?\(ALL:ALL\) ALL' /etc/sudoers.d/evolinux \
|| failed "IS_EVOLINUXSUDOGROUP" "missing evolinux-sudo directive in sudoers file"
fi
fi
fi
}
check_userinadmgroup() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
users=$(grep "^evolinux-sudo:" /etc/group | awk -F: '{print $4}' | tr ',' ' ')
for user in $users; do
if ! groups "$user" | grep -q adm; then
@ -851,42 +882,42 @@ check_userinadmgroup() {
test "${VERBOSE}" = 1 || break
fi
done
fi
}
check_apache2evolinuxconf() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
if is_installed apache2; then
{ test -L /etc/apache2/conf-enabled/z-evolinux-defaults.conf \
&& test -L /etc/apache2/conf-enabled/zzz-evolinux-custom.conf \
&& test -f /etc/apache2/ipaddr_whitelist.conf;
} || failed "IS_APACHE2EVOLINUXCONF" "missing custom evolinux apache config"
fi
fi
}
check_backportsconf() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
grep -qsE "^[^#].*backports" /etc/apt/sources.list \
&& failed "IS_BACKPORTSCONF" "backports can't be in main sources list"
if grep -qsE "^[^#].*backports" /etc/apt/sources.list.d/*.list; then
grep -qsE "^[^#].*backports" /etc/apt/preferences.d/* \
|| failed "IS_BACKPORTSCONF" "backports must have preferences"
fi
fi
}
check_bind9munin() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
if is_installed bind9; then
{ test -L /etc/munin/plugins/bind9 \
&& test -e /etc/munin/plugin-conf.d/bind9;
} || failed "IS_BIND9MUNIN" "missing bind plugin for munin"
fi
fi
}
check_bind9logrotate() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
if is_installed bind9; then
test -e /etc/logrotate.d/bind9 || failed "IS_BIND9LOGROTATE" "missing bind logrotate file"
fi
}
check_drbd_two_primaries() {
if is_installed drbd-utils; then
if command -v drbd-overview >/dev/null; then
if drbd-overview 2>&1 | grep -q "Primary/Primary"; then
failed "IS_DRBDTWOPRIMARIES" "Some DRBD ressources have two primaries, you risk a split brain!"
fi
elif command -v drbdadm >/dev/null; then
if drbdadm role all 2>&1 | grep -q 'Primary/Primary'; then
failed "IS_DRBDTWOPRIMARIES" "Some DRBD ressources have two primaries, you risk a split brain!"
fi
fi
fi
}
check_broadcomfirmware() {
@ -894,7 +925,7 @@ check_broadcomfirmware() {
if [ -x "${LSPCI_BIN}" ]; then
if ${LSPCI_BIN} | grep -q 'NetXtreme II'; then
{ is_installed firmware-bnx2 \
&& grep -q "^deb http://mirror.evolix.org/debian.* non-free" /etc/apt/sources.list;
&& apt-cache policy | grep "\bl=Debian\b" | grep --quiet -v "\b,c=non-free\b"
} || failed "IS_BROADCOMFIRMWARE" "missing non-free repository"
fi
else
@ -917,14 +948,12 @@ check_hardwareraidtool() {
fi
}
check_log2mailsystemdunit() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
systemctl -q is-active log2mail.service \
|| failed "IS_LOG2MAILSYSTEMDUNIT" "log2mail unit not running"
test -f /etc/systemd/system/log2mail.service \
|| failed "IS_LOG2MAILSYSTEMDUNIT" "missing log2mail unit file"
test -f /etc/init.d/log2mail \
&& failed "IS_LOG2MAILSYSTEMDUNIT" "/etc/init.d/log2mail may be deleted (use systemd unit)"
fi
}
check_listupgrade() {
test -f /etc/cron.d/listupgrade \
@ -933,13 +962,11 @@ check_listupgrade() {
|| failed "IS_LISTUPGRADE" "missing listupgrade script or not executable"
}
check_mariadbevolinuxconf() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
if is_installed mariadb-server; then
{ test -f /etc/mysql/mariadb.conf.d/z-evolinux-defaults.cnf \
&& test -f /etc/mysql/mariadb.conf.d/zzz-evolinux-custom.cnf;
} || failed "IS_MARIADBEVOLINUXCONF" "missing mariadb custom config"
fi
fi
}
check_sql_backup() {
if (is_installed "mysql-server" || is_installed "mariadb-server"); then
@ -997,8 +1024,27 @@ check_ldap_backup() {
check_redis_backup() {
if is_installed redis-server; then
# You could change the default path in /etc/evocheck.cf
REDIS_BACKUP_PATH=${REDIS_BACKUP_PATH:-"/home/backup/dump.rdb"}
test -f "$REDIS_BACKUP_PATH" || failed "IS_REDIS_BACKUP" "Redis dump is missing (${REDIS_BACKUP_PATH})"
# REDIS_BACKUP_PATH may contain space-separated paths, for example:
# REDIS_BACKUP_PATH='/home/backup/redis-instance1/dump.rdb /home/backup/redis-instance2/dump.rdb'
# Warning : this script doesn't handle spaces in file paths !
REDIS_BACKUP_PATH="${REDIS_BACKUP_PATH:-$(find /home/backup/ -iname "*.rdb*")}"
# Check number of dumps
n_instances=$(pgrep 'redis-server' | wc -l)
n_dumps=$(echo $REDIS_BACKUP_PATH | wc -w)
if [ ${n_dumps} -lt ${n_instances} ]; then
failed "IS_REDIS_BACKUP" "Missing Redis dump : ${n_instances} instance(s) found versus ${n_dumps} dump(s) found."
fi
# Check last dump date
age_threshold=$(date +"%s" -d "now - 2 days")
for dump in ${REDIS_BACKUP_PATH}; do
last_update=$(stat -c "%Z" $dump)
if [ "${last_update}" -lt "${age_threshold}" ]; then
failed "IS_REDIS_BACKUP" "Redis dump ${dump} is older than 2 days."
fi
done
fi
}
check_elastic_backup() {
@ -1020,7 +1066,6 @@ check_mariadbsystemdunit() {
fi
}
check_mysqlmunin() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
if is_installed mariadb-server; then
for file in mysql_bytes mysql_queries mysql_slowqueries \
mysql_threads mysql_connections mysql_files_tables \
@ -1037,10 +1082,8 @@ check_mysqlmunin() {
munin-run mysql_commands 2> /dev/null > /dev/null
test $? -eq 0 || failed "IS_MYSQLMUNIN" "Munin plugin mysql_commands returned an error"
fi
fi
}
check_mysqlnrpe() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
if is_installed mariadb-server; then
nagios_file=~nagios/.my.cnf
if ! test -f ${nagios_file}; then
@ -1053,30 +1096,25 @@ check_mysqlnrpe() {
|| failed "IS_MYSQLNRPE" "check_mysql is missing"
fi
fi
fi
}
check_phpevolinuxconf() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
is_debian_stretch && phpVersion="7.0"
is_debian_buster && phpVersion="7.3"
is_debian_bullseye && phpVersion="7.4"
is_debian_bookworm && phpVersion="8.2"
if is_installed php; then
{ test -f /etc/php/${phpVersion}/cli/conf.d/z-evolinux-defaults.ini \
&& test -f /etc/php/${phpVersion}/cli/conf.d/zzz-evolinux-custom.ini
{ test -f "/etc/php/${phpVersion}/cli/conf.d/z-evolinux-defaults.ini" \
&& test -f "/etc/php/${phpVersion}/cli/conf.d/zzz-evolinux-custom.ini"
} || failed "IS_PHPEVOLINUXCONF" "missing php evolinux config"
fi
fi
}
check_squidlogrotate() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
if is_installed squid; then
grep -q -e monthly -e daily /etc/logrotate.d/squid \
|| failed "IS_SQUIDLOGROTATE" "missing squid logrotate file"
fi
fi
}
check_squidevolinuxconf() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
if is_installed squid; then
{ grep -qs "^CONFIG=/etc/squid/evolinux-defaults.conf$" /etc/default/squid \
&& test -f /etc/squid/evolinux-defaults.conf \
@ -1087,14 +1125,13 @@ check_squidevolinuxconf() {
&& test -f /etc/squid/evolinux-custom.conf;
} || failed "IS_SQUIDEVOLINUXCONF" "missing squid evolinux config"
fi
fi
}
check_duplicate_fs_label() {
# Do it only if thereis blkid binary
BLKID_BIN=$(command -v blkid)
if [ -n "$BLKID_BIN" ]; then
tmpFile=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.duplicate_fs_label.XXXXX")
files_to_cleanup="${files_to_cleanup} ${tmpFile}"
tmpFile=$(mktemp --tmpdir "evocheck.duplicate_fs_label.XXXXX")
files_to_cleanup+=("${tmpFile}")
parts=$($BLKID_BIN -c /dev/null | grep -ve raid_member -e EFI_SYSPART | grep -Eo ' LABEL=".*"' | cut -d'"' -f2)
for part in $parts; do
@ -1152,41 +1189,20 @@ check_apache_confenabled() {
# Starting from Jessie and Apache 2.4, /etc/apache2/conf.d/
# must be replaced by conf-available/ and config files symlinked
# to conf-enabled/
if is_debian_jessie || is_debian_stretch || is_debian_buster || is_debian_bullseye; then
if [ -f /etc/apache2/apache2.conf ]; then
test -d /etc/apache2/conf.d/ \
&& failed "IS_APACHE_CONFENABLED" "apache's conf.d directory must not exists"
grep -q 'Include conf.d' /etc/apache2/apache2.conf \
&& failed "IS_APACHE_CONFENABLED" "apache2.conf must not Include conf.d"
fi
fi
}
check_meltdown_spectre() {
# For Stretch, detection is easy as the kernel use
# /sys/devices/system/cpu/vulnerabilities/
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
for vuln in meltdown spectre_v1 spectre_v2; do
test -f "/sys/devices/system/cpu/vulnerabilities/$vuln" \
|| failed "IS_MELTDOWN_SPECTRE" "vulnerable to $vuln"
test "${VERBOSE}" = 1 || break
done
# For Jessie this is quite complicated to verify and we need to use kernel config file
elif is_debian_jessie; then
if grep -q "BOOT_IMAGE=" /proc/cmdline; then
kernelPath=$(grep -Eo 'BOOT_IMAGE=[^ ]+' /proc/cmdline | cut -d= -f2)
kernelVer=${kernelPath##*/vmlinuz-}
kernelConfig="config-${kernelVer}"
# Sometimes autodetection of kernel config file fail, so we test if the file really exists.
if [ -f "/boot/${kernelConfig}" ]; then
grep -Eq '^CONFIG_PAGE_TABLE_ISOLATION=y' "/boot/$kernelConfig" \
|| failed "IS_MELTDOWN_SPECTRE" \
"PAGE_TABLE_ISOLATION must be enabled in kernel, outdated kernel?"
grep -Eq '^CONFIG_RETPOLINE=y' "/boot/$kernelConfig" \
|| failed "IS_MELTDOWN_SPECTRE" \
"RETPOLINE must be enabled in kernel, outdated kernel?"
fi
fi
fi
}
check_old_home_dir() {
homeDir=${homeDir:-/home}
@ -1217,16 +1233,10 @@ check_usrsharescripts() {
test "$expected" = "$actual" || failed "IS_USRSHARESCRIPTS" "/usr/share/scripts must be $expected"
}
check_sshpermitrootno() {
sshd_args="-C addr=,user=,host=,laddr=,lport=0"
if is_debian_jessie || is_debian_stretch; then
# Noop, we'll use the default $sshd_args
:
elif is_debian_buster; then
# You could change the SSH port in /etc/evocheck.cf
sshd_args="-C addr=,user=,host=,laddr=,lport=${SSH_PORT:-22}"
if is_debian_buster; then
sshd_args="${sshd_args},rdomain="
else
# NOTE: From Debian Bullseye 11 onward, with OpenSSH 8.1, the argument
# -T doesn't require the additional -C.
sshd_args=
fi
# shellcheck disable=SC2086
if ! (sshd -T ${sshd_args} 2> /dev/null | grep -qi 'permitrootlogin no'); then
@ -1234,17 +1244,7 @@ check_sshpermitrootno() {
fi
}
check_evomaintenanceusers() {
if is_debian_stretch || is_debian_buster || is_debian_bullseye; then
users=$(getent group evolinux-sudo | cut -d':' -f4 | tr ',' ' ')
else
if [ -f /etc/sudoers.d/evolinux ]; then
sudoers="/etc/sudoers.d/evolinux"
else
sudoers="/etc/sudoers"
fi
# combine users from User_Alias and sudo group
users=$({ grep "^User_Alias *ADMIN" $sudoers | cut -d= -f2 | tr -d " "; grep "^sudo" /etc/group | cut -d: -f 4; } | tr "," "\n" | sort -u)
fi
for user in $users; do
user_home=$(getent passwd "$user" | cut -d: -f6)
if [ -n "$user_home" ] && [ -d "$user_home" ]; then
@ -1292,8 +1292,8 @@ check_evobackup_incs() {
bkctld_cron_file=${bkctld_cron_file:-/etc/cron.d/bkctld}
if [ -f "${bkctld_cron_file}" ]; then
root_crontab=$(grep -v "^#" "${bkctld_cron_file}")
echo "${root_crontab}" | grep -q "bkctld inc" || failed "IS_EVOBACKUP_INCS" "\`bkctld inc' is missing in ${bkctld_cron_file}"
echo "${root_crontab}" | grep -qE "(check-incs.sh|bkctld check-incs)" || failed "IS_EVOBACKUP_INCS" "\`check-incs.sh' is missing in ${bkctld_cron_file}"
echo "${root_crontab}" | grep -q "bkctld inc" || failed "IS_EVOBACKUP_INCS" "'bkctld inc' is missing in ${bkctld_cron_file}"
echo "${root_crontab}" | grep -qE "(check-incs.sh|bkctld check-incs)" || failed "IS_EVOBACKUP_INCS" "'check-incs.sh' is missing in ${bkctld_cron_file}"
else
failed "IS_EVOBACKUP_INCS" "Crontab \`${bkctld_cron_file}' is missing"
fi
@ -1307,17 +1307,6 @@ check_osprober() {
fi
}
check_jessie_backports() {
if is_debian_jessie; then
jessieBackports=$(grep -hs "jessie-backports" /etc/apt/sources.list /etc/apt/sources.list.d/*)
if test -n "$jessieBackports"; then
if ! grep -q "archive.debian.org" <<< "$jessieBackports"; then
failed "IS_JESSIE_BACKPORTS" "You must use deb http://archive.debian.org/debian/ jessie-backports main"
fi
fi
fi
}
check_apt_valid_until() {
aptvalidFile="/etc/apt/apt.conf.d/99no-check-valid-until"
aptvalidText="Acquire::Check-Valid-Until no;"
@ -1335,7 +1324,7 @@ check_chrooted_binary_uptodate() {
for process_name in ${process_list}; do
# what is the binary path?
original_bin=$(command -v "${process_name}")
for pid in $(pgrep ${process_name}); do
for pid in $(pgrep "${process_name}"); do
process_bin=$(realpath "/proc/${pid}/exe")
# Is the process chrooted?
real_root=$(realpath "/proc/${pid}/root")
@ -1356,23 +1345,16 @@ check_nginx_letsencrypt_uptodate() {
snippets=$(find /etc/nginx -type f -name "letsencrypt.conf")
if [ -n "${snippets}" ]; then
while read -r snippet; do
if is_debian_jessie; then
if ! grep -qE "^\s*alias\s+/.+/\.well-known/acme-challenge" "${snippet}"; then
failed "IS_NGINX_LETSENCRYPT_UPTODATE" "Nginx snippet ${snippet} is not compatible with Nginx on Debian 8."
fi
else
if grep -qE "^\s*alias\s+/.+/\.well-known/acme-challenge" "${snippet}"; then
failed "IS_NGINX_LETSENCRYPT_UPTODATE" "Nginx snippet ${snippet} is not compatible with Nginx on Debian 9+."
fi
fi
done <<< "${snippets}"
fi
fi
}
check_lxc_container_resolv_conf() {
if is_installed lxc; then
container_list=$(lxc-ls)
container_list=$(lxc-ls --active)
current_resolvers=$(grep nameserver /etc/resolv.conf | sed 's/nameserver//g' )
for container in $container_list; do
@ -1390,6 +1372,66 @@ check_lxc_container_resolv_conf() {
done
fi
}
# Check that there are containers if lxc is installed.
check_no_lxc_container() {
if is_installed lxc; then
containers_count=$(lxc-ls --active | wc -l)
if [ "$containers_count" -eq 0 ]; then
failed "IS_NO_LXC_CONTAINER" "LXC is installed but have no active container. Consider removing it."
fi
fi
}
# Check that in LXC containers, phpXX-fpm services have UMask set to 0007.
check_lxc_php_fpm_service_umask_set() {
if is_installed lxc; then
php_containers_list=$(lxc-ls --active --filter php)
missing_umask=""
for container in $php_containers_list; do
# Translate container name in service name
if [ "$container" = "php56" ]; then
service="php5-fpm"
else
service="${container:0:4}.${container:4}-fpm"
fi
umask=$(lxc-attach --name "${container}" -- systemctl show -p UMask "$service" | cut -d "=" -f2)
if [ "$umask" != "0007" ]; then
missing_umask="${missing_umask} ${container}"
fi
done
if [ -n "${missing_umask}" ]; then
failed "IS_LXC_PHP_FPM_SERVICE_UMASK_SET" "UMask is not set to 0007 in PHP-FPM services of theses containers : ${missing_umask}."
fi
fi
}
# Check that LXC containers have the proper Debian version.
check_lxc_php_bad_debian_version() {
if is_installed lxc; then
php_containers_list=$(lxc-ls --active --filter php)
missing_umask=""
for container in $php_containers_list; do
if [ "$container" = "php56" ]; then
grep --quiet 'VERSION_ID="8"' /var/lib/lxc/${container}/rootfs/etc/os-release || failed "IS_LXC_PHP_BAD_DEBIAN_VERSION" "Container ${container} should use Jessie"
elif [ "$container" = "php70" ]; then
grep --quiet 'VERSION_ID="9"' /var/lib/lxc/${container}/rootfs/etc/os-release || failed "IS_LXC_PHP_BAD_DEBIAN_VERSION" "Container ${container} should use Stretch"
elif [ "$container" = "php73" ]; then
grep --quiet 'VERSION_ID="10"' /var/lib/lxc/${container}/rootfs/etc/os-release || failed "IS_LXC_PHP_BAD_DEBIAN_VERSION" "Container ${container} should use Buster"
elif [ "$container" = "php74" ]; then
grep --quiet 'VERSION_ID="11"' /var/lib/lxc/${container}/rootfs/etc/os-release || failed "IS_LXC_PHP_BAD_DEBIAN_VERSION" "Container ${container} should use Bullseye"
elif [ "$container" = "php82" ]; then
grep --quiet 'VERSION_ID="12"' /var/lib/lxc/${container}/rootfs/etc/os-release || failed "IS_LXC_PHP_BAD_DEBIAN_VERSION" "Container ${container} should use Bookworm"
fi
done
fi
}
check_lxc_openssh() {
if is_installed lxc; then
container_list=$(lxc-ls --active)
for container in $container_list; do
test -e /var/lib/lxc/${container}/rootfs/usr/sbin/sshd && failed "IS_LXC_OPENSSH" "openssh-server should not be installed in container ${container}"
done
fi
}
download_versions() {
local file
file=${1:-}
@ -1399,11 +1441,7 @@ download_versions() {
# evoacme 21.06
# evomaintenance 0.6.4
if is_debian; then
versions_url="https://upgrades.evolix.org/versions-${DEBIAN_RELEASE}"
else
failed "IS_CHECK_VERSIONS" "error determining os release"
fi
# fetch timeout, in seconds
timeout=10
@ -1496,8 +1534,8 @@ add_to_path() {
echo "$PATH" | grep -qF "${new_path}" || export PATH="${PATH}:${new_path}"
}
check_versions() {
versions_file=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.versions.XXXXX")
files_to_cleanup="${files_to_cleanup} ${versions_file}"
versions_file=$(mktemp --tmpdir "evocheck.versions.XXXXX")
files_to_cleanup+=("${versions_file}")
download_versions "${versions_file}"
add_to_path "/usr/share/scripts"
@ -1524,10 +1562,8 @@ main() {
# Detect operating system name, version and release
detect_os
main_output_file=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.main.XXXXX")
files_to_cleanup="${files_to_cleanup} ${main_output_file}"
MINIFW_FILE=$(minifirewall_file)
main_output_file=$(mktemp --tmpdir "evocheck.main.XXXXX")
files_to_cleanup+=("${main_output_file}")
test "${IS_TMP_1777:=1}" = 1 && check_tmp_1777
test "${IS_ROOT_0700:=1}" = 1 && check_root_0700
@ -1540,19 +1576,23 @@ main() {
test "${IS_LSBRELEASE:=1}" = 1 && check_lsbrelease
test "${IS_DPKGWARNING:=1}" = 1 && check_dpkgwarning
test "${IS_UMASKSUDOERS:=1}" = 1 && check_umasksudoers
test "${IS_POSTFIX_MYDESTINATION:=1}" = 1 && check_postfix_mydestination
test "${IS_NRPEPOSTFIX:=1}" = 1 && check_nrpepostfix
test "${IS_MODSECURITY:=1}" = 1 && check_modsecurity
test "${IS_CUSTOMSUDOERS:=1}" = 1 && check_customsudoers
test "${IS_VARTMPFS:=1}" = 1 && check_vartmpfs
test "${IS_SERVEURBASE:=1}" = 1 && check_serveurbase
test "${IS_LOGROTATECONF:=1}" = 1 && check_logrotateconf
test "${IS_SYSLOGCONF:=1}" = 1 && check_syslogconf
test "${IS_DEBIANSECURITY:=1}" = 1 && check_debiansecurity
test "${IS_APTITUDEONLY:=1}" = 1 && check_aptitudeonly
test "${IS_DEBIANSECURITY_LXC:=1}" = 1 && check_debiansecurity_lxc
test "${IS_BACKPORTS_VERSION:=1}" = 1 && check_backports_version
test "${IS_OLDPUB:=1}" = 1 && check_oldpub
test "${IS_OLDPUB_LXC:=1}" = 1 && check_oldpub_lxc
test "${IS_NEWPUB:=1}" = 1 && check_newpub
test "${IS_SURY:=1}" = 1 && check_sury
test "${IS_SURY_LXC:=1}" = 1 && check_sury_lxc
test "${IS_APTITUDE:=1}" = 1 && check_aptitude
test "${IS_APTGETBAK:=1}" = 1 && check_aptgetbak
test "${IS_APTICRON:=0}" = 1 && check_apticron
test "${IS_USRRO:=1}" = 1 && check_usrro
test "${IS_TMPNOEXEC:=1}" = 1 && check_tmpnoexec
test "${IS_MOUNT_FSTAB:=1}" = 1 && check_mountfstab
@ -1584,25 +1624,28 @@ main() {
test "${IS_LOG2MAILMYSQL:=1}" = 1 && check_log2mailmysql
test "${IS_LOG2MAILSQUID:=1}" = 1 && check_log2mailsquid
test "${IS_BINDCHROOT:=1}" = 1 && check_bindchroot
test "${IS_REPVOLATILE:=1}" = 1 && check_repvolatile
test "${IS_NETWORK_INTERFACES:=1}" = 1 && check_network_interfaces
test "${IS_AUTOIF:=1}" = 1 && check_autoif
test "${IS_INTERFACESGW:=1}" = 1 && check_interfacesgw
test "${IS_NETWORKING_SERVICE:=1}" = 1 && check_networking_service
test "${IS_EVOBACKUP:=1}" = 1 && check_evobackup
test "${IS_PURGE_FAIL2BAN:=1}" = 1 && check_fail2ban_purge
test "${IS_SSH_FAIL2BAN_JAIL_RENAMED:=1}" = 1 && check_ssh_fail2ban_jail_renamed
test "${IS_EVOBACKUP_EXCLUDE_MOUNT:=1}" = 1 && check_evobackup_exclude_mount
test "${IS_USERLOGROTATE:=1}" = 1 && check_userlogrotate
test "${IS_APACHECTL:=1}" = 1 && check_apachectl
test "${IS_APACHESYMLINK:=1}" = 1 && check_apachesymlink
test "${IS_APACHEIPINALLOW:=1}" = 1 && check_apacheipinallow
test "${IS_MUNINAPACHECONF:=1}" = 1 && check_muninapacheconf
test "${IS_SAMBAPINPRIORITY:=1}" = 1 && check_sambainpriority
test "${IS_PHPMYADMINAPACHECONF:=1}" = 1 && check_phpmyadminapacheconf
test "${IS_KERNELUPTODATE:=1}" = 1 && check_kerneluptodate
test "${IS_UPTIME:=1}" = 1 && check_uptime
test "${IS_MUNINRUNNING:=1}" = 1 && check_muninrunning
test "${IS_BACKUPUPTODATE:=1}" = 1 && check_backupuptodate
test "${IS_ETCGIT:=1}" = 1 && check_etcgit
test "${IS_ETCGIT_LXC:=1}" = 1 && check_etcgit_lxc
test "${IS_GITPERMS:=1}" = 1 && check_gitperms
test "${IS_GITPERMS_LXC:=1}" = 1 && check_gitperms_lxc
test "${IS_NOTUPGRADED:=1}" = 1 && check_notupgraded
test "${IS_TUNE2FS_M5:=1}" = 1 && check_tune2fs_m5
test "${IS_EVOLINUXSUDOGROUP:=1}" = 1 && check_evolinuxsudogroup
@ -1611,6 +1654,7 @@ main() {
test "${IS_BACKPORTSCONF:=1}" = 1 && check_backportsconf
test "${IS_BIND9MUNIN:=1}" = 1 && check_bind9munin
test "${IS_BIND9LOGROTATE:=1}" = 1 && check_bind9logrotate
test "${IS_DRBDTWOPRIMARIES:=1}" = 1 && check_drbd_two_primaries
test "${IS_BROADCOMFIRMWARE:=1}" = 1 && check_broadcomfirmware
test "${IS_HARDWARERAIDTOOL:=1}" = 1 && check_hardwareraidtool
test "${IS_LOG2MAILSYSTEMDUNIT:=1}" = 1 && check_log2mailsystemdunit
@ -1637,11 +1681,14 @@ main() {
test "${IS_OLD_HOME_DIR:=0}" = 1 && check_old_home_dir
test "${IS_EVOBACKUP_INCS:=1}" = 1 && check_evobackup_incs
test "${IS_OSPROBER:=1}" = 1 && check_osprober
test "${IS_JESSIE_BACKPORTS:=1}" = 1 && check_jessie_backports
test "${IS_APT_VALID_UNTIL:=1}" = 1 && check_apt_valid_until
test "${IS_CHROOTED_BINARY_UPTODATE:=1}" = 1 && check_chrooted_binary_uptodate
test "${IS_NGINX_LETSENCRYPT_UPTODATE:=1}" = 1 && check_nginx_letsencrypt_uptodate
test "${IS_LXC_CONTAINER_RESOLV_CONF:=1}" = 1 && check_lxc_container_resolv_conf
test "${IS_NO_LXC_CONTAINER:=1}" = 1 && check_no_lxc_container
test "${IS_LXC_PHP_FPM_SERVICE_UMASK_SET:=1}" = 1 && check_lxc_php_fpm_service_umask_set
test "${IS_LXC_PHP_BAD_DEBIAN_VERSION:=1}" = 1 && check_lxc_php_bad_debian_version
test "${IS_LXC_OPENSSH:=1}" = 1 && check_lxc_openssh
test "${IS_CHECK_VERSIONS:=1}" = 1 && check_versions
if [ -f "${main_output_file}" ]; then
@ -1655,9 +1702,12 @@ main() {
exit ${RC}
}
cleanup_temp_files() {
# shellcheck disable=SC2086
rm -f ${files_to_cleanup}
cleanup() {
# Cleanup tmp files
# shellcheck disable=SC2068,SC2317
rm -f ${files_to_cleanup[@]}
log "$PROGNAME exit."
}
PROGNAME=$(basename "$0")
@ -1668,17 +1718,23 @@ readonly PROGNAME
ARGS=$@
readonly ARGS
LOGFILE="/var/log/evocheck.log"
readonly LOGFILE
CONFIGFILE="/etc/evocheck.cf"
readonly CONFIGFILE
DATE_FORMAT="%Y-%m-%d %H:%M:%S"
# shellcheck disable=SC2034
readonly DATEFORMAT
# Disable LANG*
export LANG=C
export LANGUAGE=C
files_to_cleanup=""
# shellcheck disable=SC2064
trap cleanup_temp_files 0
# Source configuration file
# shellcheck disable=SC1091
test -f /etc/evocheck.cf && . /etc/evocheck.cf
test -f "${CONFIGFILE}" && . "${CONFIGFILE}"
# Parse options
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
@ -1726,5 +1782,24 @@ while :; do
shift
done
# Keep this after "show_version(); exit 0" which is called by check_versions
# to avoid logging exit twice.
declare -a files_to_cleanup
files_to_cleanup=""
# shellcheck disable=SC2064
trap cleanup EXIT INT TERM
log '-----------------------------------------------'
log "Running $PROGNAME $VERSION..."
# Log config file content
if [ -f "${CONFIGFILE}" ]; then
log "Runtime configuration (${CONFIGFILE}):"
sed -e '/^[[:blank:]]*#/d; s/#.*//; /^[[:blank:]]*$/d' "${CONFIGFILE}" | log
fi
# shellcheck disable=SC2086
main ${ARGS}
log "End of $PROGNAME execution."

1252
linux/evocheck.wheezy.sh Executable file
View File

@ -0,0 +1,1252 @@
#!/bin/bash
# EvoCheck
# Script to verify compliance of a Linux (Debian) server
# powered by Evolix
VERSION="24.01"
readonly VERSION
# base functions
show_version() {
cat <<END
evocheck version ${VERSION} (Wheezy)
Copyright 2009-2022 Evolix <info@evolix.fr>,
Romain Dessort <rdessort@evolix.fr>,
Benoit Série <bserie@evolix.fr>,
Gregory Colpart <reg@evolix.fr>,
Jérémy Lecour <jlecour@evolix.fr>,
Tristan Pilat <tpilat@evolix.fr>,
Victor Laborie <vlaborie@evolix.fr>,
Alexis Ben Miloud--Josselin <abenmiloud@evolix.fr>,
and others.
evocheck comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
See the GNU General Public License v3.0 for details.
END
}
show_help() {
cat <<END
evocheck is a script that verifies Evolix conventions on Linux (Debian) servers.
Usage: evocheck
or evocheck --cron
or evocheck --quiet
or evocheck --verbose
Options
--cron disable a few checks
-v, --verbose increase verbosity of checks
-q, --quiet nothing is printed on stdout nor stderr
-h, --help print this message and exit
--version print version and exit
END
}
detect_os() {
# OS detection
DEBIAN_RELEASE=""
LSB_RELEASE_BIN=$(command -v lsb_release)
if [ -e /etc/debian_version ]; then
DEBIAN_MAIN_VERSION=$(cut -d "." -f 1 < /etc/debian_version)
if [ "${DEBIAN_MAIN_VERSION}" -ne "7" ]; then
echo "Debian ${DEBIAN_MAIN_VERSION} is incompatible with this version of evocheck." >&2
echo "This version is built for Debian 7 only." >&2
exit
fi
if [ -x "${LSB_RELEASE_BIN}" ]; then
DEBIAN_RELEASE=$(${LSB_RELEASE_BIN} --codename --short)
else
case ${DEBIAN_MAIN_VERSION} in
5) DEBIAN_RELEASE="lenny";;
6) DEBIAN_RELEASE="squeeze";;
7) DEBIAN_RELEASE="wheezy";;
esac
fi
fi
}
is_debian_lenny() {
test "${DEBIAN_RELEASE}" = "lenny"
}
is_debian_squeeze() {
test "${DEBIAN_RELEASE}" = "squeeze"
}
is_debian_wheezy() {
test "${DEBIAN_RELEASE}" = "wheezy"
}
is_pack_web(){
test -e /usr/share/scripts/web-add.sh || test -e /usr/share/scripts/evoadmin/web-add.sh
}
is_pack_samba(){
test -e /usr/share/scripts/add.pl
}
is_installed(){
for pkg in "$@"; do
dpkg -l "$pkg" 2> /dev/null | grep -q -E '^(i|h)i' || return 1
done
}
# logging
failed() {
check_name=$1
shift
check_comments=$*
RC=1
if [ "${QUIET}" != 1 ]; then
if [ -n "${check_comments}" ] && [ "${VERBOSE}" = 1 ]; then
printf "%s FAILED! %s\n" "${check_name}" "${check_comments}" >> "${main_output_file}"
else
printf "%s FAILED!\n" "${check_name}" >> "${main_output_file}"
fi
fi
}
# check functions
check_lsbrelease(){
if [ -x "${LSB_RELEASE_BIN}" ]; then
## only the major version matters
lhs=$(${LSB_RELEASE_BIN} --release --short | cut -d "." -f 1)
rhs=$(cut -d "." -f 1 < /etc/debian_version)
test "$lhs" = "$rhs" || failed "IS_LSBRELEASE" "release is not consistent between lsb_release (${lhs}) and /etc/debian_version (${rhs})"
else
failed "IS_LSBRELEASE" "lsb_release is missing or not executable"
fi
}
check_dpkgwarning() {
if [ "$IS_USRRO" = 1 ] || [ "$IS_TMPNOEXEC" = 1 ]; then
test -e /etc/apt/apt.conf.d/80evolinux \
|| failed "IS_DPKGWARNING" "/etc/apt/apt.conf.d/80evolinux is missing"
test -e /etc/apt/apt.conf \
&& failed "IS_DPKGWARNING" "/etc/apt/apt.conf is missing"
fi
}
# Verifying check_mailq in Nagios NRPE config file. (Option "-M postfix" need to be set if the MTA is Postfix)
check_nrpepostfix() {
if is_installed postfix; then
{ test -e /etc/nagios/nrpe.cfg \
&& grep -qr "^command.*check_mailq -M postfix" /etc/nagios/nrpe.*;
} || failed "IS_NRPEPOSTFIX" "NRPE \"check_mailq\" for postfix is missing"
fi
}
# Check if mod-security config file is present
check_modsecurity() {
if is_installed libapache2-modsecurity; then
test -e /etc/apache2/conf.d/mod-security2.conf || failed "IS_MODSECURITY" "missing configuration file"
fi
}
check_customsudoers() {
grep -E -qr "umask=0077" /etc/sudoers* || failed "IS_CUSTOMSUDOERS" "missing umask=0077 in sudoers file"
}
check_vartmpfs() {
FINDMNT_BIN=$(command -v findmnt)
if [ -x "${FINDMNT_BIN}" ]; then
${FINDMNT_BIN} /var/tmp --type tmpfs --noheadings > /dev/null || failed "IS_VARTMPFS" "/var/tmp is not a tmpfs"
else
df /var/tmp | grep -q tmpfs || failed "IS_VARTMPFS" "/var/tmp is not a tmpfs"
fi
}
check_serveurbase() {
is_installed serveur-base || failed "IS_SERVEURBASE" "serveur-base package is not installed"
}
check_logrotateconf() {
test -e /etc/logrotate.d/zsyslog || failed "IS_LOGROTATECONF" "missing zsyslog in logrotate.d"
}
check_syslogconf() {
grep -q "^# Syslog for Pack Evolix serveur" /etc/*syslog.conf \
|| failed "IS_SYSLOGCONF" "syslog evolix config file missing"
}
check_debiansecurity() {
# Look for enabled "Debian-Security" sources from the "Debian" origin
apt-cache policy | grep "\bl=Debian-Security\b" | grep "\bo=Debian\b" | grep --quiet "\bc=main\b"
test $? -eq 0 || failed "IS_DEBIANSECURITY" "missing Debian-Security repository"
}
check_aptitudeonly() {
test -e /usr/bin/apt-get && failed "IS_APTITUDEONLY" \
"only aptitude may be enabled on Debian <=7, apt-get should be disabled"
}
check_apticron() {
status="OK"
test -e /etc/cron.d/apticron || status="fail"
test -e /etc/cron.daily/apticron && status="fail"
test "$status" = "fail" || test -e /usr/bin/apt-get.bak || status="fail"
test "$status" = "fail" && failed "IS_APTICRON" "apticron must be in cron.d not cron.daily"
}
check_usrro() {
grep /usr /etc/fstab | grep -qE "\bro\b" || failed "IS_USRRO" "missing ro directive on fstab for /usr"
}
check_tmpnoexec() {
FINDMNT_BIN=$(command -v findmnt)
if [ -x "${FINDMNT_BIN}" ]; then
options=$(${FINDMNT_BIN} --noheadings --first-only --output OPTIONS /tmp)
echo "${options}" | grep -qE "\bnoexec\b" || failed "IS_TMPNOEXEC" "/tmp is not mounted with 'noexec'"
else
mount | grep "on /tmp" | grep -qE "\bnoexec\b" || failed "IS_TMPNOEXEC" "/tmp is not mounted with 'noexec' (WARNING: findmnt(8) is not found)"
fi
}
check_mountfstab() {
# Test if lsblk available, if not skip this test...
LSBLK_BIN=$(command -v lsblk)
if test -x "${LSBLK_BIN}"; then
for mountPoint in $(${LSBLK_BIN} -o MOUNTPOINT -l -n | grep '/'); do
grep -Eq "$mountPoint\W" /etc/fstab \
|| failed "IS_MOUNT_FSTAB" "partition(s) detected mounted but no presence in fstab"
done
fi
}
check_listchangesconf() {
if [ -e "/etc/apt/listchanges.conf" ]; then
lines=$(grep -cE "(which=both|confirm=1)" /etc/apt/listchanges.conf)
if [ "$lines" != 2 ]; then
failed "IS_LISTCHANGESCONF" "apt-listchanges config is incorrect"
fi
else
failed "IS_LISTCHANGESCONF" "apt-listchanges config is missing"
fi
}
check_customcrontab() {
found_lines=$(grep -c -E "^(17 \*|25 6|47 6|52 6)" /etc/crontab)
test "$found_lines" = 4 && failed "IS_CUSTOMCRONTAB" "missing custom field in crontab"
}
check_sshallowusers() {
grep -E -qir "(AllowUsers|AllowGroups)" /etc/ssh/sshd_config /etc/ssh/sshd_config.d \
|| failed "IS_SSHALLOWUSERS" "missing AllowUsers or AllowGroups directive in sshd_config"
}
check_diskperf() {
perfFile="/root/disk-perf.txt"
test -e $perfFile || failed "IS_DISKPERF" "missing ${perfFile}"
}
check_tmoutprofile() {
grep -sq "TMOUT=" /etc/profile /etc/profile.d/evolinux.sh || failed "IS_TMOUTPROFILE" "TMOUT is not set"
}
check_alert5boot() {
if [ -n "$(find /etc/rc2.d/ -name 'S*alert5')" ]; then
grep -q "^date" /etc/rc2.d/S*alert5 || failed "IS_ALERT5BOOT" "boot mail is not sent by alert5 init script"
elif [ -n "$(find /etc/init.d/ -name 'alert5')" ]; then
grep -q "^date" /etc/init.d/alert5 || failed "IS_ALERT5BOOT" "boot mail is not sent by alert5 int script"
else
failed "IS_ALERT5BOOT" "alert5 init script is missing"
fi
}
check_alert5minifw() {
if [ -n "$(find /etc/rc2.d/ -name 'S*alert5')" ]; then
grep -q "^/etc/init.d/minifirewall" /etc/rc2.d/S*alert5 \
|| failed "IS_ALERT5MINIFW" "Minifirewall is not started by alert5 init script"
elif [ -n "$(find /etc/init.d/ -name 'alert5')" ]; then
grep -q "^/etc/init.d/minifirewall" /etc/init.d/alert5 \
|| failed "IS_ALERT5MINIFW" "Minifirewall is not started by alert5 init script"
else
failed "IS_ALERT5MINIFW" "alert5 init script is missing"
fi
}
check_minifw() {
/sbin/iptables -L -n | grep -q -E "^ACCEPT\s*all\s*--\s*31\.170\.8\.4\s*0\.0\.0\.0/0\s*$" \
|| failed "IS_MINIFW" "minifirewall seems not started"
}
check_nrpeperms() {
if [ -d /etc/nagios ]; then
nagiosDir="/etc/nagios"
actual=$(stat --format "%a" $nagiosDir)
expected="750"
test "$expected" = "$actual" || failed "IS_NRPEPERMS" "${nagiosDir} must be ${expected}"
fi
}
check_minifwperms() {
if [ -f "/etc/firewall.rc" ]; then
actual=$(stat --format "%a" "/etc/firewall.rc")
expected="600"
test "$expected" = "$actual" || failed "IS_MINIFWPERMS" "/etc/firewall.rc must be ${expected}"
fi
}
check_nrpedisks() {
NRPEDISKS=$(grep command.check_disk /etc/nagios/nrpe.cfg | grep "^command.check_disk[0-9]" | sed -e "s/^command.check_disk\([0-9]\+\).*/\1/" | sort -n | tail -1)
DFDISKS=$(df -Pl | grep -c -E -v "(^Filesystem|/lib/init/rw|/dev/shm|udev|rpc_pipefs)")
test "$NRPEDISKS" = "$DFDISKS" || failed "IS_NRPEDISKS" "there must be $DFDISKS check_disk in nrpe.cfg"
}
check_nrpepid() {
{ test -e /etc/nagios/nrpe.cfg \
&& grep -q "^pid_file=/var/run/nagios/nrpe.pid" /etc/nagios/nrpe.cfg;
} || failed "IS_NRPEPID" "missing or wrong pid_file directive in nrpe.cfg"
}
check_grsecprocs() {
if uname -a | grep -q grsec; then
{ grep -q "^command.check_total_procs..sudo" /etc/nagios/nrpe.cfg \
&& grep -A1 "^\[processes\]" /etc/munin/plugin-conf.d/munin-node | grep -q "^user root";
} || failed "IS_GRSECPROCS" "missing munin's plugin processes directive for grsec"
fi
}
check_apachemunin() {
if test -e /etc/apache2/apache2.conf; then
pattern="/server-status-[[:alnum:]]{4,}"
{ grep -r -q -s -E "^env.url.*${pattern}" /etc/munin/plugin-conf.d \
&& { grep -q -s -E "${pattern}" /etc/apache2/apache2.conf \
|| grep -q -s -E "${pattern}" /etc/apache2/mods-enabled/status.conf;
};
} || failed "IS_APACHEMUNIN" "server status is not properly configured"
fi
}
# Verification mytop + Munin si MySQL
check_mysqlutils() {
MYSQL_ADMIN=${MYSQL_ADMIN:-mysqladmin}
if is_installed mysql-server; then
# You can configure MYSQL_ADMIN in evocheck.cf
if ! grep -qs "^user *= *${MYSQL_ADMIN}" /root/.my.cnf; then
failed "IS_MYSQLUTILS" "${MYSQL_ADMIN} missing in /root/.my.cnf"
fi
if ! test -x /usr/bin/mytop; then
if ! test -x /usr/local/bin/mytop; then
failed "IS_MYSQLUTILS" "mytop binary missing"
fi
fi
if ! grep -qs '^user *=' /root/.mytop; then
failed "IS_MYSQLUTILS" "credentials missing in /root/.mytop"
fi
fi
}
# Verification de la configuration du raid soft (mdadm)
check_raidsoft() {
if test -e /proc/mdstat && grep -q md /proc/mdstat; then
{ grep -q "^AUTOCHECK=true" /etc/default/mdadm \
&& grep -q "^START_DAEMON=true" /etc/default/mdadm \
&& grep -qv "^MAILADDR ___MAIL___" /etc/mdadm/mdadm.conf;
} || failed "IS_RAIDSOFT" "missing or wrong config for mdadm"
fi
}
# Verification du LogFormat de AWStats
check_awstatslogformat() {
if is_installed apache2 awstats; then
awstatsFile="/etc/awstats/awstats.conf.local"
grep -qE '^LogFormat=1' $awstatsFile \
|| failed "IS_AWSTATSLOGFORMAT" "missing or wrong LogFormat directive in $awstatsFile"
fi
}
# Verification de la présence de la config logrotate pour Munin
check_muninlogrotate() {
{ test -e /etc/logrotate.d/munin-node \
&& test -e /etc/logrotate.d/munin;
} || failed "IS_MUNINLOGROTATE" "missing lorotate file for munin"
}
# Verification de l'activation de Squid dans le cas d'un pack mail
check_squid() {
squidconffile="/etc/squid*/squid.conf"
if is_pack_web && (is_installed squid || is_installed squid3); then
host=$(hostname -i)
# shellcheck disable=SC2086
http_port=$(grep -E "^http_port\s+[0-9]+" $squidconffile | awk '{ print $2 }')
{ grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -m owner --uid-owner proxy -j ACCEPT" "/etc/firewall.rc" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -d $host -j ACCEPT" "/etc/firewall.rc" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -d 127.0.0.(1|0/8) -j ACCEPT" "/etc/firewall.rc" \
&& grep -qE "^[^#]*iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port.* $http_port" "/etc/firewall.rc";
} || grep -qE "^PROXY='?on'?" "/etc/firewall.rc" \
|| failed "IS_SQUID" "missing squid rules in minifirewall"
fi
}
check_evomaintenance_fw() {
if [ -f "/etc/firewall.rc" ]; then
hook_db=$(grep -E '^\s*HOOK_DB' /etc/evomaintenance.cf | tr -d ' ' | cut -d= -f2)
rulesNumber=$(grep -c "/sbin/iptables -A INPUT -p tcp --sport 5432 --dport 1024:65535 -s .* -m state --state ESTABLISHED,RELATED -j ACCEPT" "/etc/firewall.rc")
if [ "$hook_db" = "1" ] && [ "$rulesNumber" -lt 2 ]; then
failed "IS_EVOMAINTENANCE_FW" "HOOK_DB is enabled but missing evomaintenance rules in minifirewall"
fi
fi
}
# Verification de la conf et de l'activation de mod-deflate
check_moddeflate() {
f=/etc/apache2/mods-enabled/deflate.conf
if is_installed apache2.2; then
{ test -e $f && grep -q "AddOutputFilterByType DEFLATE text/html text/plain text/xml" $f \
&& grep -q "AddOutputFilterByType DEFLATE text/css" $f \
&& grep -q "AddOutputFilterByType DEFLATE application/x-javascript application/javascript" $f;
} || failed "IS_MODDEFLATE" "missing AddOutputFilterByType directive for apache mod deflate"
fi
}
# Verification de la conf log2mail
check_log2mailrunning() {
if is_pack_web && is_installed log2mail; then
pgrep log2mail >/dev/null || failed "IS_LOG2MAILRUNNING" "log2mail is not running"
fi
}
check_log2mailapache() {
conf=/etc/log2mail/config/default
if is_pack_web && is_installed log2mail; then
grep -s -q "^file = /var/log/apache2/error.log" $conf \
|| failed "IS_LOG2MAILAPACHE" "missing log2mail directive for apache"
fi
}
check_log2mailmysql() {
if is_pack_web && is_installed log2mail; then
grep -s -q "^file = /var/log/syslog" /etc/log2mail/config/{default,mysql,mysql.conf} \
|| failed "IS_LOG2MAILMYSQL" "missing log2mail directive for mysql"
fi
}
check_log2mailsquid() {
if is_pack_web && is_installed log2mail; then
grep -s -q "^file = /var/log/squid.*/access.log" /etc/log2mail/config/* \
|| failed "IS_LOG2MAILSQUID" "missing log2mail directive for squid"
fi
}
# Verification si bind est chroote
check_bindchroot() {
if is_installed bind9; then
if netstat -utpln | grep "/named" | grep :53 | grep -qvE "(127.0.0.1|::1)"; then
if grep -q '^OPTIONS=".*-t' /etc/default/bind9 && grep -q '^OPTIONS=".*-u' /etc/default/bind9; then
md5_original=$(md5sum /usr/sbin/named | cut -f 1 -d ' ')
md5_chrooted=$(md5sum /var/chroot-bind/usr/sbin/named | cut -f 1 -d ' ')
if [ "$md5_original" != "$md5_chrooted" ]; then
failed "IS_BINDCHROOT" "the chrooted bind binary is different than the original binary"
fi
else
failed "IS_BINDCHROOT" "bind process is not chrooted"
fi
fi
fi
}
# /etc/network/interfaces should be present, we don't manage systemd-network yet
check_network_interfaces() {
if ! test -f /etc/network/interfaces; then
IS_AUTOIF=0
IS_INTERFACESGW=0
failed "IS_NETWORK_INTERFACES" "systemd network configuration is not supported yet"
fi
}
# Verify if all if are in auto
check_autoif() {
interfaces=$(/sbin/ifconfig -s | tail -n +2 | grep -E -v "^(lo|vnet|docker|veth|tun|tap|macvtap|vrrp)" | cut -d " " -f 1 |tr "\n" " ")
for interface in $interfaces; do
if grep -Rq "^iface $interface" /etc/network/interfaces* && ! grep -Rq "^auto $interface" /etc/network/interfaces*; then
failed "IS_AUTOIF" "Network interface \`${interface}' is statically defined but not set to auto"
test "${VERBOSE}" = 1 || break
fi
done
}
# Network conf verification
check_interfacesgw() {
number=$(grep -Ec "^[^#]*gateway [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}" /etc/network/interfaces)
test "$number" -gt 1 && failed "IS_INTERFACESGW" "there is more than 1 IPv4 gateway"
number=$(grep -Ec "^[^#]*gateway [0-9a-fA-F]+:" /etc/network/interfaces)
test "$number" -gt 1 && failed "IS_INTERFACESGW" "there is more than 1 IPv6 gateway"
}
# Verification de la mise en place d'evobackup
check_evobackup() {
evobackup_found=$(find /etc/cron* -name '*evobackup*' | wc -l)
test "$evobackup_found" -gt 0 || failed "IS_EVOBACKUP" "missing evobackup cron"
}
# Vérification de l'exclusion des montages (NFS) dans les sauvegardes
check_evobackup_exclude_mount() {
excludes_file=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.evobackup_exclude_mount.XXXXX")
files_to_cleanup="${files_to_cleanup} ${excludes_file}"
# shellcheck disable=SC2044
for evobackup_file in $(find /etc/cron* -name '*evobackup*' | grep -v -E ".disabled$"); do
# if the file seems to be a backup script, with an Rsync invocation
if grep -q "^\s*rsync" "${evobackup_file}"; then
# If rsync is not limited by "one-file-system"
# then we verify that every mount is excluded
if ! grep -q -- "^\s*--one-file-system" "${evobackup_file}"; then
grep -- "--exclude " "${evobackup_file}" | grep -E -o "\"[^\"]+\"" | tr -d '"' > "${excludes_file}"
not_excluded=$(findmnt --type nfs,nfs4,fuse.sshfs, -o target --noheadings | grep -v -f "${excludes_file}")
for mount in ${not_excluded}; do
failed "IS_EVOBACKUP_EXCLUDE_MOUNT" "${mount} is not excluded from ${evobackup_file} backup script"
done
fi
fi
done
}
# Verification de la presence du userlogrotate
check_userlogrotate() {
if is_pack_web; then
test -x /etc/cron.weekly/userlogrotate || failed "IS_USERLOGROTATE" "missing userlogrotate cron"
fi
}
# Verification de la syntaxe de la conf d'Apache
check_apachectl() {
if is_installed apache2; then
/usr/sbin/apache2ctl configtest 2>&1 | grep -q "^Syntax OK$" \
|| failed "IS_APACHECTL" "apache errors detected, run a configtest"
fi
}
# Check if there is regular files in Apache sites-enabled.
check_apachesymlink() {
if is_installed apache2; then
apacheFind=$(find /etc/apache2/sites-enabled ! -type l -type f -print)
nbApacheFind=$(wc -m <<< "$apacheFind")
if [[ $nbApacheFind -gt 1 ]]; then
if [[ $VERBOSE == 1 ]]; then
while read -r line; do
failed "IS_APACHESYMLINK" "Not a symlink: $line"
done <<< "$apacheFind"
else
failed "IS_APACHESYMLINK"
fi
fi
fi
}
# Check if there is real IP addresses in Allow/Deny directives (no trailing space, inline comments or so).
check_apacheipinallow() {
# Note: Replace "exit 1" by "print" in Perl code to debug it.
if is_installed apache2; then
grep -IrE "^[^#] *(Allow|Deny) from" /etc/apache2/ \
| grep -iv "from all" \
| grep -iv "env=" \
| perl -ne 'exit 1 unless (/from( [\da-f:.\/]+)+$/i)' \
|| failed "IS_APACHEIPINALLOW" "bad (Allow|Deny) directives in apache"
fi
}
# Check if default Apache configuration file for munin is absent (or empty or commented).
check_muninapacheconf() {
muninconf="/etc/apache2/conf.d/munin"
if is_installed apache2; then
test -e $muninconf && grep -vEq "^( |\t)*#" "$muninconf" \
&& failed "IS_MUNINAPACHECONF" "default munin configuration may be commented or disabled"
fi
}
# Check if default Apache configuration file for phpMyAdmin is absent (or empty or commented).
check_phpmyadminapacheconf() {
phpmyadminconf0="/etc/apache2/conf-available/phpmyadmin.conf"
phpmyadminconf1="/etc/apache2/conf-enabled/phpmyadmin.conf"
if is_installed apache2; then
test -e $phpmyadminconf0 && grep -vEq "^( |\t)*#" "$phpmyadminconf0" \
&& failed "IS_PHPMYADMINAPACHECONF" "default phpmyadmin configuration ($phpmyadminconf0) may be commented or disabled"
test -e $phpmyadminconf1 && grep -vEq "^( |\t)*#" "$phpmyadminconf1" \
&& failed "IS_PHPMYADMINAPACHECONF" "default phpmyadmin configuration ($phpmyadminconf1) may be commented or disabled"
fi
}
# Verification si le système doit redémarrer suite màj kernel.
check_kerneluptodate() {
if is_installed linux-image*; then
# shellcheck disable=SC2012
kernel_installed_at=$(date -d "$(ls --full-time -lcrt /boot | tail -n1 | awk '{print $6}')" +%s)
last_reboot_at=$(($(date +%s) - $(cut -f1 -d '.' /proc/uptime)))
if [ "$kernel_installed_at" -gt "$last_reboot_at" ]; then
failed "IS_KERNELUPTODATE" "machine is running an outdated kernel, reboot advised"
fi
fi
}
# Check if the server is running for more than a year.
check_uptime() {
if is_installed linux-image*; then
limit=$(date -d "now - 2 year" +%s)
last_reboot_at=$(($(date +%s) - $(cut -f1 -d '.' /proc/uptime)))
if [ "$limit" -gt "$last_reboot_at" ]; then
failed "IS_UPTIME" "machine has an uptime of more than 2 years, reboot on new kernel advised"
fi
fi
}
# Check if munin-node running and RRD files are up to date.
check_muninrunning() {
if ! pgrep munin-node >/dev/null; then
failed "IS_MUNINRUNNING" "Munin is not running"
elif [ -d "/var/lib/munin/" ] && [ -d "/var/cache/munin/" ]; then
limit=$(date +"%s" -d "now - 10 minutes")
if [ -n "$(find /var/lib/munin/ -name '*load-g.rrd')" ]; then
updated_at=$(stat -c "%Y" /var/lib/munin/*/*load-g.rrd |sort |tail -1)
[ "$limit" -gt "$updated_at" ] && failed "IS_MUNINRUNNING" "Munin load RRD has not been updated in the last 10 minutes"
else
failed "IS_MUNINRUNNING" "Munin is not installed properly (load RRD not found)"
fi
if [ -n "$(find /var/cache/munin/www/ -name 'load-day.png')" ]; then
updated_at=$(stat -c "%Y" /var/cache/munin/www/*/*/load-day.png |sort |tail -1)
grep -sq "^graph_strategy cron" /etc/munin/munin.conf && [ "$limit" -gt "$updated_at" ] && failed "IS_MUNINRUNNING" "Munin load PNG has not been updated in the last 10 minutes"
else
failed "IS_MUNINRUNNING" "Munin is not installed properly (load PNG not found)"
fi
else
failed "IS_MUNINRUNNING" "Munin is not installed properly (main directories are missing)"
fi
}
# Check if files in /home/backup/ are up-to-date
check_backupuptodate() {
backup_dir="/home/backup"
if [ -d "${backup_dir}" ]; then
if [ -n "$(ls -A ${backup_dir})" ]; then
find "${backup_dir}" -maxdepth 1 -type f | while read -r file; do
limit=$(date +"%s" -d "now - 2 day")
updated_at=$(stat -c "%Y" "$file")
if [ "$limit" -gt "$updated_at" ]; then
failed "IS_BACKUPUPTODATE" "$file has not been backed up"
test "${VERBOSE}" = 1 || break;
fi
done
else
failed "IS_BACKUPUPTODATE" "${backup_dir}/ is empty"
fi
else
failed "IS_BACKUPUPTODATE" "${backup_dir}/ is missing"
fi
}
check_etcgit() {
export GIT_DIR="/etc/.git" GIT_WORK_TREE="/etc"
git rev-parse --is-inside-work-tree > /dev/null 2>&1 \
|| failed "IS_ETCGIT" "/etc is not a git repository"
}
# Check if /etc/.git/ has read/write permissions for root only.
check_gitperms() {
GIT_DIR="/etc/.git"
if test -d $GIT_DIR; then
expected="700"
actual=$(stat -c "%a" $GIT_DIR)
[ "$expected" = "$actual" ] || failed "IS_GITPERMS" "$GIT_DIR must be $expected"
fi
}
# Check if no package has been upgraded since $limit.
check_notupgraded() {
last_upgrade=0
upgraded=false
for log in /var/log/dpkg.log*; do
if zgrep -qsm1 upgrade "$log"; then
# There is at least one upgrade
upgraded=true
break
fi
done
if $upgraded; then
last_upgrade=$(date +%s -d "$(zgrep -h upgrade /var/log/dpkg.log* | sort -n | tail -1 | cut -f1 -d ' ')")
fi
if grep -qs '^mailto="listupgrade-todo@' /etc/evolinux/listupgrade.cnf \
|| grep -qs -E '^[[:digit:]]+[[:space:]]+[[:digit:]]+[[:space:]]+[^\*]' /etc/cron.d/listupgrade; then
# Manual upgrade process
limit=$(date +%s -d "now - 180 days")
else
# Regular process
limit=$(date +%s -d "now - 90 days")
fi
install_date=0
if [ -d /var/log/installer ]; then
install_date=$(stat -c %Z /var/log/installer)
fi
# Check install_date if the system never received an upgrade
if [ "$last_upgrade" -eq 0 ]; then
[ "$install_date" -lt "$limit" ] && failed "IS_NOTUPGRADED" "The system has never been updated"
else
[ "$last_upgrade" -lt "$limit" ] && failed "IS_NOTUPGRADED" "The system hasn't been updated for too long"
fi
}
# Check if reserved blocks for root is at least 5% on every mounted partitions.
check_tune2fs_m5() {
min=5
parts=$(grep -E "ext(3|4)" /proc/mounts | cut -d ' ' -f1 | tr -s '\n' ' ')
FINDMNT_BIN=$(command -v findmnt)
for part in $parts; do
blockCount=$(dumpe2fs -h "$part" 2>/dev/null | grep -e "Block count:" | grep -Eo "[0-9]+")
# If buggy partition, skip it.
if [ -z "$blockCount" ]; then
continue
fi
reservedBlockCount=$(dumpe2fs -h "$part" 2>/dev/null | grep -e "Reserved block count:" | grep -Eo "[0-9]+")
# Use awk to have a rounded percentage
# python is slow, bash is unable and bc rounds weirdly
percentage=$(awk "BEGIN { pc=100*${reservedBlockCount}/${blockCount}; i=int(pc); print (pc-i<0.5)?i:i+1 }")
if [ "$percentage" -lt "${min}" ]; then
if [ -x "${FINDMNT_BIN}" ]; then
mount=$(${FINDMNT_BIN} --noheadings --first-only --output TARGET "${part}")
else
mount="unknown mount point"
fi
failed "IS_TUNE2FS_M5" "Partition ${part} (${mount}) has less than ${min}% reserved blocks (${percentage}%)"
fi
done
}
check_broadcomfirmware() {
LSPCI_BIN=$(command -v lspci)
if [ -x "${LSPCI_BIN}" ]; then
if ${LSPCI_BIN} | grep -q 'NetXtreme II'; then
{ is_installed firmware-bnx2 \
&& grep -q "^deb http://mirror.evolix.org/debian.* non-free" /etc/apt/sources.list;
} || failed "IS_BROADCOMFIRMWARE" "missing non-free repository"
fi
else
failed "IS_BROADCOMFIRMWARE" "lspci not found in ${PATH}"
fi
}
check_hardwareraidtool() {
LSPCI_BIN=$(command -v lspci)
if [ -x "${LSPCI_BIN}" ]; then
if ${LSPCI_BIN} | grep -q 'MegaRAID'; then
# shellcheck disable=SC2015
is_installed megacli && { is_installed megaclisas-status || is_installed megaraidsas-status; } \
|| failed "IS_HARDWARERAIDTOOL" "Mega tools not found"
fi
if ${LSPCI_BIN} | grep -q 'Hewlett-Packard Company Smart Array'; then
is_installed cciss-vol-status || failed "IS_HARDWARERAIDTOOL" "cciss-vol-status not installed"
fi
else
failed "IS_HARDWARERAIDTOOL" "lspci not found in ${PATH}"
fi
}
check_sql_backup() {
if (is_installed "mysql-server" || is_installed "mariadb-server"); then
# You could change the default path in /etc/evocheck.cf
SQL_BACKUP_PATH=${SQL_BACKUP_PATH:-"/home/backup/mysql.bak.gz"}
for backup_path in ${SQL_BACKUP_PATH}; do
if [ ! -f "${backup_path}" ]; then
failed "IS_SQL_BACKUP" "MySQL dump is missing (${backup_path})"
test "${VERBOSE}" = 1 || break
fi
done
fi
}
check_postgres_backup() {
if is_installed "postgresql-9*" || is_installed "postgresql-1*"; then
# If you use something like barman, you should disable this check
# You could change the default path in /etc/evocheck.cf
POSTGRES_BACKUP_PATH=${POSTGRES_BACKUP_PATH:-"/home/backup/pg.dump.bak*"}
for backup_path in ${POSTGRES_BACKUP_PATH}; do
if [ ! -f "${backup_path}" ]; then
failed "IS_POSTGRES_BACKUP" "PostgreSQL dump is missing (${backup_path})"
test "${VERBOSE}" = 1 || break
fi
done
fi
}
check_mongo_backup() {
if is_installed "mongodb-org-server"; then
# You could change the default path in /etc/evocheck.cf
MONGO_BACKUP_PATH=${MONGO_BACKUP_PATH:-"/home/backup/mongodump"}
if [ -d "$MONGO_BACKUP_PATH" ]; then
for file in "${MONGO_BACKUP_PATH}"/*/*.{json,bson}*; do
# Skip indexes file.
if ! [[ "$file" =~ indexes ]]; then
limit=$(date +"%s" -d "now - 2 day")
updated_at=$(stat -c "%Y" "$file")
if [ -f "$file" ] && [ "$limit" -gt "$updated_at" ]; then
failed "IS_MONGO_BACKUP" "MongoDB hasn't been dumped for more than 2 days"
break
fi
fi
done
else
failed "IS_MONGO_BACKUP" "MongoDB dump directory is missing (${MONGO_BACKUP_PATH})"
fi
fi
}
check_ldap_backup() {
if is_installed slapd; then
# You could change the default path in /etc/evocheck.cf
LDAP_BACKUP_PATH=${LDAP_BACKUP_PATH:-"/home/backup/ldap.bak"}
test -f "$LDAP_BACKUP_PATH" || failed "IS_LDAP_BACKUP" "LDAP dump is missing (${LDAP_BACKUP_PATH})"
fi
}
check_redis_backup() {
if is_installed redis-server; then
# You could change the default path in /etc/evocheck.cf
# REDIS_BACKUP_PATH may contain space-separated paths, example:
# REDIS_BACKUP_PATH='/home/backup/redis-instance1/dump.rdb /home/backup/redis-instance2/dump.rdb'
REDIS_BACKUP_PATH=${REDIS_BACKUP_PATH:-"/home/backup/redis/dump.rdb"}
for file in ${REDIS_BACKUP_PATH}; do
test -f "${file}" || failed "IS_REDIS_BACKUP" "Redis dump is missing (${file})"
done
fi
}
check_elastic_backup() {
if is_installed elasticsearch; then
# You could change the default path in /etc/evocheck.cf
ELASTIC_BACKUP_PATH=${ELASTIC_BACKUP_PATH:-"/home/backup-elasticsearch"}
test -d "$ELASTIC_BACKUP_PATH" || failed "IS_ELASTIC_BACKUP" "Elastic snapshot is missing (${ELASTIC_BACKUP_PATH})"
fi
}
check_duplicate_fs_label() {
# Do it only if thereis blkid binary
BLKID_BIN=$(command -v blkid)
if [ -n "$BLKID_BIN" ]; then
tmpFile=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.duplicate_fs_label.XXXXX")
files_to_cleanup="${files_to_cleanup} ${tmpFile}"
parts=$($BLKID_BIN -c /dev/null | grep -ve raid_member -e EFI_SYSPART | grep -Eo ' LABEL=".*"' | cut -d'"' -f2)
for part in $parts; do
echo "$part" >> "$tmpFile"
done
tmpOutput=$(sort < "$tmpFile" | uniq -d)
# If there is no duplicate, uniq will have no output
# So, if $tmpOutput is not null, there is a duplicate
if [ -n "$tmpOutput" ]; then
# shellcheck disable=SC2086
labels=$(echo -n $tmpOutput | tr '\n' ' ')
failed "IS_DUPLICATE_FS_LABEL" "Duplicate labels: $labels"
fi
else
failed "IS_DUPLICATE_FS_LABEL" "blkid not found in ${PATH}"
fi
}
check_evolix_user() {
grep -q -E "^evolix:" /etc/passwd \
&& failed "IS_EVOLIX_USER" "evolix user should be deleted, used only for install"
}
check_old_home_dir() {
homeDir=${homeDir:-/home}
for dir in "$homeDir"/*; do
statResult=$(stat -c "%n has owner %u resolved as %U" "$dir" \
| grep -Eve '.bak' -e '\.[0-9]{2}-[0-9]{2}-[0-9]{4}' \
| grep "UNKNOWN")
# There is at least one dir matching
if [[ -n "$statResult" ]]; then
failed "IS_OLD_HOME_DIR" "$statResult"
test "${VERBOSE}" = 1 || break
fi
done
}
check_tmp_1777() {
actual=$(stat --format "%a" /tmp)
expected="1777"
test "$expected" = "$actual" || failed "IS_TMP_1777" "/tmp must be $expected"
}
check_root_0700() {
actual=$(stat --format "%a" /root)
expected="700"
test "$expected" = "$actual" || failed "IS_ROOT_0700" "/root must be $expected"
}
check_usrsharescripts() {
actual=$(stat --format "%a" /usr/share/scripts)
expected="700"
test "$expected" = "$actual" || failed "IS_USRSHARESCRIPTS" "/usr/share/scripts must be $expected"
}
check_sshpermitrootno() {
# shellcheck disable=SC2086
if ! (sshd -T 2> /dev/null | grep -qi 'permitrootlogin no'); then
failed "IS_SSHPERMITROOTNO" "PermitRoot should be set to no"
fi
}
check_evomaintenanceusers() {
if [ -f /etc/sudoers.d/evolinux ]; then
sudoers="/etc/sudoers.d/evolinux"
else
sudoers="/etc/sudoers"
fi
# combine users from User_Alias and sudo group
users=$({ grep "^User_Alias *ADMIN" $sudoers | cut -d= -f2 | tr -d " "; grep "^sudo" /etc/group | cut -d: -f 4; } | tr "," "\n" | sort -u)
for user in $users; do
user_home=$(getent passwd "$user" | cut -d: -f6)
if [ -n "$user_home" ] && [ -d "$user_home" ]; then
if ! grep -qs "^trap.*sudo.*evomaintenance.sh" "${user_home}"/.*profile; then
failed "IS_EVOMAINTENANCEUSERS" "${user} doesn't have an evomaintenance trap"
test "${VERBOSE}" = 1 || break
fi
fi
done
}
check_evomaintenanceconf() {
f=/etc/evomaintenance.cf
if [ -e "$f" ]; then
perms=$(stat -c "%a" $f)
test "$perms" = "600" || failed "IS_EVOMAINTENANCECONF" "Wrong permissions on \`$f' ($perms instead of 600)"
{ grep "^export PGPASSWORD" $f | grep -qv "your-passwd" \
&& grep "^PGDB" $f | grep -qv "your-db" \
&& grep "^PGTABLE" $f | grep -qv "your-table" \
&& grep "^PGHOST" $f | grep -qv "your-pg-host" \
&& grep "^FROM" $f | grep -qv "jdoe@example.com" \
&& grep "^FULLFROM" $f | grep -qv "John Doe <jdoe@example.com>" \
&& grep "^URGENCYFROM" $f | grep -qv "mama.doe@example.com" \
&& grep "^URGENCYTEL" $f | grep -qv "06.00.00.00.00" \
&& grep "^REALM" $f | grep -qv "example.com"
} || failed "IS_EVOMAINTENANCECONF" "evomaintenance is not correctly configured"
else
failed "IS_EVOMAINTENANCECONF" "Configuration file \`$f' is missing"
fi
}
check_privatekeyworldreadable() {
# a simple globbing fails if directory is empty
if [ -n "$(ls -A /etc/ssl/private/)" ]; then
for f in /etc/ssl/private/*; do
perms=$(stat -L -c "%a" "$f")
if [ "${perms: -1}" != 0 ]; then
failed "IS_PRIVKEYWOLRDREADABLE" "$f is world-readable"
test "${VERBOSE}" = 1 || break
fi
done
fi
}
check_evobackup_incs() {
if is_installed bkctld; then
bkctld_cron_file=${bkctld_cron_file:-/etc/cron.d/bkctld}
if [ -f "${bkctld_cron_file}" ]; then
root_crontab=$(grep -v "^#" "${bkctld_cron_file}")
echo "${root_crontab}" | grep -q "bkctld inc" || failed "IS_EVOBACKUP_INCS" "\`bkctld inc' is missing in ${bkctld_cron_file}"
echo "${root_crontab}" | grep -qE "(check-incs.sh|bkctld check-incs)" || failed "IS_EVOBACKUP_INCS" "\`check-incs.sh' is missing in ${bkctld_cron_file}"
else
failed "IS_EVOBACKUP_INCS" "Crontab \`${bkctld_cron_file}' is missing"
fi
fi
}
check_osprober() {
if is_installed os-prober qemu-kvm; then
failed "IS_OSPROBER" \
"Removal of os-prober package is recommended as it can cause serious issue on KVM server"
fi
}
check_apt_valid_until() {
aptvalidFile="/etc/apt/apt.conf.d/99no-check-valid-until"
aptvalidText="Acquire::Check-Valid-Until no;"
if grep -qs "archive.debian.org" /etc/apt/sources.list /etc/apt/sources.list.d/*; then
if ! grep -qs "$aptvalidText" /etc/apt/apt.conf.d/*; then
failed "IS_APT_VALID_UNTIL" \
"As you use archive.mirror.org you need ${aptvalidFile}: ${aptvalidText}"
fi
fi
}
check_chrooted_binary_uptodate() {
# list of processes to check
process_list="sshd"
for process_name in ${process_list}; do
# what is the binary path?
original_bin=$(command -v "${process_name}")
for pid in $(pgrep ${process_name}); do
process_bin=$(realpath "/proc/${pid}/exe")
# Is the process chrooted?
real_root=$(realpath "/proc/${pid}/root")
if [ "${real_root}" != "/" ]; then
chrooted_md5=$(md5sum "${process_bin}" | cut -f 1 -d ' ')
original_md5=$(md5sum "${original_bin}" | cut -f 1 -d ' ')
# compare md5 checksums
if [ "$original_md5" != "$chrooted_md5" ]; then
failed "IS_CHROOTED_BINARY_UPTODATE" "${process_bin} (${pid}) is different than ${original_bin}."
test "${VERBOSE}" = 1 || break
fi
fi
done
done
}
check_lxc_container_resolv_conf() {
if is_installed lxc; then
container_list=$(lxc-ls)
current_resolvers=$(grep nameserver /etc/resolv.conf | sed 's/nameserver//g' )
for container in $container_list; do
if [ -f "/var/lib/lxc/${container}/rootfs/etc/resolv.conf" ]; then
while read -r resolver; do
if ! grep -qE "^nameserver\s+${resolver}" "/var/lib/lxc/${container}/rootfs/etc/resolv.conf"; then
failed "IS_LXC_CONTAINER_RESOLV_CONF" "resolv.conf miss-match beween host and container : missing nameserver ${resolver} in container ${container} resolv.conf"
fi
done <<< "${current_resolvers}"
else
failed "IS_LXC_CONTAINER_RESOLV_CONF" "resolv.conf missing in container ${container}"
fi
done
fi
}
download_versions() {
local file
file=${1:-}
## The file is supposed to list programs : each on a line, then its latest version number
## Examples:
# evoacme 21.06
# evomaintenance 0.6.4
versions_url="https://upgrades.evolix.org/versions-${DEBIAN_RELEASE}"
# fetch timeout, in seconds
timeout=10
if command -v curl > /dev/null; then
curl --max-time ${timeout} --fail --silent --output "${versions_file}" "${versions_url}"
elif command -v wget > /dev/null; then
wget --timeout=${timeout} --quiet "${versions_url}" -O "${versions_file}"
elif command -v GET; then
GET -t ${timeout}s "${versions_url}" > "${versions_file}"
else
failed "IS_CHECK_VERSIONS" "failed to find curl, wget or GET"
fi
test "$?" -eq 0 || failed "IS_CHECK_VERSIONS" "failed to download ${versions_url} to ${versions_file}"
}
get_command() {
local program
program=${1:-}
case "${program}" in
## Special cases where the program name is different than the command name
evocheck) echo "${0}" ;;
evomaintenance) command -v "evomaintenance.sh" ;;
listupgrade) command -v "evolistupgrade.sh" ;;
old-kernel-autoremoval) command -v "old-kernel-autoremoval.sh" ;;
mysql-queries-killer) command -v "mysql-queries-killer.sh" ;;
minifirewall) echo "/etc/init.d/minifirewall" ;;
## General case, where the program name is the same as the command name
*) command -v "${program}" ;;
esac
}
get_version() {
local program
local command
program=${1:-}
command=${2:-}
case "${program}" in
## Special case if `command --version => 'command` is not the standard way to get the version
# my_command)
# /path/to/my_command --get-version
# ;;
add-vm)
grep '^VERSION=' "${command}" | head -1 | cut -d '=' -f 2
;;
minifirewall)
${command} version | head -1 | cut -d ' ' -f 3
;;
## Let's try the --version flag before falling back to grep for the constant
kvmstats)
if ${command} --version > /dev/null 2> /dev/null; then
${command} --version 2> /dev/null | head -1 | cut -d ' ' -f 3
else
grep '^VERSION=' "${command}" | head -1 | cut -d '=' -f 2
fi
;;
## General case to get the version
*) ${command} --version 2> /dev/null | head -1 | cut -d ' ' -f 3 ;;
esac
}
check_version() {
local program
local expected_version
program=${1:-}
expected_version=${2:-}
command=$(get_command "${program}")
if [ -n "${command}" ]; then
# shellcheck disable=SC2086
actual_version=$(get_version "${program}" "${command}")
# printf "program:%s expected:%s actual:%s\n" "${program}" "${expected_version}" "${actual_version}"
if [ -z "${actual_version}" ]; then
failed "IS_CHECK_VERSIONS" "failed to lookup actual version of ${program}"
elif dpkg --compare-versions "${actual_version}" lt "${expected_version}"; then
failed "IS_CHECK_VERSIONS" "${program} version ${actual_version} is older than expected version ${expected_version}"
elif dpkg --compare-versions "${actual_version}" gt "${expected_version}"; then
failed "IS_CHECK_VERSIONS" "${program} version ${actual_version} is newer than expected version ${expected_version}, you should update your index."
else
: # Version check OK
fi
fi
}
add_to_path() {
local new_path
new_path=${1:-}
echo "$PATH" | grep -qF "${new_path}" || export PATH="${PATH}:${new_path}"
}
check_versions() {
versions_file=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.versions.XXXXX")
files_to_cleanup="${files_to_cleanup} ${versions_file}"
download_versions "${versions_file}"
add_to_path "/usr/share/scripts"
grep -v '^ *#' < "${versions_file}" | while IFS= read -r line; do
local program
local version
program=$(echo "${line}" | cut -d ' ' -f 1)
version=$(echo "${line}" | cut -d ' ' -f 2)
if [ -n "${program}" ]; then
if [ -n "${version}" ]; then
check_version "${program}" "${version}"
else
failed "IS_CHECK_VERSIONS" "failed to lookup expected version for ${program}"
fi
fi
done
}
main() {
# Default return code : 0 = no error
RC=0
# Detect operating system name, version and release
detect_os
main_output_file=$(mktemp --tmpdir="${TMPDIR:-/tmp}" "evocheck.main.XXXXX")
files_to_cleanup="${files_to_cleanup} ${main_output_file}"
test "${IS_TMP_1777:=1}" = 1 && check_tmp_1777
test "${IS_ROOT_0700:=1}" = 1 && check_root_0700
test "${IS_USRSHARESCRIPTS:=1}" = 1 && check_usrsharescripts
test "${IS_SSHPERMITROOTNO:=1}" = 1 && check_sshpermitrootno
test "${IS_EVOMAINTENANCEUSERS:=1}" = 1 && check_evomaintenanceusers
# Verification de la configuration d'evomaintenance
test "${IS_EVOMAINTENANCECONF:=1}" = 1 && check_evomaintenanceconf
test "${IS_PRIVKEYWOLRDREADABLE:=1}" = 1 && check_privatekeyworldreadable
test "${IS_LSBRELEASE:=1}" = 1 && check_lsbrelease
test "${IS_DPKGWARNING:=1}" = 1 && check_dpkgwarning
test "${IS_NRPEPOSTFIX:=1}" = 1 && check_nrpepostfix
test "${IS_MODSECURITY:=1}" = 1 && check_modsecurity
test "${IS_CUSTOMSUDOERS:=1}" = 1 && check_customsudoers
test "${IS_VARTMPFS:=1}" = 1 && check_vartmpfs
test "${IS_SERVEURBASE:=1}" = 1 && check_serveurbase
test "${IS_LOGROTATECONF:=1}" = 1 && check_logrotateconf
test "${IS_SYSLOGCONF:=1}" = 1 && check_syslogconf
test "${IS_DEBIANSECURITY:=1}" = 1 && check_debiansecurity
test "${IS_APTITUDEONLY:=1}" = 1 && check_aptitudeonly
test "${IS_APTICRON:=0}" = 1 && check_apticron
test "${IS_USRRO:=1}" = 1 && check_usrro
test "${IS_TMPNOEXEC:=1}" = 1 && check_tmpnoexec
test "${IS_MOUNT_FSTAB:=1}" = 1 && check_mountfstab
test "${IS_LISTCHANGESCONF:=1}" = 1 && check_listchangesconf
test "${IS_CUSTOMCRONTAB:=1}" = 1 && check_customcrontab
test "${IS_SSHALLOWUSERS:=1}" = 1 && check_sshallowusers
test "${IS_DISKPERF:=0}" = 1 && check_diskperf
test "${IS_TMOUTPROFILE:=1}" = 1 && check_tmoutprofile
test "${IS_ALERT5BOOT:=1}" = 1 && check_alert5boot
test "${IS_ALERT5MINIFW:=1}" = 1 && check_alert5minifw
test "${IS_ALERT5MINIFW:=1}" = 1 && test "${IS_MINIFW:=1}" = 1 && check_minifw
test "${IS_NRPEPERMS:=1}" = 1 && check_nrpeperms
test "${IS_MINIFWPERMS:=1}" = 1 && check_minifwperms
test "${IS_NRPEDISKS:=0}" = 1 && check_nrpedisks
test "${IS_NRPEPID:=1}" = 1 && check_nrpepid
test "${IS_GRSECPROCS:=1}" = 1 && check_grsecprocs
test "${IS_APACHEMUNIN:=1}" = 1 && check_apachemunin
test "${IS_MYSQLUTILS:=1}" = 1 && check_mysqlutils
test "${IS_RAIDSOFT:=1}" = 1 && check_raidsoft
test "${IS_AWSTATSLOGFORMAT:=1}" = 1 && check_awstatslogformat
test "${IS_MUNINLOGROTATE:=1}" = 1 && check_muninlogrotate
test "${IS_SQUID:=1}" = 1 && check_squid
test "${IS_EVOMAINTENANCE_FW:=1}" = 1 && check_evomaintenance_fw
test "${IS_MODDEFLATE:=1}" = 1 && check_moddeflate
test "${IS_LOG2MAILRUNNING:=1}" = 1 && check_log2mailrunning
test "${IS_LOG2MAILAPACHE:=1}" = 1 && check_log2mailapache
test "${IS_LOG2MAILMYSQL:=1}" = 1 && check_log2mailmysql
test "${IS_LOG2MAILSQUID:=1}" = 1 && check_log2mailsquid
test "${IS_BINDCHROOT:=1}" = 1 && check_bindchroot
test "${IS_NETWORK_INTERFACES:=1}" = 1 && check_network_interfaces
test "${IS_AUTOIF:=1}" = 1 && check_autoif
test "${IS_INTERFACESGW:=1}" = 1 && check_interfacesgw
test "${IS_EVOBACKUP:=1}" = 1 && check_evobackup
test "${IS_EVOBACKUP_EXCLUDE_MOUNT:=1}" = 1 && check_evobackup_exclude_mount
test "${IS_USERLOGROTATE:=1}" = 1 && check_userlogrotate
test "${IS_APACHECTL:=1}" = 1 && check_apachectl
test "${IS_APACHESYMLINK:=1}" = 1 && check_apachesymlink
test "${IS_APACHEIPINALLOW:=1}" = 1 && check_apacheipinallow
test "${IS_MUNINAPACHECONF:=1}" = 1 && check_muninapacheconf
test "${IS_PHPMYADMINAPACHECONF:=1}" = 1 && check_phpmyadminapacheconf
test "${IS_KERNELUPTODATE:=1}" = 1 && check_kerneluptodate
test "${IS_UPTIME:=1}" = 1 && check_uptime
test "${IS_MUNINRUNNING:=1}" = 1 && check_muninrunning
test "${IS_BACKUPUPTODATE:=1}" = 1 && check_backupuptodate
test "${IS_ETCGIT:=1}" = 1 && check_etcgit
test "${IS_GITPERMS:=1}" = 1 && check_gitperms
test "${IS_NOTUPGRADED:=1}" = 1 && check_notupgraded
test "${IS_TUNE2FS_M5:=1}" = 1 && check_tune2fs_m5
test "${IS_BROADCOMFIRMWARE:=1}" = 1 && check_broadcomfirmware
test "${IS_HARDWARERAIDTOOL:=1}" = 1 && check_hardwareraidtool
test "${IS_SQL_BACKUP:=1}" = 1 && check_sql_backup
test "${IS_POSTGRES_BACKUP:=1}" = 1 && check_postgres_backup
test "${IS_MONGO_BACKUP:=1}" = 1 && check_mongo_backup
test "${IS_LDAP_BACKUP:=1}" = 1 && check_ldap_backup
test "${IS_REDIS_BACKUP:=1}" = 1 && check_redis_backup
test "${IS_ELASTIC_BACKUP:=1}" = 1 && check_elastic_backup
test "${IS_DUPLICATE_FS_LABEL:=1}" = 1 && check_duplicate_fs_label
test "${IS_EVOLIX_USER:=1}" = 1 && check_evolix_user
test "${IS_OLD_HOME_DIR:=0}" = 1 && check_old_home_dir
test "${IS_EVOBACKUP_INCS:=1}" = 1 && check_evobackup_incs
test "${IS_OSPROBER:=1}" = 1 && check_osprober
test "${IS_APT_VALID_UNTIL:=1}" = 1 && check_apt_valid_until
test "${IS_CHROOTED_BINARY_UPTODATE:=1}" = 1 && check_chrooted_binary_uptodate
test "${IS_CHECK_VERSIONS:=1}" = 1 && check_versions
if [ -f "${main_output_file}" ]; then
lines_found=$(wc -l < "${main_output_file}")
# shellcheck disable=SC2086
if [ ${lines_found} -gt 0 ]; then
cat "${main_output_file}" 2>&1
fi
fi
exit ${RC}
}
cleanup_temp_files() {
# shellcheck disable=SC2086
rm -f ${files_to_cleanup}
}
PROGNAME=$(basename "$0")
# shellcheck disable=SC2034
readonly PROGNAME
# shellcheck disable=SC2124
ARGS=$@
readonly ARGS
# Disable LANG*
export LANG=C
export LANGUAGE=C
files_to_cleanup=""
# shellcheck disable=SC2064
trap cleanup_temp_files 0
# Source configuration file
# shellcheck disable=SC1091
test -f /etc/evocheck.cf && . /etc/evocheck.cf
# Parse options
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
while :; do
case $1 in
-h|-\?|--help)
show_help
exit 0
;;
--version)
show_version
exit 0
;;
--cron)
IS_KERNELUPTODATE=0
IS_UPTIME=0
IS_MELTDOWN_SPECTRE=0
IS_CHECK_VERSIONS=0
IS_NETWORKING_SERVICE=0
;;
-v|--verbose)
VERBOSE=1
;;
-q|--quiet)
QUIET=1
VERBOSE=0
;;
--)
# End of all options.
shift
break
;;
-?*|[[:alnum:]]*)
# ignore unknown options
if [ "${QUIET}" != 1 ]; then
printf 'WARN: Unknown option (ignored): %s\n' "$1" >&2
fi
;;
*)
# Default case: If no more options then break out of the loop.
break
;;
esac
shift
done
# shellcheck disable=SC2086
main ${ARGS}

View File

@ -7,174 +7,230 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
### Changed
- check_evobackup_exclude_mount: skip if --one-file-system is used, and exclude scripts without Rsync command
- check_backupuptodate: use find with --max-depth=1 to limit the number of evaluated files
- check_sshpermitrootno: do not display sshd errors
### Fixed
### Removed
### Security
## [23.06] - 2023-06-05
### Added
* Log output and runtime config to /var/log/evocheck.log.
* check_mountfstab and check_mount: make sure all mounted partitions are in fstab and all partitions in fstab are mounted
### Fixed
* check_carpadvbase and check_carppreempt: fixed indentation
* check_mount: removed useless echo
### Changed
* check_evobackup: zzz_evobackup is now executed with bash
## [23.02] - 2023-02-10
### Fixed
* Release with the correct version number.
## [22.12] - 2023-02-10
### Changed
* Replaced check_sudomaint with check_doasmaint because evomaintenance is used with doas, not with sudo
### Fixed
* check_history: escape $HOME variable
* check_pkgmirror: fix openbsd mirror
### Removed
* check_wheel: wheel group mustn't be sudo because we use the evolinux-sudo group
## [22.11] - 2022-11-28
### Changed
* check_pkgmirror: use our own openbsd mirror
## [22.10] - 2022-10-14
### Changed
* check_evobackup_exclude_mount: skip if --one-file-system is used, and exclude scripts without Rsync command
* check_backupuptodate: use find with --max-depth=1 to limit the number of evaluated files
* check_sshpermitrootno: do not display sshd errors
* check_ntp: comply with ntp configuration change on EvoBSD
## [22.08] - 2022-08-04
### Fixed
- Fixed check_sshpermitrootno to check real configuration
* Fixed check_sshpermitrootno to check real configuration
## [22.06] - 2022-06-16
### Changed
- Fixed various shellcheck violations
- Added a function to cleanup files at once instead of using multiple trap rm
* Fixed various shellcheck violations
* Added a function to cleanup files at once instead of using multiple trap rm
## [22.04] - 2022-04-13
### Added
- Added check_root_user: make sure that root user does not have a password
* Added check_root_user: make sure that root user does not have a password
## [22.03] - 2022-03-10
### Added
- check_evomaintenanceconf: check existence and rights of evomaintenance conf file
- Added check_nrpeopensmtpd to ensure that opensmtpd is used for mailq nrpe check
- Added check_sshallowusers to ensure that AllowUsers or AllowGroups directive is present in sshd_config
- Added check_evobackup_exclude_mount to ensure that NFS mounts are excluded from backup
- Added check_etcgit to ensure that /etc is a git repository
- Added check_evolinuxsudogroup to ensure that evolinux-sudo is properly configured in sudo if group exist
- Added check_bind9munin to ensure that a plugin for bind is configured when munin is installed
- Added check_evolix_user to ensure that evolix user does not exist
- Added check_versions and its functions (download_versions, get_command, get_version, check_version, add_to_path) to ensure that custom scripts are up to date
* check_evomaintenanceconf: check existence and rights of evomaintenance conf file
* Added check_nrpeopensmtpd to ensure that opensmtpd is used for mailq nrpe check
* Added check_sshallowusers to ensure that AllowUsers or AllowGroups directive is present in sshd_config
* Added check_evobackup_exclude_mount to ensure that NFS mounts are excluded from backup
* Added check_etcgit to ensure that /etc is a git repository
* Added check_evolinuxsudogroup to ensure that evolinux-sudo is properly configured in sudo if group exist
* Added check_bind9munin to ensure that a plugin for bind is configured when munin is installed
* Added check_evolix_user to ensure that evolix user does not exist
* Added check_versions and its functions (download_versions, get_command, get_version, check_version, add_to_path) to ensure that custom scripts are up to date
### Changed
- Overall improvement of evocheck: reordering, splitting version and help options, adding comments, developping some functions so they are more comprehensible
- Improved check_umasksudoers to have a more complete grep
- Updated check_history to reflect the new HISTSIZE value
- Renamed check_tmp1777 and check_root0700 respectively to check_tmp_1777 and check_root_0700
- Improved check_tmp_1777, check_root_0700, check_usrsharescripts in the way the folders rights are checked
* Overall improvement of evocheck: reordering, splitting version and help options, adding comments, developping some functions so they are more comprehensible
* Improved check_umasksudoers to have a more complete grep
* Updated check_history to reflect the new HISTSIZE value
* Renamed check_tmp1777 and check_root0700 respectively to check_tmp_1777 and check_root_0700
* Improved check_tmp_1777, check_root_0700, check_usrsharescripts in the way the folders rights are checked
### Fixed
- Fixed check_uptime: it didn't work at all, and tried to get uptime in the wrong way
- Fixed check_evomaintenanceusers: sudo is not used for the evomaintenance trap, doas is ; and users were not found the better way
* Fixed check_uptime: it didn't work at all, and tried to get uptime in the wrong way
* Fixed check_evomaintenanceusers: sudo is not used for the evomaintenance trap, doas is ; and users were not found the better way
### Removed
- Removed empty check_pfcustom
* Removed empty check_pfcustom
## [21.10] - 2021-10-07
### Fixed
- Fixed check_tmoutprofile: syntax error on if/else/fi test
* Fixed check_tmoutprofile: syntax error on if/else/fi test
## [21.09] - 2021-09-17
### Changed
- Changed version numbering to use year.month and be capable to know the age of the script
* Changed version numbering to use year.month and be capable to know the age of the script
### Fixed
- Fixed check_tmoutprofile: Add "if" to check if file exists
* Fixed check_tmoutprofile: Add "if" to check if file exists
## [6.9.1] - 2021-07-23
### Changed
- Renamed check_advskew, check_preempt, check_advbase and their alert to add "carp" in them
* Renamed check_advskew, check_preempt, check_advbase and their alert to add "carp" in them
## [6.9.0] - 2021-07-16
### Added
- Add check_advskew: convention for CARP interfaces. CARP in master state must have advskew parameter between 1 and 50, CARP in backup state must have advskew parameter between 100 and 150, preventing a configuration error with the same value for master and backup
* Add check_advskew: convention for CARP interfaces. CARP in master state must have advskew parameter between 1 and 50, CARP in backup state must have advskew parameter between 100 and 150, preventing a configuration error with the same value for master and backup
## [6.8.0] - 2020-10-23
### Fixed
- Fix check_noatime: do not take into account commented entry in fstab
* Fix check_noatime: do not take into account commented entry in fstab
## [6.7.7] - 2020-10-22
### Added
- Add check_openvpncronlog: a cron is needed to rotate logs, because a restart of OpenVPN would be needed with the use of newsyslog to rotate logs
* Add check_openvpncronlog: a cron is needed to rotate logs, because a restart of OpenVPN would be needed with the use of newsyslog to rotate logs
### Fixed
- Fix check_uptodate: properly check that syspatch exists
- Fix check_raidok: the same device could be displayed multiple times
* Fix check_uptodate: properly check that syspatch exists
* Fix check_raidok: the same device could be displayed multiple times
## [6.7.6] - 2020-10-15
### Added
- Add check_noatime - Check that all ffs partitions are mounted with the noatime option
* Add check_noatime - Check that all ffs partitions are mounted with the noatime option
### Fixed
- Fix check_softdep - We now check the number of ffs partitions and we compare it to the number of softdep options currently there
* Fix check_softdep - We now check the number of ffs partitions and we compare it to the number of softdep options currently there
## [6.7.5] - 2020-10-09
### Fixed
- Fix check_cronpath - Do not check PATH=XXX but only XXX because XXX can also be in quotes (PATH="XXX" would not be matched)
* Fix check_cronpath - Do not check PATH=XXX but only XXX because XXX can also be in quotes (PATH="XXX" would not be matched)
## [6.7.4] - 2020-08-04
### Added
- Add check_backupuptodate - Check that /home/backup is not older than 2 days
* Add check_backupuptodate - Check that /home/backup is not older than 2 days
## [6.7.3] - 2020-07-23
### Added
- Add check_ntp - Check the ntpd configuration
* Add check_ntp - Check the ntpd configuration
### Fixed
- Fix check_defaultroute - We need to check if the /etc/mygate file exists before comparing it
* Fix check_defaultroute - We need to check if the /etc/mygate file exists before comparing it
### Removed
- Removed check_postgresql - Deprecated since we now use an API
* Removed check_postgresql - Deprecated since we now use an API
## [6.7.2] - 2020-07-22
### Added
- Add check_defaultroute function - Make sure the default route in /etc/mygate file is the same that the one currently used
* Add check_defaultroute function - Make sure the default route in /etc/mygate file is the same that the one currently used
## [6.7.1] - 2020-07-15
### Fixed
- Fix check_customsyslog - We have to check whether EvoBSD is present in newsyslog.conf file
- Fix check_sudomaint function - ADMIN group does not exist anymore, we now check that the wheel group has NOPASSWD to run the evomaintenance command alias
- Fix check_advbase - We want the evocheck advbase function output to be uniq
* Fix check_customsyslog - We have to check whether EvoBSD is present in newsyslog.conf file
* Fix check_sudomaint function - ADMIN group does not exist anymore, we now check that the wheel group has NOPASSWD to run the evomaintenance command alias
* Fix check_advbase - We want the evocheck advbase function output to be uniq
## [6.6.2] - 2020-04-27
### Added
- Add check_sync function - If a server is a Carp member we check whether the sync.sh script is present or not
- Add check_pfenabled function - We make sure PF is enabled
- Add check_uptodate function - Use syspatch(8) to check if security updates are available
* Add check_sync function - If a server is a Carp member we check whether the sync.sh script is present or not
* Add check_pfenabled function - We make sure PF is enabled
* Add check_uptodate function - Use syspatch(8) to check if security updates are available
### Changed
- Remove check_oldhomedir - This information is irrelevant since we always keep home directories of former sysadmins
- Now use a version-naming scheme based on OpenBSD's one
* Remove check_oldhomedir - This information is irrelevant since we always keep home directories of former sysadmins
* Now use a version-naming scheme based on OpenBSD's one
## [6.6.1] - 2020-04-21
### Changed
- Rewrite if statements to functions
- Add a main function
- New help message
* Rewrite if statements to functions
* Add a main function
* New help message

View File

@ -3,7 +3,7 @@
# EvoCheck
# Script to verify compliance of an OpenBSD server powered by Evolix
readonly VERSION="22.08"
readonly VERSION="23.06"
# base functions
@ -51,6 +51,17 @@ is_installed(){
# logging
log() {
date=$(/bin/date +"${DATE_FORMAT}")
if [ "${1}" != '' ]; then
printf "[%s] %s: %s\\n" "$date" "${PROGNAME}" "${1}" >> "${LOGFILE}"
else
while read line; do
printf "[%s] %s: %s\\n" "$date" "${PROGNAME}" "${line}" >> "${LOGFILE}"
done < /dev/stdin
fi
}
failed() {
check_name=$1
shift
@ -64,6 +75,9 @@ failed() {
printf "%s FAILED!\n" "${check_name}" 2>&1
fi
fi
# Always log verbose
log "${check_name} FAILED! ${check_comments}"
}
# check functions
@ -104,9 +118,9 @@ check_raidok(){
}
check_evobackup(){
if [ -f /etc/daily.local ]; then
grep -qE "^sh /usr/share/scripts/zzz_evobackup" /etc/daily.local || failed "IS_EVOBACKUP" "Make sure 'sh /usr/share/scripts/zzz_evobackup' is present and activated in /etc/daily.local"
grep -qE "^(ba)?sh /usr/share/scripts/zzz_evobackup" /etc/daily.local || failed "IS_EVOBACKUP" "Make sure 'bash or sh /usr/share/scripts/zzz_evobackup' is present and activated in /etc/daily.local"
else
failed "IS_EVOBACKUP" "Make sure /etc/daily.local exists and 'sh /usr/share/scripts/zzz_evobackup' is present and activated in /etc/daily.local"
failed "IS_EVOBACKUP" "Make sure /etc/daily.local exists and 'bash or sh /usr/share/scripts/zzz_evobackup' is present and activated in /etc/daily.local"
fi
}
check_uptodate(){
@ -188,18 +202,13 @@ check_pfenabled(){
failed "IS_PFENABLED" "PF is disabled! Make sure pf=NO is absent from /etc/rc.conf.local and carefully run pfctl -e"
fi
}
check_wheel(){
if [ -f /etc/sudoers ]; then
grep -qE "^%wheel.*$" /etc/sudoers || failed "IS_WHEEL" ""
fi
}
check_pkgmirror(){
grep -qE "^https://cdn\.openbsd\.org/pub/OpenBSD" /etc/installurl || failed "IS_PKGMIRROR" "Check whether the right repo is present in the /etc/installurl file"
grep -qE "^https?://ftp\.evolix\.org/openbsd" /etc/installurl || failed "IS_PKGMIRROR" "Check whether the right repo is present in the /etc/installurl file"
}
check_history(){
file=/root/.profile
# shellcheck disable=SC2015
grep -qE "^HISTFILE=\$HOME/.histfile" $file && grep -qE "^export HISTSIZE=100000" $file || failed "IS_HISTORY" "Make sure both 'HISTFILE=$HOME/.histfile' and 'export HISTSIZE=100000' are present in /root/.profile"
grep -qE "^HISTFILE=\$HOME/.histfile" $file && grep -qE "^export HISTSIZE=100000" $file || failed "IS_HISTORY" "Make sure both 'HISTFILE=\$HOME/.histfile' and 'export HISTSIZE=100000' are present in /root/.profile"
}
check_vim(){
if ! is_installed vim; then
@ -212,12 +221,9 @@ check_ttyc0secure(){
check_customsyslog(){
grep -q EvoBSD /etc/newsyslog.conf || failed "IS_CUSTOMSYSLOG" ""
}
check_sudomaint(){
file=/etc/sudoers
check_doasmaint(){
# shellcheck disable=SC2015
grep -q "Cmnd_Alias MAINT = /usr/share/scripts/evomaintenance.sh" $file \
&& grep -q "%wheel ALL=NOPASSWD: MAINT" $file \
|| failed "IS_SUDOMAINT" ""
grep -q "permit setenv {ENV PS1 SSH_AUTH_SOCK SSH_TTY} nopass :evolinux-ssh as root cmd /usr/share/scripts/evomaintenance.sh" /etc/doas.conf || failed "IS_DOASMAINT" "Make sure evomaintenance.sh permission are properly configured in /etc/doas.conf"
}
check_nrpe(){
if ! is_installed monitoring-plugins || ! is_installed nrpe; then
@ -304,12 +310,12 @@ check_defaultroute(){
fi
}
check_ntp(){
if grep -q "server ntp.evolix.net" /etc/ntpd.conf; then
if grep -q "servers ntp.evolix.net" /etc/ntpd.conf; then
if [ "$(wc -l /etc/ntpd.conf | awk '{print $1}')" -ne 1 ]; then
failed "IS_NTP" "The /etc/ntpd.conf file should only contains \"server ntp.evolix.net\"."
failed "IS_NTP" "The /etc/ntpd.conf file should only contains \"servers ntp.evolix.net\"."
fi
else
failed "IS_NTP" "The configuration in /etc/ntpd.conf is not compliant. It should contains \"server ntp.evolix.net\"."
failed "IS_NTP" "The configuration in /etc/ntpd.conf is not compliant. It should contains \"servers ntp.evolix.net\"."
fi
}
check_openvpncronlog(){
@ -520,6 +526,17 @@ check_root_user() {
failed "IS_ROOT_USER" "root user should not have a password ; replace the password field with 'vipw' for the root user with '*************' (exactly 13 asterisks) "
fi
}
check_mount(){
for fstab_entry in $(grep ffs /etc/fstab | grep -v "^#" | awk '{print $2}'); do
mount | awk '{print $3}' | grep -q "^$fstab_entry$" || failed "IS_MOUNT" "Local OpenBSD partition(s) detected in /etc/fstab but not mounted"
done
}
check_mountfstab() {
for mount_point in $(mount | awk '{print $3}'); do
grep -q " $mount_point " /etc/fstab || failed "IS_MOUNT_FSTAB" "Partition(s) detected mounted but no presence in /etc/fstab"
done
}
main() {
# Default return code : 0 = no error
@ -540,13 +557,12 @@ main() {
test "${IS_CARPPREEMPT:=1}" = 1 && check_carppreempt
test "${IS_REBOOTMAIL:=1}" = 1 && check_rebootmail
test "${IS_PFENABLED:=1}" = 1 && check_pfenabled
test "${IS_WHEEL:=1}" = 1 && check_wheel
test "${IS_PKGMIRROR:=1}" = 1 && check_pkgmirror
test "${IS_HISTORY:=1}" = 1 && check_history
test "${IS_VIM:=1}" = 1 && check_vim
test "${IS_TTYC0SECURE:=1}" = 1 && check_ttyc0secure
test "${IS_CUSTOMSYSLOG:=1}" = 1 && check_customsyslog
test "${IS_SUDOMAINT:=1}" = 1 && check_sudomaint
test "${IS_DOASMAINT:=1}" = 1 && check_doasmaint
test "${IS_NRPE:=1}" = 1 && check_nrpe
test "${IS_RSYNC:=1}" = 1 && check_rsync
test "${IS_CRONPATH:=1}" = 1 && check_cronpath
@ -570,24 +586,34 @@ main() {
test "${IS_EVOLIX_USER:=1}" = 1 && check_evolix_user
test "${IS_CHECK_VERSIONS:=1}" = 1 && check_versions
test "${IS_ROOT_USER:=1}" = 1 && check_root_user
test "${IS_MOUNT:=1}" = 1 && check_mount
test "${IS_MOUNT_FSTAB:=1}" = 1 && check_mountfstab
exit ${RC}
}
cleanup_temp_files() {
cleanup() {
# Cleanup tmp files
# shellcheck disable=SC2086
rm -f ${files_to_cleanup}
log "$PROGNAME exit."
}
PROGNAME=$(basename "$0")
LOGFILE="/var/log/evocheck.log"
CONFIGFILE="/etc/evocheck.cf"
DATE_FORMAT="%Y-%m-%d %H:%M:%S"
# Disable LANG*
export LANG=C
export LANGUAGE=C
files_to_cleanup=""
trap cleanup_temp_files 0
# Source configuration file
# shellcheck disable=SC1091
test -f /etc/evocheck.cf && . /etc/evocheck.cf
test -f "${CONFIGFILE}" && . "${CONFIGFILE}"
# Parse options
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
@ -630,5 +656,25 @@ while :; do
shift
done
# Keep this after "show_version(); exit 0" which is called by check_versions
# to avoid logging exit twice.
files_to_cleanup=""
trap cleanup EXIT INT TERM
log '-----------------------------------------------'
log "Running $PROGNAME $VERSION..."
# Log config file content
if [ -f "${CONFIGFILE}" ]; then
log "Runtime configuration (${CONFIGFILE}):"
conf=$(sed -e '/^[[:blank:]]*#/d; s/#.*//; /^[[:blank:]]*$/d' "${CONFIGFILE}")
if [ ! -z "${conf}" ]; then
sed -e '/^[[:blank:]]*#/d; s/#.*//; /^[[:blank:]]*$/d' "${CONFIGFILE}" | log
else
log "${CONFIGFILE} is empty."
fi
fi
# shellcheck disable=SC2086
main ${ARGS}