Merge branch 'master' of github.com:webmin/webmin

This commit is contained in:
Jamie Cameron
2025-09-29 13:35:49 -07:00
12 changed files with 99 additions and 146 deletions

View File

@@ -647,5 +647,4 @@ else {
}
}
1;

View File

@@ -16,9 +16,9 @@ my $timeout = $gconfig{'passreset_timeout'} || 15;
$remote_user && &error($text{'forgot_elogin'});
$ENV{'HTTPS'} eq 'ON' || $gconfig{'forgot_pass'} == 2 ||
&error($text{'forgot_essl'});
$ENV{'SSL_HOST_CERT'} == 1 ||
$ENV{'SSL_CN_CERT'} == 1 ||
&error(&text('forgot_esslhost',
&html_escape($ENV{'HTTP_HOST'} || $ENV{'SSL_HOST'})))
&html_escape($ENV{'HTTP_HOST'} || $ENV{'SSL_CN'})))
if ($ENV{'HTTPS'} eq 'ON');
# Check that the random ID is valid

View File

@@ -15,9 +15,9 @@ $gconfig{'forgot_pass'} || &error($text{'forgot_ecannot'});
$remote_user && &error($text{'forgot_elogin'});
$ENV{'HTTPS'} eq 'ON' || $gconfig{'forgot_pass'} == 2 ||
&error($text{'forgot_essl'});
$ENV{'SSL_HOST_CERT'} == 1 ||
$ENV{'SSL_CN_CERT'} == 1 ||
&error(&text('forgot_esslhost',
&html_escape($ENV{'HTTP_HOST'} || $ENV{'SSL_HOST'})))
&html_escape($ENV{'HTTP_HOST'} || $ENV{'SSL_CN'})))
if ($ENV{'HTTPS'} eq 'ON');
&ui_print_header(undef, $text{'forgot_title'}, "", undef, undef, 1, 1);

View File

@@ -14,9 +14,9 @@ $gconfig{'forgot_pass'} || &error($text{'forgot_ecannot'});
$remote_user && &error($text{'forgot_elogin'});
$ENV{'HTTPS'} eq 'ON' || $gconfig{'forgot_pass'} == 2 ||
&error($text{'forgot_essl'});
$ENV{'SSL_HOST_CERT'} == 1 ||
$ENV{'SSL_CN_CERT'} == 1 ||
&error(&text('forgot_esslhost',
&html_escape($ENV{'HTTP_HOST'} || $ENV{'SSL_HOST'})))
&html_escape($ENV{'HTTP_HOST'} || $ENV{'SSL_CN'})))
if ($ENV{'HTTPS'} eq 'ON');
# Lookup the Webmin user

View File

@@ -109,7 +109,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", "html2text", "qrencode", "libdbi-perl", "libdbd-mysql-perl", "libjson-xs-perl" );
@recommends = ( "libdatetime-perl", "libdatetime-timezone-perl", "libdatetime-locale-perl", "libtime-piece-perl", "libencode-detect-perl", "libtime-hires-perl", "libsocket6-perl", "html2text", "qrencode", "libdbi-perl", "libdbd-mysql-perl", "libjson-xs-perl", "libsys-syslog-perl" );
$recommends = join(", ", @recommends);
open(CONTROL, ">$control_file");
print CONTROL <<EOF;

View File

@@ -34,7 +34,7 @@ my $allow_overwrite = 0;
my ($force_theme, $no_prefix, $set_prefix,
$obsolete_wbm, $vendor, $url, $force_usermin, $final_mod, $sign, $keyname,
$epoch, $dir, $ver, @exclude,
$epoch, $dir, $ver, @exclude, $copy_tar,
$rpmdepends, $norpmdepends, $rpmrecommends, $norpmrecommends,
$no_requires, $no_recommends, $no_suggests, $no_conflicts, $no_provides,
@@ -136,6 +136,9 @@ while(@ARGV) {
elsif ($a eq "--mod-list") {
$mod_list = shift(@ARGV);
}
elsif ($a eq "--copy-tar") {
$copy_tar = 1;
}
elsif ($a =~ /^\-\-/) {
print STDERR "Unknown option $a\n";
exit(1);
@@ -556,6 +559,15 @@ fi
EOF
close($SPEC);
# Put the tar in /tmp too if tar package is requested
my $tar_release_file;
if ($copy_tar) {
my $tar_release = $release;
$tar_release =~ s/^[0-9]+//;
$tar_release_file = "$prefix$mod-$ver$tar_release.tar.gz";
system("cp $rpm_source_dir/$mod.tar.gz /tmp/$tar_release_file");
}
# Build the actual RPM
my $cmd = -x "/usr/bin/rpmbuild" ? "/usr/bin/rpmbuild" : "/bin/rpm";
system("$cmd -ba $spec_dir/$prefix$mod.spec") && exit;
@@ -570,10 +582,20 @@ if ($sign) {
if ($target_dir =~ /:/) {
# scp to dest
system("scp $rpm_dir/$prefix$mod-$ver-$release.noarch.rpm $target_dir/$prefix$mod-$ver-$release.noarch.rpm");
# scp the tar too if requested
if ($copy_tar) {
system("scp /tmp/$tar_release_file $target_dir/$tar_release_file");
unlink("/tmp/$tar_release_file");
}
}
elsif ($rpm_dir ne $target_dir) {
# Just copy
system("/bin/cp $rpm_dir/$prefix$mod-$ver-$release.noarch.rpm $target_dir/$prefix$mod-$ver-$release.noarch.rpm");
# Copy the tar too if requested
if ($copy_tar) {
system("/bin/cp /tmp/$tar_release_file $target_dir/$tar_release_file");
unlink("/tmp/$tar_release_file");
}
}
# read_file(file, &assoc, [&order], [lowercase])

View File

@@ -88,7 +88,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) html2text shared-mime-info perl-File-Basename perl-File-Path perl-JSON-XS qrencode perl(DBI) perl(DBD::mysql)
Recommends: perl(DateTime) perl(DateTime::TimeZone) perl(DateTime::Locale) perl(Time::Piece) perl(Encode::Detect) perl(Time::HiRes) perl(Socket6) perl(Sys::Syslog) html2text shared-mime-info perl-File-Basename perl-File-Path perl-JSON-XS qrencode perl(DBI) perl(DBD::mysql)
AutoReq: 0
License: BSD-3-Clause
Group: System/Tools

View File

@@ -942,8 +942,8 @@ while(1) {
($ssl_con,
$ssl_certfile,
$ssl_keyfile,
$ssl_host,
$ssl_cert_hosts) =
$ssl_cn,
$ssl_alts) =
&ssl_connection_for_ip(
SOCK, $ipv6fhs{$s});
print DEBUG "ssl_con returned ".
@@ -2503,9 +2503,9 @@ if (&get_type($full) eq "internal/cgi" && $validated != 4) {
$ENV{"HTTPS"} = $use_ssl ? "ON" : "";
$ENV{"SSL_HSTS"} = $config{"ssl_hsts"};
if ($use_ssl) {
$ENV{"SSL_HOST"} = $ssl_host;
$ENV{"SSL_HOST_CERT"} =
&ssl_hostname_match($header{'host'}, $ssl_cert_hosts);
$ENV{"SSL_CN"} = $ssl_cn;
$ENV{"SSL_CN_CERT"} =
&ssl_hostname_match($header{'host'}, $ssl_alts);
}
$ENV{"MINISERV_PID"} = $miniserv_main_pid;
if ($use_ssl) {
@@ -4784,7 +4784,7 @@ eval 'Net::SSLeay::CTX_set_options($ssl_ctx,
&Net::SSLeay::OP_NO_RENEGOTIATION)';
# Get the hostnames each cert is valid for
my $info = &cert_file_info($certfile);
my $info = &cert_names($certfile);
my @hosts;
push(@hosts, $info->{'cn'}) if ($info->{'cn'});
push(@hosts, @{$info->{'alt'}}) if ($info->{'alt'});
@@ -5524,7 +5524,7 @@ foreach my $pe (split(/\t+/, $config{'expires_paths'})) {
undef(%sudocache);
# Reset cache of cert files
undef(%cert_file_info_cache);
undef(%cert_names_cache);
}
# is_group_member(&uinfo, groupname)
@@ -7014,122 +7014,60 @@ if (!$sig) {
return $sig;
}
# cert_file_info(file)
# Returns a hash of details of a cert in some file
sub cert_file_info
{
local ($file) = @_;
return $cert_file_info_cache{$file} if ($cert_file_info_cache{$file});
return undef if (!-r $file);
my %rv;
my $cmd = "openssl x509 -in ".quotemeta($file)." -issuer -subject -enddate -startdate -text";
open(OUT, $cmd." 2>/dev/null |");
local $_;
while(<OUT>) {
s/\r|\n//g;
s/http:\/\//http:\|\|/g; # So we can parse with regexp
if (/subject=.*C\s*=\s*([^\/,]+)/) {
$rv{'c'} = $1;
}
if (/subject=.*ST\s*=\s*([^\/,]+)/) {
$rv{'st'} = $1;
}
if (/subject=.*L\s*=\s*([^\/,]+)/) {
$rv{'l'} = $1;
}
if (/subject=.*O\s*=\s*"(.*?)"/ || /subject=.*O\s*=\s*([^\/,]+)/) {
$rv{'o'} = $1;
}
if (/subject=.*OU\s*=\s*([^\/,]+)/) {
$rv{'ou'} = $1;
}
if (/subject=.*CN\s*=\s*([^\/,]+)/) {
$rv{'cn'} = $1;
}
if (/subject=.*emailAddress\s*=\s*([^\/,]+)/) {
$rv{'email'} = $1;
}
=head2 cert_names($file)
if (/issuer=.*C\s*=\s*([^\/,]+)/) {
$rv{'issuer_c'} = $1;
}
if (/issuer=.*ST\s*=\s*([^\/,]+)/) {
$rv{'issuer_st'} = $1;
}
if (/issuer=.*L\s*=\s*([^\/,]+)/) {
$rv{'issuer_l'} = $1;
}
if (/issuer=.*O\s*=\s*"(.*?)"/ || /issuer=.*O\s*=\s*([^\/,]+)/) {
$rv{'issuer_o'} = $1;
}
if (/issuer=.*OU\s*=\s*([^\/,]+)/) {
$rv{'issuer_ou'} = $1;
}
if (/issuer=.*CN\s*=\s*([^\/,]+)/) {
$rv{'issuer_cn'} = $1;
}
if (/issuer=.*emailAddress\s*=\s*([^\/,]+)/) {
$rv{'issuer_email'} = $1;
}
if (/notAfter\s*=\s*(.*)/) {
$rv{'notafter'} = $1;
}
if (/notBefore\s*=\s*(.*)/) {
$rv{'notbefore'} = $1;
}
if (/Subject\s+Alternative\s+Name/i) {
my $alts = <OUT>;
$alts =~ s/^\s+//;
foreach my $a (split(/[, ]+/, $alts)) {
if ($a =~ /^DNS:(\S+)/) {
push(@{$rv{'alt'}}, $1);
}
}
}
# Try to detect key algorithm
if (/Key\s+Algorithm:.*?(rsa|ec)[EP]/) {
$rv{'algo'} = $1;
}
if (/RSA\s+Public\s+Key:\s+\((\d+)\s*bit/) {
$rv{'size'} = $1;
}
elsif (/EC\s+Public\s+Key:\s+\((\d+)\s*bit/) {
$rv{'size'} = $1;
}
elsif (/Public-Key:\s+\((\d+)\s*bit/) {
$rv{'size'} = $1;
}
if (/Modulus\s*\(.*\):/ || /Modulus:/) {
$inmodulus = 1;
# RSA algo
$rv{'algo'} = "rsa" if (!$rv{'algo'});
}
elsif (/pub:/) {
$inmodulus = 1;
# ECC algo
$rv{'algo'} = 'ec' if (!$rv{'algo'});
}
if (/^\s+([0-9a-f:]+)\s*$/ && $inmodulus) {
$rv{'modulus'} .= $1;
}
# RSA exponent
if (/Exponent:\s*(\d+)/) {
$rv{'exponent'} = $1;
$inmodulus = 0;
}
# ECC properties
elsif (/(ASN1\s+OID):\s*(\S+)/ || /(NIST\s+CURVE):\s*(\S+)/) {
$inmodulus = 0;
my $comma = $rv{'exponent'} ? ", " : "";
$rv{'exponent'} .= "$comma$1: $2";
Extract Common Name and Subject Alternative Names from an X.509 certificate
file. Supports both PEM and DER certificates. Returns undef if file cannot be
read or parsed. Cache results for speed.
=cut
sub cert_names
{
my ($file) = @_;
return $cert_names_cache{$file} if ($cert_names_cache{$file});
return undef if (!$file || !-r $file);
my %rv;
my $cert;
# Try PEM first
my $bio = Net::SSLeay::BIO_new_file($file, 'r');
if ($bio) {
$cert = Net::SSLeay::PEM_read_bio_X509($bio);
Net::SSLeay::BIO_free($bio);
}
# Try DER if PEM failed
if (!$cert) {
my $bio = Net::SSLeay::BIO_new_file($file, 'rb');
if ($bio) {
$cert = Net::SSLeay::d2i_X509_bio($bio);
Net::SSLeay::BIO_free($bio);
}
}
close(OUT);
foreach my $k (keys %rv) {
$rv{$k} =~ s/http:\|\|/http:\/\//g;
# Certificate not found
return undef if !$cert;
# Subject
my $subject = Net::SSLeay::X509_get_subject_name($cert);
if ($subject) {
# commonName
my $cn = Net::SSLeay::X509_NAME_get_text_by_NID($subject, 13);
$rv{cn} = $cn if defined $cn && $cn ne '' && $cn ne '-1';
}
$rv{'self'} = $rv{'o'} eq $rv{'issuer_o'} ? 1 : 0;
$cert_file_info_cache{$file} = \%rv;
# subjectAltName
my @alts = Net::SSLeay::X509_get_subjectAltNames($cert);
if (@alts) {
my @dns;
while (my ($type, $val) = splice(@alts, 0, 2)) {
push @dns, $val if $type == 2;
}
$rv{alt} = \@dns if @dns;
}
Net::SSLeay::X509_free($cert);
$cert_names_cache{$file} = \%rv;
return \%rv;
}

View File

@@ -700,14 +700,14 @@ if (!@fans && @cpu && @fans_all &&
}
# Fall back logic for CPU temperature and fans spread over multiple
# devices like Raspberry Pi #2517 and #2539
# devices like Raspberry Pi #2517 and #2539 #2545
if (@cpu || !@fans) {
# - Look for least two ISA voltage rails anywhere
# - See a CPU temp under cpu_thermal
# - Optionally grab a fan RPM under pwmfan-isa-*
# - Optionally grab a fan RPM under *fan-isa-*
my $can_fallback =
(!@cpu && (grep { /^\s*cpu_thermal/i } @sensors)) ||
(@cpu && !@fans && (grep { /^\s*pwmfan-isa-/i } @sensors));
(@cpu && !@fans && (grep { /fan-isa-\d+/i } @sensors));
return (\@cpu, \@fans) if (!$can_fallback);
my ($chip, $bus); # isa|pci|platform|virtual
my $isa_volt;
@@ -735,7 +735,7 @@ if (@cpu || !@fans) {
}
# Fan RPM
if (defined $chip && $chip =~ /^pwmfan/i &&
if (defined $chip && $chip =~ /fan$/i &&
/\b(?:cpu[_ ]?fan(?:\s*\d+)?|fan\d+)\s*:\s*(\d+)\s*rpm\b/i) {
my $rpm = $1 + 0;
$fan_rpm = $rpm if (!$fan_rpm || $rpm > $fan_rpm);

View File

@@ -971,7 +971,7 @@ if (!$ENV{'nostart'}) {
print " - DateTime, DateTime::Locale, DateTime::TimeZone, Data::Dumper,\n";
print " - Digest::MD5, Digest::SHA, Encode::Detect, File::Basename,\n";
print " - File::Path, Net::SSLeay, Time::HiRes, Time::Local, Time::Piece,\n";
print " - JSON::XS, lib, open\n";
print " - Sys::Syslog, JSON::XS, lib, open\n";
print " Packages:\n";
print " - openssl - Cryptography library with TLS implementation\n";
print " - shared-mime-info - Shared MIME information database\n";

View File

@@ -1063,7 +1063,7 @@ if [ "$nostart" = "" ]; then
echo " - DateTime, DateTime::Locale, DateTime::TimeZone, Data::Dumper,"
echo " - Digest::MD5, Digest::SHA, Encode::Detect, File::Basename,"
echo " - File::Path, Net::SSLeay, Time::HiRes, Time::Local, Time::Piece,"
echo " - JSON::XS, lib, open"
echo " - Sys::Syslog, JSON::XS, lib, open"
echo " Packages:"
echo " - openssl - Cryptography library with TLS implementation"
echo " - shared-mime-info - Shared MIME information database"

View File

@@ -7581,14 +7581,8 @@ if ($opened) {
close $fh or return "Error: close($file): $!";
}
# Optionally print to UI (web scripts only)
if ($main::webmin_script_type eq 'web') {
# Print HTTP header once per process
our $var_dump__hdr_sent ||= 0;
if (!$var_dump__hdr_sent && !$main::done_webmin_header) {
print "Content-type: text/html; charset=UTF-8\n\n";
$var_dump__hdr_sent = 1;
}
# Optionally print to UI (web scripts only) only if header already sent
if ($main::done_webmin_header && $main::webmin_script_type eq 'web') {
# Limit long dumps by wrapping parameter chunks between accordion lines
my $out = $dump_txt;
# Add header
@@ -13261,11 +13255,11 @@ if (!$def && $gconfig{'webmin_email_url'}) {
# From a config option
$url = $gconfig{'webmin_email_url'};
}
elsif ($ENV{'HTTP_HOST'} || $ENV{'SSL_HOST'}) {
elsif ($ENV{'HTTP_HOST'} || $ENV{'SSL_CN'}) {
# From this HTTP request
my $port = $ENV{'SERVER_PORT'} || 80;
my $host = $ENV{'SSL_HOST'}
? "$ENV{'SSL_HOST'}:$port"
my $host = $ENV{'SSL_CN'}
? "$ENV{'SSL_CN'}:$port"
: $ENV{'HTTP_HOST'};
if ($host =~ s/:(\d+)$//) {
$port = $1;