Advertisement
akbare

login.c

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