Synchronet now requires the libarchive development package (e.g. libarchive-dev on Debian-based Linux distros, libarchive.org for more info) to build successfully.

Commit 74daf32c authored by rswindell's avatar rswindell

Unifield login attempt lists between all servers/services.

The attempt list can be view with sbbscon->'a' command or sbbsctrl->view->Login
Attempt List...
Delay/throttle/hacklog/and auto-filter values/thresholds are now configurable
in sbbs.ini.
parent 438e2029
/* Synchronet Control Panel (GUI Borland C++ Builder Project for Win32) */
/* $Id$ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2011 Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* Anonymous FTP access to the most recent released source is available at *
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
* *
* Anonymous CVS access to the development source and modification history *
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
* (just hit return, no password is necessary) *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* You are encouraged to submit any modifications (preferably in Unix diff *
* format) via e-mail to mods@synchro.net *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
//---------------------------------------------------------------------------
#include "sbbs.h"
#include <vcl.h>
#pragma hdrstop
#include "LoginAttemptsFormUnit.h"
#include "MainFormUnit.h"
#include "userdat.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TLoginAttemptsForm *LoginAttemptsForm;
extern link_list_t login_attempt_list;
//---------------------------------------------------------------------------
__fastcall TLoginAttemptsForm::TLoginAttemptsForm(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TLoginAttemptsForm::FormShow(TObject *Sender)
{
char str[128];
TListItem* Item;
list_node_t* node;
struct tm tm;
login_attempt_t* attempt;
ColumnToSort=0;
SortBackwards=false;
Screen->Cursor=crAppStart;
listLock(&login_attempt_list);
ListView->AllocBy=listCountNodes(&login_attempt_list);
ListView->Items->BeginUpdate();
for(node=listFirstNode(&login_attempt_list); node!=NULL; node=listNextNode(node)) {
attempt=(login_attempt_t*)node->data;
if(attempt==NULL)
continue;
Item=ListView->Items->Add();
Item->Caption=AnsiString(attempt->count);
Item->Data=(void*)attempt->time;
Item->SubItems->Add(inet_ntoa(attempt->addr));
Item->SubItems->Add(attempt->prot);
Item->SubItems->Add(attempt->user);
Item->SubItems->Add(attempt->pass);
localtime_r(&attempt->time,&tm);
sprintf(str,"%u/%u %02u:%02u:%02u"
,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec);
Item->SubItems->Add(str);
}
ListView->Items->EndUpdate();
listUnlock(&login_attempt_list);
Screen->Cursor=crDefault;
}
//---------------------------------------------------------------------------
void __fastcall TLoginAttemptsForm::FormClose(TObject *Sender,
TCloseAction &Action)
{
ListView->Items->BeginUpdate();
ListView->Items->Clear();
ListView->Items->EndUpdate();
}
//---------------------------------------------------------------------------
void __fastcall TLoginAttemptsForm::ListViewColumnClick(TObject *Sender,
TListColumn *Column)
{
if(Column->Index == ColumnToSort)
SortBackwards=!SortBackwards;
else
SortBackwards=false;
ColumnToSort = Column->Index;
((TCustomListView *)Sender)->AlphaSort();
}
//---------------------------------------------------------------------------
void __fastcall TLoginAttemptsForm::ListViewCompare(TObject *Sender,
TListItem *Item1, TListItem *Item2, int Data, int &Compare)
{
/* Decimal compare */
if (ColumnToSort == 0 || ColumnToSort == 5) {
int num1, num2;
if(ColumnToSort==0) {
num1=Item1->Caption.ToIntDef(0);
num2=Item2->Caption.ToIntDef(0);
} else { /* Date */
num1=(ulong)Item1->Data;
num2=(ulong)Item2->Data;
}
if(SortBackwards)
Compare=(num2-num1);
else
Compare=(num1-num2);
} else {
int ix = ColumnToSort - 1;
if(SortBackwards)
Compare = CompareText(Item2->SubItems->Strings[ix]
,Item1->SubItems->Strings[ix]);
else
Compare = CompareText(Item1->SubItems->Strings[ix]
,Item2->SubItems->Strings[ix]);
}
}
//---------------------------------------------------------------------------
object LoginAttemptsForm: TLoginAttemptsForm
Left = 522
Top = 454
Width = 496
Height = 793
Caption = 'Failed Login Attempts'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
OnClose = FormClose
OnShow = FormShow
PixelsPerInch = 96
TextHeight = 13
object ListView: TListView
Left = 0
Top = 0
Width = 488
Height = 766
Align = alClient
Columns = <
item
Caption = 'Count'
end
item
AutoSize = True
Caption = 'Address'
end
item
Caption = 'Protocol'
end
item
Caption = 'User'
end
item
AutoSize = True
Caption = 'Password'
end
item
AutoSize = True
Caption = 'Time'
end>
TabOrder = 0
ViewStyle = vsReport
OnColumnClick = ListViewColumnClick
OnCompare = ListViewCompare
end
end
//---------------------------------------------------------------------------
#ifndef LoginAttemptsFormUnitH
#define LoginAttemptsFormUnitH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ComCtrls.hpp>
//---------------------------------------------------------------------------
class TLoginAttemptsForm : public TForm
{
__published: // IDE-managed Components
TListView *ListView;
void __fastcall FormShow(TObject *Sender);
void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
void __fastcall ListViewColumnClick(TObject *Sender,
TListColumn *Column);
void __fastcall ListViewCompare(TObject *Sender, TListItem *Item1,
TListItem *Item2, int Data, int &Compare);
private: // User declarations
public: // User declarations
__fastcall TLoginAttemptsForm(TComponent* Owner);
int ColumnToSort;
bool SortBackwards;
};
//---------------------------------------------------------------------------
extern PACKAGE TLoginAttemptsForm *LoginAttemptsForm;
//---------------------------------------------------------------------------
#endif
......@@ -71,6 +71,7 @@
#include "PropertiesDlgUnit.h"
#include "ConfigWizardUnit.h"
#include "PreviewFormUnit.h"
#include "LoginAttemptsFormUnit.h"
#include "sbbs_ini.h" // sbbs_read_ini()
#include "userdat.h" // lastuser()
......@@ -151,6 +152,7 @@ link_list_t mail_log_list;
link_list_t ftp_log_list;
link_list_t web_log_list;
link_list_t services_log_list;
link_list_t login_attempt_list;
DWORD MaxLogLen=20000;
int threads=1;
......@@ -826,6 +828,8 @@ __fastcall TMainForm::TMainForm(TComponent* Owner)
UseFileAssociations=true;
Initialized=false;
loginAttemptListInit(&login_attempt_list);
char* p;
if((p=getenv("SBBSCTRL"))!=NULL)
SAFECOPY(global.ctrl_dir,p);
......@@ -855,6 +859,7 @@ __fastcall TMainForm::TMainForm(TComponent* Owner)
bbs_startup.thread_up=thread_up;
bbs_startup.client_on=client_on;
bbs_startup.socket_open=socket_open;
bbs_startup.login_attempt_list=&login_attempt_list;
memset(&mail_startup,0,sizeof(mail_startup));
mail_startup.size=sizeof(mail_startup);
......@@ -879,6 +884,7 @@ __fastcall TMainForm::TMainForm(TComponent* Owner)
mail_startup.lines_per_yield=10;
mail_startup.max_clients=10;
mail_startup.max_msg_size=10*1024*1024;
mail_startup.login_attempt_list=&login_attempt_list;
memset(&ftp_startup,0,sizeof(ftp_startup));
ftp_startup.size=sizeof(ftp_startup);
......@@ -901,6 +907,7 @@ __fastcall TMainForm::TMainForm(TComponent* Owner)
strcpy(ftp_startup.index_file_name,"00index");
strcpy(ftp_startup.html_index_file,"00index.html");
strcpy(ftp_startup.html_index_script,"ftp-html.js");
ftp_startup.login_attempt_list=&login_attempt_list;
memset(&web_startup,0,sizeof(web_startup));
web_startup.size=sizeof(web_startup);
......@@ -915,6 +922,7 @@ __fastcall TMainForm::TMainForm(TComponent* Owner)
web_startup.thread_up=thread_up;
web_startup.client_on=client_on;
web_startup.socket_open=socket_open;
web_startup.login_attempt_list=&login_attempt_list;
memset(&services_startup,0,sizeof(services_startup));
services_startup.size=sizeof(services_startup);
......@@ -930,6 +938,7 @@ __fastcall TMainForm::TMainForm(TComponent* Owner)
services_startup.thread_up=thread_up;
services_startup.client_on=client_on;
services_startup.socket_open=socket_open;
services_startup.login_attempt_list=&login_attempt_list;
bbs_log=INVALID_HANDLE_VALUE;
event_log=INVALID_HANDLE_VALUE;
......@@ -3816,9 +3825,9 @@ TFont* __fastcall TMainForm::LogAttributes(int log_level, TColor Color, TFont* F
return LogFont[log_level];
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ViewLoginAttemptsMenuItemClick(TObject *Sender)
{
LoginAttemptsForm->Show();
}
//---------------------------------------------------------------------------
object MainForm: TMainForm
Left = 538
Top = 491
Left = 290
Top = 545
Width = 640
Height = 400
Caption = 'Synchronet Control Panel'
......@@ -10,7 +10,7 @@ object MainForm: TMainForm
DragMode = dmAutomatic
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -14
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
Icon.Data = {
......@@ -46,11 +46,11 @@ object MainForm: TMainForm
OnCloseQuery = FormCloseQuery
OnCreate = FormCreate
OnShow = FormShow
PixelsPerInch = 120
TextHeight = 16
PixelsPerInch = 96
TextHeight = 13
object HorizontalSplitter: TSplitter
Left = 0
Top = 195
Top = 164
Width = 632
Height = 1
Cursor = crVSplit
......@@ -61,9 +61,9 @@ object MainForm: TMainForm
end
object Logo: TImage
Left = 0
Top = 196
Top = 165
Width = 632
Height = 121
Height = 164
Align = alClient
AutoSize = True
Center = True
......@@ -13499,7 +13499,7 @@ object MainForm: TMainForm
Left = 0
Top = 30
Width = 632
Height = 165
Height = 134
Align = alTop
BevelOuter = bvNone
Constraints.MinHeight = 100
......@@ -13507,18 +13507,18 @@ object MainForm: TMainForm
TabOrder = 1
Visible = False
object TopVerticalSplitter: TSplitter
Left = 289
Left = 235
Top = 0
Width = 3
Height = 165
Width = 2
Height = 134
Cursor = crHSplit
MinSize = 1
end
object UpperLeftPageControl: TPageControl
Left = 0
Top = 0
Width = 289
Height = 165
Width = 235
Height = 134
Align = alLeft
DockSite = True
TabOrder = 0
......@@ -13526,10 +13526,10 @@ object MainForm: TMainForm
OnUnDock = PageControlUnDock
end
object UpperRightPageControl: TPageControl
Left = 292
Left = 237
Top = 0
Width = 340
Height = 165
Width = 395
Height = 134
Align = alClient
DockSite = True
TabOrder = 1
......@@ -13539,26 +13539,26 @@ object MainForm: TMainForm
end
object BottomPanel: TPanel
Left = 0
Top = 196
Top = 165
Width = 632
Height = 121
Height = 164
Align = alClient
BevelOuter = bvNone
TabOrder = 2
Visible = False
object BottomVerticalSplitter: TSplitter
Left = 289
Left = 235
Top = 0
Width = 3
Height = 121
Width = 2
Height = 164
Cursor = crHSplit
MinSize = 1
end
object LowerLeftPageControl: TPageControl
Left = 0
Top = 0
Width = 289
Height = 121
Width = 235
Height = 164
Align = alLeft
DockSite = True
TabOrder = 0
......@@ -13566,10 +13566,10 @@ object MainForm: TMainForm
OnUnDock = PageControlUnDock
end
object LowerRightPageControl: TPageControl
Left = 292
Left = 237
Top = 0
Width = 340
Height = 121
Width = 395
Height = 164
Align = alClient
DockSite = True
TabOrder = 1
......@@ -13579,7 +13579,7 @@ object MainForm: TMainForm
end
object StatusBar: TStatusBar
Left = 0
Top = 317
Top = 329
Width = 632
Height = 25
Panels = <
......@@ -14273,10 +14273,15 @@ object MainForm: TMainForm
ImageIndex = 29
OnClick = ViewLogClick
end
object ViewLoginAttemptsMenuItem: TMenuItem
Caption = 'Login Attempts...'
OnClick = ViewLoginAttemptsMenuItemClick
end
object ViewHackAttemptLogMenuItem: TMenuItem
AutoHotkeys = maManual
Caption = 'Hack Attempt Log...'
Hint = 'HACK.LOG'
ImageIndex = 31
OnClick = ViewLogClick
end
end
......@@ -316,6 +316,7 @@ __published: // IDE-managed Components
TMenuItem *WebPauseMenuItem;
TMenuItem *ServicesPauseMenuItem;
TMenuItem *LogoffMessage;
TMenuItem *ViewLoginAttemptsMenuItem;
void __fastcall FileExitMenuItemClick(TObject *Sender);
void __fastcall ViewToolbarMenuItemClick(TObject *Sender);
void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
......@@ -405,6 +406,7 @@ __published: // IDE-managed Components
void __fastcall WebConfigureExecute(TObject *Sender);
void __fastcall ViewServicesExecute(TObject *Sender);
void __fastcall SemFileTimerTick(TObject *Sender);
void __fastcall ViewLoginAttemptsMenuItemClick(TObject *Sender);
private: // User declarations
public: // User declarations
__fastcall TMainForm(TComponent* Owner);
......
......@@ -12,7 +12,7 @@
EventsFormUnit.obj ConfigWizardUnit.obj ServicesFormUnit.obj
TelnetCfgDlgUnit.obj MailCfgDlgUnit.obj FtpCfgDlgUnit.obj
ServicesCfgDlgUnit.obj ..\sbbs_ini.obj PreviewFormUnit.obj WebFormUnit.obj
WebCfgDlgUnit.obj"/>
WebCfgDlgUnit.obj LoginAttemptsFormUnit.obj"/>
<RESFILES value="sbbsctrl.res"/>
<IDLFILES value=""/>
<IDLGENFILES value=""/>
......@@ -24,7 +24,8 @@
UserListFormUnit.dfm UserMsgFormUnit.dfm PropertiesDlgUnit.dfm
EventsFormUnit.dfm ConfigWizardUnit.dfm ServicesFormUnit.dfm
TelnetCfgDlgUnit.dfm MailCfgDlgUnit.dfm FtpCfgDlgUnit.dfm
ServicesCfgDlgUnit.dfm PreviewFormUnit.dfm WebFormUnit.dfm WebCfgDlgUnit.dfm"/>
ServicesCfgDlgUnit.dfm PreviewFormUnit.dfm WebFormUnit.dfm
WebCfgDlgUnit.dfm LoginAttemptsFormUnit.dfm"/>
<LIBFILES value="sbbs.lib mailsrvr.lib ftpsrvr.lib services.lib
..\..\xpdev\bcc.win32.lib.debug\xpdev_mt.lib websrvr.lib"/>
<LIBRARIES value="bcb2kaxserver.lib indy.lib dbxcds.lib dclocx.lib soaprtl.lib bcbie.lib
......@@ -112,6 +113,7 @@
<FILE FILENAME="..\..\xpdev\bcc.win32.lib.debug\xpdev_mt.lib" FORMNAME="" UNITNAME="xpdev_mt.lib" CONTAINERID="LibTool" DESIGNCLASS="" LOCALCOMMAND=""/>
<FILE FILENAME="websrvr.lib" FORMNAME="" UNITNAME="websrvr.lib" CONTAINERID="LibTool" DESIGNCLASS="" LOCALCOMMAND=""/>
<FILE FILENAME="WebCfgDlgUnit.cpp" FORMNAME="WebCfgDlg" UNITNAME="WebCfgDlgUnit" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
<FILE FILENAME="LoginAttemptsFormUnit.cpp" FORMNAME="LoginAttemptsForm" UNITNAME="LoginAttemptsFormUnit" CONTAINERID="CCompiler" DESIGNCLASS="" LOCALCOMMAND=""/>
</FILELIST>
<BUILDTOOLS>
</BUILDTOOLS>
......@@ -122,7 +124,7 @@ IncludeVerInfo=1
AutoIncBuild=1
MajorVer=3
MinorVer=15
Release=0
Release=1
Build=0
Debug=0
PreRelease=0
......@@ -135,13 +137,13 @@ CodePage=1252
[Version Info Keys]
CompanyName=Rob Swindell
FileDescription=Synchronet BBS Control Panel
FileVersion=3.15.0.0
FileVersion=3.15.1.0
InternalName=
LegalCopyright=(C) 2009 Rob Swindell
LegalCopyright=(C) 2011 Rob Swindell
LegalTrademarks=
OriginalFilename=sbbsctrl.exe
ProductName=Synchronet BBS
ProductVersion=3.15a
ProductVersion=3.15b
Comments=
[HistoryLists\hlIncludePath]
......@@ -205,9 +207,10 @@ Item25=..\;..\..\..\Borland\CBuilder4\Projects;..\Lib;$(BCB)\lib\obj;$(BCB)\lib
Item26=..\..\..\Borland\CBuilder4\Projects;..\Lib;$(BCB)\lib\obj;$(BCB)\lib
[HistoryLists\hlDebugSourcePath]
Count=2
Item0=$(BCB)\source\vcl;C:\src\xpdev\
Item1=$(BCB)\source\vcl
Count=3
Item0=$(BCB)\source\vcl;C:\src\xpdev\;C:\src\sbbs3\
Item1=$(BCB)\source\vcl;C:\src\xpdev\
Item2=$(BCB)\source\vcl
[HistoryLists\hlConditionals]
Count=7
......@@ -239,11 +242,6 @@ ShowInfoMsgs=0
LinkDebugVcl=0
LinkCGLIB=0
[CORBA]
AddServerUnit=1
AddClientUnit=1
PrecompiledHeaders=1
[Language]
ActiveLang=
ProjectLang=
......
......@@ -62,6 +62,7 @@ USEFORM("ServicesCfgDlgUnit.cpp", ServicesCfgDlg);
USEFORM("PreviewFormUnit.cpp", PreviewForm);
USEFORM("WebFormUnit.cpp", WebForm);
USEFORM("WebCfgDlgUnit.cpp", WebCfgDlg);
USEFORM("LoginAttemptsFormUnit.cpp", LoginAttemptsForm);
//---------------------------------------------------------------------------
#include "MainFormUnit.h"
#include "SpyFormUnit.h"
......@@ -87,6 +88,7 @@ WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR cmd, int)
Application->CreateForm(__classid(TUserListForm), &UserListForm);
Application->CreateForm(__classid(TEventsForm), &EventsForm);
Application->CreateForm(__classid(TServicesForm), &ServicesForm);
Application->CreateForm(__classid(TLoginAttemptsForm), &LoginAttemptsForm);
if(cmd[0] && isdir(cmd))
SAFECOPY(MainForm->global.ctrl_dir,cmd);
sbbs_get_ini_fname(MainForm->ini_file, MainForm->global.ctrl_dir, NULL /* auto-hostname */);
......
......@@ -89,7 +89,6 @@ static char revision[16];
static char *text[TOTAL_TEXT];
static str_list_t recycle_semfiles;
static str_list_t shutdown_semfiles;
static link_list_t login_attempt_list;
#ifdef SOCKET_DEBUG
static BYTE socket_debug[0x10000]={0};
......@@ -2340,17 +2339,17 @@ static BOOL badlogin(SOCKET sock, ulong* login_attempts, char* user, char* passw
ulong count;
if(addr!=NULL) {
count=loginFailure(&login_attempt_list, addr, "FTP", user, passwd);
if(count>=LOGIN_ATTEMPT_HACKLOG)
count=loginFailure(startup->login_attempt_list, addr, "FTP", user, passwd);
if(startup->login_attempt_hack_threshold && count>=startup->login_attempt_hack_threshold)
ftp_hacklog("FTP LOGIN", user, passwd, host, addr);
if(count>=LOGIN_ATTEMPT_FILTER)
if(startup->login_attempt_filter_threshold && count>=startup->login_attempt_filter_threshold)
filter_ip(&scfg, "FTP", "- TOO MANY CONSECUTIVE FAILED LOGIN ATTEMPTS"
,host, inet_ntoa(addr->sin_addr), user, /* fname: */NULL);
if(count > *login_attempts)
*login_attempts=count;
}
mswait(LOGIN_ATTEMPT_DELAY); /* As recommended by RFC2577 */
mswait(startup->login_attempt_delay); /* As recommended by RFC2577 */
if(++(*login_attempts)>=3) {
sockprintf(sock,"421 Too many failed login attempts.");
......@@ -2556,10 +2555,11 @@ static void ctrl_thread(void* arg)
client.user="<unknown>";
client_on(sock,&client,FALSE /* update */);
if((login_attempt=loginAttempted(&login_attempt_list, &ftp.client_addr)) != NULL
if(startup->login_attempt_throttle
&& (login_attempt=loginAttempted(startup->login_attempt_list, &ftp.client_addr)) != NULL
&& ((login_attempt_t*)login_attempt->data)->count > 1) {
lprintf(LOG_NOTICE,"%04d Delaying suspicious connection from: %s", sock, inet_ntoa(ftp.client_addr.sin_addr));
mswait(((login_attempt_t*)login_attempt->data)->count*1000);
lprintf(LOG_DEBUG,"%04d Throttling suspicious connection from: %s", sock, inet_ntoa(ftp.client_addr.sin_addr));
mswait(((login_attempt_t*)login_attempt->data)->count*startup->login_attempt_throttle);
}
sockprintf(sock,"220-%s (%s)",scfg.sys_name, startup->host_name);
......@@ -2760,7 +2760,7 @@ static void ctrl_thread(void* arg)
/* Update client display */
if(user.pass[0]) {
client.user=user.alias;