/// <summary> /// Loads an account from the mysql database using the given character details. /// </summary> /// <param name="details">The details used to load the account.</param> /// <returns>Returns the account load result.</returns> public AccountLoadResult Load(Details details, LoginConnectionType loginType) { AccountLoadResult result = new AccountLoadResult(); if (GameEngine.World.SystemUpdate) { result.Character = new Character(details, 0); result.ReturnCode = LoginReturnCode.SystemUpdate; } try { DataRow data = null; using (SqlDatabaseClient client = GameServer.Database.GetClient()) { /* * Checks if the character exists in the database. It also * checks if the given password matches the stored password. */ client.AddParameter("username", details.Username); client.AddParameter("password", details.Password); data = client.ReadDataRow("SELECT * FROM characters LEFT JOIN (character_preferences) ON (characters.id = character_preferences.master_id) WHERE username = @username AND password = @password LIMIT 1;"); } if (data != null) // Meaning the character exists, and the password is correct. { result.Character = new Character(details, (uint)data[0]); // If a character is offensive, set the proper penalties. OffenceType offence = (OffenceType)GameEngine.World.OffenseManager.GetOffence(result.Character.MasterId); if (offence == OffenceType.Banned) // If the character is banned, flag and end this request. { result.ReturnCode = LoginReturnCode.AccountDisabled; } if (offence == OffenceType.Muted) // If the character is muted, we will mute this character. { result.Character.Muted = true; } /* * Only check if it's a new connection, as reconnections try * connnecting to the server before the older session is removed, * so we must ignore whether or not the character is online. */ if (loginType != LoginConnectionType.Reconnection && (bool)data[5]) { result.ReturnCode = LoginReturnCode.AlreadyOnline; } /* * We only want to assign the character details loaded from * the database if the player has passed though security. */ if (result.ReturnCode == LoginReturnCode.Successful) { // Core info. result.Character.ClientRights = (ClientRights)data[3]; result.Character.ServerRights = (ServerRights)data[4]; result.Active = (bool)data[6]; // Appearance. result.Character.Appearance.Gender = (Gender)data[14]; result.Character.Appearance.Head = (short)data[15]; result.Character.Appearance.Torso = (short)data[16]; result.Character.Appearance.Arms = (short)data[17]; result.Character.Appearance.Wrist = (short)data[18]; result.Character.Appearance.Legs = (short)data[19]; result.Character.Appearance.Feet = (short)data[20]; result.Character.Appearance.Beard = (short)data[21]; result.Character.Appearance.HairColor = (byte)data[22]; result.Character.Appearance.TorsoColor = (byte)data[23]; result.Character.Appearance.LegColor = (byte)data[24]; result.Character.Appearance.FeetColor = (byte)data[25]; result.Character.Appearance.SkinColor = (byte)data[26]; // Location. result.Character.Location = Location.Create((short)data[27], (short)data[28], (byte)data[29]); // Energy. result.Character.WalkingQueue.RunEnergy = (byte)data[30]; // Containers. if (data[31] is string) { result.Character.Inventory.Deserialize((string)data[31]); } if (data[32] is string) { result.Character.Equipment.Deserialize((string)data[32]); } if (data[33] is string) { result.Character.Bank.Deserialize((string)data[33]); } // Friends and ignores if (data[34] is string) { string friends = (string)data[34]; if (friends != string.Empty) { result.Character.Contacts.DeserializeFriends(friends); } } if (data[35] is string) { string ignores = (string)data[35]; if (ignores != string.Empty) { result.Character.Contacts.DeserializeIgnores((string)data[35]); } } // Preferences. result.Character.Preferences.SingleMouse = (bool)data[37]; result.Character.Preferences.DisableChatEffects = (bool)data[38]; result.Character.Preferences.SplitChat = (bool)data[39]; result.Character.Preferences.AcceptAid = (bool)data[40]; } } else // User doesn't exist or password is wrong. { result.Character = new Character(details, 0); result.ReturnCode = LoginReturnCode.WrongPassword; } } catch (Exception ex) { Program.Logger.WriteException(ex); result.Character = new Character(details, 0); result.ReturnCode = LoginReturnCode.BadSession; } return(result); }
/// <summary> /// Loads an account from the database. /// </summary> /// <param name="details">The character details to look at when loading.</param> public void LoadAccount(Details details, LoginConnectionType loginType) { StringBuilder sbQuery = new StringBuilder(); AccountLoadResult result = this.accountLoader.Load(details, loginType); // Try to load the account. GenericPacketComposer composer = new GenericPacketComposer(); // The packet going to be sent. // Try registering the user if return code is successful so far. if (result.ReturnCode == LoginReturnCode.Successful) { // The world is full. if (!Register(result.Character)) { result.ReturnCode = LoginReturnCode.WorldFull; } } composer.AppendByte((byte)result.ReturnCode); // We only need to send this if the login was successful. if (result.ReturnCode == LoginReturnCode.Successful) { composer.AppendByte((byte)result.Character.ClientRights); composer.AppendByte((byte)0); composer.AppendByte((byte)0); composer.AppendByte((byte)0); composer.AppendByte((byte)1); composer.AppendShort((short)result.Character.Index); composer.AppendByte((byte)1); if (this.logSessions) { sbQuery.Append("UPDATE characters SET last_ip=@ip, last_signin=NOW() WHERE id = @id;"); } } if (this.logAttempts) { sbQuery.Append("INSERT INTO login_attempts (username,date,ip,attempt) VALUES (@name, NOW(), @ip, @attempt);"); } if (!result.Active) { sbQuery.Append("UPDATE characters SET active = '1' WHERE id = @id;"); } if (sbQuery.Length != 0) { // Log the user's login attempt. This is useful for tracking hacking, ddos, etc. using (SqlDatabaseClient client = GameServer.Database.GetClient()) { client.AddParameter("id", result.Character.MasterId); client.AddParameter("name", details.Username); client.AddParameter("ip", details.Session.Connection.IPAddress); client.AddParameter("attempt", result.ReturnCode.ToString()); client.ExecuteUpdate(sbQuery.ToString()); } } // Send results to the client. result.Character.Session.SendData(composer.SerializeBuffer()); // We can now welcome the player and send nessesary packets. if (result.ReturnCode == LoginReturnCode.Successful) { result.Character.Session.StartConnection(); if (!result.Active) { result.Character.Preferences.Add("just_started", true); } Frames.SendLoginWelcome(result.Character); result.Character.Contacts.OnLogin(); } Program.Logger.WriteDebug(result.Character.Name + " returned " + result.ReturnCode + " at login attempt."); }
/// <summary> /// Processes the login verification. /// </summary> /// <param name="request">The request to process and verify.</param> /// <param name="type">The login connection type.</param> public static void Process(LoginRequest request, LoginConnectionType type) { short packetSize = -1; if (request.Buffer.RemainingAmount >= 2) { packetSize = request.Buffer.ReadShort(); // The size will vary depending on user's inputted username and password. } else { return; } if (request.Buffer.RemainingAmount >= packetSize) { Packet p = new Packet(request.Buffer.GetRemainingData()); int encryptedPacketSize = packetSize - packetSize - (36 + 1 + 1 + 2); // Shouldn't be under 0. int clientVersion = p.ReadInt(); if (clientVersion != 508) // Check to make sure the client is 508. { request.LoginStage = -3; return; } // Client preferences. bool lowMemory = p.ReadByte() == 1 ? true : false; bool hd = p.ReadByte() == 1 ? true : false; bool resized = p.ReadByte() == 1 ? true : false; short width = p.ReadShort(); short height = p.ReadShort(); p.Skip(141); int tmpEncryptPacketSize = p.ReadByte(); if (tmpEncryptPacketSize != 10) { int encryptPacketId = p.ReadByte(); } // Session data. long clientKey = p.ReadLong(); // The client's session key. long serverKey = p.ReadLong(); // The client's server session key. // Hash verification. long longName = p.ReadLong(); int hash = (int)(31 & longName >> 16); // Verify client session hash. if (hash != request.NameHash) // Possibly a bot attack. { request.LoginStage = -3; return; } // User data. string username = longName.LongToString(); string password = Hash.GetHash(username + Hash.GetHash( p.ReadString(), HashType.SHA1), HashType.SHA1); // Try to load the account with the given details. Details details = new Details(request.Connection, username, password, hd, resized, clientKey, serverKey); Program.Logger.WriteDebug("Login request: " + details.ToString()); GameEngine.World.CharacterManager.LoadAccount(details, type); request.Finished = true; } return; }