mirror of
https://github.com/webmin/webmin.git
synced 2026-03-20 16:50:24 +00:00
User-level blocking, and page for clearing blocks
This commit is contained in:
107
miniserv.pl
107
miniserv.pl
@@ -283,6 +283,9 @@ if ($config{'debuglog'}) {
|
||||
print DEBUG "miniserv.pl starting ..\n";
|
||||
}
|
||||
|
||||
# Write out (empty) blocked hosts file
|
||||
&write_blocked_file();
|
||||
|
||||
# Re-direct STDERR to a log file
|
||||
if ($config{'errorlog'} ne '-') {
|
||||
open(STDERR, ">>$config{'errorlog'}") || die "failed to open $config{'errorlog'} : $!";
|
||||
@@ -547,19 +550,43 @@ while(1) {
|
||||
|
||||
# run the unblocking procedure to check if enough time has passed to
|
||||
# unblock hosts that heve been blocked because of password failures
|
||||
$unblocked = 0;
|
||||
if ($config{'blockhost_failures'}) {
|
||||
$i = 0;
|
||||
while ($i <= $#deny) {
|
||||
if ($blockhosttime{$deny[$i]} && $config{'blockhost_time'} != 0 &&
|
||||
($time_now - $blockhosttime{$deny[$i]}) >= $config{'blockhost_time'}) {
|
||||
if ($blockhosttime{$deny[$i]} &&
|
||||
$config{'blockhost_time'} != 0 &&
|
||||
($time_now - $blockhosttime{$deny[$i]}) >=
|
||||
$config{'blockhost_time'}) {
|
||||
# the host can be unblocked now
|
||||
$hostfail{$deny[$i]} = 0;
|
||||
splice(@deny, $i, 1);
|
||||
$unblocked = 1;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
# Do the same for blocked users
|
||||
if ($config{'blockuser_failures'}) {
|
||||
$i = 0;
|
||||
while ($i <= $#deny) {
|
||||
if ($blockusertime{$deny[$i]} &&
|
||||
$config{'blockuser_time'} != 0 &&
|
||||
($time_now - $blockusertime{$deny[$i]}) >=
|
||||
$config{'blockuser_time'}) {
|
||||
# the user can be unblocked now
|
||||
$userfail{$deny[$i]} = 0;
|
||||
splice(@denyusers, $i, 1);
|
||||
$unblocked = 1;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
if ($unblocked) {
|
||||
&write_blocked_file();
|
||||
}
|
||||
|
||||
if ($config{'session'} && (++$remove_session_count%50) == 0) {
|
||||
# Remove sessions with more than 7 days of inactivity,
|
||||
local $s;
|
||||
@@ -742,32 +769,61 @@ while(1) {
|
||||
if ($3) {
|
||||
# login OK.. no delay
|
||||
print $outfd "0 0\n";
|
||||
$wasblocked = $hostfail{$2} ||
|
||||
$userfail{$1};
|
||||
$hostfail{$2} = 0;
|
||||
$userfail{$1} = 0;
|
||||
if ($wasblocked) {
|
||||
&write_blocked_file();
|
||||
}
|
||||
}
|
||||
else {
|
||||
# login failed..
|
||||
$hostfail{$2}++;
|
||||
# add the host to the block list if necessary
|
||||
$userfail{$1}++;
|
||||
$blocked = 0;
|
||||
|
||||
# add the host to the block list,
|
||||
# if configured
|
||||
if ($config{'blockhost_failures'} &&
|
||||
$hostfail{$2} >= $config{'blockhost_failures'}) {
|
||||
push(@deny, $2);
|
||||
$hostfail{$2} >=
|
||||
$config{'blockhost_failures'}) {
|
||||
push(@deny, $2);
|
||||
$blockhosttime{$2} = $time_now;
|
||||
$blocked = 1;
|
||||
if ($use_syslog) {
|
||||
local $logtext = "Security alert: Host $2 ".
|
||||
"blocked after $config{'blockhost_failures'} ".
|
||||
"failed logins for user $1";
|
||||
syslog("crit", "%s", $logtext);
|
||||
local $logtext = "Security alert: Host $2 blocked after $config{'blockhost_failures'} failed logins for user $1";
|
||||
syslog("crit", "%s",
|
||||
$logtext);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$blocked = 0;
|
||||
|
||||
# add the user to the user block list,
|
||||
# if configured
|
||||
if ($config{'blockuser_failures'} &&
|
||||
$userfail{$1} >=
|
||||
$config{'blockuser_failures'}) {
|
||||
push(@denyusers, $1);
|
||||
$blockusertime{$1} = $time_now;
|
||||
$blocked = 2;
|
||||
if ($use_syslog) {
|
||||
local $logtext = "Security alert: User $1 blocked after $config{'blockuser_failures'} failed logins";
|
||||
syslog("crit", "%s",
|
||||
$logtext);
|
||||
}
|
||||
}
|
||||
|
||||
# Send back a delay
|
||||
$dl = $userdlay{$1} -
|
||||
int(($time_now - $userlast{$1})/50);
|
||||
int(($time_now - $userlast{$1})/50);
|
||||
$dl = $dl < 0 ? 0 : $dl+1;
|
||||
print $outfd "$dl $blocked\n";
|
||||
$userdlay{$1} = $dl;
|
||||
|
||||
# Write out blocked status file
|
||||
if ($blocked) {
|
||||
&write_blocked_file();
|
||||
}
|
||||
}
|
||||
$userlast{$1} = $time_now;
|
||||
}
|
||||
@@ -1599,12 +1655,18 @@ if (%users) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
elsif ($blocked == 1) {
|
||||
# when the host has been blocked, give it an error
|
||||
&http_error(403, "Access denied for $acptip. The host ".
|
||||
"has been blocked because of too ".
|
||||
"many authentication failures.");
|
||||
}
|
||||
elsif ($blocked == 2) {
|
||||
# when the user has been blocked, give it an error
|
||||
&http_error(403, "Access denied. The user ".
|
||||
"has been blocked because of too ".
|
||||
"many authentication failures.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
# Get the real Webmin username
|
||||
@@ -3759,6 +3821,10 @@ if (!$config{'tempbase'}) {
|
||||
$config{'pidfile'} =~ /^(.*)\/[^\/]+$/;
|
||||
$config{'tempbase'} = "$1/cgitemp";
|
||||
}
|
||||
if (!$config{'blockedfile'}) {
|
||||
$config{'pidfile'} =~ /^(.*)\/[^\/]+$/;
|
||||
$config{'blockedfile'} = "$1/blocked";
|
||||
}
|
||||
}
|
||||
|
||||
# read_users_file()
|
||||
@@ -4353,3 +4419,18 @@ foreach my $s (@substrings, @mobile_agents) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
# write_blocked_file()
|
||||
# Writes out a text file of blocked hosts and users
|
||||
sub write_blocked_file
|
||||
{
|
||||
open(BLOCKED, ">$config{'blockedfile'}");
|
||||
foreach my $d (grep { $hostfail{$_} } @deny) {
|
||||
print BLOCKED "host $d $hostfail{$d} $blockhosttime{$d}\n";
|
||||
}
|
||||
foreach my $d (grep { $userfail{$_} } @denyusers) {
|
||||
print BLOCKED "user $d $userfail{$d} $blockusertime{$d}\n";
|
||||
}
|
||||
close(BLOCKED);
|
||||
chmod(0700, $config{'blockedfile'});
|
||||
}
|
||||
|
||||
|
||||
@@ -60,3 +60,6 @@ When Webmin's detected OS is automatically updated, Usermin's will be too (if it
|
||||
---- Changes since 1.340 ----
|
||||
Added an option to the Proxy Servers form to fallback to a direct connection if the proxy is down.
|
||||
Added a tab showing details of the current cert, with a link to download in PEM or PKCS12 format.
|
||||
---- Changes since 1.350 ----
|
||||
Added an option to the Authentication page to block users with too many failed logins, as well as hosts.
|
||||
Created the new Blocked Hosts and Users page to show blocks currently in force, and allow them to be cleared.
|
||||
|
||||
@@ -9,6 +9,8 @@ require './webmin-lib.pl';
|
||||
&lock_file($ENV{'MINISERV_CONFIG'});
|
||||
&get_miniserv_config(\%miniserv);
|
||||
$miniserv{'passdelay'} = $in{'passdelay'};
|
||||
|
||||
# Save blocked hosts
|
||||
if ($in{'blockhost_on'}) {
|
||||
$in{'blockhost_time'} =~ /^\d+$/ && $in{'blockhost_time'} > 0 ||
|
||||
&error($text{'session_eblockhost_time'});
|
||||
@@ -20,6 +22,20 @@ if ($in{'blockhost_on'}) {
|
||||
else {
|
||||
$miniserv{'blockhost_time'} = $miniserv{'blockhost_failures'} = undef;
|
||||
}
|
||||
|
||||
# Save blocked users
|
||||
if ($in{'blockuser_on'}) {
|
||||
$in{'blockuser_time'} =~ /^\d+$/ && $in{'blockuser_time'} > 0 ||
|
||||
&error($text{'session_eblockuser_time'});
|
||||
$in{'blockuser_failures'} =~ /^\d+$/ && $in{'blockuser_failures'} > 0 ||
|
||||
&error($text{'session_eblockuser_failures'});
|
||||
$miniserv{'blockuser_time'} = $in{'blockuser_time'};
|
||||
$miniserv{'blockuser_failures'} = $in{'blockuser_failures'};
|
||||
}
|
||||
else {
|
||||
$miniserv{'blockuser_time'} = $miniserv{'blockuser_failures'} = undef;
|
||||
}
|
||||
|
||||
$miniserv{'syslog'} = $in{'syslog'};
|
||||
if ($in{'session'} && $ENV{'HTTP_COOKIE'} !~ /sessiontest=1/i) {
|
||||
&error($text{'session_ecookie'});
|
||||
|
||||
8
webmin/clear_blocked.cgi
Executable file
8
webmin/clear_blocked.cgi
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/usr/local/bin/perl
|
||||
# Re-start Webmin to clear blocks
|
||||
|
||||
require './webmin-lib.pl';
|
||||
|
||||
&show_restart_page($text{'blocked_title'}, $text{'blocked_restarting'});
|
||||
|
||||
|
||||
@@ -15,15 +15,27 @@ print "<table border>\n";
|
||||
print "<tr $tb> <td><b>$text{'session_header'}</b></td> </tr>\n";
|
||||
print "<tr $cb> <td nowrap>\n";
|
||||
|
||||
# Bad password delay
|
||||
printf "<input type=radio name=passdelay value=0 %s> %s<br>\n",
|
||||
$miniserv{'passdelay'} ? '' : 'checked', $text{'session_pdisable'};
|
||||
printf "<input type=radio name=passdelay value=1 %s> %s<br>\n",
|
||||
$miniserv{'passdelay'} ? 'checked' : '', $text{'session_penable'};
|
||||
|
||||
# Block bad hosts
|
||||
printf " <input type=checkbox name=blockhost_on value=1 %s>\n",
|
||||
$miniserv{'blockhost_failures'} ? "checked" : "";
|
||||
print &text('session_blockhost',
|
||||
"<input name=blockhost_failures size=4 value='$miniserv{'blockhost_failures'}'>",
|
||||
"<input name=blockhost_time size=4 value='$miniserv{'blockhost_time'}'>"),"<br>\n";
|
||||
&ui_textbox("blockhost_failures", $miniserv{'blockhost_failures'}, 4),
|
||||
&ui_textbox("blockhost_time", $miniserv{'blockhost_time'}, 4)),"<br>\n";
|
||||
|
||||
# Block bad users
|
||||
printf " <input type=checkbox name=blockuser_on value=1 %s>\n",
|
||||
$miniserv{'blockuser_failures'} ? "checked" : "";
|
||||
print &text('session_blockuser',
|
||||
&ui_textbox("blockuser_failures", $miniserv{'blockuser_failures'}, 4),
|
||||
&ui_textbox("blockuser_time", $miniserv{'blockuser_time'}, 4)),"<br>\n";
|
||||
|
||||
# Log to syslog
|
||||
eval "use Sys::Syslog qw(:DEFAULT setlogsock)";
|
||||
if (!$@) {
|
||||
printf "<input type=checkbox name=syslog value=1 %s> %s\n",
|
||||
|
||||
BIN
webmin/images/blocked.gif
Normal file
BIN
webmin/images/blocked.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
@@ -14,7 +14,7 @@ $ver = &get_webmin_version();
|
||||
"edit_upgrade.cgi", "edit_session.cgi", "edit_assignment.cgi",
|
||||
"edit_categories.cgi", "edit_descs.cgi", "edit_themes.cgi",
|
||||
"edit_referers.cgi", "edit_anon.cgi", "edit_lock.cgi",
|
||||
"edit_mobile.cgi", "edit_advanced.cgi" );
|
||||
"edit_mobile.cgi", "edit_blocked.cgi", "edit_advanced.cgi" );
|
||||
@wtitles = ( $text{'access_title'}, $text{'bind_title'},
|
||||
$text{'log_title'}, $text{'proxy_title'},
|
||||
$text{'ui_title'}, $text{'mods_title'},
|
||||
@@ -24,7 +24,8 @@ $ver = &get_webmin_version();
|
||||
$text{'categories_title'}, $text{'descs_title'},
|
||||
$text{'themes_title'}, $text{'referers_title'},
|
||||
$text{'anon_title'}, $text{'lock_title'},
|
||||
$text{'mobile_title'}, $text{'advanced_title'} );
|
||||
$text{'mobile_title'}, $text{'blocked_title'},
|
||||
$text{'advanced_title'} );
|
||||
@wicons = ( "images/access.gif", "images/bind.gif", "images/log.gif",
|
||||
"images/proxy.gif", "images/ui.gif", "images/mods.gif",
|
||||
"images/os.gif", "images/lang.gif", "images/startpage.gif",
|
||||
@@ -32,7 +33,7 @@ $ver = &get_webmin_version();
|
||||
"images/assignment.gif", "images/categories.gif",
|
||||
"images/descs.gif", "images/themes.gif", "images/referers.gif",
|
||||
"images/anon.gif", "images/lock.gif", "images/mobile.gif",
|
||||
"images/advanced.gif" );
|
||||
"images/blocked.gif", "images/advanced.gif" );
|
||||
if ($gconfig{'eazel'}) {
|
||||
push(@wlinks, "edit_syslet.cgi");
|
||||
push(@wtitles, $text{'syslet_title'});
|
||||
|
||||
@@ -19,9 +19,12 @@ advanced_etemp=Fehlendes oder nicht-existentes Verzeichnis für temporä
|
||||
advanced_header=Erweiterte und experimentelle Optionen
|
||||
advanced_pass=Mache Passwort anderen Webmin-Programmen verfügbar?<br><font size=-1>(Funktioniert nicht, wenn Session-Authentication eingeschaltet ist)</font>
|
||||
advanced_preload=Webmin-Funktionsbibliotheken vorladen?
|
||||
advanced_showstderr=Perl-Fehler im Browser anzeigen?
|
||||
advanced_tdir=Verzeichnis
|
||||
advanced_temp=Verzeichnis für temporäre Dateien
|
||||
advanced_tempdef=Standard (<tt>/tmp/.webmin</tt>)
|
||||
advanced_title=Erweiterte Optionen
|
||||
advanced_tmod=Module
|
||||
anon_desc=Diese Seite erlaubt Ihnen, Zugriff auf ausgwählte Webmin-Module und Pfade zu gewähren, ohne dass sich die Benutzer anmelden müssen. Für jeden Modul-Pfad, den Sie unten eingeben (so wie <tt>/custom</tt> oder <tt>/passwd</tt>) müssen Sie auch den Namen des Webminbenutzers eingeben, dessen Rechte für den Zugriff auf die Module benutzt werden soll.
|
||||
anon_desc2=Sie sollten SEHR vorsichtig sein, wenn Sie anonymen Zugriff gewähren, da ungenügende IP-Zugriffskontrolle oder Zugriff auf die falschen Module Angreifern die Übernahme des Systems ermöglichen kann.
|
||||
anon_err=Konnte Einstellungen für Anonymen Zugriff nicht speichern
|
||||
@@ -79,6 +82,8 @@ ca_stop=Zertifikatsautorität herunterfahren
|
||||
ca_stopmsg=Klicken Sie auf diesen Schaltfläche, damit Webmin keine existierenden Zertifikate mehr akzeptiert oder neue ausstellt. Dies wird Benutzer zwingen, sich stattdessen mit Benutzernamen und Kennwort anzumelden.
|
||||
ca_stopok=Ihre Zertifikatsautorität wurde erfolgreich heruntergefahren.
|
||||
ca_title=Zertifikatsautorität
|
||||
cache_ok=Suchen
|
||||
cache_size=Größe
|
||||
categories_code=ID
|
||||
categories_desc=In diesem Dialog können Sie vorhandene Webmin-Kategorien bearbeiten und neue hinzufügen, denen Sie dann einzelne Module zuweisen können. Im oberen Teil der Maske sehen Sie die vorhandenen Kategorien, deren Beschreibungen Sie hier ändern können. In der untersten Zeile können Sie eine neue Kategorie erzeugen.
|
||||
categories_ecat=Kategorie-ID $1 ist bereits verwendet.
|
||||
@@ -307,6 +312,10 @@ os_update=Aktualisiere Webmin, so daß es das erkannte Betriebssystem benutz
|
||||
os_value=Wert
|
||||
os_webmin=Betriebssystem, wie Webmin es sieht.
|
||||
proxy_bind=Quell-IP-Adresse für HTTP-Verbindungen
|
||||
proxy_cache1=Nein
|
||||
proxy_clear=Cache löschen
|
||||
proxy_days=Tage
|
||||
proxy_daysdef=Für immer
|
||||
proxy_desc=Wenn der Host, auf dem Webmin läuft, sich hinter einer Firewall befindet, kann es sein, dass Sie einen Proxyserver zum Zugriff auf Web- und FTP-Seiten verwenden müssen. Einige Module, wie z. B. das Modul <tt>Software-Pakete</tt>, werden diese Proxies benutzen, wenn Sie Dateien oder Programme herunterladen.
|
||||
proxy_desc2=Wenn Webmin eine Datei von einer SourceForge-URL herunterlädt, dann wird wenn möglich automatisch der Mirror genutzt, den Sie hier angeben.
|
||||
proxy_ebind=Fehlende oder ungültige Quell-IP-Adresse
|
||||
@@ -320,6 +329,7 @@ proxy_header2=Download Sites
|
||||
proxy_http=HTTP-Proxy
|
||||
proxy_mirrordef=<Standard (UNC)>
|
||||
proxy_mirrordef2=Standard (UNC)
|
||||
proxy_mods0=Alle Module
|
||||
proxy_nofor=Kein Proxy für
|
||||
proxy_none=Keiner
|
||||
proxy_osdn=Standard OSDN-Spiegel für Downloads
|
||||
@@ -407,9 +417,13 @@ ssl_key=Private Schlüssel-Datei
|
||||
ssl_newfile=Schlüssel in Datei sichern
|
||||
ssl_newkey=Dieses Formular kann dazu benutzt werden, um einen neuen SSL-Schlüssel für Ihren Webmin-Server zu erzeugen.
|
||||
ssl_on=SSL aktivieren, wenn verfügbar
|
||||
ssl_pem=PEM-Format
|
||||
ssl_pkcs12=PKCS12-Format
|
||||
ssl_redirect=Nicht-SSL-Anfragen auf SSL umleiten?
|
||||
ssl_return=SSL-Schlüssel
|
||||
ssl_size=RSA-Schlüsselgrösse
|
||||
ssl_tabcurrent=Aktuelles Zertifikat
|
||||
ssl_tabssl=SSL Einstellungen
|
||||
ssl_title=SSL-Verschlüsselung
|
||||
ssl_usenew=Neuen Schlüssel sofort benutzen?
|
||||
ssl_version=SSL-Protokollversion
|
||||
@@ -439,6 +453,7 @@ syslet_desc=Diese Seite ist zur Konfiguration des automatischen Herunterladens u
|
||||
syslet_ebase=Ungültige Basis-URL
|
||||
syslet_err=Syslet-Optionen speichern gescheitert
|
||||
syslet_title=Automatischer Syslet-Download
|
||||
syslog_errorlog=Webmin Fehler-Log
|
||||
themes_change=Ändern
|
||||
themes_default=Standard Webmin-Theme
|
||||
themes_delete=Dieses Formular kann benutzt werden, um ein derzeit nicht benutztes Theme, welches auf Ihrem System installiert ist, zu löschen.
|
||||
|
||||
@@ -497,6 +497,7 @@ session_header=Authentication and session options
|
||||
session_pdisable=Disable password timeouts
|
||||
session_penable=Enable password timeouts
|
||||
session_blockhost=Block hosts with more than $1 failed logins for $2 seconds.
|
||||
session_blockuser=Block users with more than $1 failed logins for $2 seconds.
|
||||
session_syslog2=Log blocked hosts, logins and authentication failures to <tt>syslog</tt>
|
||||
session_disable=Disable session authentication
|
||||
session_enable=Enable session authentication
|
||||
@@ -508,6 +509,8 @@ session_err=Failed to save authentication
|
||||
session_elogouttime=Missing or invalid logout time
|
||||
session_eblockhost_time=Missing or invalid blocking time
|
||||
session_eblockhost_failures=Missing or invalid blocking logins
|
||||
session_eblockuser_time=Missing or invalid user blocking time
|
||||
session_eblockuser_failures=Missing or invalid user blocking logins
|
||||
session_ecookie=Your browser does not support cookies, which are required for session authentication
|
||||
session_elsof=Local authentication requires the <tt>lsof</tt> program
|
||||
session_remember=Offer to remember login permanently?
|
||||
@@ -768,3 +771,14 @@ mobile_agents=Additional user agents for mobile browsers
|
||||
mobile_err=Failed to save mobile device options
|
||||
mobile_prefixes=URL hostname prefixes for mobile browsers
|
||||
|
||||
blocked_title=Blocked Hosts and Users
|
||||
blocked_type=Type
|
||||
blocked_who=Hostname or username
|
||||
blocked_fails=Login failures
|
||||
blocked_when=Blocked at
|
||||
blocked_none=No hosts or users are currently blocked by Webmin.
|
||||
blocked_user=Webmin user
|
||||
blocked_host=Client host
|
||||
blocked_clear=Clear All Blocks
|
||||
blocked_cleardesc=Click this button to clear all current host and user blocks, by restarting the Webmin server process.
|
||||
blocked_restarting=The Webmin server process is now restarting to clear blocked hosts and users - please wait for a few seconds before continuing.
|
||||
|
||||
@@ -1128,11 +1128,15 @@ closedir(DIR);
|
||||
return @rv;
|
||||
}
|
||||
|
||||
# show_restart_page([title, msg])
|
||||
sub show_restart_page
|
||||
{
|
||||
&ui_print_header(undef, $text{'restart_title'}, "");
|
||||
local ($title, $msg) = @_;
|
||||
$title ||= $text{'restart_title'};
|
||||
$msg ||= $text{'restart_done'};
|
||||
&ui_print_header(undef, $title, "");
|
||||
|
||||
print "<p>$text{'restart_done'}<p>\n";
|
||||
print "<p>$msg<p>\n";
|
||||
|
||||
&ui_print_footer("", $text{'index_return'});
|
||||
&restart_miniserv(1);
|
||||
@@ -1208,6 +1212,28 @@ close(OUT);
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
# get_blocked_users_hosts(&miniserv)
|
||||
# Returns a list of blocked users and hosts from the file written by Webmin
|
||||
sub get_blocked_users_hosts
|
||||
{
|
||||
local ($miniserv) = @_;
|
||||
local $bf = $miniserv->{'blockedfile'};
|
||||
if (!$bf) {
|
||||
$miniserv->{'pidfile'} =~ /^(.*)\/[^\/]+$/;
|
||||
$bf = "$1/blocked";
|
||||
}
|
||||
local @rv;
|
||||
&open_readfile(BLOCKED, $bf);
|
||||
while(<BLOCKED>) {
|
||||
s/\r|\n//g;
|
||||
local ($type, $who, $fails, $when) = split(/\s+/, $_);
|
||||
push(@rv, { 'type' => $type,
|
||||
$type => $who,
|
||||
'fails' => $fails,
|
||||
'when' => $when });
|
||||
}
|
||||
close(BLOCKED);
|
||||
return @rv;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
Reference in New Issue
Block a user