diff options
Diffstat (limited to 'src/login/login.c')
-rw-r--r-- | src/login/login.c | 1000 |
1 files changed, 522 insertions, 478 deletions
diff --git a/src/login/login.c b/src/login/login.c index d4768df86..ae584206f 100644 --- a/src/login/login.c +++ b/src/login/login.c @@ -2,7 +2,7 @@ * This file is part of Hercules. * http://herc.ws - http://github.com/HerculesWS/Hercules * - * Copyright (C) 2012-2015 Hercules Dev Team + * Copyright (C) 2012-2016 Hercules Dev Team * Copyright (C) Athena Dev Teams * * Hercules is free software: you can redistribute it and/or modify @@ -26,6 +26,7 @@ #include "login/account.h" #include "login/ipban.h" #include "login/loginlog.h" +#include "login/lclif.h" #include "common/HPM.h" #include "common/cbasetypes.h" #include "common/conf.h" @@ -43,6 +44,11 @@ #include <stdio.h> #include <stdlib.h> +#include <sys/stat.h> // stat() + +/** @file + * Implementation of the login interface. + */ struct login_interface login_s; struct login_interface *login; @@ -64,7 +70,7 @@ AccountDB* accounts = NULL; /** * @see DBCreateData */ -static DBData login_create_online_user(DBKey key, va_list args) +static struct DBData login_create_online_user(union DBKey key, va_list args) { struct online_login_data* p; CREATE(p, struct online_login_data, 1); @@ -113,7 +119,7 @@ static int login_waiting_disconnect_timer(int tid, int64 tick, int id, intptr_t /** * @see DBApply */ -static int login_online_db_setoffline(DBKey key, DBData *data, va_list ap) +static int login_online_db_setoffline(union DBKey key, struct DBData *data, va_list ap) { struct online_login_data* p = DB->data2ptr(data); int server_id = va_arg(ap, int); @@ -135,7 +141,7 @@ static int login_online_db_setoffline(DBKey key, DBData *data, va_list ap) /** * @see DBApply */ -static int login_online_data_cleanup_sub(DBKey key, DBData *data, va_list ap) +static int login_online_data_cleanup_sub(union DBKey key, struct DBData *data, va_list ap) { struct online_login_data *character= DB->data2ptr(data); nullpo_ret(character); @@ -235,7 +241,7 @@ bool login_check_encrypted(const char* str1, const char* str2, const char* passw nullpo_ret(str2); nullpo_ret(passwd); safesnprintf(tmpstr, sizeof(tmpstr), "%s%s", str1, str2); - MD5_String(tmpstr, md5str); + md5->string(tmpstr, md5str); return (0==strcmp(passwd, md5str)); } @@ -353,7 +359,7 @@ void login_fromchar_parse_request_change_email(int fd, int id, const char *const char email[40]; int account_id = RFIFOL(fd,2); - safestrncpy(email, (char*)RFIFOP(fd,6), 40); remove_control_chars(email); + safestrncpy(email, RFIFOP(fd,6), 40); remove_control_chars(email); RFIFOSKIP(fd,46); if( e_mail_check(email) == 0 ) @@ -392,22 +398,22 @@ void login_fromchar_account(int fd, int account_id, struct mmo_account *acc) if (pincode[0] == '\0') memset(pincode,'\0',sizeof(pincode)); - safestrncpy((char*)WFIFOP(fd,6), email, 40); + safestrncpy(WFIFOP(fd,6), email, 40); WFIFOL(fd,46) = (uint32)expiration_time; WFIFOB(fd,50) = (unsigned char)group_id; WFIFOB(fd,51) = char_slots; - safestrncpy((char*)WFIFOP(fd,52), birthdate, 10+1); - safestrncpy((char*)WFIFOP(fd,63), pincode, 4+1 ); + safestrncpy(WFIFOP(fd,52), birthdate, 10+1); + safestrncpy(WFIFOP(fd,63), pincode, 4+1 ); WFIFOL(fd,68) = acc->pincode_change; } else { - safestrncpy((char*)WFIFOP(fd,6), "", 40); + safestrncpy(WFIFOP(fd,6), "", 40); WFIFOL(fd,46) = 0; WFIFOB(fd,50) = 0; WFIFOB(fd,51) = 0; - safestrncpy((char*)WFIFOP(fd,52), "", 10+1); - safestrncpy((char*)WFIFOP(fd,63), "\0\0\0\0", 4+1 ); + safestrncpy(WFIFOP(fd,52), "", 10+1); + safestrncpy(WFIFOP(fd,63), "\0\0\0\0", 4+1 ); WFIFOL(fd,68) = 0; } WFIFOSET(fd,72); @@ -450,8 +456,8 @@ void login_fromchar_parse_change_email(int fd, int id, const char *const ip) char new_email[40]; int account_id = RFIFOL(fd,2); - safestrncpy(actual_email, (char*)RFIFOP(fd,6), 40); - safestrncpy(new_email, (char*)RFIFOP(fd,46), 40); + safestrncpy(actual_email, RFIFOP(fd,6), 40); + safestrncpy(new_email, RFIFOP(fd,46), 40); RFIFOSKIP(fd, 86); if( e_mail_check(actual_email) == 0 ) @@ -495,12 +501,12 @@ void login_fromchar_parse_account_update(int fd, int id, const char *const ip) RFIFOSKIP(fd,10); if( !accounts->load_num(accounts, &acc, account_id) ) - ShowNotice("Char-server '%s': Error of Status change (account: %d not found, suggested status %d, ip: %s).\n", server[id].name, account_id, state, ip); + ShowNotice("Char-server '%s': Error of Status change (account: %d not found, suggested status %u, ip: %s).\n", server[id].name, account_id, state, ip); else if( acc.state == state ) - ShowNotice("Char-server '%s': Error of Status change - actual status is already the good status (account: %d, status %d, ip: %s).\n", server[id].name, account_id, state, ip); + ShowNotice("Char-server '%s': Error of Status change - actual status is already the good status (account: %d, status %u, ip: %s).\n", server[id].name, account_id, state, ip); else { - ShowNotice("Char-server '%s': Status change (account: %d, new status %d, ip: %s).\n", server[id].name, account_id, state, ip); + ShowNotice("Char-server '%s': Status change (account: %d, new status %u, ip: %s).\n", server[id].name, account_id, state, ip); acc.state = state; // Save @@ -528,12 +534,12 @@ void login_fromchar_parse_ban(int fd, int id, const char *const ip) struct mmo_account acc; int account_id = RFIFOL(fd,2); - int year = (short)RFIFOW(fd,6); - int month = (short)RFIFOW(fd,8); - int mday = (short)RFIFOW(fd,10); - int hour = (short)RFIFOW(fd,12); - int min = (short)RFIFOW(fd,14); - int sec = (short)RFIFOW(fd,16); + int year = RFIFOW(fd,6); + int month = RFIFOW(fd,8); + int mday = RFIFOW(fd,10); + int hour = RFIFOW(fd,12); + int min = RFIFOW(fd,14); + int sec = RFIFOW(fd,16); RFIFOSKIP(fd,18); if (!accounts->load_num(accounts, &acc, account_id)) { @@ -684,7 +690,7 @@ void login_fromchar_parse_request_account_reg2(int fd) void login_fromchar_parse_update_wan_ip(int fd, int id) { server[id].ip = ntohl(RFIFOL(fd,2)); - ShowInfo("Updated IP of Server #%d to %d.%d.%d.%d.\n",id, CONVIP(server[id].ip)); + ShowInfo("Updated IP of Server #%d to %u.%u.%u.%u.\n",id, CONVIP(server[id].ip)); RFIFOSKIP(fd,6); } @@ -700,7 +706,7 @@ void login_fromchar_parse_change_pincode(int fd) struct mmo_account acc; if (accounts->load_num(accounts, &acc, RFIFOL(fd,2))) { - safestrncpy(acc.pincode, (char*)RFIFOP(fd,6), sizeof(acc.pincode)); + safestrncpy(acc.pincode, RFIFOP(fd,6), sizeof(acc.pincode)); acc.pincode_change = ((unsigned int)time(NULL)); accounts->save(accounts, &acc); } @@ -733,22 +739,22 @@ void login_fromchar_accinfo(int fd, int account_id, int u_fd, int u_aid, int u_g { WFIFOHEAD(fd,183); WFIFOW(fd,0) = 0x2737; - safestrncpy((char*)WFIFOP(fd,2), acc->userid, NAME_LENGTH); + safestrncpy(WFIFOP(fd,2), acc->userid, NAME_LENGTH); if (u_group >= acc->group_id) - safestrncpy((char*)WFIFOP(fd,26), acc->pass, 33); + safestrncpy(WFIFOP(fd,26), acc->pass, 33); else memset(WFIFOP(fd,26), '\0', 33); - safestrncpy((char*)WFIFOP(fd,59), acc->email, 40); - safestrncpy((char*)WFIFOP(fd,99), acc->last_ip, 16); + safestrncpy(WFIFOP(fd,59), acc->email, 40); + safestrncpy(WFIFOP(fd,99), acc->last_ip, 16); WFIFOL(fd,115) = acc->group_id; - safestrncpy((char*)WFIFOP(fd,119), acc->lastlogin, 24); + safestrncpy(WFIFOP(fd,119), acc->lastlogin, 24); WFIFOL(fd,143) = acc->logincount; WFIFOL(fd,147) = acc->state; if (u_group >= acc->group_id) - safestrncpy((char*)WFIFOP(fd,151), acc->pincode, 5); + safestrncpy(WFIFOP(fd,151), acc->pincode, 5); else memset(WFIFOP(fd,151), '\0', 5); - safestrncpy((char*)WFIFOP(fd,156), acc->birthdate, 11); + safestrncpy(WFIFOP(fd,156), acc->birthdate, 11); WFIFOL(fd,167) = map_fd; WFIFOL(fd,171) = u_fd; WFIFOL(fd,175) = u_aid; @@ -813,8 +819,11 @@ int login_parse_fromchar(int fd) if (VECTOR_LENGTH(HPM->packets[hpParse_FromChar]) > 0) { int result = HPM->parse_packets(fd,command,hpParse_FromChar); - if (result == 1) + if (result == 1) { + if (sockt->session[fd] == NULL) + return 0; continue; + } if (result == 2) return 0; } @@ -1020,7 +1029,7 @@ int login_mmo_auth_new(const char* userid, const char* pass, const char sex, con acc.sex = sex; safestrncpy(acc.email, "a@a.com", sizeof(acc.email)); acc.expiration_time = (login->config->start_limited_time != -1) ? time(NULL) + login->config->start_limited_time : 0; - safestrncpy(acc.lastlogin, "0000-00-00 00:00:00", sizeof(acc.lastlogin)); + safestrncpy(acc.lastlogin, "(never)", sizeof(acc.lastlogin)); safestrncpy(acc.last_ip, last_ip, sizeof(acc.last_ip)); safestrncpy(acc.birthdate, "0000-00-00", sizeof(acc.birthdate)); safestrncpy(acc.pincode, "\0", sizeof(acc.pincode)); @@ -1057,13 +1066,14 @@ int login_mmo_auth(struct login_session_data* sd, bool isServer) { if (login->config->use_dnsbl) { char r_ip[16]; char ip_dnsbl[256]; - char* dnsbl_serv; uint8* sin_addr = (uint8*)&sockt->session[sd->fd]->client_addr; + int i; sprintf(r_ip, "%u.%u.%u.%u", sin_addr[0], sin_addr[1], sin_addr[2], sin_addr[3]); - for (dnsbl_serv = strtok(login->config->dnsbl_servs,","); dnsbl_serv != NULL; dnsbl_serv = strtok(NULL,",")) { - sprintf(ip_dnsbl, "%s.%s", r_ip, trim(dnsbl_serv)); + for (i = 0; i < VECTOR_LENGTH(login->config->dnsbl_servers); i++) { + char *dnsbl_server = VECTOR_INDEX(login->config->dnsbl_servers, i); + sprintf(ip_dnsbl, "%s.%s", r_ip, trim(dnsbl_server)); if (sockt->host2ip(ip_dnsbl)) { ShowInfo("DNSBL: (%s) Blacklisted. User Kicked.\n", r_ip); return 3; @@ -1119,7 +1129,7 @@ int login_mmo_auth(struct login_session_data* sd, bool isServer) { } if( acc.state != 0 ) { - ShowNotice("Connection refused (account: %s, pass: %s, state: %d, ip: %s)\n", sd->userid, sd->passwd, acc.state, ip); + ShowNotice("Connection refused (account: %s, pass: %s, state: %u, ip: %s)\n", sd->userid, sd->passwd, acc.state, ip); return acc.state - 1; } @@ -1181,14 +1191,6 @@ int login_mmo_auth(struct login_session_data* sd, bool isServer) { return -1; // account OK } -void login_connection_problem(int fd, uint8 status) -{ - WFIFOHEAD(fd,3); - WFIFOW(fd,0) = 0x81; - WFIFOB(fd,2) = status; - WFIFOSET(fd,3); -} - void login_kick(struct login_session_data* sd) { uint8 buf[6]; @@ -1202,9 +1204,7 @@ void login_auth_ok(struct login_session_data* sd) { int fd = 0; uint32 ip; - uint8 server_num, n; struct login_auth_node* node; - int i; nullpo_retv(sd); fd = sd->fd; @@ -1212,29 +1212,17 @@ void login_auth_ok(struct login_session_data* sd) if( core->runflag != LOGINSERVER_ST_RUNNING ) { // players can only login while running - login->connection_problem(fd, 1); // 01 = server closed + lclif->connection_error(fd, 1); // 01 = server closed return; } if (login->config->group_id_to_connect >= 0 && sd->group_id != login->config->group_id_to_connect) { ShowStatus("Connection refused: the required group id for connection is %d (account: %s, group: %d).\n", login->config->group_id_to_connect, sd->userid, sd->group_id); - login->connection_problem(fd, 1); // 01 = server closed + lclif->connection_error(fd, 1); // 01 = server closed return; } else if (login->config->min_group_id_to_connect >= 0 && login->config->group_id_to_connect == -1 && sd->group_id < login->config->min_group_id_to_connect) { ShowStatus("Connection refused: the minimum group id required for connection is %d (account: %s, group: %d).\n", login->config->min_group_id_to_connect, sd->userid, sd->group_id); - login->connection_problem(fd, 1); // 01 = server closed - return; - } - - server_num = 0; - for( i = 0; i < ARRAYLENGTH(server); ++i ) - if (sockt->session_is_active(server[i].fd)) - server_num++; - - if( server_num == 0 ) - {// if no char-server, don't send void list of servers, just disconnect the player with proper message - ShowStatus("Connection refused: there is no char-server online (account: %s).\n", sd->userid); - login->connection_problem(fd, 1); // 01 = server closed + lclif->connection_error(fd, 1); // 01 = server closed return; } @@ -1249,7 +1237,7 @@ void login_auth_ok(struct login_session_data* sd) if( data->waiting_disconnect == INVALID_TIMER ) data->waiting_disconnect = timer->add(timer->gettick()+AUTH_TIMEOUT, login->waiting_disconnect_timer, sd->account_id, 0); - login->connection_problem(fd, 8); // 08 = Server still recognizes your last login + lclif->connection_error(fd, 8); // 08 = Server still recognizes your last login return; } else @@ -1263,42 +1251,16 @@ void login_auth_ok(struct login_session_data* sd) } } + if (!lclif->server_list(sd)) { + // if no char-server, don't send void list of servers, just disconnect the player with proper message + ShowStatus("Connection refused: there is no char-server online (account: %s).\n", sd->userid); + lclif->connection_error(fd, 1); // 01 = server closed + return; + } + login_log(ip, sd->userid, 100, "login ok"); ShowStatus("Connection of the account '%s' accepted.\n", sd->userid); - WFIFOHEAD(fd,47+32*server_num); - WFIFOW(fd,0) = 0x69; - WFIFOW(fd,2) = 47+32*server_num; - WFIFOL(fd,4) = sd->login_id1; - WFIFOL(fd,8) = sd->account_id; - WFIFOL(fd,12) = sd->login_id2; - WFIFOL(fd,16) = 0; // in old version, that was for ip (not more used) - //memcpy(WFIFOP(fd,20), sd->lastlogin, 24); // in old version, that was for name (not more used) - memset(WFIFOP(fd,20), 0, 24); - WFIFOW(fd,44) = 0; // unknown - WFIFOB(fd,46) = sex_str2num(sd->sex); - for (i = 0, n = 0; i < ARRAYLENGTH(server); ++i) { - uint32 subnet_char_ip; - - if (!sockt->session_is_valid(server[i].fd)) - continue; - - subnet_char_ip = login->lan_subnet_check(ip); - WFIFOL(fd,47+n*32) = htonl((subnet_char_ip) ? subnet_char_ip : server[i].ip); - WFIFOW(fd,47+n*32+4) = sockt->ntows(htons(server[i].port)); // [!] LE byte order here [!] - memcpy(WFIFOP(fd,47+n*32+6), server[i].name, 20); - WFIFOW(fd,47+n*32+26) = server[i].users; - - if( server[i].type == CST_PAYING && sd->expiration_time > time(NULL) ) - WFIFOW(fd,47+n*32+28) = CST_NORMAL; - else - WFIFOW(fd,47+n*32+28) = server[i].type; - - WFIFOW(fd,47+n*32+30) = server[i].new_; - n++; - } - WFIFOSET(fd,47+32*server_num); - // create temporary auth entry CREATE(node, struct login_auth_node, 1); node->account_id = sd->account_id; @@ -1323,10 +1285,11 @@ void login_auth_ok(struct login_session_data* sd) } } -void login_auth_failed(struct login_session_data* sd, int result) +void login_auth_failed(struct login_session_data *sd, int result) { int fd; uint32 ip; + time_t ban_time = 0; nullpo_retv(sd); fd = sd->fd; @@ -1365,121 +1328,23 @@ void login_auth_failed(struct login_session_data* sd, int result) if (result == 1 && login->config->dynamic_pass_failure_ban && !sockt->trusted_ip_check(ip)) ipban_log(ip); // log failed password attempt -#if PACKETVER >= 20120000 /* not sure when this started */ - WFIFOHEAD(fd,26); - WFIFOW(fd,0) = 0x83e; - WFIFOL(fd,2) = result; - if( result != 6 ) - memset(WFIFOP(fd,6), '\0', 20); - else { // 6 = Your are Prohibited to log in until %s - struct mmo_account acc; - time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0; - timestamp2string((char*)WFIFOP(fd,6), 20, unban_time, login->config->date_format); - } - WFIFOSET(fd,26); -#else - WFIFOHEAD(fd,23); - WFIFOW(fd,0) = 0x6a; - WFIFOB(fd,2) = (uint8)result; - if( result != 6 ) - memset(WFIFOP(fd,3), '\0', 20); - else { // 6 = Your are Prohibited to log in until %s - struct mmo_account acc; - time_t unban_time = ( accounts->load_str(accounts, &acc, sd->userid) ) ? acc.unban_time : 0; - timestamp2string((char*)WFIFOP(fd,3), 20, unban_time, login->config->date_format); - } - WFIFOSET(fd,23); -#endif -} - -void login_login_error(int fd, uint8 status) -{ - WFIFOHEAD(fd,23); - WFIFOW(fd,0) = 0x6a; - WFIFOB(fd,2) = status; - WFIFOSET(fd,23); -} - -void login_parse_ping(int fd, struct login_session_data* sd) __attribute__((nonnull (2))); -void login_parse_ping(int fd, struct login_session_data* sd) -{ - RFIFOSKIP(fd,26); -} - -void login_parse_client_md5(int fd, struct login_session_data* sd) __attribute__((nonnull (2))); -void login_parse_client_md5(int fd, struct login_session_data* sd) -{ - sd->has_client_hash = 1; - memcpy(sd->client_hash, RFIFOP(fd, 2), 16); - - RFIFOSKIP(fd,18); + if (result == 6) { + struct mmo_account acc = { 0 }; + if (accounts->load_str(accounts, &acc, sd->userid)) + ban_time = acc.unban_time; + } + lclif->auth_failed(fd, ban_time, result); } -bool login_parse_client_login(int fd, struct login_session_data* sd, const char *const ip) __attribute__((nonnull (2))); -bool login_parse_client_login(int fd, struct login_session_data* sd, const char *const ip) +bool login_client_login(int fd, struct login_session_data *sd) __attribute__((nonnull (2))); +bool login_client_login(int fd, struct login_session_data *sd) { - uint32 version; - char username[NAME_LENGTH]; - char password[PASSWD_LEN]; - unsigned char passhash[16]; - uint8 clienttype; int result; - uint16 command = RFIFOW(fd,0); - bool israwpass = (command==0x0064 || command==0x0277 || command==0x02b0 || command == 0x0825); - - // Shinryo: For the time being, just use token as password. - if(command == 0x0825) - { - char *accname = (char *)RFIFOP(fd, 9); - char *token = (char *)RFIFOP(fd, 0x5C); - size_t uAccLen = strlen(accname); - size_t uTokenLen = RFIFOREST(fd) - 0x5C; - - version = RFIFOL(fd,4); - - if(uAccLen <= 0 || uTokenLen <= 0) { - login->auth_failed(sd, 3); - return true; - } - - safestrncpy(username, accname, NAME_LENGTH); - safestrncpy(password, token, min(uTokenLen+1, PASSWD_LEN)); // Variable-length field, don't copy more than necessary - clienttype = RFIFOB(fd, 8); - } - else - { - version = RFIFOL(fd,2); - safestrncpy(username, (const char*)RFIFOP(fd,6), NAME_LENGTH); - if( israwpass ) - { - safestrncpy(password, (const char*)RFIFOP(fd,30), NAME_LENGTH); - clienttype = RFIFOB(fd,54); - } - else - { - memcpy(passhash, RFIFOP(fd,30), 16); - clienttype = RFIFOB(fd,46); - } - } - RFIFOSKIP(fd,RFIFOREST(fd)); // assume no other packet was sent + char ip[16]; + uint32 ipl = sockt->session[fd]->client_addr; + sockt->ip2str(ipl, ip); - sd->clienttype = clienttype; - sd->version = version; - safestrncpy(sd->userid, username, NAME_LENGTH); - if( israwpass ) - { - ShowStatus("Request for connection of %s (ip: %s).\n", sd->userid, ip); - safestrncpy(sd->passwd, password, PASSWD_LEN); - if (login->config->use_md5_passwds) - MD5_String(sd->passwd, sd->passwd); - sd->passwdenc = PWENC_NONE; - } - else - { - ShowStatus("Request for connection (passwdenc mode) of %s (ip: %s).\n", sd->userid, ip); - bin2hex(sd->passwd, passhash, 16); // raw binary data here! - sd->passwdenc = PASSWORDENC; - } + ShowStatus("Request for connection %sof %s (ip: %s).\n", sd->passwdenc == PASSWORDENC ? " (passwdenc mode)" : "", sd->userid, ip); if (sd->passwdenc != PWENC_NONE && login->config->use_md5_passwds) { login->auth_failed(sd, 3); // send "rejected from server" @@ -1487,32 +1352,12 @@ bool login_parse_client_login(int fd, struct login_session_data* sd, const char } result = login->mmo_auth(sd, false); - if( result == -1 ) login->auth_ok(sd); else login->auth_failed(sd, result); - return false; -} - -void login_send_coding_key(int fd, struct login_session_data* sd) __attribute__((nonnull (2))); -void login_send_coding_key(int fd, struct login_session_data* sd) -{ - WFIFOHEAD(fd,4 + sd->md5keylen); - WFIFOW(fd,0) = 0x01dc; - WFIFOW(fd,2) = 4 + sd->md5keylen; - memcpy(WFIFOP(fd,4), sd->md5key, sd->md5keylen); - WFIFOSET(fd,WFIFOW(fd,2)); -} - -void login_parse_request_coding_key(int fd, struct login_session_data* sd) __attribute__((nonnull (2))); -void login_parse_request_coding_key(int fd, struct login_session_data* sd) -{ - memset(sd->md5key, '\0', sizeof(sd->md5key)); - sd->md5keylen = (uint16)(12 + rnd() % 4); - MD5_Salt(sd->md5keylen, sd->md5key); - login->send_coding_key(fd, sd); + return false; } void login_char_server_connection_status(int fd, struct login_session_data* sd, uint8 status) __attribute__((nonnull (2))); @@ -1524,6 +1369,7 @@ void login_char_server_connection_status(int fd, struct login_session_data* sd, WFIFOSET(fd,3); } +// CA_CHARSERVERCONNECT void login_parse_request_connection(int fd, struct login_session_data* sd, const char *const ip, uint32 ipl) __attribute__((nonnull (2, 3))); void login_parse_request_connection(int fd, struct login_session_data* sd, const char *const ip, uint32 ipl) { @@ -1535,18 +1381,17 @@ void login_parse_request_connection(int fd, struct login_session_data* sd, const uint16 new_; int result; - safestrncpy(sd->userid, (char*)RFIFOP(fd,2), NAME_LENGTH); - safestrncpy(sd->passwd, (char*)RFIFOP(fd,26), NAME_LENGTH); + safestrncpy(sd->userid, RFIFOP(fd,2), NAME_LENGTH); + safestrncpy(sd->passwd, RFIFOP(fd,26), NAME_LENGTH); if (login->config->use_md5_passwds) - MD5_String(sd->passwd, sd->passwd); + md5->string(sd->passwd, sd->passwd); sd->passwdenc = PWENC_NONE; sd->version = login->config->client_version_to_connect; // hack to skip version check server_ip = ntohl(RFIFOL(fd,54)); server_port = ntohs(RFIFOW(fd,58)); - safestrncpy(server_name, (char*)RFIFOP(fd,60), 20); + safestrncpy(server_name, RFIFOP(fd,60), 20); type = RFIFOW(fd,82); new_ = RFIFOW(fd,84); - RFIFOSKIP(fd,86); ShowInfo("Connection request of the char-server '%s' @ %u.%u.%u.%u:%u (account: '%s', pass: '%s', ip: '%s')\n", server_name, CONVIP(server_ip), server_port, sd->userid, sd->passwd, ip); sprintf(message, "charserver - %s@%u.%u.%u.%u:%u", server_name, CONVIP(server_ip), server_port); @@ -1584,121 +1429,6 @@ void login_parse_request_connection(int fd, struct login_session_data* sd, const } } -//---------------------------------------------------------------------------------------- -// Default packet parsing (normal players or char-server connection requests) -//---------------------------------------------------------------------------------------- -int login_parse_login(int fd) -{ - struct login_session_data* sd = (struct login_session_data*)sockt->session[fd]->session_data; - - char ip[16]; - uint32 ipl = sockt->session[fd]->client_addr; - sockt->ip2str(ipl, ip); - - if( sockt->session[fd]->flag.eof ) - { - ShowInfo("Closed connection from '"CL_WHITE"%s"CL_RESET"'.\n", ip); - sockt->close(fd); - return 0; - } - - if( sd == NULL ) - { - // Perform ip-ban check - if (login->config->ipban && !sockt->trusted_ip_check(ipl) && ipban_check(ipl)) { - ShowStatus("Connection refused: IP isn't authorized (deny/allow, ip: %s).\n", ip); - login_log(ipl, "unknown", -3, "ip banned"); - login->login_error(fd, 3); // 3 = Rejected from Server - sockt->eof(fd); - return 0; - } - - // create a session for this new connection - CREATE(sockt->session[fd]->session_data, struct login_session_data, 1); - sd = (struct login_session_data*)sockt->session[fd]->session_data; - sd->fd = fd; - } - - while (RFIFOREST(fd) >= 2) { - uint16 command = RFIFOW(fd,0); - - if (VECTOR_LENGTH(HPM->packets[hpParse_Login]) > 0) { - int result = HPM->parse_packets(fd,command,hpParse_Login); - if (result == 1) - continue; - if (result == 2) - return 0; - } - - switch (command) { - - case 0x0200: // New alive packet: structure: 0x200 <account.userid>.24B. used to verify if client is always alive. - if (RFIFOREST(fd) < 26) - return 0; - login->parse_ping(fd, sd); - break; - - // client md5 hash (binary) - case 0x0204: // S 0204 <md5 hash>.16B (kRO 2004-05-31aSakexe langtype 0 and 6) - if (RFIFOREST(fd) < 18) - return 0; - - login->parse_client_md5(fd, sd); - break; - - // request client login (raw password) - case 0x0064: // S 0064 <version>.L <username>.24B <password>.24B <clienttype>.B - case 0x0277: // S 0277 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B - case 0x02b0: // S 02b0 <version>.L <username>.24B <password>.24B <clienttype>.B <ip address>.16B <adapter address>.13B <g_isGravityID>.B - // request client login (md5-hashed password) - case 0x01dd: // S 01dd <version>.L <username>.24B <password hash>.16B <clienttype>.B - case 0x01fa: // S 01fa <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.B(index of the connection in the clientinfo file (+10 if the command-line contains "pc")) - case 0x027c: // S 027c <version>.L <username>.24B <password hash>.16B <clienttype>.B <?>.13B(junk) - case 0x0825: // S 0825 <packetsize>.W <version>.L <clienttype>.B <userid>.24B <password>.27B <mac>.17B <ip>.15B <token>.(packetsize - 0x5C)B - { - size_t packet_len = RFIFOREST(fd); - - if( (command == 0x0064 && packet_len < 55) - || (command == 0x0277 && packet_len < 84) - || (command == 0x02b0 && packet_len < 85) - || (command == 0x01dd && packet_len < 47) - || (command == 0x01fa && packet_len < 48) - || (command == 0x027c && packet_len < 60) - || (command == 0x0825 && (packet_len < 4 || packet_len < RFIFOW(fd, 2))) ) - return 0; - } - { - if (login->parse_client_login(fd, sd, ip)) - return 0; - } - break; - - case 0x01db: // Sending request of the coding key - RFIFOSKIP(fd,2); - { - login->parse_request_coding_key(fd, sd); - } - break; - - case 0x2710: // Connection request of a char-server - if (RFIFOREST(fd) < 86) - return 0; - { - login->parse_request_connection(fd, sd, ip, ipl); - } - return 0; // processing will continue elsewhere - - default: - ShowNotice("Abnormal end of connection (ip: %s): Unknown packet 0x%x\n", ip, command); - sockt->eof(fd); - return 0; - } - } - - return 0; -} - - void login_config_set_defaults(void) { login->config->login_ip = INADDR_ANY; @@ -1723,150 +1453,432 @@ void login_config_set_defaults(void) login->config->dynamic_pass_failure_ban_limit = 7; login->config->dynamic_pass_failure_ban_duration = 5; login->config->use_dnsbl = false; - safestrncpy(login->config->dnsbl_servs, "", sizeof(login->config->dnsbl_servs)); + VECTOR_INIT(login->config->dnsbl_servers); login->config->client_hash_check = 0; login->config->client_hash_nodes = NULL; } -//----------------------------------- -// Reading main configuration file -//----------------------------------- -int login_config_read(const char *cfgName) +/** + * Reads 'login_configuration/inter' and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool login_config_read_inter(const char *filename, struct config_t *config, bool imported) { - char line[1024], w1[1024], w2[1024]; - FILE* fp; - nullpo_retr(1, cfgName); - fp = fopen(cfgName, "r"); - if (fp == NULL) { - ShowError("Configuration file (%s) not found.\n", cfgName); - return 1; + struct config_setting_t *setting = NULL; + const char *str = NULL; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "login_configuration/inter")) == NULL) { + if (imported) + return true; + ShowError("login_config_read: login_configuration/inter was not found in %s!\n", filename); + return false; + } + + libconfig->setting_lookup_uint16(setting, "login_port", &login->config->login_port); + + if (libconfig->setting_lookup_uint32(setting, "ip_sync_interval", &login->config->ip_sync_interval) == CONFIG_TRUE) + login->config->ip_sync_interval *= 1000*60; // In minutes + + if (libconfig->setting_lookup_string(setting, "bind_ip", &str) == CONFIG_TRUE) { + char old_ip_str[16]; + sockt->ip2str(login->config->login_ip, old_ip_str); + + if ((login->config->login_ip = sockt->host2ip(str)) != 0) + ShowStatus("Login server binding IP address : %s -> %s\n", old_ip_str, str); + } + + return true; +} + +/** + * Reads 'login_configuration.console' and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool login_config_read_console(const char *filename, struct config_t *config, bool imported) +{ + struct config_setting_t *setting = NULL; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "login_configuration/console")) == NULL) { + if (imported) + return true; + ShowError("login_config_read: login_configuration/console was not found in %s!\n", filename); + return false; + } + + libconfig->setting_lookup_bool_real(setting, "stdout_with_ansisequence", &showmsg->stdout_with_ansisequence); + if (libconfig->setting_lookup_int(setting, "console_silent", &showmsg->silent) == CONFIG_TRUE) { + if (showmsg->silent) // only bother if its actually enabled + ShowInfo("Console Silent Setting: %d\n", showmsg->silent); + } + libconfig->setting_lookup_mutable_string(setting, "timestamp_format", showmsg->timestamp_format, sizeof(showmsg->timestamp_format)); + + return true; +} + +/** + * Reads 'login_configuration.log' and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool login_config_read_log(const char *filename, struct config_t *config, bool imported) +{ + struct config_setting_t *setting = NULL; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "login_configuration/log")) == NULL) { + if (imported) + return true; + ShowError("login_config_read: login_configuration/log was not found in %s!\n", filename); + return false; + } + + libconfig->setting_lookup_bool_real(setting, "log_login", &login->config->log_login); + libconfig->setting_lookup_mutable_string(setting, "date_format", login->config->date_format, sizeof(login->config->date_format)); + return true; +} + +/** + * Reads 'login_configuration.account' and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool login_config_read_account(const char *filename, struct config_t *config, bool imported) +{ + struct config_setting_t *setting = NULL; + AccountDB *db = account_engine[0].db; + bool retval = true; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "login_configuration/account")) == NULL) { + if (imported) + return true; + ShowError("login_config_read: login_configuration/account was not found in %s!\n", filename); + return false; + } + + libconfig->setting_lookup_bool_real(setting, "new_account", &login->config->new_account_flag); + libconfig->setting_lookup_bool_real(setting, "new_acc_length_limit", &login->config->new_acc_length_limit); + + libconfig->setting_lookup_int(setting, "allowed_regs", &login->config->allowed_regs); + libconfig->setting_lookup_int(setting, "time_allowed", &login->config->time_allowed); + libconfig->setting_lookup_int(setting, "start_limited_time", &login->config->start_limited_time); + libconfig->setting_lookup_bool_real(setting, "use_MD5_passwords", &login->config->use_md5_passwds); + + if (!db->set_property(db, config, imported)) + retval = false; + if (!ipban_config_read(filename, config, imported)) + retval = false; + + return retval; +} + +/** + * Frees login->config->client_hash_nodes + **/ +void clear_client_hash_nodes(void) +{ + struct client_hash_node *node = login->config->client_hash_nodes; + + while (node != NULL) { + struct client_hash_node *next = node->next; + aFree(node); + node = next; } - while(fgets(line, sizeof(line), fp)) { - if (line[0] == '/' && line[1] == '/') - continue; - if (sscanf(line, "%1023[^:]: %1023[^\r\n]", w1, w2) < 2) + login->config->client_hash_nodes = NULL; +} + +/** + * Reads information from login_configuration.permission.hash.md5_hashes. + * + * @param setting The setting to read from. + */ +void login_config_set_md5hash(struct config_setting_t *setting) +{ + int i; + int count = libconfig->setting_length(setting); + + clear_client_hash_nodes(); + + // There's no need to parse if it's disabled or if there's no list + if (count <= 0 || !login->config->client_hash_check) + return; + + for (i = 0; i < count; i++) { + int j; + int group_id = 0; + char md5hash[33]; + struct client_hash_node *nnode = NULL; + struct config_setting_t *item = libconfig->setting_get_elem(setting, i); + + if (item == NULL) continue; - if(!strcmpi(w1,"timestamp_format")) - safestrncpy(showmsg->timestamp_format, w2, 20); - else if(!strcmpi(w1,"stdout_with_ansisequence")) - showmsg->stdout_with_ansisequence = config_switch(w2) ? true : false; - else if(!strcmpi(w1,"console_silent")) { - showmsg->silent = atoi(w2); - if (showmsg->silent) /* only bother if we actually have this enabled */ - ShowInfo("Console Silent Setting: %d\n", atoi(w2)); - } - else if( !strcmpi(w1, "bind_ip") ) { - login->config->login_ip = sockt->host2ip(w2); - if (login->config->login_ip) { - char ip_str[16]; - ShowStatus("Login server binding IP address : %s -> %s\n", w2, sockt->ip2str(login->config->login_ip, ip_str)); - } + if (libconfig->setting_lookup_int(item, "group_id", &group_id) != CONFIG_TRUE) { + ShowWarning("login_config_set_md5hash: entry (%d) is missing group_id! Ignoring...\n", i); + continue; } - else if( !strcmpi(w1, "login_port") ) { - login->config->login_port = (uint16)atoi(w2); + + if (libconfig->setting_lookup_mutable_string(item, "hash", md5hash, sizeof(md5hash)) != CONFIG_TRUE) { + ShowWarning("login_config_set_md5hash: entry (%d) is missing hash! Ignoring...\n", i); + continue; } - else if(!strcmpi(w1, "log_login")) - login->config->log_login = (bool)config_switch(w2); - - else if(!strcmpi(w1, "new_account")) - login->config->new_account_flag = (bool)config_switch(w2); - else if(!strcmpi(w1, "new_acc_length_limit")) - login->config->new_acc_length_limit = (bool)config_switch(w2); - else if(!strcmpi(w1, "start_limited_time")) - login->config->start_limited_time = atoi(w2); - else if(!strcmpi(w1, "check_client_version")) - login->config->check_client_version = (bool)config_switch(w2); - else if(!strcmpi(w1, "client_version_to_connect")) - login->config->client_version_to_connect = (unsigned int)strtoul(w2, NULL, 10); - else if(!strcmpi(w1, "use_MD5_passwords")) - login->config->use_md5_passwds = (bool)config_switch(w2); - else if(!strcmpi(w1, "group_id_to_connect")) - login->config->group_id_to_connect = atoi(w2); - else if(!strcmpi(w1, "min_group_id_to_connect")) - login->config->min_group_id_to_connect = atoi(w2); - else if(!strcmpi(w1, "date_format")) - safestrncpy(login->config->date_format, w2, sizeof(login->config->date_format)); - else if(!strcmpi(w1, "allowed_regs")) //account flood protection system - login->config->allowed_regs = atoi(w2); - else if(!strcmpi(w1, "time_allowed")) - login->config->time_allowed = atoi(w2); - else if(!strcmpi(w1, "use_dnsbl")) - login->config->use_dnsbl = (bool)config_switch(w2); - else if(!strcmpi(w1, "dnsbl_servers")) - safestrncpy(login->config->dnsbl_servs, w2, sizeof(login->config->dnsbl_servs)); - else if(!strcmpi(w1, "ipban_cleanup_interval")) - login->config->ipban_cleanup_interval = (unsigned int)atoi(w2); - else if(!strcmpi(w1, "ip_sync_interval")) - login->config->ip_sync_interval = (unsigned int)1000*60*atoi(w2); //w2 comes in minutes. - else if(!strcmpi(w1, "client_hash_check")) - login->config->client_hash_check = config_switch(w2); - else if(!strcmpi(w1, "client_hash")) { - int group = 0; - char md5[33]; - memset(md5, '\0', 33); - - if (sscanf(w2, "%d, %32s", &group, md5) == 2) { - struct client_hash_node *nnode; - CREATE(nnode, struct client_hash_node, 1); - - if (strcmpi(md5, "disabled") == 0) { - nnode->hash[0] = '\0'; - } else { - int i; - for (i = 0; i < 32; i += 2) { - char buf[3]; - unsigned int byte; - - memcpy(buf, &md5[i], 2); - buf[2] = 0; - - sscanf(buf, "%x", &byte); - nnode->hash[i / 2] = (uint8)(byte & 0xFF); - } - } - - nnode->group_id = group; - nnode->next = login->config->client_hash_nodes; - - login->config->client_hash_nodes = nnode; + + CREATE(nnode, struct client_hash_node, 1); + if (strcmpi(md5hash, "disabled") == 0) { + nnode->hash[0] = '\0'; + } else { + for (j = 0; j < 32; j += 2) { + char buf[3]; + unsigned int byte; + + memcpy(buf, &md5hash[j], 2); + buf[2] = 0; + + sscanf(buf, "%x", &byte); + nnode->hash[j / 2] = (uint8)(byte & 0xFF); } } - else if(!strcmpi(w1, "import")) - login_config_read(w2); - else - { - AccountDB* db = account_engine[0].db; - if (db) - db->set_property(db, w1, w2); - ipban_config_read(w1, w2); - loginlog_config_read(w1, w2); - HPM->parseConf(w1, w2, HPCT_LOGIN); + nnode->group_id = group_id; + nnode->next = login->config->client_hash_nodes; // login->config->client_hash_nodes is initialized before calling this function + login->config->client_hash_nodes = nnode; + } + + return; +} + +/** + * Reads 'login_configuration/permission/hash' and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool login_config_read_permission_hash(const char *filename, struct config_t *config, bool imported) +{ + struct config_setting_t *setting = NULL; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "login_configuration/permission/hash")) == NULL) { + if (imported) + return true; + ShowError("login_config_read: login_configuration/permission/hash was not found in %s!\n", filename); + return false; + } + + libconfig->setting_lookup_bool_real(setting, "enabled", &login->config->client_hash_check); + + if ((setting = libconfig->lookup(config, "login_configuration/permission/hash/MD5_hashes")) != NULL) + login_config_set_md5hash(setting); + + return true; +} + +/** + * Clears login->config->dnsbl_servers, freeing any allocated memory. + */ +void clear_dnsbl_servers(void) +{ + while (VECTOR_LENGTH(login->config->dnsbl_servers) > 0) { + aFree(&VECTOR_POP(login->config->dnsbl_servers)); + } + VECTOR_CLEAR(login->config->dnsbl_servers); +} + +/** + * Reads information from login_config/permission/DNS_blacklist/dnsbl_servers. + * + * @param setting The configuration setting to read from. + */ +void login_config_set_dnsbl_servers(struct config_setting_t *setting) +{ + int i; + int count = libconfig->setting_length(setting); + + clear_dnsbl_servers(); + + // There's no need to parse if it's disabled + if (count <= 0 || !login->config->use_dnsbl) + return; + + VECTOR_ENSURE(login->config->dnsbl_servers, count, 1); + + for (i = 0; i < count; i++) { + const char *string = libconfig->setting_get_string_elem(setting, i); + + if (string == NULL || string[0] == '\0') + continue; + + VECTOR_PUSH(login->config->dnsbl_servers, aStrdup(string)); + } +} + +/** + * Reads 'login_configuration/permission/DNS_blacklist' and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool login_config_read_permission_blacklist(const char *filename, struct config_t *config, bool imported) +{ + struct config_setting_t *setting = NULL; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "login_configuration/permission/DNS_blacklist")) == NULL) { + if (imported) + return true; + ShowError("login_config_read: login_configuration/permission/DNS_blacklist was not found in %s!\n", filename); + return false; + } + + libconfig->setting_lookup_bool_real(setting, "enabled", &login->config->use_dnsbl); + + if ((setting = libconfig->lookup(config, "login_configuration/permission/DNS_blacklist/dnsbl_servers")) != NULL) + login_config_set_dnsbl_servers(setting); + + return true; +} + +/** + * Reads 'login_configuration.permission' and initializes required variables. + * + * @param filename Path to configuration file (used in error and warning messages). + * @param config The current config being parsed. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + */ +bool login_config_read_permission(const char *filename, struct config_t *config, bool imported) +{ + struct config_setting_t *setting = NULL; + bool retval = true; + + nullpo_retr(false, filename); + nullpo_retr(false, config); + + if ((setting = libconfig->lookup(config, "login_configuration/permission")) == NULL) { + if (imported) + return true; + ShowError("login_config_read: login_configuration/permission was not found in %s!\n", filename); + return false; + } + + libconfig->setting_lookup_int(setting, "group_id_to_connect", &login->config->group_id_to_connect); + libconfig->setting_lookup_int(setting, "min_group_id_to_connect", &login->config->min_group_id_to_connect); + libconfig->setting_lookup_bool_real(setting, "check_client_version", &login->config->check_client_version); + libconfig->setting_lookup_uint32(setting, "client_version_to_connect", &login->config->client_version_to_connect); + + if (!login_config_read_permission_hash(filename, config, imported)) + retval = false; + if (!login_config_read_permission_blacklist(filename, config, imported)) + retval = false; + + return retval; +} + +/** + * Reads the 'login-config' configuration file and initializes required variables. + * + * @param filename Path to configuration file. + * @param imported Whether the current config is imported from another file. + * + * @retval false in case of error. + **/ +bool login_config_read(const char *filename, bool imported) +{ + struct config_t config; + const char *import = NULL; + bool retval = true; + + nullpo_retr(false, filename); + + if (!libconfig->load_file(&config, filename)) + return false; // Error message is already shown by libconfig->load_file + + if (!login_config_read_inter(filename, &config, imported)) + retval = false; + if (!login_config_read_console(filename, &config, imported)) + retval = false; + if (!login_config_read_log(filename, &config, imported)) + retval = false; + if (!login_config_read_account(filename, &config, imported)) + retval = false; + if (!login_config_read_permission(filename, &config, imported)) + retval = false; + + if (!loginlog_config_read("conf/common/inter-server.conf", imported)) // Only inter-server + retval = false; + + if (!HPM->parse_conf(&config, filename, HPCT_LOGIN, imported)) + retval = false; + + ShowInfo("Finished reading %s.\n", filename); + + // import should overwrite any previous configuration, so it should be called last + if (libconfig->lookup_string(&config, "import", &import) == CONFIG_TRUE) { + if (strcmp(import, filename) == 0 || strcmp(import, login->LOGIN_CONF_NAME) == 0) { + ShowWarning("login_config_read: Loop detected in %s! Skipping 'import'...\n", filename); + } else { + if (!login->config_read(import, true)) + retval = false; } } - fclose(fp); - ShowInfo("Finished reading %s.\n", cfgName); - return 0; + + config_destroy(&config); + return retval; } //-------------------------------------- // Function called at exit of the server //-------------------------------------- -int do_final(void) { +int do_final(void) +{ int i; - struct client_hash_node *hn = login->config->client_hash_nodes; ShowStatus("Terminating...\n"); HPM->event(HPET_FINAL); - while (hn) { - struct client_hash_node *tmp = hn; - hn = hn->next; - aFree(tmp); - } + clear_client_hash_nodes(); + clear_dnsbl_servers(); login_log(0, "login server", 100, "login server shutdown"); @@ -1893,6 +1905,8 @@ int do_final(void) { login->fd = -1; } + lclif->final(); + HPM_login_do_final(); aFree(login->LOGIN_CONF_NAME); @@ -1945,6 +1959,19 @@ static CMDLINEARG(loginconfig) login->LOGIN_CONF_NAME = aStrdup(params); return true; } + +/** + * --run-once handler + * + * Causes the server to run its loop once, and shutdown. Useful for testing. + * @see cmdline->exec + */ +static CMDLINEARG(runonce) +{ + core->runflag = CORE_ST_STOP; + return true; +} + /** * --net-config handler * @@ -1962,6 +1989,7 @@ static CMDLINEARG(netconfig) */ void cmdline_args_init_local(void) { + CMDLINEARG_DEF2(run-once, runonce, "Closes server after loading (testing).", CMDLINE_OPT_NORMAL); CMDLINEARG_DEF2(login-config, loginconfig, "Alternative login-server configuration.", CMDLINE_OPT_PARAM); CMDLINEARG_DEF2(net-config, netconfig, "Alternative subnet configuration.", CMDLINE_OPT_PARAM); } @@ -1982,20 +2010,43 @@ int do_init(int argc, char** argv) } login_defaults(); + lclif_defaults(); // read login-server configuration login->config_set_defaults(); - login->LOGIN_CONF_NAME = aStrdup("conf/login-server.conf"); + login->LOGIN_CONF_NAME = aStrdup("conf/login/login-server.conf"); login->NET_CONF_NAME = aStrdup("conf/network.conf"); + { + // TODO: Remove this when no longer needed. +#define CHECK_OLD_LOCAL_CONF(oldname, newname) do { \ + if (stat((oldname), &fileinfo) == 0 && fileinfo.st_size > 0) { \ + ShowWarning("An old configuration file \"%s\" was found.\n", (oldname)); \ + ShowWarning("If it contains settings you wish to keep, please merge them into \"%s\".\n", (newname)); \ + ShowWarning("Otherwise, just delete it.\n"); \ + ShowInfo("Resuming in 10 seconds...\n"); \ + HSleep(10); \ + } \ +} while (0) + struct stat fileinfo; + + CHECK_OLD_LOCAL_CONF("conf/import/login_conf.txt", "conf/import/login-server.conf"); + CHECK_OLD_LOCAL_CONF("conf/import/inter_conf.txt", "conf/import/inter-server.conf"); + CHECK_OLD_LOCAL_CONF("conf/import/packet_conf.txt", "conf/import/socket.conf"); + +#undef CHECK_OLD_LOCAL_CONF + } + + lclif->init(); + HPM_login_do_init(); cmdline->exec(argc, argv, CMDLINE_OPT_PREINIT); HPM->config_read(); HPM->event(HPET_PRE_INIT); cmdline->exec(argc, argv, CMDLINE_OPT_NORMAL); - login_config_read(login->LOGIN_CONF_NAME); + login->config_read(login->LOGIN_CONF_NAME, false); sockt->net_config_read(login->NET_CONF_NAME); for( i = 0; i < ARRAYLENGTH(server); ++i ) @@ -2015,8 +2066,8 @@ int do_init(int argc, char** argv) // Interserver auth init login->auth_db = idb_alloc(DB_OPT_RELEASE_DATA); - // set default parser as login_parse_login function - sockt->set_defaultparse(login->parse_login); + // set default parser as lclif->parse function + sockt->set_defaultparse(lclif->parse); // every 10 minutes cleanup online account db. timer->add_func_list(login->online_data_cleanup, "login->online_data_cleanup"); @@ -2108,19 +2159,12 @@ void login_defaults(void) { login->fromchar_parse_accinfo = login_fromchar_parse_accinfo; login->parse_fromchar = login_parse_fromchar; - login->parse_login = login_parse_login; - login->parse_ping = login_parse_ping; - login->parse_client_md5 = login_parse_client_md5; - login->parse_client_login = login_parse_client_login; - login->parse_request_coding_key = login_parse_request_coding_key; + login->client_login = login_client_login; login->parse_request_connection = login_parse_request_connection; login->auth_ok = login_auth_ok; login->auth_failed = login_auth_failed; login->char_server_connection_status = login_char_server_connection_status; - login->connection_problem = login_connection_problem; login->kick = login_kick; - login->login_error = login_login_error; - login->send_coding_key = login_send_coding_key; login->config_set_defaults = login_config_set_defaults; login->config_read = login_config_read; |