summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaru <haru@dotalux.com>2016-02-11 00:41:54 +0100
committerHaru <haru@dotalux.com>2016-08-19 21:32:15 +0200
commitf56264d23d9cc86a87331401496e206639cdd6e3 (patch)
tree57891c2901c8cdc114baf4fbfa4dd927b5a87204
parent3c84a4df688a63577236d02b4d972775964f71ca (diff)
downloadhercules-f56264d23d9cc86a87331401496e206639cdd6e3.tar.gz
hercules-f56264d23d9cc86a87331401496e206639cdd6e3.tar.bz2
hercules-f56264d23d9cc86a87331401496e206639cdd6e3.tar.xz
hercules-f56264d23d9cc86a87331401496e206639cdd6e3.zip
Ported login-server.conf to libconfig
Ported to modern Hercules and cleaned up from Panikon's commits: ceb8a486ac47c2ed9aae4baa1ec39a11f31e9368, c1049123a4ea6ae6f0992ffe766db8aed7435ab5, 6feb097046355610d2288670a569ccc175358580, 9f6e27a96d655f2b4555310786d9d10898754404, 21fa5d24255ba026f96b1dbedf74ac5ef831d3ae, e22a56ad4def8ca22e94d44377a5364b9db1a425, f753a754923140bfec02057c16e6e8429b863d0e, 25dde7e46524ace330b83cb4bf0255cc4d796792 Signed-off-by: Haru <haru@dotalux.com>
-rw-r--r--.gitignore1
-rw-r--r--conf/common/inter-server.conf3
-rw-r--r--conf/global/sql_connection.conf3
-rw-r--r--conf/import-tmpl/login-server.conf32
-rw-r--r--conf/import-tmpl/login_conf.txt0
-rw-r--r--conf/login-server.conf156
-rw-r--r--conf/login/login-server.conf187
-rw-r--r--doc/md5_hashcheck.txt24
-rw-r--r--src/login/account.h10
-rw-r--r--src/login/account_sql.c243
-rw-r--r--src/login/ipban.h9
-rw-r--r--src/login/ipban_sql.c281
-rw-r--r--src/login/login.c547
-rw-r--r--src/login/login.h17
-rw-r--r--src/login/loginlog.h4
-rw-r--r--src/login/loginlog_sql.c198
-rwxr-xr-xtools/configconverter.pl110
17 files changed, 1142 insertions, 683 deletions
diff --git a/.gitignore b/.gitignore
index 3302e44cf..bd33fac60 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,7 +62,6 @@ Thumbs.db
/conf/import/*.conf
/conf/import/battle_conf.txt
/conf/import/log_conf.txt
-/conf/import/login_conf.txt
/conf/import/map_conf.txt
/conf/import/msg_conf.txt
/conf/import/packet_conf.txt
diff --git a/conf/common/inter-server.conf b/conf/common/inter-server.conf
index fd55b27e5..888d4ad80 100644
--- a/conf/common/inter-server.conf
+++ b/conf/common/inter-server.conf
@@ -65,6 +65,9 @@ inter_configuration: {
// this is meant for people who KNOW their stuff, and for some reason want to change their
// database layout. [CLOWNISIUS]
database_names: {
+ account_db: "login"
+ login_db: "loginlog"
+ ipban_table: "ipbanlist"
char_db: "char"
interlog_db: "interlog"
ragsrvinfo_db: "ragsrvinfo"
diff --git a/conf/global/sql_connection.conf b/conf/global/sql_connection.conf
index 58c9e6d08..60fea5656 100644
--- a/conf/global/sql_connection.conf
+++ b/conf/global/sql_connection.conf
@@ -36,6 +36,9 @@ sql_connection: {
// (Note that this feature requires MySQL 4.1+)
//default_codepage: ""
+ // [LOGIN] Is `userid` in account_db case sensitive?
+ //case_sensitive: false
+
// For IPs, ideally under linux, you want to use localhost instead of 127.0.0.1.
// Under windows, you want to use 127.0.0.1. If you see a message like
// "Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)"
diff --git a/conf/import-tmpl/login-server.conf b/conf/import-tmpl/login-server.conf
new file mode 100644
index 000000000..feadef976
--- /dev/null
+++ b/conf/import-tmpl/login-server.conf
@@ -0,0 +1,32 @@
+//================= Hercules Configuration ================================
+//= _ _ _
+//= | | | | | |
+//= | |_| | ___ _ __ ___ _ _| | ___ ___
+//= | _ |/ _ \ '__/ __| | | | |/ _ \/ __|
+//= | | | | __/ | | (__| |_| | | __/\__ \
+//= \_| |_/\___|_| \___|\__,_|_|\___||___/
+//================= License ===============================================
+//= This file is part of Hercules.
+//= http://herc.ws - http://github.com/HerculesWS/Hercules
+//=
+//= Copyright (C) 2014-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
+//= the Free Software Foundation, either version 3 of the License, or
+//= (at your option) any later version.
+//=
+//= This program is distributed in the hope that it will be useful,
+//= but WITHOUT ANY WARRANTY; without even the implied warranty of
+//= MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//= GNU General Public License for more details.
+//=
+//= You should have received a copy of the GNU General Public License
+//= along with this program. If not, see <http://www.gnu.org/licenses/>.
+//=========================================================================
+//= Login Server local configuration file.
+//=========================================================================
+
+login_configuration: {
+ // See conf/login/login-server.conf for details
+}
diff --git a/conf/import-tmpl/login_conf.txt b/conf/import-tmpl/login_conf.txt
deleted file mode 100644
index e69de29bb..000000000
--- a/conf/import-tmpl/login_conf.txt
+++ /dev/null
diff --git a/conf/login-server.conf b/conf/login-server.conf
deleted file mode 100644
index 620fae327..000000000
--- a/conf/login-server.conf
+++ /dev/null
@@ -1,156 +0,0 @@
-// Hercules Login Server configuration file.
-// Translated by Peter Kieser <pfak@telus.net>
-
-// Note: "Comments" are all text on the right side of a double slash "//"
-// Whatever text is commented will not be parsed by the servers, and serves
-// only as information/reference.
-
-// The login server listens on the interface with this IP address.
-// NOTE: This allows you to run multiple servers on multiple interfaces
-// while using the same ports for each server.
-//bind_ip: 127.0.0.1
-
-// Login Server Port
-login_port: 6900
-
-//Time-stamp format which will be printed before all messages.
-//Can at most be 20 characters long.
-//Common formats:
-// %I:%M:%S %p (hour:minute:second 12 hour, AM/PM format)
-// %H:%M:%S (hour:minute:second, 24 hour format)
-// %d/%b/%Y (day/Month/year)
-//For full format information, consult the strftime() manual.
-//timestamp_format: [%d/%b %H:%M]
-
-//If redirected output contains escape sequences (color codes)
-stdout_with_ansisequence: no
-
-//Makes server output more silent by omitting certain types of messages:
-//1: Hide Information messages
-//2: Hide Status messages
-//4: Hide Notice Messages
-//8: Hide Warning Messages
-//16: Hide Error and SQL Error messages.
-//32: Hide Debug Messages
-//Example: "console_silent: 7" Hides information, status and notice messages (1+2+4)
-console_silent: 0
-
-// Can you use _M/_F to make new accounts on the server?
-new_account: yes
-
-//If new_account is enabled, minimum length to userid and passwords should be 4?
-//Must be 'Yes' unless your client uses both 'Disable 4 LetterUserID/Password' Diffs
-new_acc_length_limit: yes
-
-// Account registration flood protection system
-// allowed_regs is the number of registrations allowed in time_allowed (in seconds)
-allowed_regs: 1
-time_allowed: 10
-
-// To log the login server?
-// NOTE: The login-sql server needs the login logs to enable dynamic pass failure bans.
-log_login: yes
-
-// Indicate how to display date in logs, to players, etc.
-date_format: %Y-%m-%d %H:%M:%S
-
-// Required account group id to connect to server.
-// -1: disabled
-// 0 or more: group id
-group_id_to_connect: -1
-
-// Minimum account group id required to connect to server.
-// Will not function if group_id_to_connect config is enabled.
-// -1: disabled
-// 0 or more: group id
-min_group_id_to_connect: -1
-
-// Starting additional sec from now for the limited time at creation of account
-// -1: new account are created with UNlimited time (default value)
-// 0 or more: new accounts was created by addition of the value (in sec) to the actual time (to set first limited time)
-start_limited_time: -1
-
-// Check The clientversion set in the clientinfo ?
-check_client_version: no
-
-// What version we would allow to connect? (if the options above is enabled..)
-client_version_to_connect: 20
-
-// Store passwords as MD5 hashes instead of plaintext ?
-// NOTE: Will not work with clients that use <passwordencrypt>
-use_MD5_passwords: no
-
-// Ipban features (SQL only)
-ipban.enable: yes
-//ipban.sql.db_hostname: 127.0.0.1
-//ipban.sql.db_port: 3306
-//ipban.sql.db_username: ragnarok
-//ipban.sql.db_password: ragnarok
-//ipban.sql.db_database: ragnarok
-//ipban.sql.codepage:
-//ipban.sql.ipban_table: ipbanlist
-// Dynamic password failure ipban system
-ipban.dynamic_pass_failure_ban: yes
-ipban.dynamic_pass_failure_ban_interval: 5
-ipban.dynamic_pass_failure_ban_limit: 7
-ipban.dynamic_pass_failure_ban_duration: 5
-
-// Interval (in seconds) to clean up expired IP bans. 0 = disabled. default = 60.
-// NOTE: Even if this is disabled, expired IP bans will be cleaned up on login server start/stop.
-// Players will still be able to login if an ipban entry exists but the expiration time has already passed.
-ipban_cleanup_interval: 60
-
-// Interval (in minutes) to execute a DNS/IP update. Disabled by default.
-// Enable it if your server uses a dynamic IP which changes with time.
-//ip_sync_interval: 10
-
-// DNS Blacklist Blocking
-// If enabled, each incoming connection will be tested against the blacklists
-// on the specified dnsbl_servers (comma-separated list)
-use_dnsbl: no
-dnsbl_servers: bl.blocklist.de, socks.dnsbl.sorbs.net
-// Here are some free DNS Blacklist Services: http://en.wikipedia.org/wiki/Comparison_of_DNS_blacklists
-//==============================================================================
-// dnsbl_servers Description
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// bl.blocklist.de IP-Addresses who attack other servers/honeypots over SSH, FTP, IMAP, etc.
-// ircbl.ahbl.org AHBL (open proxies, compromised machines, comment spammers)
-// safe.dnsbl.sorbs.net All zones in dnsbl.sorbs.net except "recent" and "escalations"
-// sbl-xbl.spamhaus.org Spamhaus blacklist (spammers, open proxies)
-// socks.dnsbl.sorbs.net Open SOCKS proxy servers
-// tor.ahbl.org Current tor relay and exit nodes
-
-
-// Account data storage configuration
-// SQL
-//account.sql.db_hostname: 127.0.0.1
-//account.sql.db_port: 3306
-//account.sql.db_username: ragnarok
-//account.sql.db_password: ragnarok
-//account.sql.db_database: ragnarok
-//account.sql.codepage:
-//account.sql.case_sensitive: no
-//account.sql.account_db: login
-//account.sql.accreg_db: global_reg_value
-
-// 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.
-client_hash_check: off
-
-// Client MD5 hashes
-// 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: 10, cb1ea78023d337c38e8ba5124e2338ae
-//client_hash: 99, disabled
-
-
-import: conf/inter-server.conf
-import: conf/import/login_conf.txt
diff --git a/conf/login/login-server.conf b/conf/login/login-server.conf
new file mode 100644
index 000000000..71928e3d0
--- /dev/null
+++ b/conf/login/login-server.conf
@@ -0,0 +1,187 @@
+//================= Hercules Configuration ================================
+//= _ _ _
+//= | | | | | |
+//= | |_| | ___ _ __ ___ _ _| | ___ ___
+//= | _ |/ _ \ '__/ __| | | | |/ _ \/ __|
+//= | | | | __/ | | (__| |_| | | __/\__ \
+//= \_| |_/\___|_| \___|\__,_|_|\___||___/
+//================= License ===============================================
+//= This file is part of Hercules.
+//= http://herc.ws - http://github.com/HerculesWS/Hercules
+//=
+//= Copyright (C) 2014-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
+//= the Free Software Foundation, either version 3 of the License, or
+//= (at your option) any later version.
+//=
+//= This program is distributed in the hope that it will be useful,
+//= but WITHOUT ANY WARRANTY; without even the implied warranty of
+//= MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//= GNU General Public License for more details.
+//=
+//= You should have received a copy of the GNU General Public License
+//= along with this program. If not, see <http://www.gnu.org/licenses/>.
+//=========================================================================
+//= Login Server configuration file.
+//=========================================================================
+
+login_configuration: {
+ // Login-server's console configuration
+ @include "conf/global/console.conf"
+
+ inter: {
+ // The login server listens on the interface with this IP address.
+ // NOTE: This allows you to run multiple servers on multiple interfaces
+ // while using the same ports for each server.
+ //bind_ip: "127.0.0.1"
+
+ // Login Server Port
+ login_port: 6900
+
+ // Interval (in minutes) to execute a DNS/IP update. Disabled by default.
+ // Enable it if your server uses a dynamic IP which changes with time.
+ //ip_sync_interval: 10
+ }
+
+ log: {
+ // To log the login server?
+ // NOTE: The login-sql server needs the login logs to enable dynamic pass failure bans.
+ log_login: true
+
+ // Indicate how to display date in logs, to players, etc.
+ date_format: "%Y-%m-%d %H:%M:%S"
+ }
+
+ // Account engine configuration
+ account: {
+ // Can you use _M/_F to make new accounts on the server?
+ new_account: true
+
+ //If new_account is enabled, minimum length to userid and passwords should be 4?
+ //Must be 'true' unless your client uses both 'Disable 4 LetterUserID/Password' Diffs
+ new_acc_length_limit: true
+
+ // Account registration flood protection system
+ // allowed_regs is the number of registrations allowed in time_allowed (in seconds)
+ allowed_regs: 1
+ time_allowed: 10
+
+ // Starting additional sec from now for the limited time at creation of account
+ // -1: new account are created with UNlimited time (default value)
+ // 0 or more: new accounts was created by addition of the value (in sec) to the actual time (to set first limited time)
+ start_limited_time: -1
+
+ // Store passwords as MD5 hashes instead of plaintext ?
+ // NOTE: Will not work with clients that use <passwordencrypt>
+ use_MD5_passwords: false
+
+ // Account data engine storage configuration
+ @include "conf/global/sql_connection.conf"
+
+ //==================================================================
+ // IP banning system
+ //==================================================================
+ ipban: {
+ enabled: true
+
+ // Interval (in seconds) to clean up expired IP bans. 0 = disabled. default = 60.
+ // NOTE: Even if this is disabled, expired IP bans will be cleaned up on login server start/stop.
+ // Players will still be able to login if an ipban entry exists but the expiration time has already passed.
+ cleanup_interval: 60
+
+ // SQL connection settings
+ @include "conf/global/sql_connection.conf"
+
+ // Dynamic password failure ipban system
+ dynamic_pass_failure: {
+ enabled: true
+
+ // Interval in minutes between failed tries
+ // Only failed tries between this interval will be accounted when banning
+ ban_interval: 5
+
+ // How many failures before adding a temporary ban entry?
+ ban_limit: 7
+
+ // Duration of the ban in minutes
+ ban_duration: 5
+ }
+ } // login_configuration.account.ipban
+ } // login_configuration.account
+
+ permission: {
+ // Required account group id to connect to server.
+ // -1: disabled
+ // 0 or more: group id
+ group_id_to_connect: -1
+
+ // Minimum account group id required to connect to server.
+ // Will not function if group_id_to_connect config is enabled.
+ // -1: disabled
+ // 0 or more: group id
+ min_group_id_to_connect: -1
+
+ // Check The clientversion set in the clientinfo ?
+ check_client_version: false
+
+ // What version we would allow to connect? (if check_client_version is enabled)
+ client_version_to_connect: 20
+
+ //==================================================================
+ // Client hash checking system
+ //==================================================================
+ // Note: see doc/md5_hashcheck.txt for more details.
+ hash: {
+ // 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.
+ enabled: false
+
+ // Client MD5 hashes
+ // 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.)
+ MD5_hashes: (
+ //{
+ // group_id: group id
+ // hash: client hash
+ //},
+ //{
+ // group_id: 0
+ // hash: "113e195e6c051bb1cfb12a644bb084c5"
+ //},
+ //{
+ // group_id: 10
+ // hash: "cb1ea78023d337c38e8ba5124e2338ae"
+ //},
+ //{
+ // group_id: 99
+ // hash: "disabled"
+ //},
+ )
+ } // login_configuration.permission.hash
+
+ DNS_blacklist: {
+ // DNS Blacklist Blocking
+ // If enabled, each incoming connection will be tested against the blacklists
+ // on the specified dnsbl_servers
+ enabled: false
+
+ dnsbl_servers: (
+ // Here are some free DNS Blacklist Services: http://en.wikipedia.org/wiki/Comparison_of_DNS_blacklists
+ "bl.blocklist.de", // IP-Addresses who attack other servers/honeypots over SSH, FTP, IMAP, etc.
+ //"ircbl.ahbl.org", // AHBL (open proxies, compromised machines, comment spammers)
+ //"safe.dnsbl.sorbs.net", // All zones in dnsbl.sorbs.net except "recent" and "escalations"
+ //"sbl-xbl.spamhaus.org", // Spamhaus blacklist (spammers, open proxies)
+ "socks.dnsbl.sorbs.net", // Open SOCKS proxy servers
+ //"tor.ahbl.org", // Current tor relay and exit nodes
+ )
+ } // login_configuration.DNS_blacklist
+ } // login_configuration.permission
+}
+
+import: "conf/import/login-server.conf"
diff --git a/doc/md5_hashcheck.txt b/doc/md5_hashcheck.txt
index d9064b1ab..b386559b5 100644
--- a/doc/md5_hashcheck.txt
+++ b/doc/md5_hashcheck.txt
@@ -3,7 +3,7 @@
//===== By: ==================================================
//= Hercules Dev Team
//===== Current Version: =====================================
-//= 20140208
+//= 20160210
//===== Description: =========================================
//= This file outlines the login server's MD5 hash check.
//============================================================
@@ -20,27 +20,9 @@ Please refer to your client diff tool manual for the appropriate patch
tools or diffs it may have similar names.)
The serverside settings for the hash check are located in
-conf/login.conf:
+conf/login.conf::login_configuration.permission.hash
-// 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.
-client_hash_check: off
-
-// Client MD5 hashes
-// 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: 10, cb1ea78023d337c38e8ba5124e2338ae
-client_hash: 99, disabled
-
-To enable MD5 hash checks, set 'client_hash_check' to 'on' and add one
+To enable MD5 hash checks, set 'client_hash_check' to 'true' 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
diff --git a/src/login/account.h b/src/login/account.h
index 7e1930ad4..9bb07fda3 100644
--- a/src/login/account.h
+++ b/src/login/account.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
@@ -27,6 +27,9 @@
/* Forward declarations */
struct Sql; // common/sql.h
+/* Forward Declarations */
+struct config_t; // common/conf.h
+
typedef struct AccountDB AccountDB;
typedef struct AccountDBIterator AccountDBIterator;
@@ -107,10 +110,9 @@ struct AccountDB
/// Sets a property in this database.
///
/// @param self Database
- /// @param key Property name
- /// @param value Property value
+ /// @param config Configuration node
/// @return true if successful
- bool (*set_property)(AccountDB* self, const char* key, const char* value);
+ bool (*set_property)(AccountDB* self, struct config_t *config, bool imported);
/// Creates a new account in this database.
/// If acc->account_id is not -1, the provided value will be used.
diff --git a/src/login/account_sql.c b/src/login/account_sql.c
index 2e128e8bf..70d4f3dfb 100644
--- a/src/login/account_sql.c
+++ b/src/login/account_sql.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
@@ -24,6 +24,7 @@
#include "account.h"
#include "common/cbasetypes.h"
+#include "common/conf.h"
#include "common/console.h"
#include "common/memmgr.h"
#include "common/mmo.h"
@@ -45,14 +46,7 @@ typedef struct AccountDB_SQL
struct Sql *accounts; // SQL accounts storage
- // global sql settings
- char global_db_hostname[32];
- uint16 global_db_port;
- char global_db_username[32];
- char global_db_password[100];
- char global_db_database[32];
- char global_codepage[32];
- // local sql settings
+ // Sql settings
char db_hostname[32];
uint16 db_port;
char db_username[32];
@@ -81,7 +75,7 @@ typedef struct AccountDBIterator_SQL
static bool account_db_sql_init(AccountDB* self);
static void account_db_sql_destroy(AccountDB* self);
static bool account_db_sql_get_property(AccountDB* self, const char* key, char* buf, size_t buflen);
-static bool account_db_sql_set_property(AccountDB* self, const char* option, const char* value);
+static bool account_db_sql_set_property(AccountDB* self, struct config_t *config, bool imported);
static bool account_db_sql_create(AccountDB* self, struct mmo_account* acc);
static bool account_db_sql_remove(AccountDB* self, const int account_id);
static bool account_db_sql_save(AccountDB* self, const struct mmo_account* acc);
@@ -113,19 +107,12 @@ AccountDB* account_db_sql(void)
// initialize to default values
db->accounts = NULL;
- // global sql settings
- safestrncpy(db->global_db_hostname, "127.0.0.1", sizeof(db->global_db_hostname));
- db->global_db_port = 3306;
- safestrncpy(db->global_db_username, "ragnarok", sizeof(db->global_db_username));
- safestrncpy(db->global_db_password, "ragnarok", sizeof(db->global_db_password));
- safestrncpy(db->global_db_database, "ragnarok", sizeof(db->global_db_database));
- safestrncpy(db->global_codepage, "", sizeof(db->global_codepage));
- // local sql settings
- safestrncpy(db->db_hostname, "", sizeof(db->db_hostname));
+ // Sql settings
+ safestrncpy(db->db_hostname, "127.0.0.1", sizeof(db->db_hostname));
db->db_port = 3306;
- safestrncpy(db->db_username, "", sizeof(db->db_username));
- safestrncpy(db->db_password, "", sizeof(db->db_password));
- safestrncpy(db->db_database, "", sizeof(db->db_database));
+ safestrncpy(db->db_username, "ragnarok", sizeof(db->db_username));
+ safestrncpy(db->db_password, "ragnarok", sizeof(db->db_password));
+ safestrncpy(db->db_database, "ragnarok", sizeof(db->db_database));
safestrncpy(db->codepage, "", sizeof(db->codepage));
// other settings
db->case_sensitive = false;
@@ -144,46 +131,22 @@ AccountDB* account_db_sql(void)
static bool account_db_sql_init(AccountDB* self)
{
AccountDB_SQL* db = (AccountDB_SQL*)self;
- struct Sql *sql_handle;
- const char* username;
- const char* password;
- const char* hostname;
- uint16 port;
- const char* database;
- const char* codepage;
+ struct Sql *sql_handle = NULL;
nullpo_ret(db);
+
db->accounts = SQL->Malloc();
sql_handle = db->accounts;
- if( db->db_hostname[0] != '\0' )
- {// local settings
- username = db->db_username;
- password = db->db_password;
- hostname = db->db_hostname;
- port = db->db_port;
- database = db->db_database;
- codepage = db->codepage;
- }
- else
- {// global settings
- username = db->global_db_username;
- password = db->global_db_password;
- hostname = db->global_db_hostname;
- port = db->global_db_port;
- database = db->global_db_database;
- codepage = db->global_codepage;
- }
-
- if( SQL_ERROR == SQL->Connect(sql_handle, username, password, hostname, port, database) )
- {
+ if (SQL_ERROR == SQL->Connect(sql_handle, db->db_username, db->db_password,
+ db->db_hostname, db->db_port, db->db_database)) {
Sql_ShowDebug(sql_handle);
SQL->Free(db->accounts);
db->accounts = NULL;
return false;
}
- if( codepage[0] != '\0' && SQL_ERROR == SQL->SetEncoding(sql_handle, codepage) )
+ if (db->codepage[0] != '\0' && SQL_ERROR == SQL->SetEncoding(sql_handle, db->codepage))
Sql_ShowDebug(sql_handle);
Sql_HerculesUpdateCheck(db->accounts);
@@ -207,6 +170,15 @@ static void account_db_sql_destroy(AccountDB* self)
/// Gets a property from this database.
static bool account_db_sql_get_property(AccountDB* self, const char* key, char* buf, size_t buflen)
{
+ /* TODO:
+ * This functionality is not being used as of now, it was removed in
+ * commit 5479f9631f8579d03fbfd14d8a49c7976226a156, it is meant to get
+ * engine properties when more than one engine is available. I'll
+ * re-add it as soon as I can, following the new standards. If anyone
+ * is interested in this functionality you can contact me in our boards
+ * and I'll try to add it sooner (Pan) [Panikon]
+ */
+#if 0
AccountDB_SQL* db = (AccountDB_SQL*)self;
const char* signature;
@@ -230,32 +202,6 @@ static bool account_db_sql_get_property(AccountDB* self, const char* key, char*
return true;
}
- signature = "sql.";
- if( strncmpi(key, signature, strlen(signature)) == 0 )
- {
- key += strlen(signature);
- if( strcmpi(key, "db_hostname") == 0 )
- safesnprintf(buf, buflen, "%s", db->global_db_hostname);
- else
- if( strcmpi(key, "db_port") == 0 )
- safesnprintf(buf, buflen, "%d", db->global_db_port);
- else
- if( strcmpi(key, "db_username") == 0 )
- safesnprintf(buf, buflen, "%s", db->global_db_username);
- else
- if( strcmpi(key, "db_password") == 0 )
- safesnprintf(buf, buflen, "%s", db->global_db_password);
- else
- if( strcmpi(key, "db_database") == 0 )
- safesnprintf(buf, buflen, "%s", db->global_db_database);
- else
- if( strcmpi(key, "codepage") == 0 )
- safesnprintf(buf, buflen, "%s", db->global_codepage);
- else
- return false;// not found
- return true;
- }
-
signature = "account.sql.";
if( strncmpi(key, signature, strlen(signature)) == 0 )
{
@@ -295,82 +241,91 @@ static bool account_db_sql_get_property(AccountDB* self, const char* key, char*
}
return false;// not found
+#endif // 0
+ return false;
}
-/// if the option is supported, adjusts the internal state
-static bool account_db_sql_set_property(AccountDB* self, const char* key, const char* value)
+/**
+ * Reads the 'inter_configuration' config file and initializes required variables.
+ *
+ * @param db Self.
+ * @param filename Path to configuration file
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ */
+bool account_db_read_inter(AccountDB_SQL *db, const char *filename, bool imported)
+{
+ struct config_t config;
+ struct config_setting_t *setting = NULL;
+
+ nullpo_retr(false, db);
+ nullpo_retr(false, filename);
+
+ if (!libconfig->load_file(&config, filename))
+ return false; // Error message is already shown by libconfig->load_file
+
+ if ((setting = libconfig->lookup(&config, "inter_configuration/database_names")) == NULL) {
+ libconfig->destroy(&config);
+ if (imported)
+ return true;
+ ShowError("account_db_sql_set_property: inter_configuration/database_names was not found!\n");
+ return false;
+ }
+ libconfig->setting_lookup_mutable_string(setting, "account_db", db->account_db, sizeof(db->account_db));
+
+ if ((setting = libconfig->lookup(&config, "inter_configuration/database_names/registry")) == NULL) {
+ libconfig->destroy(&config);
+ if (imported)
+ return true;
+ ShowError("account_db_sql_set_property: inter_configuration/database_names/registry was not found!\n");
+ return false;
+ }
+ libconfig->setting_lookup_mutable_string(setting, "global_acc_reg_str_db", db->global_acc_reg_str_db, sizeof(db->global_acc_reg_str_db));
+ libconfig->setting_lookup_mutable_string(setting, "global_acc_reg_num_db", db->global_acc_reg_num_db, sizeof(db->global_acc_reg_num_db));
+
+ // TODO: Proper import mechanism for this file
+
+ libconfig->destroy(&config);
+ return true;
+}
+
+/**
+ * Loads the sql configuration.
+ *
+ * @param self Self.
+ * @param config The current config being parsed.
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ */
+static bool account_db_sql_set_property(AccountDB* self, struct config_t *config, bool imported)
{
AccountDB_SQL* db = (AccountDB_SQL*)self;
- const char* signature;
+ struct config_setting_t *setting = NULL;
nullpo_ret(db);
- nullpo_ret(key);
- nullpo_ret(value);
- signature = "sql.";
- if( strncmp(key, signature, strlen(signature)) == 0 )
- {
- key += strlen(signature);
- if( strcmpi(key, "db_hostname") == 0 )
- safestrncpy(db->global_db_hostname, value, sizeof(db->global_db_hostname));
- else
- if( strcmpi(key, "db_port") == 0 )
- db->global_db_port = (uint16)strtoul(value, NULL, 10);
- else
- if( strcmpi(key, "db_username") == 0 )
- safestrncpy(db->global_db_username, value, sizeof(db->global_db_username));
- else
- if( strcmpi(key, "db_password") == 0 )
- safestrncpy(db->global_db_password, value, sizeof(db->global_db_password));
- else
- if( strcmpi(key, "db_database") == 0 )
- safestrncpy(db->global_db_database, value, sizeof(db->global_db_database));
- else
- if( strcmpi(key, "codepage") == 0 )
- safestrncpy(db->global_codepage, value, sizeof(db->global_codepage));
- else
- return false;// not found
- return true;
- }
+ nullpo_ret(config);
- signature = "account.sql.";
- if( strncmp(key, signature, strlen(signature)) == 0 )
- {
- key += strlen(signature);
- if( strcmpi(key, "db_hostname") == 0 )
- safestrncpy(db->db_hostname, value, sizeof(db->db_hostname));
- else
- if( strcmpi(key, "db_port") == 0 )
- db->db_port = (uint16)strtoul(value, NULL, 10);
- else
- if( strcmpi(key, "db_username") == 0 )
- safestrncpy(db->db_username, value, sizeof(db->db_username));
- else
- if( strcmpi(key, "db_password") == 0 )
- safestrncpy(db->db_password, value, sizeof(db->db_password));
- else
- if( strcmpi(key, "db_database") == 0 )
- safestrncpy(db->db_database, value, sizeof(db->db_database));
- else
- if( strcmpi(key, "codepage") == 0 )
- safestrncpy(db->codepage, value, sizeof(db->codepage));
- else
- if( strcmpi(key, "case_sensitive") == 0 )
- db->case_sensitive = (bool)config_switch(value);
- else
- if( strcmpi(key, "account_db") == 0 )
- safestrncpy(db->account_db, value, sizeof(db->account_db));
- else
- if( strcmpi(key, "global_acc_reg_str_db") == 0 )
- safestrncpy(db->global_acc_reg_str_db, value, sizeof(db->global_acc_reg_str_db));
- else
- if( strcmpi(key, "global_acc_reg_num_db") == 0 )
- safestrncpy(db->global_acc_reg_num_db, value, sizeof(db->global_acc_reg_num_db));
- else
- return false;// not found
- return true;
+ if ((setting = libconfig->lookup(config, "login_configuration/account/sql_connection")) == NULL) {
+ if (imported)
+ return true;
+ ShowError("account_db_sql_set_property: login_configuration/account/sql_connection was not found!\n");
+ ShowWarning("account_db_sql_set_property: Defaulting sql_connection...\n");
+ return false;
}
- return false;// not found
+ libconfig->setting_lookup_mutable_string(setting, "db_hostname", db->db_hostname, sizeof(db->db_hostname));
+ libconfig->setting_lookup_mutable_string(setting, "db_username", db->db_username, sizeof(db->db_username));
+ libconfig->setting_lookup_mutable_string(setting, "db_password", db->db_password, sizeof(db->db_password));
+ libconfig->setting_lookup_mutable_string(setting, "db_database", db->db_database, sizeof(db->db_database));
+ libconfig->setting_lookup_mutable_string(setting, "codepage", db->codepage, sizeof(db->codepage)); // FIXME: Why do we need both codepage and default_codepage?
+ libconfig->setting_lookup_uint16(setting, "db_port", &db->db_port);
+ libconfig->setting_lookup_bool_real(setting, "case_sensitive", &db->case_sensitive);
+
+ account_db_read_inter(db, "conf/common/inter-server.conf", imported);
+
+ return true;
}
/// create a new account entry
diff --git a/src/login/ipban.h b/src/login/ipban.h
index 85cf3873c..104e3a8a3 100644
--- a/src/login/ipban.h
+++ b/src/login/ipban.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
@@ -23,6 +23,9 @@
#include "common/cbasetypes.h"
+/* Forward Declarations */
+struct config_t; // common/conf.h
+
#ifdef HERCULES_CORE
// TODO: Interface
// initialize
@@ -37,8 +40,8 @@ bool ipban_check(uint32 ip);
// increases failure count for the specified IP
void ipban_log(uint32 ip);
-// parses configuration option
-bool ipban_config_read(const char *key, const char* value);
+// parses configuration options
+bool ipban_config_read(const char *filename, struct config_t *config, bool imported);
#endif // HERCULES_CORE
#endif /* LOGIN_IPBAN_H */
diff --git a/src/login/ipban_sql.c b/src/login/ipban_sql.c
index bec0217f4..d74e6c4fa 100644
--- a/src/login/ipban_sql.c
+++ b/src/login/ipban_sql.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
@@ -25,26 +25,21 @@
#include "login/login.h"
#include "login/loginlog.h"
#include "common/cbasetypes.h"
+#include "common/conf.h"
#include "common/nullpo.h"
+#include "common/showmsg.h"
#include "common/sql.h"
#include "common/strlib.h"
#include "common/timer.h"
#include <stdlib.h>
-// global sql settings
-static char global_db_hostname[32] = "127.0.0.1";
-static uint16 global_db_port = 3306;
-static char global_db_username[32] = "ragnarok";
-static char global_db_password[100] = "ragnarok";
-static char global_db_database[32] = "ragnarok";
-static char global_codepage[32] = "";
-// local sql settings
-static char ipban_db_hostname[32] = "";
-static uint16 ipban_db_port = 0;
-static char ipban_db_username[32] = "";
-static char ipban_db_password[100] = "";
-static char ipban_db_database[32] = "";
+// Sql settings
+static char ipban_db_hostname[32] = "127.0.0.1";
+static uint16 ipban_db_port = 3306;
+static char ipban_db_username[32] = "ragnarok";
+static char ipban_db_password[100] = "ragnarok";
+static char ipban_db_database[32] = "ragnarok";
static char ipban_codepage[32] = "";
static char ipban_table[32] = "ipbanlist";
@@ -59,54 +54,30 @@ int ipban_cleanup(int tid, int64 tick, int id, intptr_t data);
// initialize
void ipban_init(void)
{
- const char* username;
- const char* password;
- const char* hostname;
- uint16 port;
- const char* database;
- const char* codepage;
-
ipban_inited = true;
if (!login->config->ipban)
return;// ipban disabled
- if( ipban_db_hostname[0] != '\0' )
- {// local settings
- username = ipban_db_username;
- password = ipban_db_password;
- hostname = ipban_db_hostname;
- port = ipban_db_port;
- database = ipban_db_database;
- codepage = ipban_codepage;
- }
- else
- {// global settings
- username = global_db_username;
- password = global_db_password;
- hostname = global_db_hostname;
- port = global_db_port;
- database = global_db_database;
- codepage = global_codepage;
- }
-
// establish connections
sql_handle = SQL->Malloc();
- if( SQL_ERROR == SQL->Connect(sql_handle, username, password, hostname, port, database) )
- {
+ if (SQL_ERROR == SQL->Connect(sql_handle, ipban_db_username, ipban_db_password,
+ ipban_db_hostname, ipban_db_port, ipban_db_database)) {
Sql_ShowDebug(sql_handle);
SQL->Free(sql_handle);
exit(EXIT_FAILURE);
}
- if( codepage[0] != '\0' && SQL_ERROR == SQL->SetEncoding(sql_handle, codepage) )
+ if (ipban_codepage[0] != '\0' && SQL_ERROR == SQL->SetEncoding(sql_handle, ipban_codepage))
Sql_ShowDebug(sql_handle);
- if (login->config->ipban_cleanup_interval > 0)
- { // set up periodic cleanup of connection history and active bans
+ if (login->config->ipban_cleanup_interval > 0) {
+ // set up periodic cleanup of connection history and active bans
timer->add_func_list(ipban_cleanup, "ipban_cleanup");
cleanup_timer_id = timer->add_interval(timer->gettick()+10, ipban_cleanup, 0, 0, login->config->ipban_cleanup_interval*1000);
- } else // make sure it gets cleaned up on login-server start regardless of interval-based cleanups
+ } else {
+ // make sure it gets cleaned up on login-server start regardless of interval-based cleanups
ipban_cleanup(0,0,0,0);
+ }
}
// finalize
@@ -126,95 +97,153 @@ void ipban_final(void)
sql_handle = NULL;
}
-// load configuration options
-bool ipban_config_read(const char* key, const char* value)
+/**
+ * Reads 'inter_configuration' and initializes required variables/Sets global
+ * configuration.
+ *
+ * @param filename Path to configuration file (used in error and warning messages).
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+
+ */
+bool ipban_config_read_inter(const char *filename, bool imported)
{
- const char* signature;
+ struct config_t config;
+ struct config_setting_t *setting = NULL;
+ const char *import = NULL;
+ bool retval = true;
- nullpo_ret(key);
- nullpo_ret(value);
- if( ipban_inited )
- return false;// settings can only be changed before init
+ nullpo_retr(false, filename);
- signature = "sql.";
- if( strncmpi(key, signature, strlen(signature)) == 0 )
- {
- key += strlen(signature);
- if( strcmpi(key, "db_hostname") == 0 )
- safestrncpy(global_db_hostname, value, sizeof(global_db_hostname));
- else
- if( strcmpi(key, "db_port") == 0 )
- global_db_port = (uint16)strtoul(value, NULL, 10);
- else
- if( strcmpi(key, "db_username") == 0 )
- safestrncpy(global_db_username, value, sizeof(global_db_username));
- else
- if( strcmpi(key, "db_password") == 0 )
- safestrncpy(global_db_password, value, sizeof(global_db_password));
- else
- if( strcmpi(key, "db_database") == 0 )
- safestrncpy(global_db_database, value, sizeof(global_db_database));
- else
- if( strcmpi(key, "codepage") == 0 )
- safestrncpy(global_codepage, value, sizeof(global_codepage));
- else
- return false;// not found
- return true;
+ if (!libconfig->load_file(&config, filename))
+ return false; // Error message is already shown by libconfig->read_file
+
+ if ((setting = libconfig->lookup(&config, "inter_configuration/database_names")) == NULL) {
+ libconfig->destroy(&config);
+ if (imported)
+ return true;
+ ShowError("ipban_config_read: inter_configuration/database_names was not found!\n");
+ return false;
+ }
+ libconfig->setting_lookup_mutable_string(setting, "ipban_table", ipban_table, sizeof(ipban_table));
+
+ // import should overwrite any previous configuration, so it should be called last
+ if (libconfig->lookup_string(&config, "import", &import) == CONFIG_TRUE) {
+ if (strcmp(import, filename) == 0 || strcmp(import, "conf/common/inter-server.conf") == 0) {
+ ShowWarning("ipban_config_read_inter: Loop detected! Skipping 'import'...\n");
+ } else {
+ if (!ipban_config_read_inter(import, true))
+ retval = false;
+ }
}
- signature = "ipban.sql.";
- if( strncmpi(key, signature, strlen(signature)) == 0 )
- {
- key += strlen(signature);
- if( strcmpi(key, "db_hostname") == 0 )
- safestrncpy(ipban_db_hostname, value, sizeof(ipban_db_hostname));
- else
- if( strcmpi(key, "db_port") == 0 )
- ipban_db_port = (uint16)strtoul(value, NULL, 10);
- else
- if( strcmpi(key, "db_username") == 0 )
- safestrncpy(ipban_db_username, value, sizeof(ipban_db_username));
- else
- if( strcmpi(key, "db_password") == 0 )
- safestrncpy(ipban_db_password, value, sizeof(ipban_db_password));
- else
- if( strcmpi(key, "db_database") == 0 )
- safestrncpy(ipban_db_database, value, sizeof(ipban_db_database));
- else
- if( strcmpi(key, "codepage") == 0 )
- safestrncpy(ipban_codepage, value, sizeof(ipban_codepage));
- else
- if( strcmpi(key, "ipban_table") == 0 )
- safestrncpy(ipban_table, value, sizeof(ipban_table));
- else
- return false;// not found
- return true;
+ libconfig->destroy(&config);
+ return retval;
+}
+
+/**
+ * Reads login_configuration/account/ipban/sql_connection and loads configuration options.
+ *
+ * @param filename Path to configuration file (used in error and warning messages).
+ * @param config The current config being parsed.
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ */
+bool ipban_config_read_connection(const char *filename, struct config_t *config, bool imported)
+{
+ struct config_setting_t *setting = NULL;
+
+ nullpo_retr(false, filename);
+ nullpo_retr(false, config);
+
+ if ((setting = libconfig->lookup(config, "login_configuration/account/ipban/sql_connection")) == NULL) {
+ if (imported)
+ return true;
+ ShowError("account_db_sql_set_property: login_configuration/account/ipban/sql_connection was not found in %s!\n", filename);
+ return false;
}
- signature = "ipban.";
- if( strncmpi(key, signature, strlen(signature)) == 0 )
- {
- key += strlen(signature);
- if( strcmpi(key, "enable") == 0 )
- login->config->ipban = (bool)config_switch(value);
- else
- if( strcmpi(key, "dynamic_pass_failure_ban") == 0 )
- login->config->dynamic_pass_failure_ban = (bool)config_switch(value);
- else
- if( strcmpi(key, "dynamic_pass_failure_ban_interval") == 0 )
- login->config->dynamic_pass_failure_ban_interval = atoi(value);
- else
- if( strcmpi(key, "dynamic_pass_failure_ban_limit") == 0 )
- login->config->dynamic_pass_failure_ban_limit = atoi(value);
- else
- if( strcmpi(key, "dynamic_pass_failure_ban_duration") == 0 )
- login->config->dynamic_pass_failure_ban_duration = atoi(value);
- else
- return false;// not found
- return true;
+ libconfig->setting_lookup_mutable_string(setting, "db_hostname", ipban_db_hostname, sizeof(ipban_db_hostname));
+ libconfig->setting_lookup_mutable_string(setting, "db_database", ipban_db_database, sizeof(ipban_db_database));
+
+ libconfig->setting_lookup_mutable_string(setting, "db_username", ipban_db_username, sizeof(ipban_db_username));
+ libconfig->setting_lookup_mutable_string(setting, "db_password", ipban_db_password, sizeof(ipban_db_password));
+ libconfig->setting_lookup_mutable_string(setting, "codepage", ipban_codepage, sizeof(ipban_codepage));
+ libconfig->setting_lookup_uint16(setting, "db_port", &ipban_db_port);
+
+ return true;
+}
+
+/**
+ * Reads login_configuration/account/ipban/dynamic_pass_failure and loads configuration options.
+ *
+ * @param filename Path to configuration file (used in error and warning messages).
+ * @param config The current config being parsed.
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ */
+bool ipban_config_read_dynamic(const char *filename, struct config_t *config, bool imported)
+{
+ struct config_setting_t *setting = NULL;
+
+ nullpo_retr(false, filename);
+ nullpo_retr(false, config);
+
+ if ((setting = libconfig->lookup(config, "login_configuration/account/ipban/dynamic_pass_failure")) == NULL) {
+ if (imported)
+ return true;
+ ShowError("account_db_sql_set_property: login_configuration/account/ipban/dynamic_pass_failure was not found in %s!\n", filename);
+ return false;
+ }
+
+ libconfig->setting_lookup_bool_real(setting, "enabled", &login->config->dynamic_pass_failure_ban);
+ libconfig->setting_lookup_uint32(setting, "ban_interval", &login->config->dynamic_pass_failure_ban_interval);
+ libconfig->setting_lookup_uint32(setting, "ban_limit", &login->config->dynamic_pass_failure_ban_limit);
+ libconfig->setting_lookup_uint32(setting, "ban_duration", &login->config->dynamic_pass_failure_ban_duration);
+
+ return true;
+}
+
+/**
+ * Reads login_configuration.account.ipban and loads configuration options.
+ *
+ * @param filename Path to configuration file (used in error and warning messages).
+ * @param config The current config being parsed.
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ */
+bool ipban_config_read(const char *filename, struct config_t *config, bool imported)
+{
+ struct config_setting_t *setting = NULL;
+ bool retval = true;
+
+ nullpo_retr(false, filename);
+ nullpo_retr(false, config);
+
+ if (ipban_inited)
+ return false; // settings can only be changed before init
+
+ if ((setting = libconfig->lookup(config, "login_configuration/account/ipban")) == NULL) {
+ if (!imported)
+ ShowError("login_config_read: login_configuration/log was not found in %s!\n", filename);
+ return false;
}
- return false;// not found
+ libconfig->setting_lookup_bool_real(setting, "enabled", &login->config->ipban);
+ libconfig->setting_lookup_uint32(setting, "cleanup_interval", &login->config->ipban_cleanup_interval);
+
+ if (!ipban_config_read_inter("conf/common/inter-server.conf", imported))
+ retval = false;
+ if (!ipban_config_read_connection(filename, config, imported))
+ retval = false;
+ if (!ipban_config_read_dynamic(filename, config, imported))
+ retval = false;
+
+ return retval;
}
// check ip against active bans list
diff --git a/src/login/login.c b/src/login/login.c
index 6b422eef2..f1302b673 100644
--- a/src/login/login.c
+++ b/src/login/login.c
@@ -29,6 +29,7 @@
#include "login/lclif.h"
#include "common/HPM.h"
#include "common/cbasetypes.h"
+#include "common/conf.h"
#include "common/core.h"
#include "common/db.h"
#include "common/memmgr.h"
@@ -43,6 +44,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <sys/stat.h> // stat()
/** @file
* Implementation of the login interface.
@@ -1064,13 +1066,14 @@ int login_mmo_auth(struct login_session_data* sd, bool isServer) {
if (login->config->use_dnsbl) {
char r_ip[16];
char ip_dnsbl[256];
- char* dnsbl_serv;
uint8* sin_addr = (uint8*)&sockt->session[sd->fd]->client_addr;
+ int i;
sprintf(r_ip, "%u.%u.%u.%u", sin_addr[0], sin_addr[1], sin_addr[2], sin_addr[3]);
- for (dnsbl_serv = strtok(login->config->dnsbl_servs,","); dnsbl_serv != NULL; dnsbl_serv = strtok(NULL,",")) {
- sprintf(ip_dnsbl, "%s.%s", r_ip, trim(dnsbl_serv));
+ for (i = 0; i < VECTOR_LENGTH(login->config->dnsbl_servers); i++) {
+ char *dnsbl_server = VECTOR_INDEX(login->config->dnsbl_servers, i);
+ sprintf(ip_dnsbl, "%s.%s", r_ip, trim(dnsbl_server));
if (sockt->host2ip(ip_dnsbl)) {
ShowInfo("DNSBL: (%s) Blacklisted. User Kicked.\n", r_ip);
return 3;
@@ -1450,150 +1453,431 @@ void login_config_set_defaults(void)
login->config->dynamic_pass_failure_ban_limit = 7;
login->config->dynamic_pass_failure_ban_duration = 5;
login->config->use_dnsbl = false;
- safestrncpy(login->config->dnsbl_servs, "", sizeof(login->config->dnsbl_servs));
+ VECTOR_INIT(login->config->dnsbl_servers);
login->config->client_hash_check = 0;
login->config->client_hash_nodes = NULL;
}
-//-----------------------------------
-// Reading main configuration file
-//-----------------------------------
-int login_config_read(const char *cfgName)
+/**
+ * Reads 'login_configuration/inter' and initializes required variables.
+ *
+ * @param filename Path to configuration file (used in error and warning messages).
+ * @param config The current config being parsed.
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ */
+bool login_config_read_inter(const char *filename, struct config_t *config, bool imported)
{
- char line[1024], w1[1024], w2[1024];
- FILE* fp;
- nullpo_retr(1, cfgName);
- fp = fopen(cfgName, "r");
- if (fp == NULL) {
- ShowError("Configuration file (%s) not found.\n", cfgName);
- return 1;
+ struct config_setting_t *setting = NULL;
+ const char *str = NULL;
+
+ nullpo_retr(false, filename);
+ nullpo_retr(false, config);
+
+ if ((setting = libconfig->lookup(config, "login_configuration/inter")) == NULL) {
+ if (imported)
+ return true;
+ ShowError("login_config_read: login_configuration/inter was not found in %s!\n", filename);
+ return false;
}
- while(fgets(line, sizeof(line), fp)) {
- if (line[0] == '/' && line[1] == '/')
- continue;
- if (sscanf(line, "%1023[^:]: %1023[^\r\n]", w1, w2) < 2)
+ libconfig->setting_lookup_uint16(setting, "login_port", &login->config->login_port);
+
+ if (libconfig->setting_lookup_uint32(setting, "ip_sync_interval", &login->config->ip_sync_interval) == CONFIG_TRUE)
+ login->config->ip_sync_interval *= 1000*60; // In minutes
+
+ if (libconfig->setting_lookup_string(setting, "bind_ip", &str) == CONFIG_TRUE) {
+ char old_ip_str[16];
+ sockt->ip2str(login->config->login_ip, old_ip_str);
+
+ if ((login->config->login_ip = sockt->host2ip(str)) != 0)
+ ShowStatus("Login server binding IP address : %s -> %s\n", old_ip_str, str);
+ }
+
+ return true;
+}
+
+/**
+ * Reads 'login_configuration.console' and initializes required variables.
+ *
+ * @param filename Path to configuration file (used in error and warning messages).
+ * @param config The current config being parsed.
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ */
+bool login_config_read_console(const char *filename, struct config_t *config, bool imported)
+{
+ struct config_setting_t *setting = NULL;
+
+ nullpo_retr(false, filename);
+ nullpo_retr(false, config);
+
+ if ((setting = libconfig->lookup(config, "login_configuration/console")) == NULL) {
+ if (imported)
+ return true;
+ ShowError("login_config_read: login_configuration/console was not found in %s!\n", filename);
+ return false;
+ }
+
+ libconfig->setting_lookup_bool_real(setting, "stdout_with_ansisequence", &showmsg->stdout_with_ansisequence);
+ if (libconfig->setting_lookup_int(setting, "console_silent", &showmsg->silent) == CONFIG_TRUE) {
+ if (showmsg->silent) // only bother if its actually enabled
+ ShowInfo("Console Silent Setting: %d\n", showmsg->silent);
+ }
+ libconfig->setting_lookup_mutable_string(setting, "timestamp_format", showmsg->timestamp_format, sizeof(showmsg->timestamp_format));
+
+ return true;
+}
+
+/**
+ * Reads 'login_configuration.log' and initializes required variables.
+ *
+ * @param filename Path to configuration file (used in error and warning messages).
+ * @param config The current config being parsed.
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ */
+bool login_config_read_log(const char *filename, struct config_t *config, bool imported)
+{
+ struct config_setting_t *setting = NULL;
+
+ nullpo_retr(false, filename);
+ nullpo_retr(false, config);
+
+ if ((setting = libconfig->lookup(config, "login_configuration/log")) == NULL) {
+ if (imported)
+ return true;
+ ShowError("login_config_read: login_configuration/log was not found in %s!\n", filename);
+ return false;
+ }
+
+ libconfig->setting_lookup_bool_real(setting, "log_login", &login->config->log_login);
+ libconfig->setting_lookup_mutable_string(setting, "date_format", login->config->date_format, sizeof(login->config->date_format));
+ return true;
+}
+
+/**
+ * Reads 'login_configuration.account' and initializes required variables.
+ *
+ * @param filename Path to configuration file (used in error and warning messages).
+ * @param config The current config being parsed.
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ */
+bool login_config_read_account(const char *filename, struct config_t *config, bool imported)
+{
+ struct config_setting_t *setting = NULL;
+ AccountDB *db = account_engine[0].db;
+ bool retval = true;
+
+ nullpo_retr(false, filename);
+ nullpo_retr(false, config);
+
+ if ((setting = libconfig->lookup(config, "login_configuration/account")) == NULL) {
+ if (imported)
+ return true;
+ ShowError("login_config_read: login_configuration/account was not found in %s!\n", filename);
+ return false;
+ }
+
+ libconfig->setting_lookup_bool_real(setting, "new_account", &login->config->new_account_flag);
+ libconfig->setting_lookup_bool_real(setting, "new_acc_length_limit", &login->config->new_acc_length_limit);
+
+ libconfig->setting_lookup_int(setting, "allowed_regs", &login->config->allowed_regs);
+ libconfig->setting_lookup_int(setting, "time_allowed", &login->config->time_allowed);
+ libconfig->setting_lookup_int(setting, "start_limited_time", &login->config->start_limited_time);
+ libconfig->setting_lookup_bool_real(setting, "use_MD5_passwords", &login->config->use_md5_passwds);
+
+ if (!db->set_property(db, config, imported))
+ retval = false;
+ if (!ipban_config_read(filename, config, imported))
+ retval = false;
+
+ return retval;
+}
+
+/**
+ * Frees login->config->client_hash_nodes
+ **/
+void clear_client_hash_nodes(void)
+{
+ struct client_hash_node *node = login->config->client_hash_nodes;
+
+ while (node != NULL) {
+ struct client_hash_node *next = node->next;
+ aFree(node);
+ node = next;
+ }
+
+ login->config->client_hash_nodes = NULL;
+}
+
+/**
+ * Reads information from login_configuration.permission.hash.md5_hashes.
+ *
+ * @param setting The setting to read from.
+ */
+void login_config_set_md5hash(struct config_setting_t *setting)
+{
+ int i;
+ int count = libconfig->setting_length(setting);
+
+ clear_client_hash_nodes();
+
+ // There's no need to parse if it's disabled or if there's no list
+ if (count <= 0 || !login->config->client_hash_check)
+ return;
+
+ for (i = 0; i < count; i++) {
+ int j;
+ int group_id = 0;
+ char md5hash[33];
+ struct client_hash_node *nnode = NULL;
+ struct config_setting_t *item = libconfig->setting_get_elem(setting, i);
+
+ if (item == NULL)
continue;
- if(!strcmpi(w1,"timestamp_format"))
- safestrncpy(showmsg->timestamp_format, w2, 20);
- else if(!strcmpi(w1,"stdout_with_ansisequence"))
- showmsg->stdout_with_ansisequence = config_switch(w2) ? true : false;
- else if(!strcmpi(w1,"console_silent")) {
- showmsg->silent = atoi(w2);
- if (showmsg->silent) /* only bother if we actually have this enabled */
- ShowInfo("Console Silent Setting: %d\n", atoi(w2));
- }
- else if( !strcmpi(w1, "bind_ip") ) {
- login->config->login_ip = sockt->host2ip(w2);
- if (login->config->login_ip) {
- char ip_str[16];
- ShowStatus("Login server binding IP address : %s -> %s\n", w2, sockt->ip2str(login->config->login_ip, ip_str));
- }
+ if (libconfig->setting_lookup_int(item, "group_id", &group_id) != CONFIG_TRUE) {
+ ShowWarning("login_config_set_md5hash: entry (%d) is missing group_id! Ignoring...\n", i);
+ continue;
}
- else if( !strcmpi(w1, "login_port") ) {
- login->config->login_port = (uint16)atoi(w2);
+
+ if (libconfig->setting_lookup_mutable_string(item, "hash", md5hash, sizeof(md5hash)) != CONFIG_TRUE) {
+ ShowWarning("login_config_set_md5hash: entry (%d) is missing hash! Ignoring...\n", i);
+ continue;
}
- else if(!strcmpi(w1, "log_login"))
- login->config->log_login = (bool)config_switch(w2);
-
- else if(!strcmpi(w1, "new_account"))
- login->config->new_account_flag = (bool)config_switch(w2);
- else if(!strcmpi(w1, "new_acc_length_limit"))
- login->config->new_acc_length_limit = (bool)config_switch(w2);
- else if(!strcmpi(w1, "start_limited_time"))
- login->config->start_limited_time = atoi(w2);
- else if(!strcmpi(w1, "check_client_version"))
- login->config->check_client_version = (bool)config_switch(w2);
- else if(!strcmpi(w1, "client_version_to_connect"))
- login->config->client_version_to_connect = (unsigned int)strtoul(w2, NULL, 10);
- else if(!strcmpi(w1, "use_MD5_passwords"))
- login->config->use_md5_passwds = (bool)config_switch(w2);
- else if(!strcmpi(w1, "group_id_to_connect"))
- login->config->group_id_to_connect = atoi(w2);
- else if(!strcmpi(w1, "min_group_id_to_connect"))
- login->config->min_group_id_to_connect = atoi(w2);
- else if(!strcmpi(w1, "date_format"))
- safestrncpy(login->config->date_format, w2, sizeof(login->config->date_format));
- else if(!strcmpi(w1, "allowed_regs")) //account flood protection system
- login->config->allowed_regs = atoi(w2);
- else if(!strcmpi(w1, "time_allowed"))
- login->config->time_allowed = atoi(w2);
- else if(!strcmpi(w1, "use_dnsbl"))
- login->config->use_dnsbl = (bool)config_switch(w2);
- else if(!strcmpi(w1, "dnsbl_servers"))
- safestrncpy(login->config->dnsbl_servs, w2, sizeof(login->config->dnsbl_servs));
- else if(!strcmpi(w1, "ipban_cleanup_interval"))
- 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 md5hash[33];
- memset(md5hash, '\0', 33);
-
- if (sscanf(w2, "%d, %32s", &group, md5hash) == 2) {
- struct client_hash_node *nnode;
- CREATE(nnode, struct client_hash_node, 1);
-
- if (strcmpi(md5hash, "disabled") == 0) {
- nnode->hash[0] = '\0';
- } else {
- int i;
- for (i = 0; i < 32; i += 2) {
- char buf[3];
- unsigned int byte;
-
- memcpy(buf, &md5hash[i], 2);
- buf[2] = 0;
-
- sscanf(buf, "%x", &byte);
- nnode->hash[i / 2] = (uint8)(byte & 0xFF);
- }
- }
-
- nnode->group_id = group;
- nnode->next = login->config->client_hash_nodes;
-
- login->config->client_hash_nodes = nnode;
+
+ CREATE(nnode, struct client_hash_node, 1);
+ if (strcmpi(md5hash, "disabled") == 0) {
+ nnode->hash[0] = '\0';
+ } else {
+ for (j = 0; j < 32; j += 2) {
+ char buf[3];
+ unsigned int byte;
+
+ memcpy(buf, &md5hash[j], 2);
+ buf[2] = 0;
+
+ sscanf(buf, "%x", &byte);
+ nnode->hash[j / 2] = (uint8)(byte & 0xFF);
}
}
- else if(!strcmpi(w1, "import"))
- login_config_read(w2);
- else
- {
- AccountDB* db = account_engine[0].db;
- if (db)
- db->set_property(db, w1, w2);
- ipban_config_read(w1, w2);
- loginlog_config_read(w1, w2);
- HPM->parseConf(w1, w2, HPCT_LOGIN);
+ nnode->group_id = group_id;
+ nnode->next = login->config->client_hash_nodes; // login->config->client_hash_nodes is initialized before calling this function
+ login->config->client_hash_nodes = nnode;
+ }
+
+ return;
+}
+
+/**
+ * Reads 'login_configuration/permission/hash' and initializes required variables.
+ *
+ * @param filename Path to configuration file (used in error and warning messages).
+ * @param config The current config being parsed.
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ */
+bool login_config_read_permission_hash(const char *filename, struct config_t *config, bool imported)
+{
+ struct config_setting_t *setting = NULL;
+
+ nullpo_retr(false, filename);
+ nullpo_retr(false, config);
+
+ if ((setting = libconfig->lookup(config, "login_configuration/permission/hash")) == NULL) {
+ if (imported)
+ return true;
+ ShowError("login_config_read: login_configuration/permission/hash was not found in %s!\n", filename);
+ return false;
+ }
+
+ libconfig->setting_lookup_bool_real(setting, "enabled", &login->config->client_hash_check);
+
+ if ((setting = libconfig->lookup(config, "login_configuration/permission/hash/MD5_hashes")) != NULL)
+ login_config_set_md5hash(setting);
+
+ return true;
+}
+
+/**
+ * Clears login->config->dnsbl_servers, freeing any allocated memory.
+ */
+void clear_dnsbl_servers(void)
+{
+ while (VECTOR_LENGTH(login->config->dnsbl_servers) > 0) {
+ aFree(&VECTOR_POP(login->config->dnsbl_servers));
+ }
+ VECTOR_CLEAR(login->config->dnsbl_servers);
+}
+
+/**
+ * Reads information from login_config/permission/DNS_blacklist/dnsbl_servers.
+ *
+ * @param setting The configuration setting to read from.
+ */
+void login_config_set_dnsbl_servers(struct config_setting_t *setting)
+{
+ int i;
+ int count = libconfig->setting_length(setting);
+
+ clear_dnsbl_servers();
+
+ // There's no need to parse if it's disabled
+ if (count <= 0 || !login->config->use_dnsbl)
+ return;
+
+ VECTOR_ENSURE(login->config->dnsbl_servers, count, 1);
+
+ for (i = 0; i < count; i++) {
+ const char *string = libconfig->setting_get_string_elem(setting, i);
+
+ if (string == NULL || string[0] == '\0')
+ continue;
+
+ VECTOR_PUSH(login->config->dnsbl_servers, aStrdup(string));
+ }
+}
+
+/**
+ * Reads 'login_configuration/permission/DNS_blacklist' and initializes required variables.
+ *
+ * @param filename Path to configuration file (used in error and warning messages).
+ * @param config The current config being parsed.
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ */
+bool login_config_read_permission_blacklist(const char *filename, struct config_t *config, bool imported)
+{
+ struct config_setting_t *setting = NULL;
+
+ nullpo_retr(false, filename);
+ nullpo_retr(false, config);
+
+ if ((setting = libconfig->lookup(config, "login_configuration/permission/DNS_blacklist")) == NULL) {
+ if (imported)
+ return true;
+ ShowError("login_config_read: login_configuration/permission/DNS_blacklist was not found in %s!\n", filename);
+ return false;
+ }
+
+ libconfig->setting_lookup_bool_real(setting, "enabled", &login->config->use_dnsbl);
+
+ if ((setting = libconfig->lookup(config, "login_configuration/permission/DNS_blacklist/dnsbl_servers")) != NULL)
+ login_config_set_dnsbl_servers(setting);
+
+ return true;
+}
+
+/**
+ * Reads 'login_configuration.permission' and initializes required variables.
+ *
+ * @param filename Path to configuration file (used in error and warning messages).
+ * @param config The current config being parsed.
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ */
+bool login_config_read_permission(const char *filename, struct config_t *config, bool imported)
+{
+ struct config_setting_t *setting = NULL;
+ bool retval = true;
+
+ nullpo_retr(false, filename);
+ nullpo_retr(false, config);
+
+ if ((setting = libconfig->lookup(config, "login_configuration/permission")) == NULL) {
+ if (imported)
+ return true;
+ ShowError("login_config_read: login_configuration/permission was not found in %s!\n", filename);
+ return false;
+ }
+
+ libconfig->setting_lookup_int(setting, "group_id_to_connect", &login->config->group_id_to_connect);
+ libconfig->setting_lookup_int(setting, "min_group_id_to_connect", &login->config->min_group_id_to_connect);
+ libconfig->setting_lookup_bool_real(setting, "check_client_version", &login->config->check_client_version);
+ libconfig->setting_lookup_uint32(setting, "client_version_to_connect", &login->config->client_version_to_connect);
+
+ if (!login_config_read_permission_hash(filename, config, imported))
+ retval = false;
+ if (!login_config_read_permission_blacklist(filename, config, imported))
+ retval = false;
+
+ return retval;
+}
+
+/**
+ * Reads the 'login-config' configuration file and initializes required variables.
+ *
+ * @param filename Path to configuration file.
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ **/
+bool login_config_read(const char *filename, bool imported)
+{
+ struct config_t config;
+ const char *import = NULL;
+ bool retval = true;
+
+ nullpo_retr(false, filename);
+
+ if (!libconfig->load_file(&config, filename))
+ return false; // Error message is already shown by libconfig->load_file
+
+ if (!login_config_read_inter(filename, &config, imported))
+ retval = false;
+ if (!login_config_read_console(filename, &config, imported))
+ retval = false;
+ if (!login_config_read_log(filename, &config, imported))
+ retval = false;
+ if (!login_config_read_account(filename, &config, imported))
+ retval = false;
+ if (!login_config_read_permission(filename, &config, imported))
+ retval = false;
+
+ if (!loginlog_config_read("conf/common/inter-server.conf", imported)) // Only inter-server
+ retval = false;
+
+ // TODO HPM->parseConf(w1, w2, HPCT_LOGIN);
+
+ ShowInfo("Finished reading %s.\n", filename);
+
+ // import should overwrite any previous configuration, so it should be called last
+ if (libconfig->lookup_string(&config, "import", &import) == CONFIG_TRUE) {
+ if (strcmp(import, filename) == 0 || strcmp(import, login->LOGIN_CONF_NAME) == 0) {
+ ShowWarning("login_config_read: Loop detected in %s! Skipping 'import'...\n", filename);
+ } else {
+ if (!login->config_read(import, true))
+ retval = false;
}
}
- fclose(fp);
- ShowInfo("Finished reading %s.\n", cfgName);
- return 0;
+
+ config_destroy(&config);
+ return retval;
}
//--------------------------------------
// Function called at exit of the server
//--------------------------------------
-int do_final(void) {
+int do_final(void)
+{
int i;
- struct client_hash_node *hn = login->config->client_hash_nodes;
ShowStatus("Terminating...\n");
HPM->event(HPET_FINAL);
- while (hn) {
- struct client_hash_node *tmp = hn;
- hn = hn->next;
- aFree(tmp);
- }
+ clear_client_hash_nodes();
+ clear_dnsbl_servers();
login_log(0, "login server", 100, "login server shutdown");
@@ -1730,9 +2014,28 @@ int do_init(int argc, char** argv)
// read login-server configuration
login->config_set_defaults();
- login->LOGIN_CONF_NAME = aStrdup("conf/login-server.conf");
+ login->LOGIN_CONF_NAME = aStrdup("conf/login/login-server.conf");
login->NET_CONF_NAME = aStrdup("conf/network.conf");
+ {
+ // TODO: Remove this when no longer needed.
+#define CHECK_OLD_LOCAL_CONF(oldname, newname) do { \
+ if (stat((oldname), &fileinfo) == 0 && fileinfo.st_size > 0) { \
+ ShowWarning("An old configuration file \"%s\" was found.\n", (oldname)); \
+ ShowWarning("If it contains settings you wish to keep, please merge them into \"%s\".\n", (newname)); \
+ ShowWarning("Otherwise, just delete it.\n"); \
+ ShowInfo("Resuming in 10 seconds...\n"); \
+ HSleep(10); \
+ } \
+} while (0)
+ struct stat fileinfo;
+
+ CHECK_OLD_LOCAL_CONF("conf/import/login_conf.txt", "conf/import/login-server.conf");
+ CHECK_OLD_LOCAL_CONF("conf/import/inter_conf.txt", "conf/import/inter-server.conf");
+
+#undef CHECK_OLD_LOCAL_CONF
+ }
+
lclif->init();
HPM_login_do_init();
@@ -1741,7 +2044,7 @@ int do_init(int argc, char** argv)
HPM->event(HPET_PRE_INIT);
cmdline->exec(argc, argv, CMDLINE_OPT_NORMAL);
- login_config_read(login->LOGIN_CONF_NAME);
+ login->config_read(login->LOGIN_CONF_NAME, false);
sockt->net_config_read(login->NET_CONF_NAME);
for( i = 0; i < ARRAYLENGTH(server); ++i )
diff --git a/src/login/login.h b/src/login/login.h
index 36085ae91..5632e6529 100644
--- a/src/login/login.h
+++ b/src/login/login.h
@@ -97,8 +97,8 @@ struct Login_Config {
uint32 login_ip; ///< the address to bind to
uint16 login_port; ///< the port to bind to
- unsigned int ipban_cleanup_interval; ///< interval (in seconds) to clean up expired IP bans
- unsigned int ip_sync_interval; ///< interval (in minutes) to execute a DNS/IP update (for dynamic IPs)
+ uint32 ipban_cleanup_interval; ///< interval (in seconds) to clean up expired IP bans
+ uint32 ip_sync_interval; ///< interval (in minutes) to execute a DNS/IP update (for dynamic IPs)
bool log_login; ///< whether to log login server actions or not
char date_format[32]; ///< date format used in messages
bool new_account_flag,new_acc_length_limit; ///< auto-registration via _M/_F ? / if yes minimum length is 4?
@@ -113,13 +113,14 @@ struct Login_Config {
bool ipban; ///< perform IP blocking (via contents of `ipbanlist`) ?
bool dynamic_pass_failure_ban; ///< automatic IP blocking due to failed login attemps ?
- unsigned int dynamic_pass_failure_ban_interval; ///< how far to scan the loginlog for password failures
- unsigned int dynamic_pass_failure_ban_limit; ///< number of failures needed to trigger the ipban
- unsigned int dynamic_pass_failure_ban_duration; ///< duration of the ipban
+ uint32 dynamic_pass_failure_ban_interval; ///< how far to scan the loginlog for password failures
+ uint32 dynamic_pass_failure_ban_limit; ///< number of failures needed to trigger the ipban
+ uint32 dynamic_pass_failure_ban_duration; ///< duration of the ipban
bool use_dnsbl; ///< dns blacklist blocking ?
- char dnsbl_servs[1024]; ///< comma-separated list of dnsbl servers
+ VECTOR_DECL(char *) dnsbl_servers; ///< dnsbl servers
- int client_hash_check; ///< flags for checking client md5
+ bool client_hash_check; ///< flags for checking client md5
+ // TODO: VECTOR candidate
struct client_hash_node *client_hash_nodes; ///< linked list containg md5 hash for each gm group
};
@@ -207,7 +208,7 @@ struct login_interface {
void (*char_server_connection_status) (int fd, struct login_session_data* sd, uint8 status);
void (*parse_request_connection) (int fd, struct login_session_data* sd, const char *ip, uint32 ipl);
void (*config_set_defaults) (void);
- int (*config_read) (const char *cfgName);
+ bool (*config_read) (const char *filename, bool included);
char *LOGIN_CONF_NAME;
char *NET_CONF_NAME; ///< Network configuration filename
};
diff --git a/src/login/loginlog.h b/src/login/loginlog.h
index efb0873bd..589bc4fa1 100644
--- a/src/login/loginlog.h
+++ b/src/login/loginlog.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
@@ -29,7 +29,7 @@ unsigned long loginlog_failedattempts(uint32 ip, unsigned int minutes);
void login_log(uint32 ip, const char* username, int rcode, const char* message);
bool loginlog_init(void);
bool loginlog_final(void);
-bool loginlog_config_read(const char* w1, const char* w2);
+bool loginlog_config_read(const char *filename, bool imported);
#endif // HERCULES_CORE
#endif /* LOGIN_LOGINLOG_H */
diff --git a/src/login/loginlog_sql.c b/src/login/loginlog_sql.c
index 16accfada..7dff14990 100644
--- a/src/login/loginlog_sql.c
+++ b/src/login/loginlog_sql.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
@@ -23,27 +23,22 @@
#include "loginlog.h"
#include "common/cbasetypes.h"
+#include "common/conf.h"
#include "common/mmo.h"
#include "common/nullpo.h"
+#include "common/showmsg.h"
#include "common/socket.h"
#include "common/sql.h"
#include "common/strlib.h"
#include <stdlib.h> // exit
-// global sql settings (in ipban_sql.c)
-static char global_db_hostname[32] = "127.0.0.1";
-static uint16 global_db_port = 3306;
-static char global_db_username[32] = "ragnarok";
-static char global_db_password[100] = "ragnarok";
-static char global_db_database[32] = "ragnarok";
-static char global_codepage[32] = "";
-// local sql settings
-static char log_db_hostname[32] = "";
-static uint16 log_db_port = 0;
-static char log_db_username[32] = "";
-static char log_db_password[100] = "";
-static char log_db_database[32] = "";
+// Sql settings
+static char log_db_hostname[32] = "127.0.0.1";
+static uint16 log_db_port = 3306;
+static char log_db_username[32] = "ragnarok";
+static char log_db_password[100] = "ragnarok";
+static char log_db_database[32] = "ragnarok";
static char log_codepage[32] = "";
static char log_login_db[256] = "loginlog";
@@ -102,42 +97,16 @@ void login_log(uint32 ip, const char* username, int rcode, const char* message)
bool loginlog_init(void)
{
- const char* username;
- const char* password;
- const char* hostname;
- uint16 port;
- const char* database;
- const char* codepage;
-
- if( log_db_hostname[0] != '\0' )
- {// local settings
- username = log_db_username;
- password = log_db_password;
- hostname = log_db_hostname;
- port = log_db_port;
- database = log_db_database;
- codepage = log_codepage;
- }
- else
- {// global settings
- username = global_db_username;
- password = global_db_password;
- hostname = global_db_hostname;
- port = global_db_port;
- database = global_db_database;
- codepage = global_codepage;
- }
-
sql_handle = SQL->Malloc();
- if( SQL_ERROR == SQL->Connect(sql_handle, username, password, hostname, port, database) )
- {
+ if (SQL_ERROR == SQL->Connect(sql_handle, log_db_username, log_db_password,
+ log_db_hostname, log_db_port, log_db_database)) {
Sql_ShowDebug(sql_handle);
SQL->Free(sql_handle);
exit(EXIT_FAILURE);
}
- if( codepage[0] != '\0' && SQL_ERROR == SQL->SetEncoding(sql_handle, codepage) )
+ if (log_codepage[0] != '\0' && SQL_ERROR == SQL->SetEncoding(sql_handle, log_codepage))
Sql_ShowDebug(sql_handle);
enabled = true;
@@ -152,60 +121,105 @@ bool loginlog_final(void)
return true;
}
-bool loginlog_config_read(const char* key, const char* value)
+/**
+ * Reads 'inter_configuration/database_names' and initializes required
+ * variables/Sets global configuration.
+ *
+ * @param filename Path to configuration file (used in error and warning messages).
+ * @param config The current config being parsed.
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ */
+bool loginlog_config_read_names(const char *filename, struct config_t *config, bool imported)
{
- const char* signature;
+ struct config_setting_t *setting = NULL;
- nullpo_ret(key);
- nullpo_ret(value);
- signature = "sql.";
- if( strncmpi(key, signature, strlen(signature)) == 0 )
- {
- key += strlen(signature);
- if( strcmpi(key, "db_hostname") == 0 )
- safestrncpy(global_db_hostname, value, sizeof(global_db_hostname));
- else
- if( strcmpi(key, "db_port") == 0 )
- global_db_port = (uint16)strtoul(value, NULL, 10);
- else
- if( strcmpi(key, "db_username") == 0 )
- safestrncpy(global_db_username, value, sizeof(global_db_username));
- else
- if( strcmpi(key, "db_password") == 0 )
- safestrncpy(global_db_password, value, sizeof(global_db_password));
- else
- if( strcmpi(key, "db_database") == 0 )
- safestrncpy(global_db_database, value, sizeof(global_db_database));
- else
- if( strcmpi(key, "codepage") == 0 )
- safestrncpy(global_codepage, value, sizeof(global_codepage));
- else
- return false;// not found
- return true;
+ nullpo_retr(false, filename);
+ nullpo_retr(false, config);
+
+ if ((setting = libconfig->lookup(config, "inter_configuration/database_names")) == NULL) {
+ if (imported)
+ return true;
+ ShowError("loginlog_config_read: inter_configuration/database_names was not found in %s!\n", filename);
+ return false;
}
- if( strcmpi(key, "log_db_ip") == 0 )
- safestrncpy(log_db_hostname, value, sizeof(log_db_hostname));
- else
- if( strcmpi(key, "log_db_port") == 0 )
- log_db_port = (uint16)strtoul(value, NULL, 10);
- else
- if( strcmpi(key, "log_db_id") == 0 )
- safestrncpy(log_db_username, value, sizeof(log_db_username));
- else
- if( strcmpi(key, "log_db_pw") == 0 )
- safestrncpy(log_db_password, value, sizeof(log_db_password));
- else
- if( strcmpi(key, "log_db_db") == 0 )
- safestrncpy(log_db_database, value, sizeof(log_db_database));
- else
- if( strcmpi(key, "log_codepage") == 0 )
- safestrncpy(log_codepage, value, sizeof(log_codepage));
- else
- if( strcmpi(key, "log_login_db") == 0 )
- safestrncpy(log_login_db, value, sizeof(log_login_db));
- else
+ libconfig->setting_lookup_mutable_string(setting, "login_db", log_login_db, sizeof(log_login_db));
+
+ return true;
+}
+
+/**
+ * Reads 'inter_configuration.log' and initializes required variables/Sets
+ * global configuration.
+ *
+ * @param filename Path to configuration file (used in error and warning messages).
+ * @param config The current config being parsed.
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ */
+bool loginlog_config_read_log(const char *filename, struct config_t *config, bool imported)
+{
+ struct config_setting_t *setting = NULL;
+
+ nullpo_retr(false, filename);
+ nullpo_retr(false, config);
+
+ if ((setting = libconfig->lookup(config, "inter_configuration/log/sql_connection")) == NULL) {
+ if (imported)
+ return true;
+ ShowError("loginlog_config_read: inter_configuration/log/sql_connection was not found in %s!\n", filename);
return false;
+ }
+
+ libconfig->setting_lookup_mutable_string(setting, "db_hostname", log_db_hostname, sizeof(log_db_hostname));
+ libconfig->setting_lookup_mutable_string(setting, "db_database", log_db_database, sizeof(log_db_database));
+ libconfig->setting_lookup_mutable_string(setting, "db_username", log_db_username, sizeof(log_db_username));
+ libconfig->setting_lookup_mutable_string(setting, "db_password", log_db_password, sizeof(log_db_password));
+
+ libconfig->setting_lookup_uint16(setting, "db_port", &log_db_port);
+ libconfig->setting_lookup_mutable_string(setting, "codepage", log_codepage, sizeof(log_codepage));
return true;
}
+
+/**
+ * Reads 'inter_configuration' and initializes required variables/Sets global
+ * configuration.
+ *
+ * @param filename Path to configuration file.
+ * @param config The current config being parsed.
+ * @param imported Whether the current config is imported from another file.
+ *
+ * @retval false in case of error.
+ **/
+bool loginlog_config_read(const char *filename, bool imported)
+{
+ struct config_t config;
+ const char *import = NULL;
+ bool retval = true;
+
+ nullpo_retr(false, filename);
+
+ if (!libconfig->load_file(&config, filename))
+ return false; // Error message is already shown by libconfig->load_file
+
+ if (!loginlog_config_read_names(filename, &config, imported))
+ retval = false;
+ if (!loginlog_config_read_log(filename, &config, imported))
+ retval = false;
+
+ if (libconfig->lookup_string(&config, "import", &import) == CONFIG_TRUE) {
+ if (strcmp(import, filename) == 0 || strcmp(import, "conf/common/inter-server.conf") == 0) {
+ ShowWarning("inter_config_read: Loop detected! Skipping 'import'...\n");
+ } else {
+ if (!loginlog_config_read(import, true))
+ retval = false;
+ }
+ }
+
+ libconfig->destroy(&config);
+ return retval;
+}
diff --git a/tools/configconverter.pl b/tools/configconverter.pl
index c49dc95d9..435e4b246 100755
--- a/tools/configconverter.pl
+++ b/tools/configconverter.pl
@@ -57,18 +57,37 @@ sub cfg_add($$$$) {
$output->{$variable} = {value => $value, print => $default->{print}, path => $default->{path}} unless $value eq $default->{default};
}
-sub parsecfg_string($$$$) {
+sub cfg_append($$$$) {
my ($variable, $value, $default, $output) = @_;
+ for my $default_value (@{$default->{default}}) {
+ return if $value eq $default_value;
+ }
+ $output->{$variable} = {value => [], print => $default->{print}, path => $default->{path}} unless $output->{$variable};
+ push(@{$output->{$variable}->{value}}, $value);
+}
+
+sub parsecfg_string_sub($$$$$) {
+ my ($variable, $value, $default, $output, $func) = @_;
if ($value =~ m{\s*"((?:\\"|.)*)"\s*(?://.*)?$}i) {
- cfg_add($variable, $1, $default, $output);
+ $func->($variable, $1, $default, $output);
return 1;
} elsif ($value =~ m{\s*((?:\\"|.)*)\s*(?://.*)?$}i) {
- cfg_add($variable, $1, $default, $output);
+ $func->($variable, $1, $default, $output);
return 1;
}
return 0;
}
+sub parsecfg_string($$$$) {
+ my ($variable, $value, $default, $output) = @_;
+ return parsecfg_string_sub($variable, $value, $default, $output, \&cfg_add);
+}
+
+sub parsecfg_stringarr($$$$) {
+ my ($variable, $value, $default, $output) = @_;
+ return parsecfg_string_sub($variable, $value, $default, $output, \&cfg_append);
+}
+
sub parsecfg_int($$$$) {
my ($variable, $value, $default, $output) = @_;
if ($value =~ m{\s*(-?[0-9]+)\s*(?://.*)?$}) {
@@ -189,6 +208,39 @@ sub printcfg_items($$$) {
indent(")\n", $nestlevel);
}
+sub printcfg_md5hash($$$) {
+ my ($variable, $value, $nestlevel) = @_;
+
+ indent("$variable: (\n", $nestlevel);
+
+ for (@$value) {
+ my ($group_id, $hash) = split(/,/, $_, 2);
+ $group_id =~ s/\s*$//; $group_id =~ s/^\s*//;
+ $hash =~ s/\s*$//; $hash =~ s/^\s*//;
+
+ indent("{\n", $nestlevel);
+ indent("group_id: $group_id\n", $nestlevel + 1);
+ indent("hash: \"$hash\"\n", $nestlevel + 1);
+ indent("},\n", $nestlevel);
+ }
+
+ indent(")\n", $nestlevel);
+}
+
+sub printcfg_strlist($$$) {
+ my ($variable, $value, $nestlevel) = @_;
+
+ indent("$variable: (\n", $nestlevel);
+
+ for my $string (split(/,/, $value)) {
+ $string =~ s/\s*$//; $string =~ s/^\s*//;
+
+ indent("\"$string\",\n", $nestlevel + 1);
+ }
+
+ indent(")\n", $nestlevel);
+}
+
sub process_conf($$) {
my ($files, $defaults) = @_;
my $found = 0;
@@ -271,7 +323,7 @@ my @defaults = (
inter_log_filename => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/log/", default => "log/inter.log"},
mysql_reconnect_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "inter-server:inter_configuration/mysql_reconnect/type", default => 2},
mysql_reconnect_count => {parse => \&parsecfg_int, print => \&printcfg_int, path => "inter-server:inter_configuration/mysql_reconnect/count", default => 1},
- log_login_db => {parse => \&parsecfg_string, print => \&printcfg_nil, path => "inter-server:inter_configuration/database_names/login_db", default => "loginlog"},
+ log_login_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/login_db", default => "loginlog"},
char_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/", default => "char"},
interlog_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/", default => "interlog"},
ragsrvinfo_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/", default => "ragsrvinfo"},
@@ -340,6 +392,56 @@ my @defaults = (
import => {parse => \&parsecfg_string, print => \&printcfg_nil, path => "", default => "conf/import/inter_conf.txt"},
}
},
+ {
+ files => ['login-server.conf', 'import/login_conf.txt'],
+ settings => {
+ bind_ip => {parse => \&parsecfg_string, print => \&printcfg_string, path => "login-server:login_configuration/inter/", default => "127.0.0.1"},
+ login_port => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/inter/", default => 6900},
+ timestamp_format => {parse => \&parsecfg_string, print => \&printcfg_string, path => "console:console/", default => "[%d/%b %H:%M]"},
+ stdout_with_ansisequence => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "console:console/", default => "false"},
+ console_silent => {parse => \&parsecfg_int, print => \&printcfg_int, path => "console:console/", default => 0},
+ new_account => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "login-server:login_configuration/account/", default => "true"},
+ new_acc_length_limit => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "login-server:login_configuration/account/", default => "true"},
+ allowed_regs => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/account/", default => 1},
+ time_allowed => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/account/", default => 10},
+ log_login => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "login-server:login_configuration/log/", default => "true"},
+ date_format => {parse => \&parsecfg_string, print => \&printcfg_string, path => "login-server:login_configuration/log/", default => "%Y-%m-%d %H:%M:%S"},
+ group_id_to_connect => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/permission/", default => -1},
+ min_group_id_to_connect => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/permission/", default => -1},
+ start_limited_time => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/account/", default => -1},
+ check_client_version => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "login-server:login_configuration/permission/", default => "false"},
+ client_version_to_connect => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/permission/", default => 20},
+ use_MD5_passwords => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "login-server:login_configuration/account/", default => "false"},
+ 'ipban.enable' => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "login-server:login_configuration/account/ipban/enabled", default => "true"},
+ 'ipban.sql.db_hostname' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_hostname", default => "127.0.0.1"},
+ 'ipban.sql.db_port' => {parse => \&parsecfg_int, print => \&printcfg_int, path => "sql_connection:sql_connection/db_port", default => 3306},
+ 'ipban.sql.db_username' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_username", default => "ragnarok"},
+ 'ipban.sql.db_password' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_password", default => "ragnarok"},
+ 'ipban.sql.db_database' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_database", default => "ragnarok"},
+ 'ipban.sql.codepage' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/codepage", default => ""},
+ 'ipban.sql.ipban_table' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/ipban_table", default => "ipbanlist"},
+ 'ipban.dynamic_pass_failure_ban' => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "login-server:login_configuration/account/ipban/dynamic_pass_failure/enabled", default => "true"},
+ 'ipban.dynamic_pass_failure_ban_interval' => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/account/ipban/dynamic_pass_failure/ban_interval", default => 5},
+ 'ipban.dynamic_pass_failure_ban_limit' => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/account/ipban/dynamic_pass_failure/ban_limit", default => 7},
+ 'ipban.dynamic_pass_failure_ban_duration' => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/account/ipban/dynamic_pass_failure/ban_duration", default => 5},
+ ipban_cleanup_interval => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/account/ipban/cleanup_interval", default => 60},
+ ip_sync_interval => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/inter/ip_sync_interval", default => 10},
+ use_dnsbl => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "login-server:login_configuration/permission/DNS_blacklist/enabled", default => "false"},
+ dnsbl_servers => {parse => \&parsecfg_string, print => \&printcfg_strlist, path => "login-server:login_configuration/permission/DNS_blacklist/dnsbl_servers", default => "bl.blocklist.de, socks.dnsbl.sorbs.net"},
+ 'account.sql.db_hostname' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_hostname", default => "127.0.0.1"},
+ 'account.sql.db_port' => {parse => \&parsecfg_int, print => \&printcfg_int, path => "sql_connection:sql_connection/db_port", default => 3306},
+ 'account.sql.db_username' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_username", default => "ragnarok"},
+ 'account.sql.db_password' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_password", default => "ragnarok"},
+ 'account.sql.db_database' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_database", default => "ragnarok"},
+ 'account.sql.codepage' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/codepage", default => ""},
+ 'account.sql.case_sensitive' => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "sql_connection:sql_connection/case_sensitive", default => "false"},
+ 'account.sql.account_db' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/account_db", default => "login"},
+ client_hash_check => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "login-server:login_configuration/permission/hash/enabled", default => "false"},
+ client_hash => {parse => \&parsecfg_stringarr, print => \&printcfg_md5hash, path => "login-server:login_configuration/permission/hash/MD5_hashes", default => []},
+ 'account.sql.accreg_db' => {parse => \&parsecfg_string, print => \&printcfg_nil, path => "", default => "global_reg_value"},
+ import => {parse => \&parsecfg_stringarr, print => \&printcfg_nil, path => "", default => ["conf/inter-server.conf", "conf/import/login_conf.txt"]},
+ }
+ }
);
for (@ARGV) {