/** * Receiving a sex change request (sex is reversed). * @param fd: fd to parse from (char-serv) * @param id: id of char-serv * @param ip: char-serv ip (used for info) * @return 0 not enough info transmitted, 1 success */ int logchrif_parse_reqchgsex(int fd, int id, char* ip){ if( RFIFOREST(fd) < 6 ) return 0; else{ struct mmo_account acc; AccountDB* accounts = login_get_accounts_db(); uint32 account_id = RFIFOL(fd,2); RFIFOSKIP(fd,6); if( !accounts->load_num(accounts, &acc, account_id) ) ShowNotice("Char-server '%s': Error of sex change (account: %d not found, ip: %s).\n", ch_server[id].name, account_id, ip); else if( acc.sex == 'S' ) ShowNotice("Char-server '%s': Error of sex change - account to change is a Server account (account: %d, ip: %s).\n", ch_server[id].name, account_id, ip); else{ unsigned char buf[7]; char sex = ( acc.sex == 'M' ) ? 'F' : 'M'; //Change gender ShowNotice("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n", ch_server[id].name, account_id, sex, ip); acc.sex = sex; // Save accounts->save(accounts, &acc); // announce to other servers WBUFW(buf,0) = 0x2723; WBUFL(buf,2) = account_id; WBUFB(buf,6) = sex_str2num(sex); logchrif_sendallwos(-1, buf, 7); } } return 1; }
/** * Timered function to synchronize ip addresses. * Requesting all char to update their registered ip and transmit their new ip. * Performed each ip_sync_interval. * @param tid: timer id * @param tick: tick of execution * @param id: unused * @param data: unused * @return 0 */ int logchrif_sync_ip_addresses(int tid, unsigned int tick, int id, intptr_t data) { uint8 buf[2]; ShowInfo("IP Sync in progress...\n"); WBUFW(buf,0) = 0x2735; logchrif_sendallwos(-1, buf, 2); return 0; }
/** * Receiving a ban request from map-server via char-server. * @param fd: fd to parse from (char-serv) * @param id: id of char-serv * @param ip: char-serv ip (used for info) * @return 0 not enough info transmitted, 1 success * TODO check logchrif_parse_requpdaccstate for possible merge */ int logchrif_parse_reqbanacc(int fd, int id, char* ip){ if (RFIFOREST(fd) < 10) return 0; else{ struct mmo_account acc; AccountDB* accounts = login_get_accounts_db(); uint32 account_id = RFIFOL(fd,2); int timediff = RFIFOL(fd,6); RFIFOSKIP(fd,10); if( !accounts->load_num(accounts, &acc, account_id) ) ShowNotice("Char-server '%s': Error of ban request (account: %d not found, ip: %s).\n", ch_server[id].name, account_id, ip); else{ time_t timestamp; if (acc.unban_time == 0 || acc.unban_time < time(NULL)) timestamp = time(NULL); // new ban else timestamp = acc.unban_time; // add to existing ban timestamp += timediff; if (timestamp == -1) ShowNotice("Char-server '%s': Error of ban request (account: %d, invalid date, ip: %s).\n", ch_server[id].name, account_id, ip); else if( timestamp <= time(NULL) || timestamp == 0 ) ShowNotice("Char-server '%s': Error of ban request (account: %d, new date unbans the account, ip: %s).\n", ch_server[id].name, account_id, ip); else{ uint8 buf[11]; char tmpstr[24]; timestamp2string(tmpstr, sizeof(tmpstr), timestamp, login_config.date_format); ShowNotice("Char-server '%s': Ban request (account: %d, new final date of banishment: %d (%s), ip: %s).\n", ch_server[id].name, account_id, timestamp, tmpstr, ip); acc.unban_time = timestamp; // Save accounts->save(accounts, &acc); WBUFW(buf,0) = 0x2731; WBUFL(buf,2) = account_id; WBUFB(buf,6) = 1; // 0: change of status, 1: ban WBUFL(buf,7) = (uint32)timestamp; // status or final date of a banishment logchrif_sendallwos(-1, buf, 11); } } } return 1; }
/** * Receiving an account state update request from a map-server (relayed via char-server). * @param fd: fd to parse from (char-serv) * @param id: id of char-serv * @param ip: char-serv ip (used for info) * @return 0 not enough info transmitted, 1 success * TODO seems pretty damn close to logchrif_parse_reqbanacc */ int logchrif_parse_requpdaccstate(int fd, int id, char* ip){ if (RFIFOREST(fd) < 10) return 0; else{ struct mmo_account acc; uint32 account_id = RFIFOL(fd,2); unsigned int state = RFIFOL(fd,6); AccountDB* accounts = login_get_accounts_db(); 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", ch_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", ch_server[id].name, account_id, state, ip); else{ ShowNotice("Char-server '%s': Status change (account: %d, new status %d, ip: %s).\n", ch_server[id].name, account_id, state, ip); acc.state = state; // Save accounts->save(accounts, &acc); // notify other servers if (state != 0){ uint8 buf[11]; WBUFW(buf,0) = 0x2731; WBUFL(buf,2) = account_id; WBUFB(buf,6) = 0; // 0: change of state, 1: ban WBUFL(buf,7) = state; // status or final date of a banishment logchrif_sendallwos(-1, buf, 11); } } } return 1; }
/** * Auth successful, inform client and create a temp auth_node. * @param sd: player session */ static void logclif_auth_ok(struct login_session_data* sd) { int fd = sd->fd; uint32 ip = session[fd]->client_addr; uint8 server_num, n; uint32 subnet_char_ip; struct auth_node* node; int i; #if PACKETVER < 20170315 int cmd = 0x69; // AC_ACCEPT_LOGIN int header = 47; int size = 32; #else int cmd = 0xac4; // AC_ACCEPT_LOGIN3 int header = 64; int size = 160; #endif if( runflag != LOGINSERVER_ST_RUNNING ){ // players can only login while running logclif_sent_auth_result(fd,1); // 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); logclif_sent_auth_result(fd,1); // 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); logclif_sent_auth_result(fd,1); // server closed return; } server_num = 0; for( i = 0; i < ARRAYLENGTH(ch_server); ++i ) if( session_isActive(ch_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); logclif_sent_auth_result(fd,1); // server closed return; } { struct online_login_data* data = (struct online_login_data*)idb_get(online_db, sd->account_id); if( data ) {// account is already marked as online! if( data->char_server > -1 ) {// Request char servers to kick this account out. [Skotlex] uint8 buf[6]; ShowNotice("User '%s' is already online - Rejected.\n", sd->userid); WBUFW(buf,0) = 0x2734; WBUFL(buf,2) = sd->account_id; logchrif_sendallwos(-1, buf, 6); if( data->waiting_disconnect == INVALID_TIMER ) data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, login_waiting_disconnect_timer, sd->account_id, 0); logclif_sent_auth_result(fd,8); // 08 = Server still recognizes your last login return; } else if( data->char_server == -1 ) {// client has authed but did not access char-server yet // wipe previous session idb_remove(auth_db, sd->account_id); login_remove_online_user(sd->account_id); data = NULL; } } } login_log(ip, sd->userid, 100, "login ok"); ShowStatus("Connection of the account '%s' accepted.\n", sd->userid); WFIFOHEAD(fd,header+size*server_num); WFIFOW(fd,0) = cmd; WFIFOW(fd,2) = header+size*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); #if PACKETVER >= 20170315 memset(WFIFOP(fd,47),0,17); // Unknown #endif for( i = 0, n = 0; i < ARRAYLENGTH(ch_server); ++i ) { if( !session_isValid(ch_server[i].fd) ) continue; subnet_char_ip = lan_subnetcheck(ip); // Advanced subnet check [LuzZza] WFIFOL(fd,header+n*size) = htonl((subnet_char_ip) ? subnet_char_ip : ch_server[i].ip); WFIFOW(fd,header+n*size+4) = ntows(htons(ch_server[i].port)); // [!] LE byte order here [!] memcpy(WFIFOP(fd,header+n*size+6), ch_server[i].name, 20); WFIFOW(fd,header+n*size+26) = ch_server[i].users; WFIFOW(fd,header+n*size+28) = ch_server[i].type; WFIFOW(fd,header+n*size+30) = ch_server[i].new_; #if PACKETVER >= 20170315 memset(WFIFOP(fd, header+n*size+32), 0, 128); // Unknown #endif n++; } WFIFOSET(fd,header+size*server_num); // create temporary auth entry CREATE(node, struct auth_node, 1); node->account_id = sd->account_id; node->login_id1 = sd->login_id1; node->login_id2 = sd->login_id2; node->sex = sd->sex; node->ip = ip; node->clienttype = sd->clienttype; idb_put(auth_db, sd->account_id, node); { struct online_login_data* data; // mark client as 'online' data = login_add_online_user(-1, sd->account_id); // schedule deletion of this node data->waiting_disconnect = add_timer(gettick()+AUTH_TIMEOUT, login_waiting_disconnect_timer, sd->account_id, 0); } }