Noticias:

Debes de estar registrado para poder ver el contenido indicado. Registrate o Conectate

Menú Principal

Anti-Duplicate Items

Iniciado por Swarlog, Ago 14, 2022, 01:17 AM

Tema anterior - Siguiente tema

Swarlog


CitarSOLUCIÓN:

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);
-        }
-    }
-}