diff options
-rw-r--r-- | http/websocket.h | 11 | ||||
-rw-r--r-- | include/nbd_proxy.hpp | 196 |
2 files changed, 143 insertions, 64 deletions
diff --git a/http/websocket.h b/http/websocket.h index f7c818e6e1..c467d25594 100644 --- a/http/websocket.h +++ b/http/websocket.h @@ -23,6 +23,9 @@ struct Connection : std::enable_shared_from_this<Connection> explicit Connection(const crow::Request& reqIn) : req(reqIn.req), userdataPtr(nullptr){}; + explicit Connection(const crow::Request& reqIn, std::string user) : + req(reqIn.req), userName{std::move(user)}, userdataPtr(nullptr){}; + virtual void sendBinary(const std::string_view msg) = 0; virtual void sendBinary(std::string&& msg) = 0; virtual void sendText(const std::string_view msg) = 0; @@ -40,10 +43,16 @@ struct Connection : std::enable_shared_from_this<Connection> return userdataPtr; } + const std::string& getUserName() const + { + return userName; + } + boost::beast::http::request<boost::beast::http::string_body> req; crow::Response res; private: + std::string userName{}; void* userdataPtr; }; @@ -58,7 +67,7 @@ template <typename Adaptor> class ConnectionImpl : public Connection message_handler, std::function<void(Connection&, const std::string&)> close_handler, std::function<void(Connection&)> error_handler) : - Connection(reqIn), + Connection(reqIn, reqIn.session->username), ws(std::move(adaptorIn)), inString(), inBuffer(inString, 131088), openHandler(std::move(open_handler)), messageHandler(std::move(message_handler)), diff --git a/include/nbd_proxy.hpp b/include/nbd_proxy.hpp index 6922ae2765..12fbb8ed10 100644 --- a/include/nbd_proxy.hpp +++ b/include/nbd_proxy.hpp @@ -23,6 +23,7 @@ #include <boost/container/flat_map.hpp> #include <dbus_utility.hpp> #include <experimental/filesystem> +#include <privileges.hpp> #include <variant> #include <webserver_common.hpp> @@ -35,6 +36,7 @@ namespace nbd_proxy using boost::asio::local::stream_protocol; static constexpr auto nbdBufferSize = 131088; +static const char* requiredPrivilegeString = "ConfigureManager"; struct NbdProxyServer : std::enable_shared_from_this<NbdProxyServer> { @@ -250,105 +252,173 @@ void requestRoutes(CrowApp& app) { BMCWEB_ROUTE(app, "/nbd/<str>") .websocket() - .onopen([&app](crow::websocket::Connection& conn, - std::shared_ptr<bmcweb::AsyncResp> asyncResp) { + .onopen([](crow::websocket::Connection& conn, + std::shared_ptr<bmcweb::AsyncResp> asyncResp) { BMCWEB_LOG_DEBUG << "nbd-proxy.onopen(" << &conn << ")"; - for (const auto session : sessions) - { - if (session.second->getEndpointId() == conn.req.target()) + auto getUserInfoHandler = [&conn, asyncResp{std::move(asyncResp)}]( + const boost::system::error_code ec, + boost::container::flat_map< + std::string, + std::variant< + bool, std::string, + std::vector<std::string>>> + userInfo) { + if (ec) { - BMCWEB_LOG_ERROR - << "Cannot open new connection - socket is in use"; + BMCWEB_LOG_ERROR << "GetUserInfo failed..."; + asyncResp->res.result( + boost::beast::http::status::internal_server_error); return; } - } - auto openHandler = [asyncResp, &conn]( - const boost::system::error_code ec, - dbus::utility::ManagedObjectType& objects) { - const std::string* socketValue = nullptr; - const std::string* endpointValue = nullptr; - const std::string* endpointObjectPath = nullptr; - - if (ec) + const std::string* userRolePtr = nullptr; + auto userInfoIter = userInfo.find("UserPrivilege"); + if (userInfoIter != userInfo.end()) { - BMCWEB_LOG_ERROR << "DBus error: " << ec.message(); - return; + userRolePtr = + std::get_if<std::string>(&userInfoIter->second); } - for (const auto& objectPath : objects) + std::string userRole{}; + if (userRolePtr != nullptr) { - const auto interfaceMap = objectPath.second.find( - "xyz.openbmc_project.VirtualMedia.MountPoint"); + userRole = *userRolePtr; + BMCWEB_LOG_DEBUG << "userName = " << conn.getUserName() + << " userRole = " << *userRolePtr; + } - if (interfaceMap == objectPath.second.end()) - { - BMCWEB_LOG_DEBUG << "Cannot find MountPoint object"; - continue; - } + // Get the user privileges from the role + ::redfish::Privileges userPrivileges = + ::redfish::getUserPrivileges(userRole); + + const ::redfish::Privileges requiredPrivileges{ + requiredPrivilegeString}; - const auto endpoint = - interfaceMap->second.find("EndpointId"); - if (endpoint == interfaceMap->second.end()) + if (!userPrivileges.isSupersetOf(requiredPrivileges)) + { + BMCWEB_LOG_DEBUG << "User " << conn.getUserName() + << " not authorized for nbd connection"; + asyncResp->res.result( + boost::beast::http::status::unauthorized); + return; + } + + for (const auto session : sessions) + { + if (session.second->getEndpointId() == conn.req.target()) { - BMCWEB_LOG_DEBUG << "Cannot find EndpointId property"; - continue; + BMCWEB_LOG_ERROR + << "Cannot open new connection - socket is in use"; + asyncResp->res.result( + boost::beast::http::status::bad_request); + return; } + } - endpointValue = std::get_if<std::string>(&endpoint->second); + auto openHandler = [asyncResp, + &conn](const boost::system::error_code ec, + dbus::utility::ManagedObjectType& + objects) { + const std::string* socketValue = nullptr; + const std::string* endpointValue = nullptr; + const std::string* endpointObjectPath = nullptr; - if (endpointValue == nullptr) + if (ec) { - BMCWEB_LOG_ERROR << "EndpointId property value is null"; - continue; + BMCWEB_LOG_ERROR << "DBus error: " << ec.message(); + asyncResp->res.result( + boost::beast::http::status::internal_server_error); + return; } - if (*endpointValue == conn.req.target()) + for (const auto& objectPath : objects) { - const auto socket = interfaceMap->second.find("Socket"); - if (socket == interfaceMap->second.end()) + const auto interfaceMap = objectPath.second.find( + "xyz.openbmc_project.VirtualMedia.MountPoint"); + + if (interfaceMap == objectPath.second.end()) { - BMCWEB_LOG_DEBUG << "Cannot find Socket property"; + BMCWEB_LOG_DEBUG << "Cannot find MountPoint object"; continue; } - socketValue = std::get_if<std::string>(&socket->second); - if (socketValue == nullptr) + const auto endpoint = + interfaceMap->second.find("EndpointId"); + if (endpoint == interfaceMap->second.end()) { - BMCWEB_LOG_ERROR << "Socket property value is null"; + BMCWEB_LOG_DEBUG + << "Cannot find EndpointId property"; continue; } - endpointObjectPath = &objectPath.first.str; - break; + endpointValue = + std::get_if<std::string>(&endpoint->second); + + if (endpointValue == nullptr) + { + BMCWEB_LOG_ERROR + << "EndpointId property value is null"; + continue; + } + + if (*endpointValue == conn.req.target()) + { + const auto socket = + interfaceMap->second.find("Socket"); + if (socket == interfaceMap->second.end()) + { + BMCWEB_LOG_DEBUG + << "Cannot find Socket property"; + continue; + } + + socketValue = + std::get_if<std::string>(&socket->second); + if (socketValue == nullptr) + { + BMCWEB_LOG_ERROR + << "Socket property value is null"; + continue; + } + + endpointObjectPath = &objectPath.first.str; + break; + } } - } - if (endpointObjectPath == nullptr) - { - BMCWEB_LOG_ERROR << "Cannot find requested EndpointId"; - asyncResp->res.result( - boost::beast::http::status::not_found); - return; - } + if (endpointObjectPath == nullptr) + { + BMCWEB_LOG_ERROR << "Cannot find requested EndpointId"; + asyncResp->res.result( + boost::beast::http::status::not_found); + return; + } - // If the socket file exists (i.e. after bmcweb crash), we - // cannot reuse it. - std::remove((*socketValue).c_str()); + // If the socket file exists (i.e. after bmcweb crash), + // we cannot reuse it. + std::remove((*socketValue).c_str()); - sessions[&conn] = std::make_shared<NbdProxyServer>( - conn, std::move(*socketValue), std::move(*endpointValue), - std::move(*endpointObjectPath)); + sessions[&conn] = std::make_shared<NbdProxyServer>( + conn, std::move(*socketValue), + std::move(*endpointValue), + std::move(*endpointObjectPath)); - sessions[&conn]->run(); + sessions[&conn]->run(); - asyncResp->res.result(boost::beast::http::status::ok); + asyncResp->res.result(boost::beast::http::status::ok); + }; + crow::connections::systemBus->async_method_call( + std::move(openHandler), "xyz.openbmc_project.VirtualMedia", + "/xyz/openbmc_project/VirtualMedia", + "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); }; + crow::connections::systemBus->async_method_call( - std::move(openHandler), "xyz.openbmc_project.VirtualMedia", - "/xyz/openbmc_project/VirtualMedia", - "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); + std::move(getUserInfoHandler), + "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user", + "xyz.openbmc_project.User.Manager", "GetUserInfo", + conn.getUserName()); }) .onclose( [](crow::websocket::Connection& conn, const std::string& reason) { |