Browse Source

Login Server updates

- DoF and classic clients will auto login after char creation instead of getting stuck at character select
- model_color and soga_model_color properly tracked on login server
- Removed ServerOP_WorldListUpdate code (revisit at a later time)
- Login account flag fix, sets Veteran Bonus under 'Select Character' yellow (vs greyed out), adventure/tradeskill bonus 200%
- Fixed disabled flag in login_worldservers not working
- Added login_bannedips table
- Both are checked periodically against the database with logged in worlds
Image 3 years ago
parent
commit
9f9d61fbe4

+ 40 - 39
EQ2/source/LoginServer/LWorld.cpp

@@ -64,6 +64,13 @@ LWorld::LWorld(TCPConnection* in_con, bool in_OutgoingLoginUplink, int32 iIP, in
 		ip = iIP;
 	else
 		ip = in_con->GetrIP();
+
+	struct in_addr  in;
+	in.s_addr = in_con->GetrIP();
+	char* ipadd = inet_ntoa(in);
+	if(ipadd)
+		strncpy(IPAddr,ipadd,64);
+
 	if (iPort)
 		port = iPort;
 	else
@@ -100,7 +107,6 @@ LWorld::LWorld(TCPConnection* in_con, bool in_OutgoingLoginUplink, int32 iIP, in
 		OutgoingUplink = false;
 	}
 
-	struct in_addr  in;
 	in.s_addr = GetIP();
 	strcpy(address, inet_ntoa(in));
 	isaddressip = true;
@@ -115,6 +121,7 @@ LWorld::LWorld(int32 in_accountid, char* in_accountname, char* in_worldname, int
 	ip = 0;
 	port = 0;
 	ID = 0;
+	strcpy(IPAddr,"");
 	pClientPort = 0;
 	memset(account, 0, sizeof(account));
 	memset(address, 0, sizeof(address));
@@ -151,6 +158,16 @@ LWorld::LWorld(TCPConnection* in_RemoteLink, int32 in_ip, int32 in_RemoteID, int
 	RemoteID = in_RemoteID;
 	LinkWorldID = iLinkWorldID;
 	ip = in_ip;
+	
+	struct in_addr  in;
+	if(in_RemoteLink)
+		in.s_addr = in_RemoteLink->GetrIP();
+	else if (in_ip)
+		in.s_addr = in_ip;
+	char* ipadd = inet_ntoa(in);
+	if(ipadd)
+		strncpy(IPAddr,ipadd,64);
+
 	port = 0;
 	ID = 0;
 	pClientPort = 0;
@@ -234,7 +251,15 @@ bool LWorld::Process() {
 		return true;
 
 	if(pStatsTimer && pStatsTimer->Check())
+	{
+		if(isAuthenticated && (database.IsServerAccountDisabled(account) || database.IsIPBanned(IPAddr)))
+		{	
+			this->Kick(ERROR_BADPASSWORD);
+			return false;
+		}
+
 		database.UpdateWorldServerStats(this, GetStatus());
+	}
 
 	ServerPacket* pack = 0;
 	while (ret && (pack = Link->PopPacket())) {
@@ -302,6 +327,10 @@ bool LWorld::Process() {
 			UsertoWorldResponse_Struct* seps = (UsertoWorldResponse_Struct*) pack->pBuffer;
 			if (seps->ToID) {
 				LWorld* world = world_list.FindByID(seps->ToID);
+
+				if (this->GetType() != Login) {
+					break;
+				}
 				if (world) {
 					seps->ToID = world->GetRemoteID();
 					world->SendPacket(pack);
@@ -453,41 +482,6 @@ bool LWorld::Process() {
 			break;
 								  }
 		case ServerOP_WorldListUpdate: {
-			if (this->GetType() != Login) {
-				break;
-			}
-			if (pack->size != sizeof(ServerSyncWorldList_Struct)) {
-				break;
-			}
-			ServerSyncWorldList_Struct* sswls = (ServerSyncWorldList_Struct*) pack->pBuffer;
-			if (!CheckServerName(sswls->name)) {
-				//struct in_addr  in;
-				//in.s_addr = sswls->ip;
-				break; // Someone needs to tell the other login server to update it's exe!
-			}
-			LWorld* world = world_list.FindByLink(this->Link, sswls->RemoteID);
-			if (world) {
-				world->SetRemoteInfo(sswls->ip, sswls->accountid, sswls->account, sswls->name, sswls->address, sswls->status, sswls->adminid, sswls->num_players, sswls->num_zones);
-			}
-			else {
-				world = world_list.FindByAccount(sswls->accountid, World);
-				if (world == 0 || sswls->placeholder == false) {
-					if (world) {
-#ifdef _DEBUG
-						cout << "Kick(" << world->GetID() << ") in ServerOP_WorldListUpdate" << endl;
-#endif
-						world->Kick();
-					}
-					world = new LWorld(this->Link, sswls->ip, sswls->RemoteID, sswls->accountid, sswls->account, sswls->name, sswls->address, sswls->status, sswls->adminid, sswls->showdown, sswls->authlevel, sswls->placeholder, this->GetID());
-					LWorld* world2=world_list.FindByID(sswls->RemoteID);
-					if(!world2)
-						world_list.Add(world);
-				}
-			}
-			sswls->RemoteID = world->GetID();
-			if (net.GetLoginMode() != Mesh)
-				world_list.SendPacketLogin(pack, this);
-			cout << "Got world update for '" << sswls->name << "', #" << world->GetID() << endl;
 			break;
 									   }
 		case ServerOP_WorldListRemove: {
@@ -664,16 +658,24 @@ bool LWorld::SetupWorld(char* in_worldname, char* in_worldaddress, char* in_acco
 		strcpy(address, in_worldaddress);
 	}
 	if (strlen(in_worldname) > 3) {
-		int32 id = database.CheckServerAccount(in_account, in_password);
+		char tmpAccount[30];
+		memcpy(tmpAccount, in_account, 29);
+		tmpAccount[29] = '\0';
+
+		int32 id = database.CheckServerAccount(tmpAccount, in_password);
 
 		if(id == 0)
 			return false;
+		if(database.IsServerAccountDisabled(tmpAccount) || database.IsIPBanned(IPAddr) || (isaddressip && database.IsIPBanned(address)))
+			return false;
+		
 		LWorld* world = world_list.FindByID(id);
 		if(world)
 			world->Kick("Ghost Kick!");
 
 		ID = id;
 		accountid = id;
+		strncpy(account,tmpAccount,30);
 		char* name = database.GetServerAccountName(id);
 		if(name)
 			snprintf(worldname, (sizeof(worldname)) - 1, "%s", name);
@@ -684,7 +686,6 @@ bool LWorld::SetupWorld(char* in_worldname, char* in_worldaddress, char* in_acco
 			return false;
 		}
 		//world_list.KickGhostIP(GetIP(), this);
-		account[0] = 0;
 		IsInit = true;
 		ptype = World;
 		world_list.SendWorldChanged(id, true);
@@ -734,7 +735,7 @@ void LWorld::ChangeToPlaceholder() {
 void LWorld::SetRemoteInfo(int32 in_ip, int32 in_accountid, char* in_account, char* in_name, char* in_address, int32 in_status, int32 in_adminid, sint32 in_players, sint32 in_zones) {
 	ip = in_ip;
 	accountid = in_accountid;
-	strcpy(account, in_account);
+//	strcpy(account, in_account);
 	strcpy(worldname, in_name);
 	strcpy(address, in_address);
 	status = in_status;

+ 1 - 0
EQ2/source/LoginServer/LWorld.h

@@ -115,6 +115,7 @@ protected:
 private:
 	int32	ID;
 	int32	ip;
+	char	IPAddr[64];
 	int16	port;
 	bool	kicked;
 	bool	pNeverKick;

+ 40 - 1
EQ2/source/LoginServer/LoginDatabase.cpp

@@ -395,6 +395,7 @@ int32 LoginDatabase::SaveCharacter(PacketStruct* create, LoginAccount* acct, int
 	}
 	else {
 		SaveCharacterColors(char_id, "skin_color", create->getType_EQ2_Color_ByName("skin_color"));
+		SaveCharacterColors(char_id, "model_color", create->getType_EQ2_Color_ByName("model_color"));
 		SaveCharacterColors(char_id, "eye_color", create->getType_EQ2_Color_ByName("eye_color"));
 		SaveCharacterColors(char_id, "hair_color1", create->getType_EQ2_Color_ByName("hair_color1"));
 		SaveCharacterColors(char_id, "hair_color2", create->getType_EQ2_Color_ByName("hair_color2"));
@@ -412,6 +413,7 @@ int32 LoginDatabase::SaveCharacter(PacketStruct* create, LoginAccount* acct, int
 		SaveCharacterColors(char_id, "unknown9", create->getType_EQ2_Color_ByName("unknown9"));		
 
 		SaveCharacterColors(char_id, "soga_skin_color", create->getType_EQ2_Color_ByName("soga_skin_color"));
+		SaveCharacterColors(char_id, "soga_model_color", create->getType_EQ2_Color_ByName("soga_model_color"));
 		SaveCharacterColors(char_id, "soga_eye_color", create->getType_EQ2_Color_ByName("soga_eye_color"));
 		SaveCharacterColors(char_id, "soga_hair_color1", create->getType_EQ2_Color_ByName("soga_hair_color1"));
 		SaveCharacterColors(char_id, "soga_hair_color2", create->getType_EQ2_Color_ByName("soga_hair_color2"));
@@ -597,7 +599,7 @@ int32 LoginDatabase::CheckServerAccount(char* name, char* passwd){
 	Query query;
 	MYSQL_ROW row;
 	query.escaped_name = getEscapeString(name);
-	MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT lower(password), id from login_worldservers where account='%s'", query.escaped_name);
+	MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT lower(password), id from login_worldservers where account='%s' and disabled = 0", query.escaped_name);
 
 	LogWrite(LOGIN__INFO, 0, "Login", "WorldServer CheckServerAccount Account=%s\nSHA=%s", (char*)query.escaped_name, passwd);
 	if(result && mysql_num_rows(result) == 1){
@@ -613,6 +615,43 @@ int32 LoginDatabase::CheckServerAccount(char* name, char* passwd){
 	}
 	return id;
 }
+
+bool LoginDatabase::IsServerAccountDisabled(char* name){
+	Query query;
+	MYSQL_ROW row;
+	query.escaped_name = getEscapeString(name);
+	MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT id from login_worldservers where account='%s' and disabled = 1", query.escaped_name);
+
+	LogWrite(LOGIN__INFO, 0, "Login", "WorldServer IsServerAccountDisabled Account=%s", (char*)query.escaped_name);
+	if(result && mysql_num_rows(result) > 0){
+		row = mysql_fetch_row(result);
+
+		LogWrite(LOGIN__INFO, 0, "Login", "WorldServer IsServerAccountDisabled Match Account=%s", (char*)query.escaped_name);
+
+		return true;
+	}
+	return false;
+}
+
+bool LoginDatabase::IsIPBanned(char* ipaddr){
+	if(!ipaddr)
+		return false;
+
+	Query query;
+	MYSQL_ROW row;
+	MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT ip from login_bannedips where '%s' LIKE CONCAT(ip ,'%%')", ipaddr);
+
+	LogWrite(LOGIN__INFO, 0, "Login", "WorldServer IsServerIPBanned IPPartial=%s", (char*)ipaddr);
+	if(result && mysql_num_rows(result) > 0){
+		row = mysql_fetch_row(result);
+
+		LogWrite(LOGIN__INFO, 0, "Login", "WorldServer IsServerIPBanned Match IPBan=%s", row[0]);
+
+		return true;
+	}
+	return false;
+}
+
 void LoginDatabase::GetServerAccounts(vector<LWorld*>* server_list){
 	Query query;
 	MYSQL_ROW row;

+ 2 - 0
EQ2/source/LoginServer/LoginDatabase.h

@@ -38,6 +38,8 @@ public:
 	LoginAccount* LoadAccount(const char* name, const char* password, bool attemptAccountCreation=true);
 	int32 GetAccountIDByName(const char* name);
 	int32 CheckServerAccount(char* name, char* passwd);
+	bool IsServerAccountDisabled(char* name);
+	bool IsIPBanned(char* ipaddr);
 	void  GetServerAccounts(vector<LWorld*>* server_list);
 	char* GetServerAccountName(int32 id);
 	bool  VerifyDelete(int32 account_id, int32 character_id, const char* name);

+ 2 - 0
EQ2/source/LoginServer/PacketHeaders.cpp

@@ -41,6 +41,8 @@ EQ2Packet* LS_CharSelectList::serialize(int16 version){
 		for (int i = 0; i < 3; i++)
 			account_info.unknown5[i] = 0xFFFFFFFF;
 		account_info.unknown5[3] = 0;
+		account_info.unknown6 = 0xFFFF; // sets Veteran Bonus under 'Select Character' yellow (vs greyed out), adventure/tradeskill bonus 200%
+		account_info.unknown7 = 0; // when 1 (count?) provides free upgrade option for character to lvl 90 (heroic character) -- its a green 'Free' up arrow next to the character that is selected in char select
 		AddData(account_info);
 	}	
 	return new EQ2Packet(OP_AllCharactersDescReplyMsg, getData(), getDataSize());

+ 17 - 1
EQ2/source/LoginServer/client.cpp

@@ -465,6 +465,22 @@ void Client::CharacterApproved(int32 server_id,int32 char_id)
 			database.LoadCharacters(GetLoginAccount(), GetVersion());
 			
 			SendCharList();
+
+			if (GetVersion() <= 546)
+			{
+				pending_play_char_id = char_id;
+				ServerPacket* outpack = new ServerPacket(ServerOP_UsertoWorldReq, sizeof(UsertoWorldRequest_Struct));
+				UsertoWorldRequest_Struct* req = (UsertoWorldRequest_Struct*)outpack->pBuffer;
+				req->char_id = char_id;
+				req->lsaccountid = GetAccountID();
+				req->worldid = server_id;
+
+				struct in_addr in;
+				in.s_addr = GetIP();
+				strcpy(req->ip_address, inet_ntoa(in));
+				world_server->SendPacket(outpack);
+				delete outpack;
+			}
 		}
 	}
 	else{
@@ -752,4 +768,4 @@ void Client::StartDisconnectTimer() {
 		disconnectTimer = new Timer(1000);
 		disconnectTimer->Start();
 	}
-}
+}

+ 1 - 1
EQ2/source/LoginServer/login_structs.h

@@ -54,7 +54,7 @@ struct LS_CharListAccountInfo{
 	int8	unknown4;
 	int32	unknown5[4];
 	int16	unknown6;
-//	int8	unknown7; // adds 'free' option..
+	int8	unknown7; // adds 'free' option..
 };
 #pragma pack()