New Security Server security_server_open_for function.
authorZbigniew Jasinski <z.jasinski@samsung.com>
Wed, 9 Oct 2013 09:56:51 +0000 (11:56 +0200)
committerBartlomiej Grzelewski <b.grzelewski@samsung.com>
Thu, 6 Feb 2014 16:13:23 +0000 (17:13 +0100)
This function allows to create, if doesn't exist, or open existing file by
Security Server on behalf of calling process in secured directory.

[Issue#]        SSDWSSP-398
[Bug/Feature]   New SS API function.
[Cause]         DataControl issues.
[Solution]      Proposal for DataControl issues.
[Verification]  Build and run new tests:
                security-server-tests-server --output=text --regexp='open_for'

Change-Id: I9eaa69d37c20a2eb8aa3f8ba9e3aa6ef6291bae7

17 files changed:
packaging/security-server.spec
src/CMakeLists.txt
src/include/security-server.h
src/server2/client/client-common.cpp
src/server2/client/client-common.h
src/server2/client/client-open-for.cpp [new file with mode: 0644]
src/server2/common/protocols.cpp
src/server2/common/protocols.h
src/server2/main/generic-socket-manager.cpp
src/server2/main/server2-main.cpp
src/server2/service/open-for-manager.cpp [new file with mode: 0644]
src/server2/service/open-for-manager.h [new file with mode: 0644]
src/server2/service/open-for.cpp [new file with mode: 0644]
src/server2/service/open-for.h [new file with mode: 0644]
systemd/CMakeLists.txt
systemd/security-server-open-for.socket [new file with mode: 0644]
systemd/security-server.service

index 80782d0..ea379d5 100644 (file)
@@ -91,6 +91,7 @@ ln -s ../security-server-cookie-get.socket %{buildroot}/usr/lib/systemd/system/s
 ln -s ../security-server-cookie-check.socket %{buildroot}/usr/lib/systemd/system/sockets.target.wants/security-server-cookie-check.socket
 ln -s ../security-server-cookie-check-tmp.socket %{buildroot}/usr/lib/systemd/system/sockets.target.wants/security-server-cookie-check-tmp.socket
 ln -s ../security-server-app-privilege-by-name.socket %{buildroot}/usr/lib/systemd/system/sockets.target.wants/security-server-app-privilege-by-name.socket
+ln -s ../security-server-open-for.socket %{buildroot}/usr/lib/systemd/system/sockets.target.wants/security-server-open-for.socket
 
 %clean
 rm -rf %{buildroot}
@@ -151,6 +152,8 @@ fi
 %attr(-,root,root) /usr/lib/systemd/system/security-server-cookie-check-tmp.socket
 %attr(-,root,root) /usr/lib/systemd/system/sockets.target.wants/security-server-app-privilege-by-name.socket
 %attr(-,root,root) /usr/lib/systemd/system/security-server-app-privilege-by-name.socket
+%attr(-,root,root) /usr/lib/systemd/system/sockets.target.wants/security-server-open-for.socket
+%attr(-,root,root) /usr/lib/systemd/system/security-server-open-for.socket
 %attr(-,root,root) /etc/security/security-server-audit.conf
 
 %{_datadir}/license/%{name}
index dc38028..4374bb9 100644 (file)
@@ -27,6 +27,8 @@ SET(SECURITY_SERVER_SOURCES
     ${SERVER2_PATH}/service/cookie-jar.cpp
     ${SERVER2_PATH}/service/privilege-by-pid.cpp
     ${SERVER2_PATH}/service/get-object-name.cpp
+    ${SERVER2_PATH}/service/open-for.cpp
+    ${SERVER2_PATH}/service/open-for-manager.cpp
     )
 
 SET_SOURCE_FILES_PROPERTIES(
@@ -75,6 +77,7 @@ SET(SECURITY_CLIENT_SOURCES
     ${SECURITY_SERVER_PATH}/server2/client/client-privilege-by-pid.cpp
     ${SECURITY_SERVER_PATH}/server2/client/client-socket-privilege.cpp
     ${SECURITY_SERVER_PATH}/server2/client/client-get-object-name.cpp
+    ${SECURITY_SERVER_PATH}/server2/client/client-open-for.cpp
     ${SECURITY_SERVER_PATH}/client/security-server-client.c
     ${SECURITY_SERVER_PATH}/communication/security-server-comm.c
     ${SECURITY_SERVER_PATH}/util/smack-check.c
index dc45c08..b6c4e32 100644 (file)
@@ -1085,6 +1085,19 @@ int security_server_app_caller_has_privilege(app_type_t app_type,
  */
 int security_server_get_gid_by_cookie(const char *cookie, gid_t *gid);
 
+/*
+ * This function allows to create, if doesn't exist, or open existing file by
+ * Security Server on behalf of calling process in secured directory.
+ *
+ * \param[in] File name to create/open
+ * \param[out] File descriptor
+ *
+ * \return SECURITY_SERVER_API_SUCCESS on success or error code on fail
+ *
+ * Access to this function requires SMACK rule: "<app_label> security-server::api-open-for w"
+ */
+int security_server_open_for(const char *filename, int *fd);
+
 
 #ifdef __cplusplus
 }
index 9534ad3..7392d4b 100644 (file)
@@ -215,6 +215,52 @@ int sendToServer(char const * const interface, const RawBuffer &send, MessageBuf
     return SECURITY_SERVER_API_SUCCESS;
 }
 
+int sendToServerAncData(char const * const interface, const RawBuffer &send, struct msghdr &hdr) {
+    int ret;
+    SockRAII sock;
+    ssize_t done = 0;
+
+    if (SECURITY_SERVER_API_SUCCESS != (ret = sock.Connect(interface))) {
+        LogError("Error in SockRAII");
+        return ret;
+    }
+
+    while ((send.size() - done) > 0) {
+        if (0 >= waitForSocket(sock.Get(), POLLOUT, POLL_TIMEOUT)) {
+            LogError("Error in poll(POLLOUT)");
+            return SECURITY_SERVER_API_ERROR_SOCKET;
+        }
+        ssize_t temp = TEMP_FAILURE_RETRY(write(sock.Get(), &send[done], send.size() - done));
+        if (-1 == temp) {
+            int err = errno;
+            LogError("Error in write: " << strerror(err));
+            return SECURITY_SERVER_API_ERROR_SOCKET;
+        }
+        done += temp;
+    }
+
+    if (0 >= waitForSocket(sock.Get(), POLLIN, POLL_TIMEOUT)) {
+        LogError("Error in poll(POLLIN)");
+        return SECURITY_SERVER_API_ERROR_SOCKET;
+    }
+
+    ssize_t temp = TEMP_FAILURE_RETRY(recvmsg(sock.Get(), &hdr, MSG_CMSG_CLOEXEC));
+
+    if (temp < 0) {
+        int err = errno;
+        LogError("Error in recvmsg(): " << strerror(err) << " errno: " << err);
+        return SECURITY_SERVER_API_ERROR_SOCKET;
+    }
+
+    if (0 == temp) {
+        LogError("Read return 0/Connection closed by server(?)");
+        return SECURITY_SERVER_API_ERROR_SOCKET;
+    }
+
+    return SECURITY_SERVER_API_SUCCESS;
+}
+
+
 } // namespace SecurityServer
 
 static void init_lib(void) __attribute__ ((constructor));
index fd8e07d..5a892bf 100644 (file)
 
 #include <message-buffer.h>
 
+extern "C" {
+    struct msghdr;
+}
+
 namespace SecurityServer {
 
 typedef std::vector<unsigned char> RawBuffer;
 
 int sendToServer(char const * const interface, const RawBuffer &send, MessageBuffer &recv);
 
+/*
+ * sendToServerAncData is special case when we want to receive file descriptor
+ * passed by Security Server on behalf of calling process. We can't get it with
+ * MessageBuffer.
+ *
+ * This function should be called _ONLY_ in this particular case.
+ *
+ */
+int sendToServerAncData(char const * const interface, const RawBuffer &send, struct msghdr &hdr);
+
 } // namespace SecuritySever
 
 #endif // _SECURITY_SERVER_CLIENT_
diff --git a/src/server2/client/client-open-for.cpp b/src/server2/client/client-open-for.cpp
new file mode 100644 (file)
index 0000000..d67b2f1
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ *  Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Bumjin Im <bj.im@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/*
+ * @file        client-open-for-cookie.cpp
+ * @author      Zbigniew Jasinski (z.jasinski@samsung.com)
+ * @version     1.0
+ * @brief       This file contains implementation of security-server API
+ *              for file opening.
+ */
+
+#include <cstring>
+
+#include <dpl/log/log.h>
+#include <dpl/exception.h>
+
+#include <message-buffer.h>
+#include <client-common.h>
+#include <protocols.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <security-server.h>
+#include <security-server-common.h>
+
+SECURITY_SERVER_API
+int security_server_open_for(const char *filename, int *fd)
+{
+   using namespace SecurityServer;
+    try {
+        if (NULL == filename || std::string(filename).empty()) {
+            LogError("Error input param.");
+            return SECURITY_SERVER_ERROR_INPUT_PARAM;
+        }
+
+        MessageBuffer send;
+
+        Serialization::Serialize(send, std::string(filename));
+
+        struct msghdr hdr;
+        struct iovec iov;
+        struct cmsghdr *cmsg = NULL;
+        int retcode = -1;
+        int result = -1;
+        unsigned char cmsgbuf[CMSG_SPACE(sizeof(int))];
+
+        memset(&hdr, 0, sizeof(struct msghdr));
+        memset(cmsgbuf, 0, CMSG_SPACE(sizeof(int)));
+
+        iov.iov_base = &retcode;
+        iov.iov_len = sizeof(retcode);
+        hdr.msg_iov = &iov;
+        hdr.msg_iovlen = 1;
+
+        hdr.msg_control = cmsgbuf;
+        hdr.msg_controllen = CMSG_SPACE(sizeof(int));
+
+        result = sendToServerAncData(SERVICE_SOCKET_OPEN_FOR, send.Pop(), hdr);
+        if (result != SECURITY_SERVER_API_SUCCESS) {
+            *fd = -1;
+            return result;
+        }
+
+        if ((hdr.msg_flags & MSG_CTRUNC) == MSG_CTRUNC) {
+            LogError("Not enough space for ancillary element array.");
+            *fd = -1;
+            return SECURITY_SERVER_API_ERROR_BUFFER_TOO_SMALL;
+        }
+
+        for(cmsg = CMSG_FIRSTHDR(&hdr); cmsg != NULL; cmsg = CMSG_NXTHDR(&hdr, cmsg)) {
+            if((SOL_SOCKET == cmsg->cmsg_level) && (SCM_RIGHTS == cmsg->cmsg_type)) {
+                memmove(fd, CMSG_DATA(cmsg), sizeof(int));
+            }
+        }
+
+        return retcode;
+    } catch (MessageBuffer::Exception::Base &e) {
+        LogDebug("SecurityServer::MessageBuffer::Exception " << e.DumpToString());
+    } catch (std::exception &e) {
+        LogDebug("STD exception " << e.what());
+    } catch (...) {
+        LogDebug("Unknown exception occured");
+    }
+    return SECURITY_SERVER_API_ERROR_UNKNOWN;
+}
index d10ce97..c3a4c70 100644 (file)
@@ -49,6 +49,8 @@ char const * const SERVICE_SOCKET_COOKIE_CHECK =
 //after security-server-api-cookie-check.sock will be protected by smack and has proper label
 char const * const SERVICE_SOCKET_COOKIE_CHECK_TMP =
     "/tmp/.security-server-api-cookie-check-tmp.sock";
+char const * const SERVICE_SOCKET_OPEN_FOR =
+    "/tmp/.security-server-api-open-for.sock";
 
 const size_t COOKIE_SIZE = 20;
 
index f02748c..73a9490 100644 (file)
@@ -39,6 +39,7 @@ extern char const * const SERVICE_SOCKET_APP_PRIVILEGE_BY_NAME;
 extern char const * const SERVICE_SOCKET_COOKIE_GET;
 extern char const * const SERVICE_SOCKET_COOKIE_CHECK;
 extern char const * const SERVICE_SOCKET_COOKIE_CHECK_TMP;
+extern char const * const SERVICE_SOCKET_OPEN_FOR;
 
 enum class AppPermissionsAction { ENABLE, DISABLE };
 
index b2db6a1..5bf0695 100644 (file)
@@ -43,15 +43,18 @@ public:
 
         m_hdr.msg_iov = &m_iov;
         m_hdr.msg_iovlen = 1;
-        m_hdr.msg_control = m_cmsgbuf;
-        m_hdr.msg_controllen = CMSG_SPACE(sizeof(int));
 
-        m_cmsg = CMSG_FIRSTHDR(&m_hdr);
-        m_cmsg->cmsg_len = CMSG_LEN(sizeof(int));
-        m_cmsg->cmsg_level = SOL_SOCKET;
-        m_cmsg->cmsg_type = SCM_RIGHTS;
+        if (fileDesc != -1) {
+            m_hdr.msg_control = m_cmsgbuf;
+            m_hdr.msg_controllen = CMSG_SPACE(sizeof(int));
 
-        memmove(CMSG_DATA(m_cmsg), &m_fileDesc, sizeof(int));
+            m_cmsg = CMSG_FIRSTHDR(&m_hdr);
+            m_cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+            m_cmsg->cmsg_level = SOL_SOCKET;
+            m_cmsg->cmsg_type = SCM_RIGHTS;
+
+            memmove(CMSG_DATA(m_cmsg), &m_fileDesc, sizeof(int));
+        }
     }
 
     msghdr* data() { return &m_hdr; }
index b3512b1..0a386c2 100644 (file)
@@ -37,6 +37,7 @@
 #include <get-object-name.h>
 #include <app-permissions.h>
 #include <cookie.h>
+#include <open-for.h>
 #include <echo.h>
 
 IMPLEMENT_SAFE_SINGLETON(SecurityServer::Log::LogSystem);
@@ -53,6 +54,11 @@ int server2(void) {
 //        echoService->Create();
 //        manager.RegisterSocketService(echoService);
 
+
+        SecurityServer::OpenForService *openForService = new SecurityServer::OpenForService;
+        openForService->Create();
+        manager.RegisterSocketService(openForService);
+
         SecurityServer::CookieService *cookieService = new SecurityServer::CookieService;
         cookieService->Create();
         manager.RegisterSocketService(cookieService);
diff --git a/src/server2/service/open-for-manager.cpp b/src/server2/service/open-for-manager.cpp
new file mode 100644 (file)
index 0000000..63949e4
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ *  Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Bumjin Im <bj.im@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/*
+ * @file        open-for-manager.cpp
+ * @author      Zbigniew Jasinski (z.jasinski@samsung.com)
+ * @version     1.0
+ * @brief       Implementation of open-for management functions
+ */
+
+#include "open-for-manager.h"
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <fcntl.h>
+
+#include <sys/smack.h>
+#include <smack-check.h>
+
+#include <dpl/log/log.h>
+#include <dpl/serialization.h>
+
+#include <security-server.h>
+#include <security-server-util.h>
+#include <security-server-comm.h>
+
+const std::string DATA_DIR = "/var/run/security-server";
+const std::string PROHIBITED_STR = "..";
+const std::string ALLOWED_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ \
+                                   abcdefghijklmnopqrstuvwxyz \
+                                   0123456789._-";
+
+namespace SecurityServer
+{
+    // SockCred implementations
+    SockCred::SockCred()
+    {
+        m_len = sizeof(struct ucred);
+        memset(&m_cr, 0, m_len);
+    }
+
+    bool SockCred::getCred(int socket)
+    {
+        if (getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &m_cr, &m_len)) {
+            int err = errno;
+            LogError("Unable to get client credentials: " << strerror(err));
+            return true;
+        }
+
+        if (smack_check()) {
+            char label[SMACK_LABEL_LEN + 1];
+            if (PC_OPERATION_SUCCESS != get_smack_label_from_process(m_cr.pid, label)) {
+                LogError("Unable to get smack label of process.");
+                return true;
+            }
+            m_sockSmackLabel = label;
+        } else
+            m_sockSmackLabel = "";
+
+        return false;
+    }
+
+    std::string SockCred::getLabel() const
+    {
+        return m_sockSmackLabel;
+    }
+
+    // SharedFile implementations
+    SharedFile::SharedFile()
+    {
+        if (!dirExist(DATA_DIR.c_str()))
+            mkdir(DATA_DIR.c_str(), 0700);
+        else {
+            deleteDir(DATA_DIR.c_str());
+            mkdir(DATA_DIR.c_str(), 0700);
+        }
+    }
+
+    bool SharedFile::fileExist(const std::string &filename) const
+    {
+        std::string filepath = DATA_DIR + "/" + filename;
+        struct stat buf;
+
+        return ((lstat(filepath.c_str(), &buf) == 0) &&
+                (((buf.st_mode) & S_IFMT) != S_IFLNK));
+    }
+
+    bool SharedFile::dirExist(const std::string &dirpath) const
+    {
+        struct stat buf;
+
+        return ((lstat(dirpath.c_str(), &buf) == 0) &&
+                (((buf.st_mode) & S_IFMT) == S_IFDIR));
+    }
+
+    bool SharedFile::deleteDir(const std::string &dirpath) const
+    {
+        DIR *dirp;
+        struct dirent *dp;
+        char path[PATH_MAX];
+
+        if ((dirp = opendir(dirpath.c_str())) == NULL) {
+            int err = errno;
+            LogError("Cannot open data directory. " << strerror(err));
+            return true;
+        }
+
+        while ((dp = readdir(dirp)) != NULL) {
+            if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) {
+                snprintf(path, (size_t) PATH_MAX, "%s/%s", dirpath.c_str(), dp->d_name);
+                if (dp->d_type == DT_DIR) {
+                    deleteDir(path);
+                } else {
+                    unlink(path);
+                }
+            }
+        }
+        closedir(dirp);
+        rmdir(dirpath.c_str());
+
+        return false;
+    }
+
+    bool SharedFile::createFile(const std::string &filename)
+    {
+        int fd = -1;
+        std::string filepath = DATA_DIR + "/" + filename;
+
+        fd = TEMP_FAILURE_RETRY(open(filepath.c_str(), O_CREAT | O_WRONLY | O_EXCL, 0600));
+        int err = errno;
+        if (-1 == fd) {
+            LogError("Cannot create file. Error in open(): " << strerror(err));
+            return true;
+        }
+
+        TEMP_FAILURE_RETRY(close(fd));
+
+        return false;
+    }
+
+    int SharedFile::openFile(const std::string &filename)
+    {
+        int fd = -1;
+        std::string filepath = DATA_DIR + "/" + filename;
+
+        fd = TEMP_FAILURE_RETRY(open(filepath.c_str(), O_CREAT | O_RDWR, 0600));
+        int err = errno;
+        if (-1 == fd) {
+            LogError("Cannot open file. Error in open(): " << strerror(err));
+            return SECURITY_SERVER_API_ERROR_SERVER_ERROR;
+        }
+
+        return fd;
+    }
+
+    bool SharedFile::setFileLabel(const std::string &filename, const std::string &label) const
+    {
+        std::string filepath = DATA_DIR + "/" + filename;
+
+        if (smack_setlabel(filepath.c_str(), label.c_str(), SMACK_LABEL_ACCESS)) {
+            LogError("Cannot set SMACK label on file.");
+            return true;
+        }
+
+        return false;
+    }
+
+    bool SharedFile::getFileLabel(const std::string &filename)
+    {
+        std::string filepath = DATA_DIR + "/" + filename;
+
+        if (smack_check()) {
+            char *label = NULL;
+            if (PC_OPERATION_SUCCESS != smack_getlabel(filepath.c_str(), &label, SMACK_LABEL_ACCESS)) {
+                LogError("Unable to get smack label of process.");
+                return true;
+            }
+            m_fileSmackLabel = label;
+            free(label);
+        } else
+            m_fileSmackLabel.clear();
+
+        return false;
+    }
+
+    bool SharedFile::checkFileNameSyntax(const std::string &filename) const
+    {
+        std::size_t found = filename.find_first_not_of(ALLOWED_CHARS);
+
+        if (found != std::string::npos || '-' == filename[0] ||
+            '.' == filename[0]) {
+            LogError("Illegal character in filename.");
+            return true;
+        }
+
+        found = filename.find(PROHIBITED_STR);
+        if (found != std::string::npos) {
+            LogError("Illegal string in filename.");
+            return true;
+        }
+
+        return false;
+    }
+
+    int SharedFile::getFD(const std::string &filename, int socket, int &fd)
+    {
+        if (checkFileNameSyntax(filename))
+            return SECURITY_SERVER_API_ERROR_INPUT_PARAM;
+
+        if (m_sockCred.getCred(socket))
+            return SECURITY_SERVER_API_ERROR_AUTHENTICATION_FAILED;
+
+        if (!fileExist(filename)) {
+            LogSecureDebug("File: " << filename.c_str() << " does not exist.");
+
+            if (createFile(filename))
+                return SECURITY_SERVER_API_ERROR_SERVER_ERROR;
+        }
+
+        if (getFileLabel(filename))
+            return SECURITY_SERVER_API_ERROR_SERVER_ERROR;
+
+        if (setFileLabel(filename, m_sockCred.getLabel()))
+            return SECURITY_SERVER_API_ERROR_SERVER_ERROR;
+
+        fd = openFile(filename);
+
+        if (setFileLabel(filename, m_fileSmackLabel))
+            return SECURITY_SERVER_API_ERROR_SERVER_ERROR;
+
+        return SECURITY_SERVER_API_SUCCESS;
+    }
+
+} //namespace SecurityServer
diff --git a/src/server2/service/open-for-manager.h b/src/server2/service/open-for-manager.h
new file mode 100644 (file)
index 0000000..83cf0da
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ *  Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Bumjin Im <bj.im@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/*
+ * @file        open-for-manager.h
+ * @author      Zbigniew Jasinski (z.jasinski@samsung.com)
+ * @version     1.0
+ * @brief       Implementation of open-for management functions
+ */
+
+#ifndef _OPEN_FOR_MANAGER_H_
+#define _OPEN_FOR_MANAGER_H_
+
+#include "security-server-common.h"
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <string>
+
+namespace SecurityServer
+{
+    // classess
+    class SockCred
+    {
+    public:
+        SockCred();
+        bool getCred(int socket);
+        std::string getLabel(void) const;
+
+    private:
+        struct ucred m_cr;
+        unsigned m_len;
+        std::string m_sockSmackLabel;
+    };
+
+    class SharedFile
+    {
+    public:
+        SharedFile();
+        int getFD(const std::string &filename, int socket, int &fd);
+
+    private:
+        bool fileExist(const std::string &filename) const;
+        bool dirExist(const std::string &dirpath) const;
+        bool deleteDir(const std::string &dirpath) const;
+        int openFile(const std::string &filename);
+        bool createFile(const std::string &filename);
+        bool setFileLabel(const std::string &filename, const std::string &label) const;
+        bool getFileLabel(const std::string &filename);
+        bool checkFileNameSyntax(const std::string &filename) const;
+
+        uid_t m_fileUID;
+        gid_t m_fileGID;
+        mode_t m_fileMode;
+        std::string m_fileSmackLabel;
+
+        SockCred m_sockCred;
+    };
+}
+
+#endif // _OPEN_FOR_MANAGER_H_
diff --git a/src/server2/service/open-for.cpp b/src/server2/service/open-for.cpp
new file mode 100644 (file)
index 0000000..227744c
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ *  Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Bumjin Im <bj.im@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/*
+ * @file        open-for.cpp
+ * @author      Zbigniew Jasinski (z.jasinski@samsung.com)
+ * @version     1.0
+ * @brief       Implementation of open-for service
+ */
+
+#include <dpl/log/log.h>
+#include <dpl/serialization.h>
+
+#include <protocols.h>
+#include <open-for.h>
+#include <unistd.h>
+
+#include <security-server.h>
+#include <security-server-util.h>
+#include <security-server-comm.h>
+
+namespace {
+// Service may open more than one socket.
+// These ID's will be assigned to sockets
+// and will be used only by service.
+// When new connection arrives, AcceptEvent
+// will be generated with proper ID to inform
+// service about input socket.
+//
+// Please note: SocketManaged does not use it and
+// does not check it in any way.
+//
+// If your service require only one socket
+// (uses only one socket labeled with smack)
+// you may ignore this ID (just pass 0)
+const int SERVICE_SOCKET_ID = 0;
+
+} // namespace anonymous
+
+namespace SecurityServer {
+
+GenericSocketService::ServiceDescriptionVector OpenForService::GetServiceDescription() {
+    return ServiceDescriptionVector
+        {{SERVICE_SOCKET_OPEN_FOR, "security-server::api-open-for", SERVICE_SOCKET_ID, true}};
+}
+
+void OpenForService::accept(const AcceptEvent &event)
+{
+    LogDebug("Accept event. ConnectionID.sock: " << event.connectionID.sock
+        << " ConnectionID.counter: " << event.connectionID.counter
+        << " ServiceID: " << event.interfaceID);
+}
+
+void OpenForService::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 OpenForService::process(const ReadEvent &event)
+{
+    LogDebug("Read event for counter: " << event.connectionID.counter);
+    auto &info = m_socketInfoMap[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.descriptorsVector));
+}
+
+void OpenForService::close(const CloseEvent &event)
+{
+    LogDebug("CloseEvent. ConnectionID: " << event.connectionID.sock);
+    auto &descVector = m_socketInfoMap[event.connectionID.counter].descriptorsVector;
+
+    for (auto iter = descVector.begin(); iter != descVector.end(); ++iter)
+        TEMP_FAILURE_RETRY(::close(*iter));
+
+    m_socketInfoMap.erase(event.connectionID.counter);
+}
+
+bool OpenForService::processOne(const ConnectionID &conn, MessageBuffer &buffer, std::vector<int> &descVector)
+{
+    LogDebug("Iteration begin");
+
+    std::string filename;
+    MessageBuffer sendBuffer;
+
+    int retCode = SECURITY_SERVER_API_ERROR_SERVER_ERROR;
+    int fd = -1;
+
+    if (!buffer.Ready())
+        return false;
+
+    Try {
+        Deserialization::Deserialize(buffer, filename);
+    } Catch (MessageBuffer::Exception::Base) {
+        LogError("Broken protocol. Closing socket.");
+        m_serviceManager->Close(conn);
+        return false;
+    }
+
+    retCode = m_sharedFile.getFD(filename, conn.sock, fd);
+    if (fd != -1)
+        descVector.push_back(fd);
+    SendMsgData sendMsgData(retCode, fd);
+
+    m_serviceManager->Write(conn, sendMsgData);
+
+    return true;
+}
+
+} // namespace SecurityServer
diff --git a/src/server2/service/open-for.h b/src/server2/service/open-for.h
new file mode 100644 (file)
index 0000000..e56b05f
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *  Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Bumjin Im <bj.im@samsung.com>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+/*
+ * @file        open-for.h
+ * @author      Zigniew Jasinski (z.jasinski@samsung.com)
+ * @version     1.0
+ * @brief       Implementation of open-for service
+ */
+
+#ifndef _SECURITY_SERVER_OPEN_FOR_
+#define _SECURITY_SERVER_OPEN_FOR_
+
+#include <service-thread.h>
+#include <generic-socket-manager.h>
+#include <message-buffer.h>
+
+#include "security-server-common.h"
+#include "open-for-manager.h"
+
+namespace SecurityServer
+{
+    typedef std::vector<int> DescriptorVector;
+
+    struct SocketInfo {
+        DescriptorVector descriptorsVector;
+        MessageBuffer buffer;
+    };
+
+    typedef std::map<int, SocketInfo> SocketInfoMap;
+
+    class OpenForService
+      : public SecurityServer::GenericSocketService
+      , public SecurityServer::ServiceThread<OpenForService>
+    {
+    public:
+        //service functions
+        ServiceDescriptionVector GetServiceDescription();
+
+        DECLARE_THREAD_EVENT(AcceptEvent, accept)
+        DECLARE_THREAD_EVENT(WriteEvent, write)
+        DECLARE_THREAD_EVENT(ReadEvent, process)
+        DECLARE_THREAD_EVENT(CloseEvent, close)
+
+        void accept(const AcceptEvent &event);
+        void write(const WriteEvent &event);
+        void process(const ReadEvent &event);
+        void close(const CloseEvent &event);
+
+    private:
+        //internal service functions
+        bool processOne(const ConnectionID &conn, MessageBuffer &buffer, DescriptorVector &descVector);
+
+        SocketInfoMap m_socketInfoMap;
+        SharedFile m_sharedFile;
+    };
+} // namespace SecurityServer
+
+#endif // _SECURITY_SERVER_OPEN_FOR_
index 5b77861..204e635 100644 (file)
@@ -11,6 +11,7 @@ INSTALL(FILES
     ${CMAKE_SOURCE_DIR}/systemd/security-server-cookie-check.socket
     ${CMAKE_SOURCE_DIR}/systemd/security-server-app-privilege-by-name.socket
     ${CMAKE_SOURCE_DIR}/systemd/security-server-cookie-check-tmp.socket
+    ${CMAKE_SOURCE_DIR}/systemd/security-server-open-for.socket
     DESTINATION
     /usr/lib/systemd/system
 )
diff --git a/systemd/security-server-open-for.socket b/systemd/security-server-open-for.socket
new file mode 100644 (file)
index 0000000..9e2c07b
--- /dev/null
@@ -0,0 +1,10 @@
+[Socket]
+ListenStream=/tmp/.security-server-api-open-for.sock
+SocketMode=0777
+SmackLabelIPIn=security-server::api-open-for
+SmackLabelIPOut=@
+
+Service=security-server.service
+
+[Install]
+WantedBy=sockets.target
index 77f3f24..f527aa3 100644 (file)
@@ -15,6 +15,7 @@ Sockets=security-server-app-privilege-by-name.socket
 Sockets=security-server-cookie-get.socket
 Sockets=security-server-cookie-check.socket
 Sockets=security-server-cookie-check-tmp.socket
+Sockets=security-server-open-for.socket
 
 [Install]
 WantedBy=multi-user.target