* @brief Implementation of security-manager service.
*/
+#include <sys/socket.h>
+
#include <dpl/log/log.h>
#include <dpl/serialization.h>
+#include <sys/smack.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <pwd.h>
-#include <limits.h>
-#include <cstring>
-
-#include "service.h"
+#include "connection.h"
#include "protocols.h"
-#include "security-manager.h"
-#include "smack-common.h"
-#include "smack-rules.h"
-#include "smack-labels.h"
-#include "privilege_db.h"
-#include "cynara.h"
+#include "service.h"
+#include "service_impl.h"
+#include "master-req.h"
namespace SecurityManager {
const InterfaceID IFACE = 1;
-
-Service::Service()
+Service::Service(const bool isSlave):
+ m_isSlave(isSlave)
{
}
GenericSocketService::ServiceDescriptionVector Service::GetServiceDescription()
{
- return ServiceDescriptionVector {
- {SERVICE_SOCKET, "security-manager", IFACE},
- };
-}
-
-void Service::accept(const AcceptEvent &event)
-{
- LogDebug("Accept event. ConnectionID.sock: " << event.connectionID.sock <<
- " ConnectionID.counter: " << event.connectionID.counter <<
- " ServiceID: " << event.interfaceID);
-
- auto &info = m_connectionInfoMap[event.connectionID.counter];
- info.interfaceID = event.interfaceID;
-}
-
-void Service::write(const WriteEvent &event)
-{
- LogDebug("WriteEvent. ConnectionID: " << event.connectionID.sock <<
- " Size: " << event.size <<
- " Left: " << event.left);
-
- if (event.left == 0)
- m_serviceManager->Close(event.connectionID);
-}
-
-void Service::process(const ReadEvent &event)
-{
- LogDebug("Read event for counter: " << event.connectionID.counter);
- auto &info = m_connectionInfoMap[event.connectionID.counter];
- info.buffer.Push(event.rawBuffer);
-
- // We can get several requests in one package.
- // Extract and process them all
- while (processOne(event.connectionID, info.buffer, info.interfaceID));
+ if (m_isSlave)
+ return ServiceDescriptionVector {
+ {SLAVE_SERVICE_SOCKET, /* path */
+ "*", /* smackLabel label (not used, we rely on systemd) */
+ IFACE, /* InterfaceID */
+ false, /* useSendMsg */
+ true}, /* systemdOnly */
+ };
+ else
+ return ServiceDescriptionVector {
+ {SERVICE_SOCKET, /* path */
+ "*", /* smackLabel label (not used, we rely on systemd) */
+ IFACE, /* InterfaceID */
+ false, /* useSendMsg */
+ true}, /* systemdOnly */
+ };
}
-void Service::close(const CloseEvent &event)
+static bool getPeerID(int sock, uid_t &uid, pid_t &pid, std::string &smackLabel)
{
- LogDebug("CloseEvent. ConnectionID: " << event.connectionID.sock);
- m_connectionInfoMap.erase(event.connectionID.counter);
-}
-
-static bool getPeerUserID(int sock, uid_t *uid) {
struct ucred cr;
- socklen_t len = sizeof (cr);
- if (!uid) {
- return false;
- }
+ socklen_t len = sizeof(cr);
+
if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &cr, &len)) {
- *uid = cr.uid;
+ char *smk;
+ ssize_t ret = smack_new_label_from_socket(sock, &smk);
+ if (ret < 0)
+ return false;
+ smackLabel = smk;
+ uid = cr.uid;
+ pid = cr.pid;
+ free(smk);
return true;
}
+
return false;
}
bool retval = false;
uid_t uid;
+ pid_t pid;
+ std::string smackLabel;
- if(!getPeerUserID(conn.sock, &uid)) {
- LogError("Closing socket because of error: unable to get peer's uid");
+ if (!getPeerID(conn.sock, uid, pid, smackLabel)) {
+ LogError("Closing socket because of error: unable to get peer's uid, pid or smack label");
m_serviceManager->Close(conn);
return false;
}
SecurityModuleCall call_type = static_cast<SecurityModuleCall>(call_type_int);
switch (call_type) {
+ case SecurityModuleCall::NOOP:
+ LogDebug("call_type: SecurityModuleCall::NOOP");
+ Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
+ break;
case SecurityModuleCall::APP_INSTALL:
LogDebug("call_type: SecurityModuleCall::APP_INSTALL");
processAppInstall(buffer, send, uid);
case SecurityModuleCall::APP_GET_PKGID:
processGetPkgId(buffer, send);
break;
+ case SecurityModuleCall::APP_GET_GROUPS:
+ processGetAppGroups(buffer, send, uid, pid);
+ break;
+ case SecurityModuleCall::USER_ADD:
+ processUserAdd(buffer, send, uid);
+ break;
+ case SecurityModuleCall::USER_DELETE:
+ processUserDelete(buffer, send, uid);
+ break;
+ case SecurityModuleCall::POLICY_UPDATE:
+ processPolicyUpdate(buffer, send, uid, pid, smackLabel);
+ break;
+ case SecurityModuleCall::GET_CONF_POLICY_ADMIN:
+ processGetConfiguredPolicy(buffer, send, uid, pid, smackLabel, true);
+ break;
+ case SecurityModuleCall::GET_CONF_POLICY_SELF:
+ processGetConfiguredPolicy(buffer, send, uid, pid, smackLabel, false);
+ break;
+ case SecurityModuleCall::GET_POLICY:
+ processGetPolicy(buffer, send, uid, pid, smackLabel);
+ break;
+ case SecurityModuleCall::POLICY_GET_DESCRIPTIONS:
+ processPolicyGetDesc(send);
+ break;
+ case SecurityModuleCall::GET_PRIVILEGES_MAPPING:
+ processPrivilegesMappings(buffer, send);
+ break;
default:
LogError("Invalid call: " << call_type_int);
Throw(ServiceException::InvalidAction);
LogError("Broken protocol.");
} Catch (ServiceException::Base) {
LogError("Broken protocol.");
- } catch (std::exception &e) {
+ } catch (const std::exception &e) {
LogError("STD exception " << e.what());
} catch (...) {
LogError("Unknown exception");
return retval;
}
-static inline bool isSubDir(const char *parent, const char *subdir)
+void Service::processAppInstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid)
{
- while (*parent && *subdir)
- if (*parent++ != *subdir++)
- return false;
+ app_inst_req req;
- return (*subdir == '/');
+ Deserialization::Deserialize(buffer, req.appId);
+ Deserialization::Deserialize(buffer, req.pkgId);
+ Deserialization::Deserialize(buffer, req.privileges);
+ Deserialization::Deserialize(buffer, req.appPaths);
+ Deserialization::Deserialize(buffer, req.uid);
+ Serialization::Serialize(send, ServiceImpl::appInstall(req, uid, m_isSlave));
}
-static inline bool installRequestAuthCheck(const app_inst_req &req, uid_t uid)
+void Service::processAppUninstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid)
{
- if (uid == 0)
- return true;
+ std::string appId;
- struct passwd *pwd;
- do {
- errno = 0;
- pwd = getpwuid(uid);
- if (!pwd && errno != EINTR) {
- LogError("getpwuid failed with '" << uid
- << "' as paramter: " << strerror(errno));
- return false;
- }
- } while (!pwd);
+ Deserialization::Deserialize(buffer, appId);
+ Serialization::Serialize(send, ServiceImpl::appUninstall(appId, uid, m_isSlave));
+}
- std::unique_ptr<char, std::function<void(void*)>> home(
- realpath(pwd->pw_dir, NULL), free);
- if (!home.get()) {
- LogError("realpath failed with '" << pwd->pw_dir
- << "' as paramter: " << strerror(errno));
- return false;
- }
+void Service::processGetPkgId(MessageBuffer &buffer, MessageBuffer &send)
+{
+ std::string appId;
+ std::string pkgId;
+ int ret;
- for (const auto &appPath : req.appPaths) {
- std::unique_ptr<char, std::function<void(void*)>> real_path(
- realpath(appPath.first.c_str(), NULL), free);
- if (!real_path.get()) {
- LogError("realpath failed with '" << appPath.first.c_str()
- << "' as paramter: " << strerror(errno));
- return false;
- }
- LogDebug("Requested path is '" << appPath.first.c_str()
- << "'. User's HOME is '" << pwd->pw_dir << "'");
- if (!isSubDir(home.get(), real_path.get())) {
- LogWarning("User's apps may have registered folders only in user's home dir");
- return false;
- }
+ Deserialization::Deserialize(buffer, appId);
+ ret = ServiceImpl::getPkgId(appId, pkgId);
+ Serialization::Serialize(send, ret);
+ if (ret == SECURITY_MANAGER_API_SUCCESS)
+ Serialization::Serialize(send, pkgId);
+}
- app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
- if (pathType == SECURITY_MANAGER_PATH_PUBLIC) {
- LogWarning("Only root can register SECURITY_MANAGER_PATH_PUBLIC path");
- return false;
+void Service::processGetAppGroups(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid)
+{
+ std::string appId;
+ std::unordered_set<gid_t> gids;
+ int ret;
+
+ Deserialization::Deserialize(buffer, appId);
+ ret = ServiceImpl::getAppGroups(appId, uid, pid, m_isSlave, gids);
+ Serialization::Serialize(send, ret);
+ if (ret == SECURITY_MANAGER_API_SUCCESS) {
+ Serialization::Serialize(send, static_cast<int>(gids.size()));
+ for (const auto &gid : gids) {
+ Serialization::Serialize(send, gid);
}
}
- return true;
}
-bool Service::processAppInstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid)
+void Service::processUserAdd(MessageBuffer &buffer, MessageBuffer &send, uid_t uid)
{
- bool pkgIdIsNew = false;
- std::vector<std::string> addedPermissions;
- std::vector<std::string> removedPermissions;
+ int ret;
+ uid_t uidAdded;
+ int userType;
- // deserialize request data
- app_inst_req req;
- Deserialization::Deserialize(buffer, req.appId);
- Deserialization::Deserialize(buffer, req.pkgId);
- Deserialization::Deserialize(buffer, req.privileges);
- Deserialization::Deserialize(buffer, req.appPaths);
+ Deserialization::Deserialize(buffer, uidAdded);
+ Deserialization::Deserialize(buffer, userType);
- if(!installRequestAuthCheck(req, uid)) {
- LogError("Request from uid " << uid << " for app installation denied");
- Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED);
- return false;
- }
+ ret = ServiceImpl::userAdd(uidAdded, userType, uid, m_isSlave);
+ Serialization::Serialize(send, ret);
+}
- std::string smackLabel;
- if (!generateAppLabel(req.pkgId, smackLabel)) {
- LogError("Cannot generate Smack label for package: " << req.pkgId);
- Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
- return false;
- }
+void Service::processUserDelete(MessageBuffer &buffer, MessageBuffer &send, uid_t uid)
+{
+ int ret;
+ uid_t uidRemoved;
- LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
- << ", generated smack label: " << smackLabel);
+ Deserialization::Deserialize(buffer, uidRemoved);
- // create null terminated array of strings for permissions
- std::unique_ptr<const char *[]> pp_permissions(new const char* [req.privileges.size() + 1]);
- for (size_t i = 0; i < req.privileges.size(); ++i) {
- LogDebug(" Permission = " << req.privileges[i]);
- pp_permissions[i] = req.privileges[i].c_str();
- }
- pp_permissions[req.privileges.size()] = nullptr;
-
- try {
- std::vector<std::string> oldPkgPrivileges, newPkgPrivileges;
- std::string uidstr = uid ? std::to_string(static_cast<unsigned int>(uid))
- : CYNARA_ADMIN_WILDCARD;
-
- LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
- << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
-
- m_privilegeDb.BeginTransaction();
- m_privilegeDb.GetPkgPrivileges(req.pkgId, uid, oldPkgPrivileges);
- m_privilegeDb.AddApplication(req.appId, req.pkgId, uid, pkgIdIsNew);
- m_privilegeDb.UpdateAppPrivileges(req.appId, uid, req.privileges);
- m_privilegeDb.GetPkgPrivileges(req.pkgId, uid, newPkgPrivileges);
- CynaraAdmin::UpdatePackagePolicy(req.pkgId, uidstr, oldPkgPrivileges,
- newPkgPrivileges);
- m_privilegeDb.CommitTransaction();
- LogDebug("Application installation commited to database");
- } catch (const PrivilegeDb::Exception::InternalError &e) {
- m_privilegeDb.RollbackTransaction();
- LogError("Error while saving application info to database: " << e.DumpToString());
- goto error_label;
- } catch (const CynaraException::Base &e) {
- m_privilegeDb.RollbackTransaction();
- LogError("Error while setting Cynara rules for application: " << e.DumpToString());
- goto error_label;
- } catch (const std::bad_alloc &e) {
- m_privilegeDb.RollbackTransaction();
- LogError("Memory allocation while setting Cynara rules for application: " << e.what());
- goto error_label;
- }
+ ret = ServiceImpl::userDelete(uidRemoved, uid, m_isSlave);
+ Serialization::Serialize(send, ret);
+}
- // register paths
- for (const auto &appPath : req.appPaths) {
- const std::string &path = appPath.first;
- app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
- int result = setupPath(req.pkgId, path, pathType);
+void Service::processPolicyUpdate(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid, const std::string &smackLabel)
+{
+ int ret;
+ std::vector<policy_entry> policyEntries;
- if (!result) {
- LogError("setupPath() failed");
- goto error_label;
- }
- }
+ Deserialization::Deserialize(buffer, policyEntries);
- if (pkgIdIsNew) {
- LogDebug("Adding Smack rules for new pkgId " << req.pkgId);
- if (!SmackRules::installPackageRules(req.pkgId)) {
- LogError("Failed to apply package-specific smack rules");
- goto error_label;
- }
+ if (m_isSlave) {
+ ret = MasterReq::PolicyUpdate(policyEntries, uid, pid, smackLabel);
+ } else {
+ ret = ServiceImpl::policyUpdate(policyEntries, uid, pid, smackLabel);
}
-
- // success
- Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
- return true;
-
-error_label:
- Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
- return false;
+ Serialization::Serialize(send, ret);
}
-bool Service::processAppUninstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid)
+void Service::processGetConfiguredPolicy(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid, const std::string &smackLabel, bool forAdmin)
{
- // deserialize request data
- std::string appId;
- std::string pkgId;
- std::string smackLabel;
- bool appExists = true;
- bool removePkg = false;
+ int ret;
+ policy_entry filter;
+ Deserialization::Deserialize(buffer, filter);
+ std::vector<policy_entry> policyEntries;
- Deserialization::Deserialize(buffer, appId);
+ if (m_isSlave) {
+ ret = MasterReq::GetConfiguredPolicy(forAdmin, filter, uid, pid, smackLabel, policyEntries);
+ } else {
+ ret = ServiceImpl::getConfiguredPolicy(forAdmin, filter, uid, pid, smackLabel,
+ policyEntries);
+ }
- try {
- std::vector<std::string> oldPkgPrivileges, newPkgPrivileges;
+ Serialization::Serialize(send, ret);
+ Serialization::Serialize(send, static_cast<int>(policyEntries.size()));
+ for (const auto &policyEntry : policyEntries) {
+ Serialization::Serialize(send, policyEntry);
+ };
+}
- m_privilegeDb.BeginTransaction();
- if (!m_privilegeDb.GetAppPkgId(appId, pkgId)) {
- LogWarning("Application " << appId <<
- " not found in database while uninstalling");
- m_privilegeDb.RollbackTransaction();
- appExists = false;
- } else {
- if (!generateAppLabel(pkgId, smackLabel)) {
- LogError("Cannot generate Smack label for package: " << pkgId);
- goto error_label;
+void Service::processGetPolicy(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid, const std::string &smackLabel)
+{
+ int ret;
+ policy_entry filter;
+ Deserialization::Deserialize(buffer, filter);
+ std::vector<policy_entry> policyEntries;
- }
+ if (m_isSlave) {
+ ret = MasterReq::GetPolicy(filter, uid, pid, smackLabel, policyEntries);
+ } else {
+ ret = ServiceImpl::getPolicy(filter, uid, pid, smackLabel, policyEntries);
+ }
- std::string uidstr = uid ? std::to_string(static_cast<unsigned int>(uid))
- : CYNARA_ADMIN_WILDCARD;
+ Serialization::Serialize(send, ret);
+ Serialization::Serialize(send, static_cast<int>(policyEntries.size()));
+ for (const auto &policyEntry : policyEntries) {
+ Serialization::Serialize(send, policyEntry);
+ };
+}
- LogDebug("Uninstall parameters: appId: " << appId << ", pkgId: " << pkgId
- << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
+void Service::processPolicyGetDesc(MessageBuffer &send)
+{
+ int ret;
+ std::vector<std::string> descriptions;
- m_privilegeDb.GetPkgPrivileges(pkgId, uid, oldPkgPrivileges);
- m_privilegeDb.UpdateAppPrivileges(appId, uid, std::vector<std::string>());
- m_privilegeDb.RemoveApplication(appId, uid, removePkg);
- m_privilegeDb.GetPkgPrivileges(pkgId, uid, newPkgPrivileges);
- CynaraAdmin::UpdatePackagePolicy(pkgId, uidstr, oldPkgPrivileges,
- newPkgPrivileges);
- m_privilegeDb.CommitTransaction();
- LogDebug("Application uninstallation commited to database");
- }
- } catch (const PrivilegeDb::Exception::InternalError &e) {
- m_privilegeDb.RollbackTransaction();
- LogError("Error while removing application info from database: " << e.DumpToString());
- goto error_label;
- } catch (const CynaraException::Base &e) {
- m_privilegeDb.RollbackTransaction();
- LogError("Error while setting Cynara rules for application: " << e.DumpToString());
- goto error_label;
- } catch (const std::bad_alloc &e) {
- m_privilegeDb.RollbackTransaction();
- LogError("Memory allocation while setting Cynara rules for application: " << e.what());
- goto error_label;
+ if (m_isSlave) {
+ ret = MasterReq::PolicyGetDesc(descriptions);
+ } else {
+ ret = ServiceImpl::policyGetDesc(descriptions);
}
+ Serialization::Serialize(send, ret);
+ if (ret == SECURITY_MANAGER_API_SUCCESS) {
+ Serialization::Serialize(send, static_cast<int>(descriptions.size()));
- if (appExists) {
-
- if (removePkg) {
- LogDebug("Removing Smack rules for deleted pkgId " << pkgId);
- if (!SmackRules::uninstallPackageRules(pkgId)) {
- LogError("Error on uninstallation of package-specific smack rules");
- goto error_label;
- }
+ for(std::vector<std::string>::size_type i = 0; i != descriptions.size(); i++) {
+ Serialization::Serialize(send, descriptions[i]);
}
}
-
- // success
- Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
- return true;
-
-error_label:
- Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
- return false;
}
-bool Service::processGetPkgId(MessageBuffer &buffer, MessageBuffer &send)
+void Service::processPrivilegesMappings(MessageBuffer &recv, MessageBuffer &send)
{
- // deserialize request data
- std::string appId;
- std::string pkgId;
-
- Deserialization::Deserialize(buffer, appId);
- LogDebug("appId: " << appId);
+ std::vector<std::string> privileges;
+ std::string version_from, version_to;
+ Deserialization::Deserialize(recv, version_from);
+ Deserialization::Deserialize(recv, version_to);
+ Deserialization::Deserialize(recv, privileges);
- try {
- if (!m_privilegeDb.GetAppPkgId(appId, pkgId)) {
- LogWarning("Application " << appId << " not found in database");
- Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT);
- return false;
- } else {
- LogDebug("pkgId: " << pkgId);
- }
- } catch (const PrivilegeDb::Exception::InternalError &e) {
- LogError("Error while getting pkgId from database: " << e.DumpToString());
- Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
- return false;
- }
+ std::vector<std::string> mappings;
+ int ret = ServiceImpl::getPrivilegesMappings(version_from, version_to, privileges, mappings);
- // success
- Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
- Serialization::Serialize(send, pkgId);
- return true;
+ Serialization::Serialize(send, ret);
+ Serialization::Serialize(send, mappings);
}
} // namespace SecurityManager