diff options
-rw-r--r-- | src/login/login.c | 321 | ||||
-rw-r--r-- | src/login_sql/login.c | 111 | ||||
-rw-r--r-- | src/login_sql/login.h | 4 |
3 files changed, 250 insertions, 186 deletions
diff --git a/src/login/login.c b/src/login/login.c index bacab0894..f69bcba6d 100644 --- a/src/login/login.c +++ b/src/login/login.c @@ -7,12 +7,12 @@ #include "../common/socket.h" #include "../common/db.h" #include "../common/timer.h" -#include "../common/lock.h" #include "../common/malloc.h" #include "../common/strlib.h" #include "../common/showmsg.h" #include "../common/version.h" #include "../common/md5calc.h" +#include "../common/lock.h" #include "login.h" #include <stdio.h> @@ -20,13 +20,40 @@ #include <string.h> #include <sys/stat.h> // for stat/lstat/fstat -uint32 account_id_count = START_ACCOUNT_NUM; -bool new_account_flag = true; -uint32 login_ip = INADDR_ANY; -uint16 login_port = 6900; +struct Login_Config { + + uint32 login_ip; // the address to bind to + uint16 login_port; // the port to bind to + 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; // autoregistration via _M/_F ? +// bool case_sensitive; // are logins case sensitive ? + bool use_md5_passwds; // work with password hashes instead of plaintext passwords? +// bool login_gm_read; // should the login server handle info about gm accounts? + uint8 min_level_to_connect; // minimum level of player/GM (0: player, 1-99: GM) to connect + bool online_check; // reject incoming players that are already registered as online ? + bool check_client_version; // check the clientversion set in the clientinfo ? + unsigned int 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 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 + bool use_dnsbl; // dns blacklist blocking ? + char dnsbl_servs[1024]; // comma-separated list of dnsbl servers + +} login_config; + +int login_fd; // login server socket +#define MAX_SERVERS 30 +int server_fd[MAX_SERVERS]; // char server sockets +struct mmo_char_server server[MAX_SERVERS]; // char server data // Advanced subnet check [LuzZza] -struct _subnet { +struct s_subnet { uint32 subnet; uint32 mask; uint32 char_ip; @@ -35,38 +62,31 @@ struct _subnet { int subnet_count = 0; -int use_dnsbl=0; // [Zido] -char dnsbl_servs[1024]; // [Zido] +struct gm_account* gm_account_db = NULL; +unsigned int GM_num = 0; // number of gm accounts +unsigned int GM_max = 0; + +//Account flood protection [Kevin] +int allowed_regs = 1; +int time_allowed = 10; //in seconds +unsigned int new_reg_tick = 0; +int num_regs = 0; + +uint32 account_id_count = START_ACCOUNT_NUM; char account_filename[1024] = "save/account.txt"; char GM_account_filename[1024] = "conf/GM_account.txt"; char login_log_filename[1024] = "log/login.log"; FILE *log_fp = NULL; char login_log_unknown_packets_filename[1024] = "log/login_unknown_packets.log"; -char date_format[32] = "%Y-%m-%d %H:%M:%S"; int save_unknown_packets = 0; long creation_time_GM_account_file; int gm_account_filename_check_timer = 15; // Timer to check if GM_account file has been changed and reload GM account automaticaly (in seconds; default: 15) -int log_login = 1; - int display_parse_login = 0; // 0: no, 1: yes int display_parse_admin = 0; // 0: no, 1: yes int display_parse_fromchar = 0; // 0: no, 1: yes (without packet 0x2714), 2: all packets -// array of char server entries -#define MAX_SERVERS 30 -struct mmo_char_server server[MAX_SERVERS]; -int server_fd[MAX_SERVERS]; - -int login_fd; - -static int online_check=1; //When set to 1, login server rejects incoming players that are already registered as online. [Skotlex] -//Account flood protection [Kevin] -unsigned int new_reg_tick=0; -int allowed_regs=1; -int num_regs=0; -int time_allowed=10; //Init this to 10 seconds. [Skotlex] enum { ACO_DENY_ALLOW = 0, @@ -84,15 +104,9 @@ char *access_deny = NULL; int access_ladmin_allownum = 0; char *access_ladmin_allow = NULL; -int min_level_to_connect = 0; // minimum level of player/GM (0: player, 1-99: gm) to connect on the server int add_to_unlimited_account = 0; // Give possibility or not to adjust (ladmin command: timeadd) the time of an unlimited account. int start_limited_time = -1; // Starting additional sec from now for the limited time at creation of accounts (-1: unlimited time, 0 or more: additional sec from now) -int check_client_version = 0; //Client version check ON/OFF .. (sirius) -int client_version_to_connect = 20; //Client version needed to connect ..(sirius) -static int ip_sync_interval = 0; - - struct login_session_data { uint16 md5keylen; char md5key[20]; @@ -146,19 +160,12 @@ int auth_before_save_file = 0; // Counter. First save when 1st char-server do co int admin_state = 0; char admin_pass[24] = ""; -unsigned int GM_num = 0; -unsigned int GM_max = 0; char gm_pass[64] = ""; int level_new_gm = 60; -struct gm_account* gm_account_db = NULL; static struct dbt *online_db; -int use_md5_passwds = 0; - -int console = 0; - int charif_sendallwos(int sfd, unsigned char *buf, unsigned int len); //------------------------------ @@ -166,7 +173,7 @@ int charif_sendallwos(int sfd, unsigned char *buf, unsigned int len); //------------------------------ int login_log(char *fmt, ...) { - if (log_login) { + if( login_config.log_login ) { va_list ap; time_t raw_time; char tmpstr[2048]; @@ -180,7 +187,7 @@ int login_log(char *fmt, ...) else { va_start(ap, fmt); time(&raw_time); - strftime(tmpstr, 24, date_format, localtime(&raw_time)); + strftime(tmpstr, 24, login_config.date_format, localtime(&raw_time)); sprintf(tmpstr + strlen(tmpstr), ": %s", fmt); vfprintf(log_fp, tmpstr, ap); va_end(ap); @@ -210,11 +217,11 @@ static int waiting_disconnect_timer(int tid, unsigned int tick, int id, int data void add_online_user(int char_server, int account_id) { struct online_login_data *p; - if (!online_check) + if( !login_config.online_check ) return; p = idb_ensure(online_db, account_id, create_online_user); p->char_server = char_server; - if (p->waiting_disconnect != -1) + if( p->waiting_disconnect != -1 ) { delete_timer(p->waiting_disconnect, waiting_disconnect_timer); p->waiting_disconnect = -1; @@ -223,19 +230,20 @@ void add_online_user(int char_server, int account_id) void remove_online_user(int account_id) { - if(!online_check) + if( !login_config.online_check ) return; - if (account_id == 99) { // reset all to offline + if( account_id == 99 ) + {// reset all to offline online_db->clear(online_db, NULL); // purge db return; } - idb_remove(online_db,account_id); + idb_remove(online_db, account_id); } static int waiting_disconnect_timer(int tid, unsigned int tick, int id, int data) { - struct online_login_data *p; - if ((p= idb_get(online_db, id)) != NULL && p->waiting_disconnect == id) + struct online_login_data* p = idb_get(online_db, id); + if( p != NULL && p->waiting_disconnect == id ) { p->waiting_disconnect = -1; remove_online_user(id); @@ -245,7 +253,7 @@ static int waiting_disconnect_timer(int tid, unsigned int tick, int id, int data static int sync_ip_addresses(int tid, unsigned int tick, int id, int data) { - unsigned char buf[2]; + uint8 buf[2]; ShowInfo("IP Sync in progress...\n"); WBUFW(buf,0) = 0x2735; charif_sendallwos(-1, buf, 2); @@ -1091,7 +1099,7 @@ int mmo_auth_new(struct mmo_account* account, char sex, char* email) auth_dat[i].account_id = account_id_count++; safestrncpy(auth_dat[i].userid, account->userid, NAME_LENGTH); - if( use_md5_passwds ) + if( login_config.use_md5_passwds ) MD5_String(account->passwd, auth_dat[i].pass); else safestrncpy(auth_dat[i].pass, account->passwd, NAME_LENGTH); @@ -1141,16 +1149,16 @@ int mmo_auth(struct mmo_account* account, int fd) sprintf(ip, "%d.%d.%d.%d", sin_addr[3], sin_addr[2], sin_addr[1], sin_addr[0]); // DNS Blacklist check - if( use_dnsbl ) + if( login_config.use_dnsbl ) { char r_ip[16]; char ip_dnsbl[256]; - char *dnsbl_serv; + char* dnsbl_serv; bool matched = false; sprintf(r_ip, "%d.%d.%d.%d", sin_addr[0], sin_addr[1], sin_addr[2], sin_addr[3]); - for( dnsbl_serv = strtok(dnsbl_servs,","); !matched && dnsbl_serv != NULL; dnsbl_serv = strtok(NULL,",") ) + for( dnsbl_serv = strtok(login_config.dnsbl_servs,","); !matched && dnsbl_serv != NULL; dnsbl_serv = strtok(NULL,",") ) { sprintf(ip_dnsbl, "%s.%s", r_ip, dnsbl_serv); if( host2ip(ip_dnsbl) ) @@ -1165,14 +1173,14 @@ int mmo_auth(struct mmo_account* account, int fd) } //Client Version check - if( check_client_version && account->version != 0 && - account->version != client_version_to_connect ) + if( login_config.check_client_version && account->version != 0 && + account->version != login_config.client_version_to_connect ) return 5; len = strnlen(account->userid, NAME_LENGTH); // Account creation with _M/_F - if( new_account_flag ) + if( login_config.new_account_flag ) { if( len > 2 && strnlen(account->passwd, NAME_LENGTH) >= 4 && // valid user and password lengths account->passwdenc == 0 && // unencoded password @@ -1210,7 +1218,7 @@ int mmo_auth(struct mmo_account* account, int fd) return 1; // 1 = Incorrect Password } - if( use_md5_passwds ) + if( login_config.use_md5_passwds ) MD5_String(account->passwd, user_password); else safestrncpy(user_password, account->passwd, NAME_LENGTH); @@ -1229,7 +1237,7 @@ int mmo_auth(struct mmo_account* account, int fd) if( auth_dat[i].ban_until_time != 0 ) { // account is banned - strftime(tmpstr, 20, date_format, localtime(&auth_dat[i].ban_until_time)); + strftime(tmpstr, 20, login_config.date_format, localtime(&auth_dat[i].ban_until_time)); tmpstr[19] = '\0'; if( auth_dat[i].ban_until_time > time(NULL) ) { // always banned login_log("Connection refused (account: %s, pass: %s, banned until %s, ip: %s)\n", account->userid, account->passwd, tmpstr, ip); @@ -1272,7 +1280,7 @@ int mmo_auth(struct mmo_account* account, int fd) } } - if( online_check ) + if( login_config.online_check ) { struct online_login_data* data = idb_get(online_db,auth_dat[i].account_id); if( data && data->char_server > -1 ) @@ -1545,7 +1553,7 @@ int parse_fromchar(int fd) char tmpstr[24]; time_t raw_time; time(&raw_time); - strftime(tmpstr, 23, date_format, localtime(&raw_time)); + strftime(tmpstr, 23, login_config.date_format, localtime(&raw_time)); fprintf(fp, "\n// %s: @GM command on account %d\n%d %d\n", tmpstr, acc, acc, level_new_gm); fclose(fp); WBUFL(buf,6) = level_new_gm; @@ -1689,7 +1697,7 @@ int parse_fromchar(int fd) if (timestamp != 0) { unsigned char buf[16]; char tmpstr[2048]; - strftime(tmpstr, 24, date_format, localtime(×tamp)); + strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); login_log("Char-server '%s': Ban request (account: %d, new final date of banishment: %d (%s), ip: %s).\n", server[id].name, acc, timestamp, (timestamp == 0 ? "no banishment" : tmpstr), ip); WBUFW(buf,0) = 0x2731; @@ -1856,10 +1864,11 @@ int parse_fromchar(int fd) case 0x272d: // Receive list of all online accounts. [Skotlex] if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) return 0; - if (online_check) { + if( login_config.online_check ) + { struct online_login_data *p; int aid; - uint32 users; + uint32 i, users; online_db->foreach(online_db,online_db_setoffline,id); //Set all chars from this char-server offline first users = RFIFOW(fd,4); for (i = 0; i < users; i++) { @@ -1929,7 +1938,7 @@ int parse_fromchar(int fd) logfp = fopen(login_log_unknown_packets_filename, "a"); if (logfp) { time(&raw_time); - strftime(tmpstr, 23, date_format, localtime(&raw_time)); + strftime(tmpstr, 23, login_config.date_format, localtime(&raw_time)); fprintf(logfp, "%s: receiving of an unknown packet -> disconnection\n", tmpstr); fprintf(logfp, "parse_fromchar: connection #%d (ip: %s), packet: 0x%x (with being read: %lu).\n", fd, ip, command, (unsigned long)RFIFOREST(fd)); fprintf(logfp, "Detail (in hex):\n"); @@ -2387,7 +2396,7 @@ int parse_admin(int fd) if ((fp2 = lock_fopen(GM_account_filename, &lock)) != NULL) { if ((fp = fopen(GM_account_filename, "r")) != NULL) { time(&raw_time); - strftime(tmpstr, 23, date_format, localtime(&raw_time)); + strftime(tmpstr, 23, login_config.date_format, localtime(&raw_time)); modify_flag = 0; // read/write GM file while(fgets(line, sizeof(line), fp)) @@ -2574,7 +2583,7 @@ int parse_admin(int fd) account_name[23] = '\0'; remove_control_chars(account_name); timestamp = (time_t)RFIFOL(fd,26); - strftime(tmpstr, 24, date_format, localtime(×tamp)); + strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); i = search_account_index(account_name); if (i != -1) { memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); @@ -2608,7 +2617,7 @@ int parse_admin(int fd) timestamp = (time_t)RFIFOL(fd,26); if (timestamp <= time(NULL)) timestamp = 0; - strftime(tmpstr, 24, date_format, localtime(×tamp)); + strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); i = search_account_index(account_name); if (i != -1) { memcpy(WFIFOP(fd,6), auth_dat[i].userid, 24); @@ -2672,7 +2681,7 @@ int parse_admin(int fd) if (timestamp != -1) { if (timestamp <= time(NULL)) timestamp = 0; - strftime(tmpstr, 24, date_format, localtime(×tamp)); + strftime(tmpstr, 24, login_config.date_format, localtime(×tamp)); login_log("'ladmin': Adjustment of a final date of a banishment (account: %s, (%+d y %+d m %+d d %+d h %+d mn %+d s) -> new validity: %d (%s), ip: %s)\n", auth_dat[i].userid, (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), timestamp, (timestamp == 0 ? "no banishment" : tmpstr), ip); if (auth_dat[i].ban_until_time != timestamp) { @@ -2691,7 +2700,7 @@ int parse_admin(int fd) mmo_auth_sync(); } } else { - strftime(tmpstr, 24, date_format, localtime(&auth_dat[i].ban_until_time)); + strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].ban_until_time)); login_log("'ladmin': Impossible to adjust the final date of a banishment (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> ???, ip: %s)\n", auth_dat[i].userid, auth_dat[i].ban_until_time, (auth_dat[i].ban_until_time == 0 ? "no banishment" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), ip); } @@ -2781,15 +2790,15 @@ int parse_admin(int fd) tmtime->tm_sec = tmtime->tm_sec + (short)RFIFOW(fd,36); timestamp = mktime(tmtime); if (timestamp != -1) { - strftime(tmpstr, 24, date_format, localtime(&auth_dat[i].connect_until_time)); - strftime(tmpstr2, 24, date_format, localtime(×tamp)); + strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].connect_until_time)); + strftime(tmpstr2, 24, login_config.date_format, localtime(×tamp)); login_log("'ladmin': Adjustment of a validity limit (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> new validity: %d (%s), ip: %s)\n", auth_dat[i].userid, auth_dat[i].connect_until_time, (auth_dat[i].connect_until_time == 0 ? "unlimited" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), timestamp, (timestamp == 0 ? "unlimited" : tmpstr2), ip); auth_dat[i].connect_until_time = timestamp; mmo_auth_sync(); WFIFOL(fd,30) = (unsigned long)auth_dat[i].connect_until_time; } else { - strftime(tmpstr, 24, date_format, localtime(&auth_dat[i].connect_until_time)); + strftime(tmpstr, 24, login_config.date_format, localtime(&auth_dat[i].connect_until_time)); login_log("'ladmin': Impossible to adjust a validity limit (account: %s, %d (%s) + (%+d y %+d m %+d d %+d h %+d mn %+d s) -> ???, ip: %s)\n", auth_dat[i].userid, auth_dat[i].connect_until_time, (auth_dat[i].connect_until_time == 0 ? "unlimited" : tmpstr), (short)RFIFOW(fd,26), (short)RFIFOW(fd,28), (short)RFIFOW(fd,30), (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), ip); WFIFOL(fd,30) = 0; @@ -2900,7 +2909,7 @@ int parse_admin(int fd) logfp = fopen(login_log_unknown_packets_filename, "a"); if (logfp) { time(&raw_time); - strftime(tmpstr, 23, date_format, localtime(&raw_time)); + strftime(tmpstr, 23, login_config.date_format, localtime(&raw_time)); fprintf(logfp, "%s: receiving of an unknown packet -> disconnection\n", tmpstr); fprintf(logfp, "parse_admin: connection #%d (ip: %s), packet: 0x%x (with being read: %lu).\n", fd, ip, command, (unsigned long)RFIFOREST(fd)); fprintf(logfp, "Detail (in hex):\n"); @@ -3052,20 +3061,27 @@ int parse_login(int fd) account.passwdenc = (command != 0x01dd) ? 0 : PASSWORDENC; result = mmo_auth(&account, fd); - if (result == -1) { // auth success + if( result == -1 ) + { // auth success int gm_level = isGM(account.account_id); - if (min_level_to_connect > gm_level) { + if( login_config.min_level_to_connect > gm_level ) + { login_log("Connection refused: the minimum GM level for connection is %d (account: %s, GM level: %d, ip: %s).\n", - min_level_to_connect, account.userid, gm_level, ip); + login_config.min_level_to_connect, account.userid, gm_level, ip); WFIFOHEAD(fd,3); WFIFOW(fd,0) = 0x81; WFIFOB(fd,2) = 1; // 01 = Server closed WFIFOSET(fd,3); - } else { + } + else + { uint8 server_num = 0; + WFIFOHEAD(fd,47+32*MAX_SERVERS); - for(i = 0; i < MAX_SERVERS; i++) { - if (server_fd[i] >= 0) { + for( i = 0; i < MAX_SERVERS; ++i ) + { + if( session_isValid(server_fd[i]) ) + { // Advanced subnet check [LuzZza] uint32 subnet_char_ip = lan_subnetcheck(ipl); WFIFOL(fd,47+server_num*32) = htonl((subnet_char_ip) ? subnet_char_ip : server[i].ip); @@ -3110,7 +3126,9 @@ int parse_login(int fd) WFIFOSET(fd,3); } } - } else { // auth failed + } + else + { // auth failed WFIFOHEAD(fd,23); memset(WFIFOP(fd,0), '\0', 23); WFIFOW(fd,0) = 0x6a; @@ -3120,7 +3138,7 @@ int parse_login(int fd) time_t ban_until_time; i = search_account_index(account.userid); ban_until_time = (i) ? auth_dat[i].ban_until_time : 0; - strftime(tmpstr, 20, date_format, localtime(&ban_until_time)); tmpstr[19] = '\0'; + strftime(tmpstr, 20, login_config.date_format, localtime(&ban_until_time)); tmpstr[19] = '\0'; strncpy((char*)WFIFOP(fd,3), tmpstr, 20); // ban timestamp goes here } WFIFOSET(fd,23); @@ -3302,7 +3320,7 @@ int parse_login(int fd) logfp = fopen(login_log_unknown_packets_filename, "a"); if (logfp) { time(&raw_time); - strftime(tmpstr, 23, date_format, localtime(&raw_time)); + strftime(tmpstr, 23, login_config.date_format, localtime(&raw_time)); fprintf(logfp, "%s: receiving of an unknown packet -> disconnection\n", tmpstr); fprintf(logfp, "parse_login: connection #%d (ip: %s), packet: 0x%x (with being read: %lu).\n", fd, ip, command, (unsigned long)RFIFOREST(fd)); fprintf(logfp, "Detail (in hex):\n"); @@ -3520,14 +3538,16 @@ int login_config_read(const char* cfgName) } else if (strcmpi(w1, "level_new_gm") == 0) { level_new_gm = atoi(w2); } - else if (strcmpi(w1, "bind_ip") == 0) { + else if( !strcmpi(w1, "bind_ip") ) { char ip_str[16]; - login_ip = host2ip(w2); - if (login_ip) - ShowStatus("Login server binding IP address : %s -> %s\n", w2, ip2str(login_ip, ip_str)); - } else if (strcmpi(w1, "login_port") == 0) { - login_port = (uint16) atoi(w2); - } else if (strcmpi(w1, "account_filename") == 0) { + login_config.login_ip = host2ip(w2); + if( login_config.login_ip ) + 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, "account_filename") == 0) { memset(account_filename, 0, sizeof(account_filename)); strncpy(account_filename, w2, sizeof(account_filename)); account_filename[sizeof(account_filename)-1] = '\0'; @@ -3538,7 +3558,7 @@ int login_config_read(const char* cfgName) } else if (strcmpi(w1, "gm_account_filename_check_timer") == 0) { gm_account_filename_check_timer = atoi(w2); } else if (strcmpi(w1, "log_login") == 0) { - log_login = config_switch(w2); + login_config.log_login = config_switch(w2); } else if (strcmpi(w1, "login_log_filename") == 0) { memset(login_log_filename, 0, sizeof(login_log_filename)); strncpy(login_log_filename, w2, sizeof(login_log_filename)); @@ -3616,32 +3636,35 @@ int login_config_read(const char* cfgName) } } } + else if(!strcmpi(w1, "new_account")) - new_account_flag = (bool)config_switch(w2); + login_config.new_account_flag = (bool)config_switch(w2); else if(!strcmpi(w1, "check_client_version")) - check_client_version = config_switch(w2); + login_config.check_client_version = (bool)config_switch(w2); else if(!strcmpi(w1, "client_version_to_connect")) - client_version_to_connect = atoi(w2); + login_config.client_version_to_connect = (unsigned int)atoi(w2); else if(!strcmpi(w1, "use_MD5_passwords")) - use_md5_passwds = config_switch(w2); + login_config.use_md5_passwds = (bool)config_switch(w2); else if(!strcmpi(w1, "min_level_to_connect")) - min_level_to_connect = atoi(w2); + login_config.min_level_to_connect = (uint8)atoi(w2); else if(!strcmpi(w1, "date_format")) - strncpy(date_format, w2, sizeof(date_format)); + safestrncpy(login_config.date_format, w2, sizeof(login_config.date_format)); else if(!strcmpi(w1, "console")) - console = config_switch(w2); + login_config.console = config_switch(w2); +// else if(!strcmpi(w1, "case_sensitive")) +// login_config.case_sensitive = config_switch(w2); else if(!strcmpi(w1, "allowed_regs")) //account flood protection system allowed_regs = atoi(w2); else if(!strcmpi(w1, "time_allowed")) time_allowed = atoi(w2); else if(!strcmpi(w1, "online_check")) - online_check = config_switch(w2); + login_config.online_check = (bool)config_switch(w2); else if(!strcmpi(w1, "use_dnsbl")) - use_dnsbl = config_switch(w2); + login_config.use_dnsbl = (bool)config_switch(w2); else if(!strcmpi(w1, "dnsbl_servers")) - strcpy(dnsbl_servs, w2); + safestrncpy(login_config.dnsbl_servs, w2, sizeof(login_config.dnsbl_servs)); else if(!strcmpi(w1, "ip_sync_interval")) - ip_sync_interval = 1000*60*atoi(w2); //w2 comes in minutes. + login_config.ip_sync_interval = (unsigned int)1000*60*atoi(w2); //w2 comes in minutes. else if(!strcmpi(w1, "import")) login_config_read(w2); } @@ -3682,14 +3705,14 @@ void display_conf_warnings(void) level_new_gm = 60; } - if (new_account_flag != 0 && new_account_flag != 1) { + if (login_config.new_account_flag != 0 && login_config.new_account_flag != 1) { ShowWarning("Invalid value for new_account parameter -> setting to 0 (no new account).\n"); - new_account_flag = 0; + login_config.new_account_flag = 0; } - if (login_port < 1024) { + if (login_config.login_port < 1024) { ShowWarning("Invalid value for login_port parameter -> setting to 6900 (default).\n"); - login_port = 6900; + login_config.login_port = 6900; } if (gm_account_filename_check_timer < 0) { @@ -3720,12 +3743,12 @@ void display_conf_warnings(void) display_parse_fromchar = 0; } - if (min_level_to_connect < 0) { // 0: all players, 1-99 at least gm level x - ShowWarning("Invalid value for min_level_to_connect (%d) parameter -> setting 0 (any player).\n", min_level_to_connect); - min_level_to_connect = 0; - } else if (min_level_to_connect > 99) { // 0: all players, 1-99 at least gm level x - ShowWarning("Invalid value for min_level_to_connect (%d) parameter -> setting to 99 (only GM level 99)\n", min_level_to_connect); - min_level_to_connect = 99; + if (login_config.min_level_to_connect < 0) { // 0: all players, 1-99 at least gm level x + ShowWarning("Invalid value for min_level_to_connect (%d) parameter -> setting 0 (any player).\n", login_config.min_level_to_connect); + login_config.min_level_to_connect = 0; + } else if (login_config.min_level_to_connect > 99) { // 0: all players, 1-99 at least gm level x + ShowWarning("Invalid value for min_level_to_connect (%d) parameter -> setting to 99 (only GM level 99)\n", login_config.min_level_to_connect); + login_config.min_level_to_connect = 99; } if (add_to_unlimited_account != 0 && add_to_unlimited_account != 1) { // 0: no, 1: yes @@ -3804,11 +3827,11 @@ void save_config_in_log(void) else login_log("- to create GM with level '%d' when @gm is used.\n", level_new_gm); - if (new_account_flag == 1) + if (login_config.new_account_flag == 1) login_log("- to ALLOW new users (with _F/_M).\n"); else login_log("- to NOT ALLOW new users (with _F/_M).\n"); - login_log("- with port: %d.\n", login_port); + login_log("- with port: %d.\n", login_config.login_port); login_log("- with the accounts file name: '%s'.\n", account_filename); login_log("- with the GM accounts file name: '%s'.\n", GM_account_filename); if (gm_account_filename_check_timer == 0) @@ -3816,7 +3839,7 @@ void save_config_in_log(void) else login_log("- to check GM accounts file modifications every %d seconds.\n", gm_account_filename_check_timer); - if (use_md5_passwds == 0) + if (login_config.use_md5_passwds == 0) login_log("- to save password in plain text.\n"); else login_log("- to save password with MD5 encrypting.\n"); @@ -3841,12 +3864,12 @@ void save_config_in_log(void) else login_log("- to NOT display char-server parse packets on console.\n"); - if (min_level_to_connect == 0) // 0: all players, 1-99 at least gm level x + if (login_config.min_level_to_connect == 0) // 0: all players, 1-99 at least gm level x login_log("- with no minimum level for connection.\n"); - else if (min_level_to_connect == 99) + else if (login_config.min_level_to_connect == 99) login_log("- to accept only GM with level 99.\n"); else - login_log("- to accept only GM with level %d or more.\n", min_level_to_connect); + login_log("- to accept only GM with level %d or more.\n", login_config.min_level_to_connect); if (add_to_unlimited_account) login_log("- to authorize adjustment (with timeadd ladmin) on an unlimited account.\n"); @@ -3902,6 +3925,32 @@ void save_config_in_log(void) } } +void login_set_defaults() +{ + login_config.login_ip = INADDR_ANY; + login_config.login_port = 6900; + 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.case_sensitive = true; + login_config.use_md5_passwds = false; +// login_config.login_gm_read = true; + login_config.min_level_to_connect = 0; + login_config.online_check = true; + login_config.check_client_version = false; + login_config.client_version_to_connect = 20; + +// 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)); +} + //-------------------------------------- // Function called at exit of the server //-------------------------------------- @@ -3952,8 +4001,11 @@ void set_server_type(void) int do_init(int argc, char **argv) { + // initialize login server int i, j; + login_set_defaults(); + // read login-server configuration login_config_read((argc > 1) ? argv[1] : LOGIN_CONF_NAME); display_conf_warnings(); // not in login_config_read, because we can use 'import' option, and display same message twice or more @@ -3962,19 +4014,24 @@ int do_init(int argc, char **argv) srand((unsigned int)time(NULL)); - for(i = 0; i< AUTH_FIFO_SIZE; i++) + for( i = 0; i < AUTH_FIFO_SIZE; i++ ) auth_fifo[i].delflag = 1; - for(i = 0; i < MAX_SERVERS; i++) + for( i = 0; i < MAX_SERVERS; i++ ) server_fd[i] = -1; + // 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"); + + // Auth init mmo_auth_init(); + + // Read account information. 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"); + // set default parser as parse_login function + set_defaultparse(parse_login); 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) @@ -3984,19 +4041,21 @@ int do_init(int argc, char **argv) if (j == 0) // if we would not to check, we check every 60 sec, just to have timer (if we change timer, is was not necessary to check if timer already exists) j = 60; + // every x sec we check if gm file has been changed add_timer_func_list(check_GM_file, "check_GM_file"); - add_timer_interval(gettick() + j * 1000, check_GM_file, 0, 0, j * 1000); // every x sec we check if gm file has been changed + add_timer_interval(gettick() + j * 1000, check_GM_file, 0, 0, j * 1000); - + // every 10 minutes cleanup online account db. add_timer_func_list(online_data_cleanup, "online_data_cleanup"); - add_timer_interval(gettick() + 600*1000, online_data_cleanup, 0, 0, 600*1000); // every 10 minutes cleanup online account db. - - if (ip_sync_interval) { + add_timer_interval(gettick() + 600*1000, online_data_cleanup, 0, 0, 600*1000); + + // add timer to detect ip address change and perform update + if (login_config.ip_sync_interval) { add_timer_func_list(sync_ip_addresses, "sync_ip_addresses"); - add_timer_interval(gettick() + ip_sync_interval, sync_ip_addresses, 0, 0, ip_sync_interval); + add_timer_interval(gettick() + login_config.ip_sync_interval, sync_ip_addresses, 0, 0, login_config.ip_sync_interval); } - if( console ) + if( login_config.console ) { //##TODO invoke a CONSOLE_START plugin event } @@ -4004,10 +4063,10 @@ 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_fd = make_listen_bind(login_config.login_ip, login_config.login_port); - login_log("The login-server is ready (Server is listening on the port %d).\n", login_port); - ShowStatus("The login-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", login_port); + login_log("The login-server is ready (Server is listening on the port %d).\n", login_config.login_port); + ShowStatus("The login-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", login_config.login_port); return 0; } diff --git a/src/login_sql/login.c b/src/login_sql/login.c index bc3c1117a..a1ef693f6 100644 --- a/src/login_sql/login.c +++ b/src/login_sql/login.c @@ -24,18 +24,19 @@ struct Login_Config { uint32 login_ip; // the address to bind to uint16 login_port; // the port to bind to + 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? - unsigned int ip_sync_interval; // interval (in minutes) to execute a DNS/IP update (for dynamic IPs) - int min_level_to_connect; // minimum level of player/GM (0: player, 1-99: gm) to connect bool new_account_flag; // autoregistration via _M/_F ? bool case_sensitive; // are logins case sensitive ? bool use_md5_passwds; // work with password hashes instead of plaintext passwords? bool login_gm_read; // should the login server handle info about gm accounts? + uint8 min_level_to_connect; // minimum level of player/GM (0: player, 1-99: GM) to connect bool online_check; // reject incoming players that are already registered as online ? bool check_client_version; // check the clientversion set in the clientinfo ? unsigned int 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 attemps ? unsigned int dynamic_pass_failure_ban_interval; // how far to scan the loginlog for password failures @@ -47,7 +48,7 @@ struct Login_Config { } login_config; int login_fd; // login server socket -int server_num; // number of connected char servers +#define MAX_SERVERS 30 int server_fd[MAX_SERVERS]; // char server sockets struct mmo_char_server server[MAX_SERVERS]; // char server data @@ -61,15 +62,14 @@ struct s_subnet { int subnet_count = 0; - struct gm_account* gm_account_db = NULL; unsigned int GM_num = 0; // number of gm accounts //Account registration flood protection [Kevin] int allowed_regs = 1; int time_allowed = 10; //in seconds -int num_regs = 0; unsigned int new_reg_tick = 0; +int num_regs = 0; Sql* sql_handle; @@ -494,7 +494,7 @@ int mmo_auth(struct mmo_account* account, int fd) { char r_ip[16]; char ip_dnsbl[256]; - char *dnsbl_serv; + char* dnsbl_serv; bool matched = false; sprintf(r_ip, "%u.%u.%u.%u", sin_addr[0], sin_addr[1], sin_addr[2], sin_addr[3]); @@ -1172,9 +1172,11 @@ int parse_fromchar(int fd) case 0x272d: // Receive list of all online accounts. [Skotlex] if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) return 0; - if (login_config.online_check) { + if( login_config.online_check ) + { struct online_login_data *p; - int aid, users; + int aid; + uint32 i, users; online_db->foreach(online_db,online_db_setoffline,id); //Set all chars from this char-server offline first users = RFIFOW(fd,4); for (i = 0; i < users; i++) { @@ -1189,8 +1191,8 @@ int parse_fromchar(int fd) } } RFIFOSKIP(fd,RFIFOW(fd,2)); - break; + case 0x272e: //Request account_reg2 for a character. if (RFIFOREST(fd) < 10) return 0; @@ -1388,6 +1390,8 @@ int parse_login(int fd) } else { + uint8 server_num = 0; + if( login_config.log_login && SQL_ERROR == Sql_Query(sql_handle, "INSERT DELAYED INTO `%s`(`time`,`ip`,`user`,`rcode`,`log`) VALUES (NOW(), '%u', '%s','100', 'login ok')", loginlog_db, ipl, esc_userid) ) Sql_ShowDebug(sql_handle); if( account.level ) @@ -1395,8 +1399,7 @@ int parse_login(int fd) else ShowStatus("Connection of the account '%s' accepted.\n", account.userid); - server_num = 0; - WFIFOHEAD(fd, 47+32*MAX_SERVERS); + WFIFOHEAD(fd,47+32*MAX_SERVERS); for( i = 0; i < MAX_SERVERS; ++i ) { if( session_isValid(server_fd[i]) ) @@ -1812,12 +1815,13 @@ int login_config_read(const char* cfgName) ShowInfo("Console Silent Setting: %d\n", atoi(w2)); msg_silent = atoi(w2); } - else if (!strcmpi(w1, "bind_ip")) { + else if( !strcmpi(w1, "bind_ip") ) { char ip_str[16]; login_config.login_ip = host2ip(w2); - if (login_config.login_ip) + if( login_config.login_ip ) ShowStatus("Login server binding IP address : %s -> %s\n", w2, ip2str(login_config.login_ip, ip_str)); - } else if(!strcmpi(w1,"login_port")) { + } + else if( !strcmpi(w1, "login_port") ) { login_config.login_port = (uint16)atoi(w2); ShowStatus("set login_port : %s\n",w2); } @@ -1835,34 +1839,34 @@ int login_config_read(const char* cfgName) else if (!strcmpi(w1, "dynamic_pass_failure_ban_duration")) login_config.dynamic_pass_failure_ban_duration = atoi(w2); - else if (!strcmpi(w1, "new_account")) - login_config.new_account_flag=config_switch(w2); - else if (!strcmpi(w1, "check_client_version")) - login_config.check_client_version=config_switch(w2); - else if (!strcmpi(w1, "client_version_to_connect")) - login_config.client_version_to_connect=atoi(w2); - else if (!strcmpi(w1, "use_MD5_passwords")) - login_config.use_md5_passwds = config_switch(w2); - else if (!strcmpi(w1, "min_level_to_connect")) - login_config.min_level_to_connect = atoi(w2); - else if (!strcmpi(w1, "date_format")) - strncpy(login_config.date_format, w2, sizeof(login_config.date_format)); - else if (!strcmpi(w1, "console")) + else if(!strcmpi(w1, "new_account")) + login_config.new_account_flag = (bool)config_switch(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)atoi(w2); + else if(!strcmpi(w1, "use_MD5_passwords")) + login_config.use_md5_passwds = (bool)config_switch(w2); + else if(!strcmpi(w1, "min_level_to_connect")) + login_config.min_level_to_connect = (uint8)atoi(w2); + else if(!strcmpi(w1, "date_format")) + safestrncpy(login_config.date_format, w2, sizeof(login_config.date_format)); + else if(!strcmpi(w1, "console")) login_config.console = config_switch(w2); - else if (!strcmpi(w1, "case_sensitive")) + else if(!strcmpi(w1, "case_sensitive")) login_config.case_sensitive = config_switch(w2); - else if (!strcmpi(w1, "allowed_regs")) //account flood protection system + else if(!strcmpi(w1, "allowed_regs")) //account flood protection system allowed_regs = atoi(w2); - else if (!strcmpi(w1, "time_allowed")) + else if(!strcmpi(w1, "time_allowed")) time_allowed = atoi(w2); - else if (!strcmpi(w1, "online_check")) - login_config.online_check = config_switch(w2); - else if (!strcmpi(w1, "use_dnsbl")) - login_config.use_dnsbl = config_switch(w2); - else if (!strcmpi(w1, "dnsbl_servers")) - { strncpy(login_config.dnsbl_servs, w2, 1023); login_config.dnsbl_servs[1023] = '\0'; } + else if(!strcmpi(w1, "online_check")) + login_config.online_check = (bool)config_switch(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, "ip_sync_interval")) - login_config.ip_sync_interval = 1000*60*atoi(w2); //w2 comes in minutes. + login_config.ip_sync_interval = (unsigned int)1000*60*atoi(w2); //w2 comes in minutes. else if (!strcmpi(w1, "import")) login_config_read(w2); } @@ -1924,27 +1928,28 @@ void sql_config_read(const char* cfgName) void login_set_defaults() { + login_config.login_ip = INADDR_ANY; + login_config.login_port = 6900; + 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.case_sensitive = true; + login_config.use_md5_passwds = false; + login_config.login_gm_read = true; login_config.min_level_to_connect = 0; + login_config.online_check = true; login_config.check_client_version = false; login_config.client_version_to_connect = 20; - login_config.new_account_flag = true; - login_config.online_check = true; + 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.ip_sync_interval = 0; login_config.use_dnsbl = false; - strcpy(login_config.dnsbl_servs, ""); - login_config.use_md5_passwds = false; - login_config.login_gm_read = true; - login_config.login_ip = INADDR_ANY; - login_config.login_port = 6900; - login_config.console = false; - strcpy(login_config.date_format, "%Y-%m-%d %H:%M:%S"); + safestrncpy(login_config.dnsbl_servs, "", sizeof(login_config.dnsbl_servs)); } //-------------------------------------- @@ -1965,7 +1970,8 @@ void do_final(void) // Function called when the server // has received a crash signal. //------------------------------ -void do_abort(void) { +void do_abort(void) +{ } void set_server_type(void) @@ -1987,11 +1993,11 @@ int do_init(int argc, char** argv) srand((unsigned int)time(NULL)); - for(i=0;i<AUTH_FIFO_SIZE;i++) - auth_fifo[i].delflag=1; + for( i = 0; i < AUTH_FIFO_SIZE; i++ ) + auth_fifo[i].delflag = 1; - for(i=0;i<MAX_SERVERS;i++) - server_fd[i]=-1; + for( i = 0; i < MAX_SERVERS; i++ ) + server_fd[i] = -1; // Online user database init online_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int)); @@ -2015,6 +2021,7 @@ int do_init(int argc, char** argv) add_timer_func_list(online_data_cleanup, "online_data_cleanup"); add_timer_interval(gettick() + 600*1000, online_data_cleanup, 0, 0, 600*1000); + // add timer to detect ip address change and perform update if (login_config.ip_sync_interval) { add_timer_func_list(sync_ip_addresses, "sync_ip_addresses"); add_timer_interval(gettick() + login_config.ip_sync_interval, sync_ip_addresses, 0, 0, login_config.ip_sync_interval); diff --git a/src/login_sql/login.h b/src/login_sql/login.h index 086a50515..bc6337f42 100644 --- a/src/login_sql/login.h +++ b/src/login_sql/login.h @@ -4,8 +4,6 @@ #ifndef _LOGIN_SQL_H_ #define _LOGIN_SQL_H_ -#define MAX_SERVERS 30 - #define LOGIN_CONF_NAME "conf/login_athena.conf" #define SQL_CONF_NAME "conf/inter_athena.conf" #define LAN_CONF_NAME "conf/subnet_athena.conf" @@ -25,7 +23,7 @@ struct mmo_account { long login_id2; char lastlogin[24]; int sex; - int level; + uint8 level; }; struct mmo_char_server { |