Parcourir la source

* Tried and fixed md5 password encryption
- login_sql was doing stupid things like re-using one pre-generated key for all connections, and escaping binary md5 data (destroying it)
- added missing code to login_txt when creating new accounts, showing that storing passwords as md5 hashes never really worked for txt
- removed PASSWORDENC's conditional compilation effect, now just a flag
- greatly simplified md5 password checking code, credits to eapp
* login server will now bind only after finishing the init phase

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@10384 54d463be-8e91-2dee-dedb-b68131a5f0ec

ultramage il y a 18 ans
Parent
commit
833fd942a4

+ 8 - 0
Changelog-Trunk.txt

@@ -4,6 +4,14 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
 2007/04/29
+	* login server will now bind only after finishing the init phase
+	* Tried and fixed md5 password encryption [ultramage]
+	- login_sql was doing stupid things like re-using one pre-generated
+	  key for all connections, and escaping binary md5 data (destroying it)
+	- added missing code to login_txt when creating new accounts, showing
+	  that storing passwords as md5 hashes never really worked for txt
+	- removed PASSWORDENC's conditional compilation effect, now just a flag
+	- greatly simplified md5 password checking code, credits to eapp
 	* Internal changes to the script engine: [FlavioJS]
 	- modulus division detects division by 0.
 	  dividing by zero stops the script and gives an error

+ 2 - 1
conf-tmpl/login_athena.conf

@@ -163,7 +163,8 @@ check_client_version: no
 // What version we would allow to connect? (if the options above is enabled..)
 client_version_to_connect: 20
 
-// Passwords in Login DB are MD5 - <passwordencrypt> cannot b used on client with this on
+// 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)

+ 1 - 1
src/common/mmo.h

@@ -10,7 +10,7 @@
 
 // server protocol version
 #ifndef PACKETVER
-	#define PACKETVER			8
+	#define PACKETVER			7
 #endif
 
 #define FIFOSIZE_SERVERLINK	256*1024

+ 2 - 0
src/common/socket.h

@@ -5,7 +5,9 @@
 #define _SOCKET_H_
 
 #ifdef WIN32
+	#define WIN32_LEAN_AND_MEAN
 	#include <windows.h>
+	#include <winsock.h>
 	typedef long in_addr_t;
 #else
 	#include <sys/types.h>

+ 0 - 14
src/ladmin/ladmin.c

@@ -46,9 +46,7 @@ void Gettimeofday(struct timeval *timenow)
 #include "../common/version.h"
 #include "../common/mmo.h"
 
-#ifdef PASSWORDENC
 #include "../common/md5calc.h"
-#endif
 
 //-------------------------------INSTRUCTIONS------------------------------
 // Set the variables below:
@@ -63,11 +61,7 @@ void Gettimeofday(struct timeval *timenow)
 char loginserverip[16] = "127.0.0.1";        // IP of login-server
 int loginserverport = 6900;                  // Port of login-server
 char loginserveradminpassword[24] = "admin"; // Administration password
-#ifdef PASSWORDENC
-int passenc = 2;                             // Encoding type of the password
-#else
 int passenc = 0;                             // Encoding type of the password
-#endif
 char defaultlanguage = 'E';                  // Default language (F: Français/E: English)
                                              // (if it's not 'F', default is English)
 char ladmin_log_filename[1024] = "log/ladmin.log";
@@ -3274,7 +3268,6 @@ int parse_fromlogin(int fd) {
 			RFIFOSKIP(fd,3);
 			break;
 
-#ifdef PASSWORDENC
 		case 0x01dc:	// answer of a coding key request
 			if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
 				return 0;
@@ -3308,7 +3301,6 @@ int parse_fromlogin(int fd) {
 			bytes_to_read = 1;
 			RFIFOSKIP(fd,RFIFOW(fd,2));
 			break;
-#endif
 
 		case 0x7531:	// Displaying of the version of the login-server
 			if (RFIFOREST(fd) < 10)
@@ -4182,9 +4174,7 @@ int Connect_login_server(void) {
 		printf("Error: Failed to connect to Login Server\n");
 		exit(1);
 	}
-#ifdef PASSWORDENC
 	if (passenc == 0) {
-#endif
 		WFIFOHEAD(login_fd,28);
 		WFIFOW(login_fd,0) = 0x7918; // Request for administation login
 		WFIFOW(login_fd,2) = 0; // no encrypted
@@ -4198,7 +4188,6 @@ int Connect_login_server(void) {
 			printf("Sending of the password...\n");
 			ladmin_log("Sending of the password..." RETCODE);
 		}
-#ifdef PASSWORDENC
 	} else {
 		WFIFOHEAD(login_fd,2);
 		WFIFOW(login_fd,0) = 0x791a; // Sending request about the coding key
@@ -4212,7 +4201,6 @@ int Connect_login_server(void) {
 			ladmin_log("Request about the MD5 key..." RETCODE);
 		}
 	}
-#endif
 
 	return 0;
 }
@@ -4264,12 +4252,10 @@ int ladmin_config_read(const char *cfgName) {
 			} else if (strcmpi(w1, "admin_pass") == 0) {
 				strncpy(loginserveradminpassword, w2, sizeof(loginserveradminpassword));
 				loginserveradminpassword[sizeof(loginserveradminpassword)-1] = '\0';
-#ifdef PASSWORDENC
 			} else if (strcmpi(w1, "passenc") == 0) {
 				passenc = atoi(w2);
 				if (passenc < 0 || passenc > 2)
 					passenc = 0;
-#endif
 			} else if (strcmpi(w1, "defaultlanguage") == 0) {
 				if (w2[0] == 'F' || w2[0] == 'E')
 					defaultlanguage = w2[0];

+ 0 - 4
src/ladmin/ladmin.h

@@ -5,9 +5,5 @@
 #define _LADMIN_H_
 
 #define LADMIN_CONF_NAME	"conf/ladmin_athena.conf"
-#define PASSWORDENC		3	// A definition is given when making an encryption password correspond.
-							// It is 1 at the time of passwordencrypt.
-							// It is made into 2 at the time of passwordencrypt2.
-							// When it is made 3, it corresponds to both.
 
 #endif /* _LADMIN_H_ */

+ 174 - 193
src/login/login.c

@@ -1,26 +1,12 @@
 // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
 // For more information, see LICENCE in the main folder
 
-#include <sys/types.h>
-
-#ifdef __WIN32
-	#define WIN32_LEAN_AND_MEAN
-	#include <windows.h>
-	#include <winsock2.h>
-#else
-	#include <sys/socket.h>
-	#include <netinet/in.h>
-	#include <arpa/inet.h>
-	#include <netdb.h>
-#endif
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/stat.h> // for stat/lstat/fstat
 #include <signal.h>
 #include <fcntl.h>
 #include <string.h>
-#include <stdarg.h>
 
 #include "../common/cbasetypes.h"
 #include "../common/core.h"
@@ -115,14 +101,13 @@ struct login_session_data {
 };
 
 #define AUTH_FIFO_SIZE 256
-struct auth_fifo {
+struct _auth_fifo {
 	uint32 account_id;
 	uint32 login_id1, login_id2;
 	uint32 ip;
 	uint8 sex;
 	bool delflag;
-};
-struct auth_fifo auth_fifo[AUTH_FIFO_SIZE];
+} auth_fifo[AUTH_FIFO_SIZE];
 int auth_fifo_pos = 0;
 
 struct online_login_data {
@@ -131,10 +116,12 @@ struct online_login_data {
 	int char_server;
 };
 
-struct auth_dat {
+struct auth_data {
 	uint32 account_id;
 	uint8 sex; // 0, 1, 2
-	char userid[24], pass[32+1], lastlogin[24];
+	char userid[24];
+	char pass[32+1]; // 23+1 for normal, 32+1 for md5-ed passwords
+	char lastlogin[24];
 	int logincount;
 	uint32 state; // packet 0x006a value + 1 (0: compte OK)
 	char email[40]; // e-mail (by default: a@a.com)
@@ -145,8 +132,7 @@ struct auth_dat {
 	char memo[255]; // a memo field
 	int account_reg2_num;
 	struct global_reg account_reg2[ACCOUNT_REG2_NUM];
-};
-struct auth_dat* auth_dat = NULL;
+} *auth_dat = NULL;
 
 uint32 auth_num = 0, auth_max = 0;
 
@@ -536,7 +522,7 @@ int search_account_index(char* account_name) {
 //--------------------------------------------------------
 // Create a string to save the account in the account file
 //--------------------------------------------------------
-int mmo_auth_tostr(char *str, struct auth_dat *p) {
+int mmo_auth_tostr(char* str, struct auth_data* p) {
 	int i;
 	char *str_p = str;
 
@@ -572,7 +558,7 @@ int mmo_auth_init(void)
 	int server_count = 0;
 
 	auth_max = 256;
-	auth_dat = (struct auth_dat*)aCalloc(auth_max, sizeof(struct auth_dat));
+	auth_dat = (struct auth_data*)aCalloc(auth_max, sizeof(struct auth_data));
 
 	if ((fp = fopen(account_filename, "r")) == NULL) {
 		// no account file -> no account -> no login, including char-server (ERROR)
@@ -641,18 +627,18 @@ int mmo_auth_init(void)
 
 			if (auth_num >= auth_max) {
 				auth_max += 256;
-				auth_dat = (struct auth_dat*)aRealloc(auth_dat, sizeof(struct auth_dat) * auth_max);
+				auth_dat = (struct auth_data*)aRealloc(auth_dat, sizeof(struct auth_data) * auth_max);
 			}
 
-			memset(&auth_dat[auth_num], '\0', sizeof(struct auth_dat));
+			memset(&auth_dat[auth_num], '\0', sizeof(struct auth_data));
 
 			auth_dat[auth_num].account_id = account_id;
 
 			strncpy(auth_dat[auth_num].userid, userid, 24);
 
-			pass[23] = '\0';
+			pass[32] = '\0';
 			remove_control_chars(pass);
-			strncpy(auth_dat[auth_num].pass, pass, 24);
+			strncpy(auth_dat[auth_num].pass, pass, 32);
 
 			lastlogin[23] = '\0';
 			remove_control_chars(lastlogin);
@@ -763,10 +749,10 @@ int mmo_auth_init(void)
 
 			if (auth_num >= auth_max) {
 				auth_max += 256;
-				auth_dat = (struct auth_dat*)aRealloc(auth_dat, sizeof(struct auth_dat) * auth_max);
+				auth_dat = (struct auth_data*)aRealloc(auth_dat, sizeof(struct auth_data) * auth_max);
 			}
 
-			memset(&auth_dat[auth_num], '\0', sizeof(struct auth_dat));
+			memset(&auth_dat[auth_num], '\0', sizeof(struct auth_data));
 
 			auth_dat[auth_num].account_id = account_id;
 
@@ -883,7 +869,8 @@ int mmo_auth_init(void)
 // Writing of the accounts database file
 //   (accounts are sorted by id before save)
 //------------------------------------------
-void mmo_auth_sync(void) {
+void mmo_auth_sync(void)
+{
 	FILE *fp;
 	unsigned int i, j, k;
 	int lock;
@@ -1043,6 +1030,37 @@ int check_GM_file(int tid, unsigned int tick, int id, int data) {
 	return 0;
 }
 
+
+//-----------------------------------------------------
+// encrypted/unencrypted password check
+//-----------------------------------------------------
+bool check_encrypted(const char* str1, const char* str2, const char* passwd)
+{
+	char md5str[64], md5bin[32];
+	snprintf(md5str, sizeof(md5str), "%s%s", str1, str2); md5str[sizeof(md5str)-1] = '\0';
+	MD5_String2binary(md5str, md5bin);
+
+	return (0==memcmp(passwd, md5bin, 16));
+}
+
+bool check_password(struct login_session_data* ld, int passwdenc, const char* passwd, const char* refpass)
+{	
+	if(passwdenc == 0)
+	{
+		return (0==strcmp(passwd, refpass));
+	}
+	else if (ld)
+	{
+		// password mode set to 1 -> (md5key, refpass) enable with <passwordencrypt></passwordencrypt>
+		// password mode set to 2 -> (refpass, md5key) enable with <passwordencrypt2></passwordencrypt2>
+		
+		return ((passwdenc&0x01) && check_encrypted(ld->md5key, refpass, passwd)) ||
+		       ((passwdenc&0x02) && check_encrypted(refpass, ld->md5key, passwd));
+	}
+	return false;
+}
+
+
 //-------------------------------------
 // Account creation (with e-mail check)
 //-------------------------------------
@@ -1054,17 +1072,21 @@ int mmo_auth_new(struct mmo_account* account, char sex, char* email)
 
 	if (auth_num >= auth_max) {
 		auth_max += 256;
-		auth_dat = (struct auth_dat*)aRealloc(auth_dat, sizeof(struct auth_dat) * auth_max);
+		auth_dat = (struct auth_data*)aRealloc(auth_dat, sizeof(struct auth_data) * auth_max);
 	}
 
-	memset(&auth_dat[i], '\0', sizeof(struct auth_dat));
+	memset(&auth_dat[i], '\0', sizeof(struct auth_data));
 
 	while (isGM(account_id_count) > 0)
 		account_id_count++;
 
 	auth_dat[i].account_id = account_id_count++;
 	strncpy(auth_dat[i].userid, account->userid, NAME_LENGTH); auth_dat[i].userid[23] = '\0';
-	strncpy(auth_dat[i].pass, account->passwd, NAME_LENGTH); auth_dat[i].pass[23] = '\0';
+	if (use_md5_passwds) {
+		MD5_String(account->passwd, auth_dat[i].pass);
+	} else {
+		strncpy(auth_dat[i].pass, account->passwd, NAME_LENGTH); auth_dat[i].pass[23] = '\0';
+	}
 	memcpy(auth_dat[i].lastlogin, "-", 2);
 	auth_dat[i].sex = (sex == 'M' || sex == 'm');
 	auth_dat[i].logincount = 0;
@@ -1096,7 +1118,7 @@ int mmo_auth_new(struct mmo_account* account, char sex, char* email)
 }
 
 //---------------------------------------
-// Check/authentification of a connection
+// Check/authentication of a connection
 //---------------------------------------
 int mmo_auth(struct mmo_account* account, int fd)
 {
@@ -1105,11 +1127,6 @@ int mmo_auth(struct mmo_account* account, int fd)
 	char tmpstr[256];
 	int len;
 	int newaccount = 0;
-#ifdef PASSWORDENC
-	struct login_session_data *ld;
-#endif
-	int encpasswdok;
-	char md5str[64], md5bin[32];
 	char user_password[256];
 
 	char ip[16];
@@ -1163,7 +1180,7 @@ int mmo_auth(struct mmo_account* account, int fd)
 		}
 	}
 	
-	//EXE Version check [Sirius]
+	//Client Version check
 	if (check_client_version && account->version != 0 &&
 		account->version != client_version_to_connect)
 		return 5;
@@ -1188,56 +1205,16 @@ int mmo_auth(struct mmo_account* account, int fd)
 			          account->userid, account->userid[len+1], auth_dat[i].pass, account->passwd, ip);
 			return 1; // 1 = Incorrect Password
 		}
+
 		if(use_md5_passwds)
 			MD5_String(account->passwd, user_password);
 		else
 			memcpy(user_password, account->passwd, NAME_LENGTH);
-		encpasswdok = 0;
-#ifdef PASSWORDENC
-		ld = (struct login_session_data*)session[fd]->session_data;
-		if (account->passwdenc > 0) {
-			int j = account->passwdenc;
-			if (!ld) {
-				login_log("Md5 key not created (account: %s, ip: %s)" RETCODE, account->userid, ip);
-				return 1; // 1 = Incorrect Password
-			}
-			if (j > 2)
-				j = 1;
-			do {
-				if (j == 1) {
-					sprintf(md5str, "%s%s", ld->md5key, auth_dat[i].pass); // 20 + 24
-				} else if (j == 2) {
-					sprintf(md5str, "%s%s", auth_dat[i].pass, ld->md5key); // 24 + 20
-				} else
-					md5str[0] = '\0';
-				md5str[sizeof(md5str)-1] = '\0'; // 64
-				MD5_String2binary(md5str, md5bin);
-				encpasswdok = (memcmp(account->passwd, md5bin, 16) == 0);
-			} while (j < 2 && !encpasswdok && (j++) != account->passwdenc);
-//			printf("key[%s] md5 [%s] ", md5key, md5);
-//			printf("client [%s] accountpass [%s]\n", account->passwd, auth_dat[i].pass);
-		}
-#endif
-		if ((strcmp(account->passwd, auth_dat[i].pass) && !encpasswdok)) {
-			if (account->passwdenc == 0)
-				login_log("Invalid password (account: %s, pass: %s, received pass: %s, ip: %s)" RETCODE, account->userid, auth_dat[i].pass, account->passwd, ip);
-#ifdef PASSWORDENC
-			else {
-				char logbuf[512], *p = logbuf;
-				unsigned int j;
-				p += sprintf(p, "Invalid password (account: %s, received md5[", account->userid);
-				for(j = 0; j < 16; j++)
-					p += sprintf(p, "%02x", ((unsigned char *)account->passwd)[j]);
-				p += sprintf(p,"] calculated md5[");
-				for(j = 0; j < 16; j++)
-					p += sprintf(p, "%02x", ((unsigned char *)md5bin)[j]);
-				p += sprintf(p, "] md5 key[");
-				for(j = 0; j < ld->md5keylen; j++)
-					p += sprintf(p, "%02x", ((unsigned char *)ld->md5key)[j]);
-				p += sprintf(p, "], ip: %s)" RETCODE, ip);
-				login_log(logbuf);
-			}
-#endif
+
+		if (!check_password(session[fd]->session_data, account->passwdenc, user_password, auth_dat[i].pass))
+		{
+			login_log("Invalid password (account: %s, pass: %s, received pass: %s, ip: %s)" RETCODE,
+			          account->userid, auth_dat[i].pass, (account->passwdenc) ? "[MD5]" : account->passwd, ip);
 			return 1; // 1 = Incorrect Password
 		}
 
@@ -1388,27 +1365,31 @@ int parse_fromchar(int fd)
 	for(id = 0; id < MAX_SERVERS; id++)
 		if (server_fd[id] == fd)
 			break;
-
-	if (id == MAX_SERVERS)
+	if (id == MAX_SERVERS) { // not a char server
 		session[fd]->eof = 1;
+		do_close(fd);
+		return 0;
+	}
+
 	if(session[fd]->eof) {
-		if (id < MAX_SERVERS) {
-			ShowStatus("Char-server '%s' has disconnected.\n", server[id].name);
-			login_log("Char-server '%s' has disconnected (ip: %s)." RETCODE, server[id].name, ip);
-			server_fd[id] = -1;
-			memset(&server[id], 0, sizeof(struct mmo_char_server));
-			online_db->foreach(online_db,online_db_setoffline,id); //Set all chars from this char server to offline.
-		}
+		ShowStatus("Char-server '%s' has disconnected.\n", server[id].name);
+		login_log("Char-server '%s' has disconnected (ip: %s)." RETCODE, server[id].name, ip);
+		server_fd[id] = -1;
+		memset(&server[id], 0, sizeof(struct mmo_char_server));
+		online_db->foreach(online_db,online_db_setoffline,id); //Set all chars from this char server to offline.
 		do_close(fd);
 		return 0;
 	}
 
-	while (RFIFOREST(fd) >= 2) {
+	while (RFIFOREST(fd) >= 2)
+	{
+		uint16 command = RFIFOW(fd,0);
 
-		if (display_parse_fromchar == 2 || (display_parse_fromchar == 1 && RFIFOW(fd,0) != 0x2714)) // 0x2714 is done very often (number of players)
-			ShowDebug("parse_fromchar: connection #%d, packet: 0x%x (with being read: %d bytes).\n", fd, RFIFOW(fd,0), RFIFOREST(fd));
+		if (display_parse_fromchar == 2 || (display_parse_fromchar == 1 && command != 0x2714)) // 0x2714 is done very often (number of players)
+			ShowDebug("parse_fromchar: connection #%d, packet: 0x%x (with being read: %d bytes).\n", fd, command, RFIFOREST(fd));
 
-		switch (RFIFOW(fd,0)) {
+		switch (command)
+		{
 		
 		case 0x2709: // request from map-server via char-server to reload GM accounts
 			login_log("Char-server '%s': Request to re-load GM configuration file (ip: %s)." RETCODE, server[id].name, ip);
@@ -1426,10 +1407,10 @@ int parse_fromchar(int fd)
 			for(i = 0; i < AUTH_FIFO_SIZE; i++)
 			{
 				if (auth_fifo[i].account_id == RFIFOL(fd,2) &&
-				    auth_fifo[i].login_id1 == RFIFOL(fd,6) &&
-				    auth_fifo[i].login_id2 == RFIFOL(fd,10) && // relate to the versions higher than 18
-				    auth_fifo[i].sex == RFIFOB(fd,14) &&
-				    auth_fifo[i].ip == ntohl(RFIFOL(fd,15)) &&
+				    auth_fifo[i].login_id1  == RFIFOL(fd,6) &&
+				    auth_fifo[i].login_id2  == RFIFOL(fd,10) && // relate to the versions higher than 18
+				    auth_fifo[i].sex        == RFIFOB(fd,14) &&
+				    auth_fifo[i].ip         == ntohl(RFIFOL(fd,15)) &&
 				    !auth_fifo[i].delflag)
 				{
 					unsigned int k;
@@ -1595,12 +1576,8 @@ int parse_fromchar(int fd)
 		{
 			char actual_email[40], new_email[40];
 			uint32 acc = RFIFOL(fd,2);
-			memcpy(actual_email, RFIFOP(fd,6), 40);
-			actual_email[39] = '\0';
-			remove_control_chars(actual_email);
-			memcpy(new_email, RFIFOP(fd,46), 40);
-			new_email[39] = '\0';
-			remove_control_chars(new_email);
+			memcpy(actual_email, RFIFOP(fd,6), 40); actual_email[39] = '\0'; remove_control_chars(actual_email);
+			memcpy(new_email, RFIFOP(fd,46), 40); new_email[39] = '\0'; remove_control_chars(new_email);
 			if (e_mail_check(actual_email) == 0)
 				login_log("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual email is invalid (account: %d, ip: %s)" RETCODE,
 				          server[id].name, acc, ip);
@@ -1936,7 +1913,7 @@ int parse_fromchar(int fd)
 					time(&raw_time);
 					strftime(tmpstr, 23, date_format, localtime(&raw_time));
 					fprintf(logfp, "%s: receiving of an unknown packet -> disconnection" RETCODE, tmpstr);
-					fprintf(logfp, "parse_fromchar: connection #%d (ip: %s), packet: 0x%x (with being read: %lu)." RETCODE, fd, ip, RFIFOW(fd,0), (unsigned long)RFIFOREST(fd));
+					fprintf(logfp, "parse_fromchar: connection #%d (ip: %s), packet: 0x%x (with being read: %lu)." RETCODE, fd, ip, command, (unsigned long)RFIFOREST(fd));
 					fprintf(logfp, "Detail (in hex):" RETCODE);
 					fprintf(logfp, "---- 00-01-02-03-04-05-06-07  08-09-0A-0B-0C-0D-0E-0F" RETCODE);
 					memset(tmpstr, '\0', sizeof(tmpstr));
@@ -1967,7 +1944,7 @@ int parse_fromchar(int fd)
 					fclose(logfp);
 				}
 			}
-			ShowError("parse_fromchar: Unknown packet 0x%x from a char-server! Disconnecting!\n", RFIFOW(fd,0));
+			ShowError("parse_fromchar: Unknown packet 0x%x from a char-server! Disconnecting!\n", command);
 			session[fd]->eof = 1;
 			return 0;
 		}
@@ -1995,13 +1972,16 @@ int parse_admin(int fd)
 		return 0;
 	}
 
-	while(RFIFOREST(fd) >= 2) {
-          if (display_parse_admin == 1) {
+	while (RFIFOREST(fd) >= 2)
+	{
+		uint16 command = RFIFOW(fd,0);
 
-			ShowDebug("parse_admin: connection #%d, packet: 0x%x (with being read: %d).\n", fd, RFIFOW(fd,0), RFIFOREST(fd));
-          }
+        if (display_parse_admin)
+			ShowDebug("parse_admin: connection #%d, packet: 0x%x (with being read: %d).\n", fd, command, RFIFOREST(fd));
 
-		switch(RFIFOW(fd,0)) {
+		switch(command)
+		{
+		
 		case 0x7530:	// Request of the server version
 			login_log("'ladmin': Sending of the server version (ip: %s)" RETCODE, ip);
 			WFIFOHEAD(fd,10);
@@ -2902,7 +2882,7 @@ int parse_admin(int fd)
 					time(&raw_time);
 					strftime(tmpstr, 23, date_format, localtime(&raw_time));
 					fprintf(logfp, "%s: receiving of an unknown packet -> disconnection" RETCODE, tmpstr);
-					fprintf(logfp, "parse_admin: connection #%d (ip: %s), packet: 0x%x (with being read: %lu)." RETCODE, fd, ip, RFIFOW(fd,0), (unsigned long)RFIFOREST(fd));
+					fprintf(logfp, "parse_admin: connection #%d (ip: %s), packet: 0x%x (with being read: %lu)." RETCODE, fd, ip, command, (unsigned long)RFIFOREST(fd));
 					fprintf(logfp, "Detail (in hex):" RETCODE);
 					fprintf(logfp, "---- 00-01-02-03-04-05-06-07  08-09-0A-0B-0C-0D-0E-0F" RETCODE);
 					memset(tmpstr, '\0', sizeof(tmpstr));
@@ -2982,85 +2962,81 @@ int parse_login(int fd)
 		return 0;
 	}
 
-	while(RFIFOREST(fd) >= 2) {
-		if (display_parse_login == 1) {
-			if (RFIFOW(fd,0) == 0x64 || RFIFOW(fd,0) == 0x01dd) {
-				if ((int)RFIFOREST(fd) >= ((RFIFOW(fd,0) == 0x64) ? 55 : 47))
-					ShowDebug("parse_login: connection #%d, packet: 0x%x (with being read: %d), account: %s.\n", fd, RFIFOW(fd,0), RFIFOREST(fd), RFIFOP(fd,6));
-			} else if (RFIFOW(fd,0) == 0x2710) {
+	while (RFIFOREST(fd) >= 2)
+	{
+		uint16 command = RFIFOW(fd,0);
+
+		if (display_parse_login)
+		{
+			if (command == 0x0064 || command == 0x01dd)
+			{
+				if ((int)RFIFOREST(fd) >= ((command == 0x0064) ? 55 : 47))
+					ShowDebug("parse_login: connection #%d, packet: 0x%x (with being read: %d), account: %s.\n", fd, command, RFIFOREST(fd), RFIFOP(fd,6));
+			}
+			else if (command == 0x2710)
+			{
 				if (RFIFOREST(fd) >= 86)
-					ShowDebug("parse_login: connection #%d, packet: 0x%x (with being read: %d), server: %s.\n", fd, RFIFOW(fd,0), RFIFOREST(fd), RFIFOP(fd,60));
-			} else
-				ShowDebug("parse_login: connection #%d, packet: 0x%x (with being read: %d).\n", fd, RFIFOW(fd,0), RFIFOREST(fd));
+					ShowDebug("parse_login: connection #%d, packet: 0x%x (with being read: %d), server: %s.\n", fd, command, RFIFOREST(fd), RFIFOP(fd,60));
+			}
+			else
+				ShowDebug("parse_login: connection #%d, packet: 0x%x (with being read: %d).\n", fd, command, RFIFOREST(fd));
 		}
 
-		switch(RFIFOW(fd,0)) {
-		case 0x200:		// New alive packet: structure: 0x200 <account.userid>.24B. used to verify if client is always alive.
+		switch(command)
+		{
+		case 0x0200:		// New alive packet: structure: 0x200 <account.userid>.24B. used to verify if client is always alive.
 			if (RFIFOREST(fd) < 26)
 				return 0;
 			RFIFOSKIP(fd,26);
 			break;
 
-		case 0x204:		// New alive packet: structure: 0x204 <encrypted.account.userid>.16B. (new ragexe from 22 june 2004)
+		case 0x0204:		// New alive packet: structure: 0x204 <encrypted.account.userid>.16B. (new ragexe from 22 june 2004)
 			if (RFIFOREST(fd) < 18)
 				return 0;
 			RFIFOSKIP(fd,18);
 			break;
 
-		case 0x277:		// New login packet
-		case 0x64:		// request client login
-		case 0x01dd:	// request client login with encrypt
+		case 0x0064:		// request client login
+		case 0x0277:		// New login packet (layout is same as 0x64 but different length)
+		case 0x01dd:		// request client login (encryption mode)
 		{
 			int packet_len = RFIFOREST(fd);
 
 			//Perform ip-ban check
-			if (!check_ip(ipl)) {
+			if (!check_ip(ipl))
+			{
 				login_log("Connection refused: IP isn't authorised (deny/allow, ip: %s)." RETCODE, ip);
 				WFIFOHEAD(fd,23);
 				WFIFOW(fd,0) = 0x6a;
 				WFIFOB(fd,2) = 3; // 3 = Rejected from Server
 				WFIFOSET(fd,23);
 				RFIFOSKIP(fd,packet_len);
+				session[fd]->eof = 1;
 				break;
 			}
 
-			switch(RFIFOW(fd,0)){
-				case 0x64:
-					if(packet_len < 55)
-						return 0;
-					break;
-				case 0x01dd:
-					if(packet_len < 47)
-						return 0;
-					break;
-				case 0x277:
-					if(packet_len < 84)
-						return 0;
-					break;
-			}
+			if ((command == 0x0064 && packet_len < 55) ||
+				(command == 0x0277 && packet_len < 84) ||
+				(command == 0x01dd && packet_len < 47))
+				return 0;
+
+			// S 0064 <version>.l <account name>.24B <password>.24B <version2>.B
+			// S 0277 ??
+			// S 01dd <version>.l <account name>.24B <md5 binary>.16B <version2>.B
 			
-			account.version = RFIFOL(fd, 2);
+			account.version = RFIFOL(fd,2);
 			if (!account.version) account.version = 1; //Force some version...
-			memcpy(account.userid,RFIFOP(fd, 6),NAME_LENGTH);
-			account.userid[23] = '\0';
+			memcpy(account.userid,RFIFOP(fd,6),NAME_LENGTH); account.userid[23] = '\0';
 			remove_control_chars(account.userid);
-			if (RFIFOW(fd,0) != 0x01dd) {
+			if (command != 0x01dd) {
 				login_log("Request for connection (non encryption mode) of %s (ip: %s)." RETCODE, account.userid, ip);
-				memcpy(account.passwd, RFIFOP(fd,30), NAME_LENGTH);
-				account.passwd[23] = '\0';
+				memcpy(account.passwd, RFIFOP(fd,30), NAME_LENGTH); account.passwd[23] = '\0';
 				remove_control_chars(account.passwd);
 			} else {
 				login_log("Request for connection (encryption mode) of %s (ip: %s)." RETCODE, account.userid, ip);
-				 // If remove control characters from received password encrypted by md5,
-				// there would be a wrong result and failed to authentication. [End_of_exam]
-				memcpy(account.passwd, RFIFOP(fd,30), 16);
-				account.passwd[16] = '\0';
+				memcpy(account.passwd, RFIFOP(fd,30), 16); account.passwd[16] = '\0'; // binary data here
 			}
-#ifdef PASSWORDENC
-			account.passwdenc = (RFIFOW(fd,0) != 0x01dd) ? 0 : PASSWORDENC;
-#else
-			account.passwdenc = 0;
-#endif
+			account.passwdenc = (command != 0x01dd) ? 0 : PASSWORDENC;
 
 			result = mmo_auth(&account, fd);
 			if (result == -1) { // auth success
@@ -3142,33 +3118,35 @@ int parse_login(int fd)
 
 		case 0x01db:	// Sending request of the coding key
 		case 0x791a:	// Sending request of the coding key (administration packet)
-			{
-				struct login_session_data *ld;
-				if (session[fd]->session_data) {
-					ShowWarning("login: abnormal request of MD5 key (already opened session).\n");
-					session[fd]->eof = 1;
-					return 0;
-				}
-				ld = (struct login_session_data*)aCalloc(1, sizeof(struct login_session_data));
-				session[fd]->session_data = ld;
-				if (RFIFOW(fd,0) == 0x01db)
-					login_log("Sending request of the coding key (ip: %s)" RETCODE, ip);
-				else
-					login_log("'ladmin': Sending request of the coding key (ip: %s)" RETCODE, ip);
-				// Creation of the coding key
-				memset(ld->md5key, '\0', sizeof(ld->md5key));
-				ld->md5keylen = (uint16)(12 + rand() % 4);
-				for(i = 0; i < ld->md5keylen; i++)
-					ld->md5key[i] = (char)(1 + rand() % 255);
-
-				RFIFOSKIP(fd,2);
-				WFIFOHEAD(fd,4 + ld->md5keylen);
-				WFIFOW(fd,0) = 0x01dc;
-				WFIFOW(fd,2) = 4 + ld->md5keylen;
-				memcpy(WFIFOP(fd,4), ld->md5key, ld->md5keylen);
-				WFIFOSET(fd,WFIFOW(fd,2));
+		{
+			struct login_session_data* ld;
+			if (session[fd]->session_data) {
+				ShowWarning("login: abnormal request of MD5 key (already opened session).\n");
+				session[fd]->eof = 1;
+				return 0;
 			}
-			break;
+
+			ld = (struct login_session_data*)aCalloc(1, sizeof(struct login_session_data));
+			session[fd]->session_data = ld;
+			if (command == 0x01db)
+				login_log("Sending request of the coding key (ip: %s)" RETCODE, ip);
+			else
+				login_log("'ladmin': Sending request of the coding key (ip: %s)" RETCODE, ip);
+			
+			// Creation of the coding key
+			memset(ld->md5key, '\0', sizeof(ld->md5key));
+			ld->md5keylen = (uint16)(12 + rand() % 4);
+			for(i = 0; i < ld->md5keylen; i++)
+				ld->md5key[i] = (char)(1 + rand() % 255);
+			
+			RFIFOSKIP(fd,2);
+			WFIFOHEAD(fd,4 + ld->md5keylen);
+			WFIFOW(fd,0) = 0x01dc;
+			WFIFOW(fd,2) = 4 + ld->md5keylen;
+			memcpy(WFIFOP(fd,4), ld->md5key, ld->md5keylen);
+			WFIFOSET(fd,WFIFOW(fd,2));
+		}
+		break;
 
 		case 0x2710:	// Connection request of a char-server
 			if (RFIFOREST(fd) < 86)
@@ -3180,7 +3158,7 @@ int parse_login(int fd)
 				uint16 server_port;
 
  				WFIFOHEAD(fd,3);
-				memcpy(account.userid,RFIFOP(fd,2),NAME_LENGTH); account.userid[23] = '\0'; remove_control_chars(account.userid);
+				memcpy(account.userid, RFIFOP(fd,2), NAME_LENGTH); account.userid[23] = '\0'; remove_control_chars(account.userid);
 				memcpy(account.passwd, RFIFOP(fd,26), NAME_LENGTH); account.passwd[23] = '\0'; remove_control_chars(account.passwd);
 				account.passwdenc = 0;
 				server_name = (char*)RFIFOP(fd,60); server_name[20] = '\0'; remove_control_chars(server_name);
@@ -3329,7 +3307,7 @@ int parse_login(int fd)
 					time(&raw_time);
 					strftime(tmpstr, 23, date_format, localtime(&raw_time));
 					fprintf(logfp, "%s: receiving of an unknown packet -> disconnection" RETCODE, tmpstr);
-					fprintf(logfp, "parse_login: connection #%d (ip: %s), packet: 0x%x (with being read: %lu)." RETCODE, fd, ip, RFIFOW(fd,0), (unsigned long)RFIFOREST(fd));
+					fprintf(logfp, "parse_login: connection #%d (ip: %s), packet: 0x%x (with being read: %lu)." RETCODE, fd, ip, command, (unsigned long)RFIFOREST(fd));
 					fprintf(logfp, "Detail (in hex):" RETCODE);
 					fprintf(logfp, "---- 00-01-02-03-04-05-06-07  08-09-0A-0B-0C-0D-0E-0F" RETCODE);
 					memset(tmpstr, '\0', sizeof(tmpstr));
@@ -3360,7 +3338,7 @@ int parse_login(int fd)
 					fclose(logfp);
 				}
 			}
-			login_log("Abnormal end of connection (ip: %s): Unknown packet 0x%x " RETCODE, ip, RFIFOW(fd,0));
+			login_log("Abnormal end of connection (ip: %s): Unknown packet 0x%x " RETCODE, ip, command);
 			session[fd]->eof = 1;
 			return 0;
 		}
@@ -3985,18 +3963,18 @@ int do_init(int argc, char **argv)
 
 	for(i = 0; i< AUTH_FIFO_SIZE; i++)
 		auth_fifo[i].delflag = 1;
+
 	for(i = 0; i < MAX_SERVERS; i++)
 		server_fd[i] = -1;
 
 	mmo_auth_init();
 	read_gm_account();
 	set_defaultparse(parse_login);
+
 	// Online user database init
 	online_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));	// reinitialise
 	add_timer_func_list(waiting_disconnect_timer, "waiting_disconnect_timer");
 
-	login_fd = make_listen_bind(login_ip, login_port);
-
 	add_timer_func_list(check_auth_sync, "check_auth_sync");
 	add_timer_interval(gettick() + 60000, check_auth_sync, 0, 0, 60000); // every 60 sec we check if we must save accounts file (only if necessary to save)
 
@@ -4024,6 +4002,9 @@ int do_init(int argc, char **argv)
 
 	new_reg_tick = gettick();
 
+	// server port open & binding
+	login_fd = make_listen_bind(login_ip, login_port);
+
 	login_log("The login-server is ready (Server is listening on the port %d)." RETCODE, login_port);
 	ShowStatus("The login-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", login_port);
 

+ 3 - 4
src/login/login.h

@@ -6,10 +6,9 @@
 
 #define LOGIN_CONF_NAME "conf/login_athena.conf"
 #define LAN_CONF_NAME "conf/subnet_athena.conf"
-#define PASSWORDENC 3	// A definition is given when making an encryption password correspond.
-                     	// It is 1 at the time of passwordencrypt.
-                     	// It is made into 2 at the time of passwordencrypt2.
-                     	// When it is made 3, it corresponds to both.
+
+// supported encryption types: 1- passwordencrypt, 2- passwordencrypt2, 3- both
+#define PASSWORDENC 3
 
 extern uint16 login_port;
 

+ 126 - 145
src/login_sql/login.c

@@ -1,19 +1,6 @@
 // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
 // For more information, see LICENCE in the main folder
 
-#include <sys/types.h>
-
-#ifdef __WIN32
-	#define WIN32_LEAN_AND_MEAN
-	#include <windows.h>
-	#include <winsock2.h>
-#else
-	#include <sys/socket.h>
-	#include <netinet/in.h>
-	#include <arpa/inet.h>
-	#include <netdb.h>
-#endif
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/stat.h> // for stat/lstat/fstat
@@ -21,9 +8,6 @@
 #include <fcntl.h>
 #include <string.h>
 
-//add include for DBMS(mysql)
-#include <mysql.h>
-
 #include "../common/cbasetypes.h"
 #include "../common/core.h"
 #include "../common/socket.h"
@@ -37,6 +21,8 @@
 #include "../common/md5calc.h"
 #include "login.h"
 
+//add include for DBMS(mysql)
+#include <mysql.h>
 
 struct Login_Config {
 
@@ -115,6 +101,11 @@ char login_db_level[256] = "level";
 
 //-----------------------------------------------------
 
+struct login_session_data {
+	uint16 md5keylen;
+	char md5key[20];
+};
+
 #define AUTH_FIFO_SIZE 256
 struct {
 	int account_id, login_id1, login_id2;
@@ -133,8 +124,6 @@ struct online_login_data {
 
 //-----------------------------------------------------
 
-static char md5key[20], md5keylen = 16;
-
 struct dbt *online_db;
 
 static void* create_online_user(DBKey key, va_list args)
@@ -416,10 +405,10 @@ int mmo_auth_new(struct mmo_account* account, char sex)
 	mysql_real_escape_string(&mysql_handle, account->userid, account->userid, strlen(account->userid));
 	mysql_real_escape_string(&mysql_handle, account->passwd, account->passwd, strlen(account->passwd));
 
-	if (sex == 'f') sex = 'F';
-	else if (sex == 'm') sex = 'M';
+	sex = TOUPPER(sex);
+
 	if (login_config.use_md5_passwds)
-		MD5_String(account->passwd,user_password);
+		MD5_String(account->passwd, user_password);
 	else
 		jstrescapecpy(user_password, account->passwd);
 
@@ -484,8 +473,39 @@ int charif_sendallwos(int sfd, unsigned char *buf, unsigned int len)
 	return c;
 }
 
+
 //-----------------------------------------------------
-// Auth
+// encrypted/unencrypted password check
+//-----------------------------------------------------
+bool check_encrypted(const char* str1, const char* str2, const char* passwd)
+{
+	char md5str[64], md5bin[32];
+	snprintf(md5str, sizeof(md5str), "%s%s", str1, str2); md5str[sizeof(md5str)-1] = '\0';
+	MD5_String2binary(md5str, md5bin);
+
+	return (0==memcmp(passwd, md5bin, 16));
+}
+
+bool check_password(struct login_session_data* ld, int passwdenc, const char* passwd, const char* refpass)
+{	
+	if(passwdenc == 0)
+	{
+		return (0==strcmp(passwd, refpass));
+	}
+	else if (ld)
+	{
+		// password mode set to 1 -> (md5key, refpass) enable with <passwordencrypt></passwordencrypt>
+		// password mode set to 2 -> (refpass, md5key) enable with <passwordencrypt2></passwordencrypt2>
+		
+		return ((passwdenc&0x01) && check_encrypted(ld->md5key, refpass, passwd)) ||
+		       ((passwdenc&0x02) && check_encrypted(refpass, ld->md5key, passwd));
+	}
+	return false;
+}
+
+
+//-----------------------------------------------------
+// Check/authentication of a connection
 //-----------------------------------------------------
 int mmo_auth(struct mmo_account* account, int fd)
 {
@@ -495,8 +515,6 @@ int mmo_auth(struct mmo_account* account, int fd)
 	long connect_until;
 	int encpasswdok = 0, state;
 
-	char md5str[64], md5bin[32];
-
 	char ip[16];
 	uint32 ipl = session[fd]->client_addr;
 	uint8* sin_addr = (uint8*)&ipl;
@@ -594,49 +612,15 @@ int mmo_auth(struct mmo_account* account, int fd)
 	}
 
 	if (login_config.use_md5_passwds)
-		MD5_String(account->passwd,user_password);
+		MD5_String(account->passwd, user_password);
 	else
-		jstrescapecpy(user_password, account->passwd);
+		memcpy(user_password, account->passwd, NAME_LENGTH);
 
-#ifdef PASSWORDENC
-	if (account->passwdenc > 0) {
-		int j = account->passwdenc;
-
-		if (j > 2)
-			j = 1;
-		do {
-			if (j == 1) {
-				sprintf(md5str, "%s%s", md5key, password);
-			} else if (j == 2) {
-				sprintf(md5str, "%s%s", password, md5key);
-			} else
-				md5str[0] = 0;
-			MD5_String2binary(md5str, md5bin);
-			encpasswdok = (memcmp(user_password, md5bin, 16) == 0);
-		} while (j < 2 && !encpasswdok && (j++) != account->passwdenc);
-	}
-#endif
-	if ((strcmp(user_password, password) && !encpasswdok)) {
-		if (account->passwdenc == 0) {
-			ShowInfo("auth failed pass error %s %s" RETCODE, account->userid, user_password);
-#ifdef PASSWORDENC
-		} else {
-			char logbuf[1024], *p = logbuf;
-			int j;
-			p += sprintf(p, "auth failed pass error %s recv-md5[", account->userid);
-			for(j = 0; j < 16; j++)
-				p += sprintf(p, "%02x", ((unsigned char *)user_password)[j]);
-			p += sprintf(p, "] calc-md5[");
-			for(j = 0; j < 16; j++)
-				p += sprintf(p, "%02x", ((unsigned char *)md5bin)[j]);
-			p += sprintf(p, "] md5key[");
-			for(j = 0; j < md5keylen; j++)
-				p += sprintf(p, "%02x", ((unsigned char *)md5key)[j]);
-			p += sprintf(p, "]" RETCODE);
-			ShowInfo("%s\n", p);
-#endif
-		}
-		return 1;
+	if (!check_password(session[fd]->session_data, account->passwdenc, user_password, password))
+	{
+		ShowInfo("Invalid password (account: %s, pass: %s, received pass: %s, ip: %s)" RETCODE,
+		         account->userid, password, (account->passwdenc) ? "[MD5]" : account->passwd, ip);
+		return 1; // 1 = Incorrect Password
 	}
 
 	if (ban_until_time != 0) { // if account is banned
@@ -747,30 +731,32 @@ int parse_fromchar(int fd)
 	for(id = 0; id < MAX_SERVERS; id++)
 		if (server_fd[id] == fd)
 			break;
-
-	if (id == MAX_SERVERS)
+	if (id == MAX_SERVERS) { // not a char server
 		session[fd]->eof = 1;
+		do_close(fd);
+		return 0;
+	}
+
 	if(session[fd]->eof) {
-		if (id < MAX_SERVERS) {
-			ShowStatus("Char-server '%s' has disconnected.\n", server[id].name);
-			server_fd[id] = -1;
-			memset(&server[id], 0, sizeof(struct mmo_char_server));
-			online_db->foreach(online_db,online_db_setoffline,id); //Set all chars from this char server to offline.
-			// server delete
-			sprintf(tmpsql, "DELETE FROM `sstatus` WHERE `index`='%d'", id);
-			// query
-			if (mysql_query(&mysql_handle, tmpsql)) {
-				ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
-				ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
-			}
+		ShowStatus("Char-server '%s' has disconnected.\n", server[id].name);
+		server_fd[id] = -1;
+		memset(&server[id], 0, sizeof(struct mmo_char_server));
+		online_db->foreach(online_db,online_db_setoffline,id); //Set all chars from this char server to offline.
+		sprintf(tmpsql, "DELETE FROM `sstatus` WHERE `index`='%d'", id);
+		if (mysql_query(&mysql_handle, tmpsql)) {
+			ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+			ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
 		}
 		do_close(fd);
 		return 0;
 	}
 
-	while (RFIFOREST(fd) >= 2) {
+	while (RFIFOREST(fd) >= 2)
+	{
+		uint16 command = RFIFOW(fd,0);
 
-		switch (RFIFOW(fd,0)) {
+		switch (command)
+		{
 
 		case 0x2709: // request from map-server via char-server to reload GM accounts
 			if (login_config.log_login)
@@ -795,11 +781,11 @@ int parse_fromchar(int fd)
 			WFIFOHEAD(fd,51);
 			account_id = RFIFOL(fd,2); // speed up
 			for(i = 0; i < AUTH_FIFO_SIZE; i++) {
-				if(auth_fifo[i].account_id == account_id &&
-					auth_fifo[i].login_id1 == RFIFOL(fd,6) &&
-					auth_fifo[i].login_id2 == RFIFOL(fd,10) && // relate to the versions higher than 18
-					auth_fifo[i].sex == RFIFOB(fd,14) &&
-					auth_fifo[i].ip == ntohl(RFIFOL(fd,15)) &&
+				if( auth_fifo[i].account_id == account_id &&
+					auth_fifo[i].login_id1  == RFIFOL(fd,6) &&
+					auth_fifo[i].login_id2  == RFIFOL(fd,10) && // relate to the versions higher than 18
+					auth_fifo[i].sex        == RFIFOB(fd,14) &&
+					auth_fifo[i].ip         == ntohl(RFIFOL(fd,15)) &&
 					!auth_fifo[i].delflag)
 				{
 					auth_fifo[i].delflag = 1;
@@ -1319,7 +1305,6 @@ int parse_login(int fd)
 {
 	char t_uid[100];
 	struct mmo_account account;
-
 	int result, i;
 	uint32 ipl = session[fd]->client_addr;
 	char ip[16];
@@ -1330,31 +1315,31 @@ int parse_login(int fd)
 	memset(&account, 0, sizeof(account));
 
 	if (session[fd]->eof) {
-		for(i = 0; i < MAX_SERVERS; i++)
-			if (server_fd[i] == fd)
-				server_fd[i] = -1;
 		do_close(fd);
 		return 0;
 	}
 
-	while(RFIFOREST(fd) >= 2) {
+	while (RFIFOREST(fd) >= 2)
+	{
+		uint16 command = RFIFOW(fd,0);
 
-		switch(RFIFOW(fd,0)) {
-		case 0x200:		// New alive packet: structure: 0x200 <account.userid>.24B. used to verify if client is always alive.
+		switch(command)
+		{
+		case 0x0200:		// New alive packet: structure: 0x200 <account.userid>.24B. used to verify if client is always alive.
 			if (RFIFOREST(fd) < 26)
 				return 0;
 			RFIFOSKIP(fd,26);
 			break;
 
-		case 0x204:		// New alive packet: structure: 0x204 <encrypted.account.userid>.16B. (new ragexe from 22 june 2004)
+		case 0x0204:		// New alive packet: structure: 0x204 <encrypted.account.userid>.16B. (new ragexe from 22 june 2004)
 			if (RFIFOREST(fd) < 18)
 				return 0;
 			RFIFOSKIP(fd,18);
 			break;
 
-		case 0x277:		// New login packet
-		case 0x64:		// request client login
-		case 0x01dd:	// request client login with encrypt
+		case 0x0064:		// request client login
+		case 0x0277:		// New login packet (layout is same as 0x64 but different length)
+		case 0x01dd:		// request client login (encryption mode)
 		{
 			int packet_len = RFIFOREST(fd);
 
@@ -1370,37 +1355,24 @@ int parse_login(int fd)
 				break;
 			}
 
-			switch(RFIFOW(fd,0)){
-				case 0x64:
-					if(packet_len < 55)
-						return 0;
-					break;
-				case 0x01dd:
-					if(packet_len < 47)
-						return 0;
-					break;
-				case 0x277:
-					if(packet_len < 84)
-						return 0;
-					break;
-			}
+			if ((command == 0x0064 && packet_len < 55) ||
+				(command == 0x0277 && packet_len < 84) ||
+				(command == 0x01dd && packet_len < 47))
+				return 0;
+
+			// S 0064 <version>.l <account name>.24B <password>.24B <version2>.B
+			// S 0277 ??
+			// S 01dd <version>.l <account name>.24B <md5 binary>.16B <version2>.B
 
-			account.version = RFIFOL(fd, 2);
+			account.version = RFIFOL(fd,2);
 			if (!account.version) account.version = 1; //Force some version...
-			memcpy(account.userid,RFIFOP(fd, 6),NAME_LENGTH);
-			account.userid[23] = '\0';
-			memcpy(account.passwd,RFIFOP(fd, 30),NAME_LENGTH);
-			account.passwd[23] = '\0';
-
-#ifdef PASSWORDENC
-			account.passwdenc = (RFIFOW(fd,0)!=0x01dd)?0:PASSWORDENC;
-#else
-			account.passwdenc = 0;
-#endif
-			result = mmo_auth(&account, fd);
+			memcpy(account.userid,RFIFOP(fd,6),NAME_LENGTH); account.userid[23] = '\0';
+			memcpy(account.passwd,RFIFOP(fd,30),NAME_LENGTH); account.passwd[23] = '\0';
+			account.passwdenc = (command != 0x01dd) ? 0 : PASSWORDENC;
+			jstrescapecpy(t_uid, account.userid);
 
-			jstrescapecpy(t_uid,account.userid);
-			if(result == -1) { // auth success
+			result = mmo_auth(&account, fd);
+			if (result == -1) { // auth success
 				if (login_config.min_level_to_connect > account.level) {
 					WFIFOHEAD(fd,3);
 					WFIFOW(fd,0) = 0x81;
@@ -1546,7 +1518,7 @@ int parse_login(int fd)
 				//cannot connect login failed
 				memset(WFIFOP(fd,0), '\0', 23);
 				WFIFOW(fd,0) = 0x6a;
-				WFIFOB(fd,2) = result;
+				WFIFOB(fd,2) = (uint8)result;
 				if (result == 6) { // 6 = Your are Prohibited to log in until %s
 					char tmpstr[20];
 					time_t ban_until_time = (sql_row) ? atol(sql_row[0]) : 0;
@@ -1561,21 +1533,32 @@ int parse_login(int fd)
 			break;
 		}
 
-		case 0x01db:	// request password key
+		case 0x01db:	// Sending request of the coding key
+		{
+			struct login_session_data* ld;
 			if (session[fd]->session_data) {
 				ShowWarning("login: abnormal request of MD5 key (already opened session).\n");
 				session[fd]->eof = 1;
 				return 0;
 			}
-		{
+
+			ld = (struct login_session_data*)aCalloc(1, sizeof(struct login_session_data));
+			session[fd]->session_data = ld;
+
+			// Creation of the coding key
+			memset(ld->md5key, '\0', sizeof(ld->md5key));
+			ld->md5keylen = (uint16)(12 + rand() % 4);
+			for(i = 0; i < ld->md5keylen; i++)
+				ld->md5key[i] = (char)(1 + rand() % 255);
+
 			RFIFOSKIP(fd,2);
-			WFIFOHEAD(fd,4 + md5keylen);
+			WFIFOHEAD(fd,4 + ld->md5keylen);
 			WFIFOW(fd,0) = 0x01dc;
-			WFIFOW(fd,2) = 4 + md5keylen;
-			memcpy(WFIFOP(fd,4), md5key, md5keylen);
+			WFIFOW(fd,2) = 4 + ld->md5keylen;
+			memcpy(WFIFOP(fd,4), ld->md5key, ld->md5keylen);
 			WFIFOSET(fd,WFIFOW(fd,2));
 		}
-			break;
+		break;
 
 		case 0x2710:	// Connection request of a char-server
 			if (RFIFOREST(fd) < 86)
@@ -1991,41 +1974,36 @@ void set_server_type(void)
 
 int do_init(int argc, char** argv)
 {
-	//initialize login server
+	// initialize login server
 	int i;
 
 	login_set_defaults();
-	//read login configue
+
+	// read login-server configuration
 	login_config_read((argc > 1) ? argv[1] : LOGIN_CONF_NAME);
 	sql_config_read(SQL_CONF_NAME);
 	login_lan_config_read((argc > 2) ? argv[2] : LAN_CONF_NAME);
-	//Generate Passworded Key.
-	memset(md5key, 0, sizeof(md5key));
-	md5keylen=rand()%4+12;
-	for(i=0;i<md5keylen;i++)
-		md5key[i]=rand()%255+1;
+
+	srand((unsigned int)time(NULL));
 
 	for(i=0;i<AUTH_FIFO_SIZE;i++)
 		auth_fifo[i].delflag=1;
 
 	for(i=0;i<MAX_SERVERS;i++)
 		server_fd[i]=-1;
-	//server port open & binding
 
 	// Online user database init
 	online_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
 	add_timer_func_list(waiting_disconnect_timer, "waiting_disconnect_timer");
 
-	login_fd = make_listen_bind(login_config.login_ip, login_config.login_port);
-
-	//Auth start
+	// Auth init
 	mmo_auth_sqldb_init();
 
-	//Read account information.
+	// Read account information.
 	if(login_config.login_gm_read)
 		read_gm_account();
 
-	//set default parser as parse_login function
+	// set default parser as parse_login function
 	set_defaultparse(parse_login);
 
 	// ban deleter timer
@@ -2048,6 +2026,9 @@ int do_init(int argc, char** argv)
 
 	new_reg_tick = gettick();
 
+	// server port open & binding
+	login_fd = make_listen_bind(login_config.login_ip, login_config.login_port);
+
 	ShowStatus("The login-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %u).\n\n", login_config.login_port);
 
 	return 0;

+ 4 - 6
src/login_sql/login.h

@@ -10,17 +10,15 @@
 #define SQL_CONF_NAME "conf/inter_athena.conf"
 #define LAN_CONF_NAME "conf/subnet_athena.conf"
 
+// supported encryption types: 1- passwordencrypt, 2- passwordencrypt2, 3- both
+#define PASSWORDENC 3
+
 #ifndef SQL_DEBUG
 	#define mysql_query(_x, _y) mysql_query(_x, _y)
 #else 
-	#define mysql_query(_x, _y)  debug_mysql_query(__FILE__, __LINE__, _x, _y)
+	#define mysql_query(_x, _y) debug_mysql_query(__FILE__, __LINE__, _x, _y)
 #endif
 
-#define PASSWORDENC		3	// A definition is given when making an encryption password correspond.
-							// It is 1 at the time of passwordencrypt.
-							// It is made into 2 at the time of passwordencrypt2.
-							// When it is made 3, it corresponds to both.
-
 struct mmo_account {
 	int version;
 	char userid[NAME_LENGTH];