Noticias:

No tienes permiso para ver los enlaces. Para poder verlos Registrate o Conectate.

Menú Principal

Anti-Duplicate Items

Iniciado por Swarlog, Jun 25, 2025, 09:01 PM

Tema anterior - Siguiente tema

Swarlog

diff --git a/L2J_Server_BETA/dist/login/config/LoginServer.properties b/L2J_Server_BETA/dist/login/config/LoginServer.properties
index 20f96e8..5e0e33c 100644
--- a/L2J_Server_BETA/dist/login/config/LoginServer.properties
+++ b/L2J_Server_BETA/dist/login/config/LoginServer.properties
@@ -39,10 +39,6 @@ LoginPort = 9014
 # Security
 # ---------------------------------------------------------------------------
 
-# Logs in file the login server events.
-# Default: True
-LogLoginController = True
-
 # How many times you can provide an invalid account/pass before the IP gets banned.
 # Default: 5
 LoginTryBeforeBan = 5
diff --git a/L2J_Server_BETA/java/com/l2jserver/Config.java b/L2J_Server_BETA/java/com/l2jserver/Config.java
index 330e0a3..0135093 100644
--- a/L2J_Server_BETA/java/com/l2jserver/Config.java
+++ b/L2J_Server_BETA/java/com/l2jserver/Config.java
@@ -948,7 +948,6 @@
 	public static int REQUEST_ID;
 	public static boolean RESERVE_HOST_ON_LOGIN = false;
 	public static List<Integer> PROTOCOL_LIST;
-	public static boolean LOG_LOGIN_CONTROLLER;
 	public static boolean LOGIN_SERVER_SCHEDULE_RESTART;
 	public static long LOGIN_SERVER_SCHEDULE_RESTART_TIME;
 	
@@ -2790,8 +2789,6 @@ else if (Server.serverMode == Server.MODE_LOGINSERVER)
 			LOGIN_TRY_BEFORE_BAN = ServerSettings.getInt("LoginTryBeforeBan", 5);
 			LOGIN_BLOCK_AFTER_BAN = ServerSettings.getInt("LoginBlockAfterBan", 900);
 			
-			LOG_LOGIN_CONTROLLER = ServerSettings.getBoolean("LogLoginController", true);
-			
 			LOGIN_SERVER_SCHEDULE_RESTART = ServerSettings.getBoolean("LoginRestartSchedule", false);
 			LOGIN_SERVER_SCHEDULE_RESTART_TIME = ServerSettings.getLong("LoginRestartTime", 24);
 			
diff --git a/L2J_Server_BETA/java/com/l2jserver/gameserver/util/GMAudit.java b/L2J_Server_BETA/java/com/l2jserver/gameserver/util/GMAudit.java
index bac0c6b..6ad5217 100644
--- a/L2J_Server_BETA/java/com/l2jserver/gameserver/util/GMAudit.java
+++ b/L2J_Server_BETA/java/com/l2jserver/gameserver/util/GMAudit.java
@@ -27,14 +27,13 @@
 import java.util.logging.Logger;
 
 import com.l2jserver.Config;
-import com.l2jserver.util.lib.Log;
 
 /**
  * Audits Game Master's actions.
  */
 public class GMAudit
 {
-	private static final Logger _log = Logger.getLogger(Log.class.getName());
+	private static final Logger _log = Logger.getLogger(GMAudit.class.getName());
 	
 	static
 	{
diff --git a/L2J_Server_BETA/java/com/l2jserver/loginserver/LoginController.java b/L2J_Server_BETA/java/com/l2jserver/loginserver/LoginController.java
index 3da9896..3b80a31 100644
--- a/L2J_Server_BETA/java/com/l2jserver/loginserver/LoginController.java
+++ b/L2J_Server_BETA/java/com/l2jserver/loginserver/LoginController.java
@@ -20,6 +20,7 @@
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.nio.charset.StandardCharsets;
 import java.security.GeneralSecurityException;
 import java.security.KeyPairGenerator;
 import java.security.MessageDigest;
@@ -29,9 +30,9 @@
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Base64;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.logging.Level;
@@ -44,12 +45,12 @@
 import com.l2jserver.Config;
 import com.l2jserver.L2DatabaseFactory;
 import com.l2jserver.loginserver.GameServerTable.GameServerInfo;
+import com.l2jserver.loginserver.model.data.AccountInfo;
 import com.l2jserver.loginserver.network.L2LoginClient;
 import com.l2jserver.loginserver.network.gameserverpackets.ServerStatus;
 import com.l2jserver.loginserver.network.serverpackets.LoginFail.LoginFailReason;
 import com.l2jserver.util.Rnd;
 import com.l2jserver.util.crypt.ScrambledKeyPair;
-import com.l2jserver.util.lib.Log;
 
 /**
  * This class ...
@@ -67,9 +68,8 @@
 	/** Authed Clients on LoginServer */
 	protected FastMap<String, L2LoginClient> _loginServerClients = new FastMap<String, L2LoginClient>().shared();
 	
-	private final Map<String, BanInfo> _bannedIps = new FastMap<String, BanInfo>().shared();
-	
-	private final Map<InetAddress, FailedLoginAttempt> _hackProtection;
+	private final Map<InetAddress, Integer> _failedLoginAttemps = new HashMap<>();
+	private final Map<InetAddress, Long> _bannedIps = new FastMap<InetAddress, Long>().shared();
 	
 	protected ScrambledKeyPair[] _keyPairs;
 	
@@ -79,7 +79,7 @@
 	private static final int BLOWFISH_KEYS = 20;
 	
 	// SQL Queries
-	private static final String USER_INFO_SELECT = "SELECT password, IF(? > value OR value IS NULL, accessLevel, -1) AS accessLevel, lastServer FROM accounts LEFT JOIN (account_data) ON (account_data.account_name=accounts.login AND account_data.var=\"ban_temp\") WHERE login=?";
+	private static final String USER_INFO_SELECT = "SELECT login, password, IF(? > value OR value IS NULL, accessLevel, -1) AS accessLevel, lastServer FROM accounts LEFT JOIN (account_data) ON (account_data.account_name=accounts.login AND account_data.var=\"ban_temp\") WHERE login=?";
 	private static final String AUTOCREATE_ACCOUNTS_INSERT = "INSERT INTO accounts (login, password, lastactive, accessLevel, lastIP) values (?, ?, ?, ?, ?)";
 	private static final String ACCOUNT_INFO_UPDATE = "UPDATE accounts SET lastactive = ?, lastIP = ? WHERE login = ?";
 	private static final String ACCOUNT_LAST_SERVER_UPDATE = "UPDATE accounts SET lastServer = ? WHERE login = ?";
@@ -87,32 +87,10 @@
 	private static final String ACCOUNT_IPS_UPDATE = "UPDATE accounts SET pcIp = ?, hop1 = ?, hop2 = ?, hop3 = ?, hop4 = ? WHERE login = ?";
 	private static final String ACCOUNT_IPAUTH_SELECT = "SELECT * FROM accounts_ipauth WHERE login = ?";
 	
-	public static void load() throws GeneralSecurityException
-	{
-		synchronized (LoginController.class)
-		{
-			if (_instance == null)
-			{
-				_instance = new LoginController();
-			}
-			else
-			{
-				throw new IllegalStateException("LoginController can only be loaded a single time.");
-			}
-		}
-	}
-	
-	public static LoginController getInstance()
-	{
-		return _instance;
-	}
-	
 	private LoginController() throws GeneralSecurityException
 	{
 		_log.info("Loading LoginController...");
 		
-		_hackProtection = new FastMap<>();
-		
 		_keyPairs = new ScrambledKeyPair[10];
 		
 		KeyPairGenerator keygen = null;
@@ -196,57 +174,154 @@ public L2LoginClient getAuthedClient(String account)
 		return _loginServerClients.get(account);
 	}
 	
-	public static enum AuthLoginResult
+	public AccountInfo retriveAccountInfo(InetAddress clientAddr, String login, String password)
 	{
-		INVALID_PASSWORD,
-		ACCOUNT_BANNED,
-		ALREADY_ON_LS,
-		ALREADY_ON_GS,
-		AUTH_SUCCESS
+		return retriveAccountInfo(clientAddr, login, password, true);
 	}
 	
-	public AuthLoginResult tryAuthLogin(String account, String password, L2LoginClient client)
+	private void recordFailedLoginAttemp(InetAddress addr)
 	{
+		// We need to synchronize this!
+		// When multiple connections from the same address fail to login at the
+		// same time, unexpected behavior can happen.
+		Integer failedLoginAttemps;
+		synchronized (_failedLoginAttemps)
+		{
+			failedLoginAttemps = _failedLoginAttemps.get(addr);
+			if (failedLoginAttemps == null)
+			{
+				failedLoginAttemps = 1;
+			}
+			else
+			{
+				++failedLoginAttemps;
+			}
+			
+			_failedLoginAttemps.put(addr, failedLoginAttemps);
+		}
+		
+		if (failedLoginAttemps >= Config.LOGIN_TRY_BEFORE_BAN)
+		{
+			addBanForAddress(addr, Config.LOGIN_BLOCK_AFTER_BAN * 1000);
+			// we need to clear the failed login attemps here, so after the ip ban is over the client has another 5 attemps
+			clearFailedLoginAttemps(addr);
+			_log.warning("Added banned address " + addr.getHostAddress() + "! Too many login attemps.");
+		}
+	}
+	
+	private void clearFailedLoginAttemps(InetAddress addr)
+	{
+		synchronized (_failedLoginAttemps)
+		{
+			_failedLoginAttemps.remove(addr);
+		}
+	}
+	
+	private AccountInfo retriveAccountInfo(InetAddress addr, String login, String password, boolean autoCreateIfEnabled)
+	{
+		try
+		{
+			MessageDigest md = MessageDigest.getInstance("SHA");
+			byte[] raw = password.getBytes(StandardCharsets.UTF_8);
+			String hashBase64 = Base64.getEncoder().encodeToString(md.digest(raw));
+			
+			try (Connection con = L2DatabaseFactory.getInstance().getConnection();
+				PreparedStatement ps = con.prepareStatement(USER_INFO_SELECT))
+			{
+				ps.setString(1, Long.toString(System.currentTimeMillis()));
+				ps.setString(2, login);
+				try (ResultSet rset = ps.executeQuery())
+				{
+					if (rset.next())
+					{
+						if (Config.DEBUG)
+						{
+							_log.fine("Account '" + login + "' exists.");
+						}
+						
+						AccountInfo info = new AccountInfo(rset.getString("login"), rset.getString("password"), rset.getInt("accessLevel"), rset.getInt("lastServer"));
+						if (!info.checkPassHash(hashBase64))
+						{
+							// wrong password
+							recordFailedLoginAttemp(addr);
+							return null;
+						}
+						
+						clearFailedLoginAttemps(addr);
+						return info;
+					}
+				}
+			}
+			
+			if (!autoCreateIfEnabled || !Config.AUTO_CREATE_ACCOUNTS)
+			{
+				// account does not exist and auto create accoutn is not desired
+				recordFailedLoginAttemp(addr);
+				return null;
+			}
+			
+			try (Connection con = L2DatabaseFactory.getInstance().getConnection();
+				PreparedStatement ps = con.prepareStatement(AUTOCREATE_ACCOUNTS_INSERT))
+			{
+				ps.setString(1, login);
+				ps.setString(2, hashBase64);
+				ps.setLong(3, System.currentTimeMillis());
+				ps.setInt(4, 0);
+				ps.setString(5, addr.getHostAddress());
+				ps.execute();
+			}
+			catch (Exception e)
+			{
+				_log.log(Level.WARNING, "Exception while auto creating account for '" + login + "'!", e);
+				return null;
+			}
+			
+			_log.info("Auto created account '" + login + "'.");
+			return retriveAccountInfo(addr, login, password, false);
+		}
+		catch (Exception e)
+		{
+			_log.log(Level.WARNING, "Exception while retriving account info for '" + login + "'!", e);
+			return null;
+		}
+	}
+	
+	public AuthLoginResult tryCheckinAccount(L2LoginClient client, InetAddress address, AccountInfo info)
+	{
+		if (info.getAccessLevel() < 0)
+		{
+			return AuthLoginResult.ACCOUNT_BANNED;
+		}
+		
 		AuthLoginResult ret = AuthLoginResult.INVALID_PASSWORD;
 		// check auth
-		if (loginValid(account, password, client))
+		if (canCheckin(client, address, info))
 		{
 			// login was successful, verify presence on Gameservers
 			ret = AuthLoginResult.ALREADY_ON_GS;
-			if (!isAccountInAnyGameServer(account))
+			if (!isAccountInAnyGameServer(info.getLogin()))
 			{
 				// account isnt on any GS verify LS itself
 				ret = AuthLoginResult.ALREADY_ON_LS;
 				
-				if (_loginServerClients.putIfAbsent(account, client) == null)
+				if (_loginServerClients.putIfAbsent(info.getLogin(), client) == null)
 				{
 					ret = AuthLoginResult.AUTH_SUCCESS;
 				}
 			}
 		}
-		else
-		{
-			if (client.getAccessLevel() < 0)
-			{
-				ret = AuthLoginResult.ACCOUNT_BANNED;
-			}
-		}
 		return ret;
 	}
 	
 	/**
-	 * Adds the address to the ban list of the login server, with the given duration.
+	 * Adds the address to the ban list of the login server, with the given end tiem in millis.
 	 * @param address The Address to be banned.
 	 * @param expiration Timestamp in miliseconds when this ban expires
 	 * @throws UnknownHostException if the address is invalid.
 	 */
 	public void addBanForAddress(String address, long expiration) throws UnknownHostException
 	{
-		InetAddress netAddress = InetAddress.getByName(address);
-		if (!_bannedIps.containsKey(netAddress.getHostAddress()))
-		{
-			_bannedIps.put(netAddress.getHostAddress(), new BanInfo(netAddress, expiration));
-		}
+		_bannedIps.putIfAbsent(InetAddress.getByName(address), expiration);
 	}
 	
 	/**
@@ -256,16 +331,13 @@ public void addBanForAddress(String address, long expiration) throws UnknownHost
 	 */
 	public void addBanForAddress(InetAddress address, long duration)
 	{
-		if (!_bannedIps.containsKey(address.getHostAddress()))
-		{
-			_bannedIps.put(address.getHostAddress(), new BanInfo(address, System.currentTimeMillis() + duration));
-		}
+		_bannedIps.putIfAbsent(address, System.currentTimeMillis() + duration);
 	}
 	
 	public boolean isBannedAddress(InetAddress address)
 	{
 		String[] parts = address.getHostAddress().split("\\.");
-		BanInfo bi = _bannedIps.get(address.getHostAddress());
+		Long bi = _bannedIps.get(address);
 		if (bi == null)
 		{
 			bi = _bannedIps.get(parts[0] + "." + parts[1] + "." + parts[2] + ".0");
@@ -280,9 +352,10 @@ public boolean isBannedAddress(InetAddress address)
 		}
 		if (bi != null)
 		{
-			if (bi.hasExpired())
+			if ((bi > 0) && (bi < System.currentTimeMillis()))
 			{
-				_bannedIps.remove(address.getHostAddress());
+				_bannedIps.remove(address);
+				_log.info("Removed expired ip address ban " + address.getHostAddress() + ".");
 				return false;
 			}
 			return true;
@@ -290,7 +363,7 @@ public boolean isBannedAddress(InetAddress address)
 		return false;
 	}
 	
-	public Map<String, BanInfo> getBannedIps()
+	public Map<InetAddress, Long> getBannedIps()
 	{
 		return _bannedIps;
 	}
@@ -470,61 +543,21 @@ public ScrambledKeyPair getScrambledRSAKeyPair()
 	}
 	
 	/**
-	 * User name is not case sensitive any more.
-	 * @param user
-	 * @param password
-	 * @param client
-	 * @return
+	 * @param client the client
+	 * @param address client host address
+	 * @param info the account info to checkin
+	 * @return true when ok to checkin, false otherwise
 	 */
-	public boolean loginValid(String user, String password, L2LoginClient client)// throws HackingException
+	public boolean canCheckin(L2LoginClient client, InetAddress address, AccountInfo info)
 	{
-		boolean ok = false;
-		InetAddress address = client.getConnection().getInetAddress();
-		
-		// player disconnected meanwhile
-		if ((address == null) || (user == null))
-		{
-			return false;
-		}
-		
 		try
 		{
-			MessageDigest md = MessageDigest.getInstance("SHA");
-			byte[] raw = password.getBytes("UTF-8");
-			byte[] hash = md.digest(raw);
-			
-			byte[] expected = null;
-			int access = 0;
-			int lastServer = 1;
 			List<InetAddress> ipWhiteList = new ArrayList<>();
 			List<InetAddress> ipBlackList = new ArrayList<>();
 			try (Connection con = L2DatabaseFactory.getInstance().getConnection();
-				PreparedStatement ps = con.prepareStatement(USER_INFO_SELECT))
-			{
-				ps.setString(1, Long.toString(System.currentTimeMillis()));
-				ps.setString(2, user);
-				try (ResultSet rset = ps.executeQuery())
-				{
-					if (rset.next())
-					{
-						expected = Base64.getDecoder().decode(rset.getString("password"));
-						access = rset.getInt("accessLevel");
-						lastServer = rset.getInt("lastServer");
-						if (lastServer <= 0)
-						{
-							lastServer = 1; // minServerId is 1 in Interlude
-						}
-						if (Config.DEBUG)
-						{
-							_log.fine("account exists");
-						}
-					}
-				}
-			}
-			try (Connection con = L2DatabaseFactory.getInstance().getConnection();
 				PreparedStatement ps = con.prepareStatement(ACCOUNT_IPAUTH_SELECT))
 			{
-				ps.setString(1, user);
+				ps.setString(1, info.getLogin());
 				try (ResultSet rset = ps.executeQuery())
 				{
 					String ip, type;
@@ -549,162 +582,40 @@ else if (type.equals("deny"))
 				}
 			}
 			
-			// if account doesn't exists
-			if (expected == null)
-			{
-				if (Config.AUTO_CREATE_ACCOUNTS)
-				{
-					if ((user.length() >= 2) && (user.length() <= 14))
-					{
-						try (Connection con = L2DatabaseFactory.getInstance().getConnection();
-							PreparedStatement ps = con.prepareStatement(AUTOCREATE_ACCOUNTS_INSERT))
-						{
-							ps.setString(1, user);
-							ps.setString(2, Base64.getEncoder().encodeToString(hash));
-							ps.setLong(3, System.currentTimeMillis());
-							ps.setInt(4, 0);
-							ps.setString(5, address.getHostAddress());
-							ps.execute();
-						}
-						
-						if (Config.LOG_LOGIN_CONTROLLER)
-						{
-							Log.add("'" + user + "' " + address.getHostAddress() + " - OK : AccountCreate", "loginlog");
-						}
-						
-						_log.info("Created new account for " + user);
-						return true;
-						
-					}
-					if (Config.LOG_LOGIN_CONTROLLER)
-					{
-						Log.add("'" + user + "' " + address.getHostAddress() + " - ERR : ErrCreatingACC", "loginlog");
-					}
-					
-					_log.warning("Invalid username creation/use attempt: " + user);
-				}
-				else
-				{
-					if (Config.LOG_LOGIN_CONTROLLER)
-					{
-						Log.add("'" + user + "' " + address.getHostAddress() + " - ERR : AccountMissing", "loginlog");
-					}
-					
-					_log.warning("Account missing for user " + user);
-					FailedLoginAttempt failedAttempt = _hackProtection.get(address);
-					int failedCount;
-					if (failedAttempt == null)
-					{
-						_hackProtection.put(address, new FailedLoginAttempt(address, password));
-						failedCount = 1;
-					}
-					else
-					{
-						failedAttempt.increaseCounter();
-						failedCount = failedAttempt.getCount();
-					}
-					
-					if (failedCount >= Config.LOGIN_TRY_BEFORE_BAN)
-					{
-						_log.info("Banning '" + address.getHostAddress() + "' for " + Config.LOGIN_BLOCK_AFTER_BAN + " seconds due to " + failedCount + " invalid user name attempts");
-						this.addBanForAddress(address, Config.LOGIN_BLOCK_AFTER_BAN * 1000);
-					}
-				}
-				return false;
-			}
-			
-			// is this account banned?
-			if (access < 0)
-			{
-				if (Config.LOG_LOGIN_CONTROLLER)
-				{
-					Log.add("'" + user + "' " + address.getHostAddress() + " - ERR : AccountBanned", "loginlog");
-				}
-				
-				client.setAccessLevel(access);
-				return false;
-			}
-			
 			// Check IP
 			if (!ipWhiteList.isEmpty() || !ipBlackList.isEmpty())
 			{
 				if (!ipWhiteList.isEmpty() && !ipWhiteList.contains(address))
 				{
-					if (Config.LOG_LOGIN_CONTROLLER)
-					{
-						Log.add("'" + user + "' " + address.getHostAddress() + " - ERR : INCORRECT IP", "loginlog");
-					}
+					_log.warning("Account checkin attemp from address(" + address.getHostAddress() + ") not present on whitelist for account '" + info.getLogin() + "'.");
 					return false;
 				}
 				
 				if (!ipBlackList.isEmpty() && ipBlackList.contains(address))
 				{
-					if (Config.LOG_LOGIN_CONTROLLER)
-					{
-						Log.add("'" + user + "' " + address.getHostAddress() + " - ERR : BLACKLISTED IP", "loginlog");
-					}
+					_log.warning("Account checkin attemp from address(" + address.getHostAddress() + ") on blacklist for account '" + info.getLogin() + "'.");
 					return false;
 				}
 			}
 			
-			// check password hash
-			ok = Arrays.equals(hash, expected);
-			if (ok)
-			{
-				client.setAccessLevel(access);
-				client.setLastServer(lastServer);
-				try (Connection con = L2DatabaseFactory.getInstance().getConnection();
-					PreparedStatement ps = con.prepareStatement(ACCOUNT_INFO_UPDATE))
-				{
-					ps.setLong(1, System.currentTimeMillis());
-					ps.setString(2, address.getHostAddress());
-					ps.setString(3, user);
-					ps.execute();
-				}
-			}
-		}
-		catch (Exception e)
-		{
-			_log.log(Level.WARNING, "Could not check password:" + e.getMessage(), e);
-			ok = false;
-		}
-		
-		if (!ok)
-		{
-			if (Config.LOG_LOGIN_CONTROLLER)
-			{
-				Log.add("'" + user + "' " + address.getHostAddress() + " - ERR : LoginFailed", "loginlog");
-			}
-			
-			FailedLoginAttempt failedAttempt = _hackProtection.get(address);
-			int failedCount;
-			if (failedAttempt == null)
-			{
-				_hackProtection.put(address, new FailedLoginAttempt(address, password));
-				failedCount = 1;
-			}
-			else
+			client.setAccessLevel(info.getAccessLevel());
+			client.setLastServer(info.getLastServer());
+			try (Connection con = L2DatabaseFactory.getInstance().getConnection();
+				PreparedStatement ps = con.prepareStatement(ACCOUNT_INFO_UPDATE))
 			{
-				failedAttempt.increaseCounter(password);
-				failedCount = failedAttempt.getCount();
+				ps.setLong(1, System.currentTimeMillis());
+				ps.setString(2, address.getHostAddress());
+				ps.setString(3, info.getLogin());
+				ps.execute();
 			}
 			
-			if (failedCount >= Config.LOGIN_TRY_BEFORE_BAN)
-			{
-				_log.info("Banning '" + address.getHostAddress() + "' for " + Config.LOGIN_BLOCK_AFTER_BAN + " seconds due to " + failedCount + " invalid user/pass attempts");
-				this.addBanForAddress(address, Config.LOGIN_BLOCK_AFTER_BAN * 1000);
-			}
+			return true;
 		}
-		else
+		catch (Exception e)
 		{
-			_hackProtection.remove(address);
-			if (Config.LOG_LOGIN_CONTROLLER)
-			{
-				Log.add("'" + user + "' " + address.getHostAddress() + " - OK : LoginOk", "loginlog");
-			}
+			_log.log(Level.WARNING, "Could not finish login process!", e);
+			return false;
 		}
-		
-		return ok;
 	}
 	
 	public boolean isValidIPAddress(String ipAddress)
@@ -726,79 +637,24 @@ public boolean isValidIPAddress(String ipAddress)
 		return true;
 	}
 	
-	class FailedLoginAttempt
+	public static void load() throws GeneralSecurityException
 	{
-		// private InetAddress _ipAddress;
-		private int _count;
-		private long _lastAttempTime;
-		private String _lastPassword;
-		
-		public FailedLoginAttempt(InetAddress address, String lastPassword)
-		{
-			// _ipAddress = address;
-			_count = 1;
-			_lastAttempTime = System.currentTimeMillis();
-			_lastPassword = lastPassword;
-		}
-		
-		public void increaseCounter(String password)
+		synchronized (LoginController.class)
 		{
-			if (!_lastPassword.equals(password))
+			if (_instance == null)
 			{
-				// check if theres a long time since last wrong try
-				if ((System.currentTimeMillis() - _lastAttempTime) < (300 * 1000))
-				{
-					_count++;
-				}
-				else
-				{
-					// restart the status
-					_count = 1;
-					
-				}
-				_lastPassword = password;
-				_lastAttempTime = System.currentTimeMillis();
+				_instance = new LoginController();
 			}
 			else
-			// trying the same password is not brute force
 			{
-				_lastAttempTime = System.currentTimeMillis();
+				throw new IllegalStateException("LoginController can only be loaded a single time.");
 			}
 		}
-		
-		public int getCount()
-		{
-			return _count;
-		}
-		
-		public void increaseCounter()
-		{
-			_count++;
-		}
-		
 	}
 	
-	class BanInfo
+	public static LoginController getInstance()
 	{
-		private final InetAddress _ipAddress;
-		// Expiration
-		private final long _expiration;
-		
-		public BanInfo(InetAddress ipAddress, long expiration)
-		{
-			_ipAddress = ipAddress;
-			_expiration = expiration;
-		}
-		
-		public InetAddress getAddress()
-		{
-			return _ipAddress;
-		}
-		
-		public boolean hasExpired()
-		{
-			return (System.currentTimeMillis() > _expiration) && (_expiration > 0);
-		}
+		return _instance;
 	}
 	
 	class PurgeThread extends Thread
@@ -836,4 +692,13 @@ public void run()
 			}
 		}
 	}
+	
+	public static enum AuthLoginResult
+	{
+		INVALID_PASSWORD,
+		ACCOUNT_BANNED,
+		ALREADY_ON_LS,
+		ALREADY_ON_GS,
+		AUTH_SUCCESS
+	}
 }
diff --git a/L2J_Server_BETA/java/com/l2jserver/loginserver/model/data/AccountInfo.java b/L2J_Server_BETA/java/com/l2jserver/loginserver/model/data/AccountInfo.java
new file mode 100644
index 0000000..55f9f2e
--- /dev/null
+++ b/L2J_Server_BETA/java/com/l2jserver/loginserver/model/data/AccountInfo.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2004-2014 L2J Server
+ * 
+ * This file is part of L2J Server.
+ * 
+ * L2J Server 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 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * L2J Server is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.l2jserver.loginserver.model.data;
+
+/**
+ * @author FBIagent
+ */
+public final class AccountInfo
+{
+	private final String _login;
+	private final String _passHash;
+	private final int _accessLevel;
+	private final int _lastServer;
+	
+	public AccountInfo(String login, String passHash, int accessLevel, int lastServer)
+	{
+		if (login == null)
+		{
+			throw new NullPointerException("login");
+		}
+		if (passHash == null)
+		{
+			throw new NullPointerException("passHash");
+		}
+		
+		if (login.isEmpty())
+		{
+			throw new IllegalArgumentException("login");
+		}
+		if (passHash.isEmpty())
+		{
+			throw new IllegalArgumentException("passHash");
+		}
+		
+		_login = login;
+		_passHash = passHash;
+		_accessLevel = accessLevel;
+		_lastServer = lastServer;
+	}
+	
+	public boolean checkPassHash(String passHash)
+	{
+		return _passHash.equals(passHash);
+	}
+	
+	public String getLogin()
+	{
+		return _login;
+	}
+	
+	public int getAccessLevel()
+	{
+		return _accessLevel;
+	}
+	
+	public int getLastServer()
+	{
+		return _lastServer;
+	}
+}
diff --git a/L2J_Server_BETA/java/com/l2jserver/loginserver/network/clientpackets/RequestAuthLogin.java b/L2J_Server_BETA/java/com/l2jserver/loginserver/network/clientpackets/RequestAuthLogin.java
index 79e78c4..46f3fc6 100644
--- a/L2J_Server_BETA/java/com/l2jserver/loginserver/network/clientpackets/RequestAuthLogin.java
+++ b/L2J_Server_BETA/java/com/l2jserver/loginserver/network/clientpackets/RequestAuthLogin.java
@@ -18,6 +18,7 @@
  */
 package com.l2jserver.loginserver.network.clientpackets;
 
+import java.net.InetAddress;
 import java.security.GeneralSecurityException;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -28,6 +29,7 @@
 import com.l2jserver.loginserver.GameServerTable.GameServerInfo;
 import com.l2jserver.loginserver.LoginController;
 import com.l2jserver.loginserver.LoginController.AuthLoginResult;
+import com.l2jserver.loginserver.model.data.AccountInfo;
 import com.l2jserver.loginserver.network.L2LoginClient;
 import com.l2jserver.loginserver.network.L2LoginClient.LoginClientState;
 import com.l2jserver.loginserver.network.serverpackets.AccountKicked;
@@ -118,15 +120,25 @@ public void run()
 			return;
 		}
 		
+		InetAddress clientAddr = getClient().getConnection().getInetAddress();
+		
 		final LoginController lc = LoginController.getInstance();
-		AuthLoginResult result = lc.tryAuthLogin(_user, _password, client);
+		AccountInfo info = lc.retriveAccountInfo(clientAddr, _user, _password);
+		if (info == null)
+		{
+			// user or pass wrong
+			client.close(LoginFailReason.REASON_USER_OR_PASS_WRONG);
+			return;
+		}
+		
+		AuthLoginResult result = lc.tryCheckinAccount(client, clientAddr, info);
 		switch (result)
 		{
 			case AUTH_SUCCESS:
-				client.setAccount(_user);
+				client.setAccount(info.getLogin());
 				client.setState(LoginClientState.AUTHED_LOGIN);
-				client.setSessionKey(lc.assignSessionKeyToClient(_user, client));
-				lc.getCharactersOnAccount(_user);
+				client.setSessionKey(lc.assignSessionKeyToClient(info.getLogin(), client));
+				lc.getCharactersOnAccount(info.getLogin());
 				if (Config.SHOW_LICENCE)
 				{
 					client.sendPacket(new LoginOk(getClient().getSessionKey()));
@@ -141,28 +153,28 @@ public void run()
 				break;
 			case ACCOUNT_BANNED:
 				client.close(new AccountKicked(AccountKickedReason.REASON_PERMANENTLY_BANNED));
-				break;
+				return;
 			case ALREADY_ON_LS:
 				L2LoginClient oldClient;
-				if ((oldClient = lc.getAuthedClient(_user)) != null)
+				if ((oldClient = lc.getAuthedClient(info.getLogin())) != null)
 				{
 					// kick the other client
 					oldClient.close(LoginFailReason.REASON_ACCOUNT_IN_USE);
-					lc.removeAuthedLoginClient(_user);
+					lc.removeAuthedLoginClient(info.getLogin());
 				}
 				// kick also current client
 				client.close(LoginFailReason.REASON_ACCOUNT_IN_USE);
 				break;
 			case ALREADY_ON_GS:
 				GameServerInfo gsi;
-				if ((gsi = lc.getAccountOnGameServer(_user)) != null)
+				if ((gsi = lc.getAccountOnGameServer(info.getLogin())) != null)
 				{
 					client.close(LoginFailReason.REASON_ACCOUNT_IN_USE);
 					
 					// kick from there
 					if (gsi.isAuthed())
 					{
-						gsi.getGameServerThread().kickPlayer(_user);
+						gsi.getGameServerThread().kickPlayer(info.getLogin());
 					}
 				}
 				break;
diff --git a/L2J_Server_BETA/java/com/l2jserver/util/lib/Log.java b/L2J_Server_BETA/java/com/l2jserver/util/lib/Log.java
deleted file mode 100644
index ddfdac6..0000000
--- a/L2J_Server_BETA/java/com/l2jserver/util/lib/Log.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2004-2014 L2J Server
- * 
- * This file is part of L2J Server.
- * 
- * L2J Server 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 3 of the License, or
- * (at your option) any later version.
- * 
- * L2J Server is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.l2jserver.util.lib;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import com.l2jserver.Config;
-
-/**
- * @version 0.1, 2005-06-06
- * @author Balancer
- */
-public class Log
-{
-	private static final Logger _log = Logger.getLogger(Log.class.getName());
-	
-	public static final void add(String text, String cat)
-	{
-		String date = (new SimpleDateFormat("yy.MM.dd H:mm:ss")).format(new Date());
-		String curr = (new SimpleDateFormat("yyyy-MM-dd-")).format(new Date());
-		new File("log/game").mkdirs();
-		
-		final File file = new File("log/game/" + (curr != null ? curr : "") + (cat != null ? cat : "unk") + ".txt");
-		try (FileWriter save = new FileWriter(file, true))
-		{
-			save.write("[" + date + "] " + text + Config.EOL);
-		}
-		catch (IOException e)
-		{
-			_log.log(Level.WARNING, "Error saving logfile: ", e);
-		}
-	}
-}