// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL. // Copyright (c) 2014 - 2015 Evol developers #include "common/hercules.h" #include #include #include #include "common/HPMi.h" #include "common/memmgr.h" #include "common/mmo.h" #include "common/socket.h" #include "common/strlib.h" #include "common/timer.h" #include "login/account.h" #include "login/lclif.h" #include "login/login.h" #include "plugins/HPMHooking.h" #include "elogin/config.h" #include "elogin/md5calc.h" #include "elogin/parse.h" #include "elogin/send.h" int clientVersion = 0; void login_parse_version(int fd) { struct login_session_data* sd = (struct login_session_data*)sockt->session[fd]->session_data; if (!sd) return; clientVersion = RFIFOL(fd, 2); // check for minimal supported version if (clientVersion < 23) { lclif->login_error(fd, 5); return; } send_update_host(fd); send_server_version(fd); } bool elogin_client_login_pre(int *fdPtr, struct login_session_data **sdPtr __attribute__ ((unused))) { int fd = *fdPtr; uint16 command = RFIFOW(fd,0); if (command != 0x64) { lclif->login_error(fd, 3); hookStop(); return true; } char username[NAME_LENGTH]; safestrncpy(username, RFIFOP(fd, 6), NAME_LENGTH); int len = (int)safestrnlen(username, NAME_LENGTH); // check for minimal supported version if (clientVersion < 23) { lclif->login_error(fd, 5); hookStop(); return true; } else if (len >= 2 && username[len - 2] == '_' && memchr("FfMm", username[len - 1], 4)) { lclif->login_error(fd, 3); hookStop(); return true; } short *ptr = (short*)RFIFOP(fd, 2); if (*ptr == 20) *ptr = clientVersion; return false; } bool elogin_client_login_post(bool retVal, int fd, struct login_session_data* sd) { sd = (struct login_session_data*)sockt->session[fd]->session_data; if (sd) sd->version = clientVersion; return retVal; } void elogin_parse_client_login2(int fd) { char username[NAME_LENGTH]; char password[PASSWD_LEN]; char email[40]; uint8 clienttype; int result; safestrncpy(username, RFIFOP(fd, 2), NAME_LENGTH); int len = (int)safestrnlen(username, NAME_LENGTH); if (len < 2 || !(username[len - 2] == '_') || !memchr("FfMm", username[len - 1], 4)) { lclif->login_error(fd, 3); return; } safestrncpy(password, RFIFOP(fd, 26), NAME_LENGTH); safestrncpy(email, RFIFOP(fd, 51), 40); clienttype = RFIFOB(fd, 50); struct login_session_data* sd = (struct login_session_data*)sockt->session[fd]->session_data; if (!sd) return; char ip[16]; uint32 ipl = sockt->session[fd]->client_addr; sockt->ip2str(ipl, ip); sd->clienttype = clienttype; sd->version = clientVersion; sd->passwdenc = 0; safestrncpy(sd->userid, username, NAME_LENGTH); ShowStatus("Request for connection of %s (ip: %s).\n", sd->userid, ip); safestrncpy(sd->passwd, password, PASSWD_LEN); if (e_mail_check(email) == 0) { ShowNotice("Attempt to create an e-mail REFUSED - e-mail is invalid (ip: %s)\n", ip); lclif->login_error(fd, 11); return; } result = login->mmo_auth(sd, false); if (result == -1) { int account_id = sd->account_id; struct mmo_account acc; if (!login->accounts->load_num(login->accounts, &acc, account_id)) { ShowNotice("Attempt to create an e-mail on an account REFUSED - account: %d, ip: %s).\n", account_id, ip); } else { memcpy(acc.email, email, 40); ShowNotice("Create an e-mail on an account with a default e-mail (account: %d, new e-mail: %s, ip: %s).\n", account_id, email, ip); // Save login->accounts->save(login->accounts, &acc); } login->auth_ok(sd); } else { login->auth_failed(sd, result); } return; } enum parsefunc_rcode elogin_parse_ping_pre(int *fd __attribute__ ((unused)), struct login_session_data **sdPtr) { struct login_session_data *sd = *sdPtr; if (!sd) { hookStop(); return PACKET_VALID; } struct online_login_data* data = (struct online_login_data*)idb_get(login->online_db, sd->account_id); if (data == NULL) { hookStop(); return PACKET_VALID; } if (data->waiting_disconnect != INVALID_TIMER) { timer->delete(data->waiting_disconnect, login->waiting_disconnect_timer); data->waiting_disconnect = timer->add(timer->gettick() + 30000, login->waiting_disconnect_timer, sd->account_id, 0); } hookStop(); return PACKET_VALID; } void elogin_parse_change_paassword(int fd) { char actual_pass[24], new_pass[24]; int status = 0; struct mmo_account acc; const int accountId = RFIFOL (fd, 2); memcpy (actual_pass, RFIFOP (fd, 6), 24); actual_pass[23] = '\0'; memcpy (new_pass, RFIFOP (fd, 30), 24); new_pass[23] = '\0'; if (!login->accounts->load_num(login->accounts, &acc, accountId)) { // account not found send_char_password_change_ack(fd, accountId, 0); return; } if (!strcmp(actual_pass, acc.pass) || pass_ok(actual_pass, acc.pass)) { // changed ok status = 1; // Hash password safestrncpy(acc.pass, MD5_saltcrypt(new_pass, make_salt()), sizeof(acc.pass)); login->accounts->save(login->accounts, &acc); } else { // wrong password status = 2; } send_char_password_change_ack(fd, accountId, status); } void elogin_parse_serverexit(int fd) { const int code = RFIFOW(fd, 2); switch (code) { case 100: // all exit case 101: // all restart case 104: // git pull and all restart case 105: // build all case 106: // rebuild all case 107: // git pull and build all case 108: // git pull and rebuild all case 109: // build plugin case 110: // git pull and build plugin core->shutdown_callback(); break; case 102: // restart char and map server case 103: // restart map server break; default: ShowWarning("Unknown termination code: %d\n", code); } }