1 /*****************************************************************************
2  * PokerTH - The open source texas holdem engine                             *
3  * Copyright (C) 2006-2012 Felix Hammer, Florian Thauer, Lothar May          *
4  *                                                                           *
5  * This program is free software: you can redistribute it and/or modify      *
6  * it under the terms of the GNU Affero General Public License as            *
7  * published by the Free Software Foundation, either version 3 of the        *
8  * License, or (at your option) any later version.                           *
9  *                                                                           *
10  * This program is distributed in the hope that it will be useful,           *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
13  * GNU Affero General Public License for more details.                       *
14  *                                                                           *
15  * You should have received a copy of the GNU Affero General Public License  *
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.     *
17  *                                                                           *
18  *                                                                           *
19  * Additional permission under GNU AGPL version 3 section 7                  *
20  *                                                                           *
21  * If you modify this program, or any covered work, by linking or            *
22  * combining it with the OpenSSL project's OpenSSL library (or a             *
23  * modified version of that library), containing parts covered by the        *
24  * terms of the OpenSSL or SSLeay licenses, the authors of PokerTH           *
25  * (Felix Hammer, Florian Thauer, Lothar May) grant you additional           *
26  * permission to convey the resulting work.                                  *
27  * Corresponding Source for a non-source form of such a combination          *
28  * shall include the source code for the parts of OpenSSL used as well       *
29  * as that of the covered work.                                              *
30  *****************************************************************************/
31 
32 #include <net/serverbanmanager.h>
33 #include <algorithm>
34 
35 using namespace std;
36 
37 #ifdef BOOST_ASIO_HAS_STD_CHRONO
38 using namespace std::chrono;
39 #else
40 using namespace boost::chrono;
41 #endif
42 
ServerBanManager(boost::shared_ptr<boost::asio::io_service> ioService)43 ServerBanManager::ServerBanManager(boost::shared_ptr<boost::asio::io_service> ioService)
44 	: m_ioService(ioService), m_curBanId(0)
45 {
46 }
47 
~ServerBanManager()48 ServerBanManager::~ServerBanManager()
49 {
50 }
51 
52 void
SetAdminPlayerIds(const std::list<DB_id> & adminList)53 ServerBanManager::SetAdminPlayerIds(const std::list<DB_id> &adminList)
54 {
55 	boost::mutex::scoped_lock lock(m_banMutex);
56 	m_adminPlayers.resize(adminList.size());
57 	copy(adminList.begin(), adminList.end(), m_adminPlayers.begin());
58 	sort(m_adminPlayers.begin(), m_adminPlayers.end());
59 }
60 
61 void
BanPlayerName(const std::string & playerName,unsigned durationHours)62 ServerBanManager::BanPlayerName(const std::string &playerName, unsigned durationHours)
63 {
64 	boost::mutex::scoped_lock lock(m_banMutex);
65 	unsigned banId = GetNextBanId();
66 
67 	TimedPlayerBan tmpBan;
68 	tmpBan.timer = InternalRegisterTimedBan(banId, durationHours);
69 	tmpBan.nameStr = playerName;
70 	m_banPlayerNameMap[banId] = tmpBan;
71 }
72 
73 void
BanPlayerRegex(const string & playerRegex,unsigned durationHours)74 ServerBanManager::BanPlayerRegex(const string &playerRegex, unsigned durationHours)
75 {
76 	boost::mutex::scoped_lock lock(m_banMutex);
77 	unsigned banId = GetNextBanId();
78 
79 	TimedPlayerBan tmpBan;
80 	tmpBan.timer = InternalRegisterTimedBan(banId, durationHours);
81 	tmpBan.nameRegex = boost::regex(playerRegex, boost::regex::extended | boost::regex::icase);
82 	m_banPlayerNameMap[banId] = tmpBan;
83 }
84 
85 void
BanIPAddress(const string & ipAddress,unsigned durationHours)86 ServerBanManager::BanIPAddress(const string &ipAddress, unsigned durationHours)
87 {
88 	boost::mutex::scoped_lock lock(m_banMutex);
89 	unsigned banId = GetNextBanId();
90 
91 	TimedIPBan tmpBan;
92 	tmpBan.timer = InternalRegisterTimedBan(banId, durationHours);
93 	tmpBan.ipAddress = ipAddress;
94 	m_banIPAddressMap[banId] = tmpBan;
95 }
96 
97 bool
UnBan(unsigned banId)98 ServerBanManager::UnBan(unsigned banId)
99 {
100 	bool retVal = false;
101 	boost::mutex::scoped_lock lock(m_banMutex);
102 	RegexMap::iterator posNick = m_banPlayerNameMap.find(banId);
103 	if (posNick != m_banPlayerNameMap.end()) {
104 		if (posNick->second.timer)
105 			posNick->second.timer->cancel();
106 		m_banPlayerNameMap.erase(posNick);
107 		retVal = true;
108 	} else {
109 		IPAddressMap::iterator posIP = m_banIPAddressMap.find(banId);
110 		if (posIP != m_banIPAddressMap.end()) {
111 			if (posIP->second.timer)
112 				posIP->second.timer->cancel();
113 			m_banIPAddressMap.erase(posIP);
114 			retVal = true;
115 		}
116 	}
117 	return retVal;
118 }
119 
120 void
GetBanList(list<string> & list) const121 ServerBanManager::GetBanList(list<string> &list) const
122 {
123 	boost::mutex::scoped_lock lock(m_banMutex);
124 	RegexMap::const_iterator i_nick = m_banPlayerNameMap.begin();
125 	RegexMap::const_iterator end_nick = m_banPlayerNameMap.end();
126 	while (i_nick != end_nick) {
127 		ostringstream banText;
128 		if ((*i_nick).second.nameStr.empty())
129 			banText << (*i_nick).first << ": (nickRegex) - " << (*i_nick).second.nameRegex.str();
130 		else
131 			banText << (*i_nick).first << ": (nickStr) - " << (*i_nick).second.nameStr;
132 
133 		if ((*i_nick).second.timer)
134 			banText << " duration: " << duration_cast<hours>((*i_nick).second.timer->expires_from_now()).count() << "h";
135 		list.push_back(banText.str());
136 		++i_nick;
137 	}
138 	IPAddressMap::const_iterator i_ip = m_banIPAddressMap.begin();
139 	IPAddressMap::const_iterator end_ip = m_banIPAddressMap.end();
140 	while (i_ip != end_ip) {
141 		ostringstream banText;
142 		banText << (*i_ip).first << ": (IP) - " << (*i_ip).second.ipAddress;
143 		if ((*i_ip).second.timer)
144 			banText << " duration: " << duration_cast<hours>((*i_ip).second.timer->expires_from_now()).count() << "h";
145 		list.push_back(banText.str());
146 		++i_ip;
147 	}
148 }
149 
150 void
ClearBanList()151 ServerBanManager::ClearBanList()
152 {
153 	boost::mutex::scoped_lock lock(m_banMutex);
154 	m_banPlayerNameMap.clear();
155 	m_banIPAddressMap.clear();
156 }
157 
158 bool
IsAdminPlayer(DB_id playerId) const159 ServerBanManager::IsAdminPlayer(DB_id playerId) const
160 {
161 	bool retVal = false;
162 	if (playerId != DB_ID_INVALID) {
163 		boost::mutex::scoped_lock lock(m_banMutex);
164 
165 		if (binary_search(m_adminPlayers.begin(), m_adminPlayers.end(), playerId)) {
166 			retVal = true;
167 		}
168 	}
169 	return retVal;
170 }
171 
172 bool
IsPlayerBanned(const std::string & name) const173 ServerBanManager::IsPlayerBanned(const std::string &name) const
174 {
175 	bool retVal = false;
176 	boost::mutex::scoped_lock lock(m_banMutex);
177 	RegexMap::const_iterator i = m_banPlayerNameMap.begin();
178 	RegexMap::const_iterator end = m_banPlayerNameMap.end();
179 	while (i != end) {
180 		// Use regex only if name not set.
181 		if ((*i).second.nameStr.empty()) {
182 			if (regex_match(name, (*i).second.nameRegex)) {
183 				retVal = true;
184 				break;
185 			}
186 		} else {
187 			if (name == (*i).second.nameStr) {
188 				retVal = true;
189 				break;
190 			}
191 		}
192 		++i;
193 	}
194 
195 	return retVal;
196 }
197 
198 bool
IsIPAddressBanned(const std::string & ipAddress) const199 ServerBanManager::IsIPAddressBanned(const std::string &ipAddress) const
200 {
201 	bool retVal = false;
202 	boost::mutex::scoped_lock lock(m_banMutex);
203 	IPAddressMap::const_iterator i = m_banIPAddressMap.begin();
204 	IPAddressMap::const_iterator end = m_banIPAddressMap.end();
205 	while (i != end) {
206 		if (ipAddress == (*i).second.ipAddress) {
207 			retVal = true;
208 			break;
209 		}
210 		++i;
211 	}
212 
213 	return retVal;
214 }
215 
216 void
InitGameNameBadWordList(const std::list<string> & badWordList)217 ServerBanManager::InitGameNameBadWordList(const std::list<string> &badWordList)
218 {
219 	list<string>::const_iterator i = badWordList.begin();
220 	list<string>::const_iterator end = badWordList.end();
221 	while (i != end) {
222 		m_gameNameBadWordFilter.push_back(boost::regex(*i, boost::regex::extended | boost::regex::icase));
223 		++i;
224 	}
225 }
226 
227 bool
IsBadGameName(const std::string & name) const228 ServerBanManager::IsBadGameName(const std::string &name) const
229 {
230 	bool retVal = false;
231 	RegexList::const_iterator i = m_gameNameBadWordFilter.begin();
232 	RegexList::const_iterator end = m_gameNameBadWordFilter.end();
233 	while (i != end) {
234 		if (regex_match(name, *i)) {
235 			retVal = true;
236 			break;
237 		}
238 		++i;
239 	}
240 	return retVal;
241 }
242 
243 boost::shared_ptr<boost::asio::steady_timer>
InternalRegisterTimedBan(unsigned timerId,unsigned durationHours)244 ServerBanManager::InternalRegisterTimedBan(unsigned timerId, unsigned durationHours)
245 {
246 	boost::shared_ptr<boost::asio::steady_timer> tmpTimer;
247 	if (durationHours) {
248 		tmpTimer.reset(new boost::asio::steady_timer(*m_ioService));
249 		tmpTimer->expires_from_now(
250 			hours(durationHours));
251 		tmpTimer->async_wait(
252 			boost::bind(
253 				&ServerBanManager::TimerRemoveBan, shared_from_this(), boost::asio::placeholders::error, timerId, tmpTimer));
254 	}
255 	return tmpTimer;
256 }
257 
258 void
TimerRemoveBan(const boost::system::error_code & ec,unsigned banId,boost::shared_ptr<boost::asio::steady_timer> timer)259 ServerBanManager::TimerRemoveBan(const boost::system::error_code &ec, unsigned banId, boost::shared_ptr<boost::asio::steady_timer> timer)
260 {
261 	if (!ec && timer)
262 		UnBan(banId);
263 }
264 
265 unsigned
GetNextBanId()266 ServerBanManager::GetNextBanId()
267 {
268 	m_curBanId++;
269 	if (m_curBanId == 0) // 0 is an invalid id.
270 		m_curBanId++;
271 
272 	return m_curBanId;
273 }
274 
275