summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--conf/login-server.conf15
-rw-r--r--doc/md5_hashcheck.txt46
-rw-r--r--doc/script_commands.txt25
-rw-r--r--src/common/HPMDataCheck.h4
-rw-r--r--src/login/login.c40
-rw-r--r--src/map/npc.h1
-rw-r--r--src/map/npc_chat.c1
-rw-r--r--src/map/script.c76
-rw-r--r--src/map/script.h1
-rw-r--r--src/plugins/HPMHooking/HPMHooking.HPMHooksCore.inc4
-rw-r--r--src/plugins/HPMHooking/HPMHooking.HookingPoints.inc1
-rw-r--r--src/plugins/HPMHooking/HPMHooking.Hooks.inc26
12 files changed, 121 insertions, 119 deletions
diff --git a/conf/login-server.conf b/conf/login-server.conf
index 5a5a3e049..06e0eb18b 100644
--- a/conf/login-server.conf
+++ b/conf/login-server.conf
@@ -136,14 +136,21 @@ dnsbl_servers: bl.blocklist.de, socks.dnsbl.sorbs.net
// Client MD5 hash check
// If turned on, the login server will check if the client's hash matches
// the value below, and will not connect tampered clients.
-// Note: see doc\md5_hashcheck.txt for more details.
+// Note: see doc/md5_hashcheck.txt for more details.
client_hash_check: off
// Client MD5 hashes
-// A player can login with a client hash at or below the account group_id.
+// The client with the specified hash can be used to log in by players with
+// a group_id equal to or greater than the given value.
+// If you specify 'disabled' as hash, players with a group_id greater than or
+// equal to the given value will be able to log in regardless of hash (and even
+// if their client does not send a hash at all.)
// Format: group_id, hash
-client_hash: 0, 113e195e6c051bb1cfb12a644bb084c5
-client_hash: 99, cb1ea78023d337c38e8ba5124e2338ae
+// Note: see doc/md5_hashcheck.txt for more details.
+//client_hash: 0, 113e195e6c051bb1cfb12a644bb084c5
+//client_hash: 10, cb1ea78023d337c38e8ba5124e2338ae
+//client_hash: 99, disabled
+
import: conf/inter-server.conf
import: conf/import/login_conf.txt
diff --git a/doc/md5_hashcheck.txt b/doc/md5_hashcheck.txt
index 779785638..d9064b1ab 100644
--- a/doc/md5_hashcheck.txt
+++ b/doc/md5_hashcheck.txt
@@ -3,7 +3,7 @@
//===== By: ==================================================
//= Hercules Dev Team
//===== Current Version: =====================================
-//= 20120921
+//= 20140208
//===== Description: =========================================
//= This file outlines the login server's MD5 hash check.
//============================================================
@@ -13,26 +13,46 @@ This will ensure that a user has not tampered with the client and that
the client is the one specific to your server.
The client can only send the correct MD5 hash to the server on certain
-server types, so a client diff is required to ensure the hash is sent.
-A link containing the required WeeDiffGen plugin can be found at:
-http://rathena.org/board/topic/70841-r16771-client-md5-hash-check/
+server types, so a client diff may be required to ensure the hash is
+sent.
+Please refer to your client diff tool manual for the appropriate patch
+(i.e. in NEMO it's called "Force Send Client Hash Packet", in other
+tools or diffs it may have similar names.)
-The settings for the hash check are located in conf\login.conf:
+The serverside settings for the hash check are located in
+conf/login.conf:
// Client MD5 hash check
// If turned on, the login server will check if the client's hash matches
// the value below, and will not connect tampered clients.
-// Note: see doc\md5_hashcheck.txt for more details.
+// Note: see doc/md5_hashcheck.txt for more details.
client_hash_check: off
// Client MD5 hashes
-// A player can login with a client hash at or below the account group_id.
+// The client with the specified hash can be used to log in by players with
+// a group_id equal to or greater than the given value.
+// If you specify 'disabled' as hash, players with a group_id greater than or
+// equal to the given value will be able to log in regardless of hash (and even
+// if their client does not send a hash at all.)
// Format: group_id, hash
+// Note: see doc/md5_hashcheck.txt for more details.
client_hash: 0, 113e195e6c051bb1cfb12a644bb084c5
-client_hash: 99, cb1ea78023d337c38e8ba5124e2338ae
+client_hash: 10, cb1ea78023d337c38e8ba5124e2338ae
+client_hash: 99, disabled
-To enable MD5 hash checks, set 'client_hash_check' to 'on'.
-The 'client_hash' group_id can be any of the groups in conf\groups.conf,
-and is particularly useful if you wanted to allow GMs a different client
-than normal players; for example, a GM client could be hexed differently
-with dual-clienting enabled and chat flood disabled.
+To enable MD5 hash checks, set 'client_hash_check' to 'on' and add one
+'client_hash' entry for each client you want to use.
+The group_id can be any of the groups in conf/groups.conf, and it is
+useful in case if you want to allow GMs to use a different client
+than normal players; for example, a GM client could be hexed
+differently, perhaps with dual-clienting enabled and chat flood
+disabled.
+You will need to replace the example MD5 hashes with the actual hash of
+your client.
+You can use any MD5 hash tools to generate it, e.g.:
+- md5sum (command line) on linux
+- WinMD5 on Windows
+- md5 (command line) on Mac OS X
+- If you hexed your client with NEMO (version 2.0 and above), you
+ can find the MD5 hash of the generated client automatically saved to
+ client_filename.exe.secure.txt
diff --git a/doc/script_commands.txt b/doc/script_commands.txt
index c0b848663..aa8698418 100644
--- a/doc/script_commands.txt
+++ b/doc/script_commands.txt
@@ -7359,20 +7359,31 @@ setitemscript 2637,"";
---------------------------------------
-*atoi ("<string>")
-*axtoi ("<string>")
+*atoi("<string>")
+*axtoi("<string>")
+*strtol("string", base)
These commands are used to convert strings to numbers. 'atoi' will
interpret given string as a decimal number (base 10), while 'axtoi'
-interprets strings as hexadecimal numbers (base 16).
+interprets strings as hexadecimal numbers (base 16). 'strtol' lets
+the user specify a base (valid range is between 2 and 36 inclusive,
+or the special value0, which means auto-detection).
-Hexadecimal number set: {0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F}
+The atoi and strtol functions conform to the C functions with the same
+names, and axtoi is the same as strtol, with a base of 16. Results are
+clamped to signed 32 bit int range (INT_MIN ~ INT_MAX)
Example:
-set @var, atoi("11"); // Sets @var to 11
-set @var, axtoi("FF"); // Sets @var to 255
-mes axtoi("11"); // Displays 17 (1 = 1, 10 = 16)
+.@var = atoi("11"); // Sets .@var to 11
+.@var = axtoi("FF"); // Sets .@var to 255
+mes axtoi("11"); // Displays 17 (1 = 1, 10 = 16)
+.@var = strtol("11", 10); // Sets .@var to 11 (11 base 10)
+.@var = strtol("11", 16); // Sets .@var to 17 (11 base 16)
+.@var = strtol("11", 0); // Sets .@var to 11 (11 base 10, auto-detected)
+.@var = strtol("0x11", 0); // Sets .@var to 17 (11 base 16, auto-detected because of the "0x" prefix)
+.@var = strtol("011", 0); // Sets .@var to 9 (11 base 8, auto-detected because of the "0" prefix)
+.@var = strtol("11", 2); // Sets .@var to 3 (binary 11)
---------------------------------------
diff --git a/src/common/HPMDataCheck.h b/src/common/HPMDataCheck.h
index 19b079418..48089964d 100644
--- a/src/common/HPMDataCheck.h
+++ b/src/common/HPMDataCheck.h
@@ -7,7 +7,7 @@
#define _HPM_DATA_CHECK_H_
-const struct s_HPMDataCheck HPMDataCheck[] = {
+HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
#ifdef _COMMON_CONF_H_
{ "libconfig_interface", sizeof(struct libconfig_interface) },
#else
@@ -125,6 +125,6 @@ const struct s_HPMDataCheck HPMDataCheck[] = {
#define _MAP_SKILL_H_
#endif // _MAP_SKILL_H_
};
-unsigned int HPMDataCheckLen = ARRAYLENGTH(HPMDataCheck);
+HPExport unsigned int HPMDataCheckLen = ARRAYLENGTH(HPMDataCheck);
#endif /* _HPM_DATA_CHECK_H_ */
diff --git a/src/login/login.c b/src/login/login.c
index e9d0eac9d..249d008ec 100644
--- a/src/login/login.c
+++ b/src/login/login.c
@@ -977,27 +977,29 @@ int mmo_auth(struct login_session_data* sd, bool isServer) {
}
if( login_config.client_hash_check && !isServer ) {
- struct client_hash_node *node = login_config.client_hash_nodes;
+ struct client_hash_node *node = NULL;
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 ) {
+ for( node = login_config.client_hash_nodes; node; node = node->next ) {
+ if( acc.group_id < node->group_id )
+ continue;
+ if( *node->hash == '\0' // Allowed to login without hash
+ || (sd->has_client_hash && memcmp(node->hash, sd->client_hash, 16) == 0 ) // Correct hash
+ ) {
match = true;
break;
}
-
- node = node->next;
}
if( !match ) {
char smd5[33];
int i;
+ if( !sd->has_client_hash ) {
+ ShowNotice("Client didn't send client hash (account: %s, pass: %s, ip: %s)\n", sd->userid, sd->passwd, acc.state, ip);
+ return 5;
+ }
+
for( i = 0; i < 16; i++ )
sprintf(&smd5[i * 2], "%02x", sd->client_hash[i]);
@@ -1607,15 +1609,19 @@ int login_config_read(const char* cfgName)
int i;
CREATE(nnode, struct client_hash_node, 1);
- for (i = 0; i < 32; i += 2) {
- char buf[3];
- unsigned int byte;
+ if (strcmpi(md5, "disabled") == 0) {
+ nnode->hash[0] = '\0';
+ } else {
+ for (i = 0; i < 32; i += 2) {
+ char buf[3];
+ unsigned int byte;
- memcpy(buf, &md5[i], 2);
- buf[2] = 0;
+ memcpy(buf, &md5[i], 2);
+ buf[2] = 0;
- sscanf(buf, "%x", &byte);
- nnode->hash[i / 2] = (uint8)(byte & 0xFF);
+ sscanf(buf, "%x", &byte);
+ nnode->hash[i / 2] = (uint8)(byte & 0xFF);
+ }
}
nnode->group_id = group;
diff --git a/src/map/npc.h b/src/map/npc.h
index 719974ac4..346a9f8c0 100644
--- a/src/map/npc.h
+++ b/src/map/npc.h
@@ -336,6 +336,7 @@ struct pcre_interface {
int (*copy_substring) (const char *subject, int *ovector, int stringcount, int stringnumber, char *buffer, int buffersize);
void (*free_substring) (const char *stringptr);
int (*copy_named_substring) (const pcre *code, const char *subject, int *ovector, int stringcount, const char *stringname, char *buffer, int buffersize);
+ int (*get_substring) (const char *subject, int *ovector, int stringcount, int stringnumber, const char **stringptr);
};
struct pcre_interface *libpcre;
diff --git a/src/map/npc_chat.c b/src/map/npc_chat.c
index 896bbae5b..9d5639efc 100644
--- a/src/map/npc_chat.c
+++ b/src/map/npc_chat.c
@@ -440,6 +440,7 @@ void npc_chat_defaults(void) {
libpcre->copy_substring = pcre_copy_substring;
libpcre->free_substring = pcre_free_substring;
libpcre->copy_named_substring = pcre_copy_named_substring;
+ libpcre->get_substring = pcre_get_substring;
}
#endif //PCRE_SUPPORT
diff --git a/src/map/script.c b/src/map/script.c
index 21d55ca77..aa3713427 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -14064,6 +14064,15 @@ BUILDIN(sscanf) {
argc = script_lastdata(st)-3;
len = strlen(format);
+
+ if (len != 0 && strlen(str) == 0) {
+ // If the source string is empty but the format string is not, we return -1
+ // according to the C specs. (if the format string is also empty, we shall
+ // continue and return 0: 0 conversions took place out of the 0 attempted.)
+ script_pushint(st, -1);
+ return true;
+ }
+
CREATE(buf, char, len*2+1);
// Issue sscanf for each parameter
@@ -14379,14 +14388,34 @@ BUILDIN(setnpcdisplay) {
return true;
}
-BUILDIN(atoi)
-{
+BUILDIN(atoi) {
const char *value;
value = script_getstr(st,2);
script_pushint(st,atoi(value));
return true;
}
+BUILDIN(axtoi) {
+ const char *hex = script_getstr(st,2);
+ long value = strtol(hex, NULL, 16);
+#if LONG_MAX > INT_MAX || LONG_MIN < INT_MIN
+ value = cap_value(value, INT_MIN, INT_MAX);
+#endif
+ script_pushint(st, (int)value);
+ return true;
+}
+
+BUILDIN(strtol) {
+ const char *string = script_getstr(st, 2);
+ int base = script_getnum(st, 3);
+ long value = strtol(string, NULL, base);
+#if LONG_MAX > INT_MAX || LONG_MIN < INT_MIN
+ value = cap_value(value, INT_MIN, INT_MAX);
+#endif
+ script_pushint(st, (int)value);
+ return true;
+}
+
// case-insensitive substring search [lordalfa]
BUILDIN(compare)
{
@@ -15112,47 +15141,6 @@ BUILDIN(searchitem)
return true;
}
-int axtoi(const char *hexStg)
-{
- int n = 0; // position in string
- int16 m = 0; // position in digit[] to shift
- int count; // loop index
- int intValue = 0; // integer value of hex string
- int digit[11]; // hold values to convert
- while (n < 10) {
- if (hexStg[n]=='\0')
- break;
- if (hexStg[n] > 0x29 && hexStg[n] < 0x40 ) //if 0 to 9
- digit[n] = hexStg[n] & 0x0f; //convert to int
- else if (hexStg[n] >='a' && hexStg[n] <= 'f') //if a to f
- digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int
- else if (hexStg[n] >='A' && hexStg[n] <= 'F') //if A to F
- digit[n] = (hexStg[n] & 0x0f) + 9; //convert to int
- else break;
- n++;
- }
- count = n;
- m = n - 1;
- n = 0;
- while(n < count) {
- // digit[n] is value of hex digit at position n
- // (m << 2) is the number of positions to shift
- // OR the bits into return value
- intValue = intValue | (digit[n] << (m << 2));
- m--; // adjust the position to set
- n++; // next digit to process
- }
- return (intValue);
-}
-
-// [Lance] Hex string to integer converter
-BUILDIN(axtoi)
-{
- const char *hex = script_getstr(st,2);
- script_pushint(st,script->axtoi(hex));
- return true;
-}
-
// [zBuffer] List of player cont commands --->
BUILDIN(rid2name) {
struct block_list *bl = NULL;
@@ -18837,6 +18825,7 @@ void script_parse_builtin(void) {
BUILDIN_DEF(query_logsql,"s*"),
BUILDIN_DEF(escape_sql,"v"),
BUILDIN_DEF(atoi,"s"),
+ BUILDIN_DEF(strtol,"si"),
// [zBuffer] List of player cont commands --->
BUILDIN_DEF(rid2name,"i"),
BUILDIN_DEF(pcfollow,"ii"),
@@ -19220,7 +19209,6 @@ void script_defaults(void) {
script->playbgm_foreachpc_sub = playbgm_foreachpc_sub;
script->soundeffect_sub = soundeffect_sub;
script->buildin_query_sql_sub = buildin_query_sql_sub;
- script->axtoi = axtoi;
script->buildin_instance_warpall_sub = buildin_instance_warpall_sub;
script->buildin_mobuseskill_sub = buildin_mobuseskill_sub;
script->cleanfloor_sub = script_cleanfloor_sub;
diff --git a/src/map/script.h b/src/map/script.h
index b7e9e5741..4906d4fa8 100644
--- a/src/map/script.h
+++ b/src/map/script.h
@@ -665,7 +665,6 @@ struct script_interface {
int (*playbgm_foreachpc_sub) (struct map_session_data *sd, va_list args);
int (*soundeffect_sub) (struct block_list *bl, va_list ap);
int (*buildin_query_sql_sub) (struct script_state *st, Sql *handle);
- int (*axtoi) (const char *hexStg);
int (*buildin_instance_warpall_sub) (struct block_list *bl, va_list ap);
int (*buildin_mobuseskill_sub) (struct block_list *bl, va_list ap);
int (*cleanfloor_sub) (struct block_list *bl, va_list ap);
diff --git a/src/plugins/HPMHooking/HPMHooking.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking.HPMHooksCore.inc
index da77ddef0..ed58b79a3 100644
--- a/src/plugins/HPMHooking/HPMHooking.HPMHooksCore.inc
+++ b/src/plugins/HPMHooking/HPMHooking.HPMHooksCore.inc
@@ -4235,8 +4235,6 @@ struct {
struct HPMHookPoint *HP_script_soundeffect_sub_post;
struct HPMHookPoint *HP_script_buildin_query_sql_sub_pre;
struct HPMHookPoint *HP_script_buildin_query_sql_sub_post;
- struct HPMHookPoint *HP_script_axtoi_pre;
- struct HPMHookPoint *HP_script_axtoi_post;
struct HPMHookPoint *HP_script_buildin_instance_warpall_sub_pre;
struct HPMHookPoint *HP_script_buildin_instance_warpall_sub_post;
struct HPMHookPoint *HP_script_buildin_mobuseskill_sub_pre;
@@ -9264,8 +9262,6 @@ struct {
int HP_script_soundeffect_sub_post;
int HP_script_buildin_query_sql_sub_pre;
int HP_script_buildin_query_sql_sub_post;
- int HP_script_axtoi_pre;
- int HP_script_axtoi_post;
int HP_script_buildin_instance_warpall_sub_pre;
int HP_script_buildin_instance_warpall_sub_post;
int HP_script_buildin_mobuseskill_sub_pre;
diff --git a/src/plugins/HPMHooking/HPMHooking.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking.HookingPoints.inc
index bbd556954..d43852d40 100644
--- a/src/plugins/HPMHooking/HPMHooking.HookingPoints.inc
+++ b/src/plugins/HPMHooking/HPMHooking.HookingPoints.inc
@@ -2151,7 +2151,6 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(script->playbgm_foreachpc_sub, HP_script_playbgm_foreachpc_sub) },
{ HP_POP(script->soundeffect_sub, HP_script_soundeffect_sub) },
{ HP_POP(script->buildin_query_sql_sub, HP_script_buildin_query_sql_sub) },
- { HP_POP(script->axtoi, HP_script_axtoi) },
{ HP_POP(script->buildin_instance_warpall_sub, HP_script_buildin_instance_warpall_sub) },
{ HP_POP(script->buildin_mobuseskill_sub, HP_script_buildin_mobuseskill_sub) },
{ HP_POP(script->cleanfloor_sub, HP_script_cleanfloor_sub) },
diff --git a/src/plugins/HPMHooking/HPMHooking.Hooks.inc b/src/plugins/HPMHooking/HPMHooking.Hooks.inc
index e2ed78729..2e8389d59 100644
--- a/src/plugins/HPMHooking/HPMHooking.Hooks.inc
+++ b/src/plugins/HPMHooking/HPMHooking.Hooks.inc
@@ -54682,32 +54682,6 @@ int HP_script_buildin_query_sql_sub(struct script_state *st, Sql *handle) {
}
return retVal___;
}
-int HP_script_axtoi(const char *hexStg) {
- int hIndex = 0;
- int retVal___ = 0;
- if( HPMHooks.count.HP_script_axtoi_pre ) {
- int (*preHookFunc) (const char *hexStg);
- for(hIndex = 0; hIndex < HPMHooks.count.HP_script_axtoi_pre; hIndex++ ) {
- preHookFunc = HPMHooks.list.HP_script_axtoi_pre[hIndex].func;
- retVal___ = preHookFunc(hexStg);
- }
- if( *HPMforce_return ) {
- *HPMforce_return = false;
- return retVal___;
- }
- }
- {
- retVal___ = HPMHooks.source.script.axtoi(hexStg);
- }
- if( HPMHooks.count.HP_script_axtoi_post ) {
- int (*postHookFunc) (int retVal___, const char *hexStg);
- for(hIndex = 0; hIndex < HPMHooks.count.HP_script_axtoi_post; hIndex++ ) {
- postHookFunc = HPMHooks.list.HP_script_axtoi_post[hIndex].func;
- retVal___ = postHookFunc(retVal___, hexStg);
- }
- }
- return retVal___;
-}
int HP_script_buildin_instance_warpall_sub(struct block_list *bl, va_list ap) {
int hIndex = 0;
int retVal___ = 0;