Allow access to webserver logs via weinterface, if activated for customer; todo: view more content dynamically; fixes #603

Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
This commit is contained in:
Michael Kaufmann 2018-12-01 13:33:08 +01:00
parent 1bd4c00631
commit 8291c7d2ab
No known key found for this signature in database
GPG Key ID: 55284EC83A4823B8
15 changed files with 181 additions and 8 deletions

View File

@ -699,9 +699,14 @@ if ($page == 'domains' || $page == 'overview') {
} elseif ($page == 'domaindnseditor' && Settings::Get('system.dnsenabled') == '1') {
require_once __DIR__ . '/dns_editor.php';
} elseif ($page == 'sslcertificates') {
require_once __DIR__ . '/ssl_certificates.php';
} elseif ($page == 'logfiles') {
require_once __DIR__.'/logfiles_viewer.php';
}
function formatDomainEntry(&$row, &$idna_convert)

View File

@ -496,4 +496,7 @@ if ($page == 'overview') {
require_once __DIR__.'/ssl_certificates.php';
}
} elseif ($page == 'logfiles') {
require_once __DIR__.'/logfiles_viewer.php';
}

View File

@ -204,6 +204,7 @@ CREATE TABLE `panel_customers` (
`allowed_phpconfigs` varchar(500) NOT NULL default '',
`type_2fa` tinyint(1) NOT NULL default '0',
`data_2fa` varchar(500) NOT NULL default '',
`logviewenabled` tinyint(1) NOT NULL default '0',
PRIMARY KEY (`customerid`),
UNIQUE KEY `loginname` (`loginname`)
) ENGINE=MyISAM CHARSET=utf8 COLLATE=utf8_general_ci;
@ -693,7 +694,7 @@ opcache.interned_strings_buffer'),
('panel', 'password_special_char', '!?<>§$%+#=@'),
('panel', 'customer_hide_options', ''),
('panel', 'version', '0.10.0'),
('panel', 'db_version', '201811300');
('panel', 'db_version', '201812010');
DROP TABLE IF EXISTS `panel_tasks`;

View File

@ -96,3 +96,12 @@ if (isDatabaseVersion('201811180')) {
updateToDbVersion('201811300');
}
if (isDatabaseVersion('201811300')) {
showUpdateStep("Adding new logview-flag to customers");
Database::query("ALTER TABLE `" . TABLE_PANEL_CUSTOMERS . "` ADD `logviewenabled` tinyint(1) NOT NULL default '0';");
lastStepStatus(0);
updateToDbVersion('201812010');
}

View File

@ -197,10 +197,12 @@ class Customers extends ApiCommand implements ResourceEntity
* @param bool $perlenabled
* optional, whether to allow usage of Perl/CGI, default 0 (false)
* @param bool $dnsenabled
* optional, ether to allow usage of the DNS editor (requires activated nameserver in settings)
* optional, ether to allow usage of the DNS editor (requires activated nameserver in settings), default 0 (false)
* @param bool $logviewenabled
* optional, ether to allow acccess to webserver access/error-logs, default 0 (false)
* @param bool $store_defaultindex
* optional, whether to store the default index file to customers homedir
*
*
* @access admin
* @throws Exception
* @return array
@ -248,6 +250,7 @@ class Customers extends ApiCommand implements ResourceEntity
$p_allowed_phpconfigs = $this->getParam('allowed_phpconfigs', true, array());
$perlenabled = $this->getParam('perlenabled', true, 0);
$dnsenabled = $this->getParam('dnsenabled', true, 0);
$logviewenabled = $this->getParam('logviewenabled', true, 0);
$store_defaultindex = $this->getParam('store_defaultindex', true, 0);
$loginname = $this->getParam('new_loginname', true, '');
@ -375,6 +378,10 @@ class Customers extends ApiCommand implements ResourceEntity
$dnsenabled = '1';
}
if ($logviewenabled != '0') {
$logviewenabled = '1';
}
if ($password == '') {
$password = generatePassword();
}
@ -415,6 +422,7 @@ class Customers extends ApiCommand implements ResourceEntity
'pop3' => $email_pop3,
'perlenabled' => $perlenabled,
'dnsenabled' => $dnsenabled,
'logviewenabled' => $logviewenabled,
'theme' => $_theme,
'custom_notes' => $custom_notes,
'custom_notes_show' => $custom_notes_show
@ -456,6 +464,7 @@ class Customers extends ApiCommand implements ResourceEntity
`pop3` = :pop3,
`perlenabled` = :perlenabled,
`dnsenabled` = :dnsenabled,
`logviewenabled` = :logviewenabled,
`theme` = :theme,
`custom_notes` = :custom_notes,
`custom_notes_show` = :custom_notes_show
@ -828,7 +837,9 @@ class Customers extends ApiCommand implements ResourceEntity
* @param bool $perlenabled
* optional, whether to allow usage of Perl/CGI, default 0 (false)
* @param bool $dnsenabled
* optional, ether to allow usage of the DNS editor (requires activated nameserver in settings)
* optional, ether to allow usage of the DNS editor (requires activated nameserver in settings), default 0 (false)
* @param bool $logviewenabled
* optional, ether to allow acccess to webserver access/error-logs, default 0 (false)
* @param string $theme
* optional, change theme
*
@ -888,6 +899,7 @@ class Customers extends ApiCommand implements ResourceEntity
$allowed_phpconfigs = $this->getParam('allowed_phpconfigs', true, json_decode($result['allowed_phpconfigs'], true));
$perlenabled = $this->getParam('perlenabled', true, $result['perlenabled']);
$dnsenabled = $this->getParam('dnsenabled', true, $result['dnsenabled']);
$logviewenabled = $this->getParam('logviewenabled', true, $result['logviewenabled']);
$deactivated = $this->getParam('deactivated', true, $result['deactivated']);
$theme = $this->getParam('theme', true, $result['theme']);
} else {
@ -1029,6 +1041,10 @@ class Customers extends ApiCommand implements ResourceEntity
inserttask('1');
}
if ($logviewenabled != '0') {
$logviewenabled = '1';
}
// activate/deactivate customer services
if ($deactivated != $result['deactivated']) {
@ -1167,6 +1183,7 @@ class Customers extends ApiCommand implements ResourceEntity
'pop3' => $email_pop3,
'perlenabled' => $perlenabled,
'dnsenabled' => $dnsenabled,
'logviewenabled' => $logviewenabled,
'custom_notes' => $custom_notes,
'custom_notes_show' => $custom_notes_show
);
@ -1208,6 +1225,7 @@ class Customers extends ApiCommand implements ResourceEntity
`pop3` = :pop3,
`perlenabled` = :perlenabled,
`dnsenabled` = :dnsenabled,
`logviewenabled` = :logviewenabled,
`custom_notes` = :custom_notes,
`custom_notes_show` = :custom_notes_show";
$upd_query .= $admin_upd_query;

View File

@ -327,6 +327,16 @@ return array(
)
),
'visible' => (Settings::Get('system.dnsenabled') == '1' ? true : false)
),
'logviewenabled' => array(
'label' => $lng['admin']['logviewenabled'] . '?',
'type' => 'checkbox',
'values' => array(
array(
'label' => $lng['panel']['yes'],
'value' => '1'
)
)
)
)
)

View File

@ -297,6 +297,17 @@ return array(
'value' => array($result['dnsenabled']),
'visible' => (Settings::Get('system.dnsenabled') == '1' ? true : false)
),
'logviewenabled' => array(
'label' => $lng['admin']['logviewenabled'] . '?',
'type' => 'checkbox',
'values' => array(
array(
'label' => $lng['panel']['yes'],
'value' => '1'
)
),
'value' => array($result['logviewenabled'])
)
)
),
'section_d' => array(

View File

@ -19,7 +19,7 @@
$version = '0.10.0';
// Database version (YYYYMMDDC where C is a daily counter)
$dbversion = '201811300';
$dbversion = '201812010';
// Distribution branding-tag (used for Debian etc.)
$branding = '';

View File

@ -2165,3 +2165,5 @@ $lng['mails']['2fa']['subject'] = 'Froxlor - 2FA Code';
$lng['2fa']['2fa_overview_desc'] = 'Here you can activate a two-factor authentication for your account.<br><br>You can either use an authenticator-app (time-based one-time password / TOTP) or let froxlor send you an email to your account-address after each successful login with a one-time password.';
$lng['2fa']['2fa_email_desc'] = 'Your account is set up to use one-time passwords via e-mail. To deactivate, click on "'.$lng['2fa']['2fa_delete'].'"';
$lng['2fa']['2fa_ga_desc'] = 'Your account is set up to use time-based one-time passwords via authenticator-app. Please scan the QR code below with your desired authenticator app to generate the codes. To deactivate, click on "'.$lng['2fa']['2fa_delete'].'"';
$lng['admin']['logviewenabled'] = 'Enable access to access/error-logs';
$lng['panel']['viewlogs'] = 'View logfiles';

View File

@ -1813,3 +1813,5 @@ $lng['mails']['2fa']['subject'] = 'Froxlor - 2FA Code';
$lng['2fa']['2fa_overview_desc'] = 'Hier kann für das Konto eine Zwei-Faktor-Authentisierung aktiviert werden.<br><br>Es kann entweder eine Authenticator-App (time-based one-time password / TOTP) genutzt werden oder ein Einmalpasswort, welches nach erfolgreichem Login an die hinterlegte E-Mail Adresse gesendet wird.';
$lng['2fa']['2fa_email_desc'] = 'Das Konto ist eingerichtet, um Einmalpasswörter per E-Mail zu erhalten. Zum Deaktivieren, klicke auf "'.$lng['2fa']['2fa_delete'].'"';
$lng['2fa']['2fa_ga_desc'] = 'Das Konto ist eingerichtet, um zeitbasierte Einmalpasswörter via Authenticator-App zu erhalten. Um die gewünschte Authenticator-App einzurichten, scanne bitte den untenstehenden QR-Code. Zum Deaktivieren, klicke auf "'.$lng['2fa']['2fa_delete'].'"';
$lng['admin']['logviewenabled'] = 'Zugriff auf access/error-Logdateien';
$lng['panel']['viewlogs'] = 'Logdateien einsehen';

85
logfiles_viewer.php Normal file
View File

@ -0,0 +1,85 @@
<?php
if (! defined('AREA')) {
header("Location: index.php");
exit();
}
/**
* This file is part of the Froxlor project.
* Copyright (c) 2016 the Froxlor Team (see authors).
*
* For the full copyright and license information, please view the COPYING
* file that was distributed with this source code. You can also view the
* COPYING file online at http://files.froxlor.org/misc/COPYING.txt
*
* @copyright (c) the authors
* @author Froxlor team <team@froxlor.org> (2016-)
* @license GPLv2 http://files.froxlor.org/misc/COPYING.txt
* @package Panel
*
*/
// This file is being included in admin_domains and customer_domains
// and therefore does not need to require lib/init.php
// TODO get domain related settings for logfile (speciallogfile)
$domain_id = isset($_GET['domain_id']) ? (int) $_GET['domain_id'] : null;
$last_n = isset($_GET['number_of_lines']) ? (int) $_GET['number_of_lines'] : 100;
// user's with logviewenabled = false
if (AREA != 'admin' && $userinfo['logviewenabled'] != '1') {
// back to domain overview
redirectTo($filename, array(
'page' => 'domains',
's' => $s
));
}
if (function_exists('exec')) {
// get domain-info
try {
$json_result = SubDomains::getLocal($userinfo, array(
'id' => $domain_id
))->get();
} catch (Exception $e) {
dynamic_error($e->getMessage());
}
$domain = json_decode($json_result, true)['data'];
$speciallogfile = '';
if ($domain['speciallogfile'] == '1') {
if ($domain['parentdomainid'] == '0') {
$speciallogfile = '-' . $domain['domain'];
} else {
$speciallogfile = '-' . $domain['parentdomain'];
}
}
// The normal access/error - logging is enabled
$error_log = makeCorrectFile(Settings::Get('system.logfiles_directory') . getCustomerDetail($domain['customerid'], 'loginname') . $speciallogfile . '-error.log');
$access_log = makeCorrectFile(Settings::Get('system.logfiles_directory') . getCustomerDetail($domain['customerid'], 'loginname') . $speciallogfile . '-access.log');
// error log
if (file_exists($error_log)) {
$result = safe_exec('tail -n ' . $last_n . ' ' . escapeshellarg($error_log));
$error_log_content = implode("\n", $result) . "</textarea>";
} else {
$error_log_content = "Error-Log" . (AREA == 'admin' ? " '" . $error_log . "'" : "") . " does not seem to exist";
}
// access log
if (file_exists($access_log)) {
$result = safe_exec('tail -n ' . $last_n . ' ' . escapeshellarg($access_log));
$access_log_content = implode("\n", $result);
} else {
$access_log_content = "Access-Log" . (AREA == 'admin' ? " '" . $access_log . "'" : "") . " does not seem to exist";
}
eval("echo \"" . getTemplate("logfiles_viewer/index", true) . "\";");
} else {
if (AREA == 'admin') {
dynamic_error('You need to allow the exec() function in the froxlor-vhost php-config');
} else {
dynamic_error('Required function exec() is not allowed. Pllease contact the system administrator.');
}
}

View File

@ -20,6 +20,9 @@
<a href="{$linker->getLink(array('section' => 'domains', 'page' => $page, 'action' => 'edit', 'id' => $row['id']))}">
<img src="templates/{$theme}/assets/img/icons/edit.png" alt="{$lng['panel']['edit']}" title="{$lng['panel']['edit']}" />
</a>
<a href="{$linker->getLink(array('section' => 'domains', 'page' => 'logfiles', 'domain_id' => $row['id']))}">
<img src="templates/{$theme}/assets/img/icons/view.png" alt="{$lng['panel']['viewlogs']}" title="{$lng['panel']['viewlogs']}" />
</a>
<if $row['isbinddomain'] == '1' && Settings::Get('system.bind_enable') == '1' && Settings::Get('system.dnsenabled') == '1'>
&nbsp;<a href="{$linker->getLink(array('section' => 'domains', 'page' => 'domaindnseditor', 'domain_id' => $row['id']))}">
<img src="templates/{$theme}/assets/img/icons/dns_edit.png" alt="{$lng['dnseditor']['edit']}" title="{$lng['dnseditor']['edit']}" />

View File

@ -1640,7 +1640,7 @@ table thead th.tablesorter-headerDesc {
margin-bottom: 20px;
}
.shell, .filecontent {
.shell, .filecontent .logcontent {
font-family: Consolas, Monaco, Lucida Console, Liberation Mono,
DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace;
border: 1px solid #d1d5d8;

View File

@ -20,6 +20,11 @@
<img src="templates/{$theme}/assets/img/icons/edit.png" alt="{$lng['panel']['edit']}" title="{$lng['panel']['edit']}" />
</a>&nbsp;
</if>
<if $userinfo['logviewenabled'] == '1'>
<a href="{$linker->getLink(array('section' => 'domains', 'page' => 'logfiles', 'domain_id' => $row['id']))}">
<img src="templates/{$theme}/assets/img/icons/view.png" alt="{$lng['panel']['viewlogs']}" title="{$lng['panel']['viewlogs']}" />
</a>
</if>
<if $row['parentdomainid'] != '0' && !(isset($row['domainaliasid']) && $row['domainaliasid'] != 0)>
<a href="{$linker->getLink(array('section' => 'domains', 'page' => 'domains', 'action' => 'delete', 'id' => $row['id']))}">
<img src="templates/{$theme}/assets/img/icons/delete.png" alt="{$lng['panel']['delete']}" title="{$lng['panel']['delete']}" />

View File

@ -0,0 +1,19 @@
$header
<article>
<header>
<h2>
<img src="templates/{$theme}/assets/img/icons/view.png" alt="" />&nbsp;
{$lng['panel']['viewlogs']}&nbsp;(<a href="{$linker->getLink(array('section' => 'domains', 'page' => 'domains', 'action' => 'edit', 'id' => $domain_id))}">{$domain['domain']}</a>)&nbsp;[<a href="{$linker->getLink(array('section' => 'domains', 'page' => 'domains'))}">{$lng['menue']['domains']['domains']}</a>]
</h2>
</header>
<section>
<h3>Error-Log</h3>
<textarea rows="20" class="logcontent" readonly>{$error_log_content}</textarea>
<h3>Access-Log</h3>
<textarea rows="20" class="logcontent" readonly>{$access_log_content}</textarea>
</section>
</article>
$footer