diff --git a/src/char/char_clif.cpp b/src/char/char_clif.cpp index fc547090f1..0ead36110d 100644 --- a/src/char/char_clif.cpp +++ b/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 accessible_maps{ s_point_str{ MAP_PRONTERA, 273, 354 }, s_point_str{ MAP_GEFFEN, 120, 100 }, diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index 13090af7c7..4f1e7254f7 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj @@ -34,6 +34,7 @@ + diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters index 8aff9e4471..62b42598f4 100644 --- a/src/common/common.vcxproj.filters +++ b/src/common/common.vcxproj.filters @@ -56,6 +56,9 @@ Header Files + + Header Files + Header Files diff --git a/src/common/mmo.hpp b/src/common/mmo.hpp index 9959af6705..050c370209 100644 --- a/src/common/mmo.hpp +++ b/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, diff --git a/src/common/packets.hpp b/src/common/packets.hpp new file mode 100644 index 0000000000..bdcf84bff2 --- /dev/null +++ b/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 +#include + +#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 */ diff --git a/src/common/socket.hpp b/src/common/socket.hpp index 76480e4306..c072ee399c 100644 --- a/src/common/socket.hpp +++ b/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 +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 +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 */ diff --git a/src/login/account.hpp b/src/login/account.hpp index 99bfd50f7e..1adeb3e0f5 100644 --- a/src/login/account.hpp +++ b/src/login/account.hpp @@ -5,13 +5,9 @@ #define ACCOUNT_HPP #include -#include // ACCOUNT_REG2_NUM +#include // ACCOUNT_REG2_NUM, WEB_AUTH_TOKEN_LENGTH #include -#ifndef WEB_AUTH_TOKEN_LENGTH -#define WEB_AUTH_TOKEN_LENGTH 16+1 -#endif - typedef struct AccountDB AccountDB; typedef struct AccountDBIterator AccountDBIterator; diff --git a/src/login/loginclif.cpp b/src/login/loginclif.cpp index 7201994da9..7155891a00 100644 --- a/src/login/loginclif.cpp +++ b/src/login/loginclif.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include //show notice #include //wfifo session @@ -31,10 +32,12 @@ * .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 + // 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,6), 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,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 - 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); - } - 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 .L .24B .24B .B - * S 0277 .L .24B .24B .B .16B .13B - * S 02b0 .L .24B .24B .B .16B .13B .B - * S 01dd .L .24B .16B .B - * S 01fa .L .24B .16B .B .B(index of the connection in the clientinfo file (+10 if the command-line contains "pc")) - * S 027c .L .24B .16B .B .13B(junk) - * S 0825 .W .L .B .24B .27B .17B .15B .(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); +template +int logclif_parse_reqauth_raw( int fd, login_session_data& sd, char* ip ){ + P* p = (P*)RFIFOP( fd, 0 ); - 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))) ) + 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 - - 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; - } - - if( sd->passwdenc != 0 && login_config.use_md5_passwds ) - { - logclif_auth_failed(sd, 3); // send "rejected from server" - return 0; - } - - result = login_mmo_auth(sd, false); - - if( result == -1 ) - logclif_auth_ok(sd); - else - logclif_auth_failed(sd, result); } + + safestrncpy( sd.userid, p->username, sizeof( sd.userid ) ); + sd.clienttype = p->clienttype; + + ShowStatus( "Request for connection of %s (ip: %s)\n", sd.userid, ip ); + safestrncpy( sd.passwd, p->password, PASSWD_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; +} + +template +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 +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); + PACKET_CA_REQ_HASH* p_in = (PACKET_CA_REQ_HASH*)RFIFOP( fd, 0 ); - 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)); + 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 ); - 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 ); + 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 ) ); + + 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 .L .24B .24B .B - case 0x0277: // S 0277 .L .24B .24B .B .16B .13B - case 0x02b0: // S 02b0 .L .24B .24B .B .16B .13B .B - // request client login (md5-hashed password) - case 0x01dd: // S 01dd .L .24B .16B .B - case 0x01fa: // S 01fa .L .24B .16B .B .B(index of the connection in the clientinfo file (+10 if the command-line contains "pc")) - case 0x027c: // S 027c .L .24B .16B .B .13B(junk) - case 0x0825: // S 0825 .W .L .B .24B .27B .17B .15B .(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 .L .24B .24B .B + next = logclif_parse_reqauth_raw( fd, *sd, ip ); + break; + case HEADER_CA_LOGIN_PCBANG: + // S 0277 .L .24B .24B .B .16B .13B + next = logclif_parse_reqauth_raw( fd, *sd, ip ); + break; + case HEADER_CA_LOGIN_CHANNEL: + // S 02b0 .L .24B .24B .B .16B .13B .B + next = logclif_parse_reqauth_raw( fd, *sd, ip ); + break; + // request client login (md5-hashed password) + case HEADER_CA_LOGIN2: + // S 01dd .L .24B .16B .B + next = logclif_parse_reqauth_md5( fd, *sd, ip ); + break; + case HEADER_CA_LOGIN3: + // S 01fa .L .24B .16B .B .B(index of the connection in the clientinfo file (+10 if the command-line contains "pc")) + next = logclif_parse_reqauth_md5( fd, *sd, ip ); + break; + case HEADER_CA_LOGIN4: + // S 027c .L .24B .16B .B .13B + next = logclif_parse_reqauth_md5( fd, *sd, ip ); + break; + case HEADER_CA_SSO_LOGIN_REQ: + // S 0825 .W .L .B .24B .27B .17B .15B .?B + next = logclif_parse_reqauth_sso( 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) } diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 647fc9d84b..6e59564d59 100644 --- a/src/map/clif.cpp +++ b/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"