From 08bbe1199f02d09f908cd3adcf4329e4bd67fd52 Mon Sep 17 00:00:00 2001 From: Ed Tanous Date: Thu, 6 Apr 2023 13:10:02 -0700 Subject: Break up router into separate files The router is a giant behemoth. Start breaking it down into pieces. Tested: Redfish service validator passes. Signed-off-by: Ed Tanous Change-Id: I9d04f53a58ffce3ecbd88dded1aa6e9648d2a762 --- include/dbus_privileges.hpp | 180 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 include/dbus_privileges.hpp (limited to 'include') diff --git a/include/dbus_privileges.hpp b/include/dbus_privileges.hpp new file mode 100644 index 0000000000..377a41cbee --- /dev/null +++ b/include/dbus_privileges.hpp @@ -0,0 +1,180 @@ +#pragma once + +#include "dbus_utility.hpp" +#include "error_messages.hpp" +#include "http_request.hpp" +#include "http_response.hpp" +#include "logging.hpp" +#include "routing/baserule.hpp" +#include "utils/dbus_utils.hpp" + +#include +#include + +#include +#include + +namespace crow +{ +// Populate session with user information. +inline bool + populateUserInfo(Request& req, + const std::shared_ptr& asyncResp, + const dbus::utility::DBusPropertiesMap& userInfoMap) +{ + const std::string* userRolePtr = nullptr; + const bool* remoteUser = nullptr; + const bool* passwordExpired = nullptr; + const std::vector* userGroups = nullptr; + + const bool success = sdbusplus::unpackPropertiesNoThrow( + redfish::dbus_utils::UnpackErrorPrinter(), userInfoMap, "UserPrivilege", + userRolePtr, "RemoteUser", remoteUser, "UserPasswordExpired", + passwordExpired, "UserGroups", userGroups); + + if (!success) + { + BMCWEB_LOG_ERROR << "Failed to unpack user properties."; + asyncResp->res.result( + boost::beast::http::status::internal_server_error); + return false; + } + + if (userRolePtr != nullptr) + { + req.session->userRole = *userRolePtr; + BMCWEB_LOG_DEBUG << "userName = " << req.session->username + << " userRole = " << *userRolePtr; + } + + if (remoteUser == nullptr) + { + BMCWEB_LOG_ERROR << "RemoteUser property missing or wrong type"; + asyncResp->res.result( + boost::beast::http::status::internal_server_error); + return false; + } + bool expired = false; + if (passwordExpired == nullptr) + { + if (!*remoteUser) + { + BMCWEB_LOG_ERROR << "UserPasswordExpired property is expected for" + " local user but is missing or wrong type"; + asyncResp->res.result( + boost::beast::http::status::internal_server_error); + return false; + } + } + else + { + expired = *passwordExpired; + } + + // Set isConfigureSelfOnly based on D-Bus results. This + // ignores the results from both pamAuthenticateUser and the + // value from any previous use of this session. + req.session->isConfigureSelfOnly = expired; + + if (userGroups != nullptr) + { + // Populate session with user groups. + for (const auto& userGroup : *userGroups) + { + req.session->userGroups.emplace_back(userGroup); + } + } + + return true; +} + +inline bool + isUserPrivileged(Request& req, + const std::shared_ptr& asyncResp, + BaseRule& rule) +{ + // Get the user's privileges from the role + redfish::Privileges userPrivileges = + redfish::getUserPrivileges(*req.session); + + // Modify privileges if isConfigureSelfOnly. + if (req.session->isConfigureSelfOnly) + { + // Remove all privileges except ConfigureSelf + userPrivileges = + userPrivileges.intersection(redfish::Privileges{"ConfigureSelf"}); + BMCWEB_LOG_DEBUG << "Operation limited to ConfigureSelf"; + } + + if (!rule.checkPrivileges(userPrivileges)) + { + asyncResp->res.result(boost::beast::http::status::forbidden); + if (req.session->isConfigureSelfOnly) + { + redfish::messages::passwordChangeRequired( + asyncResp->res, + boost::urls::format("/redfish/v1/AccountService/Accounts/{}", + req.session->username)); + } + return false; + } + + req.userRole = req.session->userRole; + return true; +} + +template +void afterGetUserInfo(Request& req, + const std::shared_ptr& asyncResp, + BaseRule& rule, CallbackFn&& callback, + const boost::system::error_code& ec, + const dbus::utility::DBusPropertiesMap& userInfoMap) +{ + if (ec) + { + BMCWEB_LOG_ERROR << "GetUserInfo failed..."; + asyncResp->res.result( + boost::beast::http::status::internal_server_error); + return; + } + + if (!populateUserInfo(req, asyncResp, userInfoMap)) + { + BMCWEB_LOG_ERROR << "Failed to populate user information"; + asyncResp->res.result( + boost::beast::http::status::internal_server_error); + return; + } + + if (!isUserPrivileged(req, asyncResp, rule)) + { + // User is not privileged + BMCWEB_LOG_ERROR << "Insufficient Privilege"; + asyncResp->res.result(boost::beast::http::status::forbidden); + return; + } + callback(req); +} + +template +void validatePrivilege(Request& req, + const std::shared_ptr& asyncResp, + BaseRule& rule, CallbackFn&& callback) +{ + if (req.session == nullptr) + { + return; + } + std::string username = req.session->username; + crow::connections::systemBus->async_method_call( + [&req, asyncResp, &rule, callback(std::forward(callback))]( + const boost::system::error_code& ec, + const dbus::utility::DBusPropertiesMap& userInfoMap) mutable { + afterGetUserInfo(req, asyncResp, rule, + std::forward(callback), ec, userInfoMap); + }, + "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", + "xyz.openbmc_project.User.Manager", "GetUserInfo", username); +} + +} // namespace crow -- cgit v1.2.3