#!/usr/bin/perl # search.cgi # Find webmin actions use strict; use warnings; no warnings 'redefine'; no warnings 'uninitialized'; use Time::Local; require './webminlog-lib.pl'; our (%text, %config, %gconfig, $webmin_logfile, %in, $in); &foreign_require("acl", "acl-lib.pl"); &ReadParse(); if ($in{'search'}) { # Re-parse args from search param $ENV{'QUERY_STRING'} = $in{'search'}; %in = (); &ReadParse(\%in, 'GET'); } &error_setup($text{'search_err'}); # Use sensible defaults $in{'tall'} = 2 if (!defined($in{'tall'})); $in{'uall'} = 1 if (!defined($in{'uall'})); $in{'mall'} = 1 if (!defined($in{'mall'})); $in{'fall'} = 1 if (!defined($in{'fall'})); $in{'dall'} = 1 if (!defined($in{'dall'})); $in{'wall'} = 1 if (!defined($in{'wall'})); # Parse entered time ranges my ($from, $to); if ($in{'tall'} == 2) { # Today my @now = localtime(time()); $from = timelocal(0, 0, 0, $now[3], $now[4], $now[5]); $to = timelocal(59, 59, 23, $now[3], $now[4], $now[5]); $in{'tall'} = 0; } elsif ($in{'tall'} == 3) { # Yesterday my @now = localtime(time()-24*60*60); $from = timelocal(0, 0, 0, $now[3], $now[4], $now[5]); $to = timelocal(59, 59, 23, $now[3], $now[4], $now[5]); $in{'tall'} = 0; } elsif ($in{'tall'} == 4) { # Over the last week my @week = localtime(time()-7*24*60*60); $from = timelocal(0, 0, 0, $week[3], $week[4], $week[5]); $to = time(); $in{'tall'} = 0; } elsif ($in{'tall'} == 0) { # Some time range $from = &parse_time('from'); $to = &parse_time('to'); $to = $to ? $to + 24*60*60 - 1 : time(); } else { # All time $from = $to = 0; } if ($in{'csv'}) { &PrintHeader(undef, "text/csv"); } else { &ui_print_header($in{'search_sub_title'} || undef, &html_escape($in{'search_title'} || $text{'search_title'}), "", undef, undef, $in{'no_return'}); } # Perform initial search in index my @match; my %index; &build_log_index(\%index); open(LOG, "<$webmin_logfile"); while(my ($id, $idx) = each %index) { if ($id =~ /^last/) { next; } my ($pos, $time, $user, $module, $sid) = split(/\s+/, $idx); $time ||= 0; $module ||= ""; $sid ||= ""; if (($in{'uall'} == 1 || $in{'uall'} == 0 && $in{'user'} eq $user || $in{'uall'} == 3 && $in{'ouser'} eq $user || $in{'uall'} == 2 && $in{'nuser'} ne $user) && ($in{'mall'} || $in{'module'} eq $module) && (!$in{'sid'} || $in{'sid'} eq $sid || $in{'sid'} eq &acl::hash_session_id($sid)) && ($in{'tall'} || $from < $time && $to > $time)) { # Passed index check .. now look at actual log entry seek(LOG, $pos, 0); my $line = <LOG>; my $act = &parse_logline($line); next if (!$act); # Check Webmin server next if (!$in{'wall'} && $in{'webmin'} ne $act->{'webmin'}); # Check modified files if ($gconfig{'logfiles'} && (!$in{'fall'} || !$in{'dall'})) { # Make sure the specified file was modified my $found = 0; foreach my $d (&list_diffs($act)) { my $filematch = $in{'fall'} || $d->{'object'} && $d->{'object'} eq $in{'file'}; my $diffmatch = $in{'dall'} || $d->{'diff'} =~ /\Q$in{'diff'}\E/i; if ($filematch && $diffmatch) { $found++; last; } } next if (!$found); } next if (!&can_user($act->{'user'})); next if (!&can_mod($act->{'module'})); # Check description if (defined($in{'desc'}) && $in{'desc'} =~ /\S/) { my $desc = &get_action_description($act, $in{'long'}); $desc =~ s/<[^>]+>//g; next if ($desc !~ /\Q$in{'desc'}\E/i); } push(@match, $act); } } close(LOG); # Build search description my $fromstr = &make_date($from, 1); my $tostr = &make_date($to, 1); my %minfo; if (!$in{'mall'}) { %minfo = &get_module_info($in{'module'}); } my $searchmsg = join(" ", $in{'uall'} == 0 ? &text('search_critu', "<tt>".&html_escape($in{'user'})."</tt>") : $in{'uall'} == 3 ? &text('search_critu', "<tt>".&html_escape($in{'ouser'})."</tt>") : $in{'uall'} == 2 ? &text('search_critnu', "<tt>".&html_escape($in{'nuser'})."</tt>") : "", $in{'mall'} ? '' : &text('search_critm', "<tt>".&html_escape($minfo{'desc'})."</tt>"), $in{'tall'} ? '' : $fromstr eq $tostr ? &text('search_critt2', $tostr) : &text('search_critt', $fromstr, $tostr), $in{'desc'} ? &text('search_critd', &html_escape($in{'desc'})) : ""); my %minfo_cache; if ($in{'csv'}) { # Show search results as CSV my @cols; foreach my $act (sort { $b->{'time'} <=> $a->{'time'} } @match) { my $m = $act->{'module'}; my $minfo = $m eq "global" ? { 'desc' => $text{'search_global'} } : $minfo_cache{$m}; if (!$minfo) { my %minfo = &get_module_info($m); $minfo = $minfo_cache{$m} = \%minfo; } my $desc = &get_action_description($act, $in{'long'}); $desc =~ s/<[^>]+>//g; @cols = ( $desc, $minfo->{'desc'}, $act->{'user'}, $act->{'ip'} ); if ($config{'host_search'}) { push(@cols, $act->{'webmin'}); } push(@cols, &make_date($act->{'time'},0 , "yyyy-mm-dd")); print join(",", map { "\"$_\"" } @cols),"\n"; } } elsif (@match) { # Show search results in table if ($in{'sid'}) { print "<b data-search-action='sid'>",&text('search_sid', "<tt>$match[0]->{'user'}</tt>", "<tt>$in{'sid'}</tt>")," ..</b><p>\n"; } elsif ($in{'uall'} == 1 && $in{'mall'} && $in{'tall'}) { print "<b data-search-action='critall'>$text{'search_critall'} ..</b><p>\n"; } else { my %minfo = &get_module_info($in{'module'}) if (!$in{'mall'}); print "<b data-search-action='crit'>$text{'search_crit'} $searchmsg ...</b><p>\n"; } print &ui_columns_start( [ $text{'search_action'}, $text{'search_module'}, $text{'search_user'}, $text{'search_host'}, $config{'host_search'} ? ( $text{'search_webmin'} ) : ( ), $text{'search_date'}, $text{'search_time'} ], "100"); foreach my $act (sort { $b->{'time'} <=> $a->{'time'} } @match) { my @tm = localtime($act->{'time'}); my $m = $act->{'module'}; my $d; my $minfo = $m eq "global" ? { 'desc' => $text{'search_global'} } : $minfo_cache{$m}; if (!$minfo) { # first time seeing module .. my %minfo = &get_module_info($m); $minfo = $minfo_cache{$m} = \%minfo; } my @cols; my $desc = &get_action_description($act, $in{'long'}); my $anno = &get_annotation($act); push(@cols, &ui_link("view.cgi?id=$act->{'id'}". "&return=".&urlize($in{'return'} || ""). "&returndesc=".&urlize($in{'returndesc'} || ""). "&no_return=".&urlize($in{'no_return'} || ""). "&search_sub_title=".&urlize($in{'search_sub_title'} || ""). "&file=".($in{'fall'} ? "" : &urlize($in{'file'})). "&search=".&urlize($in || ""), &filter_javascript($desc)) ); if ($anno) { $cols[$#cols] .= " <img src=images/star.gif>"; } push(@cols, $minfo->{'desc'}, &html_escape($act->{'user'}), &html_escape($act->{'ip'})); if ($config{'host_search'}) { push(@cols, $act->{'webmin'}); } push(@cols, split(/\s+/, &make_date($act->{'time'}, 0, "yyyy/mm/dd"))); print &ui_columns_row(\@cols); } print &ui_columns_end(); print &ui_link("search.cgi/webminlog.csv?$in&csv=1", $text{'search_csv'}); print "<p>\n"; } else { # Tell the user that nothing matches print "<p><b>$text{'search_none2'}".(&trim($searchmsg) ? " @{[&trim($searchmsg, -1)]}" : "").".</b><p>\n"; } if (!$in{'csv'} && !$in{'no_return'}) { # Show page footer if ($in{'return'}) { &ui_print_footer($in{'return'}, $in{'returndesc'}); } else { &ui_print_footer("", $text{'index_return'}); } } sub parse_time { my $d = $in{"$_[0]_d"}; my $m = $in{"$_[0]_m"}; my $y = $in{"$_[0]_y"}; return 0 if (!$d && !$y); my $rv; eval { $rv = timelocal(0, 0, 0, $d, $m-1, $y-1900) }; &error($text{'search_etime'}) if ($@); return $rv; }
Name | Type | Size | Permission | Actions |
---|---|---|---|---|
images | Folder | 0755 |
|
|
lang | Folder | 0755 |
|
|
CHANGELOG | File | 2.01 KB | 0644 |
|
acl_security.pl | File | 1.49 KB | 0755 |
|
config | File | 14 B | 0644 |
|
config.info | File | 70 B | 0644 |
|
config.info.ar | File | 88 B | 0644 |
|
config.info.ca | File | 89 B | 0644 |
|
config.info.cs | File | 85 B | 0644 |
|
config.info.de | File | 71 B | 0644 |
|
config.info.es | File | 92 B | 0644 |
|
config.info.hr | File | 0 B | 0644 |
|
config.info.hu | File | 95 B | 0644 |
|
config.info.ja | File | 102 B | 0644 |
|
config.info.ko | File | 93 B | 0644 |
|
config.info.ms | File | 77 B | 0644 |
|
config.info.nl | File | 86 B | 0644 |
|
config.info.no | File | 65 B | 0644 |
|
config.info.pl | File | 89 B | 0644 |
|
config.info.ru | File | 128 B | 0644 |
|
config.info.sk | File | 87 B | 0644 |
|
config.info.tr | File | 89 B | 0644 |
|
defaultacl | File | 35 B | 0644 |
|
index.cgi | File | 5.29 KB | 0755 |
|
log_parser.pl | File | 508 B | 0755 |
|
module.info | File | 150 B | 0644 |
|
module.info.af | File | 0 B | 0644 |
|
module.info.af.auto | File | 120 B | 0644 |
|
module.info.ar | File | 137 B | 0644 |
|
module.info.ar.auto | File | 18 B | 0644 |
|
module.info.be | File | 0 B | 0644 |
|
module.info.be.auto | File | 192 B | 0644 |
|
module.info.bg | File | 0 B | 0644 |
|
module.info.bg.auto | File | 214 B | 0644 |
|
module.info.ca | File | 119 B | 0644 |
|
module.info.ca.auto | File | 17 B | 0644 |
|
module.info.cs | File | 38 B | 0644 |
|
module.info.cs.auto | File | 85 B | 0644 |
|
module.info.da | File | 0 B | 0644 |
|
module.info.da.auto | File | 118 B | 0644 |
|
module.info.de | File | 96 B | 0644 |
|
module.info.de.auto | File | 18 B | 0644 |
|
module.info.el | File | 0 B | 0644 |
|
module.info.el.auto | File | 192 B | 0644 |
|
module.info.es | File | 41 B | 0644 |
|
module.info.es.auto | File | 94 B | 0644 |
|
module.info.eu | File | 0 B | 0644 |
|
module.info.eu.auto | File | 124 B | 0644 |
|
module.info.fa | File | 0 B | 0644 |
|
module.info.fa.auto | File | 185 B | 0644 |
|
module.info.fi | File | 0 B | 0644 |
|
module.info.fi.auto | File | 123 B | 0644 |
|
module.info.fr | File | 38 B | 0644 |
|
module.info.fr.auto | File | 101 B | 0644 |
|
module.info.he | File | 0 B | 0644 |
|
module.info.he.auto | File | 141 B | 0644 |
|
module.info.hr | File | 0 B | 0644 |
|
module.info.hr.auto | File | 117 B | 0644 |
|
module.info.hu | File | 23 B | 0644 |
|
module.info.hu.auto | File | 115 B | 0644 |
|
module.info.it | File | 31 B | 0644 |
|
module.info.it.auto | File | 105 B | 0644 |
|
module.info.ja | File | 151 B | 0644 |
|
module.info.ko | File | 29 B | 0644 |
|
module.info.ko.auto | File | 88 B | 0644 |
|
module.info.lt | File | 0 B | 0644 |
|
module.info.lt.auto | File | 146 B | 0644 |
|
module.info.lv | File | 0 B | 0644 |
|
module.info.lv.auto | File | 124 B | 0644 |
|
module.info.ms | File | 86 B | 0644 |
|
module.info.ms.auto | File | 18 B | 0644 |
|
module.info.mt | File | 0 B | 0644 |
|
module.info.mt.auto | File | 129 B | 0644 |
|
module.info.nl | File | 25 B | 0644 |
|
module.info.nl.auto | File | 97 B | 0644 |
|
module.info.no | File | 23 B | 0644 |
|
module.info.no.auto | File | 87 B | 0644 |
|
module.info.pl | File | 98 B | 0644 |
|
module.info.pl.auto | File | 18 B | 0644 |
|
module.info.pt | File | 0 B | 0644 |
|
module.info.pt.auto | File | 125 B | 0644 |
|
module.info.pt_BR | File | 0 B | 0644 |
|
module.info.pt_BR.auto | File | 134 B | 0644 |
|
module.info.ro | File | 0 B | 0644 |
|
module.info.ro.auto | File | 136 B | 0644 |
|
module.info.ru | File | 45 B | 0644 |
|
module.info.ru.auto | File | 135 B | 0644 |
|
module.info.sk | File | 32 B | 0644 |
|
module.info.sk.auto | File | 91 B | 0644 |
|
module.info.sl | File | 0 B | 0644 |
|
module.info.sl.auto | File | 116 B | 0644 |
|
module.info.sv | File | 24 B | 0644 |
|
module.info.sv.auto | File | 96 B | 0644 |
|
module.info.th | File | 0 B | 0644 |
|
module.info.th.auto | File | 222 B | 0644 |
|
module.info.tr | File | 27 B | 0644 |
|
module.info.tr.auto | File | 110 B | 0644 |
|
module.info.uk | File | 0 B | 0644 |
|
module.info.uk.auto | File | 160 B | 0644 |
|
module.info.ur | File | 0 B | 0644 |
|
module.info.ur.auto | File | 193 B | 0644 |
|
module.info.vi | File | 0 B | 0644 |
|
module.info.vi.auto | File | 144 B | 0644 |
|
module.info.zh | File | 28 B | 0644 |
|
module.info.zh.auto | File | 73 B | 0644 |
|
module.info.zh_TW | File | 30 B | 0644 |
|
module.info.zh_TW.auto | File | 79 B | 0644 |
|
negativeacl | File | 9 B | 0644 |
|
rollback.cgi | File | 5.14 KB | 0755 |
|
safeacl | File | 19 B | 0644 |
|
save_notify.cgi | File | 1.04 KB | 0755 |
|
search.cgi | File | 7.55 KB | 0755 |
|
view.cgi | File | 5.35 KB | 0755 |
|
webminlog-lib.pl | File | 10.48 KB | 0755 |
|