From 0b81c3c3603ae14ed385f8d0d021ac1bf859b0fe Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Sun, 16 Aug 2026 22:23:04 +0200 Subject: [PATCH 01/10] Update changelog --- CHANGELOG.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db4f438ad..42169121b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,12 @@ ## Changelog -#### 2.654 (August, 2026) -* Add incremental ban time options to the Fail2Ban module +#### 2.660 (August 16, 2026) * Add Btrfs subvolume quota management to the Disk Quotas module, with full and simple accounting modes * Add support for creating `vfsv1` Linux quota files for limits above 4 TiB, while preserving existing quota file formats +* Add incremental ban time options to the Fail2Ban module +* Add APT package hold management to the Package Updates module * Add support for openSUSE 16 vendor and local Logrotate configuration overlays [#2682](https://github.com/webmin/webmin/issues/2682) -* Fix to ignore failures when adding IPv6 link-local (fe80::) addresses that may already be configured automatically +* Fix Webmin server connections that open but never send a request, preventing them from waiting indefinitely [#2815](https://github.com/webmin/webmin/pull/2815) +* Fix to ignore failures when adding IPv6 link-local (fe80\:\:) addresses that may already be configured automatically * Fixed creation of permissions new log files in the System Logs module (thanks to Kevin Carter) * Update the Authentic theme to the latest version with various improvements: - Fix disallowed entry handling in File Manager [forum.virtualmin.com/t/137654](https://forum.virtualmin.com/t/extra-admin-file-manager-permissions/137654?u=ilia) From b5194d52a61edec64a47e3e835af40783015eca8 Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Mon, 17 Aug 2026 00:11:39 +0200 Subject: [PATCH 02/10] Fix to show logrotate output only when non-empty --- logrotate/save_log.cgi | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/logrotate/save_log.cgi b/logrotate/save_log.cgi index 0be324331..6235543fa 100755 --- a/logrotate/save_log.cgi +++ b/logrotate/save_log.cgi @@ -73,8 +73,13 @@ elsif ($in{'now'}) { print $text{'force_doingone'},"\n"; ($ex, $out) = &rotate_log_now($log); - print "
$out
"; - if ($?) { + if ($out =~ /\S/) { + print "
",&html_escape($out),"
"; + } + else { + print "
\n"; + } + if ($ex) { print $text{'force_failed'},"
\n"; } else { From dd7788a09e5aedae9889072c7d2f448e1e6c36f5 Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Mon, 17 Aug 2026 00:16:55 +0200 Subject: [PATCH 03/10] Update changelog --- CHANGELOG.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42169121b..79ee22975 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,18 +1,22 @@ ## Changelog #### 2.660 (August 16, 2026) -* Add Btrfs subvolume quota management to the Disk Quotas module, with full and simple accounting modes * Add support for creating `vfsv1` Linux quota files for limits above 4 TiB, while preserving existing quota file formats -* Add incremental ban time options to the Fail2Ban module -* Add APT package hold management to the Package Updates module +* Add Btrfs subvolume quota management to the Disk Quotas module, with full and simple accounting modes * Add support for openSUSE 16 vendor and local Logrotate configuration overlays [#2682](https://github.com/webmin/webmin/issues/2682) +* Add APT package hold management to the Package Updates module +* Add incremental ban time options to the Fail2Ban module * Fix Webmin server connections that open but never send a request, preventing them from waiting indefinitely [#2815](https://github.com/webmin/webmin/pull/2815) * Fix to ignore failures when adding IPv6 link-local (fe80\:\:) addresses that may already be configured automatically * Fixed creation of permissions new log files in the System Logs module (thanks to Kevin Carter) * Update the Authentic theme to the latest version with various improvements: + - Fix change detection and submission for forms using grouped bottom action buttons + - Fix login page front side clipping and flip animation for long welcome messages + - Fix opening the wrong directory in Terminal for domain owners in File Manager - Fix disallowed entry handling in File Manager [forum.virtualmin.com/t/137654](https://forum.virtualmin.com/t/extra-admin-file-manager-permissions/137654?u=ilia) - - Fix File Manager errors for Webmin-only users - - Fix File Manager opening the wrong directory in Terminal for domain owners - - Fix support for navigation detection for the upcoming Virtualmin Podman plugin + - Fix inline images not displaying when printing emails in Usermin + - Fix navigation detection for the new Virtualmin Podman plugin + - Fix bottom page action buttons wrapping and alignment + - Fix errors for Webmin-only users in File Manager #### 2.653 (July 26, 2026) * Fix to include missing `xmlrpc-lib.pl` file in the package From aa3db4ddbfc66a9aacf4f2056cd8292fd575c7cc Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Mon, 17 Aug 2026 19:06:25 +0200 Subject: [PATCH 04/10] Fix patch command to apply with git inside another repository MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ⓘ When GNU patch is not installed, git apply was run inside the module directory, and if the Webmin root itself was a git repository, git resolved paths relative to that root and silently skipped the patched files. Limit repository discovery to the current directory and allow reduced context, similar to the default fuzz used by patch, so slightly drifted context lines no longer cause a rejection. --- bin/patch | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/bin/patch b/bin/patch index b52970c23..53923f53f 100755 --- a/bin/patch +++ b/bin/patch @@ -163,7 +163,14 @@ elsif (has_command('patch')) { } # Apply patch using git command else { - $output = `$cmd 2>&1 | git apply --reject --verbose --whitespace=fix 2>&1`; + # If the current directory is inside some git repository (e.g. Webmin + # root tracked with git), git would treat patch paths as relative to + # that repository root and silently skip them, so stop repository + # discovery at the parent directory to always apply patch paths + # relative to the current directory + local $ENV{'GIT_CEILING_DIRECTORIES'} = dirname(cwd()); + # Allow reduced context, similar to the default fuzz used by patch + $output = `$cmd 2>&1 | git apply --reject --verbose -C1 --whitespace=fix 2>&1`; if ($output !~ /applied patch.*?cleanly/i) { print "Patch failed: $output\n"; exit 1; From 77f78cdb758c3218eb566228563b34ec35794207 Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Mon, 17 Aug 2026 19:11:18 +0200 Subject: [PATCH 05/10] Fix patch command to not leave .orig backup files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ⓘ GNU patch keeps a .orig copy of the original file whenever a hunk applies with fuzz or offset, which is common when patching an installed release with a commit from the master branch. Pass --no-backup-if-mismatch, since backups are not needed. --- bin/patch | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/patch b/bin/patch index 53923f53f..067901b90 100755 --- a/bin/patch +++ b/bin/patch @@ -155,7 +155,8 @@ if ($direct) { } # Apply patch using patch command elsif (has_command('patch')) { - $output = `$cmd 2>&1 | patch -p1 --verbose 2>&1`; + # Do not leave .orig backups behind when hunks apply with fuzz or offset + $output = `$cmd 2>&1 | patch -p1 --verbose --no-backup-if-mismatch 2>&1`; if ($output !~ /succeeded/i) { print "Patch failed: $output\n"; exit 1; From c76fda35ce5a5496b3f3688b871ee8fc6afc4987 Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Mon, 17 Aug 2026 21:43:28 +0200 Subject: [PATCH 06/10] Add support for applying multiple patches with patch command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ⓘ Allow passing several patch URLs or files at once, e.g. webmin patch url1 url2 url3. Patches are applied in the given order, stopping at the first failure, and Webmin is reloaded only once after all of them are applied. --- bin/patch | 82 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 19 deletions(-) diff --git a/bin/patch b/bin/patch index 067901b90..5223e320b 100755 --- a/bin/patch +++ b/bin/patch @@ -1,5 +1,6 @@ #!/usr/bin/env perl -# patch - Apply a patch to Webmin core or its modules from GitHub or a local file +# patch - Apply one or more patches to Webmin core or its modules from +# GitHub or a local file use strict; use warnings; @@ -49,20 +50,55 @@ if (!has_command('patch')) { } } -# Get patch URL or file -my $patch = $ARGV[0]; +# Get patch URLs or files +my @patches = @ARGV; # Params check -if (!$patch) { +if (!@patches) { pod2usage(0); exit 1; } +# Apply all patches in the given order, stopping at the first failure +my $orig_cwd = cwd(); +my $applied = 0; +my $failed = 0; +foreach my $patch (@patches) { + # Show which patch is being applied if there are multiple + print "Applying $patch ..\n" if (@patches > 1); + # Always start from the original directory, as applying a patch + # may change it + chdir($orig_cwd); + if (!apply_patch($patch)) { + $failed = 1; + last; + } + $applied++; + } + +# Reload Webmin once, if any patches were applied +reload_miniserv() if ($applied); + +# Report if some patches were not applied +if ($failed) { + print "Stopped: $applied of ".scalar(@patches)." patches applied\n" + if (@patches > 1); + exit 1; + } +exit 0; + +# apply_patch(patch) +# Apply a single patch given as URL or local file, printing the outcome +# and returning 1 on success or 0 on failure +sub apply_patch +{ +my ($patch) = @_; + # Patch check if ($patch !~ /^https?:\/\//) { if (!-r $patch) { print "Patch file $patch doesn't exist\n"; - exit 1; + return 0; } } elsif ($patch =~ /^https?:\/\/(github|gitlab)\.com/ && @@ -101,9 +137,9 @@ if ($patch =~ m{ # Check if module exists if (!-d "$path/$module") { - print "Module '$module' doesn't exist\n"; - exit 1; -} + print "Module '$module' doesn't exist\n"; + return 0; + } # Prepare patch command my $cmd; @@ -128,7 +164,7 @@ if ($patch =~ m{^https?://raw\.githubusercontent\.com/} || } else { print "Patch failed: Can't parse file name from URL\n"; - exit 1; + return 0; } my $cd = "$path/$module/$dir"; $cd =~ s|/+|/|g; @@ -149,9 +185,9 @@ else { if ($direct) { $output = `$cmd 2>&1`; if ($output != 200) { - print "Patch failed: Cannot download '$filename'. HTTP status code: $output\n"; - exit 1; - } + print "Patch failed: Cannot download '$filename'. HTTP status code: $output\n"; + return 0; + } } # Apply patch using patch command elsif (has_command('patch')) { @@ -159,7 +195,7 @@ elsif (has_command('patch')) { $output = `$cmd 2>&1 | patch -p1 --verbose --no-backup-if-mismatch 2>&1`; if ($output !~ /succeeded/i) { print "Patch failed: $output\n"; - exit 1; + return 0; } } # Apply patch using git command @@ -174,9 +210,9 @@ else { $output = `$cmd 2>&1 | git apply --reject --verbose -C1 --whitespace=fix 2>&1`; if ($output !~ /applied patch.*?cleanly/i) { print "Patch failed: $output\n"; - exit 1; + return 0; } -} + } # Print results if ($direct) { @@ -191,11 +227,10 @@ if ($direct) { else { print "Patch applied successfully to:\n"; print " $1\n" while $output =~ /^(?|Applied patch\s+(\S+)|patching file\s+(\S+))/mg; + } +return 1; } -# Reload Webmin -reload_miniserv(); - =pod =head1 NAME @@ -207,9 +242,13 @@ patch Apply a patch to Webmin core or its modules from GitHub/GitLab, a local file, or by downloading and replacing the entire file from a raw URL. +Multiple patches can be given at once and are applied in the given order, +stopping at the first failure. Webmin is reloaded only once after all +patches are applied. + =head1 SYNOPSIS -webmin patch patch-url/file +webmin patch patch-url/file [patch-url/file ...] =head1 OPTIONS @@ -237,6 +276,11 @@ Examples of usage: - cd /usr/libexec/webmin/virtual-server/pro && webmin patch /root/virtualmin-pro/patches/patch-1.patch + Apply multiple patches at once. + + - webmin patch https://github.com/webmin/webmin/commit/e6a2bb15b0 \ + https://github.com/virtualmin/virtualmin-gpl/commit/f4433153d + =back =head1 LICENSE AND COPYRIGHT From dde9d46b1ea27d066aeb38ef2a7864c933fd8073 Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Mon, 17 Aug 2026 23:30:17 +0200 Subject: [PATCH 07/10] Fix patch command to restart Webmin instead of reloading --- bin/patch | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bin/patch b/bin/patch index 5223e320b..2d9afff24 100755 --- a/bin/patch +++ b/bin/patch @@ -76,8 +76,9 @@ foreach my $patch (@patches) { $applied++; } -# Reload Webmin once, if any patches were applied -reload_miniserv() if ($applied); +# Restart Webmin once, if any patches were applied, so that changes to +# any file, including miniserv.pl itself, take effect +restart_miniserv() if ($applied); # Report if some patches were not applied if ($failed) { @@ -243,7 +244,7 @@ Apply a patch to Webmin core or its modules from GitHub/GitLab, a local file, or by downloading and replacing the entire file from a raw URL. Multiple patches can be given at once and are applied in the given order, -stopping at the first failure. Webmin is reloaded only once after all +stopping at the first failure. Webmin is restarted only once after all patches are applied. =head1 SYNOPSIS From c7780ed2ae772299f48424828dbb9b994b964cee Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Mon, 17 Aug 2026 23:35:11 +0200 Subject: [PATCH 08/10] Update changelog --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79ee22975..ea236738d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,9 @@ ## Changelog -#### 2.660 (August 16, 2026) +#### 2.660 (August 17, 2026) * Add support for creating `vfsv1` Linux quota files for limits above 4 TiB, while preserving existing quota file formats * Add Btrfs subvolume quota management to the Disk Quotas module, with full and simple accounting modes * Add support for openSUSE 16 vendor and local Logrotate configuration overlays [#2682](https://github.com/webmin/webmin/issues/2682) +* Add support for applying multiple patches at once with the `patch` sub-command * Add APT package hold management to the Package Updates module * Add incremental ban time options to the Fail2Ban module * Fix Webmin server connections that open but never send a request, preventing them from waiting indefinitely [#2815](https://github.com/webmin/webmin/pull/2815) From c27917e4a32e359afba65bd96795e9ee6d59a9b6 Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Tue, 18 Aug 2026 00:11:00 +0200 Subject: [PATCH 09/10] Fix Fail2Ban jail editor to correctly separate actions without params #2718 --- CHANGELOG.md | 1 + fail2ban/fail2ban-lib.pl | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea236738d..77fda4d24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ * Fix Webmin server connections that open but never send a request, preventing them from waiting indefinitely [#2815](https://github.com/webmin/webmin/pull/2815) * Fix to ignore failures when adding IPv6 link-local (fe80\:\:) addresses that may already be configured automatically * Fixed creation of permissions new log files in the System Logs module (thanks to Kevin Carter) +* Fix Fail2Ban jail editor to correctly separate actions when one has no parameters [#2718](https://github.com/webmin/webmin/issues/2718) * Update the Authentic theme to the latest version with various improvements: - Fix change detection and submission for forms using grouped bottom action buttons - Fix login page front side clipping and flip animation for long welcome messages diff --git a/fail2ban/fail2ban-lib.pl b/fail2ban/fail2ban-lib.pl index fe7b0a609..fa482ea1a 100644 --- a/fail2ban/fail2ban-lib.pl +++ b/fail2ban/fail2ban-lib.pl @@ -210,7 +210,7 @@ my @w; my $v = $dir->{'value'}; $v =~ s/\n/ /g; while($v =~ /\S/) { - if ($v =~ /^([^\[]+\[[^\]]+\])\s*(.*)/) { + if ($v =~ /^\s*([^\s\[]+\[[^\]]*\])\s*(.*)/) { push(@w, $1); $v = $2; } From 0e0f7622b5b6f3dc89f81099de4fe6420142a562 Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Tue, 18 Aug 2026 00:12:19 +0200 Subject: [PATCH 10/10] Fix Fail2Ban continuation lines to align under the directive value --- fail2ban/fail2ban-lib.pl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fail2ban/fail2ban-lib.pl b/fail2ban/fail2ban-lib.pl index fa482ea1a..88c4e9a3d 100644 --- a/fail2ban/fail2ban-lib.pl +++ b/fail2ban/fail2ban-lib.pl @@ -408,7 +408,9 @@ my @rv; my @v = ref($dir->{'value'}) eq 'ARRAY' ? @{$dir->{'value'}} : split(/\n/, $dir->{'value'}); push(@rv, $dir->{'name'}." = ".shift(@v)); -push(@rv, map { " ".$_ } @v); # Continuation +# Indent continuation lines to align with the first value +my $indent = " " x (length($dir->{'name'}) + 3); +push(@rv, map { $indent.$_ } @v); return @rv; }