diff options
author | hemagx <hemagx2@gmail.com> | 2016-03-28 21:54:46 +0200 |
---|---|---|
committer | Haru <haru@dotalux.com> | 2016-04-16 07:29:36 +0200 |
commit | 480e959347ac5903d9c0b659376db139792eb44b (patch) | |
tree | 85235026f63260d4005f43edb1d3477195c8090e /src | |
parent | 1c6b5afe8a2926b2364d85d122c3a56ca526e98e (diff) | |
download | hercules-480e959347ac5903d9c0b659376db139792eb44b.tar.gz hercules-480e959347ac5903d9c0b659376db139792eb44b.tar.bz2 hercules-480e959347ac5903d9c0b659376db139792eb44b.tar.xz hercules-480e959347ac5903d9c0b659376db139792eb44b.zip |
Rewrite client interface for login server (part 1)
Rewritten incoming/outgoing packet handlers to use structs instead of
manipulating the WFIFO buffer bytes directly
Signed-off-by: Haru <haru@dotalux.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/common/mmo.h | 7 | ||||
-rw-r--r-- | src/login/login.c | 613 | ||||
-rw-r--r-- | src/login/login.h | 4 | ||||
-rw-r--r-- | src/map/packets_struct.h | 7 |
4 files changed, 454 insertions, 177 deletions
diff --git a/src/common/mmo.h b/src/common/mmo.h index 7df52e450..a2080d900 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2012-2015 Hercules Dev Team + * Copyright (C) 2012-2016 Hercules Dev Team * Copyright (C) Athena Dev Teams * * Hercules is free software: you can redistribute it and/or modify @@ -213,11 +213,6 @@ #define JOBL_BABY 0x2000 //8192 #define JOBL_THIRD 0x4000 //16384 -//Packet DB -#define MIN_PACKET_DB 0x0064 //what's the point of minimum packet id ? [hemagx] -#define MAX_PACKET_DB 0x0F00 -#define MAX_PACKET_POS 20 - #define SCRIPT_VARNAME_LENGTH 32 ///< Maximum length of a script variable #define INFINITE_DURATION (-1) // Infinite duration for status changes diff --git a/src/login/login.c b/src/login/login.c index f7babde86..27cdb1fa3 100644 --- a/src/login/login.c +++ b/src/login/login.c @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2012-2015 Hercules Dev Team + * Copyright (C) 2012-2016 Hercules Dev Team * Copyright (C) Athena Dev Teams * * Hercules is free software: you can redistribute it and/or modify @@ -48,6 +48,192 @@ struct login_interface *login; struct Login_Config login_config_; struct mmo_char_server server[MAX_SERVERS]; // char server data +// Packet DB +#define MIN_PACKET_DB 0x0064 +#define MAX_PACKET_DB 0x08ff + +/// Packet IDs +enum login_packet_id { + // CA (Client to Login) + PACKET_ID_CA_LOGIN = 0x0064, + PACKET_ID_CA_LOGIN2 = 0x01dd, + PACKET_ID_CA_LOGIN3 = 0x01fa, + PACKET_ID_CA_CONNECT_INFO_CHANGED = 0x0200, + PACKET_ID_CA_EXE_HASHCHECK = 0x0204, + PACKET_ID_CA_LOGIN_PCBANG = 0x0277, + PACKET_ID_CA_LOGIN4 = 0x027c, + PACKET_ID_CA_LOGIN_HAN = 0x02b0, + PACKET_ID_CA_SSO_LOGIN_REQ = 0x0825, + PACKET_ID_CA_REQ_HASH = 0x01db, + PACKET_ID_CA_CHARSERVERCONNECT = 0x2710, // Custom Hercules Packet + //PACKET_ID_CA_SSO_LOGIN_REQa = 0x825a, /* unused */ + + // AC (Login to Client) + PACKET_ID_AC_ACCEPT_LOGIN = 0x0069, + PACKET_ID_AC_REFUSE_LOGIN = 0x006a, + PACKET_ID_SC_NOTIFY_BAN = 0x0081, + PACKET_ID_AC_ACK_HASH = 0x01dc, + PACKET_ID_AC_REFUSE_LOGIN_R2 = 0x083e, +}; + +/* Packets Structs */ +#if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute +#pragma pack(push, 1) +#endif // not NetBSD < 6 / Solaris + +struct packet_CA_LOGIN { + int16 packet_id; + uint32 version; + char id[24]; + char password[24]; + uint8 clienttype; +} __attribute__((packed)); + +struct packet_CA_LOGIN2 { + int16 packet_id; + uint32 version; + char id[24]; + uint8 password_md5[16]; + uint8 clienttype; +} __attribute__((packed)); + +struct packet_CA_LOGIN3 { + int16 packet_id; + uint32 version; + char id[24]; + uint8 password_md5[16]; + uint8 clienttype; + uint8 clientinfo; +} __attribute__((packed)); + +struct packet_CA_LOGIN4 { + int16 packet_id; + uint32 version; + char id[24]; + uint8 password_md5[16]; + uint8 clienttype; + char mac_address[13]; +} __attribute__((packed)); + +struct packet_CA_LOGIN_PCBANG { + int16 packet_id; + uint32 version; + char id[24]; + char password[24]; + uint8 clienttype; + char ip[16]; + char mac_address[13]; +} __attribute__((packed)); + +struct packet_CA_LOGIN_HAN { + int16 packet_id; + uint32 version; + char id[24]; + char password[24]; + uint8 clienttype; + char ip[16]; + char mac_address[13]; + uint8 is_han_game_user; +} __attribute__((packed)); + +struct packet_CA_SSO_LOGIN_REQ { + int16 packet_id; + int16 packet_len; + uint32 version; + uint8 clienttype; + char id[24]; + char password[27]; + int8 mac_address[17]; + char ip[15]; + char t1[]; +} __attribute__((packed)); + +#if 0 // Unused +struct packet_CA_SSO_LOGIN_REQa { + int16 packet_id; + int16 packet_len; + uint32 version; + uint8 clienttype; + char id[24]; + int8 mac_address[17]; + char ip[15]; + char t1[]; +} __attribute__((packed)); +#endif // unused + +struct packet_CA_CONNECT_INFO_CHANGED { + int16 packet_id; + char id[24]; +} __attribute__((packed)); + +struct packet_CA_EXE_HASHCHECK { + int16 packet_id; + uint8 hash_value[16]; +} __attribute__((packed)); + +struct packet_CA_REQ_HASH { + int16 packet_id; +} __attribute__((packed)); + +struct packet_CA_CHARSERVERCONNECT { + int16 packet_id; + char userid[24]; + char password[24]; + int32 unknown; + int32 ip; + int16 port; + char name[20]; + int16 unknown2; + int16 type; + int16 new; +} __attribute__((packed)); + +struct packet_SC_NOTIFY_BAN { + int16 packet_id; + uint8 error_code; +} __attribute__((packed)); + +struct packet_AC_REFUSE_LOGIN { + int16 packet_id; + uint8 error_code; + char block_date[20]; +} __attribute__((packed)); + +struct packet_AC_REFUSE_LOGIN_R2 { + int16 packet_id; + uint32 error_code; + char block_date[20]; +} __attribute__((packed)); + +struct packet_AC_ACCEPT_LOGIN { + int16 packet_id; + int16 packet_len; + int32 auth_code; + uint32 aid; + uint32 user_level; + uint32 last_login_ip; + char last_login_time[26]; + uint8 sex; + struct { + uint32 ip; + int16 port; + char name[20]; + uint16 usercount; + uint16 state; + uint16 property; + } server_list[]; +} __attribute__((packed)); + +struct packet_AC_ACK_HASH { + int16 packet_id; + int16 packet_len; + uint8 secret[]; +} __attribute__((packed)); + +#if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute +#pragma pack(pop) +#endif // not NetBSD < 6 / Solaris + struct Account_engine account_engine[] = { {account_db_sql, NULL} }; @@ -1180,12 +1366,14 @@ int login_mmo_auth(struct login_session_data* sd, bool isServer) { return -1; // account OK } -void login_connection_problem(int fd, uint8 status) +void login_connection_problem(int fd, uint8 error) { - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = status; - WFIFOSET(fd,3); + struct packet_SC_NOTIFY_BAN *packet = NULL; + WFIFOHEAD(fd, sizeof(*packet)); + packet = WP2PTR(fd); + packet->packet_id = PACKET_ID_SC_NOTIFY_BAN; + packet->error_code = error; + WFIFOSET(fd, sizeof(*packet)); } void login_kick(struct login_session_data* sd) @@ -1265,38 +1453,45 @@ void login_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,47+32*server_num); - WFIFOW(fd,0) = 0x69; - WFIFOW(fd,2) = 47+32*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); - for (i = 0, n = 0; i < ARRAYLENGTH(server); ++i) { - uint32 subnet_char_ip; - - if (!sockt->session_is_valid(server[i].fd)) - continue; + { + struct packet_AC_ACCEPT_LOGIN *packet = NULL; + int length = sizeof(*packet) + sizeof(packet->server_list[0]) * server_num; + ip = sockt->session[sd->fd]->client_addr; + + // Allocate the packet + WFIFOHEAD(sd->fd, length); + packet = WP2PTR(sd->fd); + + packet->packet_id = PACKET_ID_AC_ACCEPT_LOGIN; + packet->packet_len = length; + packet->auth_code = sd->login_id1; + packet->aid = sd->account_id; + packet->user_level = sd->login_id2; + packet->last_login_ip = 0; // Not used anymore + memset(packet->last_login_time, '\0', sizeof(packet->last_login_time)); // not used anymore + packet->sex = sex_str2num(sd->sex); + for (i = 0, n = 0; i < ARRAYLENGTH(server); ++i) { + uint32 subnet_char_ip; + + if (!sockt->session_is_valid(server[i].fd)) + continue; - subnet_char_ip = login->lan_subnet_check(ip); - WFIFOL(fd,47+n*32) = htonl((subnet_char_ip) ? subnet_char_ip : server[i].ip); - WFIFOW(fd,47+n*32+4) = sockt->ntows(htons(server[i].port)); // [!] LE byte order here [!] - memcpy(WFIFOP(fd,47+n*32+6), server[i].name, 20); - WFIFOW(fd,47+n*32+26) = server[i].users; + subnet_char_ip = login->lan_subnet_check(ip); + packet->server_list[n].ip = htonl((subnet_char_ip) ? subnet_char_ip : server[i].ip); + packet->server_list[n].port = sockt->ntows(htons(server[i].port)); // [!] LE byte order here [!] + safestrncpy(packet->server_list[n].name, server[i].name, 20); + packet->server_list[n].usercount = server[i].users; - if( server[i].type == CST_PAYING && sd->expiration_time > time(NULL) ) - WFIFOW(fd,47+n*32+28) = CST_NORMAL; - else - WFIFOW(fd,47+n*32+28) = server[i].type; + if (server[i].type == CST_PAYING && sd->expiration_time > time(NULL)) + packet->server_list[n].property = CST_NORMAL; + else + packet->server_list[n].property = server[i].type; - WFIFOW(fd,47+n*32+30) = server[i].new_; - n++; + packet->server_list[n].state = server[i].new_; + ++n; + } + WFIFOSET(sd->fd, length); } - WFIFOSET(fd,47+32*server_num); // create temporary auth entry CREATE(node, struct login_auth_node, 1); @@ -1365,121 +1560,191 @@ void login_auth_failed(struct login_session_data* sd, int result) 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 = Your are Prohibited to log in until %s - struct mmo_account acc; - time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0; - timestamp2string(WFIFOP(fd,6), 20, unban_time, login->config->date_format); - } - WFIFOSET(fd,26); + struct packet_AC_REFUSE_LOGIN_R2 *packet = NULL; + int packet_id = PACKET_ID_AC_REFUSE_LOGIN_R2; #else - WFIFOHEAD(fd,23); - WFIFOW(fd,0) = 0x6a; - WFIFOB(fd,2) = (uint8)result; - if( result != 6 ) - memset(WFIFOP(fd,3), '\0', 20); - else { // 6 = Your are Prohibited to log in until %s + struct packet_AC_REFUSE_LOGIN *packet = NULL; + int packet_id = PACKET_ID_AC_REFUSE_LOGIN; +#endif + WFIFOHEAD(fd, sizeof(*packet)); + packet = WP2PTR(fd); + packet->packet_id = packet_id; + packet->error_code = result; + if (result == 6) { struct mmo_account acc; time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0; - timestamp2string(WFIFOP(fd,3), 20, unban_time, login->config->date_format); + timestamp2string(packet->block_date, sizeof(packet->block_date), unban_time, login->config->date_format); + } else { + memset(packet->block_date, '\0', sizeof(packet->block_date)); } - WFIFOSET(fd,23); -#endif + WFIFOSET(fd, sizeof(*packet)); } -void login_login_error(int fd, uint8 status) +void login_login_error(int fd, uint8 error) { - WFIFOHEAD(fd,23); - WFIFOW(fd,0) = 0x6a; - WFIFOB(fd,2) = status; - WFIFOSET(fd,23); + struct packet_AC_REFUSE_LOGIN *packet = NULL; + WFIFOHEAD(fd, sizeof(*packet)); + packet = WP2PTR(fd); + packet->packet_id = PACKET_ID_AC_REFUSE_LOGIN; + packet->error_code = error; + memset(packet->block_date, '\0', sizeof(packet->block_date)); + WFIFOSET(fd, sizeof(*packet)); } +// CA_CONNECT_INFO_CHANGED void login_parse_ping(int fd, struct login_session_data* sd) __attribute__((nonnull (2))); void login_parse_ping(int fd, struct login_session_data* sd) { - RFIFOSKIP(fd,26); + RFIFOSKIP(fd, sizeof(struct packet_CA_CONNECT_INFO_CHANGED)); } +// CA_EXE_HASHCHECK void login_parse_client_md5(int fd, struct login_session_data* sd) __attribute__((nonnull (2))); void login_parse_client_md5(int fd, struct login_session_data* sd) { + const struct packet_CA_EXE_HASHCHECK *packet = RP2PTR(fd); sd->has_client_hash = 1; - memcpy(sd->client_hash, RFIFOP(fd, 2), 16); - - RFIFOSKIP(fd,18); + memcpy(sd->client_hash, packet->hash_value, 16); + RFIFOSKIP(fd,sizeof(*packet)); } bool login_parse_client_login(int fd, struct login_session_data* sd, const char *const ip) __attribute__((nonnull (2))); bool login_parse_client_login(int fd, struct login_session_data* sd, const char *const ip) { - uint32 version; - char username[NAME_LENGTH]; - char password[PASSWD_LEN]; - unsigned char passhash[16]; - uint8 clienttype; int result; uint16 command = RFIFOW(fd,0); - bool israwpass = (command==0x0064 || command==0x0277 || command==0x02b0 || command == 0x0825); - // Shinryo: For the time being, just use token as password. - if(command == 0x0825) + switch (command) { + case PACKET_ID_CA_SSO_LOGIN_REQ: { - const char *accname = RFIFOP(fd, 9); - const char *token = RFIFOP(fd, 0x5C); - size_t uAccLen = strlen(accname); - size_t uTokenLen = RFIFOREST(fd) - 0x5C; + const struct packet_CA_SSO_LOGIN_REQ *packet = RP2PTR(fd); + int tokenlen = (int)RFIFOREST(fd) - (int)sizeof(*packet); - version = RFIFOL(fd,4); - - if(uAccLen <= 0 || uTokenLen <= 0) { + if (tokenlen > PASSWD_LEN || tokenlen < 1) { + RFIFOSKIP(fd, RFIFOREST(fd)); // assume no other packet was sent login->auth_failed(sd, 3); return true; } - safestrncpy(username, accname, NAME_LENGTH); - safestrncpy(password, token, min(uTokenLen+1, PASSWD_LEN)); // Variable-length field, don't copy more than necessary - clienttype = RFIFOB(fd, 8); + sd->clienttype = packet->clienttype; + sd->version = packet->version; + safestrncpy(sd->userid, packet->id, NAME_LENGTH); + safestrncpy(sd->passwd, packet->t1, min(tokenlen + 1, PASSWD_LEN)); // Variable-length field, don't copy more than necessary + + RFIFOSKIP(fd, sizeof(*packet)); + + if (login->config->use_md5_passwds) + MD5_String(sd->passwd, sd->passwd); + sd->passwdenc = PWENC_NONE; } - else + break; + case PACKET_ID_CA_LOGIN: { - version = RFIFOL(fd,2); - safestrncpy(username, RFIFOP(fd,6), NAME_LENGTH); - if( israwpass ) - { - safestrncpy(password, RFIFOP(fd,30), NAME_LENGTH); - clienttype = RFIFOB(fd,54); - } - else - { - memcpy(passhash, RFIFOP(fd,30), 16); - clienttype = RFIFOB(fd,46); - } + const struct packet_CA_LOGIN *packet = RP2PTR(fd); + + sd->version = packet->version; + sd->clienttype = packet->clienttype; + safestrncpy(sd->userid, packet->id, NAME_LENGTH); + safestrncpy(sd->passwd, packet->password, PASSWD_LEN); + + RFIFOSKIP(fd, sizeof(*packet)); + + if (login->config->use_md5_passwds) + MD5_String(sd->passwd, sd->passwd); + sd->passwdenc = PWENC_NONE; + } + break; + case PACKET_ID_CA_LOGIN2: + { + const struct packet_CA_LOGIN2 *packet = RP2PTR(fd); + + sd->version = packet->version; + sd->clienttype = packet->clienttype; + safestrncpy(sd->userid, packet->id, NAME_LENGTH); + bin2hex(sd->passwd, packet->password_md5, 16); + sd->passwdenc = PASSWORDENC; + + RFIFOSKIP(fd, sizeof(*packet)); + } + break; + case PACKET_ID_CA_LOGIN3: + { + const struct packet_CA_LOGIN3 *packet = RP2PTR(fd); + + sd->version = packet->version; + sd->clienttype = packet->clienttype; + /* unused */ + /* sd->clientinfo = packet->clientinfo; */ + safestrncpy(sd->userid, packet->id, NAME_LENGTH); + bin2hex(sd->passwd, packet->password_md5, 16); + sd->passwdenc = PASSWORDENC; + + RFIFOSKIP(fd, sizeof(*packet)); } - RFIFOSKIP(fd,RFIFOREST(fd)); // assume no other packet was sent + break; + case PACKET_ID_CA_LOGIN4: + { + const struct packet_CA_LOGIN4 *packet = RP2PTR(fd); + + sd->version = packet->version; + sd->clienttype = packet->clienttype; + /* unused */ + /* safestrncpy(sd->mac_address, packet->mac_address, sizeof(sd->mac_address)); */ + safestrncpy(sd->userid, packet->id, NAME_LENGTH); + bin2hex(sd->passwd, packet->password_md5, 16); + sd->passwdenc = PASSWORDENC; - sd->clienttype = clienttype; - sd->version = version; - safestrncpy(sd->userid, username, NAME_LENGTH); - if( israwpass ) + RFIFOSKIP(fd, sizeof(*packet)); + } + break; + case PACKET_ID_CA_LOGIN_PCBANG: { - ShowStatus("Request for connection of %s (ip: %s).\n", sd->userid, ip); - safestrncpy(sd->passwd, password, PASSWD_LEN); + const struct packet_CA_LOGIN_PCBANG *packet = RP2PTR(fd); + + sd->version = packet->version; + sd->clienttype = packet->clienttype; + /* unused */ + /* safestrncpy(sd->ip, packet->ip, sizeof(sd->ip)); */ + /* safestrncpy(sd->mac_address, packet->mac_address, sizeof(sd->mac_address)); */ + safestrncpy(sd->userid, packet->id, NAME_LENGTH); + safestrncpy(sd->passwd, packet->password, PASSWD_LEN); + + RFIFOSKIP(fd, sizeof(*packet)); + if (login->config->use_md5_passwds) MD5_String(sd->passwd, sd->passwd); sd->passwdenc = PWENC_NONE; } - else + break; + + case PACKET_ID_CA_LOGIN_HAN: { - 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; + const struct packet_CA_LOGIN_HAN *packet = RP2PTR(fd); + + sd->version = packet->version; + sd->clienttype = packet->clienttype; + /* unused */ + /* safestrncpy(sd->ip, packet->ip, sizeof(sd->ip)); */ + /* safestrncpy(sd->mac_address, packet->mac_address, sizeof(sd->mac_address)); */ + /* sd->ishan = packet->is_han_game_user; */ + safestrncpy(sd->userid, packet->id, NAME_LENGTH); + safestrncpy(sd->passwd, packet->password, PASSWD_LEN); + + RFIFOSKIP(fd, sizeof(*packet)); + + if (login->config->use_md5_passwds) + MD5_String(sd->passwd, sd->passwd); + sd->passwdenc = PWENC_NONE; + } + break; + default: + RFIFOSKIP(fd,RFIFOREST(fd)); // assume no other packet was sent + login->auth_failed(sd, 3); // send "rejected from server" + return true; } + ShowStatus("Request for connection %sof %s (ip: %s).\n", sd->passwdenc == PASSWORDENC ? " (passwdenc mode)" : "", sd->userid, ip); + if (sd->passwdenc != PWENC_NONE && login->config->use_md5_passwds) { login->auth_failed(sd, 3); // send "rejected from server" return true; @@ -1497,16 +1762,22 @@ bool login_parse_client_login(int fd, struct login_session_data* sd, const char void login_send_coding_key(int fd, struct login_session_data* sd) __attribute__((nonnull (2))); void login_send_coding_key(int fd, struct login_session_data* sd) { - 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)); + struct packet_AC_ACK_HASH *packet = NULL; + int16 size = sizeof(*packet) + sd->md5keylen; + + WFIFOHEAD(fd, size); + packet = WP2PTR(fd); + packet->packet_id = PACKET_ID_AC_ACK_HASH; + packet->packet_len = size; + memcpy(packet->secret, sd->md5key, sd->md5keylen); + WFIFOSET(fd, size); } +// CA_REQ_HASH void login_parse_request_coding_key(int fd, struct login_session_data* sd) __attribute__((nonnull (2))); void login_parse_request_coding_key(int fd, struct login_session_data* sd) { + RFIFOSKIP(fd, sizeof(struct packet_CA_REQ_HASH)); memset(sd->md5key, '\0', sizeof(sd->md5key)); sd->md5keylen = (uint16)(12 + rnd() % 4); MD5_Salt(sd->md5keylen, sd->md5key); @@ -1588,21 +1859,18 @@ void login_parse_request_connection(int fd, struct login_session_data* sd, const //---------------------------------------------------------------------------------------- int login_parse_login(int fd) { - struct login_session_data* sd = (struct login_session_data*)sockt->session[fd]->session_data; - + struct login_session_data *sd = NULL; char ip[16]; uint32 ipl = sockt->session[fd]->client_addr; sockt->ip2str(ipl, ip); - if( sockt->session[fd]->flag.eof ) - { + if (sockt->session[fd]->flag.eof) { ShowInfo("Closed connection from '"CL_WHITE"%s"CL_RESET"'.\n", ip); sockt->close(fd); return 0; } - if( sd == NULL ) - { + if ((sd = sockt->session[fd]->session_data) == NULL) { // Perform ip-ban check if (login->config->ipban && !sockt->trusted_ip_check(ipl) && ipban_check(ipl)) { ShowStatus("Connection refused: IP isn't authorized (deny/allow, ip: %s).\n", ip); @@ -1614,81 +1882,90 @@ int login_parse_login(int fd) // create a session for this new connection CREATE(sockt->session[fd]->session_data, struct login_session_data, 1); - sd = (struct login_session_data*)sockt->session[fd]->session_data; + sd = sockt->session[fd]->session_data; sd->fd = fd; } while (RFIFOREST(fd) >= 2) { - uint16 command = RFIFOW(fd,0); + int16 packet_id = RFIFOW(fd, 0); + int packet_len = (int)RFIFOREST(fd); + + if (packet_len < 2) + return 0; if (VECTOR_LENGTH(HPM->packets[hpParse_Login]) > 0) { - int result = HPM->parse_packets(fd,command,hpParse_Login); + int result = HPM->parse_packets(fd, packet_id, hpParse_Login); if (result == 1) continue; if (result == 2) return 0; } - switch (command) { - - case 0x0200: // New alive packet: structure: 0x200 <account.userid>.24B. used to verify if client is always alive. - if (RFIFOREST(fd) < 26) + switch (packet_id) { + case PACKET_ID_CA_CONNECT_INFO_CHANGED: // New alive packet: structure: 0x200 <account.userid>.24B. used to verify if client is always alive. + if (packet_len < (int)sizeof(struct packet_CA_CONNECT_INFO_CHANGED)) return 0; login->parse_ping(fd, sd); - break; - - // client md5 hash (binary) - case 0x0204: // S 0204 <md5 hash>.16B (kRO 2004-05-31aSakexe langtype 0 and 6) - if (RFIFOREST(fd) < 18) + break; + case PACKET_ID_CA_EXE_HASHCHECK: // S 0204 <md5 hash>.16B (kRO 2004-05-31aSakexe langtype 0 and 6) + if (packet_len < (int)sizeof(struct packet_CA_EXE_HASHCHECK)) return 0; - login->parse_client_md5(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 - { - 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))) ) + break; + case PACKET_ID_CA_LOGIN: // S 0064 <version>.L <username>.24B <password>.24B <clienttype>.B + if (packet_len < (int)sizeof(struct packet_CA_LOGIN)) return 0; - } - { if (login->parse_client_login(fd, sd, ip)) return 0; - } - break; - - case 0x01db: // Sending request of the coding key - RFIFOSKIP(fd,2); - { + break; + case PACKET_ID_CA_LOGIN_PCBANG: // S 0277 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B + if (packet_len < (int)sizeof(struct packet_CA_LOGIN_PCBANG)) + return 0; + if (login->parse_client_login(fd, sd, ip)) + return 0; + break; + case PACKET_ID_CA_LOGIN_HAN: // S 02b0 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B <g_isGravityID>.B + if (packet_len < (int)sizeof(struct packet_CA_LOGIN_HAN)) + return 0; + if (login->parse_client_login(fd, sd, ip)) + return 0; + break; + case PACKET_ID_CA_LOGIN2: // S 01dd <version>.L <username>.24B <password hash>.16B <clienttype>.B + if (packet_len < (int)sizeof(struct packet_CA_LOGIN2)) + return 0; + if (login->parse_client_login(fd, sd, ip)) + return 0; + break; + case PACKET_ID_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")) + if (packet_len < (int)sizeof(struct packet_CA_LOGIN3)) + return 0; + if (login->parse_client_login(fd, sd, ip)) + return 0; + break; + case PACKET_ID_CA_LOGIN4: // S 027c <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.13B(junk) + if (packet_len < (int)sizeof(struct packet_CA_LOGIN4)) + return 0; + if (login->parse_client_login(fd, sd, ip)) + return 0; + break; + case PACKET_ID_CA_SSO_LOGIN_REQ: // S 0825 <packetsize>.W <version>.L <clienttype>.B <userid>.24B <password>.27B <mac>.17B <ip>.15B <token>.(packetsize - 0x5C)B + if (packet_len < (int)sizeof(struct packet_CA_SSO_LOGIN_REQ) || packet_len < RFIFOW(fd, 2)) + return 0; + if (login->parse_client_login(fd, sd, ip)) + return 0; + break; + case PACKET_ID_CA_REQ_HASH: + if (packet_len < (int)sizeof(struct packet_CA_REQ_HASH)) + return 0; login->parse_request_coding_key(fd, sd); - } - break; - - case 0x2710: // Connection request of a char-server - if (RFIFOREST(fd) < 86) + break; + case PACKET_ID_CA_CHARSERVERCONNECT: + if (packet_len < (int)sizeof(struct packet_CA_CHARSERVERCONNECT)) return 0; - { login->parse_request_connection(fd, sd, ip, ipl); - } - return 0; // processing will continue elsewhere - + return 0; // processing will continue elsewhere default: - ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, command); + ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, (unsigned int)packet_id); sockt->eof(fd); return 0; } diff --git a/src/login/login.h b/src/login/login.h index 1aca47c85..0676aee1f 100644 --- a/src/login/login.h +++ b/src/login/login.h @@ -196,11 +196,11 @@ struct login_interface { bool (*fromchar_parse_wrong_pincode) (int fd); void (*fromchar_parse_accinfo) (int fd); int (*parse_fromchar) (int fd); - void (*connection_problem) (int fd, uint8 status); + void (*connection_problem) (int fd, uint8 error); void (*kick) (struct login_session_data* sd); void (*auth_ok) (struct login_session_data* sd); void (*auth_failed) (struct login_session_data* sd, int result); - void (*login_error) (int fd, uint8 status); + void (*login_error) (int fd, uint8 error); void (*parse_ping) (int fd, struct login_session_data* sd); void (*parse_client_md5) (int fd, struct login_session_data* sd); bool (*parse_client_login) (int fd, struct login_session_data* sd, const char *ip); diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h index e8f04c653..25b20cddf 100644 --- a/src/map/packets_struct.h +++ b/src/map/packets_struct.h @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2013-2015 Hercules Dev Team + * Copyright (C) 2013-2016 Hercules Dev Team * * Hercules is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +26,11 @@ #include "common/cbasetypes.h" #include "common/mmo.h" +// Packet DB +#define MIN_PACKET_DB 0x0064 +#define MAX_PACKET_DB 0x0F00 +#define MAX_PACKET_POS 20 + /** * **/ |