diff --git a/src/sbbs3/ftpsrvr.c b/src/sbbs3/ftpsrvr.c index 62b62189802c31652ed9c9364cc7ccfc8f58559d..9ab394b11a9339a916b2e1f276d5bea2d7502ba7 100644 --- a/src/sbbs3/ftpsrvr.c +++ b/src/sbbs3/ftpsrvr.c @@ -2243,9 +2243,9 @@ static BOOL badlogin(SOCKET sock, ulong* login_attempts, char* user, char* passw if(addr!=NULL) { count=loginFailure(startup->login_attempt_list, addr, "FTP", user, passwd); - if(startup->login_attempt_hack_threshold && count>=startup->login_attempt_hack_threshold) + if(startup->login_attempt.hack_threshold && count>=startup->login_attempt.hack_threshold) ftp_hacklog("FTP LOGIN", user, passwd, host, addr); - if(startup->login_attempt_filter_threshold && count>=startup->login_attempt_filter_threshold) { + if(startup->login_attempt.filter_threshold && count>=startup->login_attempt.filter_threshold) { inet_addrtop(addr, host_ip, sizeof(host_ip)); filter_ip(&scfg, "FTP", "- TOO MANY CONSECUTIVE FAILED LOGIN ATTEMPTS" ,host, host_ip, user, /* fname: */NULL); @@ -2255,7 +2255,7 @@ static BOOL badlogin(SOCKET sock, ulong* login_attempts, char* user, char* passw } else (*login_attempts)++; - mswait(startup->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."); @@ -2421,8 +2421,9 @@ static void ctrl_thread(void* arg) if(!(startup->options&FTP_OPT_NO_HOST_LOOKUP)) lprintf(LOG_INFO,"%04d Hostname: %s", sock, host_name); - if(trashcan(&scfg,host_ip,"ip")) { - lprintf(LOG_NOTICE,"%04d !CLIENT BLOCKED in ip.can: %s", sock, host_ip); + ulong banned = loginBanned(&scfg, startup->login_attempt_list, &ftp.client_addr, startup->login_attempt); + if((banned && lprintf(LOG_NOTICE, "%04d %s is TEMPORARILY BANNED (%lu more seconds)", socket, host_ip, banned)) + || (trashcan(&scfg,host_ip,"ip") && lprintf(LOG_NOTICE,"%04d !CLIENT BLOCKED in ip.can: %s", sock, host_ip))) { sockprintf(sock,"550 Access denied."); ftp_close_socket(&sock,__LINE__); thread_down(); @@ -2460,11 +2461,11 @@ static void ctrl_thread(void* arg) client.user="<unknown>"; client_on(sock,&client,FALSE /* update */); - if(startup->login_attempt_throttle + if(startup->login_attempt.throttle && (login_attempts=loginAttempts(startup->login_attempt_list, &ftp.client_addr)) > 1) { lprintf(LOG_DEBUG,"%04d Throttling suspicious connection from: %s (%u login attempts)" ,sock, host_ip, login_attempts); - mswait(login_attempts*startup->login_attempt_throttle); + mswait(login_attempts*startup->login_attempt.throttle); } sockprintf(sock,"220-%s (%s)",scfg.sys_name, startup->host_name); diff --git a/src/sbbs3/ftpsrvr.h b/src/sbbs3/ftpsrvr.h index ff0ad17aacf1df53912d2af4039135d27eaee200..540bbff1d53d2fbc85eb2253c492a7027b50fc70 100644 --- a/src/sbbs3/ftpsrvr.h +++ b/src/sbbs3/ftpsrvr.h @@ -100,10 +100,7 @@ typedef struct { js_startup_t js; /* Login Attempt parameters */ - ulong login_attempt_delay; - ulong login_attempt_throttle; - ulong login_attempt_hack_threshold; - ulong login_attempt_filter_threshold; + struct login_attempt_settings login_attempt; link_list_t* login_attempt_list; } ftp_startup_t; diff --git a/src/sbbs3/login.cpp b/src/sbbs3/login.cpp index 62526b6d94fdeedba7e7dfd9164252519e703a18..6de4ba711e2d278b2b289de0b281b02b76203006 100644 --- a/src/sbbs3/login.cpp +++ b/src/sbbs3/login.cpp @@ -148,11 +148,11 @@ void sbbs_t::badlogin(char* user, char* passwd) 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) + 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) + if(startup->login_attempt.filter_threshold && count>=startup->login_attempt.filter_threshold) filter_ip(&cfg, connection, "- TOO MANY CONSECUTIVE FAILED LOGIN ATTEMPTS" ,client_name, client_ipaddr, user, /* fname: */NULL); - mswait(startup->login_attempt_delay); + mswait(startup->login_attempt.delay); } diff --git a/src/sbbs3/mailsrvr.c b/src/sbbs3/mailsrvr.c index d6aa5d47b32356260ed35a3ef2860cac6501df9d..ace13203031c66f051c2b742f01e2a9e44f40d92 100644 --- a/src/sbbs3/mailsrvr.c +++ b/src/sbbs3/mailsrvr.c @@ -522,7 +522,7 @@ static ulong sockmimetext(SOCKET socket, smbmsg_t* msg, char* msgtxt, ulong maxl s=sockprintf(socket,"From: %s",p); /* use original RFC822 header field */ else { char fromname[256]; - SAFECOPY(fromname, msg->from); + SAFEPRINTF(fromname, "\"%s\"", msg->from); if(msg->from_net.type==NET_QWK && msg->from_net.addr!=NULL) SAFEPRINTF2(fromaddr,"%s!%s" ,(char*)msg->from_net.addr @@ -530,7 +530,7 @@ static ulong sockmimetext(SOCKET socket, smbmsg_t* msg, char* msgtxt, ulong maxl else if(msg->from_net.type==NET_FIDO && msg->from_net.addr!=NULL) { faddr_t* faddr = (faddr_t *)msg->from_net.addr; char faddrstr[128]; - SAFEPRINTF2(fromname,"%s (%s)", msg->from, smb_faddrtoa(faddr, NULL)); + SAFEPRINTF2(fromname,"\"%s\" (%s)", msg->from, smb_faddrtoa(faddr, NULL)); if(faddr->point) SAFEPRINTF4(faddrstr,"p%hu.f%hu.n%hu.z%hu"FIDO_TLD ,faddr->point, faddr->node, faddr->net, faddr->zone); @@ -543,9 +543,9 @@ static ulong sockmimetext(SOCKET socket, smbmsg_t* msg, char* msgtxt, ulong maxl else usermailaddr(&scfg,fromaddr,msg->from); if(fromaddr[0]=='<') - s=sockprintf(socket,"From: \"%s\" %s",fromname,fromaddr); + s=sockprintf(socket,"From: %s %s",fromname,fromaddr); else - s=sockprintf(socket,"From: \"%s\" <%s>",fromname,fromaddr); + s=sockprintf(socket,"From: %s <%s>",fromname,fromaddr); } if(!s) return(0); @@ -569,7 +569,7 @@ static ulong sockmimetext(SOCKET socket, smbmsg_t* msg, char* msgtxt, ulong maxl else s=sockprintf(socket,"To: \"%s\" <%s>",msg->to,(char*)msg->to_net.addr); } else if(msg->to_net.type==NET_FIDO) { - s=sockprintf(socket,"To: \"%s (%s)\"",msg->to, smb_faddrtoa((fidoaddr_t*)msg->to_net.addr, NULL)); + s=sockprintf(socket,"To: \"%s\" (%s)",msg->to, smb_faddrtoa((fidoaddr_t*)msg->to_net.addr, NULL)); } else { usermailaddr(&scfg,toaddr,msg->to); s=sockprintf(socket,"To: \"%s\" <%s>",msg->to,toaddr); @@ -782,15 +782,15 @@ static void badlogin(SOCKET sock, const char* prot, const char* resp, char* user if(addr!=NULL) { SAFEPRINTF(reason,"%s LOGIN", prot); count=loginFailure(startup->login_attempt_list, addr, prot, user, passwd); - if(startup->login_attempt_hack_threshold && count>=startup->login_attempt_hack_threshold) + if(startup->login_attempt.hack_threshold && count>=startup->login_attempt.hack_threshold) hacklog(&scfg, reason, user, passwd, host, addr); inet_addrtop(addr, ip, sizeof(ip)); - if(startup->login_attempt_filter_threshold && count>=startup->login_attempt_filter_threshold) + if(startup->login_attempt.filter_threshold && count>=startup->login_attempt.filter_threshold) filter_ip(&scfg, (char*)prot, "- TOO MANY CONSECUTIVE FAILED LOGIN ATTEMPTS" ,host, ip, user, /* fname: */NULL); } - mswait(startup->login_attempt_delay); + mswait(startup->login_attempt.delay); sockprintf(sock,(char*)resp); } @@ -853,9 +853,9 @@ static void pop3_thread(void* arg) if(!(startup->options&MAIL_OPT_NO_HOST_LOOKUP) && (startup->options&MAIL_OPT_DEBUG_POP3)) lprintf(LOG_INFO,"%04d POP3 Hostname: %s", socket, host_name); - if(trashcan(&scfg,host_ip,"ip")) { - lprintf(LOG_NOTICE,"%04d !POP3 CLIENT IP ADDRESS BLOCKED: %s" - ,socket, host_ip); + ulong banned = loginBanned(&scfg, startup->login_attempt_list, &pop3.client_addr, startup->login_attempt); + if((banned && lprintf(LOG_NOTICE, "%04d %s is TEMPORARILY BANNED (%lu more seconds)", socket, host_ip, banned)) + || (trashcan(&scfg,host_ip,"ip") && lprintf(LOG_NOTICE,"%04d !POP3 CLIENT IP ADDRESS BLOCKED: %s",socket, host_ip))) { sockprintf(socket,"-ERR Access denied."); mail_close_socket(socket); thread_down(); @@ -887,11 +887,11 @@ static void pop3_thread(void* arg) SAFEPRINTF(str,"POP3: %s", host_ip); status(str); - if(startup->login_attempt_throttle + if(startup->login_attempt.throttle && (login_attempts=loginAttempts(startup->login_attempt_list, &pop3.client_addr)) > 1) { lprintf(LOG_DEBUG,"%04d POP3 Throttling suspicious connection from: %s (%u login attempts)" ,socket, host_ip, login_attempts); - mswait(login_attempts*startup->login_attempt_throttle); + mswait(login_attempts*startup->login_attempt.throttle); } mail=NULL; @@ -2217,6 +2217,24 @@ static int chk_received_hdr(SOCKET socket,const char *buf,IN_ADDR *dnsbl_result, return(dnsbl_result->s_addr); } +static void strip_char(char* str, char ch) +{ + char* src; + char* p; + char* tmp = strdup(str); + + if(tmp == NULL) + return; + p=tmp; + for(src = str; *src; src++) { + if(*src != ch) + *(p++) = *src; + } + *p=0; + strcpy(str, tmp); + free(tmp); +} + static void parse_mail_address(char* p ,char* name, size_t name_len ,char* addr, size_t addr_len) @@ -2238,20 +2256,21 @@ static void parse_mail_address(char* p SAFECOPY(tmp,p); p=tmp; /* Get the "name" (if possible) */ - if((tp=strchr(p,'('))!=NULL) { /* name in parenthesis? */ + if((tp=strchr(p,'"'))!=NULL) { /* name in quotes? */ p=tp+1; - tp=strchr(p,')'); - } else if((tp=strchr(p,'"'))!=NULL) { /* name in quotes? */ + tp=strrchr(p,'"'); + } else if((tp=strchr(p,'('))!=NULL) { /* name in parenthesis? */ p=tp+1; - tp=strchr(p,'"'); + tp=strrchr(p,')'); } else if(*p=='<') { /* address in brackets? */ p++; - tp=strchr(p,'>'); + tp=strrchr(p,'>'); } else /* name, then address in brackets */ tp=strchr(p,'<'); if(tp) *tp=0; sprintf(name,"%.*s",(int)name_len,p); truncsp(name); + strip_char(name, '\\'); } /* Decode quoted-printable content-transfer-encoded text */ @@ -2377,7 +2396,8 @@ static void smtp_thread(void* arg) char spam_bait[MAX_PATH+1]; BOOL spam_bait_result=FALSE; char spam_block[MAX_PATH+1]; - char spam_block_exempt[MAX_PATH+1]; + char spam_block_exemptions[MAX_PATH+1]; + BOOL spam_block_exempt=FALSE; char host_name[128]; char host_ip[INET6_ADDRSTRLEN]; char server_ip[INET6_ADDRSTRLEN]; @@ -2528,7 +2548,7 @@ static void smtp_thread(void* arg) SAFEPRINTF(spam_bait,"%sspambait.cfg",scfg.ctrl_dir); SAFEPRINTF(spam_block,"%sspamblock.cfg",scfg.ctrl_dir); - SAFEPRINTF(spam_block_exempt,"%sspamblock_exempt.cfg",scfg.ctrl_dir); + SAFEPRINTF(spam_block_exemptions,"%sspamblock_exempt.cfg",scfg.ctrl_dir); inet_addrtop(&server_addr,server_ip,sizeof(server_ip)); @@ -2536,8 +2556,20 @@ static void smtp_thread(void* arg) /* local connection */ dnsbl_result.s_addr=0; } else { + ulong banned = loginBanned(&scfg, startup->login_attempt_list, &smtp.client_addr, startup->login_attempt); + if(banned) { + lprintf(LOG_NOTICE, "%04d %s is TEMPORARILY BANNED (%lu more seconds)", socket, host_ip, banned); + mail_close_socket(socket); + thread_down(); + protected_uint32_adjust(&active_clients, -1); + update_clients(); + free(mailproc_to_match); + return; + } + + spam_block_exempt = findstr(host_ip,spam_block_exemptions) || findstr(host_name,spam_block_exemptions); if(trashcan(&scfg,host_ip,"ip") - || (findstr(host_ip,spam_block) && !findstr(host_ip,spam_block_exempt))) { + || (findstr(host_ip,spam_block) && !spam_block_exempt)) { lprintf(LOG_NOTICE,"%04d !SMTP CLIENT IP ADDRESS BLOCKED: %s (%u total)" ,socket, host_ip, ++stats.sessions_refused); sockprintf(socket,"550 CLIENT IP ADDRESS BLOCKED: %s", host_ip); @@ -2550,7 +2582,7 @@ static void smtp_thread(void* arg) } if(trashcan(&scfg,host_name,"host") - || (findstr(host_name,spam_block) && !findstr(host_name,spam_block_exempt))) { + || (findstr(host_name,spam_block) && !spam_block_exempt)) { lprintf(LOG_NOTICE,"%04d !SMTP CLIENT HOSTNAME BLOCKED: %s (%u total)" ,socket, host_name, ++stats.sessions_refused); sockprintf(socket,"550 CLIENT HOSTNAME BLOCKED: %s", host_name); @@ -2641,11 +2673,11 @@ static void smtp_thread(void* arg) SAFEPRINTF(str,"SMTP: %s",host_ip); status(str); - if(startup->login_attempt_throttle + if(startup->login_attempt.throttle && (login_attempts=loginAttempts(startup->login_attempt_list, &smtp.client_addr)) > 1) { lprintf(LOG_DEBUG,"%04d SMTP Throttling suspicious connection from: %s (%u login attempts)" ,socket, host_ip, login_attempts); - mswait(login_attempts*startup->login_attempt_throttle); + mswait(login_attempts*startup->login_attempt.throttle); } /* SMTP session active: */ @@ -3849,8 +3881,7 @@ static void smtp_thread(void* arg) if(relay_user.number==0) { strcpy(tmp,"IGNORED"); if(dnsbl_result.s_addr==0 /* Don't double-filter */ - && !findstr(host_name,spam_block_exempt) - && !findstr(host_ip,spam_block_exempt)) { + && !spam_block_exempt) { lprintf(LOG_NOTICE,"%04d !BLOCKING IP ADDRESS: %s in %s", socket, host_ip, spam_block); filter_ip(&scfg, "SMTP", reason, host_name, host_ip, reverse_path, spam_block); strcat(tmp," and BLOCKED"); diff --git a/src/sbbs3/mailsrvr.h b/src/sbbs3/mailsrvr.h index e8aae6b8fb854be7d845eb5da2ca11f518e3ac45..7af590539ca80ba82fa12cc63151097f820ec379 100644 --- a/src/sbbs3/mailsrvr.h +++ b/src/sbbs3/mailsrvr.h @@ -8,7 +8,7 @@ * @format.tab-size 4 (Plain Text/Source Code File Header) * * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * * * - * Copyright 2014 Rob Swindell - http://www.synchro.net/copyright.html * + * Copyright 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 * @@ -120,10 +120,7 @@ typedef struct { js_startup_t js; /* Login Attempt parameters */ - ulong login_attempt_delay; - ulong login_attempt_throttle; - ulong login_attempt_hack_threshold; - ulong login_attempt_filter_threshold; + struct login_attempt_settings login_attempt; link_list_t* login_attempt_list; } mail_startup_t; diff --git a/src/sbbs3/main.cpp b/src/sbbs3/main.cpp index ff8e95b9f3e11a18d4acfeddaffc431d126a7036..226518607f1af1f51d962ebb8b30861c11f98134 100644 --- a/src/sbbs3/main.cpp +++ b/src/sbbs3/main.cpp @@ -4146,11 +4146,11 @@ void node_thread(void* arg) } #endif - if(startup->login_attempt_throttle + 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, sbbs->client_ipaddr, login_attempts); - mswait(login_attempts*startup->login_attempt_throttle); + mswait(login_attempts*startup->login_attempt.throttle); } if(sbbs->answer()) { @@ -5121,6 +5121,16 @@ NO_SSH: #endif , host_ip, inet_addrport(&client_addr)); + ulong banned = loginBanned(&scfg, startup->login_attempt_list, &client_addr, startup->login_attempt); + if((banned && lprintf(LOG_NOTICE, "%04d %s is TEMPORARILY BANNED (%lu more seconds)", client_socket, host_ip, banned)) + || (sbbs->trashcan(host_ip,"ip") && lprintf(LOG_NOTICE,"%04d !CLIENT BLOCKED in ip.can: %s", client_socket, host_ip))) { + SSH_END(); + close_socket(client_socket); + SAFEPRINTF(logstr, "Blocked IP: %s",host_ip); + sbbs->syslog("@!",logstr); + continue; + } + #ifdef _WIN32 if(startup->answer_sound[0] && !(startup->options&BBS_OPT_MUTE)) PlaySound(startup->answer_sound, NULL, SND_ASYNC|SND_FILENAME); @@ -5202,16 +5212,6 @@ NO_SSH: sbbs->client_socket=client_socket; // required for output to the user sbbs->online=ON_REMOTE; - if(sbbs->trashcan(host_ip,"ip")) { - SSH_END(); - close_socket(client_socket); - lprintf(LOG_NOTICE,"%04d !CLIENT BLOCKED in ip.can: %s" - ,client_socket, host_ip); - SAFEPRINTF(logstr, "Blocked IP: %s",host_ip); - sbbs->syslog("@!",logstr); - continue; - } - if(rlogin) sbbs->outcom(0); /* acknowledge RLogin per RFC 1282 */ diff --git a/src/sbbs3/sbbs_ini.c b/src/sbbs3/sbbs_ini.c index 1651ef109e1b235743f32d968c9cfe3e5cf76411..1162e3fd6cdaa0f73295a54972e48a88ac5526af 100644 --- a/src/sbbs3/sbbs_ini.c +++ b/src/sbbs3/sbbs_ini.c @@ -64,6 +64,8 @@ static const char* strHackAttemptSound="HackAttemptSound"; static const char* strLoginAttemptDelay="LoginAttemptDelay"; static const char* strLoginAttemptThrottle="LoginAttemptThrottle"; static const char* strLoginAttemptHackThreshold="LoginAttemptHackThreshold"; +static const char* strLoginAttemptTempBanThreshold="LoginAttemptTempBanThreshold"; +static const char* strLoginAttemptTempBanDuration="LoginAttemptTempBanDuration"; static const char* strLoginAttemptFilterThreshold="LoginAttemptFilterThreshold"; static const char* strJavaScriptMaxBytes ="JavaScriptMaxBytes"; static const char* strJavaScriptContextStack ="JavaScriptContextStack"; @@ -76,10 +78,6 @@ static const char* strSemFileCheckFrequency ="SemFileCheckFrequency"; #define DEFAULT_LOG_LEVEL LOG_DEBUG #define DEFAULT_BIND_RETRY_COUNT 2 #define DEFAULT_BIND_RETRY_DELAY 15 -#define DEFAULT_LOGIN_ATTEMPT_DELAY 5000 /* milliseconds */ -#define DEFAULT_LOGIN_ATTEMPT_THROTTLE 1000 /* milliseconds */ -#define DEFAULT_LOGIN_ATTEMPT_HACKLOG 10 /* write to hack.log after this many consecutive unique attempts */ -#define DEFAULT_LOGIN_ATTEMPT_FILTER 0 /* filter client IP address after this many consecutive unique attempts */ void sbbs_get_ini_fname(char* ini_file, char* ctrl_dir, char* pHostName) { @@ -190,6 +188,29 @@ BOOL sbbs_set_js_settings( return(!failure); } +static struct login_attempt_settings get_login_attempt_settings(str_list_t list, const char* section, global_startup_t* global) +{ + struct login_attempt_settings settings; + + settings.delay =iniGetInteger(list,section,strLoginAttemptDelay ,global == NULL ? 5000 : global->login_attempt.delay); + settings.throttle =iniGetInteger(list,section,strLoginAttemptThrottle ,global == NULL ? 1000 : global->login_attempt.throttle); + settings.hack_threshold =iniGetInteger(list,section,strLoginAttemptHackThreshold ,global == NULL ? 10 : global->login_attempt.hack_threshold); + settings.tempban_threshold =iniGetInteger(list,section,strLoginAttemptTempBanThreshold ,global == NULL ? 20 : global->login_attempt.tempban_threshold); + settings.tempban_duration =iniGetInteger(list,section,strLoginAttemptTempBanDuration ,global == NULL ? (10*60) : global->login_attempt.tempban_duration); + settings.filter_threshold =iniGetInteger(list,section,strLoginAttemptFilterThreshold ,global == NULL ? 0 : global->login_attempt.filter_threshold); + return settings; +} + +static void set_login_attempt_settings(str_list_t* lp, const char* section, struct login_attempt_settings settings, ini_style_t style) +{ + iniSetInteger(lp,section,strLoginAttemptDelay,settings.delay,&style); + iniSetInteger(lp,section,strLoginAttemptThrottle,settings.throttle,&style); + iniSetInteger(lp,section,strLoginAttemptHackThreshold,settings.hack_threshold,&style); + iniSetInteger(lp,section,strLoginAttemptTempBanThreshold,settings.tempban_threshold,&style); + iniSetInteger(lp,section,strLoginAttemptTempBanDuration,settings.tempban_duration,&style); + iniSetInteger(lp,section,strLoginAttemptFilterThreshold,settings.filter_threshold,&style); +} + static void get_ini_globals(str_list_t list, global_startup_t* global) { const char* section = "Global"; @@ -221,10 +242,7 @@ static void get_ini_globals(str_list_t list, global_startup_t* global) global->log_level=iniGetLogLevel(list,section,strLogLevel,DEFAULT_LOG_LEVEL); global->bind_retry_count=iniGetInteger(list,section,strBindRetryCount,DEFAULT_BIND_RETRY_COUNT); global->bind_retry_delay=iniGetInteger(list,section,strBindRetryDelay,DEFAULT_BIND_RETRY_DELAY); - global->login_attempt_delay=iniGetInteger(list,section,strLoginAttemptDelay,DEFAULT_LOGIN_ATTEMPT_DELAY); - global->login_attempt_throttle=iniGetInteger(list,section,strLoginAttemptThrottle,DEFAULT_LOGIN_ATTEMPT_THROTTLE); - global->login_attempt_hack_threshold=iniGetInteger(list,section,strLoginAttemptHackThreshold,DEFAULT_LOGIN_ATTEMPT_HACKLOG); - global->login_attempt_filter_threshold=iniGetInteger(list,section,strLoginAttemptFilterThreshold,DEFAULT_LOGIN_ATTEMPT_FILTER); + global->login_attempt = get_login_attempt_settings(list, section, NULL); /* Setup default values here */ global->js.max_bytes = JAVASCRIPT_MAX_BYTES; @@ -375,10 +393,8 @@ void sbbs_read_ini( bbs->bind_retry_count=iniGetInteger(list,section,strBindRetryCount,global->bind_retry_count); bbs->bind_retry_delay=iniGetInteger(list,section,strBindRetryDelay,global->bind_retry_delay); - bbs->login_attempt_delay=iniGetInteger(list,section,strLoginAttemptDelay,global->login_attempt_delay); - bbs->login_attempt_throttle=iniGetInteger(list,section,strLoginAttemptThrottle,global->login_attempt_throttle); - bbs->login_attempt_hack_threshold=iniGetInteger(list,section,strLoginAttemptHackThreshold,global->login_attempt_hack_threshold); - bbs->login_attempt_filter_threshold=iniGetInteger(list,section,strLoginAttemptFilterThreshold,global->login_attempt_filter_threshold); + + bbs->login_attempt = get_login_attempt_settings(list, section, global); } /***********************************************************************/ @@ -453,10 +469,7 @@ void sbbs_read_ini( ftp->bind_retry_count=iniGetInteger(list,section,strBindRetryCount,global->bind_retry_count); ftp->bind_retry_delay=iniGetInteger(list,section,strBindRetryDelay,global->bind_retry_delay); - ftp->login_attempt_delay=iniGetInteger(list,section,strLoginAttemptDelay,global->login_attempt_delay); - ftp->login_attempt_throttle=iniGetInteger(list,section,strLoginAttemptThrottle,global->login_attempt_throttle); - ftp->login_attempt_hack_threshold=iniGetInteger(list,section,strLoginAttemptHackThreshold,global->login_attempt_hack_threshold); - ftp->login_attempt_filter_threshold=iniGetInteger(list,section,strLoginAttemptFilterThreshold,global->login_attempt_filter_threshold); + ftp->login_attempt = get_login_attempt_settings(list, section, global); } /***********************************************************************/ @@ -551,10 +564,7 @@ void sbbs_read_ini( mail->bind_retry_count=iniGetInteger(list,section,strBindRetryCount,global->bind_retry_count); mail->bind_retry_delay=iniGetInteger(list,section,strBindRetryDelay,global->bind_retry_delay); - mail->login_attempt_delay=iniGetInteger(list,section,strLoginAttemptDelay,global->login_attempt_delay); - mail->login_attempt_throttle=iniGetInteger(list,section,strLoginAttemptThrottle,global->login_attempt_throttle); - mail->login_attempt_hack_threshold=iniGetInteger(list,section,strLoginAttemptHackThreshold,global->login_attempt_hack_threshold); - mail->login_attempt_filter_threshold=iniGetInteger(list,section,strLoginAttemptFilterThreshold,global->login_attempt_filter_threshold); + mail->login_attempt = get_login_attempt_settings(list, section, global); } /***********************************************************************/ @@ -598,10 +608,7 @@ void sbbs_read_ini( services->bind_retry_count=iniGetInteger(list,section,strBindRetryCount,global->bind_retry_count); services->bind_retry_delay=iniGetInteger(list,section,strBindRetryDelay,global->bind_retry_delay); - services->login_attempt_delay=iniGetInteger(list,section,strLoginAttemptDelay,global->login_attempt_delay); - services->login_attempt_throttle=iniGetInteger(list,section,strLoginAttemptThrottle,global->login_attempt_throttle); - services->login_attempt_hack_threshold=iniGetInteger(list,section,strLoginAttemptHackThreshold,global->login_attempt_hack_threshold); - services->login_attempt_filter_threshold=iniGetInteger(list,section,strLoginAttemptFilterThreshold,global->login_attempt_filter_threshold); + services->login_attempt = get_login_attempt_settings(list, section, global); } /***********************************************************************/ @@ -695,10 +702,7 @@ void sbbs_read_ini( web->bind_retry_count=iniGetInteger(list,section,strBindRetryCount,global->bind_retry_count); web->bind_retry_delay=iniGetInteger(list,section,strBindRetryDelay,global->bind_retry_delay); - web->login_attempt_delay=iniGetInteger(list,section,strLoginAttemptDelay,global->login_attempt_delay); - web->login_attempt_throttle=iniGetInteger(list,section,strLoginAttemptThrottle,global->login_attempt_throttle); - web->login_attempt_hack_threshold=iniGetInteger(list,section,strLoginAttemptHackThreshold,global->login_attempt_hack_threshold); - web->login_attempt_filter_threshold=iniGetInteger(list,section,strLoginAttemptFilterThreshold,global->login_attempt_filter_threshold); + web->login_attempt = get_login_attempt_settings(list, section, global); } free(global_interfaces); @@ -758,10 +762,7 @@ BOOL sbbs_write_ini( iniSetLogLevel(lp,section,strLogLevel,global->log_level,&style); iniSetInteger(lp,section,strBindRetryCount,global->bind_retry_count,&style); iniSetInteger(lp,section,strBindRetryDelay,global->bind_retry_delay,&style); - iniSetInteger(lp,section,strLoginAttemptDelay,global->login_attempt_delay,&style); - iniSetInteger(lp,section,strLoginAttemptThrottle,global->login_attempt_throttle,&style); - iniSetInteger(lp,section,strLoginAttemptHackThreshold,global->login_attempt_hack_threshold,&style); - iniSetInteger(lp,section,strLoginAttemptFilterThreshold,global->login_attempt_filter_threshold,&style); + set_login_attempt_settings(lp, section, global->login_attempt, style); /* JavaScript operating parameters */ if(!sbbs_set_js_settings(lp,section,&global->js,NULL,&style)) diff --git a/src/sbbs3/services.c b/src/sbbs3/services.c index 0477f66683a43889daaddd38be6730dd1810b3fc..5cb5e10e70de879999a8627c801443daa3ba1e27 100644 --- a/src/sbbs3/services.c +++ b/src/sbbs3/services.c @@ -331,15 +331,15 @@ static void badlogin(SOCKET sock, char* prot, char* user, char* passwd, char* ho SAFEPRINTF(reason,"%s LOGIN", prot); count=loginFailure(startup->login_attempt_list, addr, prot, user, passwd); - if(startup->login_attempt_hack_threshold && count>=startup->login_attempt_hack_threshold) + if(startup->login_attempt.hack_threshold && count>=startup->login_attempt.hack_threshold) hacklog(&scfg, reason, user, passwd, host, addr); - if(startup->login_attempt_filter_threshold && count>=startup->login_attempt_filter_threshold) { + if(startup->login_attempt.filter_threshold && count>=startup->login_attempt.filter_threshold) { inet_addrtop(addr, addr_ip, sizeof(addr_ip)); filter_ip(&scfg, prot, "- TOO MANY CONSECUTIVE FAILED LOGIN ATTEMPTS" ,host, addr_ip, user, /* fname: */NULL); } - mswait(startup->login_attempt_delay); + mswait(startup->login_attempt.delay); } static JSBool @@ -1085,11 +1085,11 @@ static void js_service_thread(void* arg) update_clients(); - if(startup->login_attempt_throttle + if(startup->login_attempt.throttle && (login_attempts=loginAttempts(startup->login_attempt_list, &service_client.addr)) > 1) { lprintf(LOG_DEBUG,"%04d %s Throttling suspicious connection from: %s (%u login attempts)" ,socket, service->protocol, client.addr, login_attempts); - mswait(login_attempts*startup->login_attempt_throttle); + mswait(login_attempts*startup->login_attempt.throttle); } /* RUN SCRIPT */ @@ -1427,11 +1427,11 @@ static void native_service_thread(void* arg) /* Initialize client display */ client_on(socket,&client,FALSE /* update */); - if(startup->login_attempt_throttle + if(startup->login_attempt.throttle && (login_attempts=loginAttempts(startup->login_attempt_list, &service_client.addr)) > 1) { lprintf(LOG_DEBUG,"%04d %s Throttling suspicious connection from: %s (%u login attempts)" ,socket, service->protocol, client.addr, login_attempts); - mswait(login_attempts*startup->login_attempt_throttle); + mswait(login_attempts*startup->login_attempt.throttle); } /* RUN SCRIPT */ @@ -2104,21 +2104,22 @@ void DLLCALL services_thread(void* arg) continue; } - #ifdef _WIN32 - if(startup->answer_sound[0] && !(startup->options&BBS_OPT_MUTE) - && !(service[i].options&BBS_OPT_MUTE)) - PlaySound(startup->answer_sound, NULL, SND_ASYNC|SND_FILENAME); - #endif - - if(trashcan(&scfg,host_ip,"ip")) { + ulong banned = loginBanned(&scfg, startup->login_attempt_list, &client_addr, startup->login_attempt); + if((banned && lprintf(LOG_NOTICE, "%04d %s is TEMPORARILY BANNED (%lu more seconds)", socket, host_ip, banned)) + || (trashcan(&scfg,host_ip,"ip") && lprintf(LOG_NOTICE,"%04d !%s CLIENT BLOCKED in ip.can: %s" + ,client_socket, service[i].protocol, host_ip))) { FREE_AND_NULL(udp_buf); - lprintf(LOG_NOTICE,"%04d !%s CLIENT BLOCKED in ip.can: %s" - ,client_socket, service[i].protocol, host_ip); mswait(3000); close_socket(client_socket); continue; } + #ifdef _WIN32 + if(startup->answer_sound[0] && !(startup->options&BBS_OPT_MUTE) + && !(service[i].options&BBS_OPT_MUTE)) + PlaySound(startup->answer_sound, NULL, SND_ASYNC|SND_FILENAME); + #endif + if((client=malloc(sizeof(service_client_t)))==NULL) { FREE_AND_NULL(udp_buf); lprintf(LOG_CRIT,"%04d !%s ERROR allocating %u bytes of memory for service_client" diff --git a/src/sbbs3/services.h b/src/sbbs3/services.h index 642073f62c311fd8c1fea72d69150bc3d30ee73d..662d9e92a226d29ca62447c84e4152951658b21f 100644 --- a/src/sbbs3/services.h +++ b/src/sbbs3/services.h @@ -8,7 +8,7 @@ * @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 * + * Copyright 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 * @@ -83,10 +83,7 @@ typedef struct { js_startup_t js; /* Login Attempt parameters */ - ulong login_attempt_delay; - ulong login_attempt_throttle; - ulong login_attempt_hack_threshold; - ulong login_attempt_filter_threshold; + struct login_attempt_settings login_attempt; link_list_t* login_attempt_list; } services_startup_t; diff --git a/src/sbbs3/startup.h b/src/sbbs3/startup.h index 5be96476f241f07f17a397baa3d4fdabab59205c..f6b839225e4fe9fbccd77bc47f2478afa4207722 100644 --- a/src/sbbs3/startup.h +++ b/src/sbbs3/startup.h @@ -58,6 +58,16 @@ typedef struct { char load_path[INI_MAX_VALUE_LEN]; /* additional (comma-separated) directories to search for load()ed scripts */ } js_startup_t; +/* Login Attempt parameters */ +struct login_attempt_settings { + ulong delay; /* in milliseconds */ + ulong throttle; /* in milliseconds */ + ulong hack_threshold; + ulong tempban_threshold; + ulong tempban_duration; /* in seconds */ + ulong filter_threshold; +}; + typedef struct { char ctrl_dir[INI_MAX_VALUE_LEN]; @@ -71,10 +81,7 @@ typedef struct { js_startup_t js; uint bind_retry_count; /* Number of times to retry bind() calls */ uint bind_retry_delay; /* Time to wait between each bind() retry */ - ulong login_attempt_delay; - ulong login_attempt_throttle; - ulong login_attempt_hack_threshold; - ulong login_attempt_filter_threshold; + struct login_attempt_settings login_attempt; } global_startup_t; @@ -137,11 +144,7 @@ typedef struct { /* JavaScript operating parameters */ js_startup_t js; - /* Login Attempt parameters */ - ulong login_attempt_delay; - ulong login_attempt_throttle; - ulong login_attempt_hack_threshold; - ulong login_attempt_filter_threshold; + struct login_attempt_settings login_attempt; link_list_t* login_attempt_list; } bbs_startup_t; diff --git a/src/sbbs3/userdat.c b/src/sbbs3/userdat.c index 04ad99055abbc77da71938a7fab899f8af0b1a82..eee753febcc91bc5d453072bd67f0e80f973978b 100644 --- a/src/sbbs3/userdat.c +++ b/src/sbbs3/userdat.c @@ -2888,7 +2888,7 @@ ulong DLLCALL loginFailure(link_list_t* list, const union xp_sockaddr* addr, con SAFECOPY(attempt->user, user); SAFECOPY(attempt->pass, pass); attempt->count++; - count = attempt->count-attempt->dupes; + count = attempt->count - attempt->dupes; if(node==NULL) listPushNodeData(list, attempt, sizeof(login_attempt_t)); listUnlock(list); @@ -2896,6 +2896,26 @@ ulong DLLCALL loginFailure(link_list_t* list, const union xp_sockaddr* addr, con return count; } +ulong DLLCALL loginBanned(scfg_t* cfg, link_list_t* list, const union xp_sockaddr* addr, struct login_attempt_settings settings) +{ + list_node_t* node; + login_attempt_t* attempt; + BOOL result = FALSE; + long diff; + time32_t now = time32(NULL); + + listLock(list); + node = login_attempted(list, addr); + listUnlock(list); + if(node == NULL) + return 0; + attempt = node->data; + if(((settings.tempban_threshold && (attempt->count - attempt->dupes) >= settings.tempban_threshold) + || trashcan(cfg, attempt->user, "name")) && now < (attempt->time + settings.tempban_duration)) + return settings.tempban_duration - (now - attempt->time); + return 0; +} + /****************************************************************************/ /* Message-new-scan pointer/configuration functions */ /****************************************************************************/ diff --git a/src/sbbs3/userdat.h b/src/sbbs3/userdat.h index 0f8496aad49697565bec8e949b176cc07cd792a3..5eecdc225274b122f49691f814dd9324ce9cdd72 100644 --- a/src/sbbs3/userdat.h +++ b/src/sbbs3/userdat.h @@ -145,9 +145,9 @@ DLLEXPORT BOOL DLLCALL check_name(scfg_t*, const char* name); /* Login attempt/hack tracking */ typedef struct { - union xp_sockaddr addr; /* host with consecutive failed login attmepts */ + union xp_sockaddr addr; /* host with consecutive failed login attempts */ ulong count; /* number of consecutive failed login attempts */ - ulong dupes; /* number of consecutive dupliate login attempts (same name and password) */ + ulong dupes; /* number of consecutive duplicate login attempts (same name and password) */ time32_t time; /* time of last attempt */ char prot[32]; /* protocol used in last attempt */ char user[128]; @@ -160,6 +160,7 @@ DLLEXPORT long DLLCALL loginAttemptListClear(link_list_t*); DLLEXPORT long DLLCALL loginAttempts(link_list_t*, const union xp_sockaddr*); DLLEXPORT void DLLCALL loginSuccess(link_list_t*, const union xp_sockaddr*); DLLEXPORT ulong DLLCALL loginFailure(link_list_t*, const union xp_sockaddr*, const char* prot, const char* user, const char* pass); +DLLEXPORT ulong DLLCALL loginBanned(scfg_t*, link_list_t*, const union xp_sockaddr*, struct login_attempt_settings); #ifdef __cplusplus } diff --git a/src/sbbs3/websrvr.c b/src/sbbs3/websrvr.c index 4017ed89798d82564969ba26c81258c087523047..a24970fdc9563d16397e890a8414fbb0fb33a7a7 100644 --- a/src/sbbs3/websrvr.c +++ b/src/sbbs3/websrvr.c @@ -1780,18 +1780,18 @@ static void badlogin(SOCKET sock, const char* prot, const char* user, const char SAFEPRINTF(reason,"%s LOGIN", prot); count=loginFailure(startup->login_attempt_list, addr, prot, user, passwd); - if(startup->login_attempt_hack_threshold && count>=startup->login_attempt_hack_threshold) { + if(startup->login_attempt.hack_threshold && count>=startup->login_attempt.hack_threshold) { hacklog(&scfg, reason, user, passwd, host, addr); #ifdef _WIN32 if(startup->hack_sound[0] && !(startup->options&BBS_OPT_MUTE)) PlaySound(startup->hack_sound, NULL, SND_ASYNC|SND_FILENAME); #endif } - if(startup->login_attempt_filter_threshold && count>=startup->login_attempt_filter_threshold) + if(startup->login_attempt.filter_threshold && count>=startup->login_attempt.filter_threshold) filter_ip(&scfg, prot, "- TOO MANY CONSECUTIVE FAILED LOGIN ATTEMPTS" ,host, inet_addrtop(addr, addrstr, sizeof(addrstr)), user, /* fname: */NULL); if(count>1) - mswait(startup->login_attempt_delay); + mswait(startup->login_attempt.delay); } static BOOL check_ars(http_session_t * session) @@ -6246,9 +6246,11 @@ void http_session_thread(void* arg) } } + ulong banned = loginBanned(&scfg, startup->login_attempt_list, &session.addr, startup->login_attempt); + /* host_ip wasn't defined in http_session_thread */ - if(trashcan(&scfg,session.host_ip,"ip")) { - lprintf(LOG_NOTICE,"%04d !CLIENT BLOCKED in ip.can: %s", session.socket, session.host_ip); + if((banned && lprintf(LOG_NOTICE, "%04d %s is TEMPORARILY BANNED (%lu more seconds)", socket, session.host_ip, banned)) + || (trashcan(&scfg,session.host_ip,"ip") && lprintf(LOG_NOTICE,"%04d !CLIENT BLOCKED in ip.can: %s", session.socket, session.host_ip))) { close_session_socket(&session); sem_wait(&session.output_thread_terminated); sem_destroy(&session.output_thread_terminated); @@ -6270,11 +6272,11 @@ void http_session_thread(void* arg) session.client.size=sizeof(session.client); client_on(session.socket, &session.client, /* update existing client record? */FALSE); - if(startup->login_attempt_throttle + if(startup->login_attempt.throttle && (login_attempts=loginAttempts(startup->login_attempt_list, &session.addr)) > 1) { lprintf(LOG_DEBUG,"%04d %s Throttling suspicious connection from: %s (%u login attempts)" ,socket, session.client.protocol, session.host_ip, login_attempts); - mswait(login_attempts*startup->login_attempt_throttle); + mswait(login_attempts*startup->login_attempt.throttle); } session.last_user_num=-1; diff --git a/src/sbbs3/websrvr.h b/src/sbbs3/websrvr.h index 8a4bb3ee7ff6af5f874ee4fcb1a987ad15cbc8bf..14b65ed6a822438731deefb4c0ebd42716397beb 100644 --- a/src/sbbs3/websrvr.h +++ b/src/sbbs3/websrvr.h @@ -106,10 +106,7 @@ typedef struct { js_startup_t js; /* Login Attempt parameters */ - uint32_t login_attempt_delay; - uint32_t login_attempt_throttle; - uint32_t login_attempt_hack_threshold; - uint32_t login_attempt_filter_threshold; + struct login_attempt_settings login_attempt; link_list_t* login_attempt_list; } web_startup_t;