mirror of
https://github.com/webmin/webmin.git
synced 2026-02-04 22:52:14 +00:00
Compare commits
74 Commits
dev/fix-la
...
2.200
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2751224d4d | ||
|
|
6fce9fa491 | ||
|
|
41fdb5dac2 | ||
|
|
4ffca4597c | ||
|
|
ecfc06d9c6 | ||
|
|
db55dde7ce | ||
|
|
c6edd4b97d | ||
|
|
8cd2dbae96 | ||
|
|
8676a3fb21 | ||
|
|
27339eb1bf | ||
|
|
e014926854 | ||
|
|
a721f60f9c | ||
|
|
46c76e13f9 | ||
|
|
f72058306b | ||
|
|
a15446d3b1 | ||
|
|
fc9ce7f3dd | ||
|
|
72cd50a054 | ||
|
|
e307fb4dcd | ||
|
|
d631929194 | ||
|
|
db9628e7eb | ||
|
|
2c04c04ce7 | ||
|
|
a5301245d3 | ||
|
|
165af690c7 | ||
|
|
29da8ea3d0 | ||
|
|
73b7e62f13 | ||
|
|
76141ce22f | ||
|
|
4b575b8168 | ||
|
|
2b28521297 | ||
|
|
be767951ca | ||
|
|
9960d6011f | ||
|
|
461bd30e2a | ||
|
|
2f88a4eefb | ||
|
|
c9f368d264 | ||
|
|
0e24e8ac61 | ||
|
|
1d0d25efac | ||
|
|
1c5d2d2bd7 | ||
|
|
77e809166c | ||
|
|
927a2c32d8 | ||
|
|
4a3c6c4854 | ||
|
|
37beab77ba | ||
|
|
82f5284ffc | ||
|
|
5f579e8ded | ||
|
|
4b66ac0be5 | ||
|
|
e69fb75c8e | ||
|
|
ff8781c112 | ||
|
|
0dd75db8d8 | ||
|
|
05d01aeef3 | ||
|
|
11f2bc20eb | ||
|
|
52c3178b92 | ||
|
|
e3dec2222d | ||
|
|
05752faec0 | ||
|
|
7507433bf1 | ||
|
|
248cb719c0 | ||
|
|
94b7fdf0ec | ||
|
|
d89f6411b6 | ||
|
|
01d08a3605 | ||
|
|
1cf3813fb6 | ||
|
|
1216ae709b | ||
|
|
3d9497ff45 | ||
|
|
a6832450d1 | ||
|
|
e41037388c | ||
|
|
a7b3af534b | ||
|
|
87e006ceeb | ||
|
|
fbee8f0588 | ||
|
|
e077b4da94 | ||
|
|
38efad8265 | ||
|
|
4d2a1fa084 | ||
|
|
13b2eca3b1 | ||
|
|
aa4c3b1de6 | ||
|
|
edaab4fd6f | ||
|
|
6fded0862c | ||
|
|
4006b0454e | ||
|
|
5d4ab58baa | ||
|
|
e6c7a60fe6 |
24
CHANGELOG.md
24
CHANGELOG.md
@@ -1,5 +1,29 @@
|
||||
## Changelog
|
||||
|
||||
#### 2.200 (July 21, 2024)
|
||||
* Add support for blocking a given IP temporarily or permanently in the FirewallD module
|
||||
* Add support for parsing iCalendar event files in the Mailbox module
|
||||
* Add support for tailing logs in real time in System Logs module
|
||||
* Add ability to preserve original file ACLs when writing files [webmin/authentic-theme#1511](https://github.com/webmin/authentic-theme/discussions/1511#discussioncomment-9913902)
|
||||
* Add a `patch` sub-command to the `webmin` command for easy application of patches
|
||||
* Add a config option to display hostname and comment in the DHCP Server module [#2221](https://github.com/webmin/webmin/issues/2221)
|
||||
* Add support for ED25519 and ED448 algorithms in BIND DNS module for DNSSEC
|
||||
* Add support for larger ranger of authentication methods in Dovecot module
|
||||
* Add improved support for displaying last logins in the Users and Groups module
|
||||
* Fix to prevent duplicate `also-notify` and `allow-transfer` IPs in the BIND DNS module
|
||||
* Fix issues with Terminal module to correct text display problems in editor mode
|
||||
* Fix to allow disabling the newly introduced enforcement of _sudo_-capable logins in the Terminal module
|
||||
* Fix to store Terminal module logs in the `/var/webmin` directory
|
||||
* Fix to display the Spam folder nicely in the Mailbox module
|
||||
* Fix how modules are loaded in ProFTPd module
|
||||
* Fix support for the Chrony service on Debian systems in the System Time module
|
||||
* Fix to use static routes to set the default gateway in Network Configuration module
|
||||
* Fix to correctly invalidate EOL cache on re-checks [#2139](https://github.com/webmin/webmin/issues/2139)
|
||||
* Fix to change default monitor name based on database used MariaDB vs MySQL [#2139](https://github.com/virtualmin/virtualmin-gpl/issues/798)
|
||||
* Fix to disable manual upgrades for systems installed from the repository
|
||||
* Fix to preserve Webmin service state during package upgrades [#2133](https://github.com/webmin/webmin/issues/2133)
|
||||
* Rename "System Logs" module to "System Logs RS" and "System Logs Viewer" to "System Logs" for clarity
|
||||
|
||||
#### 2.111 (April 16, 2024)
|
||||
* Fix EOL detection for unreleased Linux distributions
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
153
bin/patch
Executable file
153
bin/patch
Executable file
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env perl
|
||||
# patch - Apply a patch to Webmin core or its modules from GitHub or a local file
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use 5.010;
|
||||
|
||||
use Getopt::Long qw(:config permute pass_through);
|
||||
use Pod::Usage;
|
||||
use File::Basename;
|
||||
use Cwd qw(cwd);
|
||||
|
||||
my %opt;
|
||||
GetOptions(
|
||||
'help|h' => \$opt{'help'},
|
||||
'config|c=s' => \$opt{'config'},
|
||||
);
|
||||
pod2usage(0) if ($opt{'help'});
|
||||
|
||||
# Get Webmin path
|
||||
my $path = cwd;
|
||||
my $lib = "web-lib-funcs.pl";
|
||||
if (!-r "$path/$lib") {
|
||||
$path = dirname(dirname($0));
|
||||
if (!-r "$path/$lib") {
|
||||
$path = $path = Cwd::realpath('..');
|
||||
}
|
||||
}
|
||||
|
||||
# Init core
|
||||
my $config_dir = $opt{'config'} || '/etc/webmin';
|
||||
$ENV{'WEBMIN_CONFIG'} = $config_dir;
|
||||
push(@INC, $path);
|
||||
eval 'use WebminCore';
|
||||
init_config();
|
||||
|
||||
# Check if curl is installed
|
||||
if (!has_command('curl')) {
|
||||
print "curl is not installed\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# Check if git is installed
|
||||
if (!has_command('git')) {
|
||||
print "git is not installed\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# Get patch URL or file
|
||||
my $patch = $ARGV[0];
|
||||
|
||||
# Params check
|
||||
if (!$patch) {
|
||||
pod2usage(0);
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# Patch check
|
||||
if ($patch !~ /^https?:\/\//) {
|
||||
if (!-r $patch) {
|
||||
print "Patch file $patch doesn't exist\n";
|
||||
exit 1;
|
||||
}
|
||||
}
|
||||
elsif ($patch =~ /^https?:\/\/(github|gitlab)\.com/ &&
|
||||
$patch !~ /\.patch$/ && $patch !~ /\.diff$/) {
|
||||
$patch .= '.patch';
|
||||
}
|
||||
|
||||
# Parse module name from URL
|
||||
my $module = "";
|
||||
if ($patch =~ m{https://(github|gitlab)\.com/[^/]+/([^/]+)/commit/[^/]+}) {
|
||||
$module = $2;
|
||||
$module = "" if ($2 eq 'webmin');
|
||||
# Special handling for some modules
|
||||
$module = $module =~ /^virtualmin-pro$/ ?
|
||||
'virtual-server/pro' :
|
||||
'virtual-server'
|
||||
if $module =~ /^virtualmin-(gpl|pro)$/;
|
||||
}
|
||||
|
||||
# Check if module exists
|
||||
if (!-d "$path/$module") {
|
||||
print "Module $module doesn't exist\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# Download command or cat patch file
|
||||
my $cmd;
|
||||
if ($patch =~ /^https?:\/\//) {
|
||||
$cmd = "curl -s @{[quotemeta($patch)]}";
|
||||
chdir "$path/$module";
|
||||
}
|
||||
else {
|
||||
$cmd = "cat @{[quotemeta($patch)]}";
|
||||
}
|
||||
|
||||
# Apply patch using Git
|
||||
my $output = `$cmd 2>&1 | git apply --reject --verbose --whitespace=fix 2>&1`;
|
||||
if ($output !~ /applied patch.*?cleanly/i) {
|
||||
print "Patch failed: $output\n";
|
||||
exit 1;
|
||||
}
|
||||
print "Patch applied successfully to:\n";
|
||||
print " $1\n" while $output =~ /^Applied patch\s+(\S+)/mg;
|
||||
system("$config_dir/restart");
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
patch
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Apply a patch to Webmin core or its modules from GitHub or a local file.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
webmin patch patch-url/file
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=over
|
||||
|
||||
=item --help, -h
|
||||
|
||||
Give this help list.
|
||||
|
||||
=item --config, -c
|
||||
|
||||
Specify the full path to the Webmin configuration directory. Defaults to
|
||||
C</etc/webmin>
|
||||
|
||||
Examples of usage:
|
||||
|
||||
Apply a patch from a URL.
|
||||
|
||||
- webmin patch https://github.com/webmin/webmin/commit/e6a2bb15b0.patch
|
||||
|
||||
- webmin patch https://github.com/virtualmin/virtualmin-gpl/commit/f4433153d
|
||||
|
||||
Apply a patch from local file.
|
||||
|
||||
- cd /usr/libexec/webmin/virtual-server/pro &&
|
||||
webmin patch /root/virtualmin-pro/patches/patch-1.patch
|
||||
|
||||
=back
|
||||
|
||||
=head1 LICENSE AND COPYRIGHT
|
||||
|
||||
Copyright 2024 Ilia Ross <ilia@virtualmin.com>
|
||||
@@ -17,7 +17,6 @@ $access{'defaults'} || &error($text{'trusted_ecannot'});
|
||||
my $conf = &get_config();
|
||||
my $options = &find("options", $conf);
|
||||
my $mems = $options->{'members'};
|
||||
my @dlv = &find("dnssec-lookaside", $mems);
|
||||
my $tkeys = &find("trusted-keys", $conf);
|
||||
$tkeys ||= { 'members' => [ ] };
|
||||
|
||||
@@ -38,33 +37,6 @@ if (&supports_dnssec_client() == 2) {
|
||||
$text{'default'}, undef);
|
||||
}
|
||||
|
||||
# Trusted DLVs (obsolete)
|
||||
if (@dlv) {
|
||||
my @dtable = ( );
|
||||
my $i = 0;
|
||||
foreach my $d (@dlv, { 'values' => [ '.' ] }) {
|
||||
my $dlv = $d->{'values'}->[0];
|
||||
$dlv = "" if ($dlv eq ".");
|
||||
push(@dtable, [
|
||||
&ui_opt_textbox("anchor_$i", $d->{'values'}->[2],
|
||||
30, $text{'trusted_none'}),
|
||||
&ui_opt_textbox("dlv_$i", $dlv, 20,
|
||||
$text{'trusted_root'}) ]);
|
||||
$i++;
|
||||
}
|
||||
print &ui_table_row($text{'trusted_dlvs'},
|
||||
&ui_radio("dlv_auto",
|
||||
@dlv == 0 ? 2 :
|
||||
@dlv == 1 && $dlv[0]->{'values'}->[0] eq 'auto' ? 1 : 0,
|
||||
[ [ 1, $text{'trusted_dlvs1'} ],
|
||||
[ 2, $text{'trusted_dlvs2'} ],
|
||||
[ 0, $text{'trusted_dlvs0'} ] ])."<br>\n".
|
||||
&ui_columns_table([ $text{'trusted_anchor'},
|
||||
$text{'trusted_dlv'} ],
|
||||
undef,
|
||||
\@dtable), 3);
|
||||
}
|
||||
|
||||
# Trusted keys
|
||||
if (@{$tkeys->{'members'}}) {
|
||||
my @ktable = ( );
|
||||
|
||||
@@ -24,46 +24,6 @@ if (&supports_dnssec_client() == 2) {
|
||||
&save_choice("dnssec-validation", $options, 1);
|
||||
}
|
||||
|
||||
# Save DLV zones
|
||||
if (defined($in{'dlv_auto'})) {
|
||||
my @dlvs = ( );
|
||||
if ($in{'dlv_auto'} == 1) {
|
||||
# Automatic mode
|
||||
push(@dlvs, { 'name' => 'dnssec-lookaside',
|
||||
'values' => [ 'auto' ] });
|
||||
}
|
||||
elsif ($in{'dlv_auto'} == 0) {
|
||||
# Listed zones
|
||||
my $dlv;
|
||||
for(my $i=0; defined($in{"anchor_$i"}); $i++) {
|
||||
if (!$in{"anchor_${i}_def"}) {
|
||||
$in{"anchor_$i"} =~ /^[a-z0-9\.\-\_]+$/ ||
|
||||
&error(&text('trusted_eanchor', $i+1));
|
||||
$in{"anchor_$i"} .= "."
|
||||
if ($in{"anchor_$i"} !~ /\.$/);
|
||||
if ($in{"dlv_${i}_def"}) {
|
||||
$dlv = ".";
|
||||
}
|
||||
else {
|
||||
$in{"dlv_$i"} =~ /^[a-z0-9\.\-\_]+$/ ||
|
||||
&error(&text('trusted_edlv', $i+1));
|
||||
$dlv = $in{"dlv_$i"};
|
||||
$dlv .= "." if ($dlv !~ /\.$/);
|
||||
}
|
||||
push(@dlvs, { 'name' => 'dnssec-lookaside',
|
||||
'values' => [
|
||||
$dlv, "trust-anchor",
|
||||
$in{"anchor_$i"} ] });
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif ($in{'dlv_auto'} == 2) {
|
||||
# None
|
||||
@dlvs = ( );
|
||||
}
|
||||
&save_directive($options, "dnssec-lookaside", \@dlvs, 1);
|
||||
}
|
||||
|
||||
# Save trusted keys
|
||||
if (defined($in{'zone_0'})) {
|
||||
my @keys = ( );
|
||||
|
||||
@@ -21,7 +21,7 @@ if ($in{'source'} == 0) {
|
||||
if (!$in{'local'})
|
||||
{ &install_error($text{'download_elocal'}); }
|
||||
if (!-r $in{'local'})
|
||||
{ &install_error(&text('download_elocal2', $in{'local'})); }
|
||||
{ &install_error(&text('download_elocal2', &html_escape($in{'local'}))); }
|
||||
$source = $in{'local'};
|
||||
@pfile = ( $in{'local'} );
|
||||
$need_unlink = 0;
|
||||
@@ -91,8 +91,9 @@ elsif ($in{'source'} == 3) {
|
||||
$i = 0;
|
||||
@fallback = ( );
|
||||
foreach $yum (@cpanyum) {
|
||||
print &text('download_yum', "<tt>$cpan[$i]</tt>",
|
||||
"<tt>$yum->{'package'}</tt>"),"<br>\n";
|
||||
print &text('download_yum',
|
||||
"<tt>".&html_escape($cpan[$i])."</tt>",
|
||||
"<tt>".&html_escape($yum->{'package'})."</tt>"),"<br>\n";
|
||||
print "<ul>\n";
|
||||
@got = &software::update_system_install(
|
||||
$yum->{'package'});
|
||||
@@ -154,7 +155,8 @@ elsif ($in{'source'} == 3) {
|
||||
|
||||
# Fail if any modules are missing from CPAN
|
||||
for($i=0; $i<@cpan; $i++) {
|
||||
push(@missing, "<tt>$cpan[$i]</tt>") if (!$source[$i]);
|
||||
push(@missing, "<tt>".&html_escape($cpan[$i])."</tt>")
|
||||
if (!$source[$i]);
|
||||
}
|
||||
|
||||
if ($in{'missingok'}) {
|
||||
@@ -167,11 +169,12 @@ elsif ($in{'source'} == 3) {
|
||||
}
|
||||
}
|
||||
@cpan || &install_error(&text('download_ecpan',
|
||||
join(" ", @missing)));
|
||||
&html_escape(join(" ", @missing))));
|
||||
}
|
||||
elsif (@missing) {
|
||||
# Fail due to missing modules
|
||||
&install_error(&text('download_ecpan', join(" ", @missing)));
|
||||
&install_error(&text('download_ecpan',
|
||||
&html_escape(join(" ", @missing))));
|
||||
}
|
||||
$source = join("<br>", @source);
|
||||
|
||||
@@ -192,14 +195,16 @@ elsif ($in{'source'} == 3) {
|
||||
&ftp_download($host, $file, $pfile, \$error,
|
||||
\&progress_callback);
|
||||
}
|
||||
else { &install_error(&text('download_eurl', $m)); }
|
||||
else {
|
||||
&install_error(&text('download_eurl',&html_escape($m)));
|
||||
}
|
||||
&install_error($error) if ($error);
|
||||
push(@pfile, $pfile);
|
||||
}
|
||||
$need_unlink = 1;
|
||||
}
|
||||
else {
|
||||
&error("Unknown source mode $in{'source'}");
|
||||
&error("Unknown source mode ".&html_escape($in{'source'}));
|
||||
}
|
||||
|
||||
# Check if the file looks like a perl module
|
||||
@@ -287,7 +292,7 @@ foreach $d (@dirs) {
|
||||
close(MAKEFILE);
|
||||
push(@allreqs, @prereqs);
|
||||
}
|
||||
system("rm -rf $mtemp");
|
||||
&unlink_file($mtemp);
|
||||
|
||||
# Work out which pre-requesites are missing
|
||||
@allreqs = &unique(@allreqs);
|
||||
|
||||
@@ -8,7 +8,7 @@ lease_refresh=Seconds between refreshing lease list,3,Never
|
||||
show_ip=Show IP addresses for hosts?,1,1-Yes,0-No
|
||||
show_mac=Show MAC addresses for hosts?,1,1-Yes,0-No
|
||||
group_name=Show group names as,1,1-<tt>domain-name</tt> option,0-Name or member count,2-Description
|
||||
desc_name=Show other object descriptions instead of names?,1,1-Yes,0-No
|
||||
desc_name=Show descriptions instead of names?,1,1-Description only,0-Name only,2-Both name and description
|
||||
display_max=Maximum number of subnets and hosts to display,3,Unlimited
|
||||
add_file=Add new subnets, hosts and groups to file,3,Main configuration file
|
||||
line2=System configuration,11
|
||||
|
||||
@@ -7,7 +7,6 @@ lease_refresh=Segons entre refrescs de la llista de préstecs,3,Mai
|
||||
show_ip=Mostra les adreces IP dels hosts,1,1-Sí,0-No
|
||||
show_mac=Mostra les adreces MAC dels hosts,1,1-Sí,0-No
|
||||
group_name=Mostra els noms de grup com,1,1-Opció <tt>domini-nom</tt>,0-Nom o recompte de membres,2-Descripció
|
||||
desc_name=Mostra les descripcions dels altres objectes en lloc dels noms,1,1-Sí,0-No
|
||||
display_max=Nombre màxim de subxarxes i hosts a mostrar,3,Il·limitat
|
||||
add_file=Afegeix subxarxes noves, hosts i grups al fitxer,3,Fitxer de configuració principal
|
||||
line2=Configuració del sistema,11
|
||||
|
||||
@@ -6,7 +6,6 @@ lease_tz=Zobrazit dobu pronájmu v,1,0-GMT,1-Lokálním čase
|
||||
show_ip=Zobrazit IP adresy pro hosty?,1,1-ano,0-ne
|
||||
show_mac=Zobrazit MAC adresy hostů?,1,1-Ano,0-Ne
|
||||
group_name=Zobrazení jmen skupin jako,1,1-<tt>doménová jména</tt>,0-Jména nebo počtu členů,2-Popisu
|
||||
desc_name=Ukázat popisy objektů místo jejich názvů?,1,1-Ano,0-Ne
|
||||
display_max=Počet maximálně zobrazených podsítí a hostů,3,Bezomezení
|
||||
line2=Konfigurace systému,11
|
||||
dhcpd_conf=Konfigurační soubor DHCP serveru,0
|
||||
|
||||
@@ -6,7 +6,6 @@ lease_tz=Vis lease tider i,1,0-GMT,1-Lokal tid
|
||||
show_ip=Vis IP adresser for hosts?,1,1-Ja,0-Nej
|
||||
show_mac=Vis MAC adresser for hosts?,1,1-Ja,0-Nej
|
||||
group_name=Vis gruppenavne som,1,1-<tt>domæne-navne</tt> indstilling,0-Navn eller medlemsantal,2-Beskrivelse
|
||||
desc_name=Vis andre objektbeskrivelse istedet for navne?,1,1-Ja,0-Nej
|
||||
display_max=Maksimalt antal hosts og subnet der skal vises,3,Ubegrænset
|
||||
line2=Systemkonfiguration
|
||||
dhcpd_conf=DHCP server config fil,0
|
||||
|
||||
@@ -7,7 +7,6 @@ lease_refresh=Sekunden zwischen dem Aktualisieren der Leasing-Liste,3,Niemals
|
||||
show_ip=Zeige IP-Adressen für Hosts?,1,1-Ja,0-Nein
|
||||
show_mac=Zeige MAC-Adressen für Hosts?,1,1-Ja,0-Nein
|
||||
group_name=Zeige Gruppennamen als,1,1-<tt>domain-name</tt> Option,0-Name oder Mitglied,2-Beschreibung
|
||||
desc_name=Zeige andere Objektbeschreibungen statt Namen?,1,1-Ja,0-Nein
|
||||
display_max=Maximale Anzahl an Subnetzen und Hosts zum Anzeigen,3,Unbegrenzt
|
||||
add_file=Füge neue Subnetze, Hosts und Gruppen in einer Datei hinzu,3,Haupt-Konfigurationsdatei
|
||||
line2=Systemkonfiguration,11
|
||||
|
||||
@@ -6,7 +6,6 @@ lease_tz=نمايش زمان انتساب داده شدهها براساس,1,
|
||||
show_ip=آيا نشانيهاي IP براي ميزبانها نشان داده شود؟,1,1-بله,0-خير
|
||||
show_mac=آيا نشانيهاي MACبراي ميزبانها نشان داده شود؟,1,1-بله,0-خير
|
||||
group_name=نشاندادن نامهاي گروه بهصورت,1,1- گزينه<tt> دامنه/نام </tt>,0-نام يا تعداد اعضا,2-شرح
|
||||
desc_name=آيا ساير شرحها به جاي نام نشان داده شود؟,1,1-بله,0-خير
|
||||
display_max=حداکثر تعداد زيرشبکهها و ميزبانها جهت نمايش,3,نامحدود
|
||||
line2=پيکربندي سيستم,11
|
||||
dhcpd_conf=پرونده پيکربندي کارساز DHCP,0
|
||||
|
||||
@@ -6,7 +6,6 @@ lease_tz=Afficher les temps de bail en,1,0-GMT,1-Temps local
|
||||
show_ip=Montrer les adresses IP des postes ?,1,1-Oui,0-Non
|
||||
show_mac=Montrer les adresses MAC des postes ?,1,1-Oui,0-Non
|
||||
group_name=Montrer les noms de groupe comme,1,1-Nom de domaine,0-Nom ou numero de membre
|
||||
desc_name=Montrer les descriptions au lieu des noms ?,1,1-Oui,0-Non
|
||||
display_max=Nombre maximum de sous-reseaux et de postes a afficher,3,Illimite
|
||||
line2=Configuration du systeme,11
|
||||
dhcpd_conf=Fichier de configuration du serveur DHCP,0
|
||||
|
||||
@@ -6,7 +6,6 @@ lease_tz=リース時間の表示形式,1,0-GMT,1-ローカル時間
|
||||
show_ip=ホストのIPアドレスを表示しますか?,1,1-はい,0-いいえ
|
||||
show_mac=ホストのMACアドレスを表示しますか?,1,1-はい,0-いいえ
|
||||
group_name=グループ名の表示方法,1,1-<tt>ドメイン-名</tt> オプション,0-名前またはメンバー数
|
||||
desc_name=名称の替わりにオブジェクトの説明を表示しますか?,1,1-はい,0-いいえ
|
||||
display_max=サブネットとホストの表示する最大数,3,無制限
|
||||
line2=システム設定,11
|
||||
dhcpd_conf=DHCPサーバ 設定ファイル,0
|
||||
|
||||
@@ -7,7 +7,6 @@ lease_refresh=Seconden tussen verversen van lease lijst,3,Nooit
|
||||
show_ip=Laat IP adressen zien voor hosts?,1,1-Ja,0-Nee
|
||||
show_mac=Laat MAC adressen zien voor hosts?,1,1-Ja,0-Nee
|
||||
group_name=Laat groep namen zien als,1,1-<tt>domein-naam</tt> optie,0-Naam of Lid van,2-Omschrijving
|
||||
desc_name=Laat andere object omschrijvingen zien in plaats van namen?,1,1-Ja,0-Nee
|
||||
display_max=Maximum aantal subnets en hosts om te laten zien,3,Ongelimiteerd
|
||||
add_file=Toevoegen nieuwe subnetten, host en groepen aan file,3,Hoofd configuratie file
|
||||
line2=Systeem configuratie,11
|
||||
|
||||
@@ -7,7 +7,6 @@ lease_refresh=Sekunder mellom oppfrisking av liste med leieavtaler,3,Aldri
|
||||
show_ip=Vis IP adresser for verter?,1,1-Ja,0-Nei
|
||||
show_mac=Vis MAC adresser for verter?,1,1-Ja,0-Nei
|
||||
group_name=Vis gruppenavn som,1,1-<tt>domene-navn</tt> alternativ,0-Navn eller antall medlemmer,2-Beskrivelse
|
||||
desc_name=Vis andre objektbeskrivelser i stedet for navn,1,1-Ja,0-Nei
|
||||
display_max=Maks antall subnett og verter som skal vises,3,Ubegrenset
|
||||
add_file=Legg til nye subnett, verter og grupper i filen,3,Hoved konfigurasjonsfil
|
||||
line2=System konfigurasjon,11
|
||||
|
||||
@@ -7,7 +7,6 @@ lease_refresh=Sekund pomiędzy odświeżaniem listy dzierżawy,3,Nigdy
|
||||
show_ip=Wyświetlać adres IP hostów?,1,1-Tak,0-Nie
|
||||
show_mac=Wyświetlać adres MAC hostów?,1,1-Tak,0-Nie
|
||||
group_name=Wyświetl nazwy grupy jako,1,1-<tt>domain-name</tt>,0-Ilość lub nazwa użytkowników,2-Opis
|
||||
desc_name=Wyświetlać inne opisy obiektów zamiast nazw,1,1-Tak,0-Nie
|
||||
display_max=Maksymalna liczba wyświetlanych podsieci i hostów,3,Nieograniczona
|
||||
add_file=Dodaj nowe podsieci, hosty i grupy do pliku,3,Główny plik konfiguracyjny
|
||||
line2=Opcje systemowe,11
|
||||
|
||||
@@ -6,7 +6,6 @@ lease_tz=Display leases times in,1,0-GMT,1-Local time
|
||||
show_ip=Mostrar endereço IP para computadores?,1,1-Sim,0-Não
|
||||
show_mac=Mostrar endereço MAC para computadores?,1,1-Sim,0-Não
|
||||
group_name=Mostrar nomes de grupo como,1,1-<tt>nome de-domínio</tt>,0-Nome ou membro
|
||||
desc_name=Mostrar descrição de objetos ao invés de nomes?,1,1-Sim,0-Não
|
||||
display_max=Número máximo de subredes e computadores a serem
|
||||
add_file=Acrescentar novas subredes, hosts e grupos para arquivo,3,Arquivo principal de configuração
|
||||
line2=Configuração do sistema,11
|
||||
|
||||
@@ -6,7 +6,6 @@ lease_tz=Zobraziť časy pridelených adries v,1,0-GMT,1-Lokálnom čase
|
||||
show_ip=Zobraziť IP adresy pre počítače?,1,1-Áno,0-Nie
|
||||
show_mac=Zobraziť MAC adresy pre počítače?,1,1-Áno,0-Nie
|
||||
group_name=Zobraziť skupinové mená ako ,1,1-<tt>doménové mená</tt> ,0-Meno alebo počet členov,2-Popis
|
||||
desc_name=Ukázať popisy objektov namiesto ich názvov?,1,1-Áno,0-Nie
|
||||
display_max=Maximálny počet subnetov a hostiteľov pre zobrazenie,3,Bez limitu
|
||||
line2=Systémové nastavenia,11
|
||||
dhcpd_conf=Konfiguračný súbor DHCP servera,0
|
||||
|
||||
@@ -211,14 +211,18 @@ foreach $u (@subn) {
|
||||
push(@sicons, $i = "images/shared.gif");
|
||||
push(@checkboxids, $u->{'index'});
|
||||
}
|
||||
if ($config{'desc_name'} && $u->{'comment'}) {
|
||||
push(@utitles, $t = &html_escape($u->{'comment'}));
|
||||
if ($config{'desc_name'} == 0) {
|
||||
$t = $u->{'values'}->[0];
|
||||
}
|
||||
elsif ($config{'desc_name'} == 1) {
|
||||
$t = $u->{'comment'} || $u->{'values'}->[0];
|
||||
}
|
||||
else {
|
||||
push(@utitles, $t = &html_escape($u->{'values'}->[0]));
|
||||
$t = $u->{'values'}->[0].($u->{'comment'} ? " ($u->{'comment'})" : "");
|
||||
}
|
||||
push(@utitles, &html_escape($t));
|
||||
push(@uslinks, $l); # so that ordering is preserved
|
||||
push(@ustitles, $t);
|
||||
push(@ustitles, &html_escape($t));
|
||||
push(@usicons, $i);
|
||||
}
|
||||
@checkboxes = map { &ui_checkbox("d", $_) } @checkboxids;
|
||||
@@ -336,12 +340,16 @@ foreach $h (@host) {
|
||||
(defined($subnet{$h}) ? "&uidx=$subnet{$h}" : "").
|
||||
(defined($shared{$h}) ? "&sidx=$shared{$h}" : "") :
|
||||
undef);
|
||||
if ($config{'desc_name'} && $h->{'comment'}) {
|
||||
push(@htitles, &html_escape($h->{'comment'}));
|
||||
if ($config{'desc_name'} == 0) {
|
||||
$t = $h->{'values'}->[0];
|
||||
}
|
||||
elsif ($config{'desc_name'} == 1) {
|
||||
$t = $h->{'comment'} || $h->{'values'}->[0];
|
||||
}
|
||||
else {
|
||||
push(@htitles, &html_escape($h->{'values'}->[0]));
|
||||
$t = $h->{'values'}->[0].($h->{'comment'} ? " ($h->{'comment'})" : "");
|
||||
}
|
||||
push(@htitles, &html_escape($t));
|
||||
if ($config{'show_ip'}) {
|
||||
$fv = &fixedaddr($h);
|
||||
$htitles[$#htitles] .= "<br>".$fv if ($fv);
|
||||
|
||||
@@ -95,7 +95,7 @@ foreach (@lines) {
|
||||
}
|
||||
}
|
||||
elsif (/^(\s*)(#?)([a-z0-9\_]+)\s+=\s*(.*)/) {
|
||||
# A directive inside a section
|
||||
# A directive which may or may not be inside a section
|
||||
local $dir = { 'name' => $3,
|
||||
'value' => $4,
|
||||
'enabled' => !$2,
|
||||
@@ -376,9 +376,9 @@ else {
|
||||
}
|
||||
}
|
||||
splice(@$lref, $section->{'line'}, 0, @newlines);
|
||||
$section->{'eline'} = $section->{'line'} + scalar(@newlines) - 1;
|
||||
&renumber($conf, $section->{'eline'}, $section->{'file'},
|
||||
scalar(@newlines)-$oldlen);
|
||||
$section->{'eline'} = $section->{'line'} + scalar(@newlines) - 1;
|
||||
$section->{'file'} = $file;
|
||||
my $i = 1;
|
||||
foreach my $m (@{$section->{'members'}}) {
|
||||
@@ -391,6 +391,17 @@ foreach my $m (@{$section->{'members'}}) {
|
||||
}
|
||||
}
|
||||
|
||||
# delete_section(&conf, §ion)
|
||||
# Remove a section and all it's members from the config file
|
||||
sub delete_section
|
||||
{
|
||||
my ($conf, $section) = @_;
|
||||
my $lref = &read_file_lines($section->{'file'});
|
||||
my $len = $section->{'eline'} - $section->{'line'} + 1;
|
||||
splice(@$lref, $section->{'line'}, $len);
|
||||
&renumber($conf, $section->{'line'}, $section->{'file'}, -$len);
|
||||
}
|
||||
|
||||
# renumber(&conf, line, file, offset)
|
||||
sub renumber
|
||||
{
|
||||
|
||||
@@ -55,7 +55,7 @@ if (@jails) {
|
||||
$col =~ s/\s/_/g;
|
||||
if ($col !~ /journal_matches/ &&
|
||||
$col !~ /file_list/) {
|
||||
push(@head, "<div $tdc>".$text{"status_head_$col"}."</div>");
|
||||
push(@head, "<span $tdc>".$text{"status_head_$col"}."</span>");
|
||||
if ($col =~ /banned_ip_list/) {
|
||||
$jips = $val;
|
||||
my @ips = split(/\s+/, $val);
|
||||
|
||||
@@ -1,7 +1 @@
|
||||
body blockquote:not([style*="border-left"]) {
|
||||
border-left: 1px solid #ccc;
|
||||
margin-left: 6px;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
padding-left: 12px;
|
||||
}
|
||||
body blockquote:not([style*="border-left"]){border-left:1px solid #ccc;margin-left:6px;margin-top:0;margin-bottom:0;padding-left:12px;}pre{white-space:break-spaces;margin:0 0 4px 0}
|
||||
@@ -230,31 +230,32 @@ return @list_users_cache;
|
||||
# it to the LDAP database
|
||||
sub create_user
|
||||
{
|
||||
local $ldap = &ldap_connect();
|
||||
local $base = &get_user_base();
|
||||
$_[0]->{'dn'} = "uid=$_[0]->{'user'},$base";
|
||||
local @classes = ( &def_user_obj_class(), "shadowAccount",
|
||||
my ($user) = @_;
|
||||
my $ldap = &ldap_connect();
|
||||
my $base = &get_user_base();
|
||||
$user->{'dn'} = "uid=$user->{'user'},$base";
|
||||
my @classes = ( &def_user_obj_class(), "shadowAccount",
|
||||
split(/\s+/, $config{'other_class'}),
|
||||
@{$_[0]->{'ldap_class'}} );
|
||||
local $schema = $ldap->schema();
|
||||
@{$user->{'ldap_class'}} );
|
||||
my $schema = $ldap->schema();
|
||||
if ($schema->objectclass("person") && $config{'person'}) {
|
||||
push(@classes, "person");
|
||||
}
|
||||
@classes = &uniquelc(@classes);
|
||||
@classes = grep { /\S/ } @classes; # Remove empty
|
||||
local @attrs = &user_to_dn($_[0]);
|
||||
push(@attrs, &split_props($config{'props'}, $_[0]));
|
||||
push(@attrs, @{$_[0]->{'ldap_attrs'}});
|
||||
my @attrs = &user_to_dn($user);
|
||||
push(@attrs, &split_props($config{'props'}, $user));
|
||||
push(@attrs, @{$user->{'ldap_attrs'}});
|
||||
push(@attrs, "objectClass" => \@classes);
|
||||
if (&indexoflc("person", @classes) >= 0 && !&in_props(\@attrs, "sn")) {
|
||||
# Person needs 'sn'
|
||||
push(@attrs, "sn", &in_props(\@attrs, "cn"));
|
||||
}
|
||||
local $rv = $ldap->add($_[0]->{'dn'}, attr => \@attrs);
|
||||
my $rv = $ldap->add($user->{'dn'}, attr => \@attrs);
|
||||
if ($rv->code) {
|
||||
&error(&text('usave_eadd', $rv->error));
|
||||
}
|
||||
push(@list_users_cache, $_[0]) if (scalar(@list_users_cache));
|
||||
push(@list_users_cache, $user) if (scalar(@list_users_cache));
|
||||
$ldap->unbind();
|
||||
&useradmin::refresh_nscd() if (!$batch_mode);
|
||||
}
|
||||
@@ -264,8 +265,9 @@ $ldap->unbind();
|
||||
# it from the LDAP database
|
||||
sub delete_user
|
||||
{
|
||||
local $ldap = &ldap_connect();
|
||||
local $rv = $ldap->delete($_[0]->{'dn'});
|
||||
my ($user) = @_;
|
||||
my $ldap = &ldap_connect();
|
||||
my $rv = $ldap->delete($user->{'dn'});
|
||||
if ($rv->code) {
|
||||
my $err = $rv->error;
|
||||
if ($err !~ /No such object/i) {
|
||||
@@ -273,7 +275,7 @@ if ($rv->code) {
|
||||
}
|
||||
}
|
||||
$ldap->unbind();
|
||||
@list_users_cache = grep { $_ ne $_[0] } @list_users_cache
|
||||
@list_users_cache = grep { $_ ne $user } @list_users_cache
|
||||
if (scalar(@list_users_cache));
|
||||
&useradmin::refresh_nscd() if (!$batch_mode);
|
||||
}
|
||||
@@ -281,52 +283,53 @@ $ldap->unbind();
|
||||
# modify_user(&olduser, &newuser)
|
||||
sub modify_user
|
||||
{
|
||||
local $ldap = &ldap_connect();
|
||||
local $base = &get_user_base();
|
||||
local @attrs = &user_to_dn($_[1]);
|
||||
push(@attrs, &split_props($config{'mod_props'}, $_[1]));
|
||||
push(@attrs, @{$_[1]->{'ldap_attrs'}});
|
||||
if ($_[1]->{'ldap_class'} &&
|
||||
(!ref($_[1]->{'ldap_class'}) || @{$_[1]->{'ldap_class'}})) {
|
||||
push(@attrs, "objectClass" => $_[1]->{'ldap_class'});
|
||||
my ($olduser, $user) = @_;
|
||||
my $ldap = &ldap_connect();
|
||||
my $base = &get_user_base();
|
||||
my @attrs = &user_to_dn($user);
|
||||
push(@attrs, &split_props($config{'mod_props'}, $user));
|
||||
push(@attrs, @{$user->{'ldap_attrs'}});
|
||||
if ($user->{'ldap_class'} &&
|
||||
(!ref($user->{'ldap_class'}) || @{$user->{'ldap_class'}})) {
|
||||
push(@attrs, "objectClass" => $user->{'ldap_class'});
|
||||
}
|
||||
if (&indexoflc("person", @{$_[1]->{'ldap_class'}}) >= 0 &&
|
||||
if (&indexoflc("person", @{$user->{'ldap_class'}}) >= 0 &&
|
||||
!&in_props(\@attrs, "sn")) {
|
||||
# Person needs 'sn'
|
||||
push(@attrs, "sn", &in_props(\@attrs, "cn"));
|
||||
}
|
||||
local %replace;
|
||||
my %replace;
|
||||
for(my $i=0; $i<@attrs; $i+=2) {
|
||||
$replace{$attrs[$i]} ||= [ ];
|
||||
local $v = $attrs[$i+1];
|
||||
my $v = $attrs[$i+1];
|
||||
push(@{$replace{$attrs[$i]}}, ref($v) ? @$v : $v);
|
||||
}
|
||||
if ($_[0]->{'pass'} eq $_[1]->{'pass'}) {
|
||||
if ($olduser->{'pass'} eq $user->{'pass'}) {
|
||||
# Don't change password attribute if not change
|
||||
delete($replace{'userPassword'});
|
||||
}
|
||||
# Do rename to new DN first
|
||||
if ($_[0]->{'user'} ne $_[1]->{'user'}) {
|
||||
local $newdn = $_[0]->{'dn'};
|
||||
if ($newdn !~ s/^uid=$_[0]->{'user'},/uid=$_[1]->{'user'},/) {
|
||||
$newdn = "uid=$_[1]->{'user'},$base";
|
||||
if ($olduser->{'user'} ne $user->{'user'}) {
|
||||
my $newdn = $olduser->{'dn'};
|
||||
if ($newdn !~ s/^uid=$olduser->{'user'},/uid=$user->{'user'},/) {
|
||||
$newdn = "uid=$user->{'user'},$base";
|
||||
}
|
||||
if (!&same_dn($newdn, $_[0]->{'dn'})) {
|
||||
$rv = $ldap->moddn($_[0]->{'dn'},
|
||||
newrdn => "uid=$_[1]->{'user'}");
|
||||
if (!&same_dn($newdn, $olduser->{'dn'})) {
|
||||
$rv = $ldap->moddn($olduser->{'dn'},
|
||||
newrdn => "uid=$user->{'user'}");
|
||||
if ($rv->code) {
|
||||
&error(&text('usave_emoddn', $rv->error));
|
||||
}
|
||||
$_[1]->{'dn'} = $newdn;
|
||||
$user->{'dn'} = $newdn;
|
||||
}
|
||||
}
|
||||
local $rv = $ldap->modify($_[1]->{'dn'}, replace => \%replace);
|
||||
my $rv = $ldap->modify($user->{'dn'}, replace => \%replace);
|
||||
if ($rv->code) {
|
||||
&error(&text('usave_emod', $rv->error));
|
||||
}
|
||||
if ($_[0] ne $_[1] && &indexof($_[0], @list_users_cache) != -1) {
|
||||
if ($olduser ne $user && &indexof($olduser, @list_users_cache) != -1) {
|
||||
# Update old object in cache
|
||||
%{$_[0]} = %{$_[1]};
|
||||
%{$olduser} = %{$user};
|
||||
}
|
||||
$ldap->unbind();
|
||||
&useradmin::refresh_nscd() if (!$batch_mode);
|
||||
@@ -431,37 +434,42 @@ $ldap->unbind();
|
||||
# in the same format uses by the useradmin module
|
||||
sub dn_to_hash
|
||||
{
|
||||
if ($_[0]->get_value("uid")) {
|
||||
local %user = ( 'dn' => $_[0]->dn(),
|
||||
'user' => $_[0]->get_value("uid"),
|
||||
'uid' => $_[0]->get_value("uidNumber"),
|
||||
'gid' => $_[0]->get_value("gidNumber"),
|
||||
'real' => $_[0]->get_value("cn"),
|
||||
'home' => $_[0]->get_value("homeDirectory"),
|
||||
'shell' => $_[0]->get_value("loginShell"),
|
||||
'pass' => $_[0]->get_value("userPassword"),
|
||||
'change' => $_[0]->get_value("shadowLastChange") || "",
|
||||
'expire' => $_[0]->get_value("shadowExpire") || "",
|
||||
'min' => $_[0]->get_value("shadowMin") || "",
|
||||
'max' => $_[0]->get_value("shadowMax") || "",
|
||||
'warn' => $_[0]->get_value("shadowWarning") || "",
|
||||
'inactive' => $_[0]->get_value("shadowInactive") || "",
|
||||
);
|
||||
my ($obj) = @_;
|
||||
if ($obj->get_value("uid")) {
|
||||
my %user = ( 'dn' => $obj->dn(),
|
||||
'user' => $obj->get_value("uid"),
|
||||
'uid' => $obj->get_value("uidNumber"),
|
||||
'gid' => $obj->get_value("gidNumber"),
|
||||
'real' => $obj->get_value("cn"),
|
||||
'home' => $obj->get_value("homeDirectory"),
|
||||
'shell' => $obj->get_value("loginShell"),
|
||||
'pass' => $obj->get_value("userPassword"),
|
||||
'change' => $obj->get_value("shadowLastChange") || "",
|
||||
'expire' => $obj->get_value("shadowExpire") || "",
|
||||
'min' => $obj->get_value("shadowMin") || "",
|
||||
'max' => $obj->get_value("shadowMax") || "",
|
||||
'warn' => $obj->get_value("shadowWarning") || "",
|
||||
'inactive' => $obj->get_value("shadowInactive") || "",
|
||||
);
|
||||
if ($config{'given'}) {
|
||||
$user{'firstname'} = $obj->get_value("givenName");
|
||||
$user{'surname'} = $obj->get_value("sn");
|
||||
}
|
||||
$user{'pass'} =~ s/^(\!?)\{[a-z0-9]+\}/$1/i;
|
||||
$user{'all_ldap_attrs'} = { map { lc($_), scalar($_[0]->get_value($_)) }
|
||||
$_[0]->attributes() };
|
||||
$user{'ldap_class'} = [ $_[0]->get_value('objectClass') ];
|
||||
$user{'all_ldap_attrs'} = { map { lc($_), scalar($obj->get_value($_)) }
|
||||
$obj->attributes() };
|
||||
$user{'ldap_class'} = [ $obj->get_value('objectClass') ];
|
||||
return %user;
|
||||
}
|
||||
else {
|
||||
local @members = $_[0]->get_value('memberUid');
|
||||
local %group = ( 'dn' => $_[0]->dn(),
|
||||
'group' => $_[0]->get_value("cn"),
|
||||
'gid' => $_[0]->get_value("gidNumber"),
|
||||
'pass' => $_[0]->get_value("userPassword") || "",
|
||||
'members' => join(",", @members) || "",
|
||||
'desc' => $_[0]->get_value("description"),
|
||||
);
|
||||
my @members = $obj->get_value('memberUid');
|
||||
my %group = ( 'dn' => $obj->dn(),
|
||||
'group' => $obj->get_value("cn"),
|
||||
'gid' => $obj->get_value("gidNumber"),
|
||||
'pass' => $obj->get_value("userPassword") || "",
|
||||
'members' => join(",", @members) || "",
|
||||
'desc' => $obj->get_value("description"),
|
||||
);
|
||||
return %group;
|
||||
}
|
||||
}
|
||||
@@ -470,48 +478,56 @@ else {
|
||||
# Given a useradmin-style user hash, returns a list of properties
|
||||
sub user_to_dn
|
||||
{
|
||||
local $pfx = $_[0]->{'pass'} =~ /^\{[a-z0-9]+\}/i ? undef :
|
||||
$_[0]->{'pass'} =~ /^\$1\$/ ? "{md5}" :
|
||||
$_[0]->{'pass'} =~ /^[a-zA-Z0-9\.\/]{13}$/ ? "{crypt}" :
|
||||
$config{'md5'} == 1 || $config{'md5'} == 3 ? "{md5}" :
|
||||
$config{'md5'} == 4 ? "{ssha}" :
|
||||
$config{'md5'} == 0 ? "{crypt}" : "";
|
||||
local $pass = $_[0]->{'pass'};
|
||||
local $disabled;
|
||||
my ($user) = @_;
|
||||
my $pfx = $user->{'pass'} =~ /^\{[a-z0-9]+\}/i ? undef :
|
||||
$user->{'pass'} =~ /^\$1\$/ ? "{md5}" :
|
||||
$user->{'pass'} =~ /^[a-zA-Z0-9\.\/]{13}$/ ? "{crypt}" :
|
||||
$config{'md5'} == 1 || $config{'md5'} == 3 ? "{md5}" :
|
||||
$config{'md5'} == 4 ? "{ssha}" :
|
||||
$config{'md5'} == 0 ? "{crypt}" : "";
|
||||
my $pass = $user->{'pass'};
|
||||
my $disabled;
|
||||
if ($pass =~ s/^\!//) {
|
||||
$disabled = "!";
|
||||
}
|
||||
$cn = $_[0]->{'real'} eq '' ? $_[0]->{'user'} : $_[0]->{'real'};
|
||||
my $cn = $user->{'real'} eq '' ? $user->{'user'} : $user->{'real'};
|
||||
return ( "cn" => $cn,
|
||||
"uid" => $_[0]->{'user'},
|
||||
"uidNumber" => $_[0]->{'uid'},
|
||||
"loginShell" => $_[0]->{'shell'},
|
||||
"homeDirectory" => $_[0]->{'home'},
|
||||
"gidNumber" => $_[0]->{'gid'},
|
||||
"uid" => $user->{'user'},
|
||||
"uidNumber" => $user->{'uid'},
|
||||
"loginShell" => $user->{'shell'},
|
||||
"homeDirectory" => $user->{'home'},
|
||||
"gidNumber" => $user->{'gid'},
|
||||
"userPassword" => $disabled.$pfx.$pass,
|
||||
$_[0]->{'change'} eq '' ? ( ) :
|
||||
( "shadowLastChange" => $_[0]->{'change'} ),
|
||||
$_[0]->{'expire'} eq '' ? ( ) :
|
||||
( "shadowExpire" => $_[0]->{'expire'} ),
|
||||
$_[0]->{'min'} eq '' ? ( ) :
|
||||
( "shadowMin" => $_[0]->{'min'} ),
|
||||
$_[0]->{'max'} eq '' ? ( ) :
|
||||
( "shadowMax" => $_[0]->{'max'} ),
|
||||
$_[0]->{'warn'} eq '' ? ( ) :
|
||||
( "shadowWarning" => $_[0]->{'warn'} ),
|
||||
$_[0]->{'inactive'} eq '' ? ( ) :
|
||||
( "shadowInactive" => $_[0]->{'inactive'} )
|
||||
$user->{'change'} eq '' ? ( ) :
|
||||
( "shadowLastChange" => $user->{'change'} ),
|
||||
$user->{'expire'} eq '' ? ( ) :
|
||||
( "shadowExpire" => $user->{'expire'} ),
|
||||
$user->{'min'} eq '' ? ( ) :
|
||||
( "shadowMin" => $user->{'min'} ),
|
||||
$user->{'max'} eq '' ? ( ) :
|
||||
( "shadowMax" => $user->{'max'} ),
|
||||
$user->{'warn'} eq '' ? ( ) :
|
||||
( "shadowWarning" => $user->{'warn'} ),
|
||||
$user->{'inactive'} eq '' ? ( ) :
|
||||
( "shadowInactive" => $user->{'inactive'} ),
|
||||
$user->{'firstname'} eq '' ? ( ) :
|
||||
( "givenName" => $user->{'firstname'} ),
|
||||
$user->{'surname'} eq '' ? ( ) :
|
||||
( "sn" => $user->{'surname'} ),
|
||||
);
|
||||
}
|
||||
|
||||
# group_to_dn(&group)
|
||||
# Given a useradmin-style group hash, returns a list of properties
|
||||
sub group_to_dn
|
||||
{
|
||||
local @members = split(/,/, $_[0]->{'members'});
|
||||
return ( "cn" => $_[0]->{'group'},
|
||||
"gidNumber" => $_[0]->{'gid'},
|
||||
"userPassword" => $_[0]->{'pass'},
|
||||
my ($group) = @_;
|
||||
my @members = split(/,/, $group->{'members'});
|
||||
return ( "cn" => $group->{'group'},
|
||||
"gidNumber" => $group->{'gid'},
|
||||
"userPassword" => $group->{'pass'},
|
||||
@members ? ( "memberUid" => \@members ) : ( ),
|
||||
defined($_[0]->{'desc'}) ? ( "description" => $_[0]->{'desc'} ) : ( ),
|
||||
defined($group->{'desc'}) ? ( "description" => $group->{'desc'} ) : ( ),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -332,6 +332,7 @@ folder_inbox=Inbox
|
||||
folder_sent=Sent
|
||||
folder_drafts=Drafts
|
||||
folder_trash=Trash
|
||||
folder_spam=Spam
|
||||
|
||||
detach_err=Failed to detach file
|
||||
detach_edir=No file or directory to save to entered
|
||||
|
||||
@@ -107,7 +107,7 @@ if ($product eq "webmin") {
|
||||
$size = int(`du -sk $tmp_dir`);
|
||||
@deps = ( "perl", "libnet-ssleay-perl", "openssl", "libauthen-pam-perl", "libpam-runtime", "libio-pty-perl", "unzip", "shared-mime-info", "tar", "libdigest-sha-perl", "libdigest-md5-perl", "gzip" );
|
||||
$deps = join(", ", @deps);
|
||||
@recommends = ( "libdatetime-perl", "libdatetime-timezone-perl", "libdatetime-locale-perl", "libtime-piece-perl", "libencode-detect-perl", "libtime-hires-perl", "libsocket6-perl", "libthreads-perl", "libthreads-shared-perl", "lynx", "qrencode" );
|
||||
@recommends = ( "libdatetime-perl", "libdatetime-timezone-perl", "libdatetime-locale-perl", "libtime-piece-perl", "libencode-detect-perl", "libtime-hires-perl", "libsocket6-perl", "lynx", "qrencode" );
|
||||
$recommends = join(", ", @recommends);
|
||||
open(CONTROL, ">$control_file");
|
||||
print CONTROL <<EOF;
|
||||
|
||||
@@ -87,7 +87,7 @@ Release: $rel
|
||||
Provides: %{name}-%{version} perl(WebminCore)
|
||||
Requires(pre): /usr/bin/perl
|
||||
Requires: /bin/sh /usr/bin/perl perl(lib) perl(open) perl(Net::SSLeay) perl(Time::Local) perl(Data::Dumper) perl(File::Path) perl(File::Basename) perl(Digest::SHA) perl(Digest::MD5) openssl unzip tar gzip
|
||||
Recommends: perl(DateTime) perl(DateTime::TimeZone) perl(DateTime::Locale) perl(Time::Piece) perl(Encode::Detect) perl(Time::HiRes) perl(Socket6) perl(threads) perl(threads::shared) lynx shared-mime-info perl-File-Basename perl-File-Path qrencode
|
||||
Recommends: perl(DateTime) perl(DateTime::TimeZone) perl(DateTime::Locale) perl(Time::Piece) perl(Encode::Detect) perl(Time::HiRes) perl(Socket6) lynx shared-mime-info perl-File-Basename perl-File-Path qrencode
|
||||
AutoReq: 0
|
||||
License: BSD-3-clause
|
||||
Group: System/Tools
|
||||
|
||||
@@ -269,9 +269,9 @@ application/x-director dcr dir dxr
|
||||
application/x-dvi dvi # DVI
|
||||
application/x-futuresplash spl
|
||||
application/x-gtar gtar
|
||||
application/x-gzip gz tgz # Gzipped data
|
||||
application/gzip gz tgz # Gzipped data
|
||||
application/x-hdf hdf
|
||||
application/x-javascript js # Javascript source
|
||||
application/javascript js # Javascript source
|
||||
application/x-koan skp skd skt skm
|
||||
application/x-latex latex # LaTeX source
|
||||
application/x-netcdf nc cdf
|
||||
|
||||
@@ -4894,7 +4894,7 @@ my %vital = ("port", 80,
|
||||
"listen_delay", 5,
|
||||
"pam", "webmin",
|
||||
"sidname", "sid",
|
||||
"unauth", "^/unauthenticated/ ^/robots.txt\$ ^[A-Za-z0-9\\-/_]+\\.jar\$ ^[A-Za-z0-9\\-/_]+\\.class\$ ^[A-Za-z0-9\\-/_]+\\.gif\$ ^[A-Za-z0-9\\-/_]+\\.png\$ ^[A-Za-z0-9\\-/_]+\\.conf\$ ^[A-Za-z0-9\\-/_]+\\.ico\$ ^/robots.txt\$",
|
||||
"unauth", "^/unauthenticated/ ^/robots.txt\$ ^[A-Za-z0-9\\-/_]+\\.jar\$ ^[A-Za-z0-9\\-/_]+\\.class\$ ^[A-Za-z0-9\\-/_]+\\.gif\$ ^[A-Za-z0-9\\-/_]+\\.png\$ ^[A-Za-z0-9\\-/_]+\\.conf\$ ^[A-Za-z0-9\\-/_]+\\.ico\$ ^/robots.txt\$ ^/service-worker.js\$",
|
||||
"max_post", 10000,
|
||||
"expires", 7*24*60*60,
|
||||
"pam_test_user", "root",
|
||||
|
||||
@@ -20,12 +20,10 @@ print &ui_tabs_start([ [ 'pkgs', $text{'index_tabpkgs'} ],
|
||||
# See if any security updates exist
|
||||
$in{'mode'} ||= 'updates';
|
||||
@avail = &list_for_mode($in{'mode'}, 0);
|
||||
($sec) = grep { $_->{'security'} } @avail;
|
||||
|
||||
# Show mode selector (all, updates only, updates and new)
|
||||
@grid = ( );
|
||||
foreach $m ('current', 'updates', 'new',
|
||||
$sec || $in{'mode'} eq 'security' ? ( 'security' ) : ( )) {
|
||||
foreach $m ('current', 'updates', 'security', 'new') {
|
||||
$mmsg = $text{'index_mode_'.$m};
|
||||
if ($in{'mode'} eq $m) {
|
||||
push(@mlinks, "<b>$mmsg</b>");
|
||||
|
||||
@@ -103,6 +103,7 @@ sched_yes=Scheduled checking for updates is now active.
|
||||
sched_no=Scheduled checking for updates has been disabled.
|
||||
|
||||
log_update=Installed $1 updated packages
|
||||
log_sched=Background installed $1 updated packages
|
||||
log_sched=Enabled scheduled updates
|
||||
log_unsched=Disabled scheduled updates
|
||||
log_refresh=Refreshed available packages
|
||||
|
||||
@@ -18,6 +18,9 @@ elsif ($type eq 'repo') {
|
||||
elsif ($action eq 'update') {
|
||||
return &text('log_update', $object);
|
||||
}
|
||||
elsif ($action eq 'sched') {
|
||||
return &text('log_sched', $object);
|
||||
}
|
||||
elsif ($action eq 'sched') {
|
||||
return $text{$object ? 'log_sched' : 'log_unsched'};
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@ else {
|
||||
$redir = "index.cgi?mode=".&urlize($in{'mode'}).
|
||||
"&search=".&urlize($in{'search'});
|
||||
$redirdesc = $text{'index_return'};
|
||||
$redir = $redir =~ /tab=/ ? $redir :
|
||||
$redir =~ /\?/ ? "$redir&tab=pkgs" : "$redir?tab=pkgs";
|
||||
}
|
||||
|
||||
$redir = ($redir =~ /\?/) ? "$redir&tab=pkgs" : "$redir?tab=pkgs";
|
||||
|
||||
if ($in{'refresh'} || $in{'refresh_top'}) {
|
||||
&ui_print_unbuffered_header(undef, $text{'refresh_title'}, "");
|
||||
|
||||
|
||||
@@ -17,19 +17,22 @@ if ($ARGV[0] eq "--debug" || $ARGV[0] eq "-debug") {
|
||||
$tellcount = 0;
|
||||
%already = ( );
|
||||
&start_update_progress([ map { $_->{'name'} } @todo ]);
|
||||
$icount = 0;
|
||||
foreach $t (@todo) {
|
||||
next if ($already{$t->{'update'}});
|
||||
my $umsg = $t->{'security'} ? "security update" : "update";
|
||||
if ($config{'sched_action'} == 2 ||
|
||||
$config{'sched_action'} == 1 && $t->{'security'}) {
|
||||
# Can install
|
||||
$body .= "An update to $t->{'name'} from $t->{'oldversion'} to $t->{'version'} is needed.\n";
|
||||
$body .= "An $umsg to $t->{'name'} from $t->{'oldversion'} to $t->{'version'} is needed.\n";
|
||||
$icount++;
|
||||
($out, $done) = &capture_function_output(
|
||||
\&package_install, $t->{'update'});
|
||||
if (@$done) {
|
||||
$body .= "This update has been successfully installed.\n\n";
|
||||
$body .= "This $umsg has been successfully installed.\n\n";
|
||||
}
|
||||
else {
|
||||
$body .= "However, this update could not be installed! Try the update manually\nusing the Package Updates module.\n\n";
|
||||
$body .= "However, this $usmg could not be installed! Try the update manually\nusing the Package Updates module.\n\n";
|
||||
}
|
||||
foreach $p (@$done) {
|
||||
$already{$p}++;
|
||||
@@ -39,7 +42,7 @@ foreach $t (@todo) {
|
||||
$config{'sched_action'} == 0 ||
|
||||
$config{'sched_action'} == -1 && $t->{'security'}) {
|
||||
# Just tell the user about it
|
||||
$body .= "An update to $t->{'name'} from $t->{'oldversion'} to $t->{'version'} is available.\n\n";
|
||||
$body .= "An $umsg to $t->{'name'} from $t->{'oldversion'} to $t->{'version'} is available.\n\n";
|
||||
$tellcount++;
|
||||
}
|
||||
}
|
||||
@@ -69,3 +72,7 @@ if ($config{'sched_email'} && $body) {
|
||||
}
|
||||
}
|
||||
|
||||
# Log the update, if anything was installed
|
||||
if ($icount) {
|
||||
&webmin_log("sched", "packages", $icount);
|
||||
}
|
||||
|
||||
@@ -16,5 +16,11 @@ print &ui_hidden("oneini", $in{'oneini'}),"\n";
|
||||
print &ui_textarea("data", &read_file_contents_as_user($in{'file'}), 20, 80);
|
||||
print &ui_form_end([ [ "save", $text{'save'} ] ]);
|
||||
|
||||
&ui_print_footer("", $text{'index_return'});
|
||||
if ($in{'oneini'}) {
|
||||
&ui_print_footer("list_ini.cgi?file=".&urlize($in{'file'}),
|
||||
$text{'list_return'});
|
||||
}
|
||||
else {
|
||||
&ui_print_footer("", $text{'index_return'});
|
||||
}
|
||||
|
||||
|
||||
@@ -512,6 +512,15 @@ mail_forward=Forward
|
||||
mail_rfc=From line
|
||||
mail_move=Move to:
|
||||
mail_eexists=Message no longer exists!
|
||||
mail_qfile=Mail queue file
|
||||
mail_qlast=Last retried at
|
||||
mail_qdir=Mail queue status
|
||||
mail_qdir_active=Active
|
||||
mail_qdir_incoming=Incoming
|
||||
mail_qdir_deferred=Deferred
|
||||
mail_qdir_corrupt=Corrupt
|
||||
mail_qdir_hold=On hold
|
||||
mail_qdir_maildrop=Mail drop
|
||||
|
||||
view_title=Read Email
|
||||
view_desc=Message $1 in $2
|
||||
@@ -622,6 +631,7 @@ mailq_active=Active
|
||||
mailq_deferred=Deferred
|
||||
mailq_hold=Hold Selected
|
||||
mailq_unhold=Un-Hold Selected
|
||||
mailq_dir=Queue state
|
||||
|
||||
flushq_title=Flush Queue
|
||||
flushq_desc=Forcing the attempted delivery of mail with the command $1 ..
|
||||
|
||||
@@ -1449,6 +1449,15 @@ foreach my $l (split(/\r?\n/, $out)) {
|
||||
$q->{'time'} = $t;
|
||||
}
|
||||
}
|
||||
foreach my $dir (&list_mailq_directories()) {
|
||||
my $f = substr($q->{'id'}, 0, 1);
|
||||
my $path = "$config{'mailq_dir'}/$dir/$f/$q->{'id'}";
|
||||
if (-r $path) {
|
||||
$q->{'dir'} = $dir;
|
||||
$q->{'file'} = $file;
|
||||
last;
|
||||
}
|
||||
}
|
||||
push(@qfiles, $q);
|
||||
}
|
||||
elsif ($l =~ /\((.*)\)/ && @qfiles) {
|
||||
@@ -1461,18 +1470,18 @@ foreach my $l (split(/\r?\n/, $out)) {
|
||||
return @qfiles;
|
||||
}
|
||||
|
||||
sub list_mailq_directories
|
||||
{
|
||||
return ("active", "incoming", "deferred", "corrupt", "hold", "maildrop");
|
||||
}
|
||||
|
||||
# parse_queue_file(id)
|
||||
# Parses a postfix mail queue file into a standard mail structure
|
||||
sub parse_queue_file
|
||||
{
|
||||
local @qfiles = ( &recurse_files("$config{'mailq_dir'}/active"),
|
||||
&recurse_files("$config{'mailq_dir'}/incoming"),
|
||||
&recurse_files("$config{'mailq_dir'}/deferred"),
|
||||
&recurse_files("$config{'mailq_dir'}/corrupt"),
|
||||
&recurse_files("$config{'mailq_dir'}/hold"),
|
||||
&recurse_files("$config{'mailq_dir'}/maildrop"),
|
||||
);
|
||||
local $f = $_[0];
|
||||
local ($f) = @_;
|
||||
local @qfiles = map { &recurse_files("$config{'mailq_dir'}/$_") }
|
||||
&list_mailq_directories();
|
||||
local ($file) = grep { $_ =~ /\/$f$/ } @qfiles;
|
||||
return undef if (!$file);
|
||||
local $mode = 0;
|
||||
@@ -1504,6 +1513,12 @@ $mail->{'headers'} = \@headers;
|
||||
foreach $h (@headers) {
|
||||
$mail->{'header'}->{lc($h->[0])} = $h->[1];
|
||||
}
|
||||
$mail->{'file'} = $file;
|
||||
my @st = stat($file);
|
||||
$mail->{'last_retry'} = $st[9];
|
||||
if ($file =~ /^\Q$config{'mailq_dir'}\E\/([^\/]+)\//) {
|
||||
$mail->{'dir'} = $1;
|
||||
}
|
||||
return $mail;
|
||||
}
|
||||
|
||||
@@ -1856,11 +1871,12 @@ foreach my $q (@$qfiles) {
|
||||
'value' => $q->{'id'} });
|
||||
push(@cols, &ui_link("view_mailq.cgi?id=$q->{'id'}",$q->{'id'}));
|
||||
local $size = &nice_size($q->{'size'});
|
||||
push(@cols, "<font size=1>$q->{'date'}</font>");
|
||||
push(@cols, "<font size=1>".&html_escape($q->{'from'})."</font>");
|
||||
push(@cols, "<font size=1>".&html_escape($q->{'to'})."</font>");
|
||||
push(@cols, "<font size=1>$size</font>");
|
||||
push(@cols, "<font size=1>".&html_escape($q->{'status'})."</font>");
|
||||
push(@cols, $q->{'date'});
|
||||
push(@cols, &html_escape($q->{'from'}));
|
||||
push(@cols, &html_escape($q->{'to'}));
|
||||
push(@cols, $size);
|
||||
push(@cols, $text{'mailq_'.$q->{'dir'}} || $q->{'dir'});
|
||||
push(@cols, &html_escape($q->{'status'}));
|
||||
push(@table, \@cols);
|
||||
}
|
||||
|
||||
@@ -1877,7 +1893,8 @@ print &ui_form_columns_table("delete_queues.cgi",
|
||||
undef,
|
||||
undef,
|
||||
[ "", $text{'mailq_id'}, $text{'mailq_date'}, $text{'mailq_from'},
|
||||
$text{'mailq_to'}, $text{'mailq_size'}, $text{'mailq_status'} ],
|
||||
$text{'mailq_to'}, $text{'mailq_size'}, $text{'mailq_dir'},
|
||||
$text{'mailq_status'} ],
|
||||
100,
|
||||
\@table);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,11 @@ if ($in{'headers'}) {
|
||||
}
|
||||
foreach $h (@{$mail->{'headers'}}) {
|
||||
print &ui_table_row($h->[0],
|
||||
&html_escape(&decode_mimewords($h->[1])));
|
||||
&html_escape(&decode_mimewords($h->[1])), 1, [ "nowrap" ]);
|
||||
}
|
||||
if ($mail->{'file'}) {
|
||||
print &ui_table_row($text{'mail_qfile'},
|
||||
"<tt>".&html_escape($mail->{'file'})."</tt>");
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -68,6 +72,14 @@ else {
|
||||
print &ui_table_row($text{'mail_subject'},
|
||||
&html_escape($mail->{'header'}->{'subject'}));
|
||||
}
|
||||
if ($mail->{'last_retry'}) {
|
||||
print &ui_table_row($text{'mail_qlast'},
|
||||
&make_date($mail->{'last_retry'}));
|
||||
}
|
||||
if ($mail->{'dir'}) {
|
||||
print &ui_table_row($text{'mail_qdir'},
|
||||
$text{'mailq_'.$mail->{'dir'}} || $mail->{'dir'});
|
||||
}
|
||||
print &ui_table_end();
|
||||
|
||||
# Find body attachment
|
||||
|
||||
@@ -61,7 +61,7 @@ if ($in{'headers'}) {
|
||||
}
|
||||
foreach $h (@{$mail->{'headers'}}) {
|
||||
print &ui_table_row($h->[0],
|
||||
&html_escape(&decode_mimewords($h->[1])));
|
||||
&html_escape(&decode_mimewords($h->[1])), 1, [ "nowrap" ]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -12,10 +12,7 @@ my $err = sub {
|
||||
print("<tt>Cannot change theme : $_[0]</tt>\n");
|
||||
exit(1);
|
||||
};
|
||||
# Check if in debug mode
|
||||
&$err("Debug mode is not enabled!")
|
||||
if (!$gconfig{'debug_enabled'} &&
|
||||
!$gconfig{'debug_theme_switcher'});
|
||||
|
||||
# Check if allowed to change theme,
|
||||
# otherwise throw an error
|
||||
if (!&foreign_available('theme') &&
|
||||
|
||||
@@ -74,7 +74,7 @@ if (&foreign_installed("package-updates") && $config{'collect_pkgs'}) {
|
||||
}
|
||||
|
||||
# CPU and drive temps
|
||||
if (!$config{'collect_notemp'} && defined(&proc::get_current_cpu_data)) {
|
||||
if (!$config{'collect_notemp2'} && defined(&proc::get_current_cpu_data)) {
|
||||
my ($cpu, $fans) = &proc::get_current_cpu_data();
|
||||
$info->{'cputemps'} = $cpu if (ref($cpu) && @{$cpu} >= 1);
|
||||
$info->{'cpufans'} = $fans if (ref($fans) && @{$fans} >= 1);
|
||||
|
||||
44
ui-lib.pl
44
ui-lib.pl
@@ -2349,11 +2349,45 @@ Hotkeys are:
|
||||
sub ui_switch_theme_javascript
|
||||
{
|
||||
return &theme_ui_switch_theme_javascript(@_) if (defined(&theme_ui_switch_theme_javascript));
|
||||
return "" if (!$gconfig{'debug_enabled'} && !$gconfig{'debug_theme_switcher'});
|
||||
my $switch_script = "<script>const __webmin_webprefix__ = '@{[&get_webprefix()]}';</script>\n";
|
||||
my $webmin_version = &get_webmin_version();
|
||||
$webmin_version =~ s/\.//g;
|
||||
$switch_script .= "<script type=\"text/javascript\" src=\"@{[&get_webprefix()]}/unauthenticated/switch_theme.js?$webmin_version\"></script>\n";
|
||||
my $webprefix = &get_webprefix();
|
||||
my $switch_script .= <<EOF;
|
||||
<script type="text/javascript">
|
||||
(function () {
|
||||
let firstCombinationPressed = false;
|
||||
document.addEventListener("keydown", function (event) {
|
||||
// Check for Ctrl+Alt+T or Control+Option+T
|
||||
if (event.ctrlKey && event.altKey && event.keyCode === 84) {
|
||||
firstCombinationPressed = true;
|
||||
|
||||
// Set a timeout to reset the state after a short period (e.g., 1 seconds)
|
||||
setTimeout(() => {
|
||||
firstCombinationPressed = false;
|
||||
}, 1000);
|
||||
}
|
||||
if (firstCombinationPressed && event.shiftKey &&
|
||||
(event.keyCode === 65 ||
|
||||
event.keyCode === 70 || event.keyCode === 71 ||
|
||||
event.keyCode === 76)) {
|
||||
const theme =
|
||||
// Shift + A : Authentic theme
|
||||
event.keyCode === 65 ? 1 :
|
||||
// Shift + F / Shift + G : Framed theme / Gray theme
|
||||
(event.keyCode === 70 || event.keyCode === 71) ? 2 :
|
||||
// Shift + L : Legacy theme
|
||||
event.keyCode === 76 ? 3 : null;
|
||||
firstCombinationPressed = false;
|
||||
try {
|
||||
top.document.documentElement.style.filter = 'grayscale(100%) blur(0.5px) brightness(0.75) opacity(0.5)';
|
||||
top.document.documentElement.style.cursor = 'wait';
|
||||
top.document.documentElement.style.pointerEvents = 'none';
|
||||
} catch (error) {}
|
||||
top.location.href = "$webprefix/switch_theme.cgi?theme=" + theme + "";
|
||||
}
|
||||
});
|
||||
})();
|
||||
document.currentScript.remove();
|
||||
</script>
|
||||
EOF
|
||||
return $switch_script;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
(function () {
|
||||
let firstCombinationPressed = false;
|
||||
document.addEventListener("keydown", function (event) {
|
||||
// Check for Ctrl+Alt+T or Control+Option+T
|
||||
if (event.ctrlKey && event.altKey && event.keyCode === 84) {
|
||||
firstCombinationPressed = true;
|
||||
|
||||
// Set a timeout to reset the state after a short period (e.g., 1 seconds)
|
||||
setTimeout(() => {
|
||||
firstCombinationPressed = false;
|
||||
}, 1000);
|
||||
}
|
||||
if (firstCombinationPressed && event.shiftKey &&
|
||||
(event.keyCode === 65 || event.keyCode === 71 || event.keyCode === 76)) {
|
||||
const theme =
|
||||
// Shift + A : Authentic theme
|
||||
event.keyCode === 65 ? 1 :
|
||||
// Shift + G : Gray theme
|
||||
event.keyCode === 71 ? 2 :
|
||||
// Shift + L : Legacy theme.
|
||||
event.keyCode === 76 ? 3 : null;
|
||||
firstCombinationPressed = false;
|
||||
try {
|
||||
top.document.documentElement.style.filter = 'grayscale(100%) blur(0.5px) brightness(0.75) opacity(0.5)';
|
||||
top.document.documentElement.style.cursor = 'wait';
|
||||
top.document.documentElement.style.pointerEvents = 'none';
|
||||
} catch (error) {}
|
||||
top.location.href = __webmin_webprefix__ + "/switch_theme.cgi?theme=" + theme + "";
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -21,7 +21,8 @@ return 0;
|
||||
sub open_last_command
|
||||
{
|
||||
local ($fh, $user) = @_;
|
||||
open($fh, "last $user |");
|
||||
local $quser = quotemeta($user);
|
||||
open($fh, "(last -w $quser || last $quser) |");
|
||||
}
|
||||
|
||||
# read_last_line(handle)
|
||||
@@ -34,7 +35,9 @@ while(1) {
|
||||
chop($line = <$fh>);
|
||||
if (!$line) { return (); }
|
||||
if ($line =~ /^(reboot|shutdown)/) { next; }
|
||||
if ($line =~ /^(\S+)\s+(\S+)\s+(\S+)?\s+(\S+\s+\S+\s+\d+\s+\d+:\d+)\s+\-\s+(\S+)\s+\((\d+:\d+)\)/) {
|
||||
if ($line =~ /^(\S+)\s+(\S+)\s+(\S+)?\s+(\S+\s+\S+\s+\d+\s+\d+:\d+)\s+\-\s+(\S+)\s+\((.*?\d+:\d+.*?)\)/) {
|
||||
# root pts/0 10.211.55.2 Tue Nov 22 21:06 - 23:16 (02:10:00)
|
||||
# root pts/1 10.211.55.2 Wed Jun 29 13:13 - shutdown (7+00:01:20)
|
||||
return ($1, $2, $3, $4, $5 eq "shutdown" ? "Shutdown" :
|
||||
$5 eq "crash" ? "Crash" : $5, $6);
|
||||
}
|
||||
|
||||
@@ -44,9 +44,10 @@ while(1) {
|
||||
# jcameron pts/0 fudu Sun Feb 4 02:26:28 2024 - Wed Feb 7 18:25:09 2024 (3+15:58)
|
||||
return ($1, $2, $3, $4, $5 eq "down" ? "Shutdown" : $5, $6);
|
||||
}
|
||||
elsif ($line =~ /^(\S+)\s+(\S+)\s+(\S+)?\s+(\S+\s+\S+\s+\d+\s+\d+:\d+)\s+still/ ||
|
||||
$line =~ /^(\S+)\s+(\S+)\s+(\S+)?\s+(\S+\s+\S+\s+\d+\s+\d+:\d+:\d+\s+\d+)\s+still/) {
|
||||
elsif ($line =~ /^(\S+)\s+(\S+)\s+(\S+)?\s+(\S+\s+\S+\s+\d+\s+\d+:\d+)\s+(still|gone)/ ||
|
||||
$line =~ /^(\S+)\s+(\S+)\s+(\S+)?\s+(\S+\s+\S+\s+\d+\s+\d+:\d+:\d+\s+\d+)\s+(still|gone)/) {
|
||||
# root pts/0 fudu Fri Feb 23 18:46 still logged in
|
||||
# root ftpd10 fudu Thu Jun 20 11:19 gone - no logout
|
||||
# root pts/0 fudu Tue Jun 18 23:10:30 2024 still logged in
|
||||
return ($1, $2, $3, $4);
|
||||
}
|
||||
|
||||
207
web-lib-funcs.pl
207
web-lib-funcs.pl
@@ -2098,10 +2098,10 @@ formatted like dd/mmm/yyyy hh:mm:ss. Parameters are :
|
||||
|
||||
=item seconds - Unix time is seconds to convert.
|
||||
|
||||
=item date-only-or-opts - If set to 1, exclude the time from the returned string.
|
||||
=item date-only-or-opts - If set to 1 exclude the time from the returned string.
|
||||
|
||||
In case this param is a hash reference use it for options in a new DateTime::Locale
|
||||
code or preserve the original, old logic
|
||||
In case this param is a hash reference use it for options in a new
|
||||
DateTime::Locale code or preserve the original, old logic
|
||||
|
||||
=item fmt - Optional, one of dd/mon/yyyy, dd/mm/yyyy, mm/dd/yyyy or yyyy/mm/dd
|
||||
|
||||
@@ -2116,27 +2116,31 @@ if (!$@ && $] > 5.011) {
|
||||
my $opts = ref($only) ? $only : {};
|
||||
my $locale_default = &get_default_system_locale();
|
||||
my $locale_auto = &parse_accepted_language();
|
||||
my $locale_name = $opts->{'locale'} || $gconfig{'locale_'.$base_remote_user} ||
|
||||
my $locale_name = $opts->{'locale'} ||
|
||||
$gconfig{'locale_'.$base_remote_user} ||
|
||||
$gconfig{'locale_'.$remote_user} || $locale_auto ||
|
||||
$gconfig{'locale'} || &get_default_system_locale();
|
||||
my $tz = $opts->{'tz'};
|
||||
if (!$tz) {
|
||||
eval {
|
||||
$tz =
|
||||
DateTime::TimeZone->new(name => strftime("%z", localtime()))->name(); # +0200
|
||||
$tz = DateTime::TimeZone->new(
|
||||
name => strftime("%z", localtime()))->name(); # +0200
|
||||
};
|
||||
if ($@) {
|
||||
eval {
|
||||
$tz = DateTime::TimeZone->new(name => 'local')->name(); # Asia/Nicosia
|
||||
$tz = DateTime::TimeZone->new(
|
||||
name => 'local')->name(); # Asia/Nicosia
|
||||
};
|
||||
if ($@) {
|
||||
$tz = DateTime::TimeZone->new(name => 'UTC')->name(); # UTC
|
||||
$tz = DateTime::TimeZone->new(
|
||||
name => 'UTC')->name(); # UTC
|
||||
}
|
||||
}
|
||||
}
|
||||
# Pre-process time locale
|
||||
my $locale_military_status = sub {
|
||||
return ($locale_military_name && $locale_military_name =~ /[a-z]/i) ? 2 :
|
||||
return ($locale_military_name &&
|
||||
$locale_military_name =~ /[a-z]/i) ? 2 :
|
||||
($locale_military_name == 1) ? 1 : 0;
|
||||
};
|
||||
# Allow locales with military time (in 24h format)
|
||||
@@ -2152,15 +2156,18 @@ if (!$@ && $] > 5.011) {
|
||||
my $locale = DateTime::Locale->load($locale_name_loaded);
|
||||
# Create a new locale out of base locale
|
||||
if (&$locale_military_status() == 1) {
|
||||
my %locale_data = $locale->locale_data;
|
||||
$locale_data{'code'} = $locale_name_initial;
|
||||
my %locale_data = $locale->locale_data;
|
||||
$locale_data{'code'} = $locale_name_initial;
|
||||
|
||||
# Force 24h time
|
||||
$locale_data{'glibc_date_1_format'} = '%a %b %e %H:%M:%S %Z %Y';
|
||||
$locale_data{'glibc_date_1_format'} = '%a %b %e %H:%M:%S %Z %Y';
|
||||
$locale_data{'glibc_datetime_format'} = '%a %d %b %Y %T %Z';
|
||||
$locale_data{'glibc_time_format'} = '%T';
|
||||
$locale_data{'glibc_time_format'} = '%T';
|
||||
DateTime::Locale->register_from_data(%locale_data);
|
||||
|
||||
# Load newly cloned locale in 24h time format
|
||||
$locale_military_name = $locale_name_loaded = $locale_name_initial;
|
||||
$locale_military_name = $locale_name_loaded =
|
||||
$locale_name_initial;
|
||||
$locale = DateTime::Locale->load($locale_name_loaded);
|
||||
}
|
||||
my $locale_format_full_tz = $locale->glibc_date_1_format; # Sat 20 Nov 2286 17:46:39 UTC
|
||||
@@ -2194,18 +2201,31 @@ if (!$@ && $] > 5.011) {
|
||||
"pretty" => $ago_obj->pretty
|
||||
};
|
||||
}
|
||||
# my $xxxx = $locale->full_date_format;
|
||||
my $data = {
|
||||
# Wed Feb 8 05:09:39 PM UTC 2023
|
||||
'full-tz-utc' => DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs)->strftime($locale_format_full_tz),
|
||||
'full-tz-utc' => DateTime->from_epoch(
|
||||
locale => $locale_name_loaded,
|
||||
epoch => $secs)->strftime($locale_format_full_tz),
|
||||
# Wed Feb 8 07:10:01 PM EET 2023
|
||||
'full-tz' => DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs, time_zone => $tz)->strftime($locale_format_full_tz),
|
||||
'full-tz' => DateTime->from_epoch(
|
||||
locale => $locale_name_loaded,
|
||||
epoch => $secs,
|
||||
time_zone => $tz)->strftime($locale_format_full_tz),
|
||||
# Wed 08 Feb 2023 07:11:26 PM EET
|
||||
'full' => DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs, time_zone => $tz)->strftime($locale_format_full),
|
||||
'full' => DateTime->from_epoch(
|
||||
locale => $locale_name_loaded,
|
||||
epoch => $secs,
|
||||
time_zone => $tz)->strftime($locale_format_full),
|
||||
# 02/08/2023
|
||||
'short' => DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs, time_zone => $tz)->strftime($locale_format_short),
|
||||
'short' => DateTime->from_epoch(
|
||||
locale => $locale_name_loaded,
|
||||
epoch => $secs,
|
||||
time_zone => $tz)->strftime($locale_format_short),
|
||||
# 07:12:07 PM
|
||||
'time' => DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs, time_zone => $tz)->strftime($locale_format_time),
|
||||
'time' => DateTime->from_epoch(
|
||||
locale => $locale_name_loaded,
|
||||
epoch => $secs,
|
||||
time_zone => $tz)->strftime($locale_format_time),
|
||||
'ago' => $ago,
|
||||
'tz' => $tz,
|
||||
'delimiter' => $locale_format_delimiter,
|
||||
@@ -2216,10 +2236,16 @@ if (!$@ && $] > 5.011) {
|
||||
$data->{'timeshort'} = $data->{'time'};
|
||||
$data->{'timeshort'} =~ s/(\d+):(\d+):(\d+)(.*?)/$1:$2$4/;
|
||||
|
||||
# %c alternative with full week and month and no seconds in time (complete)
|
||||
# Wednesday, February 8, 2023, 8:18 PM or 星期三, 2023年2月8日 20:18 or miércoles, 8 febrero 2023, 20:28
|
||||
$data->{'monthfull'} = DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs, time_zone => $tz)->strftime("%B");
|
||||
foreach (split(/\s+/, DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs, time_zone => $tz)->strftime("%A, %c"))) {
|
||||
# %c alternative with full week and month and no seconds
|
||||
# in time (complete)
|
||||
# Wednesday, February 8, 2023, 8:18 PM or 星期三,
|
||||
# 2023年2月8日 20:18 or miércoles, 8 febrero 2023, 20:28
|
||||
$data->{'monthfull'} = DateTime->from_epoch(
|
||||
locale => $locale_name_loaded, epoch => $secs,
|
||||
time_zone => $tz)->strftime("%B");
|
||||
foreach (split(/\s+/, DateTime->from_epoch(
|
||||
locale => $locale_name_loaded, epoch => $secs,
|
||||
time_zone => $tz)->strftime("%A, %c"))) {
|
||||
if ($data->{'monthfull'} =~ /^$_/) {
|
||||
$data->{'complete'} .= "$data->{'monthfull'} "
|
||||
}
|
||||
@@ -2227,13 +2253,24 @@ if (!$@ && $] > 5.011) {
|
||||
$data->{'complete'} .= "$_ "
|
||||
}
|
||||
};
|
||||
$data->{'year'} = DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs, time_zone => $tz)->strftime("%Y");
|
||||
$data->{'day'} = DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs, time_zone => $tz)->strftime("%d");
|
||||
$data->{'week'} = DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs, time_zone => $tz)->strftime("%a");
|
||||
$data->{'weekfull'} = DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs, time_zone => $tz)->strftime("%A");
|
||||
$data->{'month'} = DateTime->from_epoch(locale => $locale_name_loaded, epoch => $secs, time_zone => $tz)->strftime("%b");
|
||||
$data->{'year'} = DateTime->from_epoch(
|
||||
locale => $locale_name_loaded, epoch => $secs,
|
||||
time_zone => $tz)->strftime("%Y");
|
||||
$data->{'day'} = DateTime->from_epoch(
|
||||
locale => $locale_name_loaded, epoch => $secs,
|
||||
time_zone => $tz)->strftime("%d");
|
||||
$data->{'week'} = DateTime->from_epoch(
|
||||
locale => $locale_name_loaded, epoch => $secs,
|
||||
time_zone => $tz)->strftime("%a");
|
||||
$data->{'weekfull'} = DateTime->from_epoch(
|
||||
locale => $locale_name_loaded, epoch => $secs,
|
||||
time_zone => $tz)->strftime("%A");
|
||||
$data->{'month'} = DateTime->from_epoch(
|
||||
locale => $locale_name_loaded, epoch => $secs,
|
||||
time_zone => $tz)->strftime("%b");
|
||||
$data->{'complete'} =~ s/(\d+):(\d+):(\d+)(.*?)/$1:$2$4/;
|
||||
($data->{'complete_short'} = $data->{'complete'}) =~ s/(.*?)([\s\,]*\Q$data->{'year'}\E.*)/$1/;
|
||||
($data->{'complete_short'} = $data->{'complete'}) =~
|
||||
s/(.*?)([\s\,]*\Q$data->{'year'}\E.*)/$1/;
|
||||
|
||||
if ($opts->{'get'}) {
|
||||
return $data->{$opts->{'get'}};
|
||||
@@ -7973,6 +8010,100 @@ return ref($s) && $s->{'host'} && $s->{'port'} ?
|
||||
ref($s) ? "" : "$s.$$";
|
||||
}
|
||||
|
||||
=head2 verify_session_id(session-id, [sessiondb], [miniserv])
|
||||
|
||||
Returns the username (or an array with user, last login, and IP address) for the
|
||||
given session (or session hash) ID, or undefined if session ID is invalid.
|
||||
|
||||
Args:
|
||||
|
||||
$sid: The session ID to verify
|
||||
|
||||
$sessiondb: A reference to the session database hash (optional)
|
||||
|
||||
$miniserv: A reference to the miniserv configuration hash (optional)
|
||||
|
||||
Returns:
|
||||
|
||||
In list context: A list containing the user, last activity time, and IP
|
||||
address associated with the session ID.
|
||||
|
||||
In scalar context: The user associated with the session ID.
|
||||
|
||||
If the session ID is not found, returns an empty list in list context
|
||||
or undef in scalar context.
|
||||
|
||||
Usage:
|
||||
|
||||
Retrieve the username associated with the session ID or undef if
|
||||
session is invalid.
|
||||
|
||||
my $user = verify_session_id($main::session_id);
|
||||
Example of return:
|
||||
root
|
||||
|
||||
Retrieve array containing the user, last login, and IP address
|
||||
for given session hash ID or undef if session is invalid.
|
||||
|
||||
my (@user) = verify_session_id('BSRxr6wpF25lqeRinQ/sv0');
|
||||
Example of return:
|
||||
[
|
||||
'root',
|
||||
'1719401071',
|
||||
'10.211.55.2'
|
||||
]
|
||||
|
||||
Retrieve the username associated with the session ID, using given
|
||||
session DB or undef if session is invalid.
|
||||
|
||||
my %sessiondb;
|
||||
dbmopen(%sessiondb, "$var_directory/sessiondb", 0400);
|
||||
my $user = verify_session_id($main::session_id, \%sessiondb);
|
||||
dbmclose(%sessiondb);
|
||||
Example of return:
|
||||
someuser1
|
||||
|
||||
=cut
|
||||
sub verify_session_id
|
||||
{
|
||||
my ($sid, $sessiondb, $miniserv) = @_;
|
||||
my $hashsessionidfunc = \&miniserv::hash_session_id;
|
||||
my %miniserv;
|
||||
if ($miniserv) {
|
||||
# Use provided miniserv configuration
|
||||
%miniserv = %{$miniserv};
|
||||
}
|
||||
else {
|
||||
# Load miniserv configuration if not provided
|
||||
&get_miniserv_config(\%miniserv);
|
||||
}
|
||||
my %sessiondb_;
|
||||
if ($sessiondb) {
|
||||
# Use provided session database
|
||||
%sessiondb_ = %{$sessiondb};
|
||||
}
|
||||
elsif (&foreign_available('acl')) {
|
||||
# Use session database using ACL module API
|
||||
&foreign_require("acl");
|
||||
&acl::open_session_db(\%miniserv);
|
||||
$hashsessionidfunc = \&acl::hash_session_id;
|
||||
%sessiondb_ = %acl::sessiondb;
|
||||
}
|
||||
else {
|
||||
return wantarray ? ( ) : undef;
|
||||
}
|
||||
# Verify given session (hash) ID against the session database
|
||||
foreach my $k (grep { $sessiondb_{$_} } keys %sessiondb_) {
|
||||
if ($k eq $sid ||
|
||||
(defined($hashsessionidfunc) && $k eq $hashsessionidfunc->($sid))) {
|
||||
my ($user, $last, $ip) = split(/\s+/, $sessiondb_{$k});
|
||||
return wantarray ? ($user, $last, $ip) : $user;
|
||||
}
|
||||
}
|
||||
# Return an empty list or undef if session ID is not found
|
||||
return wantarray ? ( ) : undef;
|
||||
}
|
||||
|
||||
=head2 remote_foreign_require(server, module, file)
|
||||
|
||||
Connects to rpc.cgi on a remote webmin server and have it open a session
|
||||
@@ -10545,6 +10676,16 @@ elsif (defined($main::open_tempfiles{$_[0]})) {
|
||||
# Closing a file
|
||||
my $noerror = $main::open_tempfiles_noerror{$_[0]};
|
||||
&webmin_debug_log("CLOSE", $_[0]) if ($gconfig{'debug_what_write'});
|
||||
my $getfacl = &has_command("getfacl");
|
||||
my $setfacl = &has_command("setfacl");
|
||||
my $file_acls;
|
||||
if ($getfacl && $setfacl) {
|
||||
# Set original ACLs
|
||||
my $qaclfile = quotemeta($_[0]);
|
||||
$file_acls = &backquote_command(
|
||||
"$getfacl --absolute-names $qaclfile 2>/dev/null");
|
||||
}
|
||||
# Get status info for a file
|
||||
my @st = stat($_[0]);
|
||||
if (&is_selinux_enabled() && &has_command("chcon")) {
|
||||
# Set original security context
|
||||
@@ -10566,6 +10707,12 @@ elsif (defined($main::open_tempfiles{$_[0]})) {
|
||||
chmod($st[2], $_[0]);
|
||||
chown($st[4], $st[5], $_[0]);
|
||||
}
|
||||
if ($file_acls) {
|
||||
# Set original ACLs
|
||||
open(my $pipe, '|-', "$setfacl --restore=-");
|
||||
print($pipe $file_acls);
|
||||
close($pipe);
|
||||
}
|
||||
&reset_file_attributes($_[0], \@old_attributes);
|
||||
delete($main::open_tempfiles{$_[0]});
|
||||
delete($main::open_tempfiles_noerror{$_[0]});
|
||||
|
||||
@@ -18,6 +18,7 @@ else {
|
||||
|
||||
# Save collection options
|
||||
$system_status::config{'collect_pkgs'} = $in{'pkgs'};
|
||||
$system_status::config{'collect_notemp2'} = !$in{'temp2'};
|
||||
$system_status::config{'collect_notemp'} = !$in{'temp'};
|
||||
$system_status::config{'collect_units'} = $in{'units'};
|
||||
|
||||
|
||||
@@ -277,7 +277,9 @@ else {
|
||||
my @doms = $config{'letsencrypt_doms'} ?
|
||||
split(/\s+/, $config{'letsencrypt_doms'}) : ( $host );
|
||||
print &ui_table_row($text{'ssl_letsdoms'},
|
||||
&ui_textarea("dom", join("\n", @doms), 5, 40));
|
||||
&ui_textarea("dom", join("\n", @doms), 5, 40)."<br>\n".
|
||||
&ui_checkbox("subset", 1, $text{'ssl_subset'},
|
||||
$config{'letsencrypt_subset'}));
|
||||
|
||||
# Apache vhost or other path
|
||||
my @opts;
|
||||
|
||||
@@ -19,6 +19,10 @@ print &ui_table_row($text{'status_interval'},
|
||||
print &ui_table_row($text{'status_pkgs'},
|
||||
&ui_yesno_radio("pkgs", $system_status::config{'collect_pkgs'}));
|
||||
|
||||
# Collect CPU temerature?
|
||||
print &ui_table_row($text{'status_temp2'},
|
||||
&ui_yesno_radio("temp2", !$system_status::config{'collect_notemp2'}));
|
||||
|
||||
# Collect drive temps?
|
||||
print &ui_table_row($text{'status_temp'},
|
||||
&ui_yesno_radio("temp", !$system_status::config{'collect_notemp'}));
|
||||
|
||||
@@ -424,6 +424,7 @@ ssl_letserr2=Alternately, check the <a href='$1'>module configuration</a> page t
|
||||
ssl_letsdesc2=This page can be used to request a new certificate, which will overwrite any other currently have configured in Webmin. However, the Let's Encrypt service requires that your ownership of the certificate domain be validated by checking that this system hosts the website for the domain. This is done by placing a small temporary file in the website's document directory.
|
||||
ssl_letsheader=Options for new SSL certificate
|
||||
ssl_letsdoms=Hostnames for certificate
|
||||
ssl_subset=Skip unverifiable hostnames?
|
||||
ssl_letsmode=Let's Encrypt validation method
|
||||
ssl_letsmode0=Apache virtual host matching hostname
|
||||
ssl_letsmode1=Selected Apache virtual host
|
||||
@@ -1060,6 +1061,7 @@ status_interval0=Every
|
||||
status_mins=minutes
|
||||
status_pkgs=Collect available package updates?
|
||||
status_temp=Collect drive temperatures?
|
||||
status_temp2=Collect CPU temperatures and fans speed?
|
||||
status_units=Units for temperatures
|
||||
status_celsius=Celsius
|
||||
status_fahrenheit=Fahrenheit
|
||||
|
||||
@@ -58,14 +58,16 @@ return &software::missing_install_link(
|
||||
|
||||
# request_letsencrypt_cert(domain|&domains, webroot, [email], [keysize],
|
||||
# [request-mode], [use-staging], [account-email],
|
||||
# [reuse-key], [server-url, server-key, server-hmac])
|
||||
# [key-type], [reuse-key],
|
||||
# [server-url, server-key, server-hmac],
|
||||
# [allow-subset])
|
||||
# Attempt to request a cert using a generated key with the Let's Encrypt client
|
||||
# command, and write it to the given path. Returns a status flag, and either
|
||||
# an error message or the paths to cert, key and chain files.
|
||||
sub request_letsencrypt_cert
|
||||
{
|
||||
my ($dom, $webroot, $email, $size, $mode, $staging, $account_email,
|
||||
$key_type, $reuse_key, $server, $server_key, $server_hmac) = @_;
|
||||
$key_type, $reuse_key, $server, $server_key, $server_hmac, $subset) = @_;
|
||||
my @doms = ref($dom) ? @$dom : ($dom);
|
||||
$email ||= "root\@$doms[0]";
|
||||
$mode ||= "web";
|
||||
@@ -179,6 +181,7 @@ if ($letsencrypt_cmd) {
|
||||
my $new_flags = "";
|
||||
my $reuse_flags = "";
|
||||
my $server_flags = "";
|
||||
my $subset_flags = "";
|
||||
$key_type ||= $config{'letsencrypt_algo'} || 'rsa';
|
||||
if (&compare_version_numbers($cmd_ver, 1.11) < 0) {
|
||||
$old_flags = " --manual-public-ip-logging-ok";
|
||||
@@ -192,6 +195,9 @@ if ($letsencrypt_cmd) {
|
||||
else {
|
||||
$reuse_flags = " --no-reuse-key";
|
||||
}
|
||||
if ($subset) {
|
||||
$subset_flags = " --allow-subset-of-names";
|
||||
}
|
||||
$reuse_flags = "" if ($reuse_key && $reuse_key == -1);
|
||||
if ($server) {
|
||||
$server_flags = " --server ".quotemeta($server);
|
||||
@@ -227,6 +233,7 @@ if ($letsencrypt_cmd) {
|
||||
$old_flags.
|
||||
$server_flags.
|
||||
$new_flags.
|
||||
$subset_flags.
|
||||
" 2>&1)");
|
||||
&reset_environment();
|
||||
}
|
||||
@@ -245,6 +252,7 @@ if ($letsencrypt_cmd) {
|
||||
$old_flags.
|
||||
$server_flags.
|
||||
$new_flags.
|
||||
$subset_flags.
|
||||
" 2>&1)");
|
||||
&reset_environment();
|
||||
}
|
||||
@@ -260,6 +268,7 @@ if ($letsencrypt_cmd) {
|
||||
$old_flags.
|
||||
$server_flags.
|
||||
$new_flags.
|
||||
$subset_flags.
|
||||
" 2>&1)");
|
||||
&reset_environment();
|
||||
}
|
||||
|
||||
@@ -54,8 +54,11 @@ else {
|
||||
"VirtualHost", $conf)) {
|
||||
my $sn = &apache::find_directive(
|
||||
"ServerName", $virt->{'members'});
|
||||
my @sa = &apache::find_directive(
|
||||
"ServerAlias", $virt->{'members'});
|
||||
my $match = 0;
|
||||
if ($in{'webroot_mode'} == 0 && $sn eq $doms[0]) {
|
||||
if ($in{'webroot_mode'} == 0 &&
|
||||
&indexof($doms[0], $sn, @sa) >= 0) {
|
||||
# Based on domain name
|
||||
$match = 1;
|
||||
}
|
||||
@@ -63,7 +66,16 @@ else {
|
||||
# Specifically selected domain
|
||||
$match = 1;
|
||||
}
|
||||
if ($match) {
|
||||
my @ports;
|
||||
foreach my $w (@{$virt->{'words'}}) {
|
||||
if ($w =~ /:(\d+)$/) {
|
||||
push(@ports, $1);
|
||||
}
|
||||
else {
|
||||
push(@ports, 80);
|
||||
}
|
||||
}
|
||||
if ($match && &indexof(80, @ports) >= 0) {
|
||||
# Get document root
|
||||
$webroot = &apache::find_directive(
|
||||
"DocumentRoot", $virt->{'members'}, 1);
|
||||
@@ -76,7 +88,7 @@ else {
|
||||
|
||||
if ($in{'save'}) {
|
||||
# Just update renewal
|
||||
&save_renewal_only(\@doms, $webroot, $mode);
|
||||
&save_renewal_only(\@doms, $webroot, $mode, $size, $in{'subset'});
|
||||
&redirect("edit_ssl.cgi");
|
||||
}
|
||||
else {
|
||||
@@ -88,7 +100,9 @@ else {
|
||||
'letsencrypt_doing',
|
||||
"<tt>".&html_escape(join(", ", @doms))."</tt>",
|
||||
"<tt>".&html_escape($webroot)."</tt>"),"<p>\n";
|
||||
my ($ok, $cert, $key, $chain) = &request_letsencrypt_cert(\@doms, $webroot, undef, $size, $mode, $in{'staging'});
|
||||
my ($ok, $cert, $key, $chain) = &request_letsencrypt_cert(
|
||||
\@doms, $webroot, undef, $size, $mode, $in{'staging'},
|
||||
undef, undef, undef, undef, undef, undef, $in{'subset'});
|
||||
if (!$ok) {
|
||||
print &text('letsencrypt_failed', $cert),"<p>\n";
|
||||
}
|
||||
@@ -127,7 +141,8 @@ else {
|
||||
&put_miniserv_config(\%miniserv);
|
||||
&unlock_file($ENV{'MINISERV_CONFIG'});
|
||||
|
||||
&save_renewal_only(\@doms, $webroot, $mode);
|
||||
&save_renewal_only(\@doms, $webroot, $mode,
|
||||
$size, $in{'subset'});
|
||||
|
||||
&webmin_log("letsencrypt");
|
||||
&restart_miniserv(1);
|
||||
@@ -148,15 +163,16 @@ else {
|
||||
&ui_print_footer("", $text{'index_return'});
|
||||
}
|
||||
|
||||
# save_renewal_only(&doms, webroot, mode)
|
||||
# save_renewal_only(&doms, webroot, mode, size, subset-mode)
|
||||
# Save for future renewals
|
||||
sub save_renewal_only
|
||||
{
|
||||
my ($doms, $webroot, $mode) = @_;
|
||||
my ($doms, $webroot, $mode, $size, $subset) = @_;
|
||||
$config{'letsencrypt_doms'} = join(" ", @$doms);
|
||||
$config{'letsencrypt_webroot'} = $webroot;
|
||||
$config{'letsencrypt_mode'} = $mode;
|
||||
$config{'letsencrypt_size'} = $size;
|
||||
$config{'letsencrypt_subset'} = $subset;
|
||||
&save_module_config();
|
||||
if (&foreign_check("webmincron")) {
|
||||
my $job = &find_letsencrypt_cron_job();
|
||||
|
||||
@@ -234,7 +234,7 @@ my $str = "otpauth://totp/".$name."?secret=".$user->{'twofactor_id'};
|
||||
my $url;
|
||||
if (&can_generate_qr()) {
|
||||
$url = "$gconfig{'webprefix'}/webmin/qr.cgi?".
|
||||
"size=4&str=".&urlize($str);
|
||||
"size=6&str=".&urlize($str);
|
||||
}
|
||||
else {
|
||||
$url = "https://chart.googleapis.com/chart".
|
||||
|
||||
@@ -2638,6 +2638,10 @@ $gconfig{'real_os_type'} = $osinfo{'real_os_type'};
|
||||
$gconfig{'real_os_version'} = $osinfo{'real_os_version'};
|
||||
$gconfig{'os_type'} = $osinfo{'os_type'};
|
||||
$gconfig{'os_version'} = $osinfo{'os_version'};
|
||||
foreach my $key ('os_eol_db', 'os_eol_expired',
|
||||
'os_eol_expiring') {
|
||||
delete($gconfig{$key});
|
||||
}
|
||||
&write_file("$config_directory/config", \%gconfig);
|
||||
&unlock_file("$config_directory/config");
|
||||
|
||||
@@ -2869,7 +2873,7 @@ if (!$@) {
|
||||
my $out;
|
||||
Image::PNG::QRCode::qrpng(
|
||||
text => $str,
|
||||
scale => $size || 3,
|
||||
scale => $size || 6,
|
||||
out => \$out,
|
||||
);
|
||||
return ($out, "image/png");
|
||||
|
||||
Reference in New Issue
Block a user