From da141f4c733c7ce1af4b15bf230a9bea439a2fb8 Mon Sep 17 00:00:00 2001
From: rswindell <>
Date: Wed, 14 Sep 2011 03:09:44 +0000
Subject: [PATCH] Implement login attempt tracking/throttling/filtering in the
 terminal server.

---
 src/sbbs3/answer.cpp | 11 ++++++++---
 src/sbbs3/login.cpp  | 20 +++++++++++++++++++-
 src/sbbs3/main.cpp   | 20 +++++++++++++-------
 src/sbbs3/sbbs.h     | 20 ++++++++++++++------
 4 files changed, 54 insertions(+), 17 deletions(-)

diff --git a/src/sbbs3/answer.cpp b/src/sbbs3/answer.cpp
index 5102f87967..2b0bd9ddee 100644
--- a/src/sbbs3/answer.cpp
+++ b/src/sbbs3/answer.cpp
@@ -47,13 +47,11 @@ bool sbbs_t::answer()
 	char 	path[MAX_PATH+1];
 	int		i,l,in;
 	struct tm tm;
-	struct in_addr addr;
 
 	useron.number=0;
 	answertime=logontime=starttime=now=time(NULL);
 	/* Caller ID is IP address */
-	addr.s_addr=client_addr;
-	SAFECOPY(cid,inet_ntoa(addr)); 
+	SAFECOPY(cid,inet_ntoa(client_addr.sin_addr)); 
 
 	memset(&tm,0,sizeof(tm));
     localtime_r(&now,&tm); 
@@ -118,6 +116,7 @@ bool sbbs_t::answer()
 						,rlogin_pass);
 					for(i=0;i<3;i++) {
 						if(stricmp(tmp,useron.pass)) {
+							badlogin(useron.alias, tmp);
 							rioctl(IOFI);       /* flush input buffer */
 							bputs(text[InvalidLogon]);
 							if(cfg.sys_misc&SM_ECHO_PW)
@@ -148,6 +147,7 @@ bool sbbs_t::answer()
 					}
 					if(i) {
 						if(stricmp(tmp,useron.pass)) {
+							badlogin(useron.alias, tmp);
 							bputs(text[InvalidLogon]);
 							if(cfg.sys_misc&SM_ECHO_PW)
 								sprintf(str,"(%04u)  %-25s  FAILED Password attempt: '%s'"
@@ -200,6 +200,7 @@ bool sbbs_t::answer()
 				,rlogin_pass);
 			for(i=0;i<3;i++) {
 				if(stricmp(tmp,useron.pass)) {
+					badlogin(useron.alias, tmp);
 					rioctl(IOFI);       /* flush input buffer */
 					bputs(text[InvalidLogon]);
 					if(cfg.sys_misc&SM_ECHO_PW)
@@ -236,6 +237,7 @@ bool sbbs_t::answer()
 			}
 			if(i) {
 				if(stricmp(tmp,useron.pass)) {
+					badlogin(useron.alias, tmp);
 					bputs(text[InvalidLogon]);
 					if(cfg.sys_misc&SM_ECHO_PW)
 						sprintf(str,"(%04u)  %-25s  FAILED Password attempt: '%s'"
@@ -443,5 +445,8 @@ bool sbbs_t::answer()
 		return(false); 
 	}
 
+	if(useron.pass[0])
+		loginSuccess(startup->login_attempt_list, &client_addr);
+
 	return(true);
 }
diff --git a/src/sbbs3/login.cpp b/src/sbbs3/login.cpp
index 5e0acff77b..838268af84 100644
--- a/src/sbbs3/login.cpp
+++ b/src/sbbs3/login.cpp
@@ -116,6 +116,7 @@ int sbbs_t::login(char *username, char *pw)
 			return(LOGIC_FALSE); 
 		}
 		if(stricmp(useron.pass,str)) {
+			badlogin(useron.alias, str);
 			bputs(text[InvalidLogon]);
 			if(cfg.sys_misc&SM_ECHO_PW) 
 				sprintf(tmp,"(%04u)  %-25s  FAILED Password: '%s' Attempt: '%s'"
@@ -132,8 +133,25 @@ int sbbs_t::login(char *username, char *pw)
 			bputs(text[InvalidLogon]);
 			useron.number=0;
 			useron.misc=useron_misc;
-			return(LOGIC_FALSE); } 
+			return(LOGIC_FALSE); 
+		} 
 	}
 
 	return(LOGIC_TRUE);
 }
+
+void sbbs_t::badlogin(char* user, char* passwd)
+{
+	char reason[128];
+	ulong count;
+
+	SAFEPRINTF(reason,"%s LOGIN", connection);
+	count=loginFailure(startup->login_attempt_list, &client_addr, connection, user, passwd);
+	if(startup->login_attempt_hack_threshold && count>=startup->login_attempt_hack_threshold)
+		hacklog(&cfg, reason, user, passwd, client_name, &client_addr);
+	if(startup->login_attempt_filter_threshold && count>=startup->login_attempt_filter_threshold)
+		filter_ip(&cfg, connection, "- TOO MANY CONSECUTIVE FAILED LOGIN ATTEMPTS"
+			,client_name, inet_ntoa(client_addr.sin_addr), user, /* fname: */NULL);
+
+	mswait(startup->login_attempt_delay);
+}
diff --git a/src/sbbs3/main.cpp b/src/sbbs3/main.cpp
index 2457fdab3e..fdfa73c488 100644
--- a/src/sbbs3/main.cpp
+++ b/src/sbbs3/main.cpp
@@ -2818,7 +2818,7 @@ void event_thread(void* arg)
 
 
 //****************************************************************************
-sbbs_t::sbbs_t(ushort node_num, DWORD addr, const char* name, SOCKET sd,
+sbbs_t::sbbs_t(ushort node_num, SOCKADDR_IN addr, const char* name, SOCKET sd,
 			   scfg_t* global_cfg, char* global_text[], client_t* client_info)
 {
 	char	nodestr[32];
@@ -3442,14 +3442,12 @@ int sbbs_t::nopen(char *str, int access)
 void sbbs_t::spymsg(const char* msg)
 {
 	char str[512];
-	struct in_addr addr;
 
 	if(cfg.node_num<1)
 		return;
 
-	addr.s_addr=client_addr;
 	SAFEPRINTF4(str,"\r\n\r\n*** Spy Message ***\r\nNode %d: %s [%s]\r\n*** %s ***\r\n\r\n"
-		,cfg.node_num,client_name,inet_ntoa(addr),msg);
+		,cfg.node_num,client_name,inet_ntoa(client_addr.sin_addr),msg);
 	if(startup->node_spybuf!=NULL 
 		&& startup->node_spybuf[cfg.node_num-1]!=NULL) {
 		RingBufWrite(startup->node_spybuf[cfg.node_num-1],(uchar*)str,strlen(str));
@@ -3876,6 +3874,7 @@ void node_thread(void* arg)
 	int				file;
 	uint			curshell=0;
 	node_t			node;
+	ulong			login_attempts;
 	sbbs_t*			sbbs = (sbbs_t*) arg;
 
 	update_clients();
@@ -3895,6 +3894,13 @@ void node_thread(void* arg)
 	}
 #endif
 
+	if(startup->login_attempt_throttle
+		&& (login_attempts=loginAttempts(startup->login_attempt_list, &sbbs->client_addr)) > 1) {
+		lprintf(LOG_DEBUG,"Node %d Throttling suspicious connection from: %s (%u login attempts)"
+			,sbbs->cfg.node_num, inet_ntoa(sbbs->client_addr.sin_addr), login_attempts);
+		mswait(login_attempts*startup->login_attempt_throttle);
+	}
+
 	if(sbbs->answer()) {
 
 		if(sbbs->qwklogon) {
@@ -4715,7 +4721,7 @@ void DLLCALL bbs_thread(void* arg)
 NO_SSH:
 #endif
 
-	sbbs = new sbbs_t(0, server_addr.sin_addr.s_addr
+	sbbs = new sbbs_t(0, server_addr
 		,"Terminal Server", telnet_socket, &scfg, text, NULL);
     sbbs->online = 0;
 	if(sbbs->init()==false) {
@@ -4726,7 +4732,7 @@ NO_SSH:
 	_beginthread(output_thread, 0, sbbs);
 
 	if(!(startup->options&BBS_OPT_NO_EVENTS)) {
-		events = new sbbs_t(0, server_addr.sin_addr.s_addr
+		events = new sbbs_t(0, server_addr
 			,"BBS Events", INVALID_SOCKET, &scfg, text, NULL);
 		events->online = 0;
 		if(events->init()==false) {
@@ -5253,7 +5259,7 @@ NO_SSH:
 
         node_socket[i-1]=client_socket;
 
-		sbbs_t* new_node = new sbbs_t(i, client_addr.sin_addr.s_addr, host_name
+		sbbs_t* new_node = new sbbs_t(i, client_addr, host_name
         	,client_socket
 			,&scfg, text, &client);
 
diff --git a/src/sbbs3/sbbs.h b/src/sbbs3/sbbs.h
index 1b78f1b0a9..7a380ba56d 100644
--- a/src/sbbs3/sbbs.h
+++ b/src/sbbs3/sbbs.h
@@ -163,7 +163,7 @@ class sbbs_t
 
 public:
 
-	sbbs_t(ushort node_num, DWORD addr, const char* host_name, SOCKET
+	sbbs_t(ushort node_num, SOCKADDR_IN addr, const char* host_name, SOCKET
 		,scfg_t*, char* text[], client_t* client_info);
 	~sbbs_t();
 
@@ -175,7 +175,7 @@ public:
 	client_t client;
 	SOCKET	client_socket;
 	SOCKET	client_socket_dup;
-	DWORD	client_addr;
+	SOCKADDR_IN	client_addr;
 	char	client_name[128];
 	char	client_ident[128];
 	DWORD	local_addr;
@@ -584,15 +584,23 @@ public:
 	int		putnodedat(uint number, node_t * node);
 	int		putnodeext(uint number, char * str);
 
-	/* logonoff.cpp */
-	bool	answer();
+	/* login.ccp */
 	int		login(char *str, char *pw);
+	void	badlogin(char* user, char* passwd);
+
+	/* answer.cpp */
+	bool	answer();
+
+	/* logon.ccp */
 	bool	logon(void);
+
+	/* logout.cpp */
 	void	logout(void);
-	void	logoff(void);
-	BOOL	newuser(void);					/* Get new user							*/
 	void	backout(void);
 
+	/* newuser.cpp */
+	BOOL	newuser(void);					/* Get new user							*/
+
 	/* text_sec.cpp */
 	int		text_sec(void);						/* Text sections */
 
-- 
GitLab