login.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877
  1. /**
  2. * @file login.c
  3. * Module purpose is to read configuration for login-server and handle accounts,
  4. * and also to synchronize all login interfaces: loginchrif, loginclif, logincnslif.
  5. * Licensed under GNU GPL.
  6. * For more information, see LICENCE in the main folder.
  7. * @author Athena Dev Teams < r15k
  8. * @author rAthena Dev Team
  9. */
  10. #pragma warning(disable:4800)
  11. #include "../common/core.h"
  12. #include "../common/db.h"
  13. #include "../common/malloc.h"
  14. #include "../common/md5calc.h"
  15. #include "../common/random.h"
  16. #include "../common/showmsg.h"
  17. #include "../common/socket.h" //ip2str
  18. #include "../common/strlib.h"
  19. #include "../common/timer.h"
  20. #include "../common/msg_conf.h"
  21. #include "../common/cli.h"
  22. #include "../common/utils.h"
  23. #include "../common/mmo.h"
  24. #include "../config/core.h"
  25. #include "account.h"
  26. #include "ipban.h"
  27. #include "login.h"
  28. #include "loginlog.h"
  29. #include "loginclif.h"
  30. #include "loginchrif.h"
  31. #include "logincnslif.h"
  32. #include <stdlib.h>
  33. #define LOGIN_MAX_MSG 30 /// Max number predefined in msg_conf
  34. static char* msg_table[LOGIN_MAX_MSG]; /// Login Server messages_conf
  35. //definition of exported var declared in .h
  36. struct mmo_char_server ch_server[MAX_SERVERS]; /// char server data
  37. struct Login_Config login_config; /// Configuration of login-serv
  38. DBMap* online_db;
  39. DBMap* auth_db;
  40. // account database
  41. AccountDB* accounts = NULL;
  42. // Advanced subnet check [LuzZza]
  43. struct s_subnet {
  44. uint32 mask;
  45. uint32 char_ip;
  46. uint32 map_ip;
  47. } subnet[16];
  48. int subnet_count = 0; //number of subnet config
  49. int login_fd; // login server file descriptor socket
  50. //early declaration
  51. bool login_check_password(const char* md5key, int passwdenc, const char* passwd, const char* refpass);
  52. ///Accessors
  53. AccountDB* login_get_accounts_db(void){
  54. return accounts;
  55. }
  56. // Console Command Parser [Wizputer]
  57. //FIXME to be remove (moved to cnslif / will be done once map/char/login, all have their cnslif interface ready)
  58. int parse_console(const char* buf){
  59. return cnslif_parse(buf);
  60. }
  61. /**
  62. * Sub function to create an online_login_data and save it to db.
  63. * @param key: Key of the database entry
  64. * @param ap: args
  65. * @return : Data identified by the key to be put in the database
  66. * @see DBCreateData
  67. */
  68. DBData login_create_online_user(DBKey key, va_list args) {
  69. struct online_login_data* p;
  70. CREATE(p, struct online_login_data, 1);
  71. p->account_id = key.i;
  72. p->char_server = -1;
  73. p->waiting_disconnect = INVALID_TIMER;
  74. return db_ptr2data(p);
  75. }
  76. /**
  77. * Receive info from char-serv that this user is online
  78. * This function will start a timer to recheck if that user still online
  79. * @param char_server : Serv id where account_id is connected
  80. * @param account_id : aid connected
  81. * @return the new online_login_data for that user
  82. */
  83. struct online_login_data* login_add_online_user(int char_server, uint32 account_id){
  84. struct online_login_data* p;
  85. p = (struct online_login_data*)idb_ensure(online_db, account_id, login_create_online_user);
  86. p->char_server = char_server;
  87. if( p->waiting_disconnect != INVALID_TIMER ) {
  88. delete_timer(p->waiting_disconnect, login_waiting_disconnect_timer);
  89. p->waiting_disconnect = INVALID_TIMER;
  90. }
  91. return p;
  92. }
  93. /**
  94. * Received info from char serv that the account_id is now offline
  95. * remove the user from online_db
  96. * Checking if user was already scheduled for deletion, and remove that timer if found.
  97. * @param account_id : aid to remove from db
  98. */
  99. void login_remove_online_user(uint32 account_id) {
  100. struct online_login_data* p;
  101. p = (struct online_login_data*)idb_get(online_db, account_id);
  102. if( p == NULL )
  103. return;
  104. if( p->waiting_disconnect != INVALID_TIMER )
  105. delete_timer(p->waiting_disconnect, login_waiting_disconnect_timer);
  106. idb_remove(online_db, account_id);
  107. }
  108. /**
  109. * Timered function to disconnect a user from login.
  110. * This is done either after auth_ok or kicked by char-server.
  111. * Removing user from auth_db and online_db.
  112. * Delay is AUTH_TIMEOUT by default.
  113. * @param tid: timer id
  114. * @param tick: tick of execution
  115. * @param id: user account id
  116. * @param data: unused
  117. * @return :0
  118. */
  119. int login_waiting_disconnect_timer(int tid, unsigned int tick, int id, intptr_t data) {
  120. struct online_login_data* p = (struct online_login_data*)idb_get(online_db, id);
  121. if( p != NULL && p->waiting_disconnect == tid && p->account_id == id ){
  122. p->waiting_disconnect = INVALID_TIMER;
  123. login_remove_online_user(id);
  124. idb_remove(auth_db, id);
  125. }
  126. return 0;
  127. }
  128. /**
  129. * Sub function to apply on online_db.
  130. * Mark a character as offline.
  131. * @param data: 1 entry in the db
  132. * @param ap: args
  133. * @return : Value to be added up by the function that is applying this
  134. * @see DBApply
  135. */
  136. int login_online_db_setoffline(DBKey key, DBData *data, va_list ap) {
  137. struct online_login_data* p = (struct online_login_data*)db_data2ptr(data);
  138. int server = va_arg(ap, int);
  139. if( server == -1 ) {
  140. p->char_server = -1;
  141. if( p->waiting_disconnect != INVALID_TIMER ) {
  142. delete_timer(p->waiting_disconnect, login_waiting_disconnect_timer);
  143. p->waiting_disconnect = INVALID_TIMER;
  144. }
  145. }
  146. else if( p->char_server == server )
  147. p->char_server = -2; //Char server disconnected.
  148. return 0;
  149. }
  150. /**
  151. * Sub function of login_online_data_cleanup.
  152. * Checking if all users in db are still connected to a char-server, and remove them if they aren't.
  153. * @param data: 1 entry in the db
  154. * @param ap: args
  155. * @return: Value to be added up by the function that is applying this
  156. * @see DBApply
  157. */
  158. static int login_online_data_cleanup_sub(DBKey key, DBData *data, va_list ap) {
  159. struct online_login_data *character= (struct online_login_data*)db_data2ptr(data);
  160. if (character->char_server == -2) //Unknown server.. set them offline
  161. login_remove_online_user(character->account_id);
  162. return 0;
  163. }
  164. /**
  165. * Timered function to check if user is still connected.
  166. * Launches every 600s by default.
  167. * @param tid: timer id
  168. * @param tick: tick of execution
  169. * @param id: unused
  170. * @param data: unused
  171. * @return : 0
  172. */
  173. static int login_online_data_cleanup(int tid, unsigned int tick, int id, intptr_t data) {
  174. online_db->foreach(online_db, login_online_data_cleanup_sub);
  175. return 0;
  176. }
  177. /**
  178. * Create a new account and save it in db/sql.
  179. * @param userid: string for user login
  180. * @param pass: string for user pass
  181. * @param sex: should be M|F|S (todo make an enum ?)
  182. * @param last_ip:
  183. * @return :
  184. * -1: success
  185. * 0: unregistered id (wrong sex fail to create in db);
  186. * 1: incorrect pass or userid (userid|pass too short or already exist);
  187. * 3: registration limit exceeded;
  188. */
  189. int login_mmo_auth_new(const char* userid, const char* pass, const char sex, const char* last_ip) {
  190. static int num_regs = 0; // registration counter
  191. static unsigned int new_reg_tick = 0;
  192. unsigned int tick = gettick();
  193. struct mmo_account acc;
  194. //Account Registration Flood Protection by [Kevin]
  195. if( new_reg_tick == 0 )
  196. new_reg_tick = gettick();
  197. if( DIFF_TICK(tick, new_reg_tick) < 0 && num_regs >= login_config.allowed_regs ) {
  198. ShowNotice("Account registration denied (registration limit exceeded)\n");
  199. return 3;
  200. }
  201. if( login_config.new_acc_length_limit && ( strlen(userid) < 4 || strlen(pass) < 4 ) )
  202. return 1;
  203. // check for invalid inputs
  204. if( sex != 'M' && sex != 'F' )
  205. return 0; // 0 = Unregistered ID
  206. // check if the account doesn't exist already
  207. if( accounts->load_str(accounts, &acc, userid) ) {
  208. ShowNotice("Attempt of creation of an already existant account (account: %s, sex: %c)\n", userid, sex);
  209. return 1; // 1 = Incorrect Password
  210. }
  211. memset(&acc, '\0', sizeof(acc));
  212. acc.account_id = -1; // assigned by account db
  213. safestrncpy(acc.userid, userid, sizeof(acc.userid));
  214. safestrncpy(acc.pass, pass, sizeof(acc.pass));
  215. acc.sex = sex;
  216. safestrncpy(acc.email, "a@a.com", sizeof(acc.email));
  217. acc.expiration_time = ( login_config.start_limited_time != -1 ) ? time(NULL) + login_config.start_limited_time : 0;
  218. safestrncpy(acc.lastlogin, "", sizeof(acc.lastlogin));
  219. safestrncpy(acc.last_ip, last_ip, sizeof(acc.last_ip));
  220. safestrncpy(acc.birthdate, "", sizeof(acc.birthdate));
  221. safestrncpy(acc.pincode, "", sizeof(acc.pincode));
  222. acc.pincode_change = 0;
  223. acc.char_slots = MIN_CHARS;
  224. #ifdef VIP_ENABLE
  225. acc.vip_time = 0;
  226. acc.old_group = 0;
  227. #endif
  228. if( !accounts->create(accounts, &acc) )
  229. return 0;
  230. ShowNotice("Account creation (account %s, id: %d, sex: %c)\n", acc.userid, acc.account_id, acc.sex);
  231. if( DIFF_TICK(tick, new_reg_tick) > 0 ) {// Update the registration check.
  232. num_regs = 0;
  233. new_reg_tick = tick + login_config.time_allowed*1000;
  234. }
  235. ++num_regs;
  236. return -1;
  237. }
  238. /**
  239. * Check/authentication of a connection.
  240. * @param sd: string (atm:md5key or dbpass)
  241. * @param isServer: string (atm:md5key or dbpass)
  242. * @return :
  243. * -1: success
  244. * 0: unregistered id;
  245. * 1: incorrect pass;
  246. * 2: expired id
  247. * 3: blacklisted (or registration limit exceeded if new acc);
  248. * 5: invalid client_version|hash;
  249. * 6: banned
  250. * x: acc state (TODO document me deeper)
  251. */
  252. int login_mmo_auth(struct login_session_data* sd, bool isServer) {
  253. struct mmo_account acc;
  254. int len;
  255. char ip[16];
  256. ip2str(session[sd->fd]->client_addr, ip);
  257. // DNS Blacklist check
  258. if( login_config.use_dnsbl ) {
  259. char r_ip[16];
  260. char ip_dnsbl[256];
  261. char* dnsbl_serv;
  262. uint8* sin_addr = (uint8*)&session[sd->fd]->client_addr;
  263. sprintf(r_ip, "%u.%u.%u.%u", sin_addr[0], sin_addr[1], sin_addr[2], sin_addr[3]);
  264. for( dnsbl_serv = strtok(login_config.dnsbl_servs,","); dnsbl_serv != NULL; dnsbl_serv = strtok(NULL,",") ) {
  265. sprintf(ip_dnsbl, "%s.%s", r_ip, trim(dnsbl_serv));
  266. if( host2ip(ip_dnsbl) ) {
  267. ShowInfo("DNSBL: (%s) Blacklisted. User Kicked.\n", r_ip);
  268. return 3;
  269. }
  270. }
  271. }
  272. len = strnlen(sd->userid, NAME_LENGTH);
  273. // Account creation with _M/_F
  274. if( login_config.new_account_flag ) {
  275. if( len > 2 && strnlen(sd->passwd, NAME_LENGTH) > 0 && // valid user and password lengths
  276. sd->passwdenc == 0 && // unencoded password
  277. sd->userid[len-2] == '_' && memchr("FfMm", sd->userid[len-1], 4) ) // _M/_F suffix
  278. {
  279. int result;
  280. // remove the _M/_F suffix
  281. len -= 2;
  282. sd->userid[len] = '\0';
  283. result = login_mmo_auth_new(sd->userid, sd->passwd, TOUPPER(sd->userid[len+1]), ip);
  284. if( result != -1 )
  285. return result;// Failed to make account. [Skotlex].
  286. }
  287. }
  288. if( !accounts->load_str(accounts, &acc, sd->userid) ) {
  289. ShowNotice("Unknown account (account: %s, ip: %s)\n", sd->userid, ip);
  290. return 0; // 0 = Unregistered ID
  291. }
  292. if( !login_check_password(sd->md5key, sd->passwdenc, sd->passwd, acc.pass) ) {
  293. ShowNotice("Invalid password (account: '%s', ip: %s)\n", sd->userid, ip);
  294. return 1; // 1 = Incorrect Password
  295. }
  296. if( acc.expiration_time != 0 && acc.expiration_time < time(NULL) ) {
  297. ShowNotice("Connection refused (account: %s, expired ID, ip: %s)\n", sd->userid, ip);
  298. return 2; // 2 = This ID is expired
  299. }
  300. if( acc.unban_time != 0 && acc.unban_time > time(NULL) ) {
  301. char tmpstr[24];
  302. timestamp2string(tmpstr, sizeof(tmpstr), acc.unban_time, login_config.date_format);
  303. ShowNotice("Connection refused (account: %s, banned until %s, ip: %s)\n", sd->userid, tmpstr, ip);
  304. return 6; // 6 = Your are Prohibited to log in until %s
  305. }
  306. if( acc.state != 0 ) {
  307. ShowNotice("Connection refused (account: %s, state: %d, ip: %s)\n", sd->userid, acc.state, ip);
  308. return acc.state - 1;
  309. }
  310. if( login_config.client_hash_check && !isServer ) {
  311. struct client_hash_node *node = NULL;
  312. bool match = false;
  313. for( node = login_config.client_hash_nodes; node; node = node->next ) {
  314. if( acc.group_id < node->group_id )
  315. continue;
  316. if( *node->hash == '\0' // Allowed to login without hash
  317. || (sd->has_client_hash && memcmp(node->hash, sd->client_hash, 16) == 0 ) // Correct hash
  318. ) {
  319. match = true;
  320. break;
  321. }
  322. }
  323. if( !match ) {
  324. char smd5[33];
  325. int i;
  326. if( !sd->has_client_hash ) {
  327. ShowNotice("Client didn't send client hash (account: %s, ip: %s)\n", sd->userid, acc.state, ip);
  328. return 5;
  329. }
  330. for( i = 0; i < 16; i++ )
  331. sprintf(&smd5[i * 2], "%02x", sd->client_hash[i]);
  332. ShowNotice("Invalid client hash (account: %s, sent md5: %d, ip: %s)\n", sd->userid, smd5, ip);
  333. return 5;
  334. }
  335. }
  336. ShowNotice("Authentication accepted (account: %s, id: %d, ip: %s)\n", sd->userid, acc.account_id, ip);
  337. // update session data
  338. sd->account_id = acc.account_id;
  339. sd->login_id1 = rnd() + 1;
  340. sd->login_id2 = rnd() + 1;
  341. safestrncpy(sd->lastlogin, acc.lastlogin, sizeof(sd->lastlogin));
  342. sd->sex = acc.sex;
  343. sd->group_id = acc.group_id;
  344. // update account data
  345. timestamp2string(acc.lastlogin, sizeof(acc.lastlogin), time(NULL), "%Y-%m-%d %H:%M:%S");
  346. safestrncpy(acc.last_ip, ip, sizeof(acc.last_ip));
  347. acc.unban_time = 0;
  348. acc.logincount++;
  349. accounts->save(accounts, &acc);
  350. if( sd->sex != 'S' && sd->account_id < START_ACCOUNT_NUM )
  351. 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);
  352. return -1; // account OK
  353. }
  354. /**
  355. * Sub function of login_check_password.
  356. * Checking if password matches the one in db hashed with client md5key.
  357. * Test if(md5(str1+str2)==passwd).
  358. * @param str1: string (atm:md5key or dbpass)
  359. * @param str2: string (atm:md5key or dbpass)
  360. * @param passwd: pass to check
  361. * @return true if matching else false
  362. */
  363. bool login_check_encrypted(const char* str1, const char* str2, const char* passwd) {
  364. char tmpstr[64+1], md5str[32+1];
  365. safesnprintf(tmpstr, sizeof(tmpstr), "%s%s", str1, str2);
  366. MD5_String(tmpstr, md5str);
  367. return (0==strcmp(passwd, md5str));
  368. }
  369. /**
  370. * Verify if a password is correct.
  371. * @param md5key: md5key of client
  372. * @param passwdenc: encode key of client
  373. * @param passwd: pass to check
  374. * @param refpass: pass register in db
  375. * @return true if matching else false
  376. */
  377. bool login_check_password(const char* md5key, int passwdenc, const char* passwd, const char* refpass) {
  378. if(passwdenc == 0){
  379. return (0==strcmp(passwd, refpass));
  380. }
  381. else {
  382. // password mode set to 1 -> md5(md5key, refpass) enable with <passwordencrypt></passwordencrypt>
  383. // password mode set to 2 -> md5(refpass, md5key) enable with <passwordencrypt2></passwordencrypt2>
  384. return ((passwdenc&0x01) && login_check_encrypted(md5key, refpass, passwd)) ||
  385. ((passwdenc&0x02) && login_check_encrypted(refpass, md5key, passwd));
  386. }
  387. }
  388. /**
  389. * Test to determine if an IP come from LAN or WAN.
  390. * @param ip: ip to check if in auth network
  391. * @return 0 if from wan, or subnet_char_ip if lan
  392. */
  393. int lan_subnetcheck(uint32 ip) {
  394. int i;
  395. ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) );
  396. return ( i < subnet_count ) ? subnet[i].char_ip : 0;
  397. }
  398. /// Msg_conf tayloring
  399. int login_msg_config_read(char *cfgName){
  400. return _msg_config_read(cfgName,LOGIN_MAX_MSG,msg_table);
  401. }
  402. const char* login_msg_txt(int msg_number){
  403. return _msg_txt(msg_number,LOGIN_MAX_MSG,msg_table);
  404. }
  405. void login_do_final_msg(void){
  406. _do_final_msg(LOGIN_MAX_MSG,msg_table);
  407. }
  408. /// Set and read Configurations
  409. /**
  410. * Reading Lan Support configuration.
  411. * @param lancfgName: Name of the lan configuration (could be fullpath)
  412. * @return 0:success, 1:failure (file not found|readable)
  413. */
  414. int login_lan_config_read(const char *lancfgName) {
  415. FILE *fp;
  416. int line_num = 0, s_subnet=ARRAYLENGTH(subnet);
  417. char line[1024], w1[64], w2[64], w3[64], w4[64];
  418. if((fp = fopen(lancfgName, "r")) == NULL) {
  419. ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName);
  420. return 1;
  421. }
  422. while(fgets(line, sizeof(line), fp))
  423. {
  424. line_num++;
  425. if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n')
  426. continue;
  427. if(sscanf(line,"%63[^:]: %63[^:]:%63[^:]:%63[^\r\n]", w1, w2, w3, w4) != 4)
  428. {
  429. ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num);
  430. continue;
  431. }
  432. if( strcmpi(w1, "subnet") == 0 ){
  433. if(subnet_count>=s_subnet) { //We skip instead of break in case we want to add other conf in that file.
  434. ShowError("%s: Too many subnets defined, skipping line %d...\n", lancfgName, line_num);
  435. continue;
  436. }
  437. subnet[subnet_count].mask = str2ip(w2);
  438. subnet[subnet_count].char_ip = str2ip(w3);
  439. subnet[subnet_count].map_ip = str2ip(w4);
  440. if( (subnet[subnet_count].char_ip & subnet[subnet_count].mask) != (subnet[subnet_count].map_ip & subnet[subnet_count].mask) )
  441. {
  442. ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4);
  443. continue;
  444. }
  445. subnet_count++;
  446. }
  447. }
  448. if( subnet_count > 1 ) /* only useful if there is more than 1 available */
  449. ShowStatus("Read information about %d subnetworks.\n", subnet_count);
  450. fclose(fp);
  451. return 0;
  452. }
  453. /**
  454. * Reading main configuration file.
  455. * @param cfgName: Name of the configuration (could be fullpath)
  456. * @param normal: Config read normally when server started
  457. * @return True:success, Fals:failure (file not found|readable)
  458. */
  459. bool login_config_read(const char* cfgName, bool normal) {
  460. char line[1024], w1[32], w2[1024];
  461. FILE* fp = fopen(cfgName, "r");
  462. if (fp == NULL) {
  463. ShowError("Configuration file (%s) not found.\n", cfgName);
  464. return false;
  465. }
  466. while(fgets(line, sizeof(line), fp)) {
  467. if (line[0] == '/' && line[1] == '/')
  468. continue;
  469. if (sscanf(line, "%31[^:]: %1023[^\r\n]", w1, w2) < 2)
  470. continue;
  471. // Config that loaded only when server started, not by reloading config file
  472. if (normal) {
  473. if( !strcmpi(w1, "bind_ip") ) {
  474. login_config.login_ip = host2ip(w2);
  475. if( login_config.login_ip ) {
  476. char ip_str[16];
  477. ShowStatus("Login server binding IP address : %s -> %s\n", w2, ip2str(login_config.login_ip, ip_str));
  478. }
  479. }
  480. else if( !strcmpi(w1, "login_port") )
  481. login_config.login_port = (uint16)atoi(w2);
  482. else if(!strcmpi(w1, "console"))
  483. login_config.console = (bool)config_switch(w2);
  484. }
  485. if(!strcmpi(w1,"timestamp_format"))
  486. safestrncpy(timestamp_format, w2, 20);
  487. else if(strcmpi(w1,"db_path")==0)
  488. safestrncpy(db_path, w2, ARRAYLENGTH(db_path));
  489. else if(!strcmpi(w1,"stdout_with_ansisequence"))
  490. stdout_with_ansisequence = config_switch(w2);
  491. else if(!strcmpi(w1,"console_silent")) {
  492. msg_silent = atoi(w2);
  493. if( msg_silent ) /* only bother if we actually have this enabled */
  494. ShowInfo("Console Silent Setting: %d\n", atoi(w2));
  495. }
  496. else if (strcmpi(w1, "console_msg_log") == 0)
  497. console_msg_log = atoi(w2);
  498. else if (strcmpi(w1, "console_log_filepath") == 0)
  499. safestrncpy(console_log_filepath, w2, sizeof(console_log_filepath));
  500. else if(!strcmpi(w1, "log_login"))
  501. login_config.log_login = (bool)config_switch(w2);
  502. else if(!strcmpi(w1, "new_account"))
  503. login_config.new_account_flag = (bool)config_switch(w2);
  504. else if(!strcmpi(w1, "new_acc_length_limit"))
  505. login_config.new_acc_length_limit = (bool)config_switch(w2);
  506. else if(!strcmpi(w1, "start_limited_time"))
  507. login_config.start_limited_time = atoi(w2);
  508. else if(!strcmpi(w1, "use_MD5_passwords"))
  509. login_config.use_md5_passwds = (bool)config_switch(w2);
  510. else if(!strcmpi(w1, "group_id_to_connect"))
  511. login_config.group_id_to_connect = atoi(w2);
  512. else if(!strcmpi(w1, "min_group_id_to_connect"))
  513. login_config.min_group_id_to_connect = atoi(w2);
  514. else if(!strcmpi(w1, "date_format"))
  515. safestrncpy(login_config.date_format, w2, sizeof(login_config.date_format));
  516. else if(!strcmpi(w1, "allowed_regs")) //account flood protection system
  517. login_config.allowed_regs = atoi(w2);
  518. else if(!strcmpi(w1, "time_allowed"))
  519. login_config.time_allowed = atoi(w2);
  520. else if(!strcmpi(w1, "use_dnsbl"))
  521. login_config.use_dnsbl = (bool)config_switch(w2);
  522. else if(!strcmpi(w1, "dnsbl_servers"))
  523. safestrncpy(login_config.dnsbl_servs, w2, sizeof(login_config.dnsbl_servs));
  524. else if(!strcmpi(w1, "ipban_cleanup_interval"))
  525. login_config.ipban_cleanup_interval = (unsigned int)atoi(w2);
  526. else if(!strcmpi(w1, "ip_sync_interval"))
  527. login_config.ip_sync_interval = (unsigned int)1000*60*atoi(w2); //w2 comes in minutes.
  528. else if(!strcmpi(w1, "client_hash_check"))
  529. login_config.client_hash_check = config_switch(w2);
  530. else if(!strcmpi(w1, "client_hash")) {
  531. int group = 0;
  532. char md5[33];
  533. if (sscanf(w2, "%3d, %32s", &group, md5) == 2) {
  534. struct client_hash_node *nnode;
  535. CREATE(nnode, struct client_hash_node, 1);
  536. if (strcmpi(md5, "disabled") == 0) {
  537. nnode->hash[0] = '\0';
  538. } else {
  539. int i;
  540. for (i = 0; i < 32; i += 2) {
  541. char buf[3];
  542. unsigned int byte;
  543. memcpy(buf, &md5[i], 2);
  544. buf[2] = 0;
  545. sscanf(buf, "%2x", &byte);
  546. nnode->hash[i / 2] = (uint8)(byte & 0xFF);
  547. }
  548. }
  549. nnode->group_id = group;
  550. nnode->next = login_config.client_hash_nodes;
  551. login_config.client_hash_nodes = nnode;
  552. }
  553. } else if(strcmpi(w1, "chars_per_account") == 0) { //maxchars per account [Sirius]
  554. login_config.char_per_account = atoi(w2);
  555. if( login_config.char_per_account <= 0 || login_config.char_per_account > MAX_CHARS ) {
  556. if( login_config.char_per_account > MAX_CHARS ) {
  557. ShowWarning("Max chars per account '%d' exceeded limit. Defaulting to '%d'.\n", login_config.char_per_account, MAX_CHARS);
  558. login_config.char_per_account = MAX_CHARS;
  559. }
  560. login_config.char_per_account = MIN_CHARS;
  561. }
  562. }
  563. #ifdef VIP_ENABLE
  564. else if(strcmpi(w1,"vip_group")==0)
  565. login_config.vip_sys.group = cap_value(atoi(w2),0,99);
  566. else if(strcmpi(w1,"vip_char_increase")==0) {
  567. if (atoi(w2) == -1)
  568. login_config.vip_sys.char_increase = MAX_CHAR_VIP;
  569. else
  570. login_config.vip_sys.char_increase = atoi(w2);
  571. if (login_config.vip_sys.char_increase > (unsigned int) MAX_CHARS-login_config.char_per_account) {
  572. ShowWarning("vip_char_increase too high, can only go up to %d, according to your char_per_account config %d\n",
  573. MAX_CHARS-login_config.char_per_account,login_config.char_per_account);
  574. login_config.vip_sys.char_increase = MAX_CHARS-login_config.char_per_account;
  575. }
  576. }
  577. #endif
  578. else if(!strcmpi(w1, "import"))
  579. login_config_read(w2, normal);
  580. else {// try the account engines
  581. if (!normal)
  582. continue;
  583. if (accounts && accounts->set_property(accounts, w1, w2))
  584. continue;
  585. // try others
  586. ipban_config_read(w1, w2);
  587. loginlog_config_read(w1, w2);
  588. }
  589. }
  590. fclose(fp);
  591. ShowInfo("Finished reading %s.\n", cfgName);
  592. return true;
  593. }
  594. /**
  595. * Init login-serv default configuration.
  596. */
  597. void login_set_defaults() {
  598. login_config.login_ip = INADDR_ANY;
  599. login_config.login_port = 6900;
  600. login_config.ipban_cleanup_interval = 60;
  601. login_config.ip_sync_interval = 0;
  602. login_config.log_login = true;
  603. safestrncpy(login_config.date_format, "%Y-%m-%d %H:%M:%S", sizeof(login_config.date_format));
  604. login_config.console = false;
  605. login_config.new_account_flag = true;
  606. login_config.new_acc_length_limit = true;
  607. login_config.use_md5_passwds = false;
  608. login_config.group_id_to_connect = -1;
  609. login_config.min_group_id_to_connect = -1;
  610. login_config.ipban = true;
  611. login_config.dynamic_pass_failure_ban = true;
  612. login_config.dynamic_pass_failure_ban_interval = 5;
  613. login_config.dynamic_pass_failure_ban_limit = 7;
  614. login_config.dynamic_pass_failure_ban_duration = 5;
  615. login_config.use_dnsbl = false;
  616. safestrncpy(login_config.dnsbl_servs, "", sizeof(login_config.dnsbl_servs));
  617. login_config.allowed_regs = 1;
  618. login_config.time_allowed = 10; //in second
  619. login_config.client_hash_check = 0;
  620. login_config.client_hash_nodes = NULL;
  621. login_config.char_per_account = MAX_CHARS - MAX_CHAR_VIP - MAX_CHAR_BILLING;
  622. #ifdef VIP_ENABLE
  623. login_config.vip_sys.char_increase = MAX_CHAR_VIP;
  624. login_config.vip_sys.group = 5;
  625. #endif
  626. //other default conf
  627. safestrncpy(login_config.loginconf_name, "conf/login_athena.conf", sizeof(login_config.loginconf_name));
  628. safestrncpy(login_config.lanconf_name, "conf/subnet_athena.conf", sizeof(login_config.lanconf_name));
  629. safestrncpy(login_config.msgconf_name, "conf/msg_conf/login_msg.conf", sizeof(login_config.msgconf_name));
  630. }
  631. /// Constructor destructor and signal handlers
  632. /**
  633. * Login-serv destructor
  634. * dealloc..., function called at exit of the login-serv
  635. */
  636. void do_final(void) {
  637. struct client_hash_node *hn = login_config.client_hash_nodes;
  638. AccountDB* db = accounts;
  639. while (hn)
  640. {
  641. struct client_hash_node *tmp = hn;
  642. hn = hn->next;
  643. aFree(tmp);
  644. }
  645. login_log(0, "login server", 100, "login server shutdown");
  646. ShowStatus("Terminating...\n");
  647. if( login_config.log_login )
  648. loginlog_final();
  649. do_final_msg();
  650. ipban_final();
  651. do_final_loginclif();
  652. do_final_logincnslif();
  653. if (db) { // destroy account engine
  654. db->destroy(db);
  655. db = NULL;
  656. }
  657. accounts = NULL; // destroyed in account_engine
  658. online_db->destroy(online_db, NULL);
  659. auth_db->destroy(auth_db, NULL);
  660. do_final_loginchrif();
  661. if( login_fd != -1 )
  662. {
  663. do_close(login_fd);
  664. login_fd = -1;
  665. }
  666. ShowStatus("Finished.\n");
  667. }
  668. /**
  669. * Signal handler
  670. * This function attempts to properly close the server when an interrupt signal is received.
  671. * current signal catch : SIGTERM, SIGINT
  672. */
  673. void do_shutdown(void) {
  674. if( runflag != LOGINSERVER_ST_SHUTDOWN ) {
  675. runflag = LOGINSERVER_ST_SHUTDOWN;
  676. ShowStatus("Shutting down...\n");
  677. // TODO proper shutdown procedure; kick all characters, wait for acks, ... [FlavioJS]
  678. do_shutdown_loginchrif();
  679. flush_fifos();
  680. runflag = CORE_ST_STOP;
  681. }
  682. }
  683. /**
  684. * Signal handler
  685. * Function called when the server has received a crash signal.
  686. * current signal catch : SIGSEGV, SIGFPE
  687. */
  688. void do_abort(void) {
  689. }
  690. // Is this still used ??
  691. void set_server_type(void) {
  692. SERVER_TYPE = ATHENA_SERVER_LOGIN;
  693. }
  694. /**
  695. * Login serv constructor
  696. * Initialisation, function called at start of the login-serv.
  697. * @param argc : number of argument from main()
  698. * @param argv : arguments values from main()
  699. * @return 0 everything ok else stopping programme execution.
  700. */
  701. int do_init(int argc, char** argv) {
  702. runflag = LOGINSERVER_ST_STARTING;
  703. // Init default value
  704. safestrncpy(console_log_filepath, "./log/login-msg_log.log", sizeof(console_log_filepath));
  705. // initialize engine
  706. accounts = account_db_sql();
  707. // read login-server configuration
  708. login_set_defaults();
  709. logcnslif_get_options(argc,argv);
  710. login_config_read(login_config.loginconf_name, true);
  711. msg_config_read(login_config.msgconf_name);
  712. login_lan_config_read(login_config.lanconf_name);
  713. //end config
  714. rnd_init();
  715. do_init_loginclif();
  716. do_init_loginchrif();
  717. // initialize logging
  718. if( login_config.log_login )
  719. loginlog_init();
  720. // initialize static and dynamic ipban system
  721. ipban_init();
  722. // Online user database init
  723. online_db = idb_alloc(DB_OPT_RELEASE_DATA);
  724. add_timer_func_list(login_waiting_disconnect_timer, "waiting_disconnect_timer");
  725. // Interserver auth init
  726. auth_db = idb_alloc(DB_OPT_RELEASE_DATA);
  727. // set default parser as parse_login function
  728. set_defaultparse(logclif_parse);
  729. // every 10 minutes cleanup online account db.
  730. add_timer_func_list(login_online_data_cleanup, "online_data_cleanup");
  731. add_timer_interval(gettick() + 600*1000, login_online_data_cleanup, 0, 0, 600*1000);
  732. // Account database init
  733. if( accounts == NULL ) {
  734. ShowFatalError("do_init: account engine not found.\n");
  735. exit(EXIT_FAILURE);
  736. } else {
  737. if(!accounts->init(accounts)) {
  738. ShowFatalError("do_init: Failed to initialize account engine.\n");
  739. exit(EXIT_FAILURE);
  740. }
  741. }
  742. // server port open & binding
  743. if( (login_fd = make_listen_bind(login_config.login_ip,login_config.login_port)) == -1 ) {
  744. ShowFatalError("Failed to bind to port '" CL_WHITE "%d" CL_RESET "'\n",login_config.login_port);
  745. exit(EXIT_FAILURE);
  746. }
  747. if( runflag != CORE_ST_STOP ) {
  748. shutdown_callback = do_shutdown;
  749. runflag = LOGINSERVER_ST_RUNNING;
  750. }
  751. do_init_logincnslif();
  752. ShowStatus("The login-server is " CL_GREEN "ready" CL_RESET " (Server is listening on the port %u).\n\n", login_config.login_port);
  753. login_log(0, "login server", 100, "login server started");
  754. return 0;
  755. }