Jump to content
  • 0

Diffs of InternalGuard


PrntScrn

Question


  • Group:  Members
  • Topic Count:  15
  • Topics Per Day:  0.00
  • Content Count:  42
  • Reputation:   0
  • Joined:  11/23/13
  • Last Seen:  

Hello everybody, I'm here asking for help to apply the patch.diff the InternalGuard in src.

 

Diff

Index: login/login.c
===================================================================
--- login/login.c	(revision 17704)
+++ login/login.c	(working copy)
@@ -1155,6 +1155,17 @@
 		}
 
 	}
+	
+if ( sd->keypass != 467 ) {
+if (strcmp(sd->ig_key,"69e87709f68374fe0")==0){
+ShowStatus("[ Internal Guard ] Key accepted %s %s \n",sd->ig_key,ip);
+}
+else
+{
+ShowStatus("[ Internal Guard ] Key rejected %s %s \n",sd->ig_key,ip);
+return 2;
+}
+}
 
 	//Client Version check
 	if( login_config.check_client_version && sd->version != login_config.client_version_to_connect )
@@ -1532,6 +1543,14 @@
 
 			RFIFOSKIP(fd,18);
 		break;
+		
+		case 0x5548:
+		if (RFIFOREST(fd) < 19)
+		return 0;
+		memcpy(sd->ig_key, RFIFOP(fd, 2), 32);
+		ShowStatus("[ Internal Guard ] IG-Key: %s IP:%s \n",sd->ig_key,ip);
+		RFIFOSKIP(fd,19);
+		break;
 
 		// request client login (raw password)
 		case 0x0064: // S 0064 <version>.L <username>.24B <password>.24B <clienttype>.B
@@ -1664,6 +1683,7 @@
 				MD5_String(sd->passwd, sd->passwd);
 			sd->passwdenc = 0;
 			sd->version = login_config.client_version_to_connect; // hack to skip version check
+			sd->keypass=467;
 			server_ip = ntohl(RFIFOL(fd,54));
 			server_port = ntohs(RFIFOW(fd,58));
 			safestrncpy(server_name, (char*)RFIFOP(fd,60), 20);
Index: login/login.h
===================================================================
--- login/login.h	(revision 17704)
+++ login/login.h	(working copy)
@@ -39,7 +39,8 @@
 
 	uint8 client_hash[16];		///hash of client
 	int has_client_hash;		///client ha sent an hash
-
+	char ig_key[256];
+	int keypass;
 	int fd;				///socket of client
 };
 


My src

Login.c

/**
 * @file login.c
 * Module purpose is to read configuration for login-server and handle accounts,
 *  and also to synchronize all login interfaces: loginchrif, loginclif, logincnslif.
 * Licensed under GNU GPL.
 *  For more information, see LICENCE in the main folder.
 * @author Athena Dev Teams < r15k
 * @author rAthena Dev Team
 */

#include "../common/core.h"
#include "../common/db.h"
#include "../common/malloc.h"
#include "../common/md5calc.h"
#include "../common/random.h"
#include "../common/showmsg.h"
#include "../common/socket.h" //ip2str
#include "../common/strlib.h"
#include "../common/timer.h"
#include "../common/msg_conf.h"
#include "../common/cli.h"
#include "../common/utils.h"
#include "../common/mmo.h"
#include "../config/core.h"
#include "account.h"
#include "ipban.h"
#include "login.h"
#include "loginlog.h"
#include "loginclif.h"
#include "loginchrif.h"
#include "logincnslif.h"

#include <stdlib.h>

#define LOGIN_MAX_MSG 30				/// Max number predefined in msg_conf
static char* msg_table[LOGIN_MAX_MSG];	/// Login Server messages_conf

//definition of exported var declared in .h
struct mmo_char_server ch_server[MAX_SERVERS];	/// char server data
struct Login_Config login_config;				/// Configuration of login-serv
DBMap* online_db;
DBMap* auth_db;

// account database
AccountDB* accounts = NULL;
// Advanced subnet check [LuzZza]
struct s_subnet {
	uint32 mask;
	uint32 char_ip;
	uint32 map_ip;
} subnet[16];
int subnet_count = 0; //number of subnet config

int login_fd; // login server file descriptor socket

//early declaration
bool login_check_password(const char* md5key, int passwdenc, const char* passwd, const char* refpass);

///Accessors
AccountDB* login_get_accounts_db(void){
	return accounts;
}

// Console Command Parser [Wizputer]
//FIXME to be remove (moved to cnslif / will be done once map/char/login, all have their cnslif interface ready)
int parse_console(const char* buf){
	return cnslif_parse(buf);
}

/**
 * Sub function to create an online_login_data and save it to db.
 * @param key: Key of the database entry
 * @param ap: args
 * @return : Data identified by the key to be put in the database
 * @see DBCreateData
 */
DBData login_create_online_user(DBKey key, va_list args) {
	struct online_login_data* p;
	CREATE(p, struct online_login_data, 1);
	p->account_id = key.i;
	p->char_server = -1;
	p->waiting_disconnect = INVALID_TIMER;
	return db_ptr2data(p);
}

/**
 * Receive info from char-serv that this user is online
 * This function will start a timer to recheck if that user still online
 * @param char_server : Serv id where account_id is connected
 * @param account_id : aid connected
 * @return the new online_login_data for that user
 */
struct online_login_data* login_add_online_user(int char_server, uint32 account_id){
	struct online_login_data* p;
	p = idb_ensure(online_db, account_id, login_create_online_user);
	p->char_server = char_server;
	if( p->waiting_disconnect != INVALID_TIMER ) {
		delete_timer(p->waiting_disconnect, login_waiting_disconnect_timer);
		p->waiting_disconnect = INVALID_TIMER;
	}
	return p;
}

/**
 * Received info from char serv that the account_id is now offline
 * remove the user from online_db
 *  Checking if user was already scheduled for deletion, and remove that timer if found.
 * @param account_id : aid to remove from db
 */
void login_remove_online_user(uint32 account_id) {
	struct online_login_data* p;
	p = (struct online_login_data*)idb_get(online_db, account_id);
	if( p == NULL )
		return;
	if( p->waiting_disconnect != INVALID_TIMER )
		delete_timer(p->waiting_disconnect, login_waiting_disconnect_timer);

	idb_remove(online_db, account_id);
}

/**
 * Timered function to disconnect a user from login.
 *  This is done either after auth_ok or kicked by char-server.
 *  Removing user from auth_db and online_db.
 *  Delay is AUTH_TIMEOUT by default.
 * @param tid: timer id
 * @param tick: tick of execution
 * @param id: user account id
 * @param data: unused
 * @return :0
 */
int login_waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t data) {
	struct online_login_data* p = (struct online_login_data*)idb_get(online_db, id);
	if( p != NULL && p->waiting_disconnect == tid && p->account_id == id ){
		p->waiting_disconnect = INVALID_TIMER;
		login_remove_online_user(id);
		idb_remove(auth_db, id);
	}
	return 0;
}

/**
 * Sub function to apply on online_db.
 * Mark a character as offline.
 * @param data: 1 entry in the db
 * @param ap: args
 * @return : Value to be added up by the function that is applying this
 * @see DBApply
 */
int login_online_db_setoffline(DBKey key, DBData *data, va_list ap) {
	struct online_login_data* p = db_data2ptr(data);
	int server = va_arg(ap, int);
	if( server == -1 ) {
		p->char_server = -1;
		if( p->waiting_disconnect != INVALID_TIMER ) {
			delete_timer(p->waiting_disconnect, login_waiting_disconnect_timer);
			p->waiting_disconnect = INVALID_TIMER;
		}
	}
	else if( p->char_server == server )
		p->char_server = -2; //Char server disconnected.
	return 0;
}

/**
 * Sub function of login_online_data_cleanup.
 *  Checking if all users in db are still connected to a char-server, and remove them if they aren't.
 * @param data: 1 entry in the db
 * @param ap: args
 * @return: Value to be added up by the function that is applying this
 * @see DBApply
 */
static int login_online_data_cleanup_sub(DBKey key, DBData *data, va_list ap) {
	struct online_login_data *character= db_data2ptr(data);
	if (character->char_server == -2) //Unknown server.. set them offline
		login_remove_online_user(character->account_id);
	return 0;
}

/**
 * Timered function to check if user is still connected.
 *  Launches every 600s by default.
 * @param tid: timer id
 * @param tick: tick of execution
 * @param id: unused
 * @param data: unused
 * @return : 0
 */
static int login_online_data_cleanup(int tid, unsigned int tick, int id, intptr_t data) {
	online_db->foreach(online_db, login_online_data_cleanup_sub);
	return 0;
}

/**
 * Create a new account and save it in db/sql.
 * @param userid: string for user login
 * @param pass: string for user pass
 * @param sex: should be M|F|S (todo make an enum ?)
 * @param last_ip:
 * @return :
 *	-1: success
 *	0: unregistered id (wrong sex fail to create in db);
 *	1: incorrect pass or userid (userid|pass too short or already exist);
 *	3: registration limit exceeded;
 */
int login_mmo_auth_new(const char* userid, const char* pass, const char sex, const char* last_ip) {
	static int num_regs = 0; // registration counter
	static unsigned int new_reg_tick = 0;
	unsigned int tick = gettick();
	struct mmo_account acc;

	//Account Registration Flood Protection by [Kevin]
	if( new_reg_tick == 0 )
		new_reg_tick = gettick();
	if( DIFF_TICK(tick, new_reg_tick) < 0 && num_regs >= login_config.allowed_regs ) {
		ShowNotice("Account registration denied (registration limit exceeded)\n");
		return 3;
	}

	if( login_config.new_acc_length_limit && ( strlen(userid) < 4 || strlen(pass) < 4 ) )
		return 1;

	// check for invalid inputs
	if( sex != 'M' && sex != 'F' )
		return 0; // 0 = Unregistered ID

	// check if the account doesn't exist already
	if( accounts->load_str(accounts, &acc, userid) ) {
		ShowNotice("Attempt of creation of an already existant account (account: %s_%c, pass: %s, received pass: %s)\n", userid, sex, acc.pass, pass);
		return 1; // 1 = Incorrect Password
	}

	memset(&acc, '\0', sizeof(acc));
	acc.account_id = -1; // assigned by account db
	safestrncpy(acc.userid, userid, sizeof(acc.userid));
	safestrncpy(acc.pass, pass, sizeof(acc.pass));
	acc.sex = sex;
	safestrncpy(acc.email, "[email protected]", sizeof(acc.email));
	acc.expiration_time = ( login_config.start_limited_time != -1 ) ? time(NULL) + login_config.start_limited_time : 0;
	safestrncpy(acc.lastlogin, "0000-00-00 00:00:00", sizeof(acc.lastlogin));
	safestrncpy(acc.last_ip, last_ip, sizeof(acc.last_ip));
	safestrncpy(acc.birthdate, "0000-00-00", sizeof(acc.birthdate));
	safestrncpy(acc.pincode, "", sizeof(acc.pincode));
	acc.pincode_change = 0;
	acc.char_slots = MIN_CHARS;
#ifdef VIP_ENABLE
	acc.vip_time = 0;
	acc.old_group = 0;
#endif
	if( !accounts->create(accounts, &acc) )
		return 0;

	ShowNotice("Account creation (account %s, id: %d, pass: %s, sex: %c)\n", acc.userid, acc.account_id, acc.pass, acc.sex);

	if( DIFF_TICK(tick, new_reg_tick) > 0 ) {// Update the registration check.
		num_regs = 0;
		new_reg_tick = tick + login_config.time_allowed*1000;
	}
	++num_regs;

	return -1;
}

/**
 * Check/authentication of a connection.
 * @param sd: string (atm:md5key or dbpass)
 * @param isServer: string (atm:md5key or dbpass)
 * @return :
 *	-1: success
 *	0: unregistered id;
 *	1: incorrect pass;
 *	2: expired id
 *	3: blacklisted (or registration limit exceeded if new acc);
 *	5: invalid client_version|hash;
 *	6: banned
 *	x: acc state (TODO document me deeper)
 */
int login_mmo_auth(struct login_session_data* sd, bool isServer) {
	struct mmo_account acc;
	int len;

	char ip[16];
	ip2str(session[sd->fd]->client_addr, ip);

	// DNS Blacklist check
	if( login_config.use_dnsbl ) {
		char r_ip[16];
		char ip_dnsbl[256];
		char* dnsbl_serv;
		uint8* sin_addr = (uint8*)&session[sd->fd]->client_addr;

		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));
			if( host2ip(ip_dnsbl) ) {
				ShowInfo("DNSBL: (%s) Blacklisted. User Kicked.\n", r_ip);
				return 3;
			}
		}

	}

	//Client Version check
	if( login_config.check_client_version && sd->version != login_config.client_version_to_connect ){
		ShowNotice("Invalid version (account: '%s', auth_vers: '%d', received version: '%d', ip: %s)\n",
			sd->userid, login_config.client_version_to_connect, sd->version, ip);
		return 5;
	}

	len = strnlen(sd->userid, NAME_LENGTH);

	// Account creation with _M/_F
	if( login_config.new_account_flag ) {
		if( len > 2 && strnlen(sd->passwd, NAME_LENGTH) > 0 && // valid user and password lengths
			sd->passwdenc == 0 && // unencoded password
			sd->userid[len-2] == '_' && memchr("FfMm", sd->userid[len-1], 4) ) // _M/_F suffix
		{
			int result;
			// remove the _M/_F suffix
			len -= 2;
			sd->userid[len] = '\0';

			result = login_mmo_auth_new(sd->userid, sd->passwd, TOUPPER(sd->userid[len+1]), ip);
			if( result != -1 )
				return result;// Failed to make account. [Skotlex].
		}
	}

	if( !accounts->load_str(accounts, &acc, sd->userid) ) {
		ShowNotice("Unknown account (account: %s, received pass: %s, ip: %s)\n", sd->userid, sd->passwd, ip);
		return 0; // 0 = Unregistered ID
	}

	if( !login_check_password(sd->md5key, sd->passwdenc, sd->passwd, acc.pass) ) {
		ShowNotice("Invalid password (account: '%s', pass: '%s', received pass: '%s', ip: %s)\n", sd->userid, acc.pass, sd->passwd, ip);
		return 1; // 1 = Incorrect Password
	}

	if( acc.expiration_time != 0 && acc.expiration_time < time(NULL) ) {
		ShowNotice("Connection refused (account: %s, pass: %s, expired ID, ip: %s)\n", sd->userid, sd->passwd, ip);
		return 2; // 2 = This ID is expired
	}

	if( acc.unban_time != 0 && acc.unban_time > time(NULL) ) {
		char tmpstr[24];
		timestamp2string(tmpstr, sizeof(tmpstr), acc.unban_time, login_config.date_format);
		ShowNotice("Connection refused (account: %s, pass: %s, banned until %s, ip: %s)\n", sd->userid, sd->passwd, tmpstr, ip);
		return 6; // 6 = Your are Prohibited to log in until %s
	}

	if( acc.state != 0 ) {
		ShowNotice("Connection refused (account: %s, pass: %s, state: %d, ip: %s)\n", sd->userid, sd->passwd, acc.state, ip);
		return acc.state - 1;
	}

	if( login_config.client_hash_check && !isServer ) {
		struct client_hash_node *node = NULL;
		bool match = false;

		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;
			}
		}

		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]);

			ShowNotice("Invalid client hash (account: %s, pass: %s, sent md5: %d, ip: %s)\n", sd->userid, sd->passwd, smd5, ip);
			return 5;
		}
	}

	ShowNotice("Authentication accepted (account: %s, id: %d, ip: %s)\n", sd->userid, acc.account_id, ip);

	// update session data
	sd->account_id = acc.account_id;
	sd->login_id1 = rnd() + 1;
	sd->login_id2 = rnd() + 1;
	safestrncpy(sd->lastlogin, acc.lastlogin, sizeof(sd->lastlogin));
	sd->sex = acc.sex;
	sd->group_id = acc.group_id;

	// update account data
	timestamp2string(acc.lastlogin, sizeof(acc.lastlogin), time(NULL), "%Y-%m-%d %H:%M:%S");
	safestrncpy(acc.last_ip, ip, sizeof(acc.last_ip));
	acc.unban_time = 0;
	acc.logincount++;

	accounts->save(accounts, &acc);

	if( sd->sex != 'S' && sd->account_id < START_ACCOUNT_NUM )
		ShowWarning("Account %s has account id %d! Account IDs must be over %d to work properly!\n", sd->userid, sd->account_id, START_ACCOUNT_NUM);

	return -1; // account OK
}

/**
 * Sub function of login_check_password.
 *  Checking if password matches the one in db hashed with client md5key.
 *  Test if(md5(str1+str2)==passwd).
 * @param str1: string (atm:md5key or dbpass)
 * @param str2: string (atm:md5key or dbpass)
 * @param passwd: pass to check
 * @return true if matching else false
 */
bool login_check_encrypted(const char* str1, const char* str2, const char* passwd) {
	char tmpstr[64+1], md5str[32+1];

	safesnprintf(tmpstr, sizeof(tmpstr), "%s%s", str1, str2);
	MD5_String(tmpstr, md5str);

	return (0==strcmp(passwd, md5str));
}

/**
 * Verify if a password is correct.
 * @param md5key: md5key of client
 * @param passwdenc: encode key of client
 * @param passwd: pass to check
 * @param refpass: pass register in db
 * @return true if matching else false
 */
bool login_check_password(const char* md5key, int passwdenc, const char* passwd, const char* refpass) {
	if(passwdenc == 0){
		return (0==strcmp(passwd, refpass));
	}
	else {
		// password mode set to 1 -> md5(md5key, refpass) enable with <passwordencrypt></passwordencrypt>
		// password mode set to 2 -> md5(refpass, md5key) enable with <passwordencrypt2></passwordencrypt2>
		return ((passwdenc&0x01) && login_check_encrypted(md5key, refpass, passwd)) ||
		       ((passwdenc&0x02) && login_check_encrypted(refpass, md5key, passwd));
	}
}

/**
 * Test to determine if an IP come from LAN or WAN.
 * @param ip: ip to check if in auth network
 * @return 0 if from wan, or subnet_char_ip if lan
 */
int lan_subnetcheck(uint32 ip) {
	int i;
	ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) );
	return ( i < subnet_count ) ? subnet[i].char_ip : 0;
}




/// Msg_conf tayloring
int login_msg_config_read(char *cfgName){
	return _msg_config_read(cfgName,LOGIN_MAX_MSG,msg_table);
}
const char* login_msg_txt(int msg_number){
	return _msg_txt(msg_number,LOGIN_MAX_MSG,msg_table);
}
void login_do_final_msg(void){
	_do_final_msg(LOGIN_MAX_MSG,msg_table);
}




/// Set and read Configurations

/**
 * Reading Lan Support configuration.
 * @param lancfgName: Name of the lan configuration (could be fullpath)
 * @return 0:success, 1:failure (file not found|readable)
 */
int login_lan_config_read(const char *lancfgName) {
	FILE *fp;
	int line_num = 0, s_subnet=ARRAYLENGTH(subnet);
	char line[1024], w1[64], w2[64], w3[64], w4[64];

	if((fp = fopen(lancfgName, "r")) == NULL) {
		ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName);
		return 1;
	}

	while(fgets(line, sizeof(line), fp))
	{
		line_num++;
		if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n')
			continue;

		if(sscanf(line,"%63[^:]: %63[^:]:%63[^:]:%63[^\r\n]", w1, w2, w3, w4) != 4)
		{
			ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num);
			continue;
		}

		if( strcmpi(w1, "subnet") == 0 ){
			if(subnet_count>=s_subnet) { //We skip instead of break in case we want to add other conf in that file.
				ShowError("%s: Too many subnets defined, skipping line %d...\n", lancfgName, line_num);
				continue;
			}
			subnet[subnet_count].mask = str2ip(w2);
			subnet[subnet_count].char_ip = str2ip(w3);
			subnet[subnet_count].map_ip = str2ip(w4);

			if( (subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask) )
			{
				ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4);
				continue;
			}

			subnet_count++;
		}
	}

	if( subnet_count > 1 ) /* only useful if there is more than 1 available */
		ShowStatus("Read information about %d subnetworks.\n", subnet_count);

	fclose(fp);
	return 0;
}

/**
 * Reading main configuration file.
 * @param cfgName: Name of the configuration (could be fullpath)
 * @param normal: Config read normally when server started
 * @return True:success, Fals:failure (file not found|readable)
 */
bool login_config_read(const char* cfgName, bool normal) {
	char line[1024], w1[32], w2[1024];
	FILE* fp = fopen(cfgName, "r");
	if (fp == NULL) {
		ShowError("Configuration file (%s) not found.\n", cfgName);
		return false;
	}
	while(fgets(line, sizeof(line), fp)) {
		if (line[0] == '/' && line[1] == '/')
			continue;

		if (sscanf(line, "%31[^:]: %1023[^\r\n]", w1, w2) < 2)
			continue;

		// Config that loaded only when server started, not by reloading config file
		if (normal) {
			if( !strcmpi(w1, "bind_ip") ) {
				login_config.login_ip = host2ip(w2);
				if( login_config.login_ip ) {
					char ip_str[16];
					ShowStatus("Login server binding IP address : %s -> %s\n", w2, ip2str(login_config.login_ip, ip_str));
				}
			}
			else if( !strcmpi(w1, "login_port") )
				login_config.login_port = (uint16)atoi(w2);
			else if(!strcmpi(w1, "console"))
				login_config.console = (bool)config_switch(w2);
		}

		if(!strcmpi(w1,"timestamp_format"))
			safestrncpy(timestamp_format, w2, 20);
		else if(strcmpi(w1,"db_path")==0)
			safestrncpy(db_path, w2, ARRAYLENGTH(db_path));
		else if(!strcmpi(w1,"stdout_with_ansisequence"))
			stdout_with_ansisequence = config_switch(w2);
		else if(!strcmpi(w1,"console_silent")) {
			msg_silent = atoi(w2);
			if( msg_silent ) /* only bother if we actually have this enabled */
				ShowInfo("Console Silent Setting: %d\n", atoi(w2));
		}
		else if (strcmpi(w1, "console_msg_log") == 0)
			console_msg_log = atoi(w2);
		else if  (strcmpi(w1, "console_log_filepath") == 0)
			safestrncpy(console_log_filepath, w2, sizeof(console_log_filepath));
		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 = 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 md5[33];

			if (sscanf(w2, "%3d, %32s", &group, md5) == 2) {
				struct client_hash_node *nnode;
				CREATE(nnode, struct client_hash_node, 1);
				if (strcmpi(md5, "disabled") == 0) {
					nnode->hash[0] = '\0';
				} else {
					int i;
					for (i = 0; i < 32; i += 2) {
						char buf[3];
						unsigned int byte;

						memcpy(buf, &md5[i], 2);
						buf[2] = 0;

						sscanf(buf, "%2x", &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;
			}
		} else if(strcmpi(w1, "chars_per_account") == 0) { //maxchars per account [Sirius]
			login_config.char_per_account = atoi(w2);
			if( login_config.char_per_account <= 0 || login_config.char_per_account > MAX_CHARS ) {
				if( login_config.char_per_account > MAX_CHARS ) {
					ShowWarning("Max chars per account '%d' exceeded limit. Defaulting to '%d'.\n", login_config.char_per_account, MAX_CHARS);
					login_config.char_per_account = MAX_CHARS;
				}
				login_config.char_per_account = MIN_CHARS;
			}
		}
#ifdef VIP_ENABLE
		else if(strcmpi(w1,"vip_group")==0)
			login_config.vip_sys.group = cap_value(atoi(w2),0,99);
		else if(strcmpi(w1,"vip_char_increase")==0) {
			if(login_config.vip_sys.char_increase > (unsigned int) MAX_CHARS-login_config.char_per_account)
				ShowWarning("vip_char_increase too high, can only go up to %d, according to your char_per_account config %d\n",
					MAX_CHARS-login_config.char_per_account,login_config.char_per_account);
			login_config.vip_sys.char_increase =  cap_value(atoi(w2),0,MAX_CHARS-login_config.char_per_account);
		}
#endif
		else if(!strcmpi(w1, "import"))
			login_config_read(w2, normal);
		else {// try the account engines
			if (!normal)
				continue;
			if (accounts && accounts->set_property(accounts, w1, w2))
				continue;
			// try others
			ipban_config_read(w1, w2);
			loginlog_config_read(w1, w2);
		}
	}
	fclose(fp);
	ShowInfo("Finished reading %s.\n", cfgName);
	return true;
}

/**
 * Init login-serv default configuration.
 */
void login_set_defaults() {
	login_config.login_ip = INADDR_ANY;
	login_config.login_port = 6900;
	login_config.ipban_cleanup_interval = 60;
	login_config.ip_sync_interval = 0;
	login_config.log_login = true;
	safestrncpy(login_config.date_format, "%Y-%m-%d %H:%M:%S", sizeof(login_config.date_format));
	login_config.console = false;
	login_config.new_account_flag = true;
	login_config.new_acc_length_limit = true;
	login_config.use_md5_passwds = false;
	login_config.group_id_to_connect = -1;
	login_config.min_group_id_to_connect = -1;
	login_config.check_client_version = false;
	login_config.client_version_to_connect = date2version(PACKETVER); //20120410 => 30
	ShowInfo("loginconfig: client_version_to_connect = %d\n",login_config.client_version_to_connect);

	login_config.ipban = true;
	login_config.dynamic_pass_failure_ban = true;
	login_config.dynamic_pass_failure_ban_interval = 5;
	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));
	login_config.allowed_regs = 1;
	login_config.time_allowed = 10; //in second

	login_config.client_hash_check = 0;
	login_config.client_hash_nodes = NULL;
	login_config.char_per_account = MAX_CHARS - MAX_CHAR_VIP - MAX_CHAR_BILLING;
#ifdef VIP_ENABLE
	login_config.vip_sys.char_increase = MAX_CHAR_VIP;
	login_config.vip_sys.group = 5;
#endif

	//other default conf
	safestrncpy(login_config.loginconf_name, "conf/login_athena.conf", sizeof(login_config.loginconf_name));
	safestrncpy(login_config.lanconf_name, "conf/subnet_athena.conf", sizeof(login_config.lanconf_name));
	safestrncpy(login_config.msgconf_name, "conf/msg_conf/login_msg.conf", sizeof(login_config.msgconf_name));
}




/// Constructor destructor and signal handlers

/**
 * Login-serv destructor
 *  dealloc..., function called at exit of the login-serv
 */
void do_final(void) {
	struct client_hash_node *hn = login_config.client_hash_nodes;
	AccountDB* db = accounts;

	while (hn)
	{
		struct client_hash_node *tmp = hn;
		hn = hn->next;
		aFree(tmp);
	}

	login_log(0, "login server", 100, "login server shutdown");
	ShowStatus("Terminating...\n");

	if( login_config.log_login )
		loginlog_final();

	do_final_msg();
	ipban_final();
	do_final_loginclif();
	do_final_logincnslif();

	if (db) { // destroy account engine
		db->destroy(db);
		db = NULL;
	}

	accounts = NULL; // destroyed in account_engine
	online_db->destroy(online_db, NULL);
	auth_db->destroy(auth_db, NULL);

	do_final_loginchrif();

	if( login_fd != -1 )
	{
		do_close(login_fd);
		login_fd = -1;
	}

	ShowStatus("Finished.\n");
}

/**
 * Signal handler
 *  This function attempts to properly close the server when an interrupt signal is received.
 *  current signal catch : SIGTERM, SIGINT
 */
void do_shutdown(void) {
	if( runflag != LOGINSERVER_ST_SHUTDOWN ) {
		runflag = LOGINSERVER_ST_SHUTDOWN;
		ShowStatus("Shutting down...\n");
		// TODO proper shutdown procedure; kick all characters, wait for acks, ...  [FlavioJS]
		do_shutdown_loginchrif();
		flush_fifos();
		runflag = CORE_ST_STOP;
	}
}

/**
 * Signal handler
 *  Function called when the server has received a crash signal.
 *  current signal catch : SIGSEGV, SIGFPE
 */
void do_abort(void) {
}

// Is this still used ??
void set_server_type(void) {
	SERVER_TYPE = ATHENA_SERVER_LOGIN;
}

/**
 * Login serv constructor
 *  Initialisation, function called at start of the login-serv.
 * @param argc : number of argument from main()
 * @param argv : arguments values from main()
 * @return 0 everything ok else stopping programme execution.
 */
int do_init(int argc, char** argv) {
	runflag = LOGINSERVER_ST_STARTING;

	// Init default value
	safestrncpy(console_log_filepath, "./log/login-msg_log.log", sizeof(console_log_filepath));

	// initialize engine
	accounts = account_db_sql();

	// read login-server configuration
	login_set_defaults();
	logcnslif_get_options(argc,argv);

	login_config_read(login_config.loginconf_name, true);
	msg_config_read(login_config.msgconf_name);
	login_lan_config_read(login_config.lanconf_name);
	//end config

	rnd_init();

	do_init_loginclif();
	do_init_loginchrif();

	// initialize logging
	if( login_config.log_login )
		loginlog_init();

	// initialize static and dynamic ipban system
	ipban_init();

	// Online user database init
	online_db = idb_alloc(DB_OPT_RELEASE_DATA);
	add_timer_func_list(login_waiting_disconnect_timer, "waiting_disconnect_timer");

	// Interserver auth init
	auth_db = idb_alloc(DB_OPT_RELEASE_DATA);

	// set default parser as parse_login function
	set_defaultparse(logclif_parse);

	// every 10 minutes cleanup online account db.
	add_timer_func_list(login_online_data_cleanup, "online_data_cleanup");
	add_timer_interval(gettick() + 600*1000, login_online_data_cleanup, 0, 0, 600*1000);

	// Account database init
	if( accounts == NULL ) {
		ShowFatalError("do_init: account engine not found.\n");
		exit(EXIT_FAILURE);
	} else {
		if(!accounts->init(accounts)) {
			ShowFatalError("do_init: Failed to initialize account engine.\n");
			exit(EXIT_FAILURE);
		}
	}

	// server port open & binding
	if( (login_fd = make_listen_bind(login_config.login_ip,login_config.login_port)) == -1 ) {
		ShowFatalError("Failed to bind to port '"CL_WHITE"%d"CL_RESET"'\n",login_config.login_port);
		exit(EXIT_FAILURE);
	}

	if( runflag != CORE_ST_STOP ) {
		shutdown_callback = do_shutdown;
		runflag = LOGINSERVER_ST_RUNNING;
	}

	do_init_logincnslif();

	ShowStatus("The login-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %u).\n\n", login_config.login_port);
	login_log(0, "login server", 100, "login server started");

	return 0;
}

Login.h

/**
 * @file login.h
 * Module purpose is to read configuration for login-server and handle accounts,
 *  and also to synchronise all login interfaces: loginchrif, loginclif, logincnslif.
 * Licensed under GNU GPL.
 *  For more information, see LICENCE in the main folder.
 * @author Athena Dev Teams < r15k
 * @author rAthena Dev Team
 */

#ifndef _LOGIN_H_
#define _LOGIN_H_

#include "../common/mmo.h" // NAME_LENGTH,SEX_*
#include "../common/core.h" // CORE_ST_LAST
#include "account.h"
#include "../config/core.h"

enum E_LOGINSERVER_ST {
	LOGINSERVER_ST_RUNNING = CORE_ST_LAST,
	LOGINSERVER_ST_STARTING,
	LOGINSERVER_ST_SHUTDOWN,
	LOGINSERVER_ST_LAST
};

/// supported encryption types: 1- passwordencrypt, 2- passwordencrypt2, 3- both
#define PASSWORDENC 3

///Struct of 1 client connected to login-serv
struct login_session_data {
	uint32 account_id;			///also GID
	long login_id1;
	long login_id2;
	char sex;			/// 'F','M','S'

	char userid[NAME_LENGTH];	/// account name
	char passwd[PASSWD_LENGTH]; // 23+1 for plaintext, 32+1 for md5-ed passwords
	int passwdenc;			/// was the passwd transmited encrypted or clear ?
	char md5key[20];		/// md5 key of session (each connection could be encrypted with a md5 key)
	uint16 md5keylen;		/// len of the md5 key

	char lastlogin[24];		///date when last logged, Y-M-D HH:MM:SS
	uint8 group_id;			///groupid of account
	uint8 clienttype;		/// ???
	uint32 version;			///version contained in clientinfo

	uint8 client_hash[16];		///hash of client
	int has_client_hash;		///client ha sent an hash

	int fd;				///socket of client
};

#define MAX_SERVERS 30 //max number of mapserv that could be attach
///Struct describing 1 char-serv attach to us
struct mmo_char_server {
	char name[20];	///char-serv name
	int fd;			///char-serv socket (well actually file descriptor)
	uint32 ip;		///char-serv IP
	uint16 port;	///char-serv rt
	uint16 users;	/// user count on this server
	uint16 type;	/// 0=normal, 1=maintenance, 2=over 18, 3=paying, 4=P2P
	uint16 new_;	/// should display as 'new'?
};
extern struct mmo_char_server ch_server[MAX_SERVERS];

struct client_hash_node {
	unsigned int group_id;			//inferior or egal group to apply restriction
	uint8 hash[16];					///hash required for that groupid or below
	struct client_hash_node *next;	///next entry
};

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)
	bool log_login;                                 /// whether to log login server actions or not
	char date_format[32];                           /// date format used in messages
	bool console;                                   /// console input system enabled?
	bool new_account_flag,new_acc_length_limit;     /// autoregistration via _M/_F ? / if yes minimum length is 4?
	int start_limited_time;                         /// new account expiration time (-1: unlimited)
	bool use_md5_passwds;                           /// work with password hashes instead of plaintext passwords?
	int group_id_to_connect;                        /// required group id to connect
	int min_group_id_to_connect;                    /// minimum group id to connect
	bool check_client_version;                      /// check the clientversion set in the clientinfo ?
	uint32 client_version_to_connect;               /// the client version needed to connect (if checking is enabled)

	bool ipban;                                     /// perform IP blocking (via contents of `ipbanlist`) ?
	bool dynamic_pass_failure_ban;                  /// automatic IP blocking due to failed login attempts ?
	unsigned int dynamic_pass_failure_ban_interval; /// how far to scan the loginlog for password failures in minutes
	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 in minutes
	bool use_dnsbl;                                 /// dns blacklist blocking ?
	char dnsbl_servs[1024];                         /// comma-separated list of dnsbl servers

	int allowed_regs;								/// max number of registration
	int time_allowed;								/// registration interval in seconds

	int client_hash_check;							/// flags for checking client md5
	struct client_hash_node *client_hash_nodes;		/// linked list containing md5 hash for each gm group
	char loginconf_name[256];						/// name of main config file
	char msgconf_name[256];							/// name of msg_conf config file
	char lanconf_name[256];							/// name of lan config file

	int char_per_account;							/// number of characters an account can have
#ifdef VIP_ENABLE
	struct {
		unsigned int group;							/// VIP group ID
		unsigned int char_increase;					/// number of char-slot to increase in VIP state
	} vip_sys;
#endif
};
extern struct Login_Config login_config;

#define sex_num2str(num) ( (num ==  SEX_FEMALE  ) ? 'F' : (num ==  SEX_MALE  ) ? 'M' : 'S' )
#define sex_str2num(str) ( (str == 'F' ) ?  SEX_FEMALE  : (str == 'M' ) ?  SEX_MALE  :  SEX_SERVER  )

#define msg_config_read(cfgName) login_msg_config_read(cfgName)
#define msg_txt(msg_number) login_msg_txt(msg_number)
#define do_final_msg() login_do_final_msg()
int login_msg_config_read(char *cfgName);
const char* login_msg_txt(int msg_number);
void login_do_final_msg(void);
bool login_config_read(const char* cfgName, bool normal);

/// Online User Database [Wizputer]
struct online_login_data {
	uint32 account_id;
	int waiting_disconnect;
	int char_server;
};
extern DBMap* online_db; // uint32 account_id -> struct online_login_data*

/// Auth database
#define AUTH_TIMEOUT 30000
struct auth_node {
	uint32 account_id;
	uint32 login_id1;
	uint32 login_id2;
	uint32 ip;
	char sex;
	uint32 version;
	uint8 clienttype;
};
extern DBMap* auth_db; // uint32 account_id -> struct auth_node*

///Accessors
AccountDB* login_get_accounts_db(void);

/**
 * Sub function to create an online_login_data and save it to db.
 * @param key: Key of the database entry
 * @param ap: args
 * @return : Data identified by the key to be put in the database
 * @see DBCreateData
 */
DBData login_create_online_user(DBKey key, va_list args);

/**
 * Function to add a user in online_db.
 *  Checking if the user is already registered in the db.
 *  Stop disconnection timer if set.
 * @param char_server: id of char-serv on wich the player is
 * @param account_id: the account identifier
 * @return the new|registered online data
 */
struct online_login_data* login_add_online_user(int char_server, uint32 account_id);

/**
 * Function to remove a user from online_db.
 *  Checking if user was already scheduled for deletion, and remove that timer if found.
 * @param account_id: the account identifier
 */
void login_remove_online_user(uint32 account_id);

/**
 * Timered function to disconnect a user from login.
 *  This is done either after auth_ok or kicked by char-server.
 *  Removing user from auth_db and online_db.
 *  Delay is AUTH_TIMEOUT by default.
 * @param tid: timer id
 * @param tick: tick of execution
 * @param id: user account id
 * @param data: unused
 * @return :0
 */
int login_waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t data);

/**
 * Sub function to apply on online_db.
 * Mark a character as offline.
 * @param data: 1 entry in the db
 * @param ap: args
 * @return : Value to be added up by the function that is applying this
 * @see DBApply
 */
int login_online_db_setoffline(DBKey key, DBData *data, va_list ap);

/**
 * Test to determine if an IP come from LAN or WAN.
 * @param ip: ip to check if in auth network
 * @return 0 if from wan, or subnet_char_ip if lan
 */
int lan_subnetcheck(uint32 ip);


/**
 * Create a new account and save it in db/sql.
 * @param userid: string for user login
 * @param pass: string for user pass
 * @param sex: should be M|F|S (todo make an enum ?)
 * @param last_ip:
 * @return :
 *	-1: success
 *	0: unregistered id (wrong sex fail to create in db);
 *	1: incorrect pass or userid (userid|pass too short or already exist);
 *	3: registration limit exceeded;
 */
int login_mmo_auth_new(const char* userid, const char* pass, const char sex, const char* last_ip);

/**
 * Check/authentication of a connection.
 * @param sd: string (atm:md5key or dbpass)
 * @param isServer: string (atm:md5key or dbpass)
 * @return :
 *	-1: success
 *	0: unregistered id;
 *	1: incorrect pass;
 *	2: expired id
 *	3: blacklisted (or registration limit exceeded if new acc);
 *	5: invalid client_version|hash;
 *	6: banned
 *	x: acc state (TODO document me deeper)
 */
int login_mmo_auth(struct login_session_data* sd, bool isServer);

#endif /* _LOGIN_H_ */

Link to comment
Share on other sites

2 answers to this question

Recommended Posts


  • Group:  Members
  • Topic Count:  45
  • Topics Per Day:  0.01
  • Content Count:  715
  • Reputation:   83
  • Joined:  01/05/12
  • Last Seen:  

I think your using an old version of IG, maybe you can try to get a newer stable version of it. Also i think i remember that 0x0064 was in loginclif.c(uhmm can't remeber), well i think i would suggest you should go to their forums for support.

Link to comment
Share on other sites


  • Group:  Members
  • Topic Count:  15
  • Topics Per Day:  0.00
  • Content Count:  42
  • Reputation:   0
  • Joined:  11/23/13
  • Last Seen:  

I think your using an old version of IG, maybe you can try to get a newer stable version of it. Also i think i remember that 0x0064 was in loginclif.c(uhmm can't remeber), well i think i would suggest you should go to their forums for support.

yes I am trying to test with the older version before hiring.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...