mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-08-10 12:12:31 +00:00
Add untrusted connection security infrastructure (v3)
Replace the v2 blacklist approach with a per-command flag system. Commands must opt in to being available for untrusted connections via flag_untrusted_safe (0x400), checked in call_command() which catches all execution paths including nested commands. Infrastructure changes: - Add flag_untrusted_safe to CommandMap - Add untrusted_error exception type for proper error codes - Enforce trust check in both call_command() overloads - Add catch blocks in xmlrpc_c, xmlrpc_tinyxml2, and jsonrpc handlers - Port SCGI trust state management from v2 (thread_local, header parsing) - Add _U macro variants in command_helpers.h for safe command registration - Add CMD2_VAR_*_U and CMD2_VAR_*_U_GET variants for variables
This commit is contained in:
+27
-16
@@ -111,6 +111,9 @@ SCgiTask::event_read() {
|
||||
size_t content_length = 0;
|
||||
const char* header_end = current + header_size;
|
||||
|
||||
// Assume trusted until we find the UNTRUSTED_CONNECTION header.
|
||||
m_trusted = true;
|
||||
|
||||
// Parse out the null-terminated header keys and values, with
|
||||
// checks to ensure it doesn't scan beyond the limits of the
|
||||
// header
|
||||
@@ -141,6 +144,8 @@ SCgiTask::event_read() {
|
||||
goto event_read_failed;
|
||||
} else if (strcmp(key, "CONTENT_TYPE") == 0) {
|
||||
content_type = value;
|
||||
} else if (strcmp(key, "UNTRUSTED_CONNECTION") == 0 && strcmp(value, "1") == 0) {
|
||||
m_trusted = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,6 +275,7 @@ SCgiTask::receive_call(const char* buffer, uint32_t length) {
|
||||
// TODO: Rewrite RpcManager.process to pass the result buffer instead of having to copy it.
|
||||
|
||||
auto scgi_thread = torrent::utils::Thread::self();
|
||||
bool trusted = m_trusted;
|
||||
|
||||
auto result_callback = [this, scgi_thread](const char* b, uint32_t l) {
|
||||
receive_write(b, l);
|
||||
@@ -285,30 +291,35 @@ SCgiTask::receive_call(const char* buffer, uint32_t length) {
|
||||
|
||||
auto lock = std::lock_guard<std::mutex>(m_result_mutex);
|
||||
|
||||
RpcManager::RPCType rpc_type;
|
||||
|
||||
switch (content_type()) {
|
||||
case rpc::SCgiTask::ContentType::JSON:
|
||||
torrent::main_thread::thread()->callback_interrupt_polling(this, [buffer, length, result_callback]() {
|
||||
rpc.process(RpcManager::RPCType::JSON, buffer, length,
|
||||
[result_callback](const char* b, uint32_t l) {
|
||||
result_callback(b, l);
|
||||
return true;
|
||||
});
|
||||
});
|
||||
rpc_type = RpcManager::RPCType::JSON;
|
||||
break;
|
||||
|
||||
case rpc::SCgiTask::ContentType::XML:
|
||||
torrent::main_thread::thread()->callback_interrupt_polling(this, [buffer, length, result_callback]() {
|
||||
rpc.process(RpcManager::RPCType::XML, buffer, length,
|
||||
[result_callback](const char* b, uint32_t l) {
|
||||
result_callback(b, l);
|
||||
return true;
|
||||
});
|
||||
});
|
||||
rpc_type = RpcManager::RPCType::XML;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw torrent::internal_error("SCgiTask::receive_call(...) received bad input.");
|
||||
}
|
||||
|
||||
torrent::main_thread::thread()->callback_interrupt_polling(this, [buffer, length, result_callback, trusted, rpc_type]() {
|
||||
rpc::RpcManager::set_trusted(trusted);
|
||||
|
||||
try {
|
||||
rpc.process(rpc_type, buffer, length,
|
||||
[result_callback](const char* b, uint32_t l) {
|
||||
result_callback(b, l);
|
||||
return true;
|
||||
});
|
||||
} catch (...) {
|
||||
rpc::RpcManager::set_trusted(true);
|
||||
throw;
|
||||
}
|
||||
|
||||
rpc::RpcManager::set_trusted(true);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
Reference in New Issue
Block a user