272 lines
8.8 KiB
PHP
272 lines
8.8 KiB
PHP
|
<?php
|
||
|
|
||
|
/**
|
||
|
* dmarc-srg - A php parser, viewer and summary report generator for incoming DMARC reports.
|
||
|
* Copyright (C) 2023 Aleksey Andreev (liuch)
|
||
|
*
|
||
|
* Available at:
|
||
|
* https://github.com/liuch/dmarc-srg
|
||
|
*
|
||
|
* This program is free software: you can redistribute it and/or modify it
|
||
|
* under the terms of the GNU General Public License as published by the Free
|
||
|
* Software Foundation, either version 3 of the License.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||
|
* more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License along with
|
||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*
|
||
|
* =========================
|
||
|
*
|
||
|
* This script is for checking configuration.
|
||
|
*
|
||
|
* The script can be useful for checking your configuration.
|
||
|
* Note: the current directory must be the one containing the classes directory.
|
||
|
*
|
||
|
* @category Utilities
|
||
|
* @package DmarcSrg
|
||
|
* @author Aleksey Andreev (liuch)
|
||
|
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU/GPLv3
|
||
|
*/
|
||
|
|
||
|
namespace Liuch\DmarcSrg;
|
||
|
|
||
|
use Liuch\DmarcSrg\Core;
|
||
|
use Liuch\DmarcSrg\Mail\MailBoxes;
|
||
|
use Liuch\DmarcSrg\Directories\DirectoryList;
|
||
|
use Liuch\DmarcSrg\Exception\SoftException;
|
||
|
use Liuch\DmarcSrg\Exception\RuntimeException;
|
||
|
|
||
|
require 'init.php';
|
||
|
|
||
|
if (php_sapi_name() !== 'cli') {
|
||
|
echo 'Forbidden';
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
const RESULT_SUCCESS = 1;
|
||
|
const RESULT_WARNING = 2;
|
||
|
const RESULT_ERROR = 3;
|
||
|
const RESULT_FATAL = 4;
|
||
|
|
||
|
const CONFIG_FILE = 'config/conf.php';
|
||
|
|
||
|
$e_cnt = 0;
|
||
|
$w_cnt = 0;
|
||
|
$m_str = '';
|
||
|
|
||
|
$startChecking = function (string $message, int $margin = 0) use (&$m_str): void {
|
||
|
$col_w = 35;
|
||
|
$m_str = str_repeat(' ', $margin);
|
||
|
$s = "{$m_str} * {$message}";
|
||
|
echo $s, str_repeat('.', max($col_w - strlen($s), 0)), ' ';
|
||
|
};
|
||
|
|
||
|
$endChecking = function (string $message = '', int $result = 0) use (&$e_cnt, &$w_cnt, &$m_str): void {
|
||
|
if ($result === 0) {
|
||
|
$result = empty($message) ? RESULT_SUCCESS : RESULT_ERROR;
|
||
|
}
|
||
|
switch ($result) {
|
||
|
case RESULT_SUCCESS:
|
||
|
echo 'Ok', PHP_EOL;
|
||
|
break;
|
||
|
case RESULT_WARNING:
|
||
|
++$w_cnt;
|
||
|
echo 'Warning', PHP_EOL;
|
||
|
break;
|
||
|
case RESULT_ERROR:
|
||
|
++$e_cnt;
|
||
|
echo 'Fail', PHP_EOL;
|
||
|
break;
|
||
|
case RESULT_FATAL:
|
||
|
echo 'Fail', PHP_EOL;
|
||
|
throw new SoftException($message);
|
||
|
}
|
||
|
if (!empty($message)) {
|
||
|
echo "{$m_str} Message: ", $message, PHP_EOL;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
$core = Core::instance();
|
||
|
|
||
|
ob_start(null, 0, PHP_OUTPUT_HANDLER_FLUSHABLE | PHP_OUTPUT_HANDLER_REMOVABLE);
|
||
|
$core->config('debug'); // Just in order to load the config file
|
||
|
$empty_buf = empty(ob_get_flush());
|
||
|
|
||
|
try {
|
||
|
echo '=== GENERAL INFORMATION ===', PHP_EOL;
|
||
|
$uname = implode(' ', array_map(function ($mode) {
|
||
|
return php_uname($mode);
|
||
|
}, [ 's', 'r', 'v', 'm' ]));
|
||
|
echo ' * OS information: ', $uname, PHP_EOL;
|
||
|
echo ' * PHP version: ', phpversion(), PHP_EOL;
|
||
|
|
||
|
echo PHP_EOL, '=== EXTENSIONS ===', PHP_EOL;
|
||
|
foreach ([ 'pdo_mysql', 'xmlreader', 'zip', 'json' ] as $ext) {
|
||
|
$startChecking($ext);
|
||
|
if (extension_loaded($ext)) {
|
||
|
$endChecking();
|
||
|
} else {
|
||
|
$endChecking('The extension is not loaded');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
echo PHP_EOL, '=== CONFIG FILE ===', PHP_EOL;
|
||
|
$startChecking('Checking if the file exists');
|
||
|
if (is_file(CONFIG_FILE)) {
|
||
|
$endChecking();
|
||
|
} else {
|
||
|
$endChecking('The configuration file `config/conf.php` not found', RESULT_FATAL);
|
||
|
}
|
||
|
$startChecking('Checking read permission');
|
||
|
if (is_readable(CONFIG_FILE)) {
|
||
|
$endChecking();
|
||
|
} else {
|
||
|
$endChecking('The configuration file is not readable', RESULT_FATAL);
|
||
|
}
|
||
|
$startChecking('Checking write permission');
|
||
|
if (!is_writable(CONFIG_FILE)) {
|
||
|
$endChecking();
|
||
|
} else {
|
||
|
$endChecking('The configuration file is writable', RESULT_WARNING);
|
||
|
}
|
||
|
$startChecking('Checking access by other users');
|
||
|
$r = fileperms(CONFIG_FILE);
|
||
|
if ($r !== false) {
|
||
|
if (($r & 0x6) !== 0) {
|
||
|
$endChecking('The configuration file is accessible to other users', RESULT_WARNING);
|
||
|
} else {
|
||
|
$endChecking();
|
||
|
}
|
||
|
} else {
|
||
|
$endChecking('Fileperms failed', RESULT_ERROR);
|
||
|
}
|
||
|
$startChecking('Checking the output buffer');
|
||
|
if ($empty_buf) {
|
||
|
$endChecking();
|
||
|
} else {
|
||
|
$endChecking('There are extra characters before the "<?php" string');
|
||
|
}
|
||
|
|
||
|
echo PHP_EOL, '=== DATABASE ===', PHP_EOL;
|
||
|
$startChecking('Accessibility check');
|
||
|
try {
|
||
|
$db_s = $core->database()->state();
|
||
|
$endChecking();
|
||
|
} catch (RuntimeException $e) {
|
||
|
$db_s = null;
|
||
|
$endChecking($e->getMessage());
|
||
|
}
|
||
|
if ($db_s) {
|
||
|
$startChecking('Checking for integrity');
|
||
|
if ($db_s) {
|
||
|
$endChecking();
|
||
|
} else {
|
||
|
$endChecking($db_s['message'], ($db_s['needs_upgrade'] ?? false) ? RESULT_WARNING : RESULT_ERROR);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
echo PHP_EOL, '=== MAILBOXES ===', PHP_EOL;
|
||
|
$startChecking('Checking mailboxes config');
|
||
|
try {
|
||
|
$mb_list = new MailBoxes();
|
||
|
$mb_lcnt = $mb_list->count();
|
||
|
if ($mb_lcnt === 0) {
|
||
|
$endChecking('No mailboxes found', RESULT_SUCCESS);
|
||
|
} else {
|
||
|
$endChecking("{$mb_lcnt} mailbox" . ($mb_lcnt > 1 ? 'ex' : '') . ' found', RESULT_SUCCESS);
|
||
|
$startChecking('Imap extension');
|
||
|
if (extension_loaded('imap')) {
|
||
|
$endChecking();
|
||
|
echo " * Checking mailboxes ({$mb_lcnt})", PHP_EOL;
|
||
|
for ($mb_num = 1; $mb_num <= $mb_lcnt; ++$mb_num) {
|
||
|
$mb = $mb_list->mailbox($mb_num);
|
||
|
echo " - {$mb->name()}", PHP_EOL;
|
||
|
$startChecking('Accessibility', 2);
|
||
|
$res = $mb->check();
|
||
|
if (!$res['error_code']) {
|
||
|
$endChecking();
|
||
|
} else {
|
||
|
$endChecking($res['message'] ?? null);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
$endChecking('The extension is not loaded');
|
||
|
}
|
||
|
}
|
||
|
} catch (RuntimeException $e) {
|
||
|
$endChecking($e->getMessage());
|
||
|
}
|
||
|
|
||
|
echo PHP_EOL, '=== DIRECTORIES ===', PHP_EOL;
|
||
|
$startChecking('Checking directories config');
|
||
|
try {
|
||
|
$dir_list = (new DirectoryList())->list();
|
||
|
$dir_lcnt = count($dir_list);
|
||
|
if ($dir_lcnt === 0) {
|
||
|
$endChecking('No directories found', RESULT_SUCCESS);
|
||
|
} else {
|
||
|
$endChecking("{$dir_lcnt} director" . ($dir_lcnt > 1 ? 'ies' : 'y') . ' found', RESULT_SUCCESS);
|
||
|
echo " * Checking directories ({$dir_lcnt})", PHP_EOL;
|
||
|
foreach ($dir_list as $dir) {
|
||
|
$dir_a = $dir->toArray();
|
||
|
echo " - {$dir_a['name']}", PHP_EOL;
|
||
|
$startChecking('Accessibility', 2);
|
||
|
$res = $dir->check();
|
||
|
if (!$res['error_code']) {
|
||
|
$endChecking();
|
||
|
$startChecking('Security', 2);
|
||
|
try {
|
||
|
$perms = fileperms($dir_a['location']);
|
||
|
if ($perms === false) {
|
||
|
throw new RuntimeException('Fileperms failed', RESULT_ERROR);
|
||
|
}
|
||
|
if ($perms & 0x2) {
|
||
|
throw new RuntimeException(
|
||
|
'Other users have write access to the directory',
|
||
|
RESULT_WARNING
|
||
|
);
|
||
|
}
|
||
|
$endChecking();
|
||
|
} catch (RuntimeException $e) {
|
||
|
$endChecking($e->getMessage(), $e->getCode());
|
||
|
} catch (\ErrorException $e) {
|
||
|
$endChecking($e->getMessage());
|
||
|
}
|
||
|
} else {
|
||
|
$endChecking($res['message'] ?? null);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} catch (SoftException $e) {
|
||
|
$endChecking($e->getMessage());
|
||
|
}
|
||
|
|
||
|
echo PHP_EOL, '===', PHP_EOL;
|
||
|
if ($e_cnt === 0 && $w_cnt === 0) {
|
||
|
echo 'Success!', PHP_EOL;
|
||
|
} else {
|
||
|
echo 'There ', $e_cnt + $w_cnt === 1 ? 'is' : 'are', ' ';
|
||
|
$strs = [];
|
||
|
foreach ([ [$e_cnt, 'error' ], [ $w_cnt, 'warning' ] ] as &$it) {
|
||
|
$cnt = $it[0];
|
||
|
if ($cnt > 0) {
|
||
|
$strs[] = $cnt . ' ' . $it[1] . ($cnt > 1 ? 's' : '');
|
||
|
}
|
||
|
}
|
||
|
unset($it);
|
||
|
echo implode(' and ', $strs), '!', PHP_EOL;
|
||
|
}
|
||
|
} catch (SoftException $e) {
|
||
|
echo 'Fatal error: ', $e->getMessage(), PHP_EOL;
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
if ($e_cnt > 0) {
|
||
|
exit(2);
|
||
|
}
|
||
|
exit(0);
|