Compare commits

...

36 Commits

Author SHA1 Message Date
Ilia Ross
f6b62525f8 Add ability to track session state using session database (solution two) 2025-07-02 15:27:54 +03:00
Ilia Ross
57138d505b Add ability to track session state in a separate file (solution one) 2025-07-02 14:45:41 +03:00
Ilia Ross
58580b7f4b Fix to enable log rotation for Webmin logs 2025-07-01 15:10:49 +03:00
Ilia Ross
d9a120c760 Fix to remove non-breakable spaces that don't belong in values within parentheses 2025-07-01 14:33:27 +03:00
Ilia Ross
fb832eff82 Fix to always enable HSTS 2025-06-30 14:08:54 +03:00
Ilia Ross
75b0a6f7bb Fix sending HSTS over plain HTTP does nothing
* Note: per the spec (RFC 6797), HSTS only takes effect when delivered on an HTTPS response

https://datatracker.ietf.org/doc/html/rfc6797#section-7.2
2025-06-30 13:43:46 +03:00
Ilia Ross
40707d8602 Update changelog 2025-06-29 23:04:51 +03:00
Ilia Ross
ac45266ee4 Add missing referenced variable 2025-06-29 22:28:42 +03:00
Ilia Ross
522aeb5264 Fix to consider ancient systems 2025-06-29 22:28:30 +03:00
Ilia Ross
1d24db1686 Add a warning to the login pages if the connection is not secure 2025-06-29 13:42:02 +03:00
Jamie Cameron
527043b54d Merge pull request #2506 from webmin/dev/fix-support-for-ssleay-1.93+
Fix latest SSLeay support for redirects to SSL work
2025-06-28 18:20:24 -07:00
Ilia Ross
56b62346b4 Fix not to use SSL unless clients wants it explicitly 2025-06-29 01:04:30 +03:00
Ilia Ross
ee39f99d23 Fix not to print unnecessary horizontal line
* Note: we're already inside the container
2025-06-28 15:02:23 +03:00
Ilia Ross
a223243db4 Fix comment for clarity 2025-06-27 04:01:15 +03:00
Ilia Ross
b59bdc4f1a Fix latest SSLeay support for redirects to SSL work 2025-06-27 03:57:06 +03:00
Ilia Ross
d087f9f024 Fix to correctly concatenate if string is empty 2025-06-24 13:33:26 +03:00
Jamie Cameron
1607a59239 Handle case where mime_header_checks is not set
https://forum.virtualmin.com/t/double-header-checks/133851/8
2025-06-23 16:52:26 -07:00
Jamie Cameron
70589cf88a Fix regexp to match actual output
https://github.com/webmin/webmin/issues/2501
2025-06-22 15:58:07 -07:00
Jamie Cameron
c429fbb202 Merge branch 'master' of github.com:webmin/webmin 2025-06-22 14:11:53 -07:00
Jamie Cameron
f24375e13a Deal with DNF5 format
https://github.com/webmin/webmin/issues/2501
2025-06-22 14:11:43 -07:00
Ilia Ross
d428f4d4c1 Fix comment
49ceeebbf8 (commitcomment-160355697)
2025-06-22 01:02:51 +03:00
Ilia Ross
f0e07518c9 Fix setting innodb_file_per_table option as it's always enabled by default 2025-06-21 22:45:17 +03:00
Ilia Ross
29709c3c51 Update changelog for another minor release 2025-06-21 21:05:07 +03:00
Ilia Ross
fb71fbd5ae Fix to show output properly without redirecting prematurely 2025-06-21 20:49:55 +03:00
Ilia Ross
a1f06c5548 Fix text consistency 2025-06-21 20:49:33 +03:00
Jamie Cameron
10e8a420c0 Filter out instances of the same version 2025-06-21 10:39:35 -07:00
Jamie Cameron
8149eef10a Add status monitor for PHP FPM
https://github.com/webmin/webmin/issues/2499
2025-06-20 21:53:14 -07:00
Jamie Cameron
c4b98ef376 Nut UPS is no longer supported 2025-06-19 21:31:41 -07:00
Jamie Cameron
621d5c22bc CFengine is no longer supported 2025-06-19 21:30:34 -07:00
Jamie Cameron
98000bb007 BIND 4 is no longer supported 2025-06-19 21:29:46 -07:00
Jamie Cameron
d90a33bb0c Jabber is no longer supported by Webmin 2025-06-19 21:27:45 -07:00
Jamie Cameron
d795fc7d60 Merge branch 'master' of github.com:webmin/webmin 2025-06-19 21:23:30 -07:00
Jamie Cameron
b397ece0ab Most options have moved away from set-variable
https://github.com/webmin/webmin/issues/2497
2025-06-19 21:21:47 -07:00
Jamie Cameron
0a11f182b0 Merge pull request #2498 from webmin/dev/musthost-redirect
Add ability to redirect to enforced host
2025-06-18 12:32:05 -07:00
Ilia Ross
7c05368e8f Add UI API to mask sensitive text unless specifically hovered 2025-06-18 16:53:55 +03:00
Ilia Ross
49ceeebbf8 Add ability to redirect to enforced host 2025-06-17 20:28:49 +03:00
28 changed files with 310 additions and 235 deletions

View File

@@ -1,5 +1,13 @@
## Changelog
#### 2.403 (June 30, 2025)
* Add support for the Webmin webserver to work in both HTTP and HTTPS modes at the same time
* Add status monitor for PHP FPM #2499
* Add support for redirecting to the enforced domain when the `musthost_redirect` directive is set
* Add a UI API to mask sensitive text—like displayed passwords, unless hovered over container
* Fix MySQL/MariaDB to remove obsolete `set-variable` options that break modern config files #2497
#### 2.402 (June 16, 2025)
* Update the Authentic theme to the latest version with various fixes and improvements
* Fix support for EL10-based systems

File diff suppressed because one or more lines are too long

View File

@@ -818,3 +818,8 @@ body > .mode > b[data-mode="server-manager"] > a > .ff-cloudmin {
[data-pro-disabled$="-elem"] a:hover {
filter: grayscale(1) contrast(1);
}
.not-secure {
color: #f00a38;
float: right;
cursor: help;
}

View File

@@ -189,6 +189,9 @@ pam_mesg2=You must respond to the question below to login.
pam_login=Continue
pam_restart=Restart
login_notsecure=Not Secure
login_notsecure_desc=This connection is not secure and could let a man-in-the-middle attack intercept your password or session cookie. Use HTTPS unless you are on a trusted local network or behind a secure reverse proxy.
acl_root=Root directory for file chooser
acl_otherdirs=Other visible directories in file chooser
acl_nodot=Hide dot files in file chooser?

View File

@@ -285,7 +285,7 @@ if (exists($minfo{'deb_requires'})) {
foreach my $debrequire (split(/\s+/, $minfo{'deb_requires'})) {
push(@rrequires, $debrequire);
}
$rdeps .= ", " . join(", ", @rrequires) if (@rrequires);
$rdeps .= ($rdeps ? ', ' : '') . join(", ", @rrequires) if (@rrequires);
}
# Build (append) list of recommended packages (not Webmin modules)
@@ -294,7 +294,8 @@ if (exists($minfo{'deb_recommends'})) {
foreach my $debrecommend (split(/\s+/, $minfo{'deb_recommends'})) {
push(@rrecommends, $debrecommend);
}
$rrecom .= ", " . join(", ", @rrecommends) if (@rrecommends);
$rrecom .= ($rrecom ? ', ' : '') . join(", ", @rrecommends)
if (@rrecommends);
}
# Build (standalone) list of suggested packages (not Webmin modules)

View File

@@ -312,7 +312,7 @@ if (exists($minfo{'rpm_requires'})) {
foreach my $rpmrequire (split(/\s+/, $minfo{'rpm_requires'})) {
push(@rrequires, $rpmrequire);
}
$rdeps .= " " . join(" ", @rrequires) if (@rrequires);
$rdeps .= ($rdeps ? ' ' : '') . join(" ", @rrequires) if (@rrequires);
}
# Build (append) list of recommended packages (not Webmin modules)
@@ -321,7 +321,8 @@ if (exists($minfo{'rpm_recommends'})) {
foreach my $rpmrecommend (split(/\s+/, $minfo{'rpm_recommends'})) {
push(@rrecommends, $rpmrecommend);
}
$rrecom .= " " . join(" ", @rrecommends) if (@rrecommends);
$rrecom .= ($rrecom ? ' ' : '') . join(" ", @rrecommends)
if (@rrecommends);
}
# Build (standalone) list of suggested packages (not Webmin modules)

View File

@@ -610,6 +610,53 @@ if ($config{'logclear'}) {
push(@childpids, $logclearer);
}
# session_state(session-id, set-state)
# Sets or gets the active state of the client, which is used to determine
# whether the client is away or not. This is used to allow for the session to
# expire after a period of inactivity in case a client has opened connections or
# makes HTTP requests in the background. Returns 1 if the client is currently
# not away (ie. active), or 0 if it is away.
sub session_state
{
my ($sid, $set) = @_;
return 1 if (!$sid);
# Check session database
my %sessiondb;
dbmopen(%sessiondb, $config{'sessiondb'}, 0700);
if ($@) {
dbmclose(%sessiondb);
eval "use NDBM_File";
dbmopen(%sessiondb, $config{'sessiondb'}, 0700);
}
# Get current record
my $skey = &hash_session_id($sid);
my ($user, $ltime, $ip, $lifetime, $active);
if (exists($sessiondb{$skey})) {
($user, $ltime, $ip, $lifetime, $active) =
split(/\s+/, $sessiondb{$skey});
$lifetime //= 0; # preserve or default to 0
$active //= 1; # default to 'alive'
}
# Update flag if caller supplied a value
if ($user && $ltime && $ip && defined($set)) {
$active = $set ? 1 : 0;
$sessiondb{$skey} = join(' ', $user, $ltime, $ip, $lifetime, $active);
print DEBUG "websocket updated status for $sid to $active\n";
}
else {
print DEBUG "websocket current status for $sid is $active\n";
}
# Save the record back to the database
dbmclose(%sessiondb);
# Return the active state
return $active;
}
# Setup the logout time dbm if needed
if ($config{'session'}) {
eval "use SDBM_File";
@@ -918,11 +965,27 @@ while(1) {
# Initialize SSL for this connection
if ($use_ssl) {
($ssl_con, $ssl_certfile,
$ssl_keyfile) = &ssl_connection_for_ip(
SOCK, $ipv6fhs{$s});
print DEBUG "ssl_con returned $ssl_con\n";
$ssl_con || exit;
my $byte = '';
# Look at the first byte of the socket
# buffer but don't consume it
recv(SOCK, $byte, 1, MSG_PEEK);
if (length($byte) &&
# Check if the first byte is a TLS
(ord($byte) == 0x16 ||
# Check if the first byte is SSL
(ord($byte) & 0x80))) {
($ssl_con,
$ssl_certfile,
$ssl_keyfile) =
&ssl_connection_for_ip(
SOCK, $ipv6fhs{$s});
print DEBUG "ssl_con returned ".
"$ssl_con\n";
$ssl_con || exit;
}
else {
$use_ssl = 0;
}
}
print DEBUG
@@ -1101,8 +1164,10 @@ while(1) {
print $outfd "0 0\n";
}
else {
local ($user, $ltime, $ip, $lifetime) =
local ($user, $ltime, $ip, $lifetime, $state) =
split(/\s+/, $sessiondb{$skey});
$lifetime //= 0;
$state //= 1;
local $lot = &get_logout_time($user, $session_id);
if ($lot &&
$time_now - $ltime > $lot*60 &&
@@ -1131,7 +1196,7 @@ while(1) {
# Session is OK, update last time
# and remote IP
print $outfd "2 $user\n";
$sessiondb{$skey} = "$user $time_now $vip";
$sessiondb{$skey} = "$user $time_now $vip $lifetime $state";
}
}
}
@@ -1520,7 +1585,8 @@ if (defined($header{'host'})) {
else {
$host = $header{'host'};
}
if ($config{'musthost'} && $host ne $config{'musthost'}) {
if ($config{'musthost'} && $host ne $config{'musthost'} &&
!$config{'musthost_redirect'}) {
# Disallowed hostname used
&http_error(400, "Invalid HTTP hostname");
}
@@ -1543,6 +1609,22 @@ if ($config{'redirect_prefix'}) {
}
$prot = $ssl ? "https" : "http";
# Redirect to the configured "musthost", if "musthost_redirect" is set, rather
# than showing an error
if ($config{'musthost'} && $host ne $config{'musthost'} &&
$config{'musthost_redirect'}) {
&write_data("HTTP/1.0 302 Moved Temporarily\r\n");
&write_data("Date: $datestr\r\n");
&write_data("Server: @{[&server_info()]}\r\n");
&write_data("Location: $prot://$config{'musthost'}:$redirport\r\n");
&write_keep_alive(0);
&write_data("\r\n");
&log_request($loghost, $authuser, $reqline, 302, 0) if $reqline;
shutdown(SOCK, 1);
close(SOCK);
return;
}
undef(%in);
if ($page =~ /^([^\?]+)\?(.*)$/) {
# There is some query string information
@@ -5899,7 +5981,8 @@ while(1) {
syswrite($fh, $buf, length($buf)) || last;
}
my $now = time();
if ($now - $last_session_check_time > 10) {
if ($now - $last_session_check_time > 10 &&
&session_state($session_id) == 1) {
# Re-validate the browser session every 10 seconds
print DEBUG "verifying websockets session $session_id\n";
print $PASSINw "verify $session_id 0 $acptip\n";

View File

@@ -50,9 +50,10 @@ print &ui_table_row($text{'cnf_stor'},
'NDB', 'ARCHIVE', 'CSV',
'BLACKHOLE' ], 1, 0, 1));
my $ifpt_def_off = &get_innodb_file_per_table_default() ? 0 : 1;
$fpt = &find_value("innodb_file_per_table", $mems);
print &ui_table_row($text{'cnf_fpt'},
&ui_yesno_radio("fpt", $fpt));
&ui_yesno_radio("fpt", $fpt // $ifpt_def_off));
$ilt = &find_value("innodb_lock_wait_timeout", $mems);
print &ui_table_row($text{'cnf_ilt'},

View File

@@ -88,20 +88,13 @@ if ($mysql_version =~ /mariadb/i) {
}
&fix_mysql_text(\%text);
if (&compare_version_numbers($mysql_version, "5.5") >= 0) {
@mysql_set_variables = ( "key_buffer_size", "sort_buffer_size",
"net_buffer_length" );
}
else {
@mysql_set_variables = ( "key_buffer", "sort_buffer",
"net_buffer_length" );
}
if (&compare_version_numbers($mysql_version, "5.6") >= 0) {
@mysql_number_variables = ( "table_open_cache", "max_connections" );
}
else {
@mysql_number_variables = ( "table_cache", "max_connections" );
}
@mysql_byte_variables = ( "max_allowed_packet" );
my $mysql8_optout = &compare_version_numbers($mysql_version, "8.0") >= 0 && $mysql_version !~ /maria/i;
if (!$mysql8_optout) {
@@ -115,6 +108,15 @@ else {
push(@mysql_set_variables, "myisam_sort_buffer_size");
}
if (&compare_version_numbers($mysql_version, "5.5") >= 0) {
push(@mysql_byte_variables, "key_buffer_size", "sort_buffer_size",
"net_buffer_length");
}
else {
@mysql_set_variables = ( "key_buffer", "sort_buffer",
"net_buffer_length" );
}
# make_authstr([login], [pass], [host], [port], [sock], [unix-user], [ssl])
# Returns a string to pass to MySQL commands to login to the database
sub make_authstr
@@ -1766,6 +1768,18 @@ return
$variant eq "mysql" && &compare_version_numbers($ver, "8.0") >= 0;
}
# get_innodb_file_per_table_default()
# Returns 1 if the InnoDB file-per-table option is disabled by default
sub get_innodb_file_per_table_default
{
my ($ver, $variant) = &get_remote_mysql_variant();
return
($variant eq 'mariadb' && &compare_version_numbers($ver, '10.1.0') < 0) ||
($variant eq 'mysql' && &compare_version_numbers($ver, '5.6.6') < 0)
? 1
: 0;
}
# get_plugin_sql(version, variant, plainpass, plugin)
# Get the right query for setting user password with plugin
sub get_plugin_sql

View File

@@ -18,7 +18,7 @@ else {
$mysql_login ? "<tt>$mysql_login</tt>"
: "<label>$text{'root_auto'}</label>");
print &ui_table_row($text{'root_pass'},
$mysql_pass ? "<tt>$mysql_pass</tt>"
$mysql_pass ? "<tt>".&ui_text_mask($mysql_pass)."</tt>"
: &ui_text_color($text{'root_none'}, 'danger'));
print &ui_table_row($text{'root_newpass1'},
&ui_password("newpass1", undef, 20));

View File

@@ -13,6 +13,7 @@ foreach my $l (&get_all_mysqld_files()) {
$conf = &get_mysql_config();
($mysqld) = grep { $_->{'name'} eq 'mysqld' } @$conf;
$mysqld || &error($text{'cnf_emysqld'});
$mems = $mysqld->{'members'};
# Parse mysql server inputs
if ($in{'port_def'}) {
@@ -53,11 +54,9 @@ else {
&save_directive($conf, $mysqld, "default-storage-engine",
$in{'stor'} ? [ $in{'stor'} ] : [ ]);
$fpt = &find_value("innodb_file_per_table", $mems);
if ($fpt || $in{'fpt'}) {
&save_directive($conf, $mysqld, "innodb_file_per_table",
[ $in{'fpt'} ]);
}
my $ifpt_def_off = &get_innodb_file_per_table_default();
&save_directive($conf, $mysqld, "innodb_file_per_table",
[ $in{'fpt'} ? ($ifpt_def_off ? 1 : undef) : 0 ]);
if ($in{'ilt_def'}) {
&save_directive($conf, $mysqld, "innodb_lock_wait_timeout", [ ]);

View File

@@ -72,7 +72,13 @@ print "$text{'pam_prefix'}\n";
print &ui_form_start("@{[&get_webprefix()]}/pam_login.cgi", "post");
print &ui_hidden("cid", $in{'cid'});
print &ui_table_start($text{'pam_header'},
my $not_secure;
if ($ENV{'HTTPS'} ne 'ON') {
$not_secure = ui_tag('span', "&#9888; $text{'login_notsecure'}",
{ class => 'not-secure', title => $text{'login_notsecure_desc'} });
}
print &ui_table_start($text{'pam_header'} . $not_secure,
"width=40% class='loginform'", 2);
if ($gconfig{'realname'}) {

View File

@@ -27,7 +27,8 @@ print &ui_form_end([ [ undef, $text{'opts_save'} ] ]);
# Header map contents
print &ui_hr();
if (&get_real_value("header_checks") eq "") {
my $hc = &get_real_value("mime_header_checks");
if ($hc eq "") {
print $text{'opts_header_checks_no_map'},"<p>\n";
} else {
&generate_map_edit("header_checks", $text{'map_click'}." ".
@@ -37,8 +38,11 @@ if (&get_real_value("header_checks") eq "") {
# MIME header map contents
print &ui_hr();
if (&get_real_value("mime_header_checks") eq "") {
my $mhc = &get_real_value("mime_header_checks");
if ($mhc eq "") {
print $text{'opts_mime_header_checks_no_map'},"<p>\n";
} elsif ($mhc eq $hc) {
print $text{'opts_mime_header_checks_same_map'},"<p>\n";
} else {
&generate_map_edit("mime_header_checks", $text{'map_click'}." ".
&hlink($text{'help_map_format'}, "header"), 1,

View File

@@ -654,6 +654,7 @@ opts_header_checks=Header checking tables
opts_mime_header_checks=MIME header checking tables
opts_header_checks_no_map=(No header checking map is currently defined. Define a map first, then you can edit it)
opts_mime_header_checks_no_map=(No MIME header checking map is currently defined. Define a map first, then you can edit it)
opts_mime_header_checks_same_map=(MIME header checks are the same as regular header checks. Define a different map first, then you can edit it)
header_name=Regular expression
header_value=Action for matches
header_discard=Discard (with log message..)

View File

@@ -91,7 +91,14 @@ print "$text{'session_prefix'}\n";
print &ui_form_start("@{[&get_webprefix()]}/session_login.cgi", "post");
print &ui_hidden("page", $in{'page'});
print &ui_table_start($text{'session_header'},
my $not_secure;
if ($ENV{'HTTPS'} ne 'ON') {
$not_secure = ui_tag('span', "&#9888; $text{'login_notsecure'}",
{ class => 'not-secure', title => $text{'login_notsecure_desc'} });
}
print &ui_table_start($text{'session_header'} . $not_secure,
"width=40% class='loginform'", 2);
# Login message

View File

@@ -819,15 +819,27 @@ if [ "$upgrading" != 1 ]; then
echo licence_module=$licence_module >>$config_dir/config
fi
# Enable log rotation by default
echo "logclear=1" >> $config_dir/miniserv.conf
echo "logclear=1" >> $config_dir/config
# Enable HSTS by default
echo "ssl_hsts=1" >> $config_dir/miniserv.conf
# Disallow unknown referers by default
echo "referers_none=1" >>$config_dir/config
else
# one-off hack to set log variable in config from miniserv.conf
grep log= $config_dir/config >/dev/null
if [ "$?" = "1" ]; then
grep log= $config_dir/miniserv.conf >> $config_dir/config
grep logtime= $config_dir/miniserv.conf >> $config_dir/config
grep logclear= $config_dir/miniserv.conf >> $config_dir/config
# Enable log rotation if not set
grep logclear= $config_dir/miniserv.conf >/dev/null
if [ "$?" != "0" ]; then
echo "logclear=1" >> $config_dir/miniserv.conf
echo "logclear=1" >> $config_dir/config
fi
# Enable HSTS by default if not set
grep ssl_hsts= $config_dir/miniserv.conf >/dev/null
if [ "$?" != "0" ]; then
echo "ssl_hsts=1" >> $config_dir/miniserv.conf
fi
# Disallow unknown referers if not set

View File

@@ -97,7 +97,6 @@ if ($in{'need_unlink'}) {
"delete_file.cgi?file=".
&urlize($in{'file'})),"<p>\n";
}
print &ui_hr();
&ui_print_footer("", $text{'index_return'});
exit;
}

View File

@@ -119,6 +119,13 @@ while(<CMD>) {
$pkg =~ s/\-\d.*$//; # Strip version number from end
push(@rv, $pkg);
}
elsif (/\]\s+(Upgrading|Installing)\s+(\S+)/) {
# Line like :
# [3/8] Upgrading libcurl-0:8.11.1-5.fc42 100% ...
local $pkg = $2;
$pkg =~ s/:\d.*$//; # Strip version number from end
push(@rv, $pkg);
}
if (!/ETA/ && !/\%\s+done\s+\d+\/\d+\s*$/) {
print &html_escape($_."\n");
}

View File

@@ -1,24 +0,0 @@
# cfengine-monitor.pl
# Monitor the cfengine daemon on this host
# Check the PID file to see if cfd is running
sub get_cfengine_status
{
local %cconfig = &foreign_config($_[1]);
&has_command($cconfig{'cfd'}) || return { 'up' => -1 };
local @pids = &find_byname("cfd");
if (@pids) {
return { 'up' => 1 };
}
else {
return { 'up' => 0 };
}
}
sub parse_cfengine_dialog
{
&depends_check($_[0], "cfengine");
}
1;

View File

@@ -33,7 +33,5 @@ else {
&reset_environment();
&webmin_log("refresh");
print $text{'refresh_done'},"<p>\n";
print &js_redirect("index.cgi");
&ui_print_footer("", $text{'index_return'});
}

View File

@@ -1,28 +0,0 @@
# dnsadmin-monitor.pl
# Monitor the BIND 4 DNS server on this host
# Check the PID file to see if BIND is running
sub get_dnsadmin_status
{
return { 'up' => -1 } if (!&foreign_check($_[1]));
&foreign_require($_[1], "dns-lib.pl");
local %dconfig = &foreign_config($_[1]);
return { 'up' => -1 } if (!-r $dconfig{'named_boot_file'});
if (open(PID, "<".$dconfig{'named_pid_file'}) && <PID> =~ /(\d+)/ && kill(0, $1)) {
close(PID);
local @st = stat($dconfig{'named_pid_file'});
return { 'up' => 1,
'desc' => &text('up_since', scalar(localtime($st[9]))) };
}
else {
return { 'up' => 0 };
}
}
sub parse_dnsadmin_dialog
{
&depends_check($_[0], "dnsadmin");
}
1;

View File

@@ -1,28 +0,0 @@
# jabber-monitor.pl
# Monitor the jabber server on this host
# Check the PID file to see if mon is running
sub get_jabber_status
{
return { 'up' => -1 } if (!&foreign_check($_[1]));
local %jconfig = &foreign_config($_[1]);
-r $jconfig{'jabber_config'} || return { 'up' => -1 };
&foreign_require($_[1], "jabber-lib.pl");
local $pidfile = &foreign_call($_[1], "jabber_pid_file");
if (open(PID, "<".$pidfile) && ($pid = int(<PID>)) && kill(0, $pid)) {
return { 'up' => 1 };
}
else {
return { 'up' => 0 };
}
}
sub parse_jabber_dialog
{
&depends_check($_[0], "jabber");
eval "use XML::Parser";
&error(&text('jabber_eparser', "<tt>XML::Parser</tt>")) if ($@);
}
1;

View File

@@ -25,7 +25,6 @@ type_inetd=Internet and RPC Server
type_xinetd=Extended Internet Server
type_squid=Squid Proxy Server
type_bind8=BIND DNS Server
type_dnsadmin=BIND 4 DNS Server
type_dhcpd=DHCP Server
type_tcp=TCP Connection
type_http=HTTP Request
@@ -51,12 +50,10 @@ type_change=File or Directory Change
type_oldfile=File Not Changed
type_qmailadmin=QMail Server
type_mon=MON Service Monitor
type_jabber=Jabber IM Server
type_usermin=Usermin Webserver
type_portsentry=Portsentry Daemon
type_hostsentry=Hostsentry Daemon
type_webmin=Webmin Webserver
type_cfengine=Configuration Engine Daemon
type_memory=Free Memory
type_proftpd=ProFTPD Server
type_dovecot=Dovecot IMAP/POP3 Server
@@ -66,7 +63,6 @@ type_raid=RAID Device Status
type_iface=Network Interface Status
type_init=Bootup Action
type_sensors=LM Sensor Status
type_nut=NUT UPS Value
type_mailq=Mail Queue Size
type_dns=DNS Lookup
type_query=SQL Query
@@ -78,6 +74,7 @@ type_smtp=SMTP Connection
type_imap=IMAP Connection
type_firewalld=FirewallD Server
type_reboot=Reboot Required
type_phpini=PHP-FPM Server
mon_create=Create Monitor
mon_edit=Edit Monitor
@@ -333,8 +330,6 @@ acl_sched=Can change scheduled monitoring?
change_file=File or directory to monitor (fail if changed)
jabber_eparser=The Perl module $1 is not installed on your system.
memory_min2=Minimum free real memory
memory_emin=Missing or invalid amount of free real memory
memory_eproc=Webmin does not know how to check free memory on your operating system
@@ -374,7 +369,7 @@ init_eaction=No action selected
refresh_title=Refresh Status
refresh_doing=Refreshing the status of all monitors ..
refresh_doing2=Refreshing the status of $1 selected monitors ..
refresh_done=.. done.
refresh_done=.. done
sensors_name=Sensor to check
sensors_value=Failed when
@@ -387,17 +382,6 @@ sensors_cur=$1 (currently $2 $3)
sensors_emin=Missing or invalid minimum value
sensors_emax=Missing or invalid maximum value
nut_ups=NUT UPS to check
nut_name=Attribute to check
nut_value=Failed when
nut_value1=Value is below $1
nut_value2=Value is above $1
nut_cmd=The command <tt>upsc</tt> is not installed on your system. This monitor requires the NUT package be installed and configured to operate.
nut_eups=No USP to check entered
nut_cur=$1 (currently $2)
nut_emin=Missing or invalid minimum value
nut_emax=Missing or invalid maximum value
mailq_system=Mail server
mailq_qmailadmin=Qmail
mailq_postfix=Postfix
@@ -622,4 +606,11 @@ imap_euser=Missing IMAP login
reboot_pkgs=Package updates require a reboot
phpini_file=PHP-FPM version
phpini_nofile=PHP-FPM configuration file not found!
phpini_efile=No PHP-FPM version selected!
phpini_noinit=No bootup action found for PHP-FPM version
phpini_noinit2=Bootup action $1 does not exist!
phpini_downinit=Bootup action $1 is down
__norefs=1

View File

@@ -1,89 +0,0 @@
# Check if some NUT value is too low or high
sub get_nut_status
{
return { 'up' => -1 } if (!&has_command("upsc"));
local @sens = &get_ups_values($_[0]->{'ups'});
local ($sens) = grep { $_->{'name'} eq $_[0]->{'name'} } @sens;
return { 'up' => 1 } if (!$sens);
if ($_[0]->{'mode'} == 1) {
return $sens->{'value'} < $_[0]->{'min'} ? { 'up' => 0 }
: { 'up' => 1 };
}
elsif ($_[0]->{'mode'} == 2) {
return $sens->{'value'} > $_[0]->{'max'} ? { 'up' => 0 }
: { 'up' => 1 };
}
}
sub show_nut_dialog
{
if (!&has_command("upsc")) {
print &ui_table_row(undef, $text{'nut_cmd'}, 4);
}
else {
# UPS name
print &ui_table_row($text{'nut_ups'},
&ui_textbox("ups", $_[0]->{'ups'}, 20));
# Value to check
local @sens = &get_ups_values();
if (@sens) {
print &ui_table_row($text{'nut_name'},
&ui_select("name", $_[0]->{'name'},
[ map { [ $_->{'name'},
&text('nut_cur', $_->{'name'}, $_->{'value'}) ] }
@sens ]));
}
else {
print &ui_table_row($text{'nut_name'},
&ui_textbox("name", $_[0]->{'name'}, 20));
}
# Expected value
print &ui_table_row($text{'nut_value'},
&ui_radio("mode", $_[0]->{'mode'} || 1,
[ [ 1, &text('sensors_value1',
&ui_textbox("min", $_[0]->{'min'}, 8)) ],
[ 2, &text('sensors_value2',
&ui_textbox("max", $_[0]->{'max'}, 8)) ] ]),
3);
}
}
sub parse_nut_dialog
{
&has_command("upsc") || &error($text{'nut_cmd'});
$in{'ups'} =~ /^\S+$/ || &error($text{'nut_eups'});
$_[0]->{'ups'} = $in{'ups'};
$_[0]->{'name'} = $in{'name'};
$_[0]->{'mode'} = $in{'mode'};
$_[0]->{'max'} = $in{'max'};
$_[0]->{'min'} = $in{'min'};
if ($in{'mode'} == 1) {
$in{'min'} =~ /^[0-9\.\+\-]+$/ || &error($text{'nut_emin'});
}
elsif ($in{'mode'} == 2) {
$in{'max'} =~ /^[0-9\.\+\-]+$/ || &error($text{'nut_emax'});
}
}
# get_ups_values(ups)
# Returns a list of NUT attribute names and values for some UPS
sub get_ups_values
{
if (!scalar(@get_ups_cache)) {
local @rv;
open(SENS, "upsc ".quotemeta($_[0])." 2>/dev/null |");
while(<SENS>) {
if (/^(\S+):\s+(.*)/) {
push(@rv, { 'name' => $1,
'value' => $2 });
}
}
close(SENS);
@get_ups_cache = @rv;
}
return @get_ups_cache;
}

51
status/phpini-monitor.pl Normal file
View File

@@ -0,0 +1,51 @@
# phpini-monitor.pl
# Monitor a FPM-FPM server
sub get_phpini_status
{
my ($serv, $mod) = @_;
return { 'up' => -1 } if (!&foreign_check("phpini"));
return { 'up' => -1 } if (!&foreign_check("init"));
&foreign_require("phpini");
my @files = &phpini::list_php_configs();
my ($file) = grep { $_->[0] eq $serv->{'inifile'} } @files;
return { 'up' => -1,
'desc' => $text{'phpini_nofile'} } if (!$file);
my $init = &phpini::get_php_ini_bootup($serv->{'inifile'});
return { 'up' => -1,
'desc' => $text{'phpini_noinit'} } if (!$init);
&foreign_require("init");
my $st = &init::status_action($init);
if ($st < 0) {
return { 'up' => -1,
'desc' => &text('phpini_noinit2', $init) };
}
elsif ($st > 0) {
return { 'up' => 1 };
}
else {
return { 'up' => 0,
'desc' => &text('phpini_downinit', $init) };
}
}
sub show_phpini_dialog
{
my ($serv) = @_;
&foreign_require("phpini");
my @files = grep { $_->[1] }
map { [ $_->[0], &phpini::get_php_ini_version($_->[0]) ] }
&phpini::list_php_configs();
my %donever;
@files = grep { !$donever{$_->[1]}++ } @files;
print &ui_table_row($text{'phpini_file'},
&ui_select("inifile", $serv->{'inifile'}, \@files));
}
sub parse_phpini_dialog
{
my ($serv) = @_;
$in{'inifile'} || &error($text{'phpini_efile'});
$serv->{'inifile'} = $in{'inifile'};
}

View File

@@ -3760,5 +3760,56 @@ my ($content, $attrs) = @_;
return ui_tag('p', $content, $attrs);
}
=head2 ui_text_mask(text, [tag], [extra_class])
Returns an HTML string with the given text hidden inside a tag that only shows
on hover. If a second parameter is given, it is used as the outer tag that
triggers the hover (default is "td"). If a third parameter is provided,
it is added as an extra class to both the tag and its style.
=cut
sub ui_text_mask
{
return &theme_ui_text_mask(@_) if (defined(&theme_ui_text_mask));
my ($text, $tag, $extra_class) = @_;
my $class = 'hover-mask';
my $classcss = ".$class";
if ($extra_class) {
$class .= " $extra_class";
$classcss .= ".$extra_class";
}
$tag ||= 'td';
my $style_content = <<"CSS";
x-ui-text-mask${classcss} {
position: relative;
display: inline-block;
color: transparent;
transition:color .25s ease;
}
x-ui-text-mask${classcss}::after{
content: attr(data-mask);
position: absolute;
inset: 0;
color: var(--ui-password-mask-color, #000);
pointer-events: none;
transition: opacity .25s ease;
}
$tag:has(>*>x-ui-text-mask${classcss}):hover x-ui-text-mask${classcss},
$tag:has(>x-ui-text-mask${classcss}):hover x-ui-text-mask${classcss}{
color: inherit;
}
$tag:has(>*>x-ui-text-mask${classcss}):hover x-ui-text-mask${classcss}::after,
$tag:has(>x-ui-text-mask${classcss}):hover x-ui-text-mask${classcss}::after{
opacity: 0;
}
CSS
my $rv = '';
$rv .= &ui_tag('style', $style_content, { type => 'text/css' })
if (!$main::ui_text_mask_donecss->{"$tag$class"}++);
$rv .= &ui_tag('x-ui-text-mask', $text,
{ 'class' => $class, 'data-mask' => '••••••••' });
return $rv;
}
1;

View File

@@ -1077,11 +1077,13 @@ sub PrintHeader
{
my ($cs, $mt, $headers) = @_;
$mt ||= "text/html";
if ($ENV{'SSL_HSTS'} == 1 && uc($ENV{'HTTPS'}) eq "ON") {
print "Strict-Transport-Security: max-age=31536000;\n";
}
elsif (uc($ENV{'HTTPS'}) ne "ON") {
print "Strict-Transport-Security: max-age=0;\n";
if (uc($ENV{'HTTPS'}) eq "ON") {
if ($ENV{'SSL_HSTS'}) {
print "Strict-Transport-Security: max-age=31536000;\n";
}
else {
print "Strict-Transport-Security: max-age=0;\n";
}
}
if ($pragma_no_cache || $gconfig{'pragma_no_cache'}) {
print "pragma: no-cache\n";

View File

@@ -28,7 +28,7 @@ print &ui_table_row($text{'debug_file'},
print &ui_table_row($text{'debug_size'},
&ui_radio("debug_size_def", $gconfig{'debug_size'} ? 0 : 1,
[ [ 1, $text{'default'}.
" (".&nice_size($main::default_debug_log_size).")" ],
" (".&html_strip(&nice_size($main::default_debug_log_size)).")" ],
[ 0, &ui_bytesbox("debug_size", $gconfig{'debug_size'}) ] ]
), undef, [ "valign=middle","valign=middle" ]);