Beispiel #1
0
bool ProtocolOld::parseFirstPacket(NetworkMessage& msg)
{
	if(g_game.getGameState() == GAME_STATE_SHUTDOWN)
	{
		getConnection()->closeConnection();
		return false;
	}

	/*uint16_t clientOS =*/ msg.GetU16();
	uint16_t version = msg.GetU16();
	msg.SkipBytes(12);

	if(version <= 760)
		disconnectClient(0x0A, "Only clients with protocol " CLIENT_VERSION_STR " allowed!");

	if(!RSA_decrypt(msg))
	{
		getConnection()->closeConnection();
		return false;
	}

	uint32_t key[4];
	key[0] = msg.GetU32();
	key[1] = msg.GetU32();
	key[2] = msg.GetU32();
	key[3] = msg.GetU32();
	enableXTEAEncryption();
	setXTEAKey(key);

	if(version <= 822)
		disableChecksum();

	disconnectClient(0x0A, "Only clients with protocol " CLIENT_VERSION_STR " allowed!");
	return false;
}
Beispiel #2
0
void ProtocolOld::onRecvFirstMessage(NetworkMessage& msg)
{
	if(g_game.getGameState() == GAMESTATE_SHUTDOWN)
	{
		getConnection()->close();
		return;
	}

	msg.skip(2);
	uint16_t version = msg.get<uint16_t>();

	msg.skip(12);
	if(version <= 760)
		disconnectClient(0x0A, "Only clients with protocol " CLIENT_VERSION_STRING " allowed!");

	if(!RSA_decrypt(msg))
	{
		getConnection()->close();
		return;
	}

	uint32_t key[4] = {msg.get<uint32_t>(), msg.get<uint32_t>(), msg.get<uint32_t>(), msg.get<uint32_t>()};
	enableXTEAEncryption();
	setXTEAKey(key);

	if(version <= 822)
		disableChecksum();

	disconnectClient(0x0A, "Only clients with protocol " CLIENT_VERSION_STRING " allowed!");
}
Beispiel #3
0
bool ProtocolOld::parseFirstPacket(NetworkMessage& msg)
{
	if(g_game.getGameState() == GAMESTATE_SHUTDOWN)
	{
		getConnection()->close();
		return false;
	}

	/*uint16_t operatingSystem = */msg.get<uint16_t>();
	uint16_t version = msg.get<uint16_t>();
	msg.skip(12);
	if(version <= 760)
		disconnectClient(0x0A, CLIENT_VERSION_STRING);

	if(!RSA_decrypt(msg))
	{
		getConnection()->close();
		return false;
	}

	uint32_t key[4] = {msg.get<uint32_t>(), msg.get<uint32_t>(), msg.get<uint32_t>(), msg.get<uint32_t>()};
	enableXTEAEncryption();
	setXTEAKey(key);

	if(version <= 822)
		disableChecksum();

	disconnectClient(0x0A, CLIENT_VERSION_STRING);
	return false;
}
Beispiel #4
0
/*
 * Ensure the client has the private key by first decrypting the packet and
 * then checking the packet digests.
 */
static int process_cert_verify(SSL *ssl)
{
    uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];
    int pkt_size = ssl->bm_index;
    uint8_t dgst_buf[MAX_KEY_BYTE_SIZE];
    uint8_t dgst[MD5_SIZE+SHA1_SIZE];
    X509_CTX *x509_ctx = ssl->x509_ctx;
    int ret = SSL_OK;
    int n;

    PARANOIA_CHECK(pkt_size, x509_ctx->rsa_ctx->num_octets+6);
    DISPLAY_RSA(ssl, x509_ctx->rsa_ctx);

    /* rsa_ctx->bi_ctx is not thread-safe */
    SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
    n = RSA_decrypt(x509_ctx->rsa_ctx, &buf[6], dgst_buf, 0);
    SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);

    if (n != SHA1_SIZE + MD5_SIZE)
    {
        ret = SSL_ERROR_INVALID_KEY;
        goto end_cert_vfy;
    }

    finished_digest(ssl, NULL, dgst);       /* calculate the digest */
    if (memcmp(dgst_buf, dgst, MD5_SIZE + SHA1_SIZE))
    {
        ret = SSL_ERROR_INVALID_KEY;
    }

end_cert_vfy:
    ssl->next_state = HS_FINISHED;
error:
    return ret;
}
Beispiel #5
0
/**************************************************************************
 * RSA tests 
 *
 * Use the results from openssl to verify PKCS1 etc 
 **************************************************************************/
static int RSA_test(void)
{
    int res = 1;
    const char *plaintext = /* 128 byte hex number */
        "1234567890abbbbbbbbbbbbbbbccccccccccccccdddddddddddddeeeeeeeeee2"
        "1aaaaaaaaaabbbbbbbbbbbbbbbccccccccccccccdddddddddddddeeeeeeeee2\012";
    uint8_t enc_data[128], dec_data[128];
    RSA_CTX *rsa_ctx = NULL;
    BI_CTX *bi_ctx;
    bigint *plaintext_bi;
    bigint *enc_data_bi, *dec_data_bi;
    uint8_t enc_data2[128], dec_data2[128];
    int len; 
    uint8_t *buf;
	
    /* extract the private key elements */
    len = get_file("./axTLS.key_1024", &buf);
    if (asn1_get_private_key(buf, len, &rsa_ctx) < 0)
    {
        goto end;
    }

    free(buf);
    
	dump_frame("original data",(char *)plaintext, strlen(plaintext));
	
    bi_ctx = rsa_ctx->bi_ctx;
    plaintext_bi = bi_import(bi_ctx, 
            (const uint8_t *)plaintext, strlen(plaintext));
    /* basic rsa encrypt */
    enc_data_bi = RSA_public(rsa_ctx, plaintext_bi);
    bi_export(bi_ctx, bi_copy(enc_data_bi), enc_data, sizeof(enc_data));
	dump_frame("encrypt data",(char *)enc_data, sizeof(enc_data));
    /* basic rsa decrypt */
    dec_data_bi = RSA_private(rsa_ctx, enc_data_bi);
    bi_export(bi_ctx, dec_data_bi, dec_data, sizeof(dec_data));
	dump_frame("decrypt data",(char *)dec_data, sizeof(dec_data));
    if (memcmp(dec_data, plaintext, strlen(plaintext)))
    {
        printf("Error: DECRYPT #1 failed\n");
        goto end;
    }

    RSA_encrypt(rsa_ctx, (const uint8_t *)"abc", 3, enc_data2, 0);
    RSA_decrypt(rsa_ctx, enc_data2, dec_data2, 1);
    if (memcmp("abc", dec_data2, 3))
    {
        printf("Error: ENCRYPT/DECRYPT #2 failed\n");
        goto end;
    }

    RSA_free(rsa_ctx);
    res = 0;
    printf("All RSA tests passed\n");

end:
    return res;
}
Beispiel #6
0
/*
 * Pull apart a client key exchange message. Decrypt the pre-master key (using
 * our RSA private key) and then work out the master key. Initialise the
 * ciphers.
 */
static int ICACHE_FLASH_ATTR process_client_key_xchg(SSL *ssl)
{
    uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];
    int pkt_size = ssl->bm_index;
    int premaster_size, secret_length = (buf[2] << 8) + buf[3];
    uint8_t premaster_secret[MAX_KEY_BYTE_SIZE];
    RSA_CTX *rsa_ctx = ssl->ssl_ctx->rsa_ctx;
    int offset = 4;
    int ret = SSL_OK;
    
    if (rsa_ctx == NULL)
    {
        ret = SSL_ERROR_NO_CERT_DEFINED;
        goto error;
    }

    /* is there an extra size field? */
    if ((secret_length - 2) == rsa_ctx->num_octets)
        offset += 2;

    PARANOIA_CHECK(pkt_size, rsa_ctx->num_octets+offset);

    /* rsa_ctx->bi_ctx is not thread-safe */
    SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
    premaster_size = RSA_decrypt(rsa_ctx, &buf[offset], premaster_secret,
            sizeof(premaster_secret), 1);
    SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);

    if (premaster_size != SSL_SECRET_SIZE || 
            premaster_secret[0] != 0x03 ||  /* must be the same as client
                                               offered version */
                premaster_secret[1] != (ssl->client_version & 0x0f))
    {
        /* guard against a Bleichenbacher attack */
        if (get_random(SSL_SECRET_SIZE, premaster_secret) < 0)
            return SSL_NOT_OK;

        /* and continue - will die eventually when checking the mac */
    }

#if 0
    print_blob("pre-master", premaster_secret, SSL_SECRET_SIZE);
#endif

    generate_master_secret(ssl, premaster_secret);

#ifdef CONFIG_SSL_CERT_VERIFICATION
    ssl->next_state = IS_SET_SSL_FLAG(SSL_CLIENT_AUTHENTICATION) ?  
                                            HS_CERT_VERIFY : HS_FINISHED;
#else
    ssl->next_state = HS_FINISHED; 
#endif

    ssl->dc->bm_proc_index += rsa_ctx->num_octets+offset;
error:
    return ret;
}
Beispiel #7
0
/**
 * Processes encryption key information received in a REGISTER message
 */
int handle_register_keys(const struct register_h *reg,
                         const unsigned char *enckey,
                         struct pr_group_list_t *group, int hostidx,
                         uint32_t src)
{
    unsigned char premaster[PUBKEY_LEN];
    unsigned int len;
    struct pr_destinfo_t *dest;

    dest = &group->destinfo[hostidx];
    memcpy(dest->rand2, reg->rand2, sizeof(dest->rand2));
    if (group->keyextype == KEYEX_RSA) {
        if (!RSA_decrypt(group->proxy_privkey.rsa, enckey,
                         ntohs(reg->keyinfo_len), premaster, &len)) {
            glog1(group, "Rejecting REGISTER from %s: "
                         "failed to decrypt premaster secret", dest->name);
            return 0;
        }
        if (len != MASTER_LEN) {
            glog1(group, "Rejecting REGISTER from %s: "
                         "premaster secret wrong length", dest->name);
            return 0;
        }
    } else {
        if (!import_EC_key(&dest->dhkey.ec, enckey,
                           ntohs(reg->keyinfo_len), 1)) {
            glog1(group, "Rejecting REGISTER from %s: "
                         "failed to import ECDH key", dest->name);
            return 0;
        }
        if (get_EC_curve(dest->dhkey.ec) !=
                get_EC_curve(group->proxy_dhkey.ec)) {
            glog1(group, "Rejecting REGISTER from %s: "
                         "invalid curve for ECDH", dest->name);
            return 0;
        }
        if (!get_ECDH_key(dest->dhkey.ec, group->proxy_dhkey.ec,
                          premaster, &len)) {
            glog1(group, "Rejecting REGISTER from %s: "
                         "failed to calculate premaster secret", dest->name);
            return 0;
        }

    }
    memcpy(dest->premaster, premaster, len);
    dest->premaster_len = len;
    calculate_client_keys(group, hostidx);

    if (dest->pubkey.key) {
        if (!verify_client_key(group, hostidx)) {
            return 0;
        }
    }

    return 1;
}
Beispiel #8
0
int RSA_private_decrypt(int flen, const uint8_t *from, uint8_t *to, RSA *rsa,
                        int padding) {
  size_t out_len;

  if (!RSA_decrypt(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) {
    return -1;
  }

  return out_len;
}
Beispiel #9
0
static int pkey_rsa_decrypt(EVP_PKEY_CTX *ctx, uint8_t *out,
                            size_t *outlen, const uint8_t *in,
                            size_t inlen) {
  RSA_PKEY_CTX *rctx = ctx->data;
  RSA *rsa = ctx->pkey->pkey.rsa;
  const size_t key_len = EVP_PKEY_size(ctx->pkey);

  if (!out) {
    *outlen = key_len;
    return 1;
  }

  if (*outlen < key_len) {
    OPENSSL_PUT_ERROR(EVP, pkey_rsa_decrypt, EVP_R_BUFFER_TOO_SMALL);
    return 0;
  }

  if (rctx->pad_mode == RSA_PKCS1_OAEP_PADDING) {
    size_t plaintext_len;
    int message_len;

    if (!setup_tbuf(rctx, ctx) ||
        !RSA_decrypt(rsa, &plaintext_len, rctx->tbuf, key_len, in, inlen,
                     RSA_NO_PADDING)) {
      return 0;
    }

    message_len = RSA_padding_check_PKCS1_OAEP_mgf1(
        out, key_len, rctx->tbuf, plaintext_len, rctx->oaep_label,
        rctx->oaep_labellen, rctx->md, rctx->mgf1md);
    if (message_len < 0) {
      return 0;
    }
    *outlen = message_len;
    return 1;
  }

  return RSA_decrypt(rsa, outlen, out, key_len, in, inlen, rctx->pad_mode);
}
Beispiel #10
0
int RSA_private_decrypt(size_t flen, const uint8_t *from, uint8_t *to, RSA *rsa,
                        int padding) {
  size_t out_len;

  if (!RSA_decrypt(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) {
    return -1;
  }

  if (out_len > INT_MAX) {
    OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW);
    return -1;
  }
  return out_len;
}
Beispiel #11
0
enum ssl_private_key_result_t ssl_private_key_decrypt(
    SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
    const uint8_t *in, size_t in_len) {
  if (ssl->cert->key_method != NULL) {
    return ssl->cert->key_method->decrypt(ssl, out, out_len, max_out, in,
                                          in_len);
  }

  RSA *rsa = EVP_PKEY_get0_RSA(ssl->cert->privatekey);
  if (rsa == NULL) {
    /* Decrypt operations are only supported for RSA keys. */
    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
    return ssl_private_key_failure;
  }

  /* Decrypt with no padding. PKCS#1 padding will be removed as part
   * of the timing-sensitive code by the caller. */
  if (!RSA_decrypt(rsa, out_len, out, max_out, in, in_len, RSA_NO_PADDING)) {
    return ssl_private_key_failure;
  }
  return ssl_private_key_success;
}
bool ProtocolLogin::parseFirstPacket(NetworkMessage& msg)
{
	if(
#ifndef _CONSOLE
		!GUI::getInstance()->m_connections ||
#endif
		g_game.getGameState() == GAME_STATE_SHUTDOWN)
	{
		getConnection()->closeConnection();
		return false;
	}

	uint32_t clientip = getConnection()->getIP();

	/*uint16_t clientos = */msg.GetU16();
	uint16_t version = msg.GetU16();
	msg.SkipBytes(12);

	if(version <= 760)
	{
		disconnectClient(0x0A, "Only clients with protocol " CLIENT_VERSION_STR " allowed!");
		return false;
	}

	if(!RSA_decrypt(msg))
	{
		getConnection()->closeConnection();
		return false;
	}

	uint32_t key[4];
	key[0] = msg.GetU32();
	key[1] = msg.GetU32();
	key[2] = msg.GetU32();
	key[3] = msg.GetU32();
	enableXTEAEncryption();
	setXTEAKey(key);

	std::string accountName = msg.GetString();
	std::string password = msg.GetString();

	if(accountName.empty())
	{
		if(g_config.getBoolean(ConfigManager::ACCOUNT_MANAGER))
		{
			accountName = "1";
			password = "******";
		}
		else
		{
			disconnectClient(0x0A, "Invalid Account Name.");
			return false;
		}
	}

	if(version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX)
	{
		disconnectClient(0x0A, "Only clients with protocol " CLIENT_VERSION_STR " allowed!");
		return false;
	}

	if(g_game.getGameState() == GAME_STATE_STARTUP)
	{
		disconnectClient(0x0A, "Gameworld is starting up. Please wait.");
		return false;
	}

	if(g_game.getGameState() == GAME_STATE_MAINTAIN)
	{
		disconnectClient(0x0A, "Gameworld is under maintenance. Please re-connect in a while.");
		return false;
	}

	if(g_bans.isIpDisabled(clientip))
	{
		disconnectClient(0x0A, "Too many connections attempts from this IP. Try again later.");
		return false;
	}

	if(IOBan::getInstance()->isIpBanished(clientip))
	{
		disconnectClient(0x0A, "Your IP is banished!");
		return false;
	}

	uint32_t serverip = serverIPs[0].first;
	for(uint32_t i = 0; i < serverIPs.size(); i++)
	{
		if((serverIPs[i].first & serverIPs[i].second) == (clientip & serverIPs[i].second))
		{
			serverip = serverIPs[i].first;
			break;
		}
	}

	Account account = IOLoginData::getInstance()->loadAccount(accountName);
	if(account.id == 0 || !passwordTest(password, account.password))
	{
		g_bans.addLoginAttempt(clientip, false);
		disconnectClient(0x0A, "Account name or password is not correct.");
		return false;
	}

	g_bans.addLoginAttempt(clientip, true);

	OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false);
	if(output)
	{
		TRACK_MESSAGE(output);

		//Update premium days
		g_game.updatePremium(account);

		//Add MOTD
		output->AddByte(0x14);

		std::ostringstream ss;
		ss << g_game.getMotdNum() << "\n" << g_config.getString(ConfigManager::MOTD);
		output->AddString(ss.str());

		//Add char list
		output->AddByte(0x64);
		if(g_config.getBoolean(ConfigManager::ACCOUNT_MANAGER) && account.id != 1)
		{
			output->AddByte((uint8_t)account.charList.size() + 1);
			output->AddString("Account Manager");
			output->AddString(g_config.getString(ConfigManager::SERVER_NAME));
			output->AddU32(serverip);
			output->AddU16(g_config.getNumber(ConfigManager::GAME_PORT));
		}
		else
			output->AddByte((uint8_t)account.charList.size());

		std::list<std::string>::iterator it, end;
		for(it = account.charList.begin(), end = account.charList.end(); it != end; ++it)
		{
			output->AddString(*it);
			if(g_config.getBoolean(ConfigManager::ON_OR_OFF_CHARLIST))
			{
				if(g_game.getPlayerByName((*it)))
					output->AddString("Online");
				else
					output->AddString("Offline");
			}
			else
				output->AddString(g_config.getString(ConfigManager::SERVER_NAME));

			output->AddU32(serverip);
			output->AddU16(g_config.getNumber(ConfigManager::GAME_PORT));
		}

		//Add premium days
		if(g_config.getBoolean(ConfigManager::FREE_PREMIUM))
			output->AddU16(0xFFFF); //client displays free premium
		else
			output->AddU16(account.premiumDays);

		OutputMessagePool::getInstance()->send(output);
	}
	getConnection()->closeConnection();
	return true;
}
bool ProtocolLogin::parseFirstPacket(NetworkMessage& msg)
{
	if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
		getConnection()->closeConnection();
		return false;
	}

	uint32_t clientip = getConnection()->getIP();

	/*uint16_t clientos = */
	msg.get<uint16_t>();
	uint16_t version = msg.get<uint16_t>();

	if (version >= 971) {
		msg.SkipBytes(17);
	}
	else {
		msg.SkipBytes(12);
	}

	/*
	* Skipped bytes:
	* 4 bytes: protocolVersion (only 971+)
	* 12 bytes: dat, spr, pic signatures (4 bytes each)
	* 1 byte: 0 (only 971+)
	*/

	if (version <= 760) {
		disconnectClient(0x0A, "Only clients with protocol " CLIENT_VERSION_STR " allowed!");
		return false;
	}
	
	if (!RSA_decrypt(msg)) {
		getConnection()->closeConnection();
		return false;
	}

	uint32_t key[4];
	key[0] = msg.get<uint32_t>();
	key[1] = msg.get<uint32_t>();
	key[2] = msg.get<uint32_t>();
	key[3] = msg.get<uint32_t>();
	enableXTEAEncryption();
	setXTEAKey(key);

	std::string accountName = msg.GetString();
	std::string password = msg.GetString();

	if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) {
		if (version >= 1076)
			disconnectClient(0x0B, "Only clients with protocol " CLIENT_VERSION_STR " allowed!");
		else
			disconnectClient(0x0A, "Only clients with protocol " CLIENT_VERSION_STR " allowed!");
		return false;
	}

	if (g_game.getGameState() == GAME_STATE_STARTUP) {
		disconnectClient(0x0B, "Gameworld is starting up. Please wait.");
		return false;
	}

	if (g_game.getGameState() == GAME_STATE_MAINTAIN) {
		disconnectClient(0x0B, "Gameworld is under maintenance. Please re-connect in a while.");
		return false;
	}

	BanInfo banInfo;
	if (IOBan::isIpBanned(clientip, banInfo)) {
		if (banInfo.reason.empty()) {
			banInfo.reason = "(none)";
		}

		std::ostringstream ss;
		ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason;
		disconnectClient(0x0B, ss.str().c_str());
		return false;
	}
	//IF THE PASSWORD FIELDS AND ACCOUNT FIELD ARE EMPTY THEN THE USER WAN'T TO USE CAST SYSTEM
	bool cast_login = false;
	if ((accountName.empty() && password.empty()) || (accountName.empty() && !password.empty()))
	{
		cast_login = true;
	}
	if (!cast_login && accountName.empty()) {
		disconnectClient(0x0B, "Invalid account name.");
		return false;
	}

	Account account;
	if (!cast_login && !IOLoginData::loginserverAuthentication(accountName, password, account)) {
		disconnectClient(0x0B, "Account name or password is not correct.");
		return false;
	}

	OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false);
	if (output) {
		//Update premium days
		g_game.updatePremium(account);

		//Add MOTD
		output->AddByte(0x14);

		std::ostringstream ss;
		ss << g_game.getMotdNum() << "\n" << g_config.getString(ConfigManager::MOTD);
		output->AddString(ss.str());

		//SessionKey
		if (!cast_login) {
			output->AddByte(0x28);

			output->AddString(accountName + "\n" + password);
		}

		//Add char list
		output->AddByte(0x64);

	
		if (cast_login)
		{
			int cz = 0;
			std::vector<std::string>	names;
			std::vector<uint32_t>		counts;
			cast_login = false;
			uint8_t size = 0;
			g_game.lockPlayers();
			for (const auto& it : g_game.getPlayers())
			{
				if (it.second->cast.isCasting && (it.second->cast.password == "" || it.second->cast.password == password))
				{
					names.push_back(it.second->getName());
					counts.push_back(it.second->getCastViewerCount());
					it.second->getCastViewerCount();
					cast_login = true;
					size++;
				}
			}
			g_game.unlockPlayers();
			if (cast_login)
			{
				output->AddByte(size); // number of worlds
				for (auto it = counts.begin(); it != counts.end(); it++)
				{
					output->AddByte(cz); // world id
					std::ostringstream os;
					os << (*it);
					output->AddString(os.str() + std::string(" viewers"));
					output->AddString(g_config.getString(ConfigManager::IP));
					output->add<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT));
					output->AddByte(0);

					cz++;
				}


				output->AddByte((uint8_t)cz);
				int world = 0;
				for (auto it : names)
				{
					output->AddByte(world);
					output->AddString(it);
					world++;
				}
				
			}
		}
		if (!cast_login)
		{
			output->AddByte(1); // number of worlds

			output->AddByte(0); // world id
			output->AddString(g_config.getString(ConfigManager::SERVER_NAME));
			output->AddString(g_config.getString(ConfigManager::IP));
			output->add<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT));
			output->AddByte(0);

			output->AddByte((uint8_t)account.charList.size());

			for (const std::string& characterName : account.charList) {
				output->AddByte(0);
				output->AddString(characterName);
			}
		}

		//Add premium days
		if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
			output->add<uint16_t>(0xFFFF);    //client displays free premium
		}
		else {
			output->add<uint16_t>(account.premiumDays);
		}

		OutputMessagePool::getInstance()->send(output);
	}

	getConnection()->closeConnection();
	return true;
}
Beispiel #14
0
void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
{
	if(
#if defined(WINDOWS) && !defined(_CONSOLE)
		!GUI::getInstance()->m_connections ||
#endif
		g_game.getGameState() == GAMESTATE_SHUTDOWN)
	{
		getConnection()->close();
		return;
	}

	uint32_t clientIp = getConnection()->getIP();
	msg.get<uint16_t>();
	uint16_t version = msg.get<uint16_t>();

	msg.skip(12);
	#ifdef _MULTIPLATFORM77
	if(!RSA_decrypt(msg))
	{
		getConnection()->close();
		return;
	}

	uint32_t key[4] = {msg.get<uint32_t>(), msg.get<uint32_t>(), msg.get<uint32_t>(), msg.get<uint32_t>()};
	enableXTEAEncryption();
	setXTEAKey(key);
	#endif
	uint32_t name = msg.get<uint32_t>();
	std::string password = msg.getString();

	if(!name)
	{
		if(!g_config.getBool(ConfigManager::ACCOUNT_MANAGER))
		{
			disconnectClient(0x0A, "Invalid account name.");
			return;
		}

		name = 1;
		password = "******";
	}

	if(!g_config.getBool(ConfigManager::MANUAL_ADVANCED_CONFIG))
	{
		if(version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX)
		{
			disconnectClient(0x0A, CLIENT_VERSION_STRING);
			return;
		}
	else
		if(version < g_config.getNumber(ConfigManager::VERSION_MIN) || version > g_config.getNumber(ConfigManager::VERSION_MAX))
		{
			disconnectClient(0x0A, g_config.getString(ConfigManager::VERSION_MSG).c_str());
			return;
		}
	}
#ifdef CLIENT_VERSION_DATA

	if(sprSignature != CLIENT_VERSION_SPR)
	{
		disconnectClient(0x0A, CLIENT_VERSION_DATA);
		return;
	}

	if(datSignature != CLIENT_VERSION_DAT)
	{
		disconnectClient(0x0A, CLIENT_VERSION_DATA);
		return;
	}

	if(picSignature != CLIENT_VERSION_PIC)
	{
		disconnectClient(0x0A, CLIENT_VERSION_DATA);
		return;
	}
#endif

	if(g_game.getGameState() < GAMESTATE_NORMAL)
	{
		disconnectClient(0x0A, "Server is just starting up, please wait.");
		return;
	}

	if(g_game.getGameState() == GAMESTATE_MAINTAIN)
	{
		disconnectClient(0x0A, "Server is under maintenance, please re-connect in a while.");
		return;
	}

	if(ConnectionManager::getInstance()->isDisabled(clientIp, protocolId))
	{
		disconnectClient(0x0A, "Too many connections attempts from your IP address, please try again later.");
		return;
	}

	if(IOBan::getInstance()->isIpBanished(clientIp))
	{
		disconnectClient(0x0A, "Your IP is banished!");
		return;
	}

	uint32_t id = 1;
	if(!IOLoginData::getInstance()->getAccountId(name, id))
	{
		ConnectionManager::getInstance()->addAttempt(clientIp, protocolId, false);
		disconnectClient(0x0A, "Invalid account id.");
		return;
	}

	Account account = IOLoginData::getInstance()->loadAccount(id);
	if(!encryptTest(account.salt + password, account.password))
	{
		ConnectionManager::getInstance()->addAttempt(clientIp, protocolId, false);
		disconnectClient(0x0A, "Invalid password.");
		return;
	}

	Ban ban;
	ban.value = account.number;

	ban.type = BAN_ACCOUNT;
	if(IOBan::getInstance()->getData(ban) && !IOLoginData::getInstance()->hasFlag(account.number, PlayerFlag_CannotBeBanned))
	{
		bool deletion = ban.expires < 0;
		std::string name_ = "Automatic ";
		if(!ban.adminId)
			name_ += (deletion ? "deletion" : "banishment");
		else
			IOLoginData::getInstance()->getNameByGuid(ban.adminId, name_, true);

		std::stringstream ss;
		ss << "Your account has been " << (deletion ? "deleted" : "banished") << " at:\n" << formatDateEx(ban.added, "%d %b %Y").c_str()
			<< " by: " << name_.c_str() << "\nReason:\n" << getReason(ban.reason).c_str() << ".\nComment:\n" << ban.comment.c_str() << ".\nYour " << (deletion ?
			"account won't be undeleted" : "banishment will be lifted at:\n") << (deletion ? "" : formatDateEx(ban.expires).c_str());

		disconnectClient(0x0A, ss.str().c_str());
		return;
	}

	// remove premium days
	#ifndef __LOGIN_SERVER__
	IOLoginData::getInstance()->removePremium(account);
	if(!g_config.getBool(ConfigManager::ACCOUNT_MANAGER) && !account.charList.size())
	{
		disconnectClient(0x0A, std::string("This account does not contain any character yet.\nCreate a new character on the "
			+ g_config.getString(ConfigManager::SERVER_NAME) + " website at " + g_config.getString(ConfigManager::URL) + ".").c_str());
		return;
	}
	#else
	Characters charList;
	for(Characters::iterator it = account.charList.begin(); it != account.charList.end(); ++it)
	{
		if(version >= it->second.server->getVersionMin() && version <= it->second.server->getVersionMax())
			charList[it->first] = it->second;
	}

	IOLoginData::getInstance()->removePremium(account);
	if(!g_config.getBool(ConfigManager::ACCOUNT_MANAGER) && !charList.size())
	{
		disconnectClient(0x0A, std::string("This account does not contain any character on this client yet.\nCreate a new character on the "
			+ g_config.getString(ConfigManager::SERVER_NAME) + " website at " + g_config.getString(ConfigManager::URL) + ".").c_str());
		return;
	}
	#endif

	ConnectionManager::getInstance()->addAttempt(clientIp, protocolId, true);
	if(OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false))
	{
		TRACK_MESSAGE(output);
		output->put<char>(0x14);
		uint32_t serverIp = serverIps.front().first;
		for(std::list<std::pair<uint32_t, uint32_t> >::iterator it = serverIps.begin(); it != serverIps.end(); ++it)
		{
			if((it->first & it->second) != (clientIp & it->second))
				continue;

			serverIp = it->first;
			break;
		}

		char motd[1300];
		sprintf(motd, "%d\n%s", g_game.getMotdId(), g_config.getString(ConfigManager::MOTD).c_str());
		output->putString(motd);

		//Add char list
		output->put<char>(0x64);
		if(g_config.getBool(ConfigManager::ACCOUNT_MANAGER) && account.number != 1)
		{
			output->put<char>(account.charList.size() + 1);
			output->putString("Account Manager");

			output->putString(g_config.getString(ConfigManager::SERVER_NAME));
			output->put<uint32_t>(serverIp);

			output->put<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT));
		}
		else
			output->put<char>((uint8_t)account.charList.size());

		#ifndef __LOGIN_SERVER__
		for(Characters::iterator it = account.charList.begin(); it != account.charList.end(); ++it)
		{
			output->putString((*it));
			if(g_config.getBool(ConfigManager::ON_OR_OFF_CHARLIST)
				&& !g_config.getBool(ConfigManager::CHARLIST_INFO))
			{
				if(g_game.getPlayerByName((*it)))
					output->putString("Online");
				else
					output->putString("Offline");
			}
			else if(g_config.getBool(ConfigManager::CHARLIST_INFO))
			{
				std::stringstream str;
				Player *player = g_game.getPlayerByName((*it));
				bool v = false;
				if(g_config.getBool(ConfigManager::ON_OR_OFF_CHARLIST))
				{
					if(player)
						str << "On";
					else
						str << "Off";

					str << "/";
				}

				if(!player)
				{
					v = true;
					player = g_game.getPlayerByNameEx((*it));
				}

				str << player->getLevel();
				str << "/";
				str << player->getVocation()->getName();
				output->putString(str.str());
				if(v)
					delete player;
			}
			else
				output->putString(g_config.getString(ConfigManager::SERVER_NAME));

			output->put<uint32_t>(serverIp);
			output->put<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT));
		}
		#else
		for(Characters::iterator it = charList.begin(); it != charList.end(); ++it)
		{
			output->putString(it->second.name);
			if(!g_config.getBool(ConfigManager::ON_OR_OFF_CHARLIST) || it->second.status < 0)
				output->putString(it->second.server->getName());
			else if(it->second.status)
				output->putString("Online");
			else
				output->putString("Offline");

			output->put<uint32_t>(it->second.server->getAddress());
			IntegerVec games = it->second.server->getPorts();
			output->put<uint16_t>(games[random_range(0, games.size() - 1)]);
		}
		#endif

		//Add premium days
		if(g_config.getBool(ConfigManager::FREE_PREMIUM))
			output->put<uint16_t>(GRATIS_PREMIUM);
		else
			output->put<uint16_t>(account.premiumDays);

		OutputMessagePool::getInstance()->send(output);
	}

	getConnection()->close();
}
bool ProtocolLogin::parseFirstPacket(NetworkMessage& msg)
{
	if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
		getConnection()->closeConnection();
		return false;
	}

	uint32_t clientip = getConnection()->getIP();

	/*uint16_t clientos = */
	msg.GetU16();
	uint16_t version = msg.GetU16();
	msg.SkipBytes(12);

	/*
	 * Skipped bytes:
	 * 12 bytes: dat, spr, pic signatures (4 bytes each)
	*/

	#ifdef __PROTOCOL_77__
	if (!RSA_decrypt(msg)) {
		getConnection()->closeConnection();
		return false;
	}

	uint32_t key[4];
	key[0] = msg.GetU32();
	key[1] = msg.GetU32();
	key[2] = msg.GetU32();
	key[3] = msg.GetU32();
	enableXTEAEncryption();
	setXTEAKey(key);
	#endif

	uint32_t accountName = msg.GetU32();
	std::string password = msg.GetString();

	if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) {
		disconnectClient(0x0A, "Only clients with protocol " CLIENT_VERSION_STR " allowed!");
		return false;
	}

	if (g_game.getGameState() == GAME_STATE_STARTUP) {
		disconnectClient(0x0A, "Gameworld is starting up. Please wait.");
		return false;
	}

	if (g_game.getGameState() == GAME_STATE_MAINTAIN) {
		disconnectClient(0x0A, "Gameworld is under maintenance. Please re-connect in a while.");
		return false;
	}

	BanInfo banInfo;
	if (IOBan::getInstance()->isIpBanned(clientip, banInfo)) {
		if (banInfo.reason.empty()) {
			banInfo.reason = "(none)";
		}

		std::ostringstream ss;
		ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason;
		disconnectClient(0x0A, ss.str().c_str());
		return false;
	}

	uint32_t serverip = serverIPs[0].first;
	for (uint32_t i = 0; i < serverIPs.size(); i++) {
		if ((serverIPs[i].first & serverIPs[i].second) == (clientip & serverIPs[i].second)) {
			serverip = serverIPs[i].first;
			break;
		}
	}

	if (!accountName) {
		disconnectClient(0x0A, "Invalid account id.");
		return false;
	}

	Account account;
	if (!IOLoginData::getInstance()->loginserverAuthentication(accountName, password, account)) {
		disconnectClient(0x0A, "Account id or password is not correct.");
		return false;
	}

	OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false);
	if (output) {
		//Update premium days
		g_game.updatePremium(account);

		//Add MOTD
		output->AddByte(0x14);

		std::ostringstream ss;
		ss << g_game.getMotdNum() << "\n" << g_config.getString(ConfigManager::MOTD);
		output->AddString(ss.str());

		//Add char list
		output->AddByte(0x64);
		output->AddByte((uint8_t)account.charList.size());

		for (const std::string& characterName : account.charList) {
			output->AddString(characterName);

			if (g_config.getBoolean(ConfigManager::ON_OR_OFF_CHARLIST)) {
				if (g_game.getPlayerByName(characterName)) {
					output->AddString("Online");
				} else {
					output->AddString("Offline");
				}
			} else {
				output->AddString(g_config.getString(ConfigManager::SERVER_NAME));
			}

			output->AddU32(serverip);
			output->AddU16(g_config.getNumber(ConfigManager::GAME_PORT));
		}

		//Add premium days
		if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
			output->AddU16(0xFFFF);    //client displays free premium
		} else {
			output->AddU16(account.premiumDays);
		}

		OutputMessagePool::getInstance()->send(output);
	}

	getConnection()->closeConnection();
	return true;
}
void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
{
	if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
		getConnection()->closeConnection();
		return;
	}

	uint32_t clientip = getConnection()->getIP();

	/*uint16_t clientos = */
	msg.get<uint16_t>();
	uint16_t version = msg.get<uint16_t>();

	if (version >= 971) {
		msg.SkipBytes(17);
	} else {
		msg.SkipBytes(12);
	}

	/*
	 * Skipped bytes:
	 * 4 bytes: protocolVersion (only 971+)
	 * 12 bytes: dat, spr, pic signatures (4 bytes each)
	 * 1 byte: 0 (only 971+)
	 */

#define dispatchDisconnectClient(err) g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::disconnectClient, this, err)))

	if (version <= 760) {
		dispatchDisconnectClient("Only clients with protocol " CLIENT_VERSION_STR " allowed!");
		return;
	}

	if (!RSA_decrypt(msg)) {
		getConnection()->closeConnection();
		return;
	}

	uint32_t key[4];
	key[0] = msg.get<uint32_t>();
	key[1] = msg.get<uint32_t>();
	key[2] = msg.get<uint32_t>();
	key[3] = msg.get<uint32_t>();
	enableXTEAEncryption();
	setXTEAKey(key);

	std::string accountName = msg.GetString();
	std::string password = msg.GetString();

	if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) {
		dispatchDisconnectClient("Only clients with protocol " CLIENT_VERSION_STR " allowed!");
		return;
	}

	if (g_game.getGameState() == GAME_STATE_STARTUP) {
		dispatchDisconnectClient("Gameworld is starting up. Please wait.");
		return;
	}

	if (g_game.getGameState() == GAME_STATE_MAINTAIN) {
		dispatchDisconnectClient("Gameworld is under maintenance. Please re-connect in a while.");
		return;
	}

	BanInfo banInfo;
	if (IOBan::isIpBanned(clientip, banInfo)) {
		if (banInfo.reason.empty()) {
			banInfo.reason = "(none)";
		}

		std::ostringstream ss;
		ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason;
		dispatchDisconnectClient(ss.str());
		return;
	}

	if (accountName.empty()) {
		dispatchDisconnectClient("Invalid account name.");
		return;
	}

#undef dispatchDisconnectClient

	g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, this, accountName, password)));
}
Beispiel #17
0
void ProtocolAdmin::parsePacket(NetworkMessage& msg)
{
	if(g_game.getGameState() == GAMESTATE_SHUTDOWN)
	{
		getConnection()->close();
		return;
	}

	uint8_t recvbyte = msg.get<char>();
	OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false);
	if(!output)
		return;

	TRACK_MESSAGE(output);
	switch(m_state)
	{
		case ENCRYPTION_NO_SET:
		{
			if(Admin::getInstance()->isEncypted())
			{
				if((time(NULL) - m_startTime) > 30000)
				{
					getConnection()->close();
					addLogLine(LOGTYPE_EVENT, "encryption timeout");
					return;
				}

				if(recvbyte != AP_MSG_ENCRYPTION && recvbyte != AP_MSG_KEY_EXCHANGE)
				{
					output->put<char>(AP_MSG_ERROR);
					output->putString("encryption needed");
					OutputMessagePool::getInstance()->send(output);

					getConnection()->close();
					addLogLine(LOGTYPE_EVENT, "wrong command while ENCRYPTION_NO_SET");
					return;
				}
			}
			else
				m_state = NO_LOGGED_IN;

			break;
		}

		case NO_LOGGED_IN:
		{
			if(g_config.getBool(ConfigManager::ADMIN_REQUIRE_LOGIN))
			{
				if((time(NULL) - m_startTime) > 30000)
				{
					//login timeout
					getConnection()->close();
					addLogLine(LOGTYPE_EVENT, "login timeout");
					return;
				}

				if(m_loginTries > 3)
				{
					output->put<char>(AP_MSG_ERROR);
					output->putString("too many login tries");
					OutputMessagePool::getInstance()->send(output);

					getConnection()->close();
					addLogLine(LOGTYPE_EVENT, "too many login tries");
					return;
				}

				if(recvbyte != AP_MSG_LOGIN)
				{
					output->put<char>(AP_MSG_ERROR);
					output->putString("you are not logged in");
					OutputMessagePool::getInstance()->send(output);

					getConnection()->close();
					addLogLine(LOGTYPE_EVENT, "wrong command while NO_LOGGED_IN");
					return;
				}
			}
			else
				m_state = LOGGED_IN;

			break;
		}

		case LOGGED_IN:
			break;

		default:
		{
			getConnection()->close();
			addLogLine(LOGTYPE_EVENT, "no valid connection state!!!");
			return;
		}
	}

	m_lastCommand = time(NULL);
	switch(recvbyte)
	{
		case AP_MSG_LOGIN:
		{
			if(m_state == NO_LOGGED_IN && g_config.getBool(ConfigManager::ADMIN_REQUIRE_LOGIN))
			{
				std::string pass = msg.getString(), word = g_config.getString(ConfigManager::ADMIN_PASSWORD);
				_encrypt(word, false);
				if(pass == word)
				{
					m_state = LOGGED_IN;
					output->put<char>(AP_MSG_LOGIN_OK);
					addLogLine(LOGTYPE_EVENT, "login ok");
				}
				else
				{
					m_loginTries++;
					output->put<char>(AP_MSG_LOGIN_FAILED);
					output->putString("wrong password");
					addLogLine(LOGTYPE_EVENT, "login failed.("+ pass + ")");
				}
			}
			else
			{
				output->put<char>(AP_MSG_LOGIN_FAILED);
				output->putString("cannot login");
				addLogLine(LOGTYPE_EVENT, "wrong state at login");
			}

			break;
		}

		case AP_MSG_ENCRYPTION:
		{
			if(m_state == ENCRYPTION_NO_SET && Admin::getInstance()->isEncypted())
			{
				uint8_t keyType = msg.get<char>();
				switch(keyType)
				{
					case ENCRYPTION_RSA1024XTEA:
					{
						RSA* rsa = Admin::getInstance()->getRSAKey(ENCRYPTION_RSA1024XTEA);
						if(!rsa)
						{
							output->put<char>(AP_MSG_ENCRYPTION_FAILED);
							addLogLine(LOGTYPE_EVENT, "no valid server key type");
							break;
						}

						if(RSA_decrypt(rsa, msg))
						{
							m_state = NO_LOGGED_IN;
							uint32_t k[4]= {msg.get<uint32_t>(), msg.get<uint32_t>(), msg.get<uint32_t>(), msg.get<uint32_t>()};

							//use for in/out the new key we have
							enableXTEAEncryption();
							setXTEAKey(k);

							output->put<char>(AP_MSG_ENCRYPTION_OK);
							addLogLine(LOGTYPE_EVENT, "encryption ok");
						}
						else
						{
							output->put<char>(AP_MSG_ENCRYPTION_FAILED);
							output->putString("wrong encrypted packet");
							addLogLine(LOGTYPE_EVENT, "wrong encrypted packet");
						}

						break;
					}

					default:
					{
						output->put<char>(AP_MSG_ENCRYPTION_FAILED);
						output->putString("no valid key type");

						addLogLine(LOGTYPE_EVENT, "no valid client key type");
						break;
					}
				}
			}
			else
			{
				output->put<char>(AP_MSG_ENCRYPTION_FAILED);
				output->putString("cannot set encryption");
				addLogLine(LOGTYPE_EVENT, "cannot set encryption");
			}

			break;
		}

		case AP_MSG_KEY_EXCHANGE:
		{
			if(m_state == ENCRYPTION_NO_SET && Admin::getInstance()->isEncypted())
			{
				uint8_t keyType = msg.get<char>();
				switch(keyType)
				{
					case ENCRYPTION_RSA1024XTEA:
					{
						RSA* rsa = Admin::getInstance()->getRSAKey(ENCRYPTION_RSA1024XTEA);
						if(!rsa)
						{
							output->put<char>(AP_MSG_KEY_EXCHANGE_FAILED);
							addLogLine(LOGTYPE_EVENT, "no valid server key type");
							break;
						}

						output->put<char>(AP_MSG_KEY_EXCHANGE_OK);
						output->put<char>(ENCRYPTION_RSA1024XTEA);

						char RSAPublicKey[128];
						rsa->getPublicKey(RSAPublicKey);

						output->put<char>s(RSAPublicKey, 128);
						break;
					}

					default:
					{
						output->put<char>(AP_MSG_KEY_EXCHANGE_FAILED);
						addLogLine(LOGTYPE_EVENT, "no valid client key type");
						break;
					}
				}
			}
			else
			{
				output->put<char>(AP_MSG_KEY_EXCHANGE_FAILED);
				output->putString("cannot get public key");
				addLogLine(LOGTYPE_EVENT, "cannot get public key");
			}

			break;
		}

		case AP_MSG_COMMAND:
		{
			if(m_state != LOGGED_IN)
			{
				addLogLine(LOGTYPE_EVENT, "recvbyte == AP_MSG_COMMAND && m_state != LOGGED_IN !!!");
				break;
			}

			uint8_t command = msg.get<char>();
			switch(command)
			{
				case CMD_SAVE_SERVER:
				case CMD_SHALLOW_SAVE_SERVER:
				{
					uint8_t flags = (uint8_t)SAVE_PLAYERS | (uint8_t)SAVE_MAP | (uint8_t)SAVE_STATE;
					if(command == CMD_SHALLOW_SAVE_SERVER)
						flags |= SAVE_PLAYERS_SHALLOW;

					addLogLine(LOGTYPE_EVENT, "saving server");
					Dispatcher::getInstance().addTask(createTask(boost::bind(&Game::saveGameState, &g_game, flags)));

					output->put<char>(AP_MSG_COMMAND_OK);
					break;
				}

				case CMD_CLOSE_SERVER:
				{
					addLogLine(LOGTYPE_EVENT, "closing server");
					Dispatcher::getInstance().addTask(createTask(boost::bind(
						&Game::setGameState, &g_game, GAMESTATE_CLOSED)));

					output->put<char>(AP_MSG_COMMAND_OK);
					break;
				}

				case CMD_OPEN_SERVER:
				{
					addLogLine(LOGTYPE_EVENT, "opening server");
					g_game.setGameState(GAMESTATE_NORMAL);

					output->put<char>(AP_MSG_COMMAND_OK);
					break;
				}

				case CMD_SHUTDOWN_SERVER:
				{
					addLogLine(LOGTYPE_EVENT, "shutting down server");
					Dispatcher::getInstance().addTask(createTask(boost::bind(
						&Game::setGameState, &g_game, GAMESTATE_SHUTDOWN)));

					output->put<char>(AP_MSG_COMMAND_OK);
					break;
				}

				case CMD_PAY_HOUSES:
				{
					Dispatcher::getInstance().addTask(createTask(boost::bind(
						&ProtocolAdmin::adminCommandPayHouses, this)));
					break;
				}

				case CMD_RELOAD_SCRIPTS:
				{
					const int8_t reload = msg.get<char>();
					Dispatcher::getInstance().addTask(createTask(boost::bind(
						&ProtocolAdmin::adminCommandReload, this, reload)));
					break;
				}

				case CMD_KICK:
				{
					const std::string param = msg.getString();
					Dispatcher::getInstance().addTask(createTask(boost::bind(
						&ProtocolAdmin::adminCommandKickPlayer, this, param)));
					break;
				}

				case CMD_SEND_MAIL:
				{
					const std::string xmlData = msg.getString();
					Dispatcher::getInstance().addTask(createTask(boost::bind(
						&ProtocolAdmin::adminCommandSendMail, this, xmlData)));
					break;
				}

				case CMD_BROADCAST:
				{
					const std::string param = msg.getString();
					addLogLine(LOGTYPE_EVENT, "broadcasting: " + param);
					Dispatcher::getInstance().addTask(createTask(boost::bind(
						&Game::broadcastMessage, &g_game, param, MSG_STATUS_WARNING)));

					output->put<char>(AP_MSG_COMMAND_OK);
					break;
				}

				default:
				{
					output->put<char>(AP_MSG_COMMAND_FAILED);
					output->putString("not known server command");
					addLogLine(LOGTYPE_EVENT, "not known server command");
				}
			}
			break;
		}

		case AP_MSG_PING:
			output->put<char>(AP_MSG_PING_OK);
			break;

		case AP_MSG_KEEP_ALIVE:
			break;

		default:
		{
			output->put<char>(AP_MSG_ERROR);
			output->putString("not known command byte");

			addLogLine(LOGTYPE_EVENT, "not known command byte");
			break;
		}
	}

	if(output->size() > 0)
		OutputMessagePool::getInstance()->send(output);
}
Beispiel #18
0
bool ProtocolLogin::parseFirstPacket(NetworkMessage& msg)
{
	if(g_game.getGameState() == GAME_STATE_SHUTDOWN){
		getConnection()->closeConnection();
		return false;
	}

	uint32_t clientip = getConnection()->getIP();

	/*uint16_t clientos =*/ msg.GetU16();
	uint16_t version  = msg.GetU16();
	msg.SkipBytes(12);

	if(version <= 760){
		disconnectClient(0x0A, "This server requires client version " CLIENT_VERSION_STRING ".");
	}

	if(!RSA_decrypt(msg)){
		getConnection()->closeConnection();
		return false;
	}

	uint32_t key[4];
	key[0] = msg.GetU32();
	key[1] = msg.GetU32();
	key[2] = msg.GetU32();
	key[3] = msg.GetU32();
	enableXTEAEncryption();
	setXTEAKey(key);

	std::string accname = msg.GetString();
	std::string password = msg.GetString();

	if(!accname.length()){
		//Tibia sends this message if the account name length is < 5
		//We will send it only if account name is BLANK
		disconnectClient(0x0A, "Invalid Account Name.");
		return false;
	}

	if(version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX){
		disconnectClient(0x0A, "This server requires client version " CLIENT_VERSION_STRING ".");
		return false;
	}

	if(g_game.getGameState() == GAME_STATE_STARTUP){
		disconnectClient(0x0A, "Gameworld is starting up. Please wait.");
		return false;
	}

	if(g_bans.isIpDisabled(clientip)){
		disconnectClient(0x0A, "Too many connections attempts from this IP. Try again later.");
		return false;
	}

	if(g_bans.isIpBanished(clientip)){
		disconnectClient(0x0A, "Your IP is banished!");
		return false;
	}
	/*
	uint32_t serverip = serverIPs[0].first;
	for(uint32_t i = 0; i < serverIPs.size(); i++){
		if((serverIPs[i].first & serverIPs[i].second) == (clientip & serverIPs[i].second)){
			serverip = serverIPs[i].first;
			break;
		}
	}
	*/

	Account account = IOAccount::instance()->loadAccount(accname);
	if(!(asLowerCaseString(account.name) == asLowerCaseString(accname) &&
			passwordTest(password, account.password))){

		g_bans.addLoginAttempt(clientip, false);
		disconnectClient(0x0A, "Account name or password is not correct.");
		return false;
	}

	g_bans.addLoginAttempt(clientip, true);


	OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false);
	if(output){
		TRACK_MESSAGE(output);
		//Add MOTD
		std::stringstream motd;
		output->AddByte(0x14);
		motd << g_config.getNumber(ConfigManager::MOTD_NUM) << "\n";
		motd << g_config.getString(ConfigManager::MOTD);
		output->AddString(motd.str());
		//Add char list
		output->AddByte(0x64);
		output->AddByte((uint8_t)account.charList.size());
		std::list<AccountCharacter>::iterator it;
		for(it = account.charList.begin(); it != account.charList.end(); it++){
			const AccountCharacter& character = *it;
			output->AddString(character.name);
			output->AddString(character.world_name);
			output->AddU32(character.ip);
			output->AddU16(character.port);
		}
		
		output->AddU16(IOAccount::getPremiumDaysLeft(account.premiumEnd));

		OutputMessagePool::getInstance()->send(output);
	}
	getConnection()->closeConnection();

	return true;
}
Beispiel #19
0
bool ProtocolLogin::parseFirstPacket(NetworkMessage& msg)
{	
	if(g_game.getGameState() == GAME_STATE_SHUTDOWN){
		getConnection()->closeConnection();
		return false;
	}

	uint32_t clientip = getConnection()->getIP();

	/*uint16_t clientos =*/ msg.GetU16();
	uint16_t version  = msg.GetU16();
	msg.SkipBytes(12);
	
	if(version <= 760){
		disconnectClient(0x0A, STRING_CLIENT_VERSION);
	}

	if(!RSA_decrypt(g_otservRSA, msg)){
		getConnection()->closeConnection();
		return false;
	}

	uint32_t key[4];
	key[0] = msg.GetU32();
	key[1] = msg.GetU32();
	key[2] = msg.GetU32();
	key[3] = msg.GetU32();
	enableXTEAEncryption();
	setXTEAKey(key);

	uint32_t accnumber = msg.GetU32();
	std::string password = msg.GetString();

	if(!accnumber){
		disconnectClient(0x0A, "You must enter your account number.");
		return false;
	}

	if(version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX){
		disconnectClient(0x0A, STRING_CLIENT_VERSION);
		return false;
	}

	if(g_game.getGameState() == GAME_STATE_STARTUP){
		disconnectClient(0x0A, "Gameworld is starting up. Please wait.");
		return false;
	}

	if(g_bans.isIpDisabled(clientip)){
		disconnectClient(0x0A, "Too many connections attempts from this IP. Try again later.");
		return false;
	}
	
	if(g_bans.isIpBanished(clientip)){
		disconnectClient(0x0A, "Your IP is banished!");
		return false;
	}

	uint32_t serverip = serverIPs[0].first;
	for(uint32_t i = 0; i < serverIPs.size(); i++){
		if((serverIPs[i].first & serverIPs[i].second) == (clientip & serverIPs[i].second)){
			serverip = serverIPs[i].first;
			break;
		}
	}
	
	Account account = IOAccount::instance()->loadAccount(accnumber);
	if(!(accnumber != 0 && account.accnumber == accnumber &&
			passwordTest(password, account.password))){

		g_bans.addLoginAttempt(clientip, false);
		disconnectClient(0x0A, "Please enter a valid account number and password.");
		return false;
	}

	g_bans.addLoginAttempt(clientip, true);
		
	
	OutputMessage* output = OutputMessagePool::getInstance()->getOutputMessage(this, false);
	//Add MOTD
	std::stringstream motd;
	output->AddByte(0x14);
	motd << g_config.getNumber(ConfigManager::MOTD_NUM) << "\n";
	motd << g_config.getString(ConfigManager::MOTD);
	output->AddString(motd.str());
	//Add char list
	output->AddByte(0x64);
	output->AddByte((uint8_t)account.charList.size());
	std::list<std::string>::iterator it;
	for(it = account.charList.begin(); it != account.charList.end(); it++){
		output->AddString((*it));
		output->AddString(g_config.getString(ConfigManager::WORLD_NAME));
		output->AddU32(serverip);
		output->AddU16(g_config.getNumber(ConfigManager::PORT));
	}
	//Add premium days
	output->AddU16(account.premiumDays);//output->AddU16(0);
	
	OutputMessagePool::getInstance()->send(output);
	getConnection()->closeConnection();

	return true;
}
void ProtocolSpectator::onRecvFirstMessage(NetworkMessage& msg)
{
	if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
		getConnection()->close();
		return;
	}

	operatingSystem = (OperatingSystem_t)msg.get<uint16_t>();
	version = msg.get<uint16_t>();

	msg.skipBytes(7); // U32 clientVersion, U8 clientType

	if (!RSA_decrypt(msg)) {
		getConnection()->close();
		return;
	}

	uint32_t key[4];
	key[0] = msg.get<uint32_t>();
	key[1] = msg.get<uint32_t>();
	key[2] = msg.get<uint32_t>();
	key[3] = msg.get<uint32_t>();
	enableXTEAEncryption();
	setXTEAKey(key);

	if (operatingSystem >= CLIENTOS_OTCLIENT_LINUX) {
		NetworkMessage opcodeMessage;
		opcodeMessage.addByte(0x32);
		opcodeMessage.addByte(0x00);
		opcodeMessage.add<uint16_t>(0x00);
		writeToOutputBuffer(opcodeMessage);
	}

	msg.skipBytes(1); // gamemaster flag
	std::string password = msg.getString();
	std::string characterName = msg.getString();
	

	uint32_t timeStamp = msg.get<uint32_t>();
	uint8_t randNumber = msg.getByte();
	if (m_challengeTimestamp != timeStamp || m_challengeRandom != randNumber) {
		getConnection()->close();
		return;
	}
	auto dispatchDisconnectClient = [this](const std::string& msg) {
		g_dispatcher.addTask(createTask(
					std::bind(&ProtocolSpectator::disconnectSpectator, this, msg)));
	};
	if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) {
		
		dispatchDisconnectClient("Only clients with protocol " CLIENT_VERSION_STR " allowed!");
		return;
	}

	if (g_game.getGameState() == GAME_STATE_STARTUP) {
		dispatchDisconnectClient("Gameworld is starting up. Please wait.");
		return;
	}

	if (g_game.getGameState() == GAME_STATE_MAINTAIN) {
		dispatchDisconnectClient("Gameworld is under maintenance. Please re-connect in a while.");
		return;
	}
	
	BanInfo banInfo;
	if (IOBan::isIpBanned(getIP(), banInfo)) {
		if (banInfo.reason.empty()) {
			banInfo.reason = "(none)";
		}

		std::ostringstream ss;
		ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason;
		dispatchDisconnectClient(ss.str());
		return;
	}
	password.erase(password.begin());
	g_dispatcher.addTask(createTask(std::bind(&ProtocolSpectator::login, this, characterName, password)));
}
/*
 * Ensure the client has the private key by first decrypting the packet and
 * then checking the packet digests.
 */
static int process_cert_verify(SSL *ssl)
{
    uint8_t *buf = &ssl->bm_data[ssl->dc->bm_proc_index];
    int pkt_size = ssl->bm_index;
    uint8_t dgst_buf[MAX_KEY_BYTE_SIZE];
    uint8_t dgst[MD5_SIZE + SHA1_SIZE];
    X509_CTX *x509_ctx = ssl->x509_ctx;
    int ret = SSL_OK;
    int offset = 6;
    int rsa_len;
    int n;

    DISPLAY_RSA(ssl, x509_ctx->rsa_ctx);

    if (ssl->version >= SSL_PROTOCOL_VERSION_TLS1_2) // TLS1.2+
    {
        // TODO: should really need to be able to handle other algorihms. An 
        // assumption is made on RSA/SHA256 and appears to be OK.
        //uint8_t hash_alg = buf[4];
        //uint8_t sig_alg = buf[5];
        offset = 8;
        rsa_len = (buf[6] << 8) + buf[7];
    }
    else
    {
        rsa_len = (buf[4] << 8) + buf[5];
    }

    PARANOIA_CHECK(pkt_size, offset + rsa_len);

    /* rsa_ctx->bi_ctx is not thread-safe */
    SSL_CTX_LOCK(ssl->ssl_ctx->mutex);
    n = RSA_decrypt(x509_ctx->rsa_ctx, &buf[offset], dgst_buf, 
                    sizeof(dgst_buf), 0);
    SSL_CTX_UNLOCK(ssl->ssl_ctx->mutex);

    if (ssl->version >= SSL_PROTOCOL_VERSION_TLS1_2) // TLS1.2+
    {
        if (memcmp(dgst_buf, g_asn1_sha256, sizeof(g_asn1_sha256)))
        {
            ret = SSL_ERROR_INVALID_KEY;
            goto error;
        }

        finished_digest(ssl, NULL, dgst);       /* calculate the digest */
        if (memcmp(&dgst_buf[sizeof(g_asn1_sha256)], dgst, SHA256_SIZE))
        {
            ret = SSL_ERROR_INVALID_KEY;
            goto error;
        }
    }
    else // TLS1.0/1.1
    {
        if (n != SHA1_SIZE + MD5_SIZE)
        {
            ret = SSL_ERROR_INVALID_KEY;
            goto end_cert_vfy;
        }

        finished_digest(ssl, NULL, dgst);       /* calculate the digest */
        if (memcmp(dgst_buf, dgst, MD5_SIZE + SHA1_SIZE))
        {
            ret = SSL_ERROR_INVALID_KEY;
        }
    }

end_cert_vfy:
    ssl->next_state = HS_FINISHED;
error:
    return ret;
}
Beispiel #22
0
void ProtocolAdmin::parsePacket(NetworkMessage& msg)
{
	if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
		getConnection()->closeConnection();
		return;
	}

	uint8_t recvbyte = msg.GetByte();

	OutputMessagePool* outputPool = OutputMessagePool::getInstance();

	OutputMessage_ptr output = outputPool->getOutputMessage(this, false);

	if (!output) {
		return;
	}

	switch (m_state) {
		case ENCRYPTION_NO_SET: {
			if (g_adminConfig->requireEncryption()) {
				if ((time(NULL) - m_startTime) > 30000) {
					getConnection()->closeConnection();
					addLogLine(this, LOGTYPE_WARNING, 1, "encryption timeout");
					return;
				}

				if (recvbyte != AP_MSG_ENCRYPTION && recvbyte != AP_MSG_KEY_EXCHANGE) {
					output->AddByte(AP_MSG_ERROR);
					output->AddString("encryption needed");
					outputPool->send(output);
					getConnection()->closeConnection();
					addLogLine(this, LOGTYPE_WARNING, 1, "wrong command while ENCRYPTION_NO_SET");
					return;
				}

				break;
			} else {
				m_state = NO_LOGGED_IN;
			}
		}

		case NO_LOGGED_IN: {
			if (g_adminConfig->requireLogin()) {
				if ((time(NULL) - m_startTime) > 30000) {
					//login timeout
					getConnection()->closeConnection();
					addLogLine(this, LOGTYPE_WARNING, 1, "login timeout");
					return;
				}

				if (m_loginTries > 3) {
					output->AddByte(AP_MSG_ERROR);
					output->AddString("too many login tries");
					outputPool->send(output);
					getConnection()->closeConnection();
					addLogLine(this, LOGTYPE_WARNING, 1, "too many login tries");
					return;
				}

				if (recvbyte != AP_MSG_LOGIN) {
					output->AddByte(AP_MSG_ERROR);
					output->AddString("you are not logged in");
					outputPool->send(output);
					getConnection()->closeConnection();
					addLogLine(this, LOGTYPE_WARNING, 1, "wrong command while NO_LOGGED_IN");
					return;
				}

				break;
			} else {
				m_state = LOGGED_IN;
			}
		}

		case LOGGED_IN: {
			//can execute commands
			break;
		}

		default: {
			getConnection()->closeConnection();
			return;
		}
	}

	m_lastCommand = time(NULL);

	switch (recvbyte) {
		case AP_MSG_LOGIN: {
			if (m_state == NO_LOGGED_IN && g_adminConfig->requireLogin()) {
				std::string password = msg.GetString();

				if (g_adminConfig->passwordMatch(password)) {
					m_state = LOGGED_IN;
					output->AddByte(AP_MSG_LOGIN_OK);
					addLogLine(this, LOGTYPE_EVENT, 1, "login ok");
				} else {
					m_loginTries++;
					output->AddByte(AP_MSG_LOGIN_FAILED);
					output->AddString("wrong password");
					addLogLine(this, LOGTYPE_WARNING, 1, "login failed.(" + password + ")");
				}
			} else {
				output->AddByte(AP_MSG_LOGIN_FAILED);
				output->AddString("can not login");
				addLogLine(this, LOGTYPE_WARNING, 1, "wrong state at login");
			}

			break;
		}

		case AP_MSG_ENCRYPTION: {
			if (m_state == ENCRYPTION_NO_SET && g_adminConfig->requireEncryption()) {
				uint8_t keyType = msg.GetByte();

				if (keyType == ENCRYPTION_RSA1024XTEA) {
					RSA* rsa = g_adminConfig->getRSAKey(ENCRYPTION_RSA1024XTEA);

					if (!rsa) {
						output->AddByte(AP_MSG_ENCRYPTION_FAILED);
						addLogLine(this, LOGTYPE_WARNING, 1, "no valid server key type");
						break;
					}

					if (RSA_decrypt(rsa, msg)) {
						m_state = NO_LOGGED_IN;
						uint32_t k[4];
						k[0] = msg.GetU32();
						k[1] = msg.GetU32();
						k[2] = msg.GetU32();
						k[3] = msg.GetU32();

						//use for in/out the new key we have
						enableXTEAEncryption();
						setXTEAKey(k);

						output->AddByte(AP_MSG_ENCRYPTION_OK);
						addLogLine(this, LOGTYPE_EVENT, 1, "encryption ok");
					} else {
						output->AddByte(AP_MSG_ENCRYPTION_FAILED);
						output->AddString("wrong encrypted packet");
						addLogLine(this, LOGTYPE_WARNING, 1, "wrong encrypted packet");
					}
				} else {
					output->AddByte(AP_MSG_ENCRYPTION_FAILED);
					output->AddString("no valid key type");
					addLogLine(this, LOGTYPE_WARNING, 1, "no valid client key type");
				}
			} else {
				output->AddByte(AP_MSG_ENCRYPTION_FAILED);
				output->AddString("can not set encryption");
				addLogLine(this, LOGTYPE_EVENT, 1, "can not set encryption");
			}

			break;
		}

		case AP_MSG_KEY_EXCHANGE: {
			if (m_state == ENCRYPTION_NO_SET && g_adminConfig->requireEncryption()) {
				uint8_t keyType = msg.GetByte();

				if (keyType == ENCRYPTION_RSA1024XTEA) {
					RSA* rsa = g_adminConfig->getRSAKey(ENCRYPTION_RSA1024XTEA);

					if (!rsa) {
						output->AddByte(AP_MSG_KEY_EXCHANGE_FAILED);
						addLogLine(this, LOGTYPE_WARNING, 1, "no valid server key type");
						break;
					}

					output->AddByte(AP_MSG_KEY_EXCHANGE_OK);
					output->AddByte(ENCRYPTION_RSA1024XTEA);
					char RSAPublicKey[128];
					rsa->getPublicKey(RSAPublicKey);
					output->AddBytes(RSAPublicKey, 128);
				} else {
					output->AddByte(AP_MSG_KEY_EXCHANGE_FAILED);
					addLogLine(this, LOGTYPE_WARNING, 1, "no valid client key type");
				}
			} else {
				output->AddByte(AP_MSG_KEY_EXCHANGE_FAILED);
				output->AddString("can not get public key");
				addLogLine(this, LOGTYPE_WARNING, 1, "can not get public key");
			}

			break;
		}

		case AP_MSG_COMMAND: {
			if (m_state != LOGGED_IN) {
				addLogLine(this, LOGTYPE_ERROR, 1, "recvbyte == AP_MSG_COMMAND && m_state != LOGGED_IN !!!");
				// We should never reach this point
				break;
			}

			uint8_t command = msg.GetByte();

			switch (command) {
				case CMD_BROADCAST: {
					const std::string message = msg.GetString();
					addLogLine(this, LOGTYPE_EVENT, 1, "broadcast: " + message);
					g_dispatcher.addTask(createTask(boost::bind(&Game::broadcastMessage, &g_game, message, MSG_STATUS_WARNING)));
					output->AddByte(AP_MSG_COMMAND_OK);
					break;
				}

				case CMD_CLOSE_SERVER: {
					g_dispatcher.addTask(createTask(boost::bind(&ProtocolAdmin::adminCommandCloseServer, this)));
					break;
				}

				case CMD_PAY_HOUSES: {
					g_dispatcher.addTask(createTask(boost::bind(&ProtocolAdmin::adminCommandPayHouses, this)));
					break;
				}

				case CMD_OPEN_SERVER: {
					g_dispatcher.addTask(createTask(boost::bind(&ProtocolAdmin::adminCommandOpenServer, this)));
					break;
				}

				case CMD_SHUTDOWN_SERVER: {
					g_dispatcher.addTask(createTask(boost::bind(&ProtocolAdmin::adminCommandShutdownServer, this)));
					getConnection()->closeConnection();
					return;
				}

				case CMD_KICK: {
					const std::string name = msg.GetString();
					g_dispatcher.addTask(createTask(boost::bind(&ProtocolAdmin::adminCommandKickPlayer, this, name)));
					break;
				}

				case CMD_SETOWNER: {
					const std::string param = msg.GetString();
					g_dispatcher.addTask(createTask(boost::bind(&ProtocolAdmin::adminCommandSetOwner, this, param)));
					break;
				}

				default: {
					output->AddByte(AP_MSG_COMMAND_FAILED);
					output->AddString("not known server command");
					addLogLine(this, LOGTYPE_WARNING, 1, "not known server command");
					break;
				}
			}

			break;
		}

		case AP_MSG_PING: {
			output->AddByte(AP_MSG_PING_OK);
			break;
		}

		default: {
			output->AddByte(AP_MSG_ERROR);
			output->AddString("not known command byte");
			addLogLine(this, LOGTYPE_WARNING, 1, "not known command byte");
			break;
		}
	}

	if (output->getMessageLength() > 0) {
		outputPool->send(output);
	}
}
Beispiel #23
0
bool ProtocolLogin::parseFirstPacket(NetworkMessage& msg)
{
	if(server.game().getGameState() == GAME_STATE_SHUTDOWN)
	{
		getConnection()->close();
		return false;
	}

	uint32_t clientIp = getConnection()->getIP();
	/*uint16_t operatingSystem = msg.GetU16();*/msg.SkipBytes(2);
	uint16_t version = msg.GetU16();

	msg.SkipBytes(12);
	if(!RSA_decrypt(msg))
	{
		getConnection()->close();
		return false;
	}

	uint32_t key[4] = {msg.GetU32(), msg.GetU32(), msg.GetU32(), msg.GetU32()};
	enableXTEAEncryption();
	setXTEAKey(key);

	std::string name = msg.GetString(), password = msg.GetString();
	if(name.empty())
	{
		if(!server.configManager().getBool(ConfigManager::ACCOUNT_MANAGER))
		{
			disconnectClient(0x0A, "Invalid account name.");
			return false;
		}

		name = "1";
		password = "******";
	}

	if(version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX)
	{
		disconnectClient(0x0A, CLIENT_VERSION_STRING);
		return false;
	}

	if(server.game().getGameState() < GAME_STATE_NORMAL)
	{
		disconnectClient(0x0A, "Server is just starting up, please wait.");
		return false;
	}

	if(server.game().getGameState() == GAME_STATE_MAINTAIN)
	{
		disconnectClient(0x0A, "Server is under maintenance, please re-connect in a while.");
		return false;
	}

	if(ConnectionManager::getInstance()->isDisabled(clientIp, protocolId))
	{
		disconnectClient(0x0A, "Too many connections attempts from your IP address, please try again later.");
		return false;
	}

	if(IOBan::getInstance()->isIpBanished(clientIp))
	{
		disconnectClient(0x0A, "Your IP is banished!");
		return false;
	}

	uint32_t id = 1;
	if(!IOLoginData::getInstance()->getAccountId(name, id))
	{
		ConnectionManager::getInstance()->addAttempt(clientIp, protocolId, false);
		disconnectClient(0x0A, "Invalid account name.");
		return false;
	}

	AccountP account = IOLoginData::getInstance()->loadAccount(id);
	if (account == nullptr) {
		disconnectClient(0x0A, "Invalid account name.");
		return false;
	}

	if(!encryptTest(password, account->getPassword()))
	{
		ConnectionManager::getInstance()->addAttempt(clientIp, protocolId, false);
		disconnectClient(0x0A, "Invalid password.");
		return false;
	}

	Ban ban;
	ban.value = account->getId();

	ban.type = BAN_ACCOUNT;
	if(IOBan::getInstance()->getData(ban) && !IOLoginData::getInstance()->hasFlag(account->getId(), PlayerFlag_CannotBeBanned))
	{
		bool deletion = ban.expires < 0;
		std::string name_ = "Automatic ";
		if(!ban.adminId)
			name_ += (deletion ? "deletion" : "banishment");
		else
			IOLoginData::getInstance()->getNameByGuid(ban.adminId, name_, true);

		char buffer[500 + ban.comment.length()];
		sprintf(buffer, "Your account has been %s at:\n%s by: %s,\nfor the following reason:\n%s.\nThe action taken was:\n%s.\nThe comment given was:\n%s.\nYour %s%s.",
			(deletion ? "deleted" : "banished"), formatDateShort(ban.added).c_str(), name_.c_str(),
			getReason(ban.reason).c_str(), getAction(ban.action, false).c_str(), ban.comment.c_str(),
			(deletion ? "account won't be undeleted" : "banishment will be lifted at:\n"),
			(deletion ? "." : formatDateShort(ban.expires, true).c_str()));

		disconnectClient(0x0A, buffer);
		return false;
	}

	const Account::Characters& characters = account->getCharacters();
	if(!server.configManager().getBool(ConfigManager::ACCOUNT_MANAGER) && characters.empty())
	{
		disconnectClient(0x0A, std::string("This account does not contain any character yet.\nCreate a new character on the "
			+ server.configManager().getString(ConfigManager::SERVER_NAME) + " website at " + server.configManager().getString(ConfigManager::URL) + ".").c_str());
		return false;
	}

	ConnectionManager::getInstance()->addAttempt(clientIp, protocolId, true);
	if(OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false))
	{
		TRACK_MESSAGE(output);
		output->AddByte(0x14);

		char motd[1300];
		sprintf(motd, "%d\n%s", server.game().getMotdId(), server.configManager().getString(ConfigManager::MOTD).c_str());
		output->AddString(motd);

		uint32_t serverIp = serverIps[0].first;
		for(IpList::iterator it = serverIps.begin(); it != serverIps.end(); ++it)
		{
			if((it->first & it->second) != (clientIp & it->second))
				continue;

			serverIp = it->first;
			break;
		}

		//Add char list
		output->AddByte(0x64);
		if(server.configManager().getBool(ConfigManager::ACCOUNT_MANAGER) && id != 1)
		{
			output->AddByte(characters.size() + 1);
			output->AddString("Account Manager");
			output->AddString(server.configManager().getString(ConfigManager::SERVER_NAME));
			output->AddU32(serverIp);
			output->AddU16(server.configManager().getNumber(ConfigManager::GAME_PORT));
		}
		else
			output->AddByte((uint8_t)characters.size());

		for (auto it = characters.cbegin(); it != characters.cend(); ++it) {
			auto& character = *it;

#ifndef __LOGIN_SERVER__
			output->AddString(character->getName());
			output->AddString(character->getType());
			output->AddU32(serverIp);
			output->AddU16(server.configManager().getNumber(ConfigManager::GAME_PORT));
#else
			if(version < it->second->getVersionMin() || version > it->second->getVersionMax())
				continue;

			output->AddString(it->first);
			output->AddString(it->second->getName());
			output->AddU32(it->second->getAddress());
			output->AddU16(it->second->getPort());
#endif
		}

		Days premiumDays = account->getPremiumDays();
		if (premiumDays.count() >= std::numeric_limits<uint16_t>::max()) {
			output->AddU16(std::numeric_limits<uint16_t>::max());
		}
		else {
			output->AddU16(static_cast<uint16_t>(premiumDays.count()));
		}

		OutputMessagePool::getInstance()->send(output);
	}

	getConnection()->close();
	return true;
}