Compare commits

..

12 Commits

Author SHA1 Message Date
77ca17c851 * Mon Mar 17 2025 Brian Read <brianr@koozali.org> 11.0.0-69.sme
- Add a total summary report across all existing logs [SME: 12951]
2025-03-17 15:27:16 +00:00
535d78eacb * Mon Mar 17 2025 Brian Read <brianr@koozali.org> 11.0.0-68.sme
- re-write qmailanalog for postfix [SME: 12951]
- Clean up backup.pm
- Enhance module panel - used by mail log analysis and Licence display
2025-03-17 12:22:38 +00:00
88ee369253 * Mon Mar 17 2025 Brian Read <brianr@koozali.org> 11.0.0-67.sme
- re-write qmailanalog for postfix [SME: 12951]
- Clean up backup.pm
- Enhance module panel - used by mail log analysis and Licence display
2025-03-17 12:20:55 +00:00
5be2152e89 * Mon Mar 17 2025 Brian Read <brianr@koozali.org> 11.0.0-67.sme
- re-write qmailanalog for postfix [SME: 12951]
- Clean up backup.pm
- Enhance module panel - used by mail log analysis and Licence display
2025-03-17 12:08:40 +00:00
63973f2bb4 * Tue Mar 11 2025 Brian Read <brianr@koozali.org> 11.0.0-66.sme
- Move the button for each backup panel to the left to conform to all the other panels.
2025-03-11 17:37:44 +00:00
82ff48e641 * Sun Mar 09 2025 Brian Read <brianr@koozali.org> 11.0.0-65.sme
- Sort out missing hostname on nfs and cifs workstation backup on error [SME: 12948]
2025-03-09 15:38:39 +00:00
c5d863b3a0 * Sat Mar 08 2025 Brian Read <brianr@koozali.org> 11.0.0-64.sme
- Add code to check for boot phase completion [SME: 12953]
2025-03-08 10:45:00 +00:00
4f00dfbdb1 * Thu Mar 06 2025 Brian Read <brianr@koozali.org> 11.0.0-63.sme
- Add boot.svg image to Bug Report panel [SME: 12953]
- Move report template to inside smanager tree
- Add one-off systemd task to create boot.svg run from panel
2025-03-07 15:41:55 +00:00
f9bf8cf064 refine spec comment 2025-03-04 14:36:14 +00:00
4f0617f6c3 * Tue Mar 04 2025 Brian Read <brianr@koozali.org> 11.0.0-62.sme
- Update .lex files to conform to standard english punctuation  [SME: 11809]
2025-03-04 14:18:38 +00:00
4c94d768e2 * Tue Mar 04 2025 Brian Read <brianr@koozali.org> 11.0.0-61.sme
- Arrange for the version in the footer to be suppressed if non admin login  [SME: 12887]
2025-03-04 10:11:38 +00:00
1731f75cba * Thu Feb 27 2025 Brian Read <brianr@koozali.org> 11.0.0-60.sme
- Enhance ssh security wording to mention autoblock in remoteaccess panel  [SME: 8309]
2025-02-27 15:54:27 +00:00
34 changed files with 691 additions and 147 deletions

View File

@@ -0,0 +1,9 @@
[Unit]
Description=Koozali SME Server boot diagnostic tool
After=sme-server.target
PartOf=sme-server.target
[Service]
Type=oneshot
ExecStart=/bin/sh -c "/usr/bin/systemd-analyze plot > /usr/share/smanager/themes/default/public/images/boot.svg"
RemainAfterExit=yes

View File

@@ -32,6 +32,10 @@ use esmith::util;
use esmith::lockfile;
use esmith::BlockDevices;
use constant DEBUG => $ENV{MOJO_SMANAGER_DEBUG} || 0;
use constant FALSE => 0;
use constant TRUE => 1;
#our $cdb = esmith::ConfigDB->open || die "Couldn't open config db"; #remove as cached gives problems
#our $adb = esmith::AccountsDB->open || die "Couldn't open accounts db";
#our $rdb = esmith::ConfigDB->open('/etc/e-smith/restore') || die "Couldn't open restore db";
@@ -526,13 +530,13 @@ sub do_update {
# common part for all functions
if ($res ne 'OK') {
if ($res eq 'NEXT') {
$dest = 'back_' . $bac_datas{"function"};
} else {
$c->stash(error => $result);
$dest = "back_$function";
}
$bac_datas{vfstype} = $c->param('VFSType');
$c->stash(title => $title, bac_datas => \%bac_datas);
return $c->render($dest);
} ## end if ($res ne 'OK')
@@ -932,7 +936,7 @@ sub workstnVerify {
sub workstnRestore {
my ($c) = @_;
my $out;
my $out = '';
my $restoreref = $c->param('Backupset');
my $set = $restoreref;
$set =~ s/\/[^\/]*$//;
@@ -1015,6 +1019,7 @@ sub workstnRestore {
return "$c->l('bac_OPERATION_STATUS_REPORT') $c->l('bac_ERR_PRE_RESTORE')";
}
$| = 1;
my $RD;
if (open(RD, "-|")) {
@@ -1047,8 +1052,8 @@ sub workstnRestore {
or warn($c->l('bac_ERR_RESTORING_INITIAL_GRP') . "\n");
esmith::util::backgroundCommand(0, "/sbin/e-smith/signal-event", "post-upgrade");
# system("/sbin/e-smith/signal-event", "post-upgrade") == 0
# or die ($c->l('bac_ERROR_UPDATING_CONFIGURATION')."\n");
#system("/sbin/e-smith/signal-event", "post-upgrade") == 0
# or die ($c->l('bac_ERROR_UPDATING_CONFIGURATION')."\n");
} else {
$message = $c->l('bac_RESTORE_FAILED');
}
@@ -1076,9 +1081,111 @@ sub workstnRestore {
die($error_message) if $error_message;
exit(0);
} ## end else [ if (open(RD, "-|")) ]
$rdb->reload;
$error_message .= $c->bunmount($mntdir, $VFSType);
return '#OK#' . $out;
#my $RD;
## Fork-safe open with explicit error handling
#unless (open($RD, "-|")) {
## Child process
#local $SIG{__DIE__} = sub { exit 255 };
#$| = 1; # Autoflush
#eval {
#foreach my $file (@restorefiles) {
## Security: strict filename validation
#unless ($file =~ m{^[\w\/.-]+$}) {
#die "Invalid filename: $file";
#}
## Check file existence
#unless (-e $file) {
#die "Backup file $file does not exist";
#}
## Execute dar with error checking
#system("/usr/bin/dar", "-Q", "-x", $file, "-v", "-N", "-R", "/", "-wa");
#if ($? == -1) {
#die "Failed to execute dar: $!";
#} elsif ($? & 127) {
#die sprintf("dar died with signal %d, %s coredump",
#($? & 127), ($? & 128) ? 'with' : 'without');
#} elsif ($? >> 8 != 0) {
#die "dar exited with error code " . ($? >> 8);
#}
#}
## Unmount with error checking
#if (my $unmount_err = $c->bunmount($mntdir, $VFSType)) {
#die "Unmount failed: $unmount_err";
#}
#};
#if (my $child_err = $@) {
#print STDERR "CHILD ERROR: $child_err";
#exit 254;
#}
#exit 0;
#}
#else {
## Parent process
#eval {
## Verify fork succeeded
#unless (defined $RD) {
#die "Fork failed: $!";
#}
#$out .= $c->l('bac_FILES_HAVE_BEEN_RESTORED') . "\n<UL>";
#my $complete = 0;
## Read from child process
#while (<$RD>) {
#$complete++ if /etc\/samba\/smbpasswd$/;
#$out .= "<li>$_</li>\n";
#}
#$out .= "</UL>";
## Close pipe and check status
#unless (close $RD) {
#die "Pipe close failed: $!";
#}
#my $child_status = $?;
#if ($child_status != 0) {
#die "Child process failed with status " . ($child_status >> 8);
#}
## Post-restore actions
#if ($complete) {
#system("/usr/sbin/groupmod", "-g", $www_gid, "www");
#if ($? != 0) {
#die $c->l('bac_ERR_RESTORING_GID') . ": $! (status $?)";
#}
#system("/usr/sbin/usermod", "-g", $www_gid, "www");
#if ($? != 0) {
#die $c->l('bac_ERR_RESTORING_INITIAL_GRP') . ": $! (status $?)";
#}
#my $bg_result = esmith::util::backgroundCommand(0, "/sbin/e-smith/signal-event", "post-upgrade");
#unless ($bg_result) {
#die "Failed to schedule post-upgrade event";
#}
#} else {
#die $c->l('bac_RESTORE_FAILED');
#}
#};
## Error handling
#if (my $err = $@) {
#$rec->set_prop('state', 'failed');
#$rec->set_prop('error', "$err");
#esmith::lockfile::UnlockFile($file_handle);
#return $c->l('bac_RESTORE_FAILED_MSG') . ": $err";
#}
#}
$rdb->reload;
$error_message .= $c->bunmount($mntdir, $VFSType);
return '#OK#' . $out;
} ## end sub workstnRestore
sub workstnSelRestore() {
@@ -1455,6 +1562,7 @@ sub performReboot {
#print "$c->l('bac_SERVER_REBOOT')";
#print "$c->l('bac_SERVER_WILL_REBOOT')";
warn "reboot coming";
esmith::util::backgroundCommand(2, "/sbin/e-smith/signal-event", "reboot");
return "#OK#" . $c->l('bac_SERVER_WILL_REBOOT');
} ## end sub performReboot
@@ -1985,7 +2093,7 @@ sub bunmount {
system('/bin/umount', '-f', $mount) == 0
or return ($c->l('bac_ERR_WHILE_UNMOUNTING'));
}
return;
return "";
} ## end sub bunmount
sub findmnt {

View File

@@ -17,6 +17,9 @@ use File::Basename;
use SrvMngr qw( gen_locale_date_string );
our $cdb = esmith::ConfigDB->open or die "Couldn't open ConfigDB\n";
use constant FALSE => 0;
use constant TRUE => 1;
# Get some basic info on the current SME install
our $sysconfig = $cdb->get('sysconfig');
our $systemmode = $cdb->get('SystemMode')->value;
@@ -78,7 +81,7 @@ sub create_configuration_report {
# create the reporting template
my $configreport_template = Text::Template->new(
TYPE => 'FILE',
SOURCE => '/etc/e-smith/web/common/configuration_report.tmpl',
SOURCE => '/usr/share/smanager/themes/default/public/configuration_report.tmpl',
UNTAINT => 1
);
my $report_creation_time = gen_locale_date_string;
@@ -114,13 +117,40 @@ sub create_configuration_report {
# prcess template
my $result = $configreport_template->fill_in(HASH => \%vars);
#take out any multiple blank lines
#$result =~ s/\n{3,}/\n/g;
# write processed template to file
open(my $cfgrep, '>', $configreportfile) or die "Could not create temporary file for config report!";
print $cfgrep $result;
close $cfgrep;
#check if boot phase has completed.
if (wait_for_boot_completion()) {
#And create boot analysis image - now run externally following boot.
$result = `/usr/bin/systemctl start bootsequence.service`;
if (!$? == 0) {
warn "/usr/bin/systemd-analyze plot Command failed \n";
}
}
} ## end sub create_configuration_report
sub wait_for_boot_completion {
my $timeout = 60; # 1-minute timeout
my $end_time = time() + $timeout;
while (time() < $end_time) {
if (`systemctl list-jobs 2>&1` =~ /No jobs running/) {
return TRUE; # Success
}
sleep 5;
}
warn "Boot did not complete within $timeout seconds.\n";
return FALSE; # Failure
} ## end wait_for_boot_completion
sub show_config_report {
my $c = shift;
my $out = '';
@@ -143,4 +173,4 @@ sub download_config_report {
'cleanup' => 1,
);
} ## end sub download_config_report
1;
1;

View File

@@ -14,6 +14,9 @@ use SrvMngr qw(gen_locale_date_string);
use Locale::gettext;
use SrvMngr::I18N;
use SrvMngr qw(theme_list init_session);
use List::Util qw(sum);
#use Mail::Log::Trace::Postfix;
sub main {
my $c = shift;
@@ -48,44 +51,66 @@ sub generateReport {
my $c = shift;
my $report_type = shift;
my $out = '';
#------------------------------------------------------------
# Looks good; go ahead and generate the report.
# Go ahead and generate the report.
#------------------------------------------------------------
# $| = 1;
my $now_string = $c->gen_locale_date_string();
my $log_path = '/var/log/maillog';
$out .= sprintf("<h3>%s %s </h3>", $c->l('REPORT_GENERATED'), $now_string);
if ($report_type =~ /^qmail-q/) {
open(QMAILQUEUEREPORT, "/var/qmail/bin/$report_type |");
$out .= sprintf "<pre>";
while (<QMAILQUEUEREPORT>) {
$out .= sprintf("%s", $_);
}
close QMAILQUEUEREPORT;
$out .= sprintf "</pre>";
$out .= sprintf("<h3>%s</h3>", $c->l('END_OF_REPORT'));
return '';
} ## end if ($report_type =~ /^qmail-q/)
chdir "/var/log/qmail";
open(QMAILANALOG,
"/bin/cat \@* current 2>/dev/null"
. "| /usr/local/bin/tai64nunix"
. "| /usr/local/qmailanalog/bin/matchup 5>/dev/null"
. "| /usr/local/qmailanalog/bin/$report_type |");
$out .= sprintf "<pre>";
# Get the selected report from the form submission
my $selected_report = $report_type;
while (<QMAILANALOG>) {
# Call the relevant report sub based on the selection
if ($selected_report eq 'daily_summary') {
$out .= daily_summary_report($log_path);
}
elsif ($selected_report eq 'daily_summary_today') {
$out .= daily_summary_report_today($log_path);
}
elsif ($selected_report eq 'daily_summary_all') {
$out .= daily_summary_report_all($log_path);
}
elsif ($selected_report eq 'top_senders') {
$out .= top_senders_and_recipients($log_path);
}
elsif ($selected_report eq 'bounce_analysis') {
$out .= bounce_rate_analysis($log_path);
}
elsif ($selected_report eq 'spam_and_virus') {
$out .= spam_and_virus_filter_report($log_path);
}
elsif ($selected_report eq 'delivery_status') {
$out .= delivery_status_report($log_path);
}
elsif ($selected_report eq 'geo_analysis') {
$out .= geographical_analysis_of_email($log_path);
}
elsif ($selected_report eq 'traffic_analysis') {
$out .= traffic_analysis($log_path);
}
elsif ($selected_report eq 'auth_analysis') {
$out .= authentication_analysis($log_path);
}
elsif ($selected_report eq 'user_activity') {
$out .= user_activity_report($log_path);
}
elsif ($selected_report eq 'error_reporting') {
$out .= error_reporting($log_path);
}
elsif ($selected_report eq 'comparison_reports') {
$out .= comparison_reports($log_path, '/var/log/mail.log.1');
}
elsif ($selected_report eq 'customized_reports') {
$out .= customized_reports($log_path);
}
else {
$out .= 'Invalid report selected';
}
# Cook any special HTML characters
s/\&/\&amp;/g;
s/\"/\&quot;/g;
s/\>/\&gt;/g;
s/\</\&lt;/g;
$out .= sprintf("%s", $_);
} ## end while (<QMAILANALOG>)
close QMAILANALOG;
# The $output variable now contains the generated report output.
# Further processing can be done here, or you can render it later.
$out .= sprintf "</pre>";
$out .= sprintf("<h3>%s</h3>", $c->l('END_OF_REPORT'));
return $out;
@@ -94,22 +119,243 @@ sub generateReport {
sub reportType_list {
my $c = shift;
my @array = (
# [ $c->l('qma_LIST_OUTGOING') => 'qmail-qread' ],
# [ $c->l('qma_SUMMARIZE_QUEUE') => 'qmail-qstat' ],
[ $c->l('qma_SUCCESSFUL_DELIVERY_DELAY') => 'zddist' ],
[ $c->l('qma_REASONS_DEFERRAL') => 'zdeferrals' ],
[ $c->l('qma_REASONS_FAILURE') => 'zfailures' ],
[ $c->l('qma_BASIC_STATS') => 'zoverall' ],
[ $c->l('qma_RECIP_STATS') => 'zrecipients' ],
[ $c->l('qma_RECIP_HOSTS') => 'zrhosts' ],
[ $c->l('qma_RECIP_ORDERED') => 'zrxdelay' ],
[ $c->l('qma_SENDER_STATS') => 'zsenders' ],
[ $c->l('qma_SENDMAIL_STYLE') => 'zsendmail' ],
[ $c->l('qma_REASONS_SUCCESS') => 'zsuccesses' ],
[ $c->l('qma_SENDER_UIDS') => 'zsuids' ]
);
[$c->l('qma_Daily_Summary_Report_yesterday') => 'daily_summary'],
[$c->l('qma_Daily_Summary_Report_today') => 'daily_summary_today'],
[$c->l('qma_Daily_Summary_Report_all') => 'daily_summary_all'],
#[$c->l('qma_Top Senders and Recipients') => 'top_senders'],
#[$c->l('qma_Bounce Rate Analysis') => 'bounce_analysis'],
#[$c->l('qma_Spam and Virus Filtering Report') => 'spam_and_virus'],
#[$c->l('qma_Delivery Status Report') => 'delivery_status'],
#[$c->l('qma_Geographic Analysis of Email') => 'geo_analysis'],
#[$c->l('qma_Traffic Analysis') => 'traffic_analysis'],
#[$c->l('qma_Authentication Analysis') => 'auth_analysis'],
#[$c->l('qma_User Activity Report') => 'user_activity'],
#[$c->l('qma_Error Reporting') => 'error_reporting'],
#[$c->l('qma_Comparison Reports') => 'comparison_reports'],
#[$c->l('qma_Customized Reports') => 'customized_reports'],
);
my @sorted_array = sort { $a->[0] cmp $b->[0] } @array;
return \@sorted_array;
} ## end sub reportType_list
1;
sub daily_summary_report {
my $log_file = shift; # Path to log file
my $output = qx(ls -1 /var/log/maillog* | xargs cat |pflogsumm -d yesterday --detail 0 --no-no-msg-size);
return format_as_html("Daily Summary Report", $output);
}
sub daily_summary_report_today {
my $log_file = shift; # Path to log file
my $output = qx(ls -1 /var/log/maillog* | xargs cat |pflogsumm -d today --detail 0 --no-no-msg-size);
return format_as_html("Daily Summary Report", $output);
}
sub daily_summary_report_all {
my $log_file = shift; # Path to log file
my $output = qx(ls -1 /var/log/maillog* | xargs cat |pflogsumm --detail 0 --no-no-msg-size);
return format_as_html("Summary Report across all logs", $output);
}
sub top_senders_and_recipients {
my $log_file = shift;
my $output = qx(pflogsumm --smtpd-stats $log_file);
return format_as_html("Top Senders and Recipients", $output);
}
sub bounce_rate_analysis {
my $log_file = shift;
my $output = qx(pflogsumm --bounce-detail 10 $log_file); # Show up to 10 bounce details
return format_as_html("Bounce Rate Analysis", $output);
}
sub spam_and_virus_filter_report {
my $log_file = shift;
my $output = qx(pflogsumm -u 10 $log_file); # User report with up to 10 entries
return format_as_html("Spam and Virus Filtering Report", $output);
}
sub delivery_status_report {
my $log_file = shift;
my $output = qx(pflogsumm --deferral-detail 10 $log_file); # Show deferral details
return format_as_html("Delivery Status Report", $output);
}
sub geographical_analysis_of_email {
my $log_file = shift;
# `pflogsumm` doesn't have a specific option for geographic analysis in the help text;
# It's assumed this could be replaced with something relevant, like a SMTP detail.
my $output = qx(pflogsumm --smtp-detail 10 $log_file); # Show up to 10 SMTP details
return format_as_html("Geographic Analysis of Email", $output);
}
sub traffic_analysis {
my $log_file = shift;
my $output = qx(pflogsumm --verbose-msg-detail $log_file); # Request verbose detail
return format_as_html("Traffic Analysis", $output);
}
sub authentication_analysis {
my $log_file = shift;
my $output = qx(pflogsumm -u 10 --verbose-msg-detail $log_file); # User detailed report
return format_as_html("Authentication Analysis", $output);
}
sub user_activity_report {
my $log_file = shift;
my $output = qx(pflogsumm -u 20 $log_file); # Show user activity for up to 20 users
return format_as_html("User Activity Report", $output);
}
sub error_reporting {
my $log_file = shift;
my $output = qx(pflogsumm --problems-first $log_file); # This will show problems first
return format_as_html("Error Reporting", $output);
}
sub comparison_reports {
my ($log_file1, $log_file2) = @_; # Comparing two log files
my $output = qx(pflogsumm $log_file1 $log_file2); # Standard comparison without special flags
return format_as_html("Comparison Reports", $output);
}
sub customized_reports {
my $log_file = shift;
# Because we don't have a concrete custom flag, we'll consider using -d with specific detail.
my $output = qx(pflogsumm --detail 10 $log_file); # Generally show detailed summary
return format_as_html("Customized Reports", $output);
}
sub format_as_html {
my ($title, $content) = @_;
return <<HTML;
<h2>$title</h2>
<pre>$content</pre>
HTML
}
### 1. Message Tracking
#sub trace_message {
#my ($log_path, $message_id) = @_;
##my $tracer = Mail::Log::Trace::Postfix->new({log_file => $log_path});
##$tracer->set_message_id($message_id);
#my $output = "Message Tracking Report for ID: $message_id\n";
##$output .= "=" x 50 . "\n";
##$output .= sprintf "%-12s: %s\n", 'From', $tracer->get_from_address;
##$output .= sprintf "%-12s: %s\n", 'Status', $tracer->get_final_status;
##$output .= "\nRecipients:\n";
##$output .= join("\n", map { "- $_" } $tracer->get_recipient_addresses);
##$output .= "\n\nTimeline:\n";
##my $timeline = $tracer->get_timestamps;
##while (my ($stage, $time) = each %$timeline) {
##$output .= sprintf "%-10s: %s\n", ucfirst($stage), $time;
##}
#return $output || "No records found for message ID: $message_id";
#}
#### 2. Queue Analysis
#sub get_queue_stats {
#my $spool_dir = '/var/spool/postfix';
#my %queues = map { $_ => 0 } qw(active deferred bounce hold corrupt);
#foreach my $q (keys %queues) {
#opendir(my $dh, "$spool_dir/$q");
#$queues{$q} = scalar(grep { -f "$spool_dir/$q/$_" } readdir($dh));
#closedir($dh);
#}
#my $output = "Current Postfix Queue Status\n";
#$output .= "=" x 30 . "\n";
#$output .= sprintf "%-10s: %3d messages\n", ucfirst($_), $queues{$_}
#for sort keys %queues;
#$output .= "\nTotal: " . sum(values %queues) . " messages in queue";
#return $output;
#}
#### 3. Message Statistics
#sub get_message_stats {
#my ($log_path) = @_;
#my %stats = (received => 0, rejected => 0, delivered => 0,
#deferred => 0, bounced => 0, held => 0);
#open(my $fh, '<', $log_path);
#while(<$fh>) {
#$stats{received}++ if /qmgr.*: [A-Z0-9]+: from=/;
#$stats{delivered}++ if /status=sent/;
#$stats{rejected}++ if /NOQUEUE: reject/;
#$stats{deferred}++ if /status=deferred/;
#$stats{bounced}++ if /status=bounced/;
#$stats{held}++ if /status=hold/;
#}
#close($fh);
#my $output = "Message Statistics for " . localtime . "\n";
#$output .= "=" x 40 . "\n";
#$output .= sprintf "%-12s: %6d\n", 'Received', $stats{received};
#$output .= sprintf "%-12s: %6d (%.1f%%)\n", 'Delivered', $stats{delivered},
#($stats{received} ? ($stats{delivered}/$stats{received}*100) : 0);
#$output .= sprintf "%-12s: %6d\n", 'Rejected', $stats{rejected};
#$output .= sprintf "%-12s: %6d\n", 'Deferred', $stats{deferred};
#$output .= sprintf "%-12s: %6d\n", 'Bounced', $stats{bounced};
#$output .= sprintf "%-12s: %6d\n", 'Held', $stats{held};
#return $output;
#}
#### 4. User Activity Audit
#sub get_user_activity {
#my ($log_path, $email) = @_;
##my $tracer = Mail::Log::Trace::Postfix->new({log_file => $log_path});
##my $sent = scalar $tracer->find_messages_by_sender($email);
##my $received = scalar $tracer->find_messages_by_recipient($email);
#my $output = "Activity Report for: $email\n";
##$output .= "=" x (length($email) + 18) . "\n";
##$output .= "Messages sent: $sent\n";
##$output .= "Messages received: $received\n\n";
##$output .= "Last week's activity:\n";
##$output .= join("\n", map { sprintf "- %s: %d messages", $_->[0], $_->[1] }
##$tracer->get_weekly_stats($email));
#return $output || "No activity found for $email";
#}
#### 5. Security Monitoring
#sub detect_auth_failures {
#my ($log_path) = @_;
#my %failures;
#open(my $fh, '<', $log_path);
#while(<$fh>) {
#if(/SASL (?:LOGIN|PLAIN) authentication failed.*?\[([0-9.]+)\]/) {
#$failures{$1}++;
#}
#}
#close($fh);
#return "No authentication failures found" unless keys %failures;
#my $output = "Authentication Failure Report\n";
#$output .= "=" x 30 . "\n";
#$output .= sprintf "%-15s %s\n", 'IP Address', 'Attempts';
#$output .= sprintf "%-15s %s\n", '-' x 15, '-' x 7;
#foreach my $ip (sort { $failures{$b} <=> $failures{$a} } keys %failures) {
#$output .= sprintf "%-15s %5d\n", $ip, $failures{$ip};
#}
#$output .= "\nTotal failures: " . sum(values %failures);
#return $output;
#}
1;

View File

@@ -2,7 +2,7 @@
'clm_LABEL_FILESYSTEM_SCAN_PERIOD' => 'Scan filesystem',
'clm_DESC_FILESYSTEM_SCAN_PERIOD' => '<h2>General Settings</h2>
If this option is enabled then the filesystem will be
scanned for viruses.A report of any found viruses will be
scanned for viruses. A report of any found viruses will be
emailed to the administrator.',
'clm_LABEL_QUARANTINE' => 'Quarantine infected files',
'clm_LABEL_CLAM_VERSIONS' => 'ClamAV and db versions',

View File

@@ -14,26 +14,26 @@ web site for that domain.',
i-bay as the content.',
'dom_DOMAIN_NAME_VALIDATION_ERROR' => 'Error: unexpected or missing characters in domain name
[_1].The domain name should contain one or more
letters, numbers, periods and minus signs.Did not create new domain.',
letters, numbers, periods and minus signs. Did not create new domain.',
'dom_DOMAIN_DESCRIPTION_VALIDATION_ERROR' => 'Error: unexpected or missing characters in domain description
[_1]. Did not create new domain.',
'dom_DOMAIN_IN_USE_ERROR' => 'Error: domain [_1] is already in use.Did not create
'dom_DOMAIN_IN_USE_ERROR' => 'Error: domain [_1] is already in use. Did not create
new domain.',
'dom_SYSTEM_DOMAIN_ERROR' => 'Error: domain [_1] is your system domain name.You
cannot have a domain with the same name.Did not create new domain.',
'dom_SYSTEM_DOMAIN_ERROR' => 'Error: domain [_1] is your system domain name. You
cannot have a domain with the same name. Did not create new domain.',
'dom_SUCCESSFULLY_CREATED' => 'Successfully created domain [_1].Your web
server is now being restarted.The links on this page will be
server is now being restarted. The links on this page will be
inactive until the web server restart is complete.',
'dom_MODIFY_TITLE' => 'Modify domain',
'dom_NONEXISTENT_DOMAIN_ERROR' => 'Error: [_1] is not an existing domain.',
'dom_SUCCESSFULLY_MODIFIED' => 'Successfully modified domain [_1].Your web
server is now being restarted.The links on this page will be inactive until the web server restart is complete.',
server is now being restarted. The links on this page will be inactive until the web server restart is complete.',
'dom_REMOVE_TITLE' => 'Remove domain',
'dom_REMOVE_DESCRIPTION' => 'You are about to remove the domain "[_1]" ([_2]).',
'dom_ABOUT_TO_REMOVE' => 'Are you sure you wish to remove this domain ?',
'dom_ERROR_WHILE_REMOVING_DOMAIN' => 'Error: internal failure while removing domain [_1].',
'dom_SUCCESSFULLY_DELETED' => 'Successfully deleted domain [_1]. Your web server
is now being restarted.The links on this page will be inactive
is now being restarted. The links on this page will be inactive
until the web server restart is complete.',
'dom_DESC_CORPORATE_DNS_CURRENT' => 'Corporate DNS Settings',
'dom_DOMAINS_PAGE_CORPORATE_DNS' => 'Modify corporate DNS settings',

View File

@@ -128,7 +128,7 @@
'FM_IP_NUMBER3' => '[_1] is more than 255',
'FM_USERNAME' => 'This field must look like a valid username (3 to 8 letters and numbers)',
'FM_PASSWORD1' => 'You must provide a password.',
'FM_PASSWORD2' => 'The password you provided was not a good password.A good password must contain all of the following: upper case letter, lower case letter, number, non-alphanumeric character, be at least 7 characters long.',
'FM_PASSWORD2' => 'The password you provided was not a good password. A good password must contain all of the following: upper case letter, lower case letter, number, non-alphanumeric character, be at least 7 characters long.',
'FM_MAC_ADDRESS1' => 'You must provide a MAC address.',
'FM_MAC_ADDRESS2' => 'The MAC address you provided was not valid.',
'FM_ERR_UNEXPECTED_DESC' => 'Error: unexpected or missing characters in description',
@@ -151,4 +151,5 @@ SMALL => 'Small',
MEDIUM => 'Medium',
LARGE => 'Large',
FIELD_INVALID_CHARS => 'A field you entered contains invalid characters.',
'REPORT_GENERATED' => "Report generated",
'END_OF_REPORT' => 'End of Report',

View File

@@ -4,7 +4,7 @@
'grp_ACCOUNT_CONFLICT' => 'Error: the group "[_1]" can\'t be created because there is
already a [_2] account of that name.',
'grp_INVALID_GROUP_DESCRIPTION' => 'Error: unexpected or missing characters in group description',
'grp_NO_MEMBERS' => 'Error: no members in group.Did not create new group.',
'grp_NO_MEMBERS' => 'Error: no members in group. Did not create new group.',
'grp_CREATED_GROUP' => 'Successfully created user group',
'grp_DELETED_GROUP' => 'Successfully removed user group',
'grp_MODIFIED_GROUP' => 'Successfully modifed user group',

View File

@@ -34,17 +34,17 @@ the local network. Please enter a valid IP address in the
format "aaa.bbb.ccc.ddd".',
'hos_ETHERNET_ADDRESS_DESCRIPTION' => 'The ethernet address is optional and causes the DHCP server to
statically bind the local IP address to the computer with this
ethernet address.If specified, it must be of the form
ethernet address. If specified, it must be of the form
"AA:BB:CC:DD:EE:FF" and must contain only the numbers 0-9 and
the letters A-F.',
'hos_CREATE_LOCAL_HOST_TITLE' => 'Create a new hostname referring to a local host.',
'hos_DIDNT_ENTER_LOCAL_IP' => 'Error: You did not specify a Local IP address.IP
'hos_DIDNT_ENTER_LOCAL_IP' => 'Error: You did not specify a Local IP address. IP
addresses must contain only numbers and periods and
be in the form "aaa.bbb.ccc.ddd".Did not create hostname.',
'hos_IP_VALIDATION_ERROR' => 'Error: IP Address [_1] is
invalid. IP Addresses must contain only numbers and periodsand be in the form "aaa.bbb.ccc.ddd". Did not create hostname.',
'hos_MAC_ADDRESS_VALIDATION_ERROR' => 'Error: Ethernet address [_1]
is invalid.Ethernet addresses must be in the
is invalid. Ethernet addresses must be in the
form "AA:BB:CC:DD:EE:FF" and only contain the
numbers 0-9 and the letters A-F. Did not create
hostname.',

View File

@@ -14,7 +14,7 @@ For example, you may wish to create a pseudonym
"webmaster" for your "webdevelopers" group or a
pseudonym "joe" for the user "joseph".</p>
<p>The server automatically creates pseudonyms of the form
firstname.lastname and firstname_lastname for every user
firstname. lastname and firstname_lastname for every user
on the system and a pseudonym "everyone" which contains
all users on the system.</p>
<p>Pseudonyms also allow you to create e-mail aliases for valid

View File

@@ -8,6 +8,15 @@ reports are available.</P>
these reports</P>',
'qma_REPORT_TYPE' => 'Choose a report type',
'qma_GENERATE_REPORT' => 'Generate report',
'qma_INVALID_REPORT_TYPE' => 'Invalid report type: ',
'qma_REPORT_GENERATED' => 'Report generated: ',
'qma_END_OF_REPORT' => 'End of Report',
'Mail log file analysis' => 'Mail log file analysis',
'qma_Daily_Summary_Report_yesterday' => 'Summary report for yesterday',
'qma_Daily_Summary_Report_today' => 'Summary report for today up to now',
'qma_Daily_Summary_Report_all' => 'Summary report for all time up to now',
'qma_LIST_OUTGOING' => 'List outgoing messages and recipients',
'qma_SUMMARIZE_QUEUE' => 'Summarize status of mail queue',
'qma_SUCCESSFUL_DELIVERY_DELAY' => 'Successful delivery delay distribution',
@@ -20,9 +29,4 @@ these reports</P>',
'qma_SENDER_STATS' => 'Sender statistics',
'qma_SENDMAIL_STYLE' => 'Sendmail style log',
'qma_REASONS_SUCCESS' => 'Reasons for success',
'qma_SENDER_UIDS' => 'Sender uids',
'qma_INVALID_REPORT_TYPE' => 'Invalid report type: ',
'qma_REPORT_GENERATED' => 'Report generated: ',
'qma_END_OF_REPORT' => 'End of Report',
'Mail log file analysis' => 'Mail log file analysis',
'qma_SENDER_UIDS' => 'Sender uids',

View File

@@ -26,7 +26,9 @@ experienced administrators
for remote problem diagnosis and resolution.
We recommend leaving this
parameter set to "No Access"
unless you have a specific reason to do otherwise.',
unless you have a specific reason to do otherwise.
Note that an "Autoblock" feature is enabled by default when public access is enabled; to disable or tune this feature, refer to the manual at https://wiki.koozali.org/AutoBlock
',
'rma_TITLE_FTP_ACCESS' => 'FTP Settings',
'rma_DESC_FTP_ACCESS' => 'You can also control <b>FTP</b> access to your server. We
recommend leaving this parameter set to \'no access\' unless you
@@ -75,11 +77,11 @@ connected to a server serial port.',
'rma_LABEL_PPTP_ACCESS' => 'PPTP default user access',
'rma_TITLE_TELNET_ACCESS' => 'Telnet Settings',
'rma_DESC_TELNET_ACCESS' => 'WARNING:Telnet is currently enabled, but this feature is
no longer supported.Telnet is inherently insecure and should only
no longer supported. Telnet is inherently insecure and should only
be used in circumstances where no practical alternative exists. You
should change option to [_1] and use
secure shell if remote access is
required.Once disabled, telnet will no longer appear on this
required. Once disabled, telnet will no longer appear on this
screen. ',
'rma_TITLE_IPSECRW' => 'IPSEC Client (Roadwarrior) Settings',
'rma_DESC_IPSECRW' => 'You can allow IPSEC client access to your server, authenticated by
@@ -90,4 +92,4 @@ to the number 0 unless you require IPSEC client access.',
can do so here.<br>Any old certificates will no longer
authenticate against the server, so <b><i>all IPSEC clients will
need to import a new certificate!</i></b>.',
'rma_LABEL_IPSECRW_RESET' => 'Reset digital certificates',
'rma_LABEL_IPSECRW_RESET' => 'Reset digital certificates',

View File

@@ -2,7 +2,7 @@
'rvw_FORM_TITLE' => 'Review configuration',
'rvw_DESCRIPTION' => 'This report summarizes the networking, server, and domain
parameters on this server relevant to configuring
the client computers on your network.You may wish to print this
the client computers on your network. You may wish to print this
page and use it as a reference.',
'rvw_NETWORKING_PARAMS' => 'Networking Parameters',
'rvw_SERVER_MODE' => 'Server Mode',

View File

@@ -4,7 +4,7 @@
by the services running on your server.',
'log_LOG_FILE_SELECT_DESC' => 'Choose a log file to view',
'log_FILTER_PATTERN_DESC' => 'You may optionally specify a filter pattern to display only the
lines from the log file which match this pattern.If you leave
lines from the log file which match this pattern. If you leave
this field blank, all available lines of the log file will be
displayed. Note that this option is not used if you download the
logfile.',

View File

@@ -0,0 +1,38 @@
Configuration report created {$report_creation_time}
==================
Base configuration
==================
SME server version: {$releaseversion}
SME server mode: {$systemmode}
SME server previous mode: {$previoussystemmode }
Running Kernel: {$curkernel}
===========================
New RPMs not in base system
===========================
{ foreach $i (@newrpms) {
$OUT .= "$i";
}
}
===========================
Custom and modified templates
===========================
{ foreach $i (@templates) {
$OUT .= "$i";
}
}
===========================
Modified events
===========================
{ foreach $i (@events) {
$OUT .= "$i";
}
}
=======================
Additional repositories
=======================
{ foreach $r (@repositories) {
$OUT .= "$r";
}
}
DONE!

View File

@@ -0,0 +1,43 @@
/* General styles for the module panel */
#module {
padding: 20px;
border: 1px solid #ccc;
border-radius: 10px;
background-color: #f9f9f9;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
/* Debug information styling */
#module p {
font-family: monospace;
color: #555;
}
#module pre {
background-color: #eee;
padding: 10px;
border-radius: 5px;
}
/* Error message styling */
.sme-error {
color: #d9534f;
font-weight: bold;
margin-bottom: 15px;
}
/* Title styling */
#module h1 {
font-family: Arial, sans-serif;
color: #333;
text-align: center;
margin-bottom: 20px;
}
/* Content styling */
.module-content {
font-family: Georgia, serif;
font-size: 13px;
line-height: 1.2;
color: #555;
}

View File

@@ -0,0 +1,25 @@
document.addEventListener('DOMContentLoaded', function() {
const analysisType = document.getElementById('analysis_type');
const messageIdGroup = document.getElementById('message_id_group');
const emailAddressGroup = document.getElementById('email_address_group');
// Initially hide both controls
messageIdGroup.style.display = 'none';
emailAddressGroup.style.display = 'none';
analysisType.addEventListener('change', function() {
// Hide both controls first
messageIdGroup.style.display = 'none';
emailAddressGroup.style.display = 'none';
// Show the relevant control based on the selected option
switch(this.value) {
case 'trace_message':
messageIdGroup.style.display = 'block';
break;
case 'user_activity':
emailAddressGroup.style.display = 'block';
break;
}
});
});

View File

@@ -74,10 +74,8 @@
</p><br>
%= hidden_field 'Function' => $bac_datas->{'function'}
<div class='center'>
%= submit_button $c->l('bac_UPDATE_CONF'), class => 'action'
</div>
% end
</div>
% end
% end

View File

@@ -30,10 +30,8 @@
%= hidden_field 'Function' => $bac_datas->{'function'}
<div class='center'>
%= submit_button $c->l('bac_RESTORE_FROM_TAPE'), class => 'action'
</div>
% end
</div>
% end
% end

View File

@@ -44,12 +44,10 @@
</span></p>
%= hidden_field 'Function' => $bac_datas->{'function'} . '1'
<div class='center'>
%= submit_button $c->l('NEXT'), class => 'action'
</div>
% end
</div>
% end
% end

View File

@@ -148,9 +148,7 @@
%= hidden_field 'Function' => $bac_datas->{function}
%= hidden_field 'VFSType' => $bac_datas->{vfstype}
<div class='center'>
%= submit_button $c->l('bac_UPDATE_CONF'), class => 'action'
</div>
% end
</div>
% end
% end

View File

@@ -38,9 +38,7 @@
</span><br><br>
%= hidden_field 'Function' => $bac_datas->{'function'}
<div class='center'>
%= submit_button $c->l('bac_RESTORE_FROM_WORKSTN'), class => 'action'
</div>
% end
</div>
% end
% end

View File

@@ -29,9 +29,7 @@
%=l 'bac_YOU_MUST_REBOOT'
</p>
%= hidden_field 'Function' => $bac_datas->{'function'}
<div class='center'>
%= submit_button $c->l('bac_REBOOT'), class => 'action'
</div>
% end
</div>

View File

@@ -39,12 +39,10 @@
</span><br>
<br>
%= hidden_field 'Function' => $bac_datas->{'function'}
<div class='center'>
%= submit_button $c->l('PERFORM'), class => 'action'
</div>
% end
</div>
% end
% end

View File

@@ -41,9 +41,7 @@
%= hidden_field 'Backupset' => $bac_datas->{'backupset'}
%= hidden_field 'Filterexp' => $bac_datas->{'filterexp'}
<div class='center'>
%= submit_button $c->l('PERFORM'), class => 'action'
</div>
% end

View File

@@ -24,9 +24,7 @@
%= form_for '/backupd' => (method => 'POST') => begin
%= hidden_field 'Function' => $bac_datas->{'function'}
<div class='center'>
%= submit_button $c->l('NEXT'), class => 'action'
</div>
% end

View File

@@ -44,10 +44,8 @@
<br><br>
%= hidden_field 'Function' => $bac_datas->{'function'} . '1'
<div class='center'>
%= submit_button $c->l('bac_VERIFY'), class => 'action'
</div>
% end
</div>
% end
% end

View File

@@ -28,10 +28,8 @@
%= hidden_field 'Function' => $bac_datas->{'function'}
<div class='center'>
%= submit_button $c->l('NEXT'), class => 'action'
</div>
% end
</div>
% end
% end

View File

@@ -70,12 +70,10 @@
</span></p>
<br>
<div class='center'>
%= submit_button $c->l('PERFORM'), class => 'action'
</div>
%= submit_button $c->l('PERFORM'), class => 'action'
% end
</div>
% end
% end

View File

@@ -18,9 +18,16 @@
<% my $btn = l('bugr_Download this report'); %>
%= form_for 'bugreportD' => (method => 'POST') => begin
%= submit_button "$btn", class => 'action'
%= hidden_field 'trt' => $bugr_datas->{trt}
% end
%= submit_button "$btn", class => 'action'
%= hidden_field 'trt' => $bugr_datas->{trt}
% end
% my $out = "================== <br />";
% $out .= "Boot anaysis image (right click and save image to download)<br />";
% $out .= "================== <br />";
% $out .= "<img src='images/boot.svg' alt='boot timing image' width=95% >";
<br><%= $c->render_to_string(inline=>$out) %><br>
</div>

View File

@@ -1,20 +1,27 @@
% layout 'default', title => "Sme server 2 - module";
% content_for 'module' => begin
%= stylesheet '/css/module.css'
<div id='module' class='module module-panel'>
% if (config->{debug} == 1) {
<p>
%= dumper $c->current_route
</p>
<p>
<strong>Debug Info:</strong>
<pre><%= dumper $c->current_route %></pre>
</p>
% }
% if ( stash 'error' ) {
<br><div class=sme-error>
%= $c->render_to_string(inline => stash 'error')
</div>
%}
<h1> <%=$title %></h1><br>
%= $c->render_to_string( inline => stash 'modul' )
% if (stash 'error') {
<div class="sme-error">
<strong>Error:</strong><br>
<%= $c->render_to_string(inline => stash 'error') %>
</div>
% }
<h1><%= $title %></h1>
<div class="module-content">
<%= $c->render_to_string(inline => stash 'modul') %>
</div>
</div>
%end
% end

View File

@@ -2,7 +2,7 @@
<HR class="sme-copyrightbar">
<a href="https://mojolicious.org" target="_blank"><img src="images/sme-mojo-logo-white.png" style="position:relative;"></a>
<font class="sme-copyright">
% if ( $c->is_logged_in ) {
% if ( $c->is_logged_in && $c->is_admin) {
SME Server <%= session 'releaseVersion' %>-<%= $c->app->VERSION %> Manager II
% my $mode;
% if (config->{mode} eq 'development'){ $mode = '-dev';} else { $mode = '';}

View File

@@ -1,6 +1,6 @@
% layout 'default', title => "Sme server 2 - qmailanalog";
% content_for 'module' => begin
%= javascript '/js/qmailanalog.js'
<div id='module' class='module qmailanalog-panel'>
%if (config->{debug} == 1) {
<p>
@@ -11,17 +11,34 @@
<br>
<%= $modul %>
<% my $btn = l('qma_GENERATE_REPORT'); %>
%= form_for 'qmailanalog' => (method => 'POST') => begin
<p>
<span class=label>
%=l 'qma_REPORT_TYPE'
</span><span class=data>
<!-- (to be sorted) -->
%= select_field 'report_type' => $c->reportType_list()
</span>
</p>
%= submit_button "$btn", class => 'action'
<p>
<span class=label>
%=l 'qma_REPORT_TYPE'
</span><span class=data>
<!-- (to be sorted) -->
%= select_field 'report_type' => $c->reportType_list(), id => 'analysis_type'
</span>
</p>
<!--And optional parameters, depending on the choice.-->
<div id="message_id_group">
<span class=label>
%= label_for message_id => 'Message ID:'
</span><span class=data>
%= text_field 'message_id', placeholder => 'Enter Postfix Message ID', id => 'message_id_group'
</span>
</div>
<div id="email_address_group">
<span class=label>
%= label_for email_address => 'Email Address:'
</span><span class=data>
%= email_field 'email_address', placeholder => 'Enter email address', id => 'email_address_group'
</span>
</div>
%= submit_button "$btn", class => 'action'
% end
</div>
%end

View File

@@ -2,7 +2,7 @@ Summary: Sme server navigation module : manager 2
%define name smeserver-manager
Name: %{name}
%define version 11.0.0
%define release 59
%define release 69
Version: %{version}
Release: %{release}%{?dist}
License: GPL
@@ -143,6 +143,37 @@ true
%defattr(-,root,root)
%changelog
* Mon Mar 17 2025 Brian Read <brianr@koozali.org> 11.0.0-69.sme
- Add a total summary report across all existing logs [SME: 12951]
* Mon Mar 17 2025 Brian Read <brianr@koozali.org> 11.0.0-68.sme
- re-write qmailanalog for postfix [SME: 12951]
- Clean up backup.pm
- Enhance module panel - used by mail log analysis and Licence display
* Tue Mar 11 2025 Brian Read <brianr@koozali.org> 11.0.0-66.sme
- Move the button for each backup panel to the left to conform to all the other panels.
* Sun Mar 09 2025 Brian Read <brianr@koozali.org> 11.0.0-65.sme
- Sort out missing hostname on nfs and cifs workstation backup on error [SME: 12948]
* Sat Mar 08 2025 Brian Read <brianr@koozali.org> 11.0.0-64.sme
- Add code to check for boot phase completion [SME: 12953]
* Thu Mar 06 2025 Brian Read <brianr@koozali.org> 11.0.0-63.sme
- Add boot.svg image to Bug Report panel [SME: 12953]
- Move report template to inside smanager tree
- Add one-off systemd task to create boot.svg run from panel
* Tue Mar 04 2025 Brian Read <brianr@koozali.org> 11.0.0-62.sme
- Update *_en.lex files to conform to standard english punctuation [SME: 11809]
* Tue Mar 04 2025 Brian Read <brianr@koozali.org> 11.0.0-61.sme
- Arrange for the version in the footer to be suppressed if non admin login [SME: 12887]
* Thu Feb 27 2025 Brian Read <brianr@koozali.org> 11.0.0-60.sme
- Enhance ssh security wording to mention autoblock in remoteaccess panel [SME: 8309]
* Thu Feb 27 2025 Brian Read <brianr@koozali.org> 11.0.0-59.sme
- Arrange for Urgent notice to be displayed if date is past Rocky 8 EOL [SME: 12918]