예제 #1
0
    public BattlenetRpcErrorCode JoinRealm(uint realmAddress, uint build, IPAddress clientAddress, Array <byte> clientSecret, LocaleConstant locale, string os, string accountName, Bgs.Protocol.GameUtilities.V1.ClientResponse response)
    {
        Realm realm = GetRealm(new RealmHandle(realmAddress));

        if (realm != null)
        {
            if (realm.Flags.HasAnyFlag(RealmFlags.Offline) || realm.Build != build)
            {
                return(BattlenetRpcErrorCode.UserServerNotPermittedOnRealm);
            }

            RealmListServerIPAddresses serverAddresses = new RealmListServerIPAddresses();
            AddressFamily addressFamily = new AddressFamily();
            addressFamily.Id = 1;

            var address = new Address();
            address.Ip   = realm.GetAddressForClient(clientAddress).Address.ToString();
            address.Port = realm.Port;
            addressFamily.Addresses.Add(address);
            serverAddresses.Families.Add(addressFamily);

            byte[] compressed = Json.Deflate("JSONRealmListServerIPAddresses", serverAddresses);

            byte[] serverSecret = new byte[0].GenerateRandomKey(32);

            Sha256 sha256 = new Sha256();
            sha256.Process(clientSecret.ToArray(), clientSecret.Count);
            sha256.Finish(serverSecret, 32);

            PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_BNET_GAME_ACCOUNT_LOGIN_INFO);
            stmt.AddValue(0, sha256.Digest.ToHexString());
            stmt.AddValue(1, clientAddress.ToString());
            stmt.AddValue(2, locale);
            stmt.AddValue(3, os);
            stmt.AddValue(4, accountName);
            DB.Login.Execute(stmt);

            Bgs.Protocol.Attribute attribute = new Bgs.Protocol.Attribute();
            attribute.Name            = "Param_RealmJoinTicket";
            attribute.Value           = new Bgs.Protocol.Variant();
            attribute.Value.BlobValue = Google.Protobuf.ByteString.CopyFrom(accountName, System.Text.Encoding.UTF8);
            response.Attribute.Add(attribute);

            attribute                 = new Bgs.Protocol.Attribute();
            attribute.Name            = "Param_ServerAddresses";
            attribute.Value           = new Bgs.Protocol.Variant();
            attribute.Value.BlobValue = Google.Protobuf.ByteString.CopyFrom(compressed);
            response.Attribute.Add(attribute);

            attribute                 = new Bgs.Protocol.Attribute();
            attribute.Name            = "Param_JoinSecret";
            attribute.Value           = new Bgs.Protocol.Variant();
            attribute.Value.BlobValue = Google.Protobuf.ByteString.CopyFrom(serverSecret);
            response.Attribute.Add(attribute);
            return(BattlenetRpcErrorCode.Ok);
        }

        return(BattlenetRpcErrorCode.UtilServerUnknownRealm);
    }
예제 #2
0
        public override void Write()
        {
            ByteBuffer whereBuffer = new ByteBuffer();

            whereBuffer.WriteUInt8((byte)Payload.Where.Type);

            switch (Payload.Where.Type)
            {
            case AddressType.IPv4:
                whereBuffer.WriteBytes(Payload.Where.IPv4);
                break;

            case AddressType.IPv6:
                whereBuffer.WriteBytes(Payload.Where.IPv6);
                break;

            case AddressType.NamedSocket:
                whereBuffer.WriteString(Payload.Where.NameSocket);
                break;

            default:
                break;
            }

            Sha256 hash = new Sha256();

            hash.Process(whereBuffer.GetData(), (int)whereBuffer.GetSize());
            hash.Process((uint)Payload.Where.Type);
            hash.Finish(BitConverter.GetBytes(Payload.Port));

            Payload.Signature = RsaCrypt.RSA.SignHash(hash.Digest, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1).Reverse().ToArray();

            _worldPacket.WriteBytes(Payload.Signature, (uint)Payload.Signature.Length);
            _worldPacket.WriteBytes(whereBuffer);
            _worldPacket.WriteUInt16(Payload.Port);
            _worldPacket.WriteUInt32((uint)Serial);
            _worldPacket.WriteUInt8(Con);
            _worldPacket.WriteUInt64(Key);
        }
예제 #3
0
        void HandleAuthSessionCallback(AuthSession authSession, SQLResult result)
        {
            // Stop if the account is not found
            if (result.IsEmpty())
            {
                Log.outError(LogFilter.Network, "HandleAuthSession: Sent Auth Response (unknown account).");
                CloseSocket();
                return;
            }

            AccountInfo account = new AccountInfo(result.GetFields());

            // For hook purposes, we get Remoteaddress at this point.
            string address = GetRemoteIpAddress().ToString();

            byte[] clientSeed = ClientTypeSeed_Win;
            if (account.game.OS == "Wn64")
            {
                clientSeed = ClientTypeSeed_Wn64;
            }
            else if (account.game.OS == "Mc64")
            {
                clientSeed = ClientTypeSeed_Mc64;
            }

            Sha256 digestKeyHash = new Sha256();

            digestKeyHash.Process(account.game.SessionKey, account.game.SessionKey.Length);
            digestKeyHash.Finish(clientSeed, clientSeed.Length);

            HmacSha256 hmac = new HmacSha256(digestKeyHash.Digest);

            hmac.Process(authSession.LocalChallenge, authSession.LocalChallenge.Count);
            hmac.Process(_serverChallenge, 16);
            hmac.Finish(AuthCheckSeed, 16);

            // Check that Key and account name are the same on client and server
            if (!hmac.Digest.Compare(authSession.Digest))
            {
                Log.outError(LogFilter.Network, "WorldSocket.HandleAuthSession: Authentication failed for account: {0} ('{1}') address: {2}", account.game.Id, authSession.RealmJoinTicket, address);
                CloseSocket();
                return;
            }

            Sha256 keyData = new Sha256();

            keyData.Finish(account.game.SessionKey, account.game.SessionKey.Length);

            HmacSha256 sessionKeyHmac = new HmacSha256(keyData.Digest);

            sessionKeyHmac.Process(_serverChallenge, 16);
            sessionKeyHmac.Process(authSession.LocalChallenge, authSession.LocalChallenge.Count);
            sessionKeyHmac.Finish(SessionKeySeed, 16);

            _sessionKey = new byte[40];
            var sessionKeyGenerator = new SessionKeyGenerator(sessionKeyHmac.Digest, 32);

            sessionKeyGenerator.Generate(_sessionKey, 40);

            // As we don't know if attempted login process by ip works, we update last_attempt_ip right away
            PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_LAST_ATTEMPT_IP);

            stmt.AddValue(0, address);
            stmt.AddValue(1, authSession.RealmJoinTicket);

            DB.Login.Execute(stmt);
            // This also allows to check for possible "hack" attempts on account

            stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_ACCOUNT_INFO_CONTINUED_SESSION);
            stmt.AddValue(0, _sessionKey.ToHexString());
            stmt.AddValue(1, account.game.Id);
            DB.Login.Execute(stmt);

            // First reject the connection if packet contains invalid data or realm state doesn't allow logging in
            if (Global.WorldMgr.IsClosed())
            {
                SendAuthResponseError(BattlenetRpcErrorCode.Denied);
                Log.outError(LogFilter.Network, "WorldSocket.HandleAuthSession: World closed, denying client ({0}).", GetRemoteIpAddress());
                CloseSocket();
                return;
            }

            if (authSession.RealmID != Global.WorldMgr.GetRealm().Id.Realm)
            {
                SendAuthResponseError(BattlenetRpcErrorCode.Denied);
                Log.outError(LogFilter.Network, "WorldSocket.HandleAuthSession: Client {0} requested connecting with realm id {1} but this realm has id {2} set in config.",
                             GetRemoteIpAddress().ToString(), authSession.RealmID, Global.WorldMgr.GetRealm().Id.Realm);
                CloseSocket();
                return;
            }

            // Must be done before WorldSession is created
            bool wardenActive = WorldConfig.GetBoolValue(WorldCfg.WardenEnabled);

            if (wardenActive && account.game.OS != "Win" && account.game.OS != "Wn64" && account.game.OS != "Mc64")
            {
                SendAuthResponseError(BattlenetRpcErrorCode.Denied);
                Log.outError(LogFilter.Network, "WorldSocket.HandleAuthSession: Client {0} attempted to log in using invalid client OS ({1}).", address, account.game.OS);
                CloseSocket();
                return;
            }

            //Re-check ip locking (same check as in auth).
            if (account.battleNet.IsLockedToIP) // if ip is locked
            {
                if (account.battleNet.LastIP != address)
                {
                    SendAuthResponseError(BattlenetRpcErrorCode.RiskAccountLocked);
                    Log.outDebug(LogFilter.Network, "HandleAuthSession: Sent Auth Response (Account IP differs).");
                    CloseSocket();
                    return;
                }
            }
            else if (!account.battleNet.LockCountry.IsEmpty() && account.battleNet.LockCountry != "00" && !_ipCountry.IsEmpty())
            {
                if (account.battleNet.LockCountry != _ipCountry)
                {
                    SendAuthResponseError(BattlenetRpcErrorCode.RiskAccountLocked);
                    Log.outDebug(LogFilter.Network, "WorldSocket.HandleAuthSession: Sent Auth Response (Account country differs. Original country: {0}, new country: {1}).", account.battleNet.LockCountry, _ipCountry);
                    CloseSocket();
                    return;
                }
            }

            long mutetime = account.game.MuteTime;

            //! Negative mutetime indicates amount of seconds to be muted effective on next login - which is now.
            if (mutetime < 0)
            {
                mutetime = Time.UnixTime + mutetime;

                stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_MUTE_TIME_LOGIN);
                stmt.AddValue(0, mutetime);
                stmt.AddValue(1, account.game.Id);
                DB.Login.Execute(stmt);
            }

            if (account.IsBanned()) // if account banned
            {
                SendAuthResponseError(BattlenetRpcErrorCode.GameAccountBanned);
                Log.outError(LogFilter.Network, "WorldSocket:HandleAuthSession: Sent Auth Response (Account banned).");
                CloseSocket();
                return;
            }

            // Check locked state for server
            AccountTypes allowedAccountType = Global.WorldMgr.GetPlayerSecurityLimit();

            if (allowedAccountType > AccountTypes.Player && account.game.Security < allowedAccountType)
            {
                SendAuthResponseError(BattlenetRpcErrorCode.ServerIsPrivate);
                Log.outInfo(LogFilter.Network, "WorldSocket:HandleAuthSession: User tries to login but his security level is not enough");
                CloseSocket();
                return;
            }

            Log.outDebug(LogFilter.Network, "WorldSocket:HandleAuthSession: Client '{0}' authenticated successfully from {1}.", authSession.RealmJoinTicket, address);

            // Update the last_ip in the database
            stmt = DB.Login.GetPreparedStatement(LoginStatements.UPD_LAST_IP);
            stmt.AddValue(0, address);
            stmt.AddValue(1, authSession.RealmJoinTicket);
            DB.Login.Execute(stmt);

            _worldSession = new WorldSession(account.game.Id, authSession.RealmJoinTicket, account.battleNet.Id, this, account.game.Security, (Expansion)account.game.Expansion,
                                             mutetime, account.game.OS, account.battleNet.Locale, account.game.Recruiter, account.game.IsRectuiter);

            // Initialize Warden system only if it is enabled by config
            //if (wardenActive)
            //_worldSession.InitWarden(_sessionKey);

            _queryProcessor.AddQuery(_worldSession.LoadPermissionsAsync().WithCallback(LoadSessionPermissionsCallback));
        }