login.c 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035
  1. // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <sys/stat.h> // for stat/lstat/fstat
  6. #include <signal.h>
  7. #include <fcntl.h>
  8. #include <string.h>
  9. #include "../common/cbasetypes.h"
  10. #include "../common/core.h"
  11. #include "../common/socket.h"
  12. #include "../common/db.h"
  13. #include "../common/timer.h"
  14. #include "../common/malloc.h"
  15. #include "../common/strlib.h"
  16. #include "../common/mmo.h"
  17. #include "../common/showmsg.h"
  18. #include "../common/version.h"
  19. #include "../common/md5calc.h"
  20. #include "login.h"
  21. //add include for DBMS(mysql)
  22. #include <mysql.h>
  23. struct Login_Config {
  24. uint32 login_ip; // the address to bind to
  25. uint16 login_port; // the port to bind to
  26. bool log_login; // whether to log login server actions or not
  27. char date_format[32]; // date format used in messages
  28. bool console; // console input system enabled?
  29. unsigned int ip_sync_interval; // interval (in minutes) to execute a DNS/IP update (for dynamic IPs)
  30. int min_level_to_connect; // minimum level of player/GM (0: player, 1-99: gm) to connect
  31. bool new_account_flag; // autoregistration via _M/_F ?
  32. bool case_sensitive; // are logins case sensitive ?
  33. bool use_md5_passwds; // work with password hashes instead of plaintext passwords?
  34. bool login_gm_read; // should the login server handle info about gm accounts?
  35. bool online_check; // reject incoming players that are already registered as online ?
  36. bool check_client_version; // check the clientversion set in the clientinfo ?
  37. unsigned int client_version_to_connect; // the client version needed to connect (if checking is enabled)
  38. bool ipban; // perform IP blocking (via contents of `ipbanlist`) ?
  39. bool dynamic_pass_failure_ban; // automatic IP blocking due to failed login attemps ?
  40. unsigned int dynamic_pass_failure_ban_interval; // how far to scan the loginlog for password failures
  41. unsigned int dynamic_pass_failure_ban_limit; // number of failures needed to trigger the ipban
  42. unsigned int dynamic_pass_failure_ban_duration; // duration of the ipban
  43. bool use_dnsbl; // dns blacklist blocking ?
  44. char dnsbl_servs[1024]; // comma-separated list of dnsbl servers
  45. } login_config;
  46. int login_fd; // login server socket
  47. int server_num; // number of connected char servers
  48. int server_fd[MAX_SERVERS]; // char server sockets
  49. struct mmo_char_server server[MAX_SERVERS]; // char server data
  50. // Advanced subnet check [LuzZza]
  51. struct _subnet {
  52. uint32 subnet;
  53. uint32 mask;
  54. uint32 char_ip;
  55. uint32 map_ip;
  56. } subnet[16];
  57. int subnet_count = 0;
  58. struct gm_account* gm_account_db = NULL;
  59. unsigned int GM_num = 0; // number of gm accounts
  60. //Account registration flood protection [Kevin]
  61. int allowed_regs = 1;
  62. int time_allowed = 10; //in seconds
  63. int num_regs = 0;
  64. unsigned int new_reg_tick = 0;
  65. MYSQL mysql_handle;
  66. MYSQL_RES* sql_res ;
  67. MYSQL_ROW sql_row ;
  68. char tmpsql[65535];
  69. // database parameters
  70. int login_server_port = 3306;
  71. char login_server_ip[32] = "127.0.0.1";
  72. char login_server_id[32] = "ragnarok";
  73. char login_server_pw[32] = "ragnarok";
  74. char login_server_db[32] = "ragnarok";
  75. char default_codepage[32] = "";
  76. char login_db[256] = "login";
  77. char loginlog_db[256] = "loginlog";
  78. char reg_db[256] = "global_reg_value";
  79. // added to help out custom login tables, without having to recompile
  80. // source so options are kept in the login_athena.conf or the inter_athena.conf
  81. char login_db_account_id[256] = "account_id";
  82. char login_db_userid[256] = "userid";
  83. char login_db_user_pass[256] = "user_pass";
  84. char login_db_level[256] = "level";
  85. //-----------------------------------------------------
  86. struct login_session_data {
  87. uint16 md5keylen;
  88. char md5key[20];
  89. };
  90. #define AUTH_FIFO_SIZE 256
  91. struct {
  92. int account_id, login_id1, login_id2;
  93. uint32 ip;
  94. char sex;
  95. bool delflag;
  96. } auth_fifo[AUTH_FIFO_SIZE];
  97. int auth_fifo_pos = 0;
  98. struct online_login_data {
  99. int account_id;
  100. int waiting_disconnect;
  101. short char_server;
  102. };
  103. //-----------------------------------------------------
  104. struct dbt *online_db;
  105. static void* create_online_user(DBKey key, va_list args)
  106. {
  107. struct online_login_data *p;
  108. p = aCalloc(1, sizeof(struct online_login_data));
  109. p->account_id = key.i;
  110. p->char_server = -1;
  111. p->waiting_disconnect = -1;
  112. return p;
  113. }
  114. int charif_sendallwos(int sfd, unsigned char *buf, unsigned int len);
  115. static int waiting_disconnect_timer(int tid, unsigned int tick, int id, int data);
  116. //-----------------------------------------------------
  117. // Online User Database [Wizputer]
  118. //-----------------------------------------------------
  119. void add_online_user(int char_server, int account_id)
  120. {
  121. struct online_login_data *p;
  122. if (!login_config.online_check)
  123. return;
  124. p = idb_ensure(online_db, account_id, create_online_user);
  125. p->char_server = char_server;
  126. if (p->waiting_disconnect != -1)
  127. {
  128. delete_timer(p->waiting_disconnect, waiting_disconnect_timer);
  129. p->waiting_disconnect = -1;
  130. }
  131. }
  132. void remove_online_user(int account_id)
  133. {
  134. if(!login_config.online_check)
  135. return;
  136. if (account_id == 99) { // reset all to offline
  137. online_db->clear(online_db, NULL); // purge db
  138. return;
  139. }
  140. idb_remove(online_db,account_id);
  141. }
  142. static int waiting_disconnect_timer(int tid, unsigned int tick, int id, int data)
  143. {
  144. struct online_login_data *p;
  145. if ((p= idb_get(online_db, id)) != NULL && p->waiting_disconnect == id)
  146. {
  147. p->waiting_disconnect = -1;
  148. remove_online_user(id);
  149. }
  150. return 0;
  151. }
  152. static int sync_ip_addresses(int tid, unsigned int tick, int id, int data)
  153. {
  154. unsigned char buf[2];
  155. ShowInfo("IP Sync in progress...\n");
  156. WBUFW(buf,0) = 0x2735;
  157. charif_sendallwos(-1, buf, 2);
  158. return 0;
  159. }
  160. //-----------------------------------------------------
  161. // Read GM accounts
  162. //-----------------------------------------------------
  163. void read_gm_account(void)
  164. {
  165. if(!login_config.login_gm_read)
  166. return;
  167. sprintf(tmpsql, "SELECT `%s`,`%s` FROM `%s` WHERE `%s`> '0'",login_db_account_id,login_db_level,login_db,login_db_level);
  168. if (mysql_query(&mysql_handle, tmpsql)) {
  169. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  170. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  171. return; //Failed to read GM list!
  172. }
  173. if (gm_account_db != NULL)
  174. {
  175. aFree(gm_account_db);
  176. gm_account_db = NULL;
  177. }
  178. GM_num = 0;
  179. sql_res = mysql_store_result(&mysql_handle);
  180. if (sql_res) {
  181. gm_account_db = (struct gm_account*)aCalloc((size_t)mysql_num_rows(sql_res), sizeof(struct gm_account));
  182. while ((sql_row = mysql_fetch_row(sql_res))) {
  183. gm_account_db[GM_num].account_id = atoi(sql_row[0]);
  184. gm_account_db[GM_num].level = atoi(sql_row[1]);
  185. GM_num++;
  186. }
  187. mysql_free_result(sql_res);
  188. }
  189. }
  190. //-----------------------------------------------------
  191. // Send GM accounts to all char-server
  192. //-----------------------------------------------------
  193. void send_GM_accounts(int fd)
  194. {
  195. unsigned int i;
  196. unsigned char buf[32767];
  197. int len;
  198. if(!login_config.login_gm_read)
  199. return;
  200. len = 4;
  201. WBUFW(buf,0) = 0x2732;
  202. for(i = 0; i < GM_num; i++)
  203. // send only existing accounts. We can not create a GM account when server is online.
  204. if (gm_account_db[i].level > 0) {
  205. WBUFL(buf,len) = gm_account_db[i].account_id;
  206. WBUFB(buf,len+4) = (unsigned char)gm_account_db[i].level;
  207. len += 5;
  208. if (len >= 32000) {
  209. ShowWarning("send_GM_accounts: Too many accounts! Only %d out of %d were sent.\n", i, GM_num);
  210. break;
  211. }
  212. }
  213. WBUFW(buf,2) = len;
  214. if (fd == -1)
  215. charif_sendallwos(-1, buf, len);
  216. else
  217. {
  218. WFIFOHEAD(fd,len);
  219. memcpy(WFIFOP(fd,0), buf, len);
  220. WFIFOSET(fd,len);
  221. }
  222. return;
  223. }
  224. /*=============================================
  225. * Does a mysql_ping to all connection handles
  226. *---------------------------------------------*/
  227. int login_sql_ping(int tid, unsigned int tick, int id, int data)
  228. {
  229. ShowInfo("Pinging SQL server to keep connection alive...\n");
  230. mysql_ping(&mysql_handle);
  231. return 0;
  232. }
  233. int sql_ping_init(void)
  234. {
  235. int connection_timeout, connection_ping_interval;
  236. // set a default value first
  237. connection_timeout = 28800; // 8 hours
  238. // ask the mysql server for the timeout value
  239. if (!mysql_query(&mysql_handle, "SHOW VARIABLES LIKE 'wait_timeout'")
  240. && (sql_res = mysql_store_result(&mysql_handle)) != NULL) {
  241. sql_row = mysql_fetch_row(sql_res);
  242. if (sql_row)
  243. connection_timeout = atoi(sql_row[1]);
  244. if (connection_timeout < 60)
  245. connection_timeout = 60;
  246. mysql_free_result(sql_res);
  247. }
  248. // establish keepalive
  249. connection_ping_interval = connection_timeout - 30; // 30-second reserve
  250. add_timer_func_list(login_sql_ping, "login_sql_ping");
  251. add_timer_interval(gettick() + connection_ping_interval*1000, login_sql_ping, 0, 0, connection_ping_interval*1000);
  252. return 0;
  253. }
  254. //-----------------------------------------------------
  255. // Read Account database - mysql db
  256. //-----------------------------------------------------
  257. int mmo_auth_sqldb_init(void)
  258. {
  259. ShowStatus("Login server init....\n");
  260. mysql_init(&mysql_handle);
  261. // DB connection start
  262. ShowStatus("Connect Login Database Server....\n");
  263. if (!mysql_real_connect(&mysql_handle, login_server_ip, login_server_id, login_server_pw, login_server_db, login_server_port, (char *)NULL, 0)) {
  264. ShowFatalError("%s\n", mysql_error(&mysql_handle));
  265. exit(1);
  266. } else {
  267. ShowStatus("Connect success!\n");
  268. }
  269. if( strlen(default_codepage) > 0 ) {
  270. sprintf( tmpsql, "SET NAMES %s", default_codepage );
  271. if (mysql_query(&mysql_handle, tmpsql)) {
  272. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  273. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  274. }
  275. }
  276. if (login_config.log_login)
  277. {
  278. sprintf(tmpsql, "INSERT DELAYED INTO `%s`(`time`,`ip`,`user`,`rcode`,`log`) VALUES (NOW(), '0', 'lserver','100','login server started')", loginlog_db);
  279. //query
  280. if (mysql_query(&mysql_handle, tmpsql)) {
  281. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  282. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  283. }
  284. }
  285. sql_ping_init();
  286. return 0;
  287. }
  288. //-----------------------------------------------------
  289. // close DB
  290. //-----------------------------------------------------
  291. void mmo_db_close(void)
  292. {
  293. int i, fd;
  294. //set log.
  295. if (login_config.log_login)
  296. {
  297. sprintf(tmpsql,"INSERT DELAYED INTO `%s`(`time`,`ip`,`user`,`rcode`,`log`) VALUES (NOW(), '0', 'lserver','100', 'login server shutdown')", loginlog_db);
  298. //query
  299. if (mysql_query(&mysql_handle, tmpsql)) {
  300. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  301. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  302. }
  303. }
  304. for (i = 0; i < MAX_SERVERS; i++) {
  305. if ((fd = server_fd[i]) >= 0)
  306. { //Clean only data related to servers we are connected to. [Skotlex]
  307. sprintf(tmpsql,"DELETE FROM `sstatus` WHERE `index` = '%d'", i);
  308. if (mysql_query(&mysql_handle, tmpsql))
  309. {
  310. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  311. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  312. }
  313. do_close(fd);
  314. }
  315. }
  316. mysql_close(&mysql_handle);
  317. ShowStatus("close DB connect....\n");
  318. if (login_fd > 0)
  319. do_close(login_fd);
  320. }
  321. //-----------------------------------------------------
  322. // Make new account
  323. //-----------------------------------------------------
  324. int mmo_auth_new(struct mmo_account* account, char sex)
  325. {
  326. unsigned int tick = gettick();
  327. char user_password[256];
  328. //Account Registration Flood Protection by [Kevin]
  329. if(DIFF_TICK(tick, new_reg_tick) < 0 && num_regs >= allowed_regs) {
  330. ShowNotice("Account registration denied (registration limit exceeded)\n");
  331. return 3;
  332. }
  333. //Check for preexisting account
  334. sprintf(tmpsql, "SELECT `%s` FROM `%s` WHERE `userid` = '%s'", login_db_userid, login_db, account->userid);
  335. if(mysql_query(&mysql_handle, tmpsql)){
  336. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  337. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  338. return 1; //Return Incorrect user/pass?
  339. }
  340. sql_res = mysql_store_result(&mysql_handle);
  341. if(mysql_num_rows(sql_res) > 0){
  342. mysql_free_result(sql_res);
  343. return 1; //Already exists, return incorrect user/pass.
  344. }
  345. mysql_free_result(sql_res); //Only needed for the already-exists check...
  346. mysql_real_escape_string(&mysql_handle, account->userid, account->userid, strlen(account->userid));
  347. mysql_real_escape_string(&mysql_handle, account->passwd, account->passwd, strlen(account->passwd));
  348. sex = TOUPPER(sex);
  349. if (login_config.use_md5_passwds)
  350. MD5_String(account->passwd, user_password);
  351. else
  352. jstrescapecpy(user_password, account->passwd);
  353. ShowInfo("New account: user: %s with passwd: %s sex: %c\n", account->userid, user_password, sex);
  354. sprintf(tmpsql, "INSERT INTO `%s` (`%s`, `%s`, `sex`, `email`) VALUES ('%s', '%s', '%c', '%s')", login_db, login_db_userid, login_db_user_pass, account->userid, user_password, sex, "a@a.com");
  355. if(mysql_query(&mysql_handle, tmpsql)){
  356. //Failed to insert new acc :/
  357. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  358. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  359. return 1;
  360. }
  361. if(mysql_field_count(&mysql_handle) == 0 &&
  362. mysql_insert_id(&mysql_handle) < START_ACCOUNT_NUM) {
  363. //Invalid Account ID! Must update it.
  364. int id = (int)mysql_insert_id(&mysql_handle);
  365. sprintf(tmpsql, "UPDATE `%s` SET `%s`='%d' WHERE `%s`='%d'", login_db, login_db_account_id, START_ACCOUNT_NUM, login_db_account_id, id);
  366. if(mysql_query(&mysql_handle, tmpsql)){
  367. ShowError("New account %s has an invalid account ID [%d] which could not be updated (account_id must be %d or higher).", account->userid, id, START_ACCOUNT_NUM);
  368. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  369. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  370. //Just delete it and fail.
  371. sprintf(tmpsql, "DELETE FROM `%s` WHERE `%s`='%d'", login_db, login_db_account_id, id);
  372. if(mysql_query(&mysql_handle, tmpsql)){
  373. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  374. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  375. }
  376. return 1;
  377. }
  378. ShowNotice("Updated New account %s's ID %d->%d (account_id must be %d or higher).", account->userid, id, START_ACCOUNT_NUM, START_ACCOUNT_NUM);
  379. }
  380. if(DIFF_TICK(tick, new_reg_tick) > 0)
  381. { //Update the registration check.
  382. num_regs=0;
  383. new_reg_tick=tick+time_allowed*1000;
  384. }
  385. num_regs++;
  386. return 0;
  387. }
  388. //--------------------------------------------------------------------
  389. // Packet send to all char-servers, except one (wos: without our self)
  390. //--------------------------------------------------------------------
  391. int charif_sendallwos(int sfd, unsigned char *buf, unsigned int len)
  392. {
  393. int i, c, fd;
  394. for(i = 0, c = 0; i < MAX_SERVERS; i++) {
  395. if ((fd = server_fd[i]) > 0 && fd != sfd) {
  396. WFIFOHEAD(fd,len);
  397. if (WFIFOSPACE(fd) < len) //Increase buffer size.
  398. realloc_writefifo(fd, len);
  399. memcpy(WFIFOP(fd,0), buf, len);
  400. WFIFOSET(fd,len);
  401. c++;
  402. }
  403. }
  404. return c;
  405. }
  406. //-----------------------------------------------------
  407. // encrypted/unencrypted password check
  408. //-----------------------------------------------------
  409. bool check_encrypted(const char* str1, const char* str2, const char* passwd)
  410. {
  411. char md5str[64], md5bin[32];
  412. snprintf(md5str, sizeof(md5str), "%s%s", str1, str2); md5str[sizeof(md5str)-1] = '\0';
  413. MD5_String2binary(md5str, md5bin);
  414. return (0==memcmp(passwd, md5bin, 16));
  415. }
  416. bool check_password(struct login_session_data* ld, int passwdenc, const char* passwd, const char* refpass)
  417. {
  418. if(passwdenc == 0)
  419. {
  420. return (0==strcmp(passwd, refpass));
  421. }
  422. else if (ld)
  423. {
  424. // password mode set to 1 -> (md5key, refpass) enable with <passwordencrypt></passwordencrypt>
  425. // password mode set to 2 -> (refpass, md5key) enable with <passwordencrypt2></passwordencrypt2>
  426. return ((passwdenc&0x01) && check_encrypted(ld->md5key, refpass, passwd)) ||
  427. ((passwdenc&0x02) && check_encrypted(refpass, ld->md5key, passwd));
  428. }
  429. return false;
  430. }
  431. //-----------------------------------------------------
  432. // Check/authentication of a connection
  433. //-----------------------------------------------------
  434. int mmo_auth(struct mmo_account* account, int fd)
  435. {
  436. time_t ban_until_time;
  437. char t_uid[256];
  438. char user_password[256], password[256];
  439. long connect_until;
  440. int encpasswdok = 0, state;
  441. char ip[16];
  442. uint32 ipl = session[fd]->client_addr;
  443. uint8* sin_addr = (uint8*)&ipl;
  444. sprintf(ip, "%d.%d.%d.%d", sin_addr[3], sin_addr[2], sin_addr[1], sin_addr[0]);
  445. // DNS Blacklist check
  446. if(login_config.use_dnsbl)
  447. {
  448. char r_ip[16];
  449. char ip_dnsbl[256];
  450. char *dnsbl_serv;
  451. bool matched = false;
  452. sprintf(r_ip, "%d.%d.%d.%d", sin_addr[0], sin_addr[1], sin_addr[2], sin_addr[3]);
  453. for (dnsbl_serv = strtok(login_config.dnsbl_servs,","); dnsbl_serv != NULL; dnsbl_serv = strtok(NULL,","))
  454. {
  455. if (!matched) {
  456. sprintf(ip_dnsbl, "%s.%s", r_ip, dnsbl_serv);
  457. if(gethostbyname(ip_dnsbl))
  458. matched = true;
  459. }
  460. }
  461. if (matched) {
  462. ShowInfo("DNSBL: (%s) Blacklisted. User Kicked.\n", r_ip);
  463. return 3;
  464. }
  465. }
  466. // Account creation with _M/_F
  467. if (login_config.new_account_flag)
  468. {
  469. int len = strlen(account->userid) - 2;
  470. if (account->passwdenc == 0 && account->userid[len] == '_' &&
  471. (account->userid[len+1] == 'F' || account->userid[len+1] == 'M' ||
  472. account->userid[len+1] == 'f' || account->userid[len+1] == 'm') &&
  473. len >= 4 && strlen(account->passwd) >= 4)
  474. {
  475. int result;
  476. account->userid[len] = '\0'; //Terminating the name.
  477. if ((result = mmo_auth_new(account, account->userid[len+1])))
  478. return result; //Failed to make account. [Skotlex].
  479. }
  480. }
  481. jstrescapecpy(t_uid,account->userid);
  482. // retrieve login entry for the specified username
  483. sprintf(tmpsql, "SELECT `%s`,`%s`,`lastlogin`,`sex`,`connect_until`,`ban_until`,`state`,`%s`"
  484. " FROM `%s` WHERE `%s`= %s '%s'", login_db_account_id, login_db_user_pass, login_db_level, login_db, login_db_userid, login_config.case_sensitive ? "BINARY" : "", t_uid);
  485. //login {0-account_id/1-user_pass/2-lastlogin/3-sex/4-connect_untl/5-ban_until/6-state/7-level}
  486. // query
  487. if (mysql_query(&mysql_handle, tmpsql)) {
  488. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  489. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  490. }
  491. sql_res = mysql_store_result(&mysql_handle) ;
  492. if (!sql_res) {
  493. ShowError("mmo_auth DB result error ! \n");
  494. return 0;
  495. }
  496. sql_row = mysql_fetch_row(sql_res);
  497. if (!sql_row) {
  498. //there's no id.
  499. ShowNotice("auth failed: no such account %s\n", account->userid);
  500. mysql_free_result(sql_res);
  501. return 0;
  502. }
  503. account->account_id = atoi(sql_row[0]);
  504. strncpy(password, sql_row[1], sizeof(password)-1);
  505. strncpy(account->lastlogin, sql_row[2], 24);
  506. account->sex = sql_row[3][0] == 'S' ? 2 : sql_row[3][0]=='M' ? 1 : 0;
  507. connect_until = atol(sql_row[4]);
  508. ban_until_time = atol(sql_row[5]);
  509. state = atoi(sql_row[6]);
  510. account->level = atoi(sql_row[7]);
  511. if (account->level > 99) account->level = 99;
  512. //This function has too many leaks because this is only free'd on the end.
  513. //Better avoid that and free it as soon as possible. [Skotlex]
  514. mysql_free_result(sql_res);
  515. //Client Version check
  516. if(login_config.check_client_version && account->version != 0 &&
  517. account->version != login_config.client_version_to_connect)
  518. return 5;
  519. switch (state) {
  520. case -3: //id is banned
  521. case -2: //dynamic ban
  522. return state;
  523. }
  524. if (login_config.use_md5_passwds)
  525. MD5_String(account->passwd, user_password);
  526. else
  527. memcpy(user_password, account->passwd, NAME_LENGTH);
  528. if (!check_password(session[fd]->session_data, account->passwdenc, user_password, password))
  529. {
  530. ShowInfo("Invalid password (account: %s, pass: %s, received pass: %s, ip: %s)" RETCODE,
  531. account->userid, password, (account->passwdenc) ? "[MD5]" : account->passwd, ip);
  532. return 1; // 1 = Incorrect Password
  533. }
  534. if (ban_until_time != 0) { // if account is banned
  535. if (ban_until_time > time(NULL)) // always banned
  536. return 6; // 6 = Your are Prohibited to log in until %s
  537. sprintf(tmpsql, "UPDATE `%s` SET `ban_until`='0' %s WHERE `%s`= '%d'",
  538. login_db, state==7?",state='0'":"",
  539. login_db_account_id, account->account_id);
  540. if (mysql_query(&mysql_handle, tmpsql)) {
  541. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  542. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  543. }
  544. }
  545. if (state)
  546. switch(state) { // packet 0x006a value + 1
  547. case 1: // 0 = Unregistered ID
  548. case 2: // 1 = Incorrect Password
  549. case 3: // 2 = This ID is expired
  550. case 4: // 3 = Rejected from Server
  551. case 5: // 4 = You have been blocked by the GM Team
  552. case 6: // 5 = Your Game's EXE file is not the latest version
  553. case 7: // 6 = Your are Prohibited to log in until %s
  554. case 8: // 7 = Server is jammed due to over populated
  555. case 9: // 8 = No more accounts may be connected from this company
  556. case 10: // 9 = MSI_REFUSE_BAN_BY_DBA
  557. case 11: // 10 = MSI_REFUSE_EMAIL_NOT_CONFIRMED
  558. case 12: // 11 = MSI_REFUSE_BAN_BY_GM
  559. case 13: // 12 = MSI_REFUSE_TEMP_BAN_FOR_DBWORK
  560. case 14: // 13 = MSI_REFUSE_SELF_LOCK
  561. case 15: // 14 = MSI_REFUSE_NOT_PERMITTED_GROUP
  562. case 16: // 15 = MSI_REFUSE_NOT_PERMITTED_GROUP
  563. case 100: // 99 = This ID has been totally erased
  564. case 101: // 100 = Login information remains at %s.
  565. case 102: // 101 = Account has been locked for a hacking investigation. Please contact the GM Team for more information
  566. case 103: // 102 = This account has been temporarily prohibited from login due to a bug-related investigation
  567. case 104: // 103 = This character is being deleted. Login is temporarily unavailable for the time being
  568. case 105: // 104 = Your spouse character is being deleted. Login is temporarily unavailable for the time being
  569. ShowInfo("Auth Error #%d\n", state);
  570. return state - 1;
  571. default:
  572. return 99; // 99 = ID has been totally erased
  573. }
  574. if (connect_until != 0 && connect_until < time(NULL))
  575. return 2; // 2 = This ID is expired
  576. if (login_config.online_check) {
  577. struct online_login_data* data = idb_get(online_db,account->account_id);
  578. if (data && data->char_server > -1) {
  579. //Request char servers to kick this account out. [Skotlex]
  580. unsigned char buf[8];
  581. ShowNotice("User [%s] is already online - Rejected.\n",account->userid);
  582. WBUFW(buf,0) = 0x2734;
  583. WBUFL(buf,2) = account->account_id;
  584. charif_sendallwos(-1, buf, 6);
  585. if (data->waiting_disconnect == -1)
  586. data->waiting_disconnect = add_timer(gettick()+30000, waiting_disconnect_timer, account->account_id, 0);
  587. return 3; // Rejected
  588. }
  589. }
  590. account->login_id1 = rand();
  591. account->login_id2 = rand();
  592. if (account->sex != 2 && account->account_id < START_ACCOUNT_NUM)
  593. ShowWarning("Account %s has account id %d! Account IDs must be over %d to work properly!\n", account->userid, account->account_id, START_ACCOUNT_NUM);
  594. sprintf(tmpsql, "UPDATE `%s` SET `lastlogin` = NOW(), `logincount`=`logincount` +1, `last_ip`='%s' WHERE `%s` = '%d'",
  595. login_db, ip, login_db_account_id, account->account_id);
  596. if (mysql_query(&mysql_handle, tmpsql)) {
  597. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  598. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  599. }
  600. return -1;
  601. }
  602. static int online_db_setoffline(DBKey key, void* data, va_list ap)
  603. {
  604. struct online_login_data *p = (struct online_login_data *)data;
  605. int server = va_arg(ap, int);
  606. if (server == -1) {
  607. p->char_server = -1;
  608. if (p->waiting_disconnect != -1)
  609. {
  610. delete_timer(p->waiting_disconnect, waiting_disconnect_timer);
  611. p->waiting_disconnect = -1;
  612. }
  613. } else if (p->char_server == server)
  614. p->char_server = -2; //Char server disconnected.
  615. return 0;
  616. }
  617. //--------------------------------
  618. // Packet parsing for char-servers
  619. //--------------------------------
  620. int parse_fromchar(int fd)
  621. {
  622. int i, id;
  623. uint32 ipl = session[fd]->client_addr;
  624. char ip[16];
  625. RFIFOHEAD(fd);
  626. ip2str(ipl, ip);
  627. for(id = 0; id < MAX_SERVERS; id++)
  628. if (server_fd[id] == fd)
  629. break;
  630. if (id == MAX_SERVERS) { // not a char server
  631. session[fd]->eof = 1;
  632. do_close(fd);
  633. return 0;
  634. }
  635. if(session[fd]->eof) {
  636. ShowStatus("Char-server '%s' has disconnected.\n", server[id].name);
  637. server_fd[id] = -1;
  638. memset(&server[id], 0, sizeof(struct mmo_char_server));
  639. online_db->foreach(online_db,online_db_setoffline,id); //Set all chars from this char server to offline.
  640. sprintf(tmpsql, "DELETE FROM `sstatus` WHERE `index`='%d'", id);
  641. if (mysql_query(&mysql_handle, tmpsql)) {
  642. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  643. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  644. }
  645. do_close(fd);
  646. return 0;
  647. }
  648. while (RFIFOREST(fd) >= 2)
  649. {
  650. uint16 command = RFIFOW(fd,0);
  651. switch (command)
  652. {
  653. case 0x2709: // request from map-server via char-server to reload GM accounts
  654. if (login_config.log_login)
  655. {
  656. sprintf(tmpsql,"INSERT DELAYED INTO `%s`(`time`,`ip`,`user`,`log`) VALUES (NOW(), '%u', '%s', 'GM reload request')", loginlog_db, ipl, server[id].name);
  657. if (mysql_query(&mysql_handle, tmpsql)) {
  658. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  659. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  660. }
  661. }
  662. read_gm_account();
  663. // send GM accounts to all char-servers
  664. send_GM_accounts(-1);
  665. RFIFOSKIP(fd,2);
  666. break;
  667. case 0x2712: // request from char-server to authenticate an account
  668. if (RFIFOREST(fd) < 19)
  669. return 0;
  670. {
  671. int account_id;
  672. WFIFOHEAD(fd,51);
  673. account_id = RFIFOL(fd,2); // speed up
  674. for(i = 0; i < AUTH_FIFO_SIZE; i++) {
  675. if( auth_fifo[i].account_id == account_id &&
  676. auth_fifo[i].login_id1 == RFIFOL(fd,6) &&
  677. auth_fifo[i].login_id2 == RFIFOL(fd,10) && // relate to the versions higher than 18
  678. auth_fifo[i].sex == RFIFOB(fd,14) &&
  679. auth_fifo[i].ip == ntohl(RFIFOL(fd,15)) &&
  680. !auth_fifo[i].delflag)
  681. {
  682. auth_fifo[i].delflag = 1;
  683. break;
  684. }
  685. }
  686. if (i != AUTH_FIFO_SIZE && account_id > 0) { // send ack
  687. time_t connect_until_time = 0;
  688. char email[40] = "";
  689. account_id=RFIFOL(fd,2);
  690. sprintf(tmpsql, "SELECT `email`,`connect_until` FROM `%s` WHERE `%s`='%d'", login_db, login_db_account_id, account_id);
  691. if (mysql_query(&mysql_handle, tmpsql)) {
  692. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  693. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  694. }
  695. sql_res = mysql_store_result(&mysql_handle) ;
  696. if (sql_res) {
  697. sql_row = mysql_fetch_row(sql_res);
  698. connect_until_time = atol(sql_row[1]);
  699. strcpy(email, sql_row[0]);
  700. mysql_free_result(sql_res);
  701. }
  702. WFIFOW(fd,0) = 0x2713;
  703. WFIFOL(fd,2) = account_id;
  704. WFIFOB(fd,6) = 0;
  705. memcpy(WFIFOP(fd, 7), email, 40);
  706. WFIFOL(fd,47) = (unsigned long) connect_until_time;
  707. WFIFOSET(fd,51);
  708. } else {
  709. WFIFOW(fd,0) = 0x2713;
  710. WFIFOL(fd,2) = account_id;
  711. WFIFOB(fd,6) = 1;
  712. WFIFOSET(fd,51);
  713. }
  714. }
  715. RFIFOSKIP(fd,19);
  716. break;
  717. case 0x2714:
  718. if (RFIFOREST(fd) < 6)
  719. return 0;
  720. // how many users on world? (update)
  721. if (server[id].users != RFIFOL(fd,2))
  722. {
  723. ShowStatus("set users %s : %d\n", server[id].name, RFIFOL(fd,2));
  724. server[id].users = RFIFOL(fd,2);
  725. sprintf(tmpsql,"UPDATE `sstatus` SET `user` = '%d' WHERE `index` = '%d'", server[id].users, id);
  726. // query
  727. if (mysql_query(&mysql_handle, tmpsql)) {
  728. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  729. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  730. }
  731. }
  732. { // send some answer
  733. WFIFOHEAD(fd,6);
  734. WFIFOW(fd,0) = 0x2718;
  735. WFIFOSET(fd,2);
  736. }
  737. RFIFOSKIP(fd,6);
  738. break;
  739. case 0x2716: // received an e-mail/limited time request, because a player comes back from a map-server to the char-server
  740. if (RFIFOREST(fd) < 6)
  741. return 0;
  742. {
  743. int account_id;
  744. time_t connect_until_time = 0;
  745. char email[40] = "";
  746. WFIFOHEAD(fd,50);
  747. account_id=RFIFOL(fd,2);
  748. sprintf(tmpsql,"SELECT `email`,`connect_until` FROM `%s` WHERE `%s`='%d'",login_db, login_db_account_id, account_id);
  749. if(mysql_query(&mysql_handle, tmpsql)) {
  750. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  751. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  752. }
  753. sql_res = mysql_store_result(&mysql_handle) ;
  754. if (sql_res) {
  755. sql_row = mysql_fetch_row(sql_res);
  756. connect_until_time = atol(sql_row[1]);
  757. strcpy(email, sql_row[0]);
  758. }
  759. mysql_free_result(sql_res);
  760. //printf("parse_fromchar: E-mail/limited time request from '%s' server (concerned account: %d)\n", server[id].name, RFIFOL(fd,2));
  761. WFIFOW(fd,0) = 0x2717;
  762. WFIFOL(fd,2) = RFIFOL(fd,2);
  763. memcpy(WFIFOP(fd, 6), email, 40);
  764. WFIFOL(fd,46) = (unsigned long) connect_until_time;
  765. WFIFOSET(fd,50);
  766. }
  767. RFIFOSKIP(fd,6);
  768. break;
  769. case 0x2720: // Request to become a GM (TXT only!)
  770. if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  771. return 0;
  772. //oldacc = RFIFOL(fd,4);
  773. ShowWarning("change GM isn't supported in this login server version.\n");
  774. ShowError("change GM error 0 %s\n", RFIFOP(fd, 8));
  775. RFIFOSKIP(fd, RFIFOW(fd, 2));
  776. {
  777. WFIFOHEAD(fd,10);
  778. WFIFOW(fd,0) = 0x2721;
  779. WFIFOL(fd,2) = RFIFOL(fd,4); // oldacc;
  780. WFIFOL(fd,6) = 0; // newacc;
  781. WFIFOSET(fd,10);
  782. }
  783. return 0;
  784. // Map server send information to change an email of an account via char-server
  785. case 0x2722: // 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B
  786. if (RFIFOREST(fd) < 86)
  787. return 0;
  788. {
  789. int acc;
  790. char actual_email[40], new_email[40];
  791. acc = RFIFOL(fd,2);
  792. memcpy(actual_email, RFIFOP(fd,6), 40);
  793. memcpy(new_email, RFIFOP(fd,46), 40);
  794. if (e_mail_check(actual_email) == 0)
  795. ShowWarning("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command), but actual email is invalid (account: %d, ip: %s)" RETCODE,
  796. server[id].name, acc, ip);
  797. else if (e_mail_check(new_email) == 0)
  798. ShowWarning("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a invalid new e-mail (account: %d, ip: %s)" RETCODE,
  799. server[id].name, acc, ip);
  800. else if (strcmpi(new_email, "a@a.com") == 0)
  801. ShowWarning("Char-server '%s': Attempt to modify an e-mail on an account (@email GM command) with a default e-mail (account: %d, ip: %s)" RETCODE,
  802. server[id].name, acc, ip);
  803. else {
  804. sprintf(tmpsql, "SELECT `%s`,`email` FROM `%s` WHERE `%s` = '%d'", login_db_userid, login_db, login_db_account_id, acc);
  805. if (mysql_query(&mysql_handle, tmpsql))
  806. {
  807. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  808. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  809. }
  810. sql_res = mysql_store_result(&mysql_handle);
  811. if (sql_res) {
  812. sql_row = mysql_fetch_row(sql_res); //row fetching
  813. if (strcmpi(sql_row[1], actual_email) == 0) {
  814. sprintf(tmpsql, "UPDATE `%s` SET `email` = '%s' WHERE `%s` = '%d'", login_db, new_email, login_db_account_id, acc);
  815. // query
  816. if (mysql_query(&mysql_handle, tmpsql)) {
  817. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  818. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  819. }
  820. ShowInfo("Char-server '%s': Modify an e-mail on an account (@email GM command) (account: %d (%s), new e-mail: %s, ip: %s)." RETCODE,
  821. server[id].name, acc, sql_row[0], actual_email, ip);
  822. }
  823. }
  824. }
  825. RFIFOSKIP(fd, 86);
  826. break;
  827. }
  828. case 0x2724: // Receiving of map-server via char-server a status change resquest
  829. if (RFIFOREST(fd) < 10)
  830. return 0;
  831. {
  832. int acc, statut;
  833. acc = RFIFOL(fd,2);
  834. statut = RFIFOL(fd,6);
  835. sprintf(tmpsql, "SELECT `state` FROM `%s` WHERE `%s` = '%d'", login_db, login_db_account_id, acc);
  836. if (mysql_query(&mysql_handle, tmpsql)) {
  837. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  838. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  839. }
  840. sql_res = mysql_store_result(&mysql_handle);
  841. if (sql_res) {
  842. sql_row = mysql_fetch_row(sql_res); // row fetching
  843. }
  844. if (atoi(sql_row[0]) != statut && statut != 0) {
  845. unsigned char buf[16];
  846. WBUFW(buf,0) = 0x2731;
  847. WBUFL(buf,2) = acc;
  848. WBUFB(buf,6) = 0; // 0: change of statut, 1: ban
  849. WBUFL(buf,7) = statut; // status or final date of a banishment
  850. charif_sendallwos(-1, buf, 11);
  851. }
  852. sprintf(tmpsql,"UPDATE `%s` SET `state` = '%d' WHERE `%s` = '%d'", login_db, statut,login_db_account_id,acc);
  853. //query
  854. if(mysql_query(&mysql_handle, tmpsql)) {
  855. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  856. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  857. }
  858. RFIFOSKIP(fd,10);
  859. break;
  860. }
  861. case 0x2725: // Receiving of map-server via char-server a ban resquest
  862. if (RFIFOREST(fd) < 18)
  863. return 0;
  864. {
  865. int acc;
  866. struct tm *tmtime;
  867. time_t timestamp, tmptime;
  868. acc = RFIFOL(fd,2);
  869. sprintf(tmpsql, "SELECT `ban_until` FROM `%s` WHERE `%s` = '%d'",login_db,login_db_account_id,acc);
  870. if (mysql_query(&mysql_handle, tmpsql)) {
  871. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  872. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  873. }
  874. sql_res = mysql_store_result(&mysql_handle);
  875. if (sql_res) {
  876. sql_row = mysql_fetch_row(sql_res); // row fetching
  877. }
  878. tmptime = atol(sql_row[0]);
  879. if (tmptime == 0 || tmptime < time(NULL))
  880. timestamp = time(NULL);
  881. else
  882. timestamp = tmptime;
  883. tmtime = localtime(&timestamp);
  884. tmtime->tm_year = tmtime->tm_year + (short)RFIFOW(fd,6);
  885. tmtime->tm_mon = tmtime->tm_mon + (short)RFIFOW(fd,8);
  886. tmtime->tm_mday = tmtime->tm_mday + (short)RFIFOW(fd,10);
  887. tmtime->tm_hour = tmtime->tm_hour + (short)RFIFOW(fd,12);
  888. tmtime->tm_min = tmtime->tm_min + (short)RFIFOW(fd,14);
  889. tmtime->tm_sec = tmtime->tm_sec + (short)RFIFOW(fd,16);
  890. timestamp = mktime(tmtime);
  891. if (timestamp != -1) {
  892. if (timestamp <= time(NULL))
  893. timestamp = 0;
  894. if (tmptime != timestamp) {
  895. if (timestamp != 0) {
  896. unsigned char buf[16];
  897. WBUFW(buf,0) = 0x2731;
  898. WBUFL(buf,2) = acc;
  899. WBUFB(buf,6) = 1; // 0: change of statut, 1: ban
  900. WBUFL(buf,7) = (unsigned int)timestamp; // status or final date of a banishment
  901. charif_sendallwos(-1, buf, 11);
  902. }
  903. ShowNotice("Account: %d Banned until: %ld\n", acc, timestamp);
  904. sprintf(tmpsql, "UPDATE `%s` SET `ban_until` = '%ld' WHERE `%s` = '%d'", login_db, (unsigned long)timestamp, login_db_account_id, acc);
  905. // query
  906. if (mysql_query(&mysql_handle, tmpsql)) {
  907. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  908. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  909. }
  910. }
  911. }
  912. RFIFOSKIP(fd,18);
  913. break;
  914. }
  915. case 0x2727: // Change of sex (sex is reversed)
  916. if (RFIFOREST(fd) < 6)
  917. return 0;
  918. {
  919. int acc,sex;
  920. unsigned char buf[16];
  921. acc=RFIFOL(fd,2);
  922. sprintf(tmpsql,"SELECT `sex` FROM `%s` WHERE `%s` = '%d'",login_db,login_db_account_id,acc);
  923. if(mysql_query(&mysql_handle, tmpsql)) {
  924. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  925. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  926. return 0;
  927. }
  928. sql_res = mysql_store_result(&mysql_handle) ;
  929. if (sql_res) {
  930. if (mysql_num_rows(sql_res) == 0) {
  931. mysql_free_result(sql_res);
  932. return 0;
  933. }
  934. sql_row = mysql_fetch_row(sql_res); //row fetching
  935. }
  936. if (strcmpi(sql_row[0], "M") == 0)
  937. sex = 0; //Change to female
  938. else
  939. sex = 1; //Change to make
  940. sprintf(tmpsql,"UPDATE `%s` SET `sex` = '%c' WHERE `%s` = '%d'", login_db, (sex?'M':'F'), login_db_account_id, acc);
  941. //query
  942. if(mysql_query(&mysql_handle, tmpsql)) {
  943. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  944. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  945. }
  946. WBUFW(buf,0) = 0x2723;
  947. WBUFL(buf,2) = acc;
  948. WBUFB(buf,6) = sex;
  949. charif_sendallwos(-1, buf, 7);
  950. RFIFOSKIP(fd,6);
  951. break;
  952. }
  953. case 0x2728: // save account_reg2
  954. if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  955. return 0;
  956. if (RFIFOL(fd,4) > 0) {
  957. int acc,p,j,len;
  958. char str[32];
  959. char temp_str[64]; //Needs twice as much space as the original string.
  960. char temp_str2[512];
  961. char value[256];
  962. unsigned char *buf;
  963. acc=RFIFOL(fd,4);
  964. buf = (unsigned char*)aCalloc(RFIFOW(fd,2)+1, sizeof(unsigned char));
  965. //Delete all global account variables....
  966. sprintf(tmpsql,"DELETE FROM `%s` WHERE `type`='1' AND `account_id`='%d';",reg_db,acc);
  967. if(mysql_query(&mysql_handle, tmpsql)) {
  968. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  969. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  970. }
  971. //Proceed to insert them....
  972. for(j=0,p=13;j<ACCOUNT_REG2_NUM && p<RFIFOW(fd,2);j++){
  973. sscanf(RFIFOP(fd,p), "%31c%n",str,&len);
  974. str[len]='\0';
  975. p +=len+1; //+1 to skip the '\0' between strings.
  976. sscanf(RFIFOP(fd,p), "%255c%n",value,&len);
  977. value[len]='\0';
  978. p +=len+1;
  979. sprintf(tmpsql,"INSERT INTO `%s` (`type`, `account_id`, `str`, `value`) VALUES ( 1 , '%d' , '%s' , '%s');", reg_db, acc, jstrescapecpy(temp_str,str), jstrescapecpy(temp_str2,value));
  980. if(mysql_query(&mysql_handle, tmpsql)) {
  981. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  982. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  983. }
  984. }
  985. // Send to char
  986. memcpy(WBUFP(buf,0),RFIFOP(fd,0),RFIFOW(fd,2));
  987. WBUFW(buf,0)=0x2729;
  988. charif_sendallwos(fd,buf,WBUFW(buf,2));
  989. if (buf) aFree(buf);
  990. }
  991. RFIFOSKIP(fd,RFIFOW(fd,2));
  992. break;
  993. case 0x272a: // Receiving of map-server via char-server a unban resquest
  994. if (RFIFOREST(fd) < 6)
  995. return 0;
  996. {
  997. int acc;
  998. acc = RFIFOL(fd,2);
  999. sprintf(tmpsql,"SELECT `ban_until` FROM `%s` WHERE `%s` = '%d'",login_db,login_db_account_id,acc);
  1000. if(mysql_query(&mysql_handle, tmpsql)) {
  1001. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  1002. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  1003. }
  1004. sql_res = mysql_store_result(&mysql_handle) ;
  1005. if (sql_res && mysql_num_rows(sql_res) > 0) { //Found a match
  1006. sprintf(tmpsql,"UPDATE `%s` SET `ban_until` = '0' WHERE `%s` = '%d'", login_db,login_db_account_id,acc);
  1007. //query
  1008. if(mysql_query(&mysql_handle, tmpsql)) {
  1009. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  1010. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  1011. }
  1012. }
  1013. if (sql_res) mysql_free_result(sql_res);
  1014. RFIFOSKIP(fd,6);
  1015. }
  1016. return 0;
  1017. case 0x272b: // Set account_id to online [Wizputer]
  1018. if (RFIFOREST(fd) < 6)
  1019. return 0;
  1020. add_online_user(id, RFIFOL(fd,2));
  1021. RFIFOSKIP(fd,6);
  1022. break;
  1023. case 0x272c: // Set account_id to offline [Wizputer]
  1024. if (RFIFOREST(fd) < 6)
  1025. return 0;
  1026. remove_online_user(RFIFOL(fd,2));
  1027. RFIFOSKIP(fd,6);
  1028. break;
  1029. case 0x272d: // Receive list of all online accounts. [Skotlex]
  1030. if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  1031. return 0;
  1032. if (login_config.online_check) {
  1033. struct online_login_data *p;
  1034. int aid, users;
  1035. online_db->foreach(online_db,online_db_setoffline,id); //Set all chars from this char-server offline first
  1036. users = RFIFOW(fd,4);
  1037. for (i = 0; i < users; i++) {
  1038. aid = RFIFOL(fd,6+i*4);
  1039. p = idb_ensure(online_db, aid, create_online_user);
  1040. p->char_server = id;
  1041. if (p->waiting_disconnect != -1)
  1042. {
  1043. delete_timer(p->waiting_disconnect, waiting_disconnect_timer);
  1044. p->waiting_disconnect = -1;
  1045. }
  1046. }
  1047. }
  1048. RFIFOSKIP(fd,RFIFOW(fd,2));
  1049. break;
  1050. case 0x272e: //Request account_reg2 for a character.
  1051. if (RFIFOREST(fd) < 10)
  1052. return 0;
  1053. {
  1054. int account_id = RFIFOL(fd, 2);
  1055. int char_id = RFIFOL(fd, 6);
  1056. int p;
  1057. WFIFOHEAD(fd,10000);
  1058. RFIFOSKIP(fd,10);
  1059. sprintf(tmpsql, "SELECT `str`,`value` FROM `%s` WHERE `type`='1' AND `account_id`='%d'",reg_db, account_id);
  1060. if (mysql_query(&mysql_handle, tmpsql)) {
  1061. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  1062. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  1063. break;
  1064. }
  1065. sql_res = mysql_store_result(&mysql_handle) ;
  1066. if (!sql_res) {
  1067. break;
  1068. }
  1069. WFIFOW(fd,0) = 0x2729;
  1070. WFIFOL(fd,4) = account_id;
  1071. WFIFOL(fd,8) = char_id;
  1072. WFIFOB(fd,12) = 1; //Type 1 for Account2 registry
  1073. for(p = 13; (sql_row = mysql_fetch_row(sql_res)) && p < 9000;){
  1074. if (sql_row[0][0]) {
  1075. p+= sprintf(WFIFOP(fd,p), "%s", sql_row[0])+1; //We add 1 to consider the '\0' in place.
  1076. p+= sprintf(WFIFOP(fd,p), "%s", sql_row[1])+1;
  1077. }
  1078. }
  1079. if (p >= 9000)
  1080. ShowWarning("Too many account2 registries for AID %d. Some registries were not sent.\n", account_id);
  1081. WFIFOW(fd,2) = p;
  1082. WFIFOSET(fd,WFIFOW(fd,2));
  1083. mysql_free_result(sql_res);
  1084. }
  1085. break;
  1086. case 0x2736: // WAN IP update from char-server
  1087. if (RFIFOREST(fd) < 6)
  1088. return 0;
  1089. server[id].ip = ntohl(RFIFOL(fd,2));
  1090. ShowInfo("Updated IP of Server #%d to %d.%d.%d.%d.\n",id, CONVIP(server[id].ip));
  1091. RFIFOSKIP(fd,6);
  1092. break;
  1093. case 0x2737: //Request to set all offline.
  1094. ShowInfo("Setting accounts from char-server %d offline.\n", id);
  1095. online_db->foreach(online_db,online_db_setoffline,id);
  1096. RFIFOSKIP(fd,2);
  1097. break;
  1098. default:
  1099. ShowError("parse_fromchar: Unknown packet 0x%x from a char-server! Disconnecting!\n", RFIFOW(fd,0));
  1100. session[fd]->eof = 1;
  1101. return 0;
  1102. }
  1103. }
  1104. RFIFOSKIP(fd,RFIFOREST(fd));
  1105. return 0;
  1106. }
  1107. //--------------------------------------------
  1108. // Test to know if an IP come from LAN or WAN.
  1109. //--------------------------------------------
  1110. int lan_subnetcheck(uint32 ip)
  1111. {
  1112. int i;
  1113. for(i = 0; i < subnet_count; i++) {
  1114. if(subnet[i].subnet == (ip & subnet[i].mask)) {
  1115. return subnet[i].char_ip;
  1116. }
  1117. }
  1118. return 0;
  1119. }
  1120. int login_ip_ban_check(uint32 ip)
  1121. {
  1122. char* p = (char*)&ip;
  1123. sprintf(tmpsql, "SELECT count(*) FROM `ipbanlist` WHERE `list` = '%d.*.*.*' OR `list` = '%d.%d.*.*' OR `list` = '%d.%d.%d.*' OR `list` = '%d.%d.%d.%d'",
  1124. p[3], p[3], p[2], p[3], p[2], p[1], p[3], p[2], p[1], p[0]);
  1125. if (mysql_query(&mysql_handle, tmpsql)) {
  1126. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  1127. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  1128. // close connection because we can't verify their connectivity.
  1129. return 1;
  1130. }
  1131. sql_res = mysql_store_result(&mysql_handle) ;
  1132. sql_row = sql_res?mysql_fetch_row(sql_res):NULL;
  1133. if(!sql_row) { //Shouldn't happen, but just in case...
  1134. mysql_free_result(sql_res);
  1135. return 1;
  1136. }
  1137. if (atoi(sql_row[0]) == 0) { //No ban
  1138. mysql_free_result(sql_res);
  1139. return 0;
  1140. }
  1141. // ip ban ok.
  1142. ShowInfo("Packet from banned ip : %d.%d.%d.%d\n" RETCODE, CONVIP(ip));
  1143. if (login_config.log_login)
  1144. {
  1145. sprintf(tmpsql,"INSERT DELAYED INTO `%s`(`time`,`ip`,`user`,`rcode`,`log`) VALUES (NOW(), '%u', 'unknown','-3', 'ip banned')", loginlog_db, ip);
  1146. // query
  1147. if(mysql_query(&mysql_handle, tmpsql)) {
  1148. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  1149. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  1150. }
  1151. }
  1152. mysql_free_result(sql_res);
  1153. return 1;
  1154. }
  1155. //----------------------------------------------------------------------------------------
  1156. // Default packet parsing (normal players or administation/char-server connection requests)
  1157. //----------------------------------------------------------------------------------------
  1158. int parse_login(int fd)
  1159. {
  1160. char t_uid[100];
  1161. struct mmo_account account;
  1162. int result, i;
  1163. uint32 ipl = session[fd]->client_addr;
  1164. char ip[16];
  1165. RFIFOHEAD(fd);
  1166. ip2str(ipl, ip);
  1167. memset(&account, 0, sizeof(account));
  1168. if (session[fd]->eof) {
  1169. do_close(fd);
  1170. return 0;
  1171. }
  1172. while (RFIFOREST(fd) >= 2)
  1173. {
  1174. uint16 command = RFIFOW(fd,0);
  1175. switch(command)
  1176. {
  1177. case 0x0200: // New alive packet: structure: 0x200 <account.userid>.24B. used to verify if client is always alive.
  1178. if (RFIFOREST(fd) < 26)
  1179. return 0;
  1180. RFIFOSKIP(fd,26);
  1181. break;
  1182. case 0x0204: // New alive packet: structure: 0x204 <encrypted.account.userid>.16B. (new ragexe from 22 june 2004)
  1183. if (RFIFOREST(fd) < 18)
  1184. return 0;
  1185. RFIFOSKIP(fd,18);
  1186. break;
  1187. case 0x0064: // request client login
  1188. case 0x0277: // New login packet (layout is same as 0x64 but different length)
  1189. case 0x01dd: // request client login (encryption mode)
  1190. {
  1191. int packet_len = RFIFOREST(fd);
  1192. //Perform ip-ban check
  1193. if (login_config.ipban && login_ip_ban_check(ipl))
  1194. {
  1195. WFIFOHEAD(fd,23);
  1196. WFIFOW(fd,0) = 0x6a;
  1197. WFIFOB(fd,2) = 3; // 3 = Rejected from Server
  1198. WFIFOSET(fd,23);
  1199. RFIFOSKIP(fd,packet_len);
  1200. session[fd]->eof = 1;
  1201. break;
  1202. }
  1203. if ((command == 0x0064 && packet_len < 55) ||
  1204. (command == 0x0277 && packet_len < 84) ||
  1205. (command == 0x01dd && packet_len < 47))
  1206. return 0;
  1207. // S 0064 <version>.l <account name>.24B <password>.24B <version2>.B
  1208. // S 0277 ??
  1209. // S 01dd <version>.l <account name>.24B <md5 binary>.16B <version2>.B
  1210. account.version = RFIFOL(fd,2);
  1211. if (!account.version) account.version = 1; //Force some version...
  1212. memcpy(account.userid,RFIFOP(fd,6),NAME_LENGTH); account.userid[23] = '\0';
  1213. memcpy(account.passwd,RFIFOP(fd,30),NAME_LENGTH); account.passwd[23] = '\0';
  1214. account.passwdenc = (command != 0x01dd) ? 0 : PASSWORDENC;
  1215. jstrescapecpy(t_uid, account.userid);
  1216. result = mmo_auth(&account, fd);
  1217. if (result == -1) { // auth success
  1218. if (login_config.min_level_to_connect > account.level) {
  1219. WFIFOHEAD(fd,3);
  1220. WFIFOW(fd,0) = 0x81;
  1221. WFIFOB(fd,2) = 1; // 01 = Server closed
  1222. WFIFOSET(fd,3);
  1223. } else {
  1224. WFIFOHEAD(fd,47+32*MAX_SERVERS);
  1225. if (login_config.log_login) {
  1226. sprintf(tmpsql,"INSERT DELAYED INTO `%s`(`time`,`ip`,`user`,`rcode`,`log`) VALUES (NOW(), '%u', '%s','100', 'login ok')", loginlog_db, ipl, t_uid);
  1227. //query
  1228. if(mysql_query(&mysql_handle, tmpsql)) {
  1229. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  1230. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  1231. }
  1232. }
  1233. if (account.level)
  1234. ShowStatus("Connection of the GM (level:%d) account '%s' accepted.\n", account.level, account.userid);
  1235. else
  1236. ShowStatus("Connection of the account '%s' accepted.\n", account.userid);
  1237. server_num = 0;
  1238. for(i = 0; i < MAX_SERVERS; i++) {
  1239. if (server_fd[i] >= 0) {
  1240. // Advanced subnet check [LuzZza]
  1241. uint32 subnet_char_ip = lan_subnetcheck(ipl);
  1242. WFIFOL(fd,47+server_num*32) = htonl((subnet_char_ip) ? subnet_char_ip : server[i].ip);
  1243. WFIFOW(fd,47+server_num*32+4) = ntows(htons(server[i].port)); // [!] LE byte order here [!]
  1244. memcpy(WFIFOP(fd,47+server_num*32+6), server[i].name, 20);
  1245. WFIFOW(fd,47+server_num*32+26) = server[i].users;
  1246. WFIFOW(fd,47+server_num*32+28) = server[i].maintenance;
  1247. WFIFOW(fd,47+server_num*32+30) = server[i].new_;
  1248. server_num++;
  1249. }
  1250. }
  1251. if (server_num > 0) { // if at least 1 char-server
  1252. WFIFOW(fd,0) = 0x69;
  1253. WFIFOW(fd,2) = 47+32*server_num;
  1254. WFIFOL(fd,4) = account.login_id1;
  1255. WFIFOL(fd,8) = account.account_id;
  1256. WFIFOL(fd,12) = account.login_id2;
  1257. WFIFOL(fd,16) = 0; // in old version, that was for ip (not more used)
  1258. //memcpy(WFIFOP(fd,20), account.lastlogin, 24); // in old version, that was for name (not more used)
  1259. WFIFOB(fd,46) = account.sex;
  1260. WFIFOSET(fd,47+32*server_num);
  1261. if (auth_fifo_pos >= AUTH_FIFO_SIZE)
  1262. auth_fifo_pos = 0;
  1263. auth_fifo[auth_fifo_pos].account_id = account.account_id;
  1264. auth_fifo[auth_fifo_pos].login_id1 = account.login_id1;
  1265. auth_fifo[auth_fifo_pos].login_id2 = account.login_id2;
  1266. auth_fifo[auth_fifo_pos].sex = account.sex;
  1267. auth_fifo[auth_fifo_pos].delflag = 0;
  1268. auth_fifo[auth_fifo_pos].ip = session[fd]->client_addr;
  1269. auth_fifo_pos++;
  1270. } else { // if no char-server, don't send void list of servers, just disconnect the player with proper message
  1271. WFIFOW(fd,0) = 0x81;
  1272. WFIFOB(fd,2) = 1; // 01 = Server closed
  1273. WFIFOSET(fd,3);
  1274. }
  1275. }
  1276. } else { // auth failed
  1277. WFIFOHEAD(fd,23);
  1278. if (login_config.log_login)
  1279. {
  1280. const char* error;
  1281. switch ((result + 1)) {
  1282. case -2: error = "Account banned."; break; //-3 = Account Banned
  1283. case -1: error = "dynamic ban (ip and account)."; break; //-2 = Dynamic Ban
  1284. case 1: error = "Unregistered ID."; break; // 0 = Unregistered ID
  1285. case 2: error = "Incorrect Password."; break; // 1 = Incorrect Password
  1286. case 3: error = "Account Expired."; break; // 2 = This ID is expired
  1287. case 4: error = "Rejected from server."; break; // 3 = Rejected from Server
  1288. case 5: error = "Blocked by GM."; break; // 4 = You have been blocked by the GM Team
  1289. case 6: error = "Not latest game EXE."; break; // 5 = Your Game's EXE file is not the latest version
  1290. case 7: error = "Banned."; break; // 6 = Your are Prohibited to log in until %s
  1291. case 8: error = "Server Over-population."; break; // 7 = Server is jammed due to over populated
  1292. case 9: error = "Account limit from company"; break; // 8 = No more accounts may be connected from this company
  1293. case 10: error = "Ban by DBA"; break; // 9 = MSI_REFUSE_BAN_BY_DBA
  1294. case 11: error = "Email not confirmed"; break; // 10 = MSI_REFUSE_EMAIL_NOT_CONFIRMED
  1295. case 12: error = "Ban by GM"; break; // 11 = MSI_REFUSE_BAN_BY_GM
  1296. case 13: error = "Working in DB"; break; // 12 = MSI_REFUSE_TEMP_BAN_FOR_DBWORK
  1297. case 14: error = "Self Lock"; break; // 13 = MSI_REFUSE_SELF_LOCK
  1298. case 15: error = "Not Permitted Group"; break; // 14 = MSI_REFUSE_NOT_PERMITTED_GROUP
  1299. case 16: error = "Not Permitted Group"; break; // 15 = MSI_REFUSE_NOT_PERMITTED_GROUP
  1300. case 100: error = "Account gone."; break; // 99 = This ID has been totally erased
  1301. case 101: error = "Login info remains."; break; // 100 = Login information remains at %s
  1302. case 102: error = "Hacking investigation."; break; // 101 = Account has been locked for a hacking investigation. Please contact the GM Team for more information
  1303. case 103: error = "Bug investigation."; break; // 102 = This account has been temporarily prohibited from login due to a bug-related investigation
  1304. case 104: error = "Deleting char."; break; // 103 = This character is being deleted. Login is temporarily unavailable for the time being
  1305. case 105: error = "Deleting spouse char."; break; // 104 = This character is being deleted. Login is temporarily unavailable for the time being
  1306. default : error = "Unknown Error."; break;
  1307. }
  1308. sprintf(tmpsql, "INSERT DELAYED INTO `%s`(`time`,`ip`,`user`,`rcode`,`log`) VALUES (NOW(), '%u', '%s', '%d','login failed : %s')", loginlog_db, ipl, t_uid, result, error);
  1309. //query
  1310. if(mysql_query(&mysql_handle, tmpsql)) {
  1311. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  1312. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  1313. }
  1314. }
  1315. if ((result == 1) && login_config.dynamic_pass_failure_ban && login_config.log_login) { // failed password
  1316. sprintf(tmpsql,"SELECT count(*) FROM `%s` WHERE `ip` = '%u' AND `rcode` = '1' AND `time` > NOW() - INTERVAL %d MINUTE",
  1317. loginlog_db, ipl, login_config.dynamic_pass_failure_ban_interval); //how many times filed account? in one ip.
  1318. if(mysql_query(&mysql_handle, tmpsql)) {
  1319. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  1320. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  1321. }
  1322. //check query result
  1323. sql_res = mysql_store_result(&mysql_handle) ;
  1324. sql_row = sql_res?mysql_fetch_row(sql_res):NULL; //row fetching
  1325. if (sql_row && (unsigned int)atoi(sql_row[0]) >= login_config.dynamic_pass_failure_ban_limit ) {
  1326. uint8* p = (uint8*)&ipl;
  1327. sprintf(tmpsql,"INSERT INTO `ipbanlist`(`list`,`btime`,`rtime`,`reason`) VALUES ('%d.%d.%d.*', NOW() , NOW() + INTERVAL %d MINUTE ,'Password error ban: %s')", (uint8)p[3], (uint8)p[2], (uint8)p[1], login_config.dynamic_pass_failure_ban_duration, t_uid);
  1328. if(mysql_query(&mysql_handle, tmpsql)) {
  1329. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  1330. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  1331. }
  1332. }
  1333. if(sql_res) mysql_free_result(sql_res);
  1334. }
  1335. else if (result == -2){ //dynamic banned - add ip to ban list.
  1336. uint8* p = (uint8*)&ipl;
  1337. sprintf(tmpsql,"INSERT INTO `ipbanlist`(`list`,`btime`,`rtime`,`reason`) VALUES ('%d.%d.%d.*', NOW() , NOW() + INTERVAL 1 MONTH ,'Dynamic banned user id : %s')", (uint8)p[3], (uint8)p[2], (uint8)p[1], t_uid);
  1338. if(mysql_query(&mysql_handle, tmpsql)) {
  1339. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  1340. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  1341. }
  1342. result = -3;
  1343. }else if(result == 6){ //not lastet version ..
  1344. //result = 5;
  1345. }
  1346. sprintf(tmpsql,"SELECT `ban_until` FROM `%s` WHERE `%s` = %s '%s'",login_db, login_db_userid, login_config.case_sensitive ? "BINARY" : "", t_uid);
  1347. if(mysql_query(&mysql_handle, tmpsql)) {
  1348. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  1349. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  1350. }
  1351. sql_res = mysql_store_result(&mysql_handle) ;
  1352. sql_row = sql_res?mysql_fetch_row(sql_res):NULL;
  1353. //cannot connect login failed
  1354. memset(WFIFOP(fd,0), '\0', 23);
  1355. WFIFOW(fd,0) = 0x6a;
  1356. WFIFOB(fd,2) = (uint8)result;
  1357. if (result == 6) { // 6 = Your are Prohibited to log in until %s
  1358. char tmpstr[20];
  1359. time_t ban_until_time = (sql_row) ? atol(sql_row[0]) : 0;
  1360. strftime(tmpstr, 20, login_config.date_format, localtime(&ban_until_time)); tmpstr[19] = '\0';
  1361. strncpy(WFIFOP(fd,3), tmpstr, 20); // ban timestamp goes here
  1362. }
  1363. WFIFOSET(fd,23);
  1364. if (sql_res) mysql_free_result(sql_res);
  1365. }
  1366. RFIFOSKIP(fd,packet_len);
  1367. break;
  1368. }
  1369. case 0x01db: // Sending request of the coding key
  1370. {
  1371. struct login_session_data* ld;
  1372. if (session[fd]->session_data) {
  1373. ShowWarning("login: abnormal request of MD5 key (already opened session).\n");
  1374. session[fd]->eof = 1;
  1375. return 0;
  1376. }
  1377. ld = (struct login_session_data*)aCalloc(1, sizeof(struct login_session_data));
  1378. session[fd]->session_data = ld;
  1379. // Creation of the coding key
  1380. memset(ld->md5key, '\0', sizeof(ld->md5key));
  1381. ld->md5keylen = (uint16)(12 + rand() % 4);
  1382. for(i = 0; i < ld->md5keylen; i++)
  1383. ld->md5key[i] = (char)(1 + rand() % 255);
  1384. RFIFOSKIP(fd,2);
  1385. WFIFOHEAD(fd,4 + ld->md5keylen);
  1386. WFIFOW(fd,0) = 0x01dc;
  1387. WFIFOW(fd,2) = 4 + ld->md5keylen;
  1388. memcpy(WFIFOP(fd,4), ld->md5key, ld->md5keylen);
  1389. WFIFOSET(fd,WFIFOW(fd,2));
  1390. }
  1391. break;
  1392. case 0x2710: // Connection request of a char-server
  1393. if (RFIFOREST(fd) < 86)
  1394. return 0;
  1395. {
  1396. char* server_name;
  1397. uint32 server_ip;
  1398. uint16 server_port;
  1399. WFIFOHEAD(fd,3);
  1400. memcpy(account.userid,RFIFOP(fd,2),NAME_LENGTH); account.userid[23] = '\0';
  1401. memcpy(account.passwd,RFIFOP(fd,26),NAME_LENGTH); account.passwd[23] = '\0';
  1402. account.passwdenc = 0;
  1403. server_name = (char*)RFIFOP(fd,60); server_name[20] = '\0';
  1404. server_ip = ntohl(RFIFOL(fd,54));
  1405. server_port = ntohs(RFIFOW(fd,58));
  1406. ShowInfo("Connection request of the char-server '%s' @ %d.%d.%d.%d:%d (ip: %s)\n",
  1407. server_name, CONVIP(server_ip), server_port, ip);
  1408. jstrescapecpy(t_uid, server_name);
  1409. if (login_config.log_login)
  1410. {
  1411. char t_login[50];
  1412. jstrescapecpy(t_login,account.userid);
  1413. sprintf(tmpsql,"INSERT DELAYED INTO `%s`(`time`,`ip`,`user`,`rcode`,`log`) VALUES (NOW(), '%u', '%s@%s','100', 'charserver - %s@%u.%u.%u.%u:%d')",
  1414. loginlog_db, ipl, t_login, t_uid, t_uid, CONVIP(server_ip), server_port);
  1415. //query
  1416. if(mysql_query(&mysql_handle, tmpsql)) {
  1417. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  1418. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  1419. }
  1420. }
  1421. result = mmo_auth(&account, fd);
  1422. if (result == -1 && account.sex == 2 && account.account_id < MAX_SERVERS && server_fd[account.account_id] == -1) {
  1423. ShowStatus("Connection of the char-server '%s' accepted.\n", server_name);
  1424. memset(&server[account.account_id], 0, sizeof(struct mmo_char_server));
  1425. server[account.account_id].ip = ntohl(RFIFOL(fd,54));
  1426. server[account.account_id].port = ntohs(RFIFOW(fd,58));
  1427. memcpy(server[account.account_id].name, server_name, 20);
  1428. server[account.account_id].users = 0;
  1429. server[account.account_id].maintenance = RFIFOW(fd,82);
  1430. server[account.account_id].new_ = RFIFOW(fd,84);
  1431. server_fd[account.account_id] = fd;
  1432. sprintf(tmpsql,"DELETE FROM `sstatus` WHERE `index`='%d'", account.account_id);
  1433. //query
  1434. if(mysql_query(&mysql_handle, tmpsql)) {
  1435. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  1436. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  1437. }
  1438. sprintf(tmpsql,"INSERT INTO `sstatus`(`index`,`name`,`user`) VALUES ( '%d', '%s', '%d')",
  1439. account.account_id, t_uid,0);
  1440. //query
  1441. if(mysql_query(&mysql_handle, tmpsql)) {
  1442. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  1443. ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmpsql);
  1444. }
  1445. WFIFOW(fd,0) = 0x2711;
  1446. WFIFOB(fd,2) = 0;
  1447. WFIFOSET(fd,3);
  1448. session[fd]->func_parse = parse_fromchar;
  1449. realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  1450. // send GM account to char-server
  1451. send_GM_accounts(fd);
  1452. } else {
  1453. WFIFOW(fd,0) = 0x2711;
  1454. WFIFOB(fd,2) = 3;
  1455. WFIFOSET(fd,3);
  1456. }
  1457. }
  1458. RFIFOSKIP(fd,86);
  1459. return 0;
  1460. case 0x7530: // Server version information request
  1461. {
  1462. ShowInfo ("Athena version check...\n");
  1463. WFIFOHEAD(fd,10);
  1464. WFIFOW(fd,0) = 0x7531;
  1465. WFIFOB(fd,2) = ATHENA_MAJOR_VERSION;
  1466. WFIFOB(fd,3) = ATHENA_MINOR_VERSION;
  1467. WFIFOB(fd,4) = ATHENA_REVISION;
  1468. WFIFOB(fd,5) = ATHENA_RELEASE_FLAG;
  1469. WFIFOB(fd,6) = ATHENA_OFFICIAL_FLAG;
  1470. WFIFOB(fd,7) = ATHENA_SERVER_LOGIN;
  1471. WFIFOW(fd,8) = ATHENA_MOD_VERSION;
  1472. WFIFOSET(fd,10);
  1473. RFIFOSKIP(fd,2);
  1474. break;
  1475. }
  1476. case 0x7532: // Request to end connection
  1477. ShowStatus ("End of connection (ip: %s)" RETCODE, ip);
  1478. session[fd]->eof = 1;
  1479. break;
  1480. default:
  1481. ShowStatus ("Abnormal end of connection (ip: %s): Unknown packet 0x%x " RETCODE, ip, RFIFOW(fd,0));
  1482. session[fd]->eof = 1;
  1483. return 0;
  1484. }
  1485. }
  1486. RFIFOSKIP(fd,RFIFOREST(fd));
  1487. return 0;
  1488. }
  1489. int parse_console(char* buf)
  1490. {
  1491. char command[256];
  1492. memset(command, 0, sizeof(command));
  1493. sscanf(buf, "%[^\n]", command);
  1494. //login_log("Console command :%s" RETCODE, command);
  1495. if( strcmpi("shutdown", command) == 0 ||
  1496. strcmpi("exit", command) == 0 ||
  1497. strcmpi("quit", command) == 0 ||
  1498. strcmpi("end", command) == 0 )
  1499. runflag = 0;
  1500. else if( strcmpi("alive", command) == 0 ||
  1501. strcmpi("status", command) == 0 )
  1502. ShowInfo(CL_CYAN"Console: "CL_BOLD"I'm Alive."CL_RESET"\n");
  1503. else if( strcmpi("help", command) == 0 ){
  1504. printf(CL_BOLD"Help of commands:"CL_RESET"\n");
  1505. printf(" To shutdown the server:\n");
  1506. printf(" 'shutdown|exit|qui|end'\n");
  1507. printf(" To know if server is alive:\n");
  1508. printf(" 'alive|status'\n");
  1509. }
  1510. return 0;
  1511. }
  1512. static int online_data_cleanup_sub(DBKey key, void *data, va_list ap)
  1513. {
  1514. struct online_login_data *character= (struct online_login_data*)data;
  1515. if (character->char_server == -2) //Unknown server.. set them offline
  1516. remove_online_user(character->account_id);
  1517. else if (character->char_server < 0)
  1518. //Free data from players that have not been online for a while.
  1519. db_remove(online_db, key);
  1520. return 0;
  1521. }
  1522. static int online_data_cleanup(int tid, unsigned int tick, int id, int data)
  1523. {
  1524. online_db->foreach(online_db, online_data_cleanup_sub);
  1525. return 0;
  1526. }
  1527. //----------------------------------
  1528. // Reading Lan Support configuration
  1529. //----------------------------------
  1530. int login_lan_config_read(const char *lancfgName)
  1531. {
  1532. FILE *fp;
  1533. int line_num = 0;
  1534. char line[1024], w1[64], w2[64], w3[64], w4[64];
  1535. if((fp = fopen(lancfgName, "r")) == NULL) {
  1536. ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName);
  1537. return 1;
  1538. }
  1539. ShowInfo("Reading the configuration file %s...\n", lancfgName);
  1540. while(fgets(line, sizeof(line)-1, fp)) {
  1541. line_num++;
  1542. if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n')
  1543. continue;
  1544. line[sizeof(line)-1] = '\0';
  1545. if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) {
  1546. ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num);
  1547. continue;
  1548. }
  1549. remove_control_chars(w1);
  1550. remove_control_chars(w2);
  1551. remove_control_chars(w3);
  1552. remove_control_chars(w4);
  1553. if(strcmpi(w1, "subnet") == 0) {
  1554. subnet[subnet_count].mask = str2ip(w2);
  1555. subnet[subnet_count].char_ip = str2ip(w3);
  1556. subnet[subnet_count].map_ip = str2ip(w4);
  1557. subnet[subnet_count].subnet = subnet[subnet_count].char_ip&subnet[subnet_count].mask;
  1558. if (subnet[subnet_count].subnet != (subnet[subnet_count].map_ip&subnet[subnet_count].mask)) {
  1559. ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4);
  1560. continue;
  1561. }
  1562. subnet_count++;
  1563. }
  1564. ShowStatus("Read information about %d subnetworks.\n", subnet_count);
  1565. }
  1566. fclose(fp);
  1567. return 0;
  1568. }
  1569. //-----------------------------------------------------
  1570. // clear expired ip bans
  1571. //-----------------------------------------------------
  1572. int ip_ban_flush(int tid, unsigned int tick, int id, int data)
  1573. {
  1574. if(mysql_query(&mysql_handle, "DELETE FROM `ipbanlist` WHERE `rtime` <= NOW()")) {
  1575. ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
  1576. ShowDebug("at %s:%d - DELETE FROM `ipbanlist` WHERE `rtime` <= NOW()\n", __FILE__,__LINE__);
  1577. }
  1578. return 0;
  1579. }
  1580. //-----------------------------------
  1581. // Reading main configuration file
  1582. //-----------------------------------
  1583. int login_config_read(const char* cfgName)
  1584. {
  1585. char line[1024], w1[1024], w2[1024];
  1586. FILE* fp = fopen(cfgName, "r");
  1587. if (fp == NULL) {
  1588. ShowError("Configuration file (%s) not found.\n", cfgName);
  1589. return 1;
  1590. }
  1591. ShowInfo("Reading configuration file %s...\n", cfgName);
  1592. while (fgets(line, sizeof(line)-1, fp))
  1593. {
  1594. if (line[0] == '/' && line[1] == '/')
  1595. continue;
  1596. if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) < 2)
  1597. continue;
  1598. remove_control_chars(w1);
  1599. remove_control_chars(w2);
  1600. if(!strcmpi(w1,"timestamp_format")) {
  1601. strncpy(timestamp_format, w2, 20);
  1602. } else if(!strcmpi(w1,"stdout_with_ansisequence")) {
  1603. stdout_with_ansisequence = config_switch(w2);
  1604. } else if(!strcmpi(w1,"console_silent")) {
  1605. ShowInfo("Console Silent Setting: %d\n", atoi(w2));
  1606. msg_silent = atoi(w2);
  1607. }
  1608. else if (!strcmpi(w1, "bind_ip")) {
  1609. char ip_str[16];
  1610. login_config.login_ip = host2ip(w2);
  1611. if (login_config.login_ip)
  1612. ShowStatus("Login server binding IP address : %s -> %s\n", w2, ip2str(login_config.login_ip, ip_str));
  1613. } else if(!strcmpi(w1,"login_port")) {
  1614. login_config.login_port = (uint16)atoi(w2);
  1615. ShowStatus("set login_port : %s\n",w2);
  1616. }
  1617. else if (!strcmpi(w1, "log_login"))
  1618. login_config.log_login = config_switch(w2);
  1619. else if (!strcmpi(w1, "ipban"))
  1620. login_config.ipban = config_switch(w2);
  1621. else if (!strcmpi(w1, "dynamic_pass_failure_ban"))
  1622. login_config.dynamic_pass_failure_ban = config_switch(w2);
  1623. else if (!strcmpi(w1, "dynamic_pass_failure_ban_interval"))
  1624. login_config.dynamic_pass_failure_ban_interval = atoi(w2);
  1625. else if (!strcmpi(w1, "dynamic_pass_failure_ban_limit"))
  1626. login_config.dynamic_pass_failure_ban_limit = atoi(w2);
  1627. else if (!strcmpi(w1, "dynamic_pass_failure_ban_duration"))
  1628. login_config.dynamic_pass_failure_ban_duration = atoi(w2);
  1629. else if (!strcmpi(w1, "new_account"))
  1630. login_config.new_account_flag=config_switch(w2);
  1631. else if (!strcmpi(w1, "check_client_version"))
  1632. login_config.check_client_version=config_switch(w2);
  1633. else if (!strcmpi(w1, "client_version_to_connect"))
  1634. login_config.client_version_to_connect=atoi(w2);
  1635. else if (!strcmpi(w1, "use_MD5_passwords"))
  1636. login_config.use_md5_passwds = config_switch(w2);
  1637. else if (!strcmpi(w1, "min_level_to_connect"))
  1638. login_config.min_level_to_connect = atoi(w2);
  1639. else if (!strcmpi(w1, "date_format"))
  1640. strncpy(login_config.date_format, w2, sizeof(login_config.date_format));
  1641. else if (!strcmpi(w1, "console"))
  1642. login_config.console = config_switch(w2);
  1643. else if (!strcmpi(w1, "case_sensitive"))
  1644. login_config.case_sensitive = config_switch(w2);
  1645. else if (!strcmpi(w1, "allowed_regs")) //account flood protection system
  1646. allowed_regs = atoi(w2);
  1647. else if (!strcmpi(w1, "time_allowed"))
  1648. time_allowed = atoi(w2);
  1649. else if (!strcmpi(w1, "online_check"))
  1650. login_config.online_check = config_switch(w2);
  1651. else if (!strcmpi(w1, "use_dnsbl"))
  1652. login_config.use_dnsbl = config_switch(w2);
  1653. else if (!strcmpi(w1, "dnsbl_servers"))
  1654. { strncpy(login_config.dnsbl_servs, w2, 1023); login_config.dnsbl_servs[1023] = '\0'; }
  1655. else if (!strcmpi(w1, "ip_sync_interval"))
  1656. login_config.ip_sync_interval = 1000*60*atoi(w2); //w2 comes in minutes.
  1657. else if (!strcmpi(w1, "import"))
  1658. login_config_read(w2);
  1659. }
  1660. fclose(fp);
  1661. ShowInfo("Finished reading %s.\n", cfgName);
  1662. return 0;
  1663. }
  1664. void sql_config_read(const char* cfgName)
  1665. {
  1666. char line[1024], w1[1024], w2[1024];
  1667. FILE* fp = fopen(cfgName, "r");
  1668. if(fp == NULL) {
  1669. ShowFatalError("file not found: %s\n", cfgName);
  1670. exit(1);
  1671. }
  1672. ShowInfo("reading configuration file %s...\n", cfgName);
  1673. while (fgets(line, sizeof(line)-1, fp))
  1674. {
  1675. if (line[0] == '/' && line[1] == '/')
  1676. continue;
  1677. if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) < 2)
  1678. continue;
  1679. if (!strcmpi(w1, "gm_read_method"))
  1680. login_config.login_gm_read = (atoi(w2) == 0);
  1681. else if (!strcmpi(w1, "login_db"))
  1682. strcpy(login_db, w2);
  1683. else if (!strcmpi(w1, "login_server_ip"))
  1684. strcpy(login_server_ip, w2);
  1685. else if (!strcmpi(w1, "login_server_port"))
  1686. login_server_port = atoi(w2);
  1687. else if (!strcmpi(w1, "login_server_id"))
  1688. strcpy(login_server_id, w2);
  1689. else if (!strcmpi(w1, "login_server_pw"))
  1690. strcpy(login_server_pw, w2);
  1691. else if (!strcmpi(w1, "login_server_db"))
  1692. strcpy(login_server_db, w2);
  1693. else if (!strcmpi(w1, "default_codepage"))
  1694. strcpy(default_codepage, w2);
  1695. else if (!strcmpi(w1, "login_db_account_id"))
  1696. strcpy(login_db_account_id, w2);
  1697. else if (!strcmpi(w1, "login_db_userid"))
  1698. strcpy(login_db_userid, w2);
  1699. else if (!strcmpi(w1, "login_db_user_pass"))
  1700. strcpy(login_db_user_pass, w2);
  1701. else if (!strcmpi(w1, "login_db_level"))
  1702. strcpy(login_db_level, w2);
  1703. else if (!strcmpi(w1, "loginlog_db"))
  1704. strcpy(loginlog_db, w2);
  1705. else if (!strcmpi(w1, "reg_db"))
  1706. strcpy(reg_db, w2);
  1707. else if (!strcmpi(w1, "import"))
  1708. sql_config_read(w2);
  1709. }
  1710. fclose(fp);
  1711. ShowInfo("done reading %s.\n", cfgName);
  1712. }
  1713. void login_set_defaults()
  1714. {
  1715. login_config.log_login = true;
  1716. login_config.case_sensitive = true;
  1717. login_config.min_level_to_connect = 0;
  1718. login_config.check_client_version = false;
  1719. login_config.client_version_to_connect = 20;
  1720. login_config.new_account_flag = true;
  1721. login_config.online_check = true;
  1722. login_config.ipban = true;
  1723. login_config.dynamic_pass_failure_ban = true;
  1724. login_config.dynamic_pass_failure_ban_interval = 5;
  1725. login_config.dynamic_pass_failure_ban_limit = 7;
  1726. login_config.dynamic_pass_failure_ban_duration = 5;
  1727. login_config.ip_sync_interval = 0;
  1728. login_config.use_dnsbl = false;
  1729. strcpy(login_config.dnsbl_servs, "");
  1730. login_config.use_md5_passwds = false;
  1731. login_config.login_gm_read = true;
  1732. login_config.login_ip = INADDR_ANY;
  1733. login_config.login_port = 6900;
  1734. login_config.console = false;
  1735. strcpy(login_config.date_format, "%Y-%m-%d %H:%M:%S");
  1736. }
  1737. //--------------------------------------
  1738. // Function called at exit of the server
  1739. //--------------------------------------
  1740. void do_final(void)
  1741. {
  1742. //sync account when terminating.
  1743. //but no need when you using DBMS (mysql)
  1744. ShowStatus("Terminating...\n");
  1745. mmo_db_close();
  1746. online_db->destroy(online_db, NULL);
  1747. if (gm_account_db)
  1748. aFree(gm_account_db);
  1749. }
  1750. //------------------------------
  1751. // Function called when the server
  1752. // has received a crash signal.
  1753. //------------------------------
  1754. void do_abort(void) {
  1755. }
  1756. void set_server_type(void)
  1757. {
  1758. SERVER_TYPE = ATHENA_SERVER_LOGIN;
  1759. }
  1760. int do_init(int argc, char** argv)
  1761. {
  1762. // initialize login server
  1763. int i;
  1764. login_set_defaults();
  1765. // read login-server configuration
  1766. login_config_read((argc > 1) ? argv[1] : LOGIN_CONF_NAME);
  1767. sql_config_read(SQL_CONF_NAME);
  1768. login_lan_config_read((argc > 2) ? argv[2] : LAN_CONF_NAME);
  1769. srand((unsigned int)time(NULL));
  1770. for(i=0;i<AUTH_FIFO_SIZE;i++)
  1771. auth_fifo[i].delflag=1;
  1772. for(i=0;i<MAX_SERVERS;i++)
  1773. server_fd[i]=-1;
  1774. // Online user database init
  1775. online_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
  1776. add_timer_func_list(waiting_disconnect_timer, "waiting_disconnect_timer");
  1777. // Auth init
  1778. mmo_auth_sqldb_init();
  1779. // Read account information.
  1780. if(login_config.login_gm_read)
  1781. read_gm_account();
  1782. // set default parser as parse_login function
  1783. set_defaultparse(parse_login);
  1784. // ban deleter timer
  1785. add_timer_func_list(ip_ban_flush, "ip_ban_flush");
  1786. add_timer_interval(gettick()+10, ip_ban_flush, 0, 0, 60*1000);
  1787. // every 10 minutes cleanup online account db.
  1788. add_timer_func_list(online_data_cleanup, "online_data_cleanup");
  1789. add_timer_interval(gettick() + 600*1000, online_data_cleanup, 0, 0, 600*1000);
  1790. if (login_config.ip_sync_interval) {
  1791. add_timer_func_list(sync_ip_addresses, "sync_ip_addresses");
  1792. add_timer_interval(gettick() + login_config.ip_sync_interval, sync_ip_addresses, 0, 0, login_config.ip_sync_interval);
  1793. }
  1794. if( login_config.console )
  1795. {
  1796. //##TODO invoke a CONSOLE_START plugin event
  1797. }
  1798. new_reg_tick = gettick();
  1799. // server port open & binding
  1800. login_fd = make_listen_bind(login_config.login_ip, login_config.login_port);
  1801. ShowStatus("The login-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %u).\n\n", login_config.login_port);
  1802. return 0;
  1803. }