Security-server new API for privilege checking
authorMarcin Lis <m.lis@samsung.com>
Fri, 18 Oct 2013 16:13:43 +0000 (18:13 +0200)
committerBartlomiej Grzelewski <b.grzelewski@samsung.com>
Thu, 6 Feb 2014 16:13:23 +0000 (17:13 +0100)
[Issue#]       SSDWSSP-527
[Feature]      Introduce two new SS API functions.
[Cause]        New API will improve the performance while checking
               app privileges.
[Solution]     Two new functions in client API enable to check whether a given
               app or caller app has enabled permission specified by name.
               Modified service: app-permissions.
               Two new sockets added to systemd and affected service.
[Verification] Build, install & run tests.
               Verify together with new libprivilege database.

Change-Id: If8d4efd30bbf22f82cd1442256ccbe7efb68a8aa

packaging/security-server.manifest
packaging/security-server.spec
src/include/security-server.h
src/server2/client/client-app-permissions.cpp
src/server2/common/protocols.cpp
src/server2/common/protocols.h
src/server2/service/app-permissions.cpp
src/server2/service/app-permissions.h
systemd/CMakeLists.txt
systemd/security-server-app-privilege-by-name.socket [new file with mode: 0644]
systemd/security-server.service

index c7d43d1..71e677f 100644 (file)
@@ -5,6 +5,7 @@
                        <label name="security-server::daemon" />
                        <label name="security-server::db" />
                        <label name="security-server::api-app-permissions" />
+                       <label name="security-server::api-app-privilege-by-name" />
                        <label name="security-server::api-cookie-check" />
                        <label name="security-server::api-cookie-get" />
                        <label name="security-server::api-data-share" />
index a9b98b4..80782d0 100644 (file)
@@ -90,6 +90,7 @@ ln -s ../security-server-app-permissions.socket %{buildroot}/usr/lib/systemd/sys
 ln -s ../security-server-cookie-get.socket %{buildroot}/usr/lib/systemd/system/sockets.target.wants/security-server-cookie-get.socket
 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
 
 %clean
 rm -rf %{buildroot}
@@ -148,6 +149,8 @@ fi
 %attr(-,root,root) /usr/lib/systemd/system/security-server-cookie-check.socket
 %attr(-,root,root) /usr/lib/systemd/system/sockets.target.wants/security-server-cookie-check-tmp.socket
 %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) /etc/security/security-server-audit.conf
 
 %{_datadir}/license/%{name}
index 20b3ad3..dc45c08 100644 (file)
 /*! \brief   indicating password retry timeout is not occurred yet  */
 #define SECURITY_SERVER_API_ERROR_PASSWORD_REUSED -20
 
+/*! \brief   indicating getting smack label from socket failed  */
+#define SECURITY_SERVER_API_ERROR_GETTING_SOCKET_LABEL_FAILED -21
+
 /*! \brief   indicating the error with unknown reason */
 #define SECURITY_SERVER_API_ERROR_UNKNOWN -255
 /** @}*/
@@ -1037,6 +1040,40 @@ int security_server_app_disable_permissions(const char *app_id, app_type_t app_t
 int security_server_get_uid_by_cookie(const char *cookie, uid_t *uid);
 
 /*
+ * This function allows middleware to check if an app has the specified privilege
+ * enabled.
+ *
+ * \param[in] Application ID
+ * \param[in] Application type
+ * \param[in] Privilege name
+ * \param[out] Handler to store the result. It is set to 1 (true) if privilege is enabled, 0 (false) otherwise
+ *
+ * \return SECURITY_SERVER_SUCCESS on success or error code on fail
+ *
+ * Access to this function requires SMACK rule: "<app_label> security-server::api-app-privilege-by-name w"
+ */
+int security_server_app_has_privilege(const char *app_id,
+                                      app_type_t app_type,
+                                      const char *privilege_name,
+                                      int *result);
+
+/*
+ * This function allows middleware to check if caller app has the specified privilege
+ * enabled. Security Server gets caller app smack label from the IPC socket.
+ *
+ * \param[in] Application type
+ * \param[in] Privilege name
+ * \param[out] Handler to store the result. It is set to 1 (true) if privilege is enabled, 0 (false) otherwise
+ *
+ * \return SECURITY_SERVER_SUCCESS on success or error code on fail
+ *
+ * Access to this function requires SMACK rule: "<app_label> security-server::api-app-privilege-by-name w"
+ */
+int security_server_app_caller_has_privilege(app_type_t app_type,
+                                             const char *privilege_name,
+                                             int *result);
+
+/*
  * This function allows middleware to get GID assigned to cookie
  *
  * \param[in] Cookie
index 9a0703b..2f9ec2f 100644 (file)
@@ -152,3 +152,118 @@ int security_server_app_disable_permissions(const char *app_id, app_type_t app_t
 
     return SECURITY_SERVER_API_ERROR_UNKNOWN;
 }
+
+
+SECURITY_SERVER_API
+int security_server_app_has_privilege(const char *app_id,
+                                      app_type_t app_type,
+                                      const char *privilege_name,
+                                      int *result)
+{
+    using namespace SecurityServer;
+    MessageBuffer send, recv;
+
+    LogDebug("security_server_app_has_privilege() called");
+
+    try {
+        if ((NULL == app_id) || (strlen(app_id) == 0)) {
+            LogError("app_id is NULL or empty");
+            return SECURITY_SERVER_API_ERROR_INPUT_PARAM;
+        }
+        if ((NULL == privilege_name) || (strlen(privilege_name) == 0)) {
+            LogError("privilege_name is NULL or empty");
+            return SECURITY_SERVER_API_ERROR_INPUT_PARAM;
+        }
+        if (NULL == result) {
+            LogError("result is NULL");
+            return SECURITY_SERVER_API_ERROR_INPUT_PARAM;
+        }
+
+        LogDebug("app_id: " << app_id);
+        LogDebug("app_type: " << static_cast<int>(app_type));
+        LogDebug("privilege_name: " << privilege_name);
+
+        //put data into buffer
+        Serialization::Serialize(send, static_cast<int>(PrivilegeCheckCall::CHECK_GIVEN_APP));
+        Serialization::Serialize(send, std::string(app_id));
+        Serialization::Serialize(send, static_cast<int>(app_type));
+        Serialization::Serialize(send, std::string(privilege_name));
+
+        //send buffer to server
+        int apiResult = sendToServer(SERVICE_SOCKET_APP_PRIVILEGE_BY_NAME, send.Pop(), recv);
+        if (apiResult != SECURITY_SERVER_API_SUCCESS) {
+            LogError("Error in sendToServer. Error code: " << apiResult);
+            return apiResult;
+        }
+
+        //receive response from server
+        Deserialization::Deserialize(recv, apiResult);
+        if (apiResult == SECURITY_SERVER_API_SUCCESS) {
+            Deserialization::Deserialize(recv, *result);
+        }
+        return apiResult;
+
+    } catch (MessageBuffer::Exception::Base &e) {
+        LogError("SecurityServer::MessageBuffer::Exception " << e.DumpToString());
+    } catch (std::exception &e) {
+        LogError("STD exception " << e.what());
+    } catch (...) {
+        LogError("Unknown exception occured");
+    }
+
+    return SECURITY_SERVER_API_ERROR_UNKNOWN;
+}
+
+
+SECURITY_SERVER_API
+int security_server_app_caller_has_privilege(app_type_t app_type,
+                                             const char *privilege_name,
+                                             int *result)
+{
+    using namespace SecurityServer;
+    MessageBuffer send, recv;
+
+    LogDebug("security_server_app_caller_has_privilege() called");
+
+    try {
+        if ((NULL == privilege_name) || (strlen(privilege_name) == 0)) {
+            LogError("privilege_name is NULL or empty");
+            return SECURITY_SERVER_API_ERROR_INPUT_PARAM;
+        }
+        if (NULL == result) {
+            LogError("result is NULL");
+            return SECURITY_SERVER_API_ERROR_INPUT_PARAM;
+        }
+
+        LogDebug("app_type: " << static_cast<int>(app_type));
+        LogDebug("privilege_name: " << privilege_name);
+
+        //put data into buffer
+        Serialization::Serialize(send, static_cast<int>(PrivilegeCheckCall::CHECK_CALLER_APP));
+        Serialization::Serialize(send, static_cast<int>(app_type));
+        Serialization::Serialize(send, std::string(privilege_name));
+
+        //send buffer to server
+        int apiResult = sendToServer(SERVICE_SOCKET_APP_PRIVILEGE_BY_NAME, send.Pop(), recv);
+        if (apiResult != SECURITY_SERVER_API_SUCCESS) {
+            LogError("Error in sendToServer. Error code: " << apiResult);
+            return apiResult;
+        }
+
+        //receive response from server
+        Deserialization::Deserialize(recv, apiResult);
+        if (apiResult == SECURITY_SERVER_API_SUCCESS) {
+            Deserialization::Deserialize(recv, *result);
+        }
+        return apiResult;
+
+    } catch (MessageBuffer::Exception::Base &e) {
+        LogError("SecurityServer::MessageBuffer::Exception " << e.DumpToString());
+    } catch (std::exception &e) {
+        LogError("STD exception " << e.what());
+    } catch (...) {
+        LogError("Unknown exception occured");
+    }
+
+    return SECURITY_SERVER_API_ERROR_UNKNOWN;
+}
index 87ffd74..d10ce97 100644 (file)
@@ -39,6 +39,8 @@ char const * const SERVICE_SOCKET_GET_OBJECT_NAME =
     "/tmp/.security-server-api-get-object-name.sock";
 char const * const SERVICE_SOCKET_APP_PERMISSIONS =
     "/tmp/.security-server-api-app-permissions.sock";
+char const * const SERVICE_SOCKET_APP_PRIVILEGE_BY_NAME =
+    "/tmp/.security-server-api-app-privilege-by-name.sock";
 char const * const SERVICE_SOCKET_COOKIE_GET =
     "/tmp/.security-server-api-cookie-get.sock";
 char const * const SERVICE_SOCKET_COOKIE_CHECK =
index ec9e4f6..f02748c 100644 (file)
@@ -35,6 +35,7 @@ extern char const * const SERVICE_SOCKET_GET_GID;
 extern char const * const SERVICE_SOCKET_PRIVILEGE_BY_PID;
 extern char const * const SERVICE_SOCKET_GET_OBJECT_NAME;
 extern char const * const SERVICE_SOCKET_APP_PERMISSIONS;
+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;
@@ -52,6 +53,12 @@ enum class CookieCall
     CHECK_UID
 };
 
+enum class PrivilegeCheckCall
+{
+    CHECK_GIVEN_APP,
+    CHECK_CALLER_APP
+};
+
 extern const size_t COOKIE_SIZE;
 
 } // namespace SecuritySever
index f174328..f622d02 100644 (file)
 #include <memory>
 #include <dpl/log/log.h>
 #include <dpl/serialization.h>
+#include <privilege-control.h>
+
+#include <sys/smack.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <app-permissions.h>
 #include <protocols.h>
 #include <security-server.h>
-#include <privilege-control.h>
 #include <security-server-common.h>
-#include <app-permissions.h>
+
 
 namespace {
 
@@ -54,14 +60,22 @@ int privilegeToSecurityServerError(int error) {
 namespace SecurityServer {
 
 GenericSocketService::ServiceDescriptionVector AppPermissionsService::GetServiceDescription() {
-    return ServiceDescriptionVector
-        {{SERVICE_SOCKET_APP_PERMISSIONS, "security-server::api-app-permissions" }};
+    return ServiceDescriptionVector {
+        { SERVICE_SOCKET_APP_PERMISSIONS,
+          "security-server::api-app-permissions",
+          static_cast<int>(InterfaceType::CHANGE_APP_PERMISSIONS) },
+        { SERVICE_SOCKET_APP_PRIVILEGE_BY_NAME,
+          "security-server::api-app-privilege-by-name",
+          static_cast<int>(InterfaceType::CHECK_APP_PRIVILEGE) }
+    };
 }
 
 void AppPermissionsService::accept(const AcceptEvent &event) {
     LogDebug("Accept event. ConnectionID.sock: " << event.connectionID.sock
         << " ConnectionID.counter: " << event.connectionID.counter
         << " ServiceID: " << event.interfaceID);
+    auto &info = m_socketInfoMap[event.connectionID.counter];
+    info.interfaceID = static_cast<InterfaceType>(event.interfaceID);
 }
 
 void AppPermissionsService::write(const WriteEvent &event) {
@@ -73,23 +87,49 @@ void AppPermissionsService::write(const WriteEvent &event) {
 
 void AppPermissionsService::process(const ReadEvent &event) {
     LogDebug("Read event for counter: " << event.connectionID.counter);
-    auto &buffer = m_messageBufferMap[event.connectionID.counter];
-    buffer.Push(event.rawBuffer);
+    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, buffer));
+    while(processOne(event.connectionID, info.buffer, info.interfaceID));
 }
 
 void AppPermissionsService::close(const CloseEvent &event) {
     LogDebug("CloseEvent. ConnectionID: " << event.connectionID.sock);
-    m_messageBufferMap.erase(event.connectionID.counter);
+    m_socketInfoMap.erase(event.connectionID.counter);
 }
 
-bool AppPermissionsService::processOne(const ConnectionID &conn, MessageBuffer &buffer)
+bool AppPermissionsService::processOne(const ConnectionID &conn,
+                                       MessageBuffer &buffer,
+                                       InterfaceType interfaceID)
 {
     LogDebug("Iteration begin");
-    MessageBuffer send, recv;
+
+    //waiting for all data
+    if (!buffer.Ready()) {
+        return false;
+    }
+
+    LogDebug("Entering app_permissions server side handler");
+
+    switch(interfaceID) {
+    case InterfaceType::CHANGE_APP_PERMISSIONS:
+        return processPermissionsChange(conn, buffer);
+
+    case InterfaceType::CHECK_APP_PRIVILEGE:
+        return processCheckAppPrivilege(conn, buffer);
+
+    default:
+        LogDebug("Unknown interfaceId. Closing socket.");
+        m_serviceManager->Close(conn);
+        return false;
+    }
+}
+
+bool AppPermissionsService::processPermissionsChange(const ConnectionID &conn, MessageBuffer &buffer)
+{
+    MessageBuffer send;
     std::vector<std::string> permissions_list;
     std::string app_id;
     int persistent;
@@ -98,12 +138,7 @@ bool AppPermissionsService::processOne(const ConnectionID &conn, MessageBuffer &
     app_type_t app_type;
     AppPermissionsAction appPermAction;
 
-    //waiting for all data
-    if (!buffer.Ready()) {
-        return false;
-    }
-
-    LogDebug("Entering app_permissions server side handler");
+    LogDebug("Processing permissions change request");
 
     //receive data from buffer and check MSG_ID
     Try {
@@ -148,13 +183,13 @@ bool AppPermissionsService::processOne(const ConnectionID &conn, MessageBuffer &
 
     //use received data
     if (appPermAction == AppPermissionsAction::ENABLE) {
-        LogDebug("Calling app_enable_permiossions()");
+        LogDebug("Calling perm_app_enable_permissions()");
         result = perm_app_enable_permissions(app_id.c_str(), app_type, perm_list.get(), persistent);
-        LogDebug("app_enable_permissions() returned: " << result);
+        LogDebug("perm_app_enable_permissions() returned: " << result);
     } else {
-        LogDebug("Calling app_disable_permiossions()");
+        LogDebug("Calling perm_app_disable_permissions()");
         result = perm_app_disable_permissions(app_id.c_str(), app_type, perm_list.get());
-        LogDebug("app_disable_permissions() returned: " << result);
+        LogDebug("perm_app_disable_permissions() returned: " << result);
     }
 
     //send response
@@ -163,5 +198,67 @@ bool AppPermissionsService::processOne(const ConnectionID &conn, MessageBuffer &
     return true;
 }
 
-} // namespace SecurityServer
+bool AppPermissionsService::processCheckAppPrivilege(const ConnectionID &conn, MessageBuffer &buffer)
+{
+    MessageBuffer send;
+    std::string privilege_name;
+    std::string app_id;
+    int result = SECURITY_SERVER_API_ERROR_SERVER_ERROR;
+    app_type_t app_type;
+    bool has_permission = false;
+    PrivilegeCheckCall checkType = PrivilegeCheckCall::CHECK_GIVEN_APP;
+
+    LogDebug("Processing app privilege check request");
+
+    //receive data from buffer
+    Try {
+        int temp;
+        Deserialization::Deserialize(buffer, temp); // call type
+        checkType = static_cast<PrivilegeCheckCall>(temp);
+        LogDebug("App privilege check call type: "
+                 << (checkType == PrivilegeCheckCall::CHECK_GIVEN_APP ?
+                     "CHECK_GIVEN_APP":"CHECK_CALLER_APP"));
+        if (checkType == PrivilegeCheckCall::CHECK_GIVEN_APP) { //app_id present only in this case
+            Deserialization::Deserialize(buffer, app_id); //get app id
+        }
+        Deserialization::Deserialize(buffer, temp); //get app type
+        app_type = static_cast<app_type_t>(temp);
+
+        Deserialization::Deserialize(buffer, privilege_name); //get privilege name
+    } Catch (MessageBuffer::Exception::Base) {
+        LogDebug("Broken protocol. Closing socket.");
+        m_serviceManager->Close(conn);
+        return false;
+    }
+
+    if (checkType == PrivilegeCheckCall::CHECK_CALLER_APP) { //get sender app_id in this case
+        char *label = NULL;
+        if (smack_new_label_from_socket(conn.sock, &label) < 0) {
+            LogDebug("Error in smack_new_label_from_socket(): "
+                     "client label is unknown. Sending error response.");
+            Serialization::Serialize(send, SECURITY_SERVER_API_ERROR_GETTING_SOCKET_LABEL_FAILED);
+            m_serviceManager->Write(conn, send.Pop());
+            return false;
+        } else {
+            app_id = label;
+            free(label);
+        }
+    } //end if
+
+    //print received data
+    LogDebug("app_id: " << app_id);
+    LogDebug("app_type: " << static_cast<int>(app_type));
+    LogDebug("privilege_name: " << privilege_name);
+
+    LogDebug("Calling perm_app_has_permission()");
+    result = perm_app_has_permission(app_id.c_str(), app_type, privilege_name.c_str(), &has_permission);
+    LogDebug("perm_app_has_permission() returned: " << result << " , permission enabled: " << has_permission);
 
+    //send response
+    Serialization::Serialize(send, privilegeToSecurityServerError(result));
+    Serialization::Serialize(send, static_cast<int>(has_permission));
+    m_serviceManager->Write(conn, send.Pop());
+    return true;
+}
+
+} // namespace SecurityServer
index f5ee638..a22bfbc 100644 (file)
@@ -39,7 +39,17 @@ class AppPermissionsService  :
   , public SecurityServer::ServiceThread<AppPermissionsService>
 {
 public:
-    typedef std::map<int, MessageBuffer> MessageBufferMap;
+    enum class InterfaceType {
+        CHANGE_APP_PERMISSIONS,
+        CHECK_APP_PRIVILEGE,
+    };
+
+    struct SocketInfo {
+        InterfaceType interfaceID;
+        MessageBuffer buffer;
+    };
+
+    typedef std::map<int, SocketInfo> SocketInfoMap;
 
     ServiceDescriptionVector GetServiceDescription();
 
@@ -54,9 +64,12 @@ public:
     void close(const CloseEvent &event);
 
 private:
-    bool processOne(const ConnectionID &conn, MessageBuffer &buffer);
+    bool processOne(const ConnectionID &conn, MessageBuffer &buffer, InterfaceType interfaceID);
+
+    bool processPermissionsChange(const ConnectionID &conn, MessageBuffer &buffer);
+    bool processCheckAppPrivilege(const ConnectionID &conn, MessageBuffer &buffer);
 
-    MessageBufferMap m_messageBufferMap;
+    SocketInfoMap m_socketInfoMap;
 };
 
 } // namespace SecurityServer
index f0151fc..5b77861 100644 (file)
@@ -9,6 +9,7 @@ INSTALL(FILES
     ${CMAKE_SOURCE_DIR}/systemd/security-server-app-permissions.socket
     ${CMAKE_SOURCE_DIR}/systemd/security-server-cookie-get.socket
     ${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
     DESTINATION
     /usr/lib/systemd/system
diff --git a/systemd/security-server-app-privilege-by-name.socket b/systemd/security-server-app-privilege-by-name.socket
new file mode 100644 (file)
index 0000000..1850f2d
--- /dev/null
@@ -0,0 +1,10 @@
+[Socket]
+ListenStream=/tmp/.security-server-api-app-privilege-by-name.sock
+SocketMode=0777
+SmackLabelIPIn=security-server::api-app-privilege-by-name
+SmackLabelIPOut=@
+
+Service=security-server.service
+
+[Install]
+WantedBy=sockets.target
index 610e6ff..77f3f24 100644 (file)
@@ -11,6 +11,7 @@ Sockets=security-server-privilege-by-pid.socket
 Sockets=security-server-exec-path.socket
 Sockets=security-server-get-object-name.socket
 Sockets=security-server-app-permissions.socket
+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