*/
/*
* @file client-security-manager.cpp
- * @author Pawel Polawski (p.polawski@samsung.com)
+ * @author Pawel Polawski <p.polawski@samsung.com>
+ * @author Rafal Krypa <r.krypa@samsung.com>
* @version 1.0
* @brief This file contain client side implementation of security-manager API
*/
#include <cstdio>
#include <utility>
+#include <unistd.h>
+#include <grp.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/xattr.h>
#include <sys/smack.h>
+#include <sys/capability.h>
#include <dpl/log/log.h>
#include <dpl/exception.h>
using namespace SecurityManager;
MessageBuffer send, recv;
- LogDebug("app_install() called");
-
return try_catch([&] {
//checking parameters
if (!p_req)
Serialization::Serialize(send, p_req->appPaths);
//send buffer to server
- int retval = sendToServer(SERVICE_SOCKET_INSTALLER, send.Pop(), recv);
+ int retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv);
if (retval != SECURITY_MANAGER_API_SUCCESS) {
- LogDebug("Error in sendToServer. Error code: " << retval);
+ LogError("Error in sendToServer. Error code: " << retval);
return SECURITY_MANAGER_ERROR_UNKNOWN;
}
//receive response from server
Deserialization::Deserialize(recv, retval);
- if (retval != SECURITY_MANAGER_API_SUCCESS)
- return SECURITY_MANAGER_ERROR_UNKNOWN;
+ switch(retval) {
+ case SECURITY_MANAGER_API_SUCCESS:
+ return SECURITY_MANAGER_SUCCESS;
+ case SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED:
+ return SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED;
+ default:
+ return SECURITY_MANAGER_ERROR_UNKNOWN;
+ }
- return SECURITY_MANAGER_SUCCESS;;
});
}
using namespace SecurityManager;
MessageBuffer send, recv;
- LogDebug("app_uninstall() called");
-
return try_catch([&] {
//checking parameters
if (!p_req)
Serialization::Serialize(send, p_req->appId);
//send buffer to server
- int retval = sendToServer(SERVICE_SOCKET_INSTALLER, send.Pop(), recv);
+ int retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv);
if (retval != SECURITY_MANAGER_API_SUCCESS) {
- LogDebug("Error in sendToServer. Error code: " << retval);
+ LogError("Error in sendToServer. Error code: " << retval);
return SECURITY_MANAGER_ERROR_UNKNOWN;
}
Serialization::Serialize(send, std::string(app_id));
//send buffer to server
- int retval = sendToServer(SERVICE_SOCKET_INSTALLER, send.Pop(), recv);
+ int retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv);
if (retval != SECURITY_MANAGER_API_SUCCESS) {
LogDebug("Error in sendToServer. Error code: " << retval);
return SECURITY_MANAGER_ERROR_UNKNOWN;
});
}
-SECURITY_MANAGER_API
-int security_manager_set_process_label_from_binary(const char *path)
+static bool setup_smack(const char *label)
{
- char *smack_label;
- int ret;
+ int labelSize = strlen(label);
- LogDebug("security_manager_set_process_label_from_binary() called");
+ // Set Smack label for open socket file descriptors
- if (smack_smackfs_path() == NULL)
- return SECURITY_MANAGER_SUCCESS;
-
- if (path == NULL) {
- LogError("security_manager_set_process_label_from_binary: path is NULL");
- return SECURITY_MANAGER_ERROR_INPUT_PARAM;
+ std::unique_ptr<DIR, std::function<int(DIR*)>> dir(
+ opendir("/proc/self/fd"), closedir);
+ if (!dir.get()) {
+ LogError("Unable to read list of open file descriptors: " <<
+ strerror(errno));
+ return SECURITY_MANAGER_ERROR_UNKNOWN;
}
- ret = SecurityManager::getSmackLabelFromBinary(&smack_label, path);
- if (ret == SECURITY_MANAGER_SUCCESS && smack_label != NULL) {
- if (smack_set_label_for_self(smack_label) != 0) {
- ret = SECURITY_MANAGER_ERROR_UNKNOWN;
- LogError("Failed to set smack label " << smack_label << " for current process");
+ do {
+ errno = 0;
+ struct dirent *dirEntry = readdir(dir.get());
+ if (dirEntry == nullptr) {
+ if (errno == 0) // NULL return value also signals end of directory
+ break;
+
+ LogError("Unable to read list of open file descriptors: " <<
+ strerror(errno));
+ return SECURITY_MANAGER_ERROR_UNKNOWN;
}
- free(smack_label);
- }
- return ret;
+ // Entries with numerical names specify file descriptors, ignore the rest
+ if (!isdigit(dirEntry->d_name[0]))
+ continue;
+
+ struct stat statBuf;
+ int fd = atoi(dirEntry->d_name);
+ int ret = fstat(fd, &statBuf);
+ if (ret != 0) {
+ LogWarning("fstat failed on file descriptor " << fd << ": " <<
+ strerror(errno));
+ continue;
+ }
+ if (S_ISSOCK(statBuf.st_mode)) {
+ ret = fsetxattr(fd, XATTR_NAME_SMACKIPIN, label, labelSize, 0);
+ if (ret != 0) {
+ LogError("Setting Smack label failed on file descriptor " <<
+ fd << ": " << strerror(errno));
+ return SECURITY_MANAGER_ERROR_UNKNOWN;
+ }
+
+ ret = fsetxattr(fd, XATTR_NAME_SMACKIPOUT, label, labelSize, 0);
+ if (ret != 0) {
+ LogError("Setting Smack label failed on file descriptor " <<
+ fd << ": " << strerror(errno));
+ return SECURITY_MANAGER_ERROR_UNKNOWN;
+ }
+ }
+ } while (true);
+
+ // Set Smack label of current process
+ smack_set_label_for_self(label);
+
+ return SECURITY_MANAGER_SUCCESS;
}
SECURITY_MANAGER_API
}
if (SecurityManager::generateAppLabel(std::string(pkg_id), appLabel)) {
- if (smack_set_label_for_self(appLabel.c_str()) != 0) {
+ ret = setup_smack(appLabel.c_str());
+ if (ret != SECURITY_MANAGER_SUCCESS) {
LogError("Failed to set smack label " << appLabel << " for current process");
- ret = SECURITY_MANAGER_ERROR_UNKNOWN;
}
}
else {
return ret;
}
+SECURITY_MANAGER_API
+int security_manager_set_process_groups_from_appid(const char *app_id)
+{
+ using namespace SecurityManager;
+ MessageBuffer send, recv;
+ int ret;
+
+ LogDebug("security_manager_set_process_groups_from_appid() called");
+
+ return try_catch([&] {
+ //checking parameters
+
+ if (app_id == nullptr) {
+ LogError("app_id is NULL");
+ return SECURITY_MANAGER_ERROR_INPUT_PARAM;
+ }
+
+ //put data into buffer
+ Serialization::Serialize(send, static_cast<int>(SecurityModuleCall::APP_GET_GROUPS));
+ Serialization::Serialize(send, std::string(app_id));
+
+ //send buffer to server
+ int retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv);
+ if (retval != SECURITY_MANAGER_API_SUCCESS) {
+ LogDebug("Error in sendToServer. Error code: " << retval);
+ return SECURITY_MANAGER_ERROR_UNKNOWN;
+ }
+
+ //receive response from server
+ Deserialization::Deserialize(recv, retval);
+ if (retval != SECURITY_MANAGER_API_SUCCESS)
+ return SECURITY_MANAGER_ERROR_UNKNOWN;
+
+ //How many new groups?
+ int newGroupsCnt;
+ Deserialization::Deserialize(recv, newGroupsCnt);
+
+ //And how many groups do we belong to already?
+ int oldGroupsCnt;
+ ret = getgroups(0, nullptr);
+ if (ret == -1) {
+ LogError("Unable to get list of current supplementary groups: " <<
+ strerror(errno));
+ return SECURITY_MANAGER_ERROR_UNKNOWN;
+ }
+ oldGroupsCnt = ret;
+
+ //Allocate an array for both old and new groups gids
+ std::unique_ptr<gid_t[]> groups(new gid_t[oldGroupsCnt + newGroupsCnt]);
+ if (!groups.get()) {
+ LogError("Memory allocation failed.");
+ return SECURITY_MANAGER_ERROR_MEMORY;
+ }
+
+ //Get the old groups from process
+ ret = getgroups(oldGroupsCnt, groups.get());
+ if (ret == -1) {
+ LogError("Unable to get list of current supplementary groups: " <<
+ strerror(errno));
+ return SECURITY_MANAGER_ERROR_UNKNOWN;
+ }
+
+ //Get the new groups from server response
+ for (int i = 0; i < newGroupsCnt; ++i) {
+ gid_t gid;
+ Deserialization::Deserialize(recv, gid);
+ groups.get()[oldGroupsCnt + i] = gid;
+ LogDebug("Adding process to group " << gid);
+ }
+
+ //Apply the modified groups list
+ ret = setgroups(oldGroupsCnt + newGroupsCnt, groups.get());
+ if (ret == -1) {
+ LogError("Unable to get list of current supplementary groups: " <<
+ strerror(errno));
+ return SECURITY_MANAGER_ERROR_UNKNOWN;
+ }
+
+ return SECURITY_MANAGER_SUCCESS;
+ });
+}
+
+SECURITY_MANAGER_API
+int security_manager_drop_process_privileges(void)
+{
+ LogDebug("security_manager_drop_process_privileges() called");
+
+ int ret;
+ cap_t cap = cap_init();
+ if (!cap) {
+ LogError("Unable to allocate capability object");
+ return SECURITY_MANAGER_ERROR_MEMORY;
+ }
+ ret = cap_clear(cap);
+ if (ret) {
+ LogError("Unable to initialize capability object");
+ cap_free(cap);
+ return SECURITY_MANAGER_ERROR_UNKNOWN;
+ }
+
+ ret = cap_set_proc(cap);
+ if (ret) {
+ LogError("Unable to drop process capabilities");
+ cap_free(cap);
+ return SECURITY_MANAGER_ERROR_UNKNOWN;
+ }
+
+ cap_free(cap);
+ return SECURITY_MANAGER_SUCCESS;
+}
+
+SECURITY_MANAGER_API
+int security_manager_prepare_app(const char *app_id)
+{
+ LogDebug("security_manager_prepare_app() called");
+ int ret;
+
+ ret = security_manager_set_process_label_from_appid(app_id);
+ if (ret != SECURITY_MANAGER_SUCCESS)
+ return ret;
+
+ ret = security_manager_set_process_groups_from_appid(app_id);
+ if (ret != SECURITY_MANAGER_SUCCESS)
+ return ret;
+
+ ret = security_manager_drop_process_privileges();
+ return ret;
+}