mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-22 01:13:00 +02:00
Add --log-level command line option to filter out log messages from lower log levels. Then fix the annoying CzechLight warning message and useless "NACM config validation" log. Then add audit trail as we have in netopeer2-server, and finish off by stripping redundant fields from log message: timestamp, identity, and log level. Fixes #892 Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
91 lines
4.3 KiB
Diff
91 lines
4.3 KiB
Diff
From 228aa9ea848d437565b5f90972a0c4b23b279337 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Pecka?= <tomas.pecka@cesnet.cz>
|
|
Date: Tue, 21 Oct 2025 17:23:44 +0200
|
|
Subject: [PATCH 24/42] restconf: validate input for internal rpcs
|
|
MIME-Version: 1.0
|
|
Content-Type: text/plain; charset=UTF-8
|
|
Content-Transfer-Encoding: 8bit
|
|
Organization: Wires
|
|
|
|
Jan found an issue where invalid input to internal rpcs was accepted. It
|
|
turns out that the issue was in parsing, but not validating input for
|
|
internally processed RPCs (those RPCs for subscribed notifications).
|
|
|
|
This patch adds the validation using a wrapper for lyd_validate_op from
|
|
libyang-cpp.
|
|
|
|
I shuffled a little bit of the code around together with this change to
|
|
make it cleaner.
|
|
Also, to make the code generic, we store the name of the internal RPC
|
|
and a XPath for fetching data required for validation (see
|
|
lyd_validate_op docs). The code validates the input data before processing
|
|
the RPC.
|
|
|
|
Change-Id: I55296895e6993b4ca27d21ce2a64ec2d159a35fc
|
|
Signed-off-by: Mattias Walström <lazzer@gmail.com>
|
|
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
|
|
---
|
|
src/restconf/Server.cpp | 36 +++++++++++++++++++++++++++++-------
|
|
1 file changed, 29 insertions(+), 7 deletions(-)
|
|
|
|
diff --git a/src/restconf/Server.cpp b/src/restconf/Server.cpp
|
|
index 77ae1be..7e8db58 100644
|
|
--- a/src/restconf/Server.cpp
|
|
+++ b/src/restconf/Server.cpp
|
|
@@ -438,9 +438,12 @@ libyang::CreatedNodes createEditForPutAndPatch(libyang::Context& ctx, const std:
|
|
return {editNode, replacementNode};
|
|
}
|
|
|
|
-std::optional<libyang::DataNode> processInternalRPC(sysrepo::Session& sess, const libyang::DataNode& rpcInput, const libyang::DataFormat requestEncoding)
|
|
+std::optional<libyang::DataNode> processInternalRPC(sysrepo::Session& sess, libyang::DataNode& rpcInput, const libyang::DataFormat requestEncoding)
|
|
{
|
|
- using InternalRPCHandler = std::function<void(sysrepo::Session&, const libyang::DataFormat, const libyang::DataNode&, libyang::DataNode&)>;
|
|
+ struct InternalRPCHandler {
|
|
+ std::optional<std::string> validationDataXPath; ///< XPath to data used for RPC input validation
|
|
+ std::function<void(sysrepo::Session&, const libyang::DataFormat, const libyang::DataNode&, libyang::DataNode&)> rpcHandler; // The function that processes the RPC
|
|
+ };
|
|
const std::map<std::string, InternalRPCHandler> handlers;
|
|
|
|
const auto rpcPath = rpcInput.path();
|
|
@@ -451,13 +454,32 @@ std::optional<libyang::DataNode> processInternalRPC(sysrepo::Session& sess, cons
|
|
throw ErrorResponse(403, "application", "access-denied", "Access denied.", rpcNode.createdNode->path());
|
|
}
|
|
|
|
- if (auto it = handlers.find(rpcPath); it != handlers.end()) {
|
|
- auto [parent, rpcOutput] = sess.getContext().newPath2(rpcPath, std::nullopt);
|
|
- it->second(sess, requestEncoding, rpcInput, *rpcOutput);
|
|
- return *parent;
|
|
+ auto handlerIt = handlers.find(rpcPath);
|
|
+ if (handlerIt == handlers.end()) {
|
|
+ throw ErrorResponse(501, "application", "operation-not-supported", "Unsupported RPC call to " + rpcPath, rpcPath);
|
|
+ }
|
|
+
|
|
+ // RPC input validation.
|
|
+ sess.switchDatastore(sysrepo::Datastore::Operational);
|
|
+ auto validationData = handlerIt->second.validationDataXPath ? sess.getData(*handlerIt->second.validationDataXPath) : std::nullopt;
|
|
+
|
|
+ try {
|
|
+ libyang::validateOp(rpcInput, validationData, libyang::OperationType::RpcRestconf);
|
|
+ } catch (const libyang::ErrorWithCode& exc) {
|
|
+ const auto errors = sess.getContext().getErrors();
|
|
+
|
|
+ if (!errors.empty()) {
|
|
+ const auto& error = errors.back();
|
|
+ throw ErrorResponse(400, "protocol", "invalid-value", error.message, error.dataPath.value_or(rpcInput.path()));
|
|
+ } else {
|
|
+ // Fallback if no detailed error is available
|
|
+ throw ErrorResponse(400, "protocol", "invalid-value", "Input validation failed"s, rpcInput.path());
|
|
+ }
|
|
}
|
|
|
|
- throw ErrorResponse(501, "application", "operation-not-supported", "Unsupported RPC call to " + rpcPath, rpcPath);
|
|
+ auto [parent, rpcOutput] = sess.getContext().newPath2(rpcPath, std::nullopt);
|
|
+ handlerIt->second.rpcHandler(sess, requestEncoding, rpcInput, *rpcOutput);
|
|
+ return *parent;
|
|
}
|
|
|
|
void processActionOrRPC(std::shared_ptr<RequestContext> requestCtx, const std::chrono::milliseconds timeout)
|
|
--
|
|
2.43.0
|
|
|