diff options
-rw-r--r-- | conf/login_athena.conf | 12 | ||||
-rw-r--r-- | src/login/login.c | 68 | ||||
-rw-r--r-- | src/login/login.h | 13 |
3 files changed, 92 insertions, 1 deletions
diff --git a/conf/login_athena.conf b/conf/login_athena.conf index 5c2afa8d9..3ad5db762 100644 --- a/conf/login_athena.conf +++ b/conf/login_athena.conf @@ -135,5 +135,17 @@ account.engine: auto //account.sql.account_db: login //account.sql.accreg_db: global_reg_value +// Client MD5 hash check +// Check client hash? +client_hash_check: off + +// Put your client hashes here, a player can login into the server using +// a hash with a group_id equal or lower the account group_id +// Follow the model(without the //): +// client_hash: group_id, hash +// Examples: +client_hash: 0, 113e195e6c051bb1cfb12a644bb084c5 +client_hash: 99, cb1ea78023d337c38e8ba5124e2338ae + import: conf/inter_athena.conf import: conf/import/login_conf.txt diff --git a/src/login/login.c b/src/login/login.c index 687dd172c..a0a34f36d 100644 --- a/src/login/login.c +++ b/src/login/login.c @@ -1067,6 +1067,41 @@ int mmo_auth(struct login_session_data* sd) ShowNotice("Connection refused (account: %s, pass: %s, state: %d, ip: %s)\n", sd->userid, sd->passwd, acc.state, ip); return acc.state - 1; } + + if( login_config.client_hash_check ) + { + struct client_hash_node *node = login_config.client_hash_nodes; + bool match = false; + + if( !sd->has_client_hash ) + { + ShowNotice("Client doesn't sent client hash (account: %s, pass: %s, ip: %s)\n", sd->userid, sd->passwd, acc.state, ip); + return 5; + } + + while( node ) + { + if( node->group_id <= acc.group_id && memcmp(node->hash, sd->client_hash, 16) == 0 ) + { + match = true; + break; + } + + node = node->next; + } + + if( !match ) + { + char smd5[33]; + int i; + + for( i = 0; i < 16; i++ ) + sprintf(&smd5[i * 2], "%02x", sd->client_hash[i]); + + ShowNotice("Invalid client hash (account: %s, pass: %s, sent md5: %d, ip: %s)\n", sd->userid, sd->passwd, smd5, ip); + return 5; + } + } ShowNotice("Authentication accepted (account: %s, id: %d, ip: %s)\n", sd->userid, acc.account_id, ip); @@ -1338,6 +1373,10 @@ int parse_login(int fd) case 0x0204: // S 0204 <md5 hash>.16B (kRO 2004-05-31aSakexe langtype 0 and 6) if (RFIFOREST(fd) < 18) return 0; + + sd->has_client_hash = 1; + memcpy(sd->client_hash, RFIFOP(fd, 2), 16); + RFIFOSKIP(fd,18); break; @@ -1556,6 +1595,9 @@ void login_set_defaults() login_config.use_dnsbl = false; safestrncpy(login_config.dnsbl_servs, "", sizeof(login_config.dnsbl_servs)); safestrncpy(login_config.account_engine, "auto", sizeof(login_config.account_engine)); + + login_config.client_hash_check = 0; + login_config.client_hash_nodes = NULL; } //----------------------------------- @@ -1631,6 +1673,32 @@ int login_config_read(const char* cfgName) login_config.ipban_cleanup_interval = (unsigned int)atoi(w2); else if(!strcmpi(w1, "ip_sync_interval")) login_config.ip_sync_interval = (unsigned int)1000*60*atoi(w2); //w2 comes in minutes. + else if(!strcmpi(w1, "client_hash_check")) + login_config.client_hash_check = config_switch(w2); + else if(!strcmpi(w1, "client_hash")) { + int group = 0; + char md5[33]; + int i; + + if (sscanf(w2, "%d, %32s", &group, md5) == 2) { + struct client_hash_node *nnode; + CREATE(nnode, struct client_hash_node, 1); + + for (i = 0; i < 32; i += 2) { + char buf[3]; + + memcpy(buf, &md5[i], 2); + buf[2] = 0; + + sscanf(buf, "%x", &nnode->hash[i / 2]); + } + + nnode->group_id = group; + nnode->next = login_config.client_hash_nodes; + + login_config.client_hash_nodes = nnode; + } + } else if(!strcmpi(w1, "import")) login_config_read(w2); else diff --git a/src/login/login.h b/src/login/login.h index e79f44626..bedf5e179 100644 --- a/src/login/login.h +++ b/src/login/login.h @@ -21,7 +21,6 @@ enum E_LOGINSERVER_ST #define PASSWORDENC 3 struct login_session_data { - int account_id; long login_id1; long login_id2; @@ -38,6 +37,9 @@ struct login_session_data { uint8 clienttype; uint32 version; + uint8 client_hash[16]; + int has_client_hash; + int fd; }; @@ -52,6 +54,12 @@ struct mmo_char_server { uint16 new_; // should display as 'new'? }; +struct client_hash_node { + int group_id; + uint8 hash[16]; + struct client_hash_node *next; +}; + struct Login_Config { uint32 login_ip; // the address to bind to @@ -78,6 +86,9 @@ struct Login_Config { char dnsbl_servs[1024]; // comma-separated list of dnsbl servers char account_engine[256]; // name of the engine to use (defaults to auto, for the first available engine) + + int client_hash_check; // flags for checking client md5 + struct client_hash_node *client_hash_nodes; // linked list containg md5 hash for each gm group }; #define sex_num2str(num) ( (num == SEX_FEMALE ) ? 'F' : (num == SEX_MALE ) ? 'M' : 'S' ) |