Browse Source

Refactored login-server clif to structs (#8058)

Communication between the login-server and the client is now done with structs.
Moved the definition of the global reusable packet buffer to socket.hpp
Lemongrass3110 1 year ago
parent
commit
7999ccb215

+ 0 - 4
src/char/char_clif.cpp

@@ -30,10 +30,6 @@
 
 using namespace rathena;
 
-// Reuseable global packet buffer to prevent too many allocations
-// Take socket.cpp::socket_max_client_packet into consideration
-static int8 packet_buffer[UINT16_MAX];
-
 std::vector<struct s_point_str> accessible_maps{
 	s_point_str{ MAP_PRONTERA, 273, 354 },
 	s_point_str{ MAP_GEFFEN, 120, 100 },

+ 1 - 0
src/common/common.vcxproj

@@ -34,6 +34,7 @@
     <ClInclude Include="mmo.hpp" />
     <ClInclude Include="msg_conf.hpp" />
     <ClInclude Include="nullpo.hpp" />
+    <ClInclude Include="packets.hpp" />
     <ClInclude Include="random.hpp" />
     <ClInclude Include="showmsg.hpp" />
     <ClInclude Include="socket.hpp" />

+ 3 - 0
src/common/common.vcxproj.filters

@@ -56,6 +56,9 @@
     <ClInclude Include="nullpo.hpp">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="packets.hpp">
+      <Filter>Header Files</Filter>
+    </ClInclude>
     <ClInclude Include="random.hpp">
       <Filter>Header Files</Filter>
     </ClInclude>

+ 3 - 0
src/common/mmo.hpp

@@ -116,6 +116,9 @@ typedef uint32 t_itemid;
 #ifndef MAX_BARTER_REQUIREMENTS
 	#define MAX_BARTER_REQUIREMENTS 5
 #endif
+#ifndef WEB_AUTH_TOKEN_LENGTH
+	#define WEB_AUTH_TOKEN_LENGTH 16+1
+#endif
 
 enum e_enchantgrade : uint16{
 	ENCHANTGRADE_NONE = 0,

+ 212 - 0
src/common/packets.hpp

@@ -0,0 +1,212 @@
+// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#ifndef PACKETS_HPP
+#define PACKETS_HPP
+
+#include <common/cbasetypes.hpp>
+#include <common/mmo.hpp>
+
+#pragma warning( push )
+#pragma warning( disable : 4200 )
+
+#define DEFINE_PACKET_HEADER( name, id ) const int16 HEADER_##name = id
+#define DEFINE_PACKET_ID( name, id ) DEFINE_PACKET_HEADER( name, id )
+
+// NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
+#if !defined( sun ) && ( !defined( __NETBSD__ ) || __NetBSD_Version__ >= 600000000 )
+	#pragma pack( push, 1 )
+#endif
+
+struct PACKET_CA_LOGIN{
+	int16 packetType;
+	uint32 version;
+	char username[NAME_LENGTH];
+	char password[NAME_LENGTH];
+	uint8 clienttype;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CA_LOGIN, 0x64 );
+
+#if PACKETVER >= 20170315
+struct PACKET_AC_ACCEPT_LOGIN_sub{
+	uint32 ip;
+	uint16 port;
+	char name[20];
+	uint16 users;
+	uint16 type;
+	uint16 new_;
+	uint8 unknown[128];
+} __attribute__((packed));
+
+struct PACKET_AC_ACCEPT_LOGIN{
+	int16 packetType;
+	int16 packetLength;
+	uint32 login_id1;
+	uint32 AID;
+	uint32 login_id2;
+	uint32 last_ip;
+	char last_login[26];
+	uint8 sex;
+	char token[WEB_AUTH_TOKEN_LENGTH];
+	PACKET_AC_ACCEPT_LOGIN_sub char_servers[];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( AC_ACCEPT_LOGIN, 0xac4 );
+#else
+struct PACKET_AC_ACCEPT_LOGIN_sub{
+	uint32 ip;
+	uint16 port;
+	char name[20];
+	uint16 users;
+	uint16 type;
+	uint16 new_;
+} __attribute__((packed));
+
+struct PACKET_AC_ACCEPT_LOGIN{
+	int16 packetType;
+	int16 packetLength;
+	uint32 login_id1;
+	uint32 AID;
+	uint32 login_id2;
+	uint32 last_ip;
+	char last_login[26];
+	uint8 sex;
+	PACKET_AC_ACCEPT_LOGIN_sub char_servers[];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( AC_ACCEPT_LOGIN, 0x69 );
+#endif
+
+// not sure when this started
+#if PACKETVER >= 20120000
+struct PACKET_AC_REFUSE_LOGIN{
+	int16 packetType;
+	uint32 error;
+	char unblock_time[20];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( AC_REFUSE_LOGIN, 0x83e );
+#else
+struct PACKET_AC_REFUSE_LOGIN{
+	int16 packetType;
+	uint8 error;
+	char unblock_time[20];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( AC_REFUSE_LOGIN, 0x6a );
+#endif
+
+struct PACKET_SC_NOTIFY_BAN{
+	int16 packetType;
+	uint8 result;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( SC_NOTIFY_BAN, 0x81 );
+
+struct PACKET_CA_REQ_HASH{
+	int16 packetType;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CA_REQ_HASH, 0x1db );
+
+struct PACKET_AC_ACK_HASH{
+	int16 packetType;
+	int16 packetLength;
+	char salt[];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( AC_ACK_HASH, 0x1dc );
+
+struct PACKET_CA_LOGIN2{
+	int16 packetType;
+	uint32 version;
+	char username[NAME_LENGTH];
+	uint8 passwordMD5[16];
+	uint8 clienttype;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CA_LOGIN2, 0x1dd );
+
+struct PACKET_CA_LOGIN3{
+	int16 packetType;
+	uint32 version;
+	char username[NAME_LENGTH];
+	uint8 passwordMD5[16];
+	uint8 clienttype;
+	uint8 clientinfo;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CA_LOGIN3, 0x1fa );
+
+struct PACKET_CA_CONNECT_INFO_CHANGED{
+	int16 packetType;
+	char name[NAME_LENGTH];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CA_CONNECT_INFO_CHANGED, 0x200 );
+
+struct PACKET_CA_EXE_HASHCHECK{
+	int16 packetType;
+	char hash[16];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CA_EXE_HASHCHECK, 0x204 );
+
+struct PACKET_CA_LOGIN_PCBANG{
+	int16 packetType;
+	uint32 version;
+	char username[NAME_LENGTH];
+	char password[NAME_LENGTH];
+	uint8 clienttype;
+	char ip[16];
+	char mac[13];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CA_LOGIN_PCBANG, 0x277 );
+
+struct PACKET_CA_LOGIN4{
+	int16 packetType;
+	uint32 version;
+	char username[NAME_LENGTH];
+	uint8 passwordMD5[16];
+	uint8 clienttype;
+	char mac[13];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CA_LOGIN4, 0x27c );
+
+struct PACKET_CA_LOGIN_CHANNEL{
+	int16 packetType;
+	uint32 version;
+	char username[NAME_LENGTH];
+	char password[NAME_LENGTH];
+	uint8 clienttype;
+	char ip[16];
+	char mac[13];
+	uint8 is_gravity;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CA_LOGIN_CHANNEL, 0x2b0 );
+
+struct PACKET_CA_SSO_LOGIN_REQ{
+	int16 packetType;
+	int16 packetLength;
+	uint32 version;
+	uint8 clienttype;
+	char username[NAME_LENGTH];
+	char password[27];
+	char mac[17];
+	char ip[15];
+	char token[];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CA_SSO_LOGIN_REQ, 0x825 );
+
+struct PACKET_CT_AUTH{
+	int16 packetType;
+	uint8 unknown[66];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( CT_AUTH, 0xacf );
+
+struct PACKET_TC_RESULT{
+	int16 packetType;
+	int16 packetLength;
+	uint32 type;
+	char unknown1[20];
+	char unknown2[6];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER( TC_RESULT, 0xae3 );
+
+// NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
+#if !defined( sun ) && ( !defined( __NETBSD__ ) || __NetBSD_Version__ >= 600000000 )
+	#pragma pack( pop )
+#endif
+
+#pragma warning( pop )
+
+#endif /* PACKETS_HPP */

+ 30 - 0
src/common/socket.hpp

@@ -199,4 +199,34 @@ void send_shortlist_add_fd(int fd);
 void send_shortlist_do_sends();
 #endif
 
+// Reuseable global packet buffer to prevent too many allocations
+// Take socket.cpp::socket_max_client_packet into consideration
+static int8 packet_buffer[UINT16_MAX];
+
+template <typename P>
+bool socket_send( int fd, P& packet ){
+	if( !session_isActive( fd ) ){
+		return false;
+	}
+
+	WFIFOHEAD( fd, sizeof( P ) );
+	memcpy( WFIFOP( fd, 0 ), &packet, sizeof( P ) );
+	WFIFOSET( fd, sizeof( P ) );
+
+	return true;
+}
+
+template <typename P>
+bool socket_send( int fd, P* packet ){
+	if( !session_isActive( fd ) ){
+		return false;
+	}
+
+	WFIFOHEAD( fd, packet->packetLength );
+	memcpy( WFIFOP( fd, 0 ), packet, packet->packetLength );
+	WFIFOSET( fd, packet->packetLength );
+
+	return true;
+}
+
 #endif /* SOCKET_HPP */

+ 1 - 5
src/login/account.hpp

@@ -5,13 +5,9 @@
 #define ACCOUNT_HPP
 
 #include <common/cbasetypes.hpp>
-#include <common/mmo.hpp> // ACCOUNT_REG2_NUM
+#include <common/mmo.hpp> // ACCOUNT_REG2_NUM, WEB_AUTH_TOKEN_LENGTH
 #include <config/core.hpp>
 
-#ifndef WEB_AUTH_TOKEN_LENGTH
-#define WEB_AUTH_TOKEN_LENGTH 16+1
-#endif
-
 typedef struct AccountDB AccountDB;
 typedef struct AccountDBIterator AccountDBIterator;
 

+ 259 - 207
src/login/loginclif.cpp

@@ -8,6 +8,7 @@
 
 #include <common/malloc.hpp>
 #include <common/md5calc.hpp>
+#include <common/packets.hpp>
 #include <common/random.hpp>
 #include <common/showmsg.hpp> //show notice
 #include <common/socket.hpp> //wfifo session
@@ -31,10 +32,12 @@
  * <result>.B (SC_NOTIFY_BAN)
  */
 static void logclif_sent_auth_result(int fd,char result){
-	WFIFOHEAD(fd,3);
-	WFIFOW(fd,0) = 0x81;
-	WFIFOB(fd,2) = result;
-	WFIFOSET(fd,3);
+	PACKET_SC_NOTIFY_BAN p = {};
+
+	p.packetType = HEADER_SC_NOTIFY_BAN;
+	p.result = result;
+
+	socket_send( fd, p );
 }
 
 /**
@@ -49,16 +52,6 @@ static void logclif_auth_ok(struct login_session_data* sd) {
 	uint32 subnet_char_ip;
 	int i;
 
-#if PACKETVER < 20170315
-	int cmd = 0x69; // AC_ACCEPT_LOGIN
-	int header = 47;
-	int size = 32;
-#else
-	int cmd = 0xac4; // AC_ACCEPT_LOGIN3
-	int header = 64;
-	int size = 160;
-#endif
-
 	if( !global_core->is_running() ){
 		// players can only login while running
 		logclif_sent_auth_result(fd,1); // server closed
@@ -118,33 +111,39 @@ static void logclif_auth_ok(struct login_session_data* sd) {
 	login_log(ip, sd->userid, 100, "login ok");
 	ShowStatus("Connection of the account '%s' accepted.\n", sd->userid);
 
-	WFIFOHEAD(fd,header+size*server_num);
-	WFIFOW(fd,0) = cmd;
-	WFIFOW(fd,2) = header+size*server_num;
-	WFIFOL(fd,4) = sd->login_id1;
-	WFIFOL(fd,8) = sd->account_id;
-	WFIFOL(fd,12) = sd->login_id2;
-	WFIFOL(fd,16) = 0; // in old version, that was for ip (not more used)
-	//memcpy(WFIFOP(fd,20), sd->lastlogin, 24); // in old version, that was for name (not more used)
-	memset(WFIFOP(fd,20), 0, 24);
-	WFIFOW(fd,44) = 0; // unknown
-	WFIFOB(fd,46) = sex_str2num(sd->sex);
+	PACKET_AC_ACCEPT_LOGIN* p = (PACKET_AC_ACCEPT_LOGIN*)packet_buffer;
+
+	p->packetType = HEADER_AC_ACCEPT_LOGIN;
+	p->packetLength = sizeof( *p );
+	p->login_id1 = sd->login_id1;
+	p->AID = sd->account_id;
+	p->login_id2 = sd->login_id2;
+	// in old version, that was for ip (not more used)
+	p->last_ip = 0;
+	// in old version, that was for last login time (not more used)
+	safestrncpy( p->last_login, "", sizeof( p->last_login ) );
+	p->sex = sex_str2num( sd->sex );
 #if PACKETVER >= 20170315
-	safestrncpy( WFIFOCP( fd, 47 ), sd->web_auth_token, WEB_AUTH_TOKEN_LENGTH ); // web authentication token
+	safestrncpy( p->token, sd->web_auth_token, WEB_AUTH_TOKEN_LENGTH ); // web authentication token
 #endif
+
 	for( i = 0, n = 0; i < ARRAYLENGTH(ch_server); ++i ) {
 		if( !session_isValid(ch_server[i].fd) )
 			continue;
 		subnet_char_ip = lan_subnetcheck(ip); // Advanced subnet check [LuzZza]
-		WFIFOL(fd,header+n*size) = htonl((subnet_char_ip) ? subnet_char_ip : ch_server[i].ip);
-		WFIFOW(fd,header+n*size+4) = ntows(htons(ch_server[i].port)); // [!] LE byte order here [!]
-		memcpy(WFIFOP(fd,header+n*size+6), ch_server[i].name, 20);
-		WFIFOW(fd,header+n*size+26) = login_get_usercount( ch_server[i].users );
-		WFIFOW(fd,header+n*size+28) = ch_server[i].type;
-		WFIFOW(fd,header+n*size+30) = ch_server[i].new_;
+
+		PACKET_AC_ACCEPT_LOGIN_sub& char_server = p->char_servers[n];
+
+		char_server.ip = htonl( ( subnet_char_ip ) ? subnet_char_ip : ch_server[i].ip );
+		char_server.port = ntows( htons( ch_server[i].port ) ); // [!] LE byte order here [!]
+		safestrncpy( char_server.name, ch_server[i].name, sizeof( char_server.name ) );
+		char_server.users = login_get_usercount( ch_server[i].users );
+		char_server.type = ch_server[i].type;
+		char_server.new_ = ch_server[i].new_;
 #if PACKETVER >= 20170315
-		memset(WFIFOP(fd, header+n*size+32), 0, 128); // Unknown
+		memset( &char_server.unknown, 0, sizeof( char_server.unknown ) );
 #endif
+
 #ifdef DEBUG
 		ShowDebug(
 			"Sending the client (%d %d.%d.%d.%d) to char-server %s with ip %d.%d.%d.%d and port "
@@ -152,9 +151,12 @@ static void logclif_auth_ok(struct login_session_data* sd) {
 			sd->account_id, CONVIP(ip), ch_server[i].name,
 			CONVIP((subnet_char_ip) ? subnet_char_ip : ch_server[i].ip), ch_server[i].port);
 #endif
+
 		n++;
+		p->packetLength += sizeof( char_server );
 	}
-	WFIFOSET(fd,header+size*server_num);
+
+	socket_send( fd, p );
 
 	// create temporary auth entry
 	login_add_auth_node( sd, ip );
@@ -165,6 +167,16 @@ static void logclif_auth_ok(struct login_session_data* sd) {
 	data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, login_waiting_disconnect_timer, sd->account_id, 0);
 }
 
+static void logclif_auth_failed( int fd, int result, const char* unblock_time = "" ){
+	PACKET_AC_REFUSE_LOGIN p = {};
+
+	p.packetType = HEADER_AC_REFUSE_LOGIN;
+	p.error = result;
+	safestrncpy( p.unblock_time, "", sizeof( p.unblock_time ) );
+
+	socket_send( fd, p );
+}
+
 /**
  * Inform client that auth has failed.
  * @param sd: player session
@@ -210,33 +222,18 @@ static void logclif_auth_failed(struct login_session_data* sd, int result) {
 	if( (result == 0 || result == 1) && login_config.dynamic_pass_failure_ban )
 		ipban_log(ip); // log failed password attempt
 
-#if PACKETVER >= 20120000 /* not sure when this started */
-	WFIFOHEAD(fd,26);
-	WFIFOW(fd,0) = 0x83e;
-	WFIFOL(fd,2) = result;
-	if( result != 6 )
-		memset(WFIFOP(fd,6), '\0', 20);
-	else { // 6 = You are prohibited to log in until %s
-		struct mmo_account acc;
-		AccountDB* accounts = login_get_accounts_db();
-		time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0;
-		timestamp2string(WFIFOCP(fd,6), 20, unban_time, login_config.date_format);
-	}
-	WFIFOSET(fd,26);
-#else
-	WFIFOHEAD(fd,23);
-	WFIFOW(fd,0) = 0x6a;
-	WFIFOB(fd,2) = (uint8)result;
-	if( result != 6 )
-		memset(WFIFOP(fd,3), '\0', 20);
-	else { // 6 = You are prohibited to log in until %s
+	// 6 = You are prohibited to log in until %s
+	if( result == 6 ){
+		char unblock_time[20];
 		struct mmo_account acc;
 		AccountDB* accounts = login_get_accounts_db();
-		time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0;
-		timestamp2string(WFIFOCP(fd,3), 20, unban_time, login_config.date_format);
+		time_t unban_time = ( accounts->load_str( accounts, &acc, sd->userid ) ) ? acc.unban_time : 0;
+		timestamp2string( unblock_time, sizeof( unblock_time ), unban_time, login_config.date_format );
+
+		logclif_auth_failed( fd, result, unblock_time );
+	}else{
+		logclif_auth_failed( fd, result );
 	}
-	WFIFOSET(fd,23);
-#endif	
 }
 
 /**
@@ -246,9 +243,14 @@ static void logclif_auth_failed(struct login_session_data* sd, int result) {
  * @return 0 not enough info transmitted, 1 success
  */
 static int logclif_parse_keepalive(int fd){
-	if (RFIFOREST(fd) < 26)
+	PACKET_CA_CONNECT_INFO_CHANGED* p = (PACKET_CA_CONNECT_INFO_CHANGED*)RFIFOP( fd, 0 );
+
+	if( RFIFOREST( fd ) < sizeof( *p ) ){
 		return 0;
-	RFIFOSKIP(fd,26);
+	}
+
+	RFIFOSKIP( fd,  sizeof( *p ) );
+
 	return 1;
 }
 
@@ -259,112 +261,124 @@ static int logclif_parse_keepalive(int fd){
  * @return 0 not enough info transmitted, 1 success
  */
 static int logclif_parse_updclhash(int fd, struct login_session_data *sd){
-	if (RFIFOREST(fd) < 18)
+	PACKET_CA_EXE_HASHCHECK* p = (PACKET_CA_EXE_HASHCHECK*)RFIFOP( fd, 0 );
+
+	if( RFIFOREST( fd ) < sizeof( *p ) ){
 		return 0;
+	}
+
 	sd->has_client_hash = 1;
-	memcpy(sd->client_hash, RFIFOP(fd, 2), 16);
-	RFIFOSKIP(fd,18);
+	memcpy( sd->client_hash, p->hash, sizeof( sd->client_hash ) );
+
+	RFIFOSKIP( fd,  sizeof( *p ) );
+
 	return 1;
 }
 
-/**
- * Received a connection request.
- * @param fd: file descriptor to parse from (client)
- * @param sd: client session
- * @param command: packet type sent
- * @param ip: ipv4 address (client)
- *  S 0064 <version>.L <username>.24B <password>.24B <clienttype>.B
- *  S 0277 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B
- *  S 02b0 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B <g_isGravityID>.B
- *  S 01dd <version>.L <username>.24B <password hash>.16B <clienttype>.B
- *  S 01fa <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.B(index of the connection in the clientinfo file (+10 if the command-line contains "pc"))
- *  S 027c <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.13B(junk)
- *  S 0825 <packetsize>.W <version>.L <clienttype>.B <userid>.24B <password>.27B <mac>.17B <ip>.15B <token>.(packetsize - 0x5C)B
- * @param fd: fd to parse from (client fd)
- * @return 0 failure, 1 success
- */
-static int logclif_parse_reqauth(int fd, struct login_session_data *sd, int command, char* ip){
-	size_t packet_len = RFIFOREST(fd);
-
-	if( (command == 0x0064 && packet_len < 55)
-	||  (command == 0x0277 && packet_len < 84)
-	||  (command == 0x02b0 && packet_len < 85)
-	||  (command == 0x01dd && packet_len < 47)
-	||  (command == 0x01fa && packet_len < 48)
-	||  (command == 0x027c && packet_len < 60)
-	||  (command == 0x0825 && (packet_len < 4 || packet_len < RFIFOW(fd, 2))) )
+template <typename P>
+int logclif_parse_reqauth_raw( int fd, login_session_data& sd, char* ip ){
+	P* p = (P*)RFIFOP( fd, 0 );
+
+	if( RFIFOREST( fd ) < sizeof( *p ) ){
 		return 0;
-	else {
-		int result;
-		char username[NAME_LENGTH];
-		char password[PASSWD_LENGTH];
-		unsigned char passhash[16];
-		uint8 clienttype;
-		bool israwpass = (command==0x0064 || command==0x0277 || command==0x02b0 || command == 0x0825);
-
-		// Shinryo: For the time being, just use token as password.
-		if(command == 0x0825) {
-			char *accname = RFIFOCP(fd, 9);
-			char *token = RFIFOCP(fd, 0x5C);
-			size_t uAccLen = strlen(accname);
-			size_t uTokenLen = RFIFOREST(fd) - 0x5C;
-
-			if(uAccLen > NAME_LENGTH - 1 || uAccLen == 0 || uTokenLen > NAME_LENGTH - 1  || uTokenLen == 0)
-			{
-				logclif_auth_failed(sd, 3);
-				return 0;
-			}
+	}
 
-			safestrncpy(username, accname, uAccLen + 1);
-			safestrncpy(password, token, uTokenLen + 1);
-			clienttype = RFIFOB(fd, 8);
-		}
-		else
-		{
-			safestrncpy(username, RFIFOCP(fd,6), NAME_LENGTH);
-			if( israwpass )
-			{
-				safestrncpy(password, RFIFOCP(fd,30), PASSWD_LENGTH);
-				clienttype = RFIFOB(fd,54);
-			}
-			else
-			{
-				memcpy(passhash, RFIFOP(fd,30), 16);
-				clienttype = RFIFOB(fd,46);
-			}
-		}
-		RFIFOSKIP(fd,RFIFOREST(fd)); // assume no other packet was sent
+	safestrncpy( sd.userid, p->username, sizeof( sd.userid ) );
+	sd.clienttype = p->clienttype;
 
-		sd->clienttype = clienttype;
-		safestrncpy(sd->userid, username, NAME_LENGTH);
-		if( israwpass )
-		{
-			ShowStatus("Request for connection of %s (ip: %s)\n", sd->userid, ip);
-			safestrncpy(sd->passwd, password, PASSWD_LENGTH);
-			if( login_config.use_md5_passwds )
-				MD5_String(sd->passwd, sd->passwd);
-			sd->passwdenc = 0;
-		}
-		else
-		{
-			ShowStatus("Request for connection (passwdenc mode) of %s (ip: %s)\n", sd->userid, ip);
-			bin2hex(sd->passwd, passhash, 16); // raw binary data here!
-			sd->passwdenc = PASSWORDENC;
-		}
+	ShowStatus( "Request for connection of %s (ip: %s)\n", sd.userid, ip );
+	safestrncpy( sd.passwd, p->password, PASSWD_LENGTH );
 
-		if( sd->passwdenc != 0 && login_config.use_md5_passwds )
-		{
-			logclif_auth_failed(sd, 3); // send "rejected from server"
-			return 0;
-		}
+	if( login_config.use_md5_passwds ){
+		MD5_String( sd.passwd, sd.passwd );
+	}
 
-		result = login_mmo_auth(sd, false);
+	sd.passwdenc = 0;
 
-		if( result == -1 )
-			logclif_auth_ok(sd);
-		else
-			logclif_auth_failed(sd, result);
+	RFIFOSKIP( fd, sizeof( *p ) );
+
+	int result = login_mmo_auth( &sd, false );
+
+	if( result == -1 ){
+		logclif_auth_ok( &sd );
+	}else{
+		logclif_auth_failed( &sd, result );
+	}
+
+	return 1;
+}
+
+template <typename P>
+int logclif_parse_reqauth_md5( int fd, login_session_data& sd, char* ip ){
+	P* p = (P*)RFIFOP( fd, 0 );
+
+	if( RFIFOREST( fd ) < sizeof( *p ) ){
+		return 0;
+	}
+
+	safestrncpy( sd.userid, p->username, sizeof( sd.userid ) );
+	sd.clienttype = p->clienttype;
+
+	ShowStatus( "Request for connection (passwdenc mode) of %s (ip: %s)\n", sd.userid, ip );
+	bin2hex( sd.passwd, p->passwordMD5, sizeof( p->passwordMD5 ) ); // raw binary data here!
+
+	sd.passwdenc = PASSWORDENC;
+
+	RFIFOSKIP( fd, sizeof( *p ) );
+
+	if( login_config.use_md5_passwds ){
+		logclif_auth_failed( &sd, 3 ); // send "rejected from server"
+		return 0;
+	}
+
+	int result = login_mmo_auth( &sd, false );
+
+	if( result == -1 ){
+		logclif_auth_ok( &sd );
+	}else{
+		logclif_auth_failed( &sd, result );
 	}
+
+	return 1;
+}
+
+template <typename P>
+int logclif_parse_reqauth_sso( int fd, login_session_data& sd, char* ip ){
+	P* p = (P*)RFIFOP( fd, 0 );
+
+	if( RFIFOREST( fd ) < sizeof( *p ) ){
+		return 0;
+	}
+
+	if( RFIFOREST( fd ) < p->packetLength ){
+		return 0;
+	}
+
+	size_t token_length = p->packetLength - sizeof( *p );
+
+	safestrncpy( sd.userid, p->username, sizeof( sd.userid ) );
+	sd.clienttype = p->clienttype;
+
+	ShowStatus( "Request for connection (SSO mode) of %s (ip: %s)\n", sd.userid, ip );
+	// Shinryo: For the time being, just use token as password.
+	safestrncpy( sd.passwd, p->token, token_length );
+
+	if( login_config.use_md5_passwds ){
+		MD5_String( sd.passwd, sd.passwd );
+	}
+
+	sd.passwdenc = 0;
+
+	RFIFOSKIP( fd, sizeof( *p ) );
+
+	int result = login_mmo_auth( &sd, false );
+
+	if( result == -1 ){
+		logclif_auth_ok( &sd );
+	}else{
+		logclif_auth_failed( &sd, result );
+	}
+
 	return 1;
 }
 
@@ -375,17 +389,25 @@ static int logclif_parse_reqauth(int fd, struct login_session_data *sd, int comm
  * @return 1 success
  */
 static int logclif_parse_reqkey(int fd, struct login_session_data *sd){
-	RFIFOSKIP(fd,2);
-	{
-		sd->md5keylen = sizeof( sd->md5key );
-		MD5_Salt(sd->md5keylen, sd->md5key);
-
-		WFIFOHEAD(fd,4 + sd->md5keylen);
-		WFIFOW(fd,0) = 0x01dc;
-		WFIFOW(fd,2) = 4 + sd->md5keylen;
-		memcpy(WFIFOP(fd,4), sd->md5key, sd->md5keylen);
-		WFIFOSET(fd,WFIFOW(fd,2));
+	PACKET_CA_REQ_HASH* p_in = (PACKET_CA_REQ_HASH*)RFIFOP( fd, 0 );
+
+	if( RFIFOREST( fd ) < sizeof( *p_in ) ){
+		return 0;
 	}
+
+	RFIFOSKIP( fd,  sizeof( *p_in ) );
+
+	sd->md5keylen = sizeof( sd->md5key );
+	MD5_Salt( sd->md5keylen, sd->md5key );
+
+	PACKET_AC_ACK_HASH* p_out = (PACKET_AC_ACK_HASH*)packet_buffer;
+
+	p_out->packetType = HEADER_AC_ACK_HASH;
+	p_out->packetLength = sizeof( *p_out ) + sd->md5keylen;
+	strncpy( p_out->salt, sd->md5key, sd->md5keylen );
+
+	socket_send( fd, p_out );
+
 	return 1;
 }
 
@@ -464,15 +486,23 @@ static int logclif_parse_reqcharconnec(int fd, struct login_session_data *sd, ch
 }
 
 int logclif_parse_otp_login( int fd, struct login_session_data* sd ){
-	RFIFOSKIP( fd, 68 );
+	PACKET_CT_AUTH* p_in = (PACKET_CT_AUTH*)RFIFOP( fd, 0 );
+
+	if( RFIFOREST( fd ) < sizeof( *p_in ) ){
+		return 0;
+	}
+
+	RFIFOSKIP( fd,  sizeof( *p_in ) );
+
+	PACKET_TC_RESULT p_out = {};
+
+	p_out.packetType = HEADER_TC_RESULT;
+	p_out.packetLength = sizeof( p_out );
+	p_out.type = 0; // normal login
+	safestrncpy( p_out.unknown1, "S1000", sizeof( p_out.unknown1 ) );
+	safestrncpy( p_out.unknown2, "token", sizeof( p_out.unknown2 ) );
 
-	WFIFOHEAD( fd, 34 );
-	WFIFOW( fd, 0 ) = 0xae3;
-	WFIFOW( fd, 2 ) = 34;
-	WFIFOL( fd, 4 ) = 0; // normal login
-	safestrncpy( WFIFOCP( fd, 8 ), "S1000", 6 );
-	safestrncpy( WFIFOCP( fd, 28 ), "token", 6 );
-	WFIFOSET( fd, 34 );
+	socket_send( fd, p_out );
 
 	return 1;
 }
@@ -497,17 +527,15 @@ int logclif_parse(int fd) {
 		return 0;
 	}
 
-	if( sd == NULL )
-	{
+	if( sd == nullptr ){
 		// Perform ip-ban check
 		if( login_config.ipban && ipban_check(ipl) )
 		{
 			ShowStatus("Connection refused: IP isn't authorised (deny/allow, ip: %s).\n", ip);
 			login_log(ipl, "unknown", -3, "ip banned");
-			WFIFOHEAD(fd,23);
-			WFIFOW(fd,0) = 0x6a;
-			WFIFOB(fd,2) = 3; // 3 = Rejected from Server
-			WFIFOSET(fd,23);
+
+			logclif_auth_failed( fd, 3 ); // 3 = Rejected from Server
+
 			set_eof(fd);
 			return 0;
 		}
@@ -522,35 +550,59 @@ int logclif_parse(int fd) {
 		uint16 command = RFIFOW(fd,0);
 		int next=1;
 
-		switch( command )
-		{
-		// New alive packet: used to verify if client is always alive.
-		case 0x0200: next = logclif_parse_keepalive(fd); break;
-		// client md5 hash (binary)
-		case 0x0204: next = logclif_parse_updclhash(fd,sd); break;
-		// request client login (raw password)
-		case 0x0064: // S 0064 <version>.L <username>.24B <password>.24B <clienttype>.B
-		case 0x0277: // S 0277 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B
-		case 0x02b0: // S 02b0 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B <g_isGravityID>.B
-		// request client login (md5-hashed password)
-		case 0x01dd: // S 01dd <version>.L <username>.24B <password hash>.16B <clienttype>.B
-		case 0x01fa: // S 01fa <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.B(index of the connection in the clientinfo file (+10 if the command-line contains "pc"))
-		case 0x027c: // S 027c <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.13B(junk)
-		case 0x0825: // S 0825 <packetsize>.W <version>.L <clienttype>.B <userid>.24B <password>.27B <mac>.17B <ip>.15B <token>.(packetsize - 0x5C)B
-			next = logclif_parse_reqauth(fd,  sd, command, ip); 
-			break;
-		// Sending request of the coding key
-		case 0x01db: next = logclif_parse_reqkey(fd, sd); break;
-		// OTP token login
-		case 0x0acf:
-			next = logclif_parse_otp_login( fd, sd );
-			break;
-		// Connection request of a char-server
-		case 0x2710: logclif_parse_reqcharconnec(fd,sd, ip); return 0; // processing will continue elsewhere
-		default:
-			ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, command);
-			set_eof(fd);
-			return 0;
+		switch( command ){
+			// New alive packet: used to verify if client is always alive.
+			case HEADER_CA_CONNECT_INFO_CHANGED:
+				next = logclif_parse_keepalive( fd );
+				break;
+			// client md5 hash (binary)
+			case HEADER_CA_EXE_HASHCHECK:
+				next = logclif_parse_updclhash( fd, sd );
+				break;
+			// request client login (raw password)
+			case HEADER_CA_LOGIN:
+				// S 0064 <version>.L <username>.24B <password>.24B <clienttype>.B
+				next = logclif_parse_reqauth_raw<PACKET_CA_LOGIN>( fd, *sd, ip );
+				break;
+			case HEADER_CA_LOGIN_PCBANG:
+				// S 0277 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B
+				next = logclif_parse_reqauth_raw<PACKET_CA_LOGIN_PCBANG>( fd, *sd, ip );
+				break;
+			case HEADER_CA_LOGIN_CHANNEL:
+				// S 02b0 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B <g_isGravityID>.B
+				next = logclif_parse_reqauth_raw<PACKET_CA_LOGIN_CHANNEL>( fd, *sd, ip );
+				break;
+			// request client login (md5-hashed password)
+			case HEADER_CA_LOGIN2:
+				// S 01dd <version>.L <username>.24B <password hash>.16B <clienttype>.B
+				next = logclif_parse_reqauth_md5<PACKET_CA_LOGIN2>( fd, *sd, ip );
+				break;
+			case HEADER_CA_LOGIN3:
+				// S 01fa <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.B(index of the connection in the clientinfo file (+10 if the command-line contains "pc"))
+				next = logclif_parse_reqauth_md5<PACKET_CA_LOGIN3>( fd, *sd, ip );
+				break;
+			case HEADER_CA_LOGIN4:
+				// S 027c <version>.L <username>.24B <password hash>.16B <clienttype>.B <adapter address>.13B
+				next = logclif_parse_reqauth_md5<PACKET_CA_LOGIN4>( fd, *sd, ip );
+				break;
+			case HEADER_CA_SSO_LOGIN_REQ:
+				// S 0825 <packetsize>.W <version>.L <clienttype>.B <userid>.24B <password>.27B <mac>.17B <ip>.15B <token>.?B
+				next = logclif_parse_reqauth_sso<PACKET_CA_SSO_LOGIN_REQ>( fd, *sd, ip );
+				break;
+			// Sending request of the coding key
+			case HEADER_CA_REQ_HASH:
+				next = logclif_parse_reqkey( fd, sd );
+				break;
+			// OTP token login
+			case HEADER_CT_AUTH:
+				next = logclif_parse_otp_login( fd, sd );
+				break;
+			// Connection request of a char-server
+			case 0x2710: logclif_parse_reqcharconnec(fd,sd, ip); return 0; // processing will continue elsewhere
+			default:
+				ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, command);
+				set_eof(fd);
+				return 0;
 		}
 		if(next==0) return 0; // avoid processing of followup packets (prev was probably incomplete)
 	}

+ 0 - 3
src/map/clif.cpp

@@ -81,9 +81,6 @@ static inline int32 client_exp(t_exp exp) {
 static struct eri *delay_clearunit_ers;
 
 struct s_packet_db packet_db[MAX_PACKET_DB + 1];
-// Reuseable global packet buffer to prevent too many allocations
-// Take socket.cpp::socket_max_client_packet into consideration
-static int8 packet_buffer[UINT16_MAX];
 unsigned long color_table[COLOR_MAX];
 
 #include "clif_obfuscation.hpp"