195 lines
5.3 KiB
C++
195 lines
5.3 KiB
C++
#include <sol/types.hpp>
|
|
#include <sstream>
|
|
#include <vector>
|
|
|
|
#include "session.h"
|
|
#include "db/database_manager.h"
|
|
#include "i_network_bridge.h"
|
|
#include "lua_api.h"
|
|
#include "lua_processor.h"
|
|
#include "machine.h"
|
|
#include "vfs.h"
|
|
#include "util.h"
|
|
|
|
vfs_node* find_node_by_id(vfs_node* root, long long id) {
|
|
if(root->id == id) {
|
|
return root;
|
|
}
|
|
for(auto const& [name, child] : root->children) {
|
|
vfs_node* found = find_node_by_id(child, id);
|
|
if(found) {
|
|
return found;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
Session::Session(Machine* home_machine,
|
|
DatabaseManager* db_manager,
|
|
MachineManager* machine_manager,
|
|
INetworkBridge* network_bridge) :
|
|
_machine_manager(machine_manager),
|
|
_db_manager(db_manager),
|
|
_network_bridge(network_bridge),
|
|
_home_machine(home_machine),
|
|
_session_machine(home_machine) {
|
|
|
|
if(home_machine) _current_dir = home_machine->vfs_root;
|
|
}
|
|
|
|
Session::~Session(void) {
|
|
}
|
|
|
|
vfs_node* Session::get_current_dir(void) {
|
|
return _current_dir;
|
|
}
|
|
|
|
Machine* Session::get_home_machine(void) { return _home_machine; }
|
|
Machine* Session::get_session_machine(void) { return _session_machine; }
|
|
|
|
DatabaseManager* Session::get_db_manager(void) {
|
|
return _db_manager;
|
|
}
|
|
|
|
MachineManager* Session::get_machine_manager(void) {
|
|
return _machine_manager;
|
|
}
|
|
|
|
INetworkBridge* Session::get_network_bridge(void) {
|
|
return _network_bridge;
|
|
}
|
|
|
|
void Session::set_current_dir(vfs_node* node) {
|
|
_current_dir = node;
|
|
}
|
|
|
|
void Session::set_session_machine(Machine* machine) {
|
|
_session_machine = machine;
|
|
if(_session_machine) {
|
|
_current_dir = _session_machine->vfs_root;
|
|
}
|
|
}
|
|
|
|
uint32_t Session::get_current_uid(void) {
|
|
return _home_machine->owner_id;
|
|
}
|
|
|
|
uint32_t Session::get_current_gid(void) {
|
|
return _home_machine->owner_id;
|
|
}
|
|
|
|
std::string Session::process_command(const std::string& command) {
|
|
/*
|
|
* Creating the Lua processor on-demand to ensure it exists on the same
|
|
* thread that will execute the script.
|
|
*/
|
|
LuaProcessor lua(*this);
|
|
|
|
/* Trim trailing whitespace. */
|
|
std::string cmd = command;
|
|
size_t end = cmd.find_last_not_of(" \t\n\r");
|
|
cmd = (end == std::string::npos) ? "" : cmd.substr(0, end+1);
|
|
|
|
/* === Generic script executer. === */
|
|
/* Parse the command and it's arguments. */
|
|
std::stringstream ss(cmd);
|
|
std::string command_name;
|
|
ss >> command_name;
|
|
|
|
std::vector<std::string> args;
|
|
std::string arg;
|
|
while(ss >> arg) {
|
|
args.push_back(arg);
|
|
}
|
|
|
|
vfs_node* command_node = nullptr;
|
|
if(command_name.find('/') != std::string::npos) {
|
|
/* Path provided, find node directly. */
|
|
command_node = find_node_by_path(_session_machine->vfs_root, command_name);
|
|
} else {
|
|
/* No path, search current dir then /bin. */
|
|
vfs_node* current_dir = get_current_dir();
|
|
if(current_dir->children.count(command_name)) {
|
|
command_node = current_dir->children.at(command_name);
|
|
} else {
|
|
vfs_node* bin_dir = find_node_by_path(_session_machine->vfs_root, "/bin");
|
|
if(bin_dir && bin_dir->children.count(command_name)) {
|
|
command_node = bin_dir->children.at(command_name);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(command_node) {
|
|
if(command_node->type == EXEC_NODE) {
|
|
if(!has_permission(command_node, *this, EXEC_PERM)) {
|
|
return "Cannot execute '" + command_name + "': Permission denied.";
|
|
}
|
|
bool is_remote = (_session_machine != _home_machine);
|
|
std::string deobfuscated_content = util::xor_string(command_node->content);
|
|
sol::object result = lua.execute(deobfuscated_content, *this, args, is_remote);
|
|
return result.is<std::string>() ? result.as<std::string>()
|
|
: "[Script returned non-string value]";
|
|
} else if(command_node->type == DIR_NODE) {
|
|
return "Cannot execute '" + command_name + "' It is a directory.";
|
|
} else {
|
|
return "Cannot execute '" + command_name + "': Not an executable file.";
|
|
}
|
|
}
|
|
return "Unknown command: " + command_name;
|
|
}
|
|
|
|
std::string Session::write_file(const std::string& path, const std::string& content) {
|
|
return api::write_file(*this, path, content);
|
|
}
|
|
|
|
std::string Session::read_file(const std::string& path) {
|
|
vfs_node* root = get_session_machine()->vfs_root;
|
|
vfs_node* node = nullptr;
|
|
|
|
if(path[0] == '/') {
|
|
node = find_node_by_path(root, path);
|
|
} else {
|
|
/* Relative path. */
|
|
vfs_node* current_dir = get_current_dir();
|
|
if(current_dir->children.count(path)) {
|
|
node = current_dir->children.at(path);
|
|
}
|
|
}
|
|
|
|
if(node && (node->type == FILE_NODE || node->type == EXEC_NODE)) {
|
|
return node->content;
|
|
}
|
|
return "Error: file not found.";
|
|
}
|
|
|
|
std::string Session::get_username(void) {
|
|
if(!_home_machine || !_home_machine->vfs_root) {
|
|
return "unknown";
|
|
}
|
|
|
|
vfs_node* passwd_node = find_node_by_path(_home_machine->vfs_root, "/etc/passwd");
|
|
if(!passwd_node || passwd_node->type != FILE_NODE) {
|
|
return "unknown";
|
|
}
|
|
|
|
std::stringstream ss(passwd_node->content);
|
|
std::string line;
|
|
uint32_t player_id = _home_machine->owner_id;
|
|
|
|
while(std::getline(ss, line)) {
|
|
std::vector<std::string> parts;
|
|
std::stringstream line_ss(line);
|
|
std::string part;
|
|
while(std::getline(line_ss, part, ':')) {
|
|
parts.push_back(part);
|
|
}
|
|
|
|
if(parts.size() >= 3) {
|
|
if(std::to_string(player_id) == parts[2]) {
|
|
return parts[0]; /* Username. */
|
|
}
|
|
}
|
|
}
|
|
return "unknown";
|
|
}
|