/** * Copyright (C) 2014-2016 Jessica James. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Written by Jessica James */ #include #include "Jupiter/IRC_Client.h" #include "Jupiter/INIFile.h" #include "RenX_PlayerInfo.h" #include "RenX_BanDatabase.h" #include "RenX_Core.h" #include "RenX_Plugin.h" using namespace Jupiter::literals; RenX::BanDatabase _banDatabase; RenX::BanDatabase *RenX::banDatabase = &_banDatabase; RenX::BanDatabase &RenX::defaultBanDatabase = _banDatabase; void RenX::BanDatabase::process_data(Jupiter::DataBuffer &buffer, FILE *file, fpos_t pos) { if (RenX::BanDatabase::read_version < 3U) return; // incompatible database version RenX::BanDatabase::Entry *entry = new RenX::BanDatabase::Entry(); entry->pos = pos; // Read data from buffer to entry entry->flags = buffer.pop(); entry->timestamp = buffer.pop(); entry->length = buffer.pop(); entry->steamid = buffer.pop(); entry->ip = buffer.pop(); entry->prefix_length = buffer.pop(); entry->rdns = buffer.pop(); entry->name = buffer.pop(); entry->banner = buffer.pop(); entry->reason = buffer.pop(); // Read varData from buffer to entry for (size_t varData_entries = buffer.pop(); varData_entries != 0; --varData_entries) entry->varData.set(buffer.pop(), buffer.pop()); } void RenX::BanDatabase::process_header(FILE *file) { int chr = fgetc(file); if (chr != EOF) RenX::BanDatabase::read_version = chr; } void RenX::BanDatabase::create_header(FILE *file) { fputc(RenX::BanDatabase::write_version, file); } void RenX::BanDatabase::process_file_finish(FILE *file) { if (RenX::BanDatabase::read_version < 3) { if (freopen(RenX::BanDatabase::filename.c_str(), "wb", file) == nullptr) puts("FATAL ERROR: UNABLE TO REMOVE UNSUPPORTED BAN DATABASE FILE VERSION"); else { puts("Warning: Unsupported ban database file version. The database will be removed and rewritten."); this->create_header(file); RenX::BanDatabase::read_version = RenX::BanDatabase::write_version; } } } void RenX::BanDatabase::upgrade_database() { FILE *file = fopen(RenX::BanDatabase::filename.c_str(), "wb"); if (file != nullptr) { this->create_header(file); for (size_t index = 0; RenX::BanDatabase::entries.size(); ++index) RenX::BanDatabase::write(RenX::BanDatabase::entries.get(index), file); fclose(file); } } void RenX::BanDatabase::write(RenX::BanDatabase::Entry *entry) { FILE *file = fopen(filename.c_str(), "ab"); if (file != nullptr) { RenX::BanDatabase::write(entry, file); fclose(file); } } void RenX::BanDatabase::write(RenX::BanDatabase::Entry *entry, FILE *file) { Jupiter::DataBuffer buffer; fgetpos(file, &entry->pos); // push data from entry to buffer buffer.push(entry->flags); buffer.push(entry->timestamp); buffer.push(entry->length); buffer.push(entry->steamid); buffer.push(entry->ip); buffer.push(entry->prefix_length); buffer.push(entry->rdns); buffer.push(entry->name); buffer.push(entry->banner); buffer.push(entry->reason); // push varData from entry to buffer size_t varData_entries = entry->varData.size(); buffer.push(varData_entries); Jupiter::INIFile::Section::KeyValuePair *pair; while (varData_entries != 0) { pair = entry->varData.getPair(--varData_entries); buffer.push(pair->getKey()); buffer.push(pair->getValue()); } // push buffer to file buffer.push_to(file); } void RenX::BanDatabase::add(RenX::Server *server, const RenX::PlayerInfo *player, const Jupiter::ReadableString &banner, const Jupiter::ReadableString &reason, time_t length, uint16_t flags) { Entry *entry = new Entry(); entry->set_active(); entry->flags |= flags; entry->timestamp = time(0); entry->length = length; entry->steamid = player->steamid; entry->ip = player->ip32; entry->prefix_length = 32U; entry->rdns = player->rdns; entry->name = player->name; entry->banner = banner; entry->reason = reason; // add plugin data Jupiter::String pluginData; Jupiter::ArrayList &xPlugins = *RenX::getCore()->getPlugins(); for (size_t i = 0; i < xPlugins.size(); i++) if (xPlugins.get(i)->RenX_OnBan(server, player, pluginData)) entry->varData.set(xPlugins.get(i)->getName(), pluginData); entries.add(entry); RenX::BanDatabase::write(entry); } void RenX::BanDatabase::add(const Jupiter::ReadableString &name, uint32_t ip, uint8_t prefix_length, uint64_t steamid, const Jupiter::ReadableString &rdns, Jupiter::ReadableString &banner, Jupiter::ReadableString &reason, time_t length, uint16_t flags) { Entry *entry = new Entry(); entry->set_active(); entry->flags |= flags; entry->timestamp = time(0); entry->length = length; entry->steamid = steamid; entry->ip = ip; entry->prefix_length = prefix_length; entry->rdns = rdns; entry->name = name; entry->banner = banner; entry->reason = reason; entries.add(entry); RenX::BanDatabase::write(entry); } bool RenX::BanDatabase::deactivate(size_t index) { RenX::BanDatabase::Entry *entry = RenX::BanDatabase::entries.get(index); if (entry->is_active()) { entry->unset_active(); FILE *file = fopen(RenX::BanDatabase::filename.c_str(), "r+b"); if (file != nullptr) { fsetpos(file, &entry->pos); fputc(entry->flags, file); fclose(file); } return true; } return false; } uint8_t RenX::BanDatabase::getVersion() const { return RenX::BanDatabase::write_version; } const Jupiter::ReadableString &RenX::BanDatabase::getFileName() const { return RenX::BanDatabase::filename; } const Jupiter::ArrayList &RenX::BanDatabase::getEntries() const { return RenX::BanDatabase::entries; } RenX::BanDatabase::BanDatabase() { RenX::BanDatabase::filename = Jupiter::IRC::Client::Config->get(STRING_LITERAL_AS_REFERENCE("RenX"), STRING_LITERAL_AS_REFERENCE("BanDB"), STRING_LITERAL_AS_REFERENCE("Bans.db")); this->process_file(filename); } RenX::BanDatabase::~BanDatabase() { RenX::BanDatabase::entries.emptyAndDelete(); }