--- /dev/null
+/*
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ */
+/*
+ * @file security_server_mockup.cpp
+ * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com)
+ * @version 1.0
+ * @brief All mockups required in security-server tests.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <fcntl.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <poll.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <security-server.h>
+
+#include <dpl/log/log.h>
+
+#define SECURITY_SERVER_TEST_SOCK_PATH "/tmp/.security_server_sock_mockup"
+
+/* Create a Unix domain socket and bind */
+int create_new_socket()
+{
+ int localsockfd = -1, flags;
+ struct sockaddr_un serveraddr;
+ mode_t sock_mode;
+
+ if (-1 == remove(SECURITY_SERVER_TEST_SOCK_PATH)) {
+ LogDebug("Unable to remove " << SECURITY_SERVER_TEST_SOCK_PATH);
+ }
+
+ /* Create Unix domain socket */
+ if((localsockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0 )
+ {
+ localsockfd = -1;
+ LogDebug("Socket creation failed");
+ goto error;
+ }
+
+ /* Make socket as non blocking */
+ if((flags = fcntl(localsockfd, F_GETFL, 0)) < 0 ||
+ fcntl(localsockfd, F_SETFL, flags) < 0)
+ {
+ close(localsockfd);
+ localsockfd = -1;
+ LogDebug("Cannot go to nonblocking mode");
+ goto error;
+ }
+
+ bzero (&serveraddr, sizeof(serveraddr));
+ serveraddr.sun_family = AF_UNIX;
+ strncpy(serveraddr.sun_path, SECURITY_SERVER_TEST_SOCK_PATH,
+ strlen(SECURITY_SERVER_TEST_SOCK_PATH) + 1);
+
+ /* Bind the socket */
+ if((bind(localsockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr))) < 0)
+ {
+ LogDebug("Cannot bind");
+ close(localsockfd);
+ localsockfd = -1;
+ goto error;
+ }
+
+ /* Change permission to accept all processes that has different uID/gID */
+ sock_mode = (S_IRWXU | S_IRWXG | S_IRWXO);
+
+ /* Flawfinder hits this chmod function as level 5 CRITICAL as race condition flaw *
+ * * Flawfinder recommends to user fchmod insted of chmod
+ * * But, fchmod doesn't work on socket file so there is no other choice at this point */
+ if(chmod(SECURITY_SERVER_TEST_SOCK_PATH, sock_mode) < 0) /* Flawfinder: ignore */
+ {
+ LogDebug("chmod() error");
+ close(localsockfd);
+ localsockfd = -1;
+ goto error;
+ }
+error:
+ return localsockfd;
+}
+
+int connect_to_testserver()
+{
+ struct sockaddr_un clientaddr;
+ int client_len = 0, localsockfd;
+
+ /* Create a socket */
+ if((localsockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ {
+ LogDebug("Error on socket. Errno: " << errno);
+ return -1;
+ }
+
+ bzero(&clientaddr, sizeof(clientaddr));
+ clientaddr.sun_family = AF_UNIX;
+ strncpy(clientaddr.sun_path, SECURITY_SERVER_TEST_SOCK_PATH, strlen(SECURITY_SERVER_TEST_SOCK_PATH));
+ clientaddr.sun_path[strlen(SECURITY_SERVER_TEST_SOCK_PATH)] = 0;
+ client_len = sizeof(clientaddr);
+ if(connect(localsockfd, (struct sockaddr*)&clientaddr, client_len) < 0)
+ {
+ LogDebug("Error on connect. Errno: " << errno);
+ close(localsockfd);
+ return -1;
+ }
+ return localsockfd;
+}
+
*/
/*
* @file security_server_tests_client_smack.cpp
- * @author Bumjin Im (bj.im@samsung.com)
- * @author Mariusz Domanski (m.domanski@samsung.com)
- * @version 1.0
- * @brief Test cases for security server client
+ * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com)
+ * @version 1.1
+ * @brief Test cases for security-server-client-smack.
*/
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/smack.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+
+#include <dpl/log/log.h>
#include <dpl/test/test_runner.h>
-#include <dlog.h>
-#include "security_server_tests_client.h"
+#include <dpl/test/test_runner_child.h>
+#include "security_server_mockup.h"
+
+#include <security-server.h>
+
+#define ENVIRONMENT \
+do { \
+ const char *subject_label = "mylabel"; \
+ RUNNER_ASSERT_MSG(-1 != system("touch /opt/home/root/pid_cycle"),\
+ "Cannot prepare environment for test."); \
+ RUNNER_ASSERT_MSG(0 == smack_set_label_for_self(subject_label), \
+ "Cannot prepare environment for test."); \
+ RUNNER_ASSERT_MSG(-1 != setgid(1), \
+ "Cannot prepare environment for test."); \
+ RUNNER_ASSERT_MSG(-1 != setuid(1), \
+ "Cannot prepare environment for test"); \
+}while(0)
RUNNER_TEST_GROUP_INIT(SECURITY_SERVER_TESTS_CLIENT_SMACK)
-RUNNER_TEST(tc_security_server_get_cookie_size)
+/*
+ * test: Check cookie size returned by security_server_get_cookie_size.
+ * description: Cookie used by security-server is 20 bytes long.
+ * Any other size of cookies should be treated as error.
+ * expected: Function security_server_get_cookie_size returns 20.
+ */
+RUNNER_CHILD_TEST(tc01_security_server_get_cookie_size)
{
+ ENVIRONMENT;
+
int ret = security_server_get_cookie_size();
- LOGD("ret = %d", ret);
- RUNNER_ASSERT(ret == 20);
+ RUNNER_ASSERT_MSG(20 == ret, "ret = " << ret);
}
-RUNNER_TEST(tc_security_server_request_cookie_normal_case)
+/*
+ * test: security_server_request_cookie
+ * description: Function security_server_request_cookie will return
+ * 20 bytes long cookie.
+ * expected: function will set up cookie in the array and return
+ * SECURITY_SERVER_API_SUCCESS.
+ */
+RUNNER_CHILD_TEST(tc02_security_server_request_cookie_normal_case)
{
+ ENVIRONMENT;
+
+ char cookie[20];
int ret = security_server_request_cookie(cookie, 20);
- LOGD("ret = %d", ret);
- RUNNER_ASSERT(ret == SECURITY_SERVER_API_SUCCESS);
+ LogDebug("ret = " << ret);
+ RUNNER_ASSERT(SECURITY_SERVER_API_SUCCESS == ret);
}
-RUNNER_TEST(tc_security_server_request_cookie_too_small_buffer_size)
+/*
+ * test: security_server_request_cookie
+ * description: Function security_server_request_cookie will return
+ * 20 bytes long cookie.
+ * expected: function will set up cookie in the array and return
+ * SECURITY_SERVER_API_SUCCESS.
+ */
+RUNNER_CHILD_TEST(tc03_security_server_request_cookie_too_small_buffer_size)
{
+ ENVIRONMENT;
+
+ char cookie[20];
int ret = security_server_request_cookie(cookie, 10);
- LOGD("ret = %d", ret);
- RUNNER_ASSERT(ret == SECURITY_SERVER_API_ERROR_BUFFER_TOO_SMALL);
+ LogDebug("ret = " << ret);
+ RUNNER_ASSERT(SECURITY_SERVER_API_ERROR_BUFFER_TOO_SMALL == ret);
}
-RUNNER_TEST(tc_security_server_get_gid_client_is_not_allowed)
+/*
+ * test: tc04_security_server_get_gid_client_is_not_allowed
+ * description: ??
+ * expected: security_server_get_gid should return AUTHENTICATION_FAILED
+ */
+RUNNER_CHILD_TEST(tc04_security_server_get_gid_client_is_not_allowed)
{
+ ENVIRONMENT;
+
int ret = security_server_get_gid("telephony");
- LOGD("ret = %d", ret);
- RUNNER_ASSERT(ret == SECURITY_SERVER_API_ERROR_AUTHENTICATION_FAILED);
+ LogDebug("ret = " << ret);
+ RUNNER_ASSERT(SECURITY_SERVER_API_ERROR_AUTHENTICATION_FAILED == ret);
}
-RUNNER_TEST(tc_requesting_access_to_test_server_via_security_server)
+/*
+ * test: tc05_check_privilege_by_cookie
+ * description: Function security_server_check_privilege_by_cookie should
+ * return status of access rights of cookie owner. In this case cookie owner
+ * is the same process that ask for the rights.
+ * expected: Function call with access rights set to "r" should return SUCCESS,
+ * with "rw" should return ACCESS DENIED.
+ */
+RUNNER_CHILD_TEST(tc05_check_privilege_by_cookie)
{
- sock_fd = connect_to_testserver();
- if(sock_fd < 1)
- {
- LOGD("sock_fd = %d", sock_fd);
- RUNNER_ASSERT_MSG(false, "Socket connection error");
- }
- int ret = send_request_new_cookie(sock_fd, cookie, object_label, access_rights);
- if(ret != 0)
- {
- close(sock_fd);
- LOGD("ret = %d", ret);
- RUNNER_ASSERT_MSG(false, "send failed");
- }
- ret = recv_result(sock_fd);
- close(sock_fd);
- sock_fd = 0;
- if(ret == SECURITY_SERVER_API_SUCCESS)
- {
- LOGD("Permission granted\n");
- }
- else if(ret == SECURITY_SERVER_API_ERROR_ACCESS_DENIED)
- {
- RUNNER_ASSERT_MSG(false, "Permission denied");
- }
- else
- {
- LOGD("ret = %d", ret);
- RUNNER_ASSERT_MSG(false, "Recv error");
- }
+ char cookie[20];
+ const char *object_label = "tc05objectlabel";
+ const char *access_rights = "r";
+ const char *access_rights_ext = "rw";
+ const char *subject_label = "tc05subjectlabel";
+
+ smack_accesses *handle;
+
+ RUNNER_ASSERT(0 == smack_accesses_new(&handle));
+
+ RUNNER_ASSERT(0 == smack_accesses_add(handle,
+ subject_label,
+ object_label,
+ access_rights));
+
+ RUNNER_ASSERT(0 == smack_accesses_apply(handle));
+
+ smack_accesses_free(handle);
+
+ RUNNER_ASSERT(0 == smack_set_label_for_self(subject_label));
+
+ RUNNER_ASSERT(SECURITY_SERVER_API_SUCCESS ==
+ security_server_request_cookie(cookie,20));
+
+ RUNNER_ASSERT(SECURITY_SERVER_API_SUCCESS ==
+ security_server_check_privilege_by_cookie(
+ cookie,
+ object_label,
+ access_rights));
+
+ RUNNER_ASSERT(SECURITY_SERVER_API_ERROR_ACCESS_DENIED ==
+ security_server_check_privilege_by_cookie(
+ cookie,
+ object_label,
+ access_rights_ext));
+
}
-RUNNER_TEST(tc_requesting_access_to_test_server_with_direct_ipc)
+/*
+ * test: security_server_check_privilege_by_sockfd
+ * description: This test will create dummy server that will accept connection
+ * and die. The client will try to check access rights using connection descriptor.
+ * expected: Function call with access rights set to "r" should return SUCCESS,
+ * with "rw" should return ACCESS DENIED.
+ */
+RUNNER_TEST(tc06_check_privilege_by_sockfd)
{
- LOGD("subject: >%s<\n", subject_label);
- LOGD("object: >%s<\n", object_label);
- LOGD("access: >%s<\n", access_rights);
-
- sock_fd = connect_to_testserver();
- if(sock_fd < 1)
- {
- LOGD("sock_fd = %d", sock_fd);
- RUNNER_ASSERT_MSG(false, "Socket connection error");
- }
- int ret = send_request_new_direct(sock_fd, object_label, access_rights);
- if(ret != 0)
- {
- close(sock_fd);
- LOGD("ret = %d", ret);
- RUNNER_ASSERT_MSG(false, "send failed");
- }
- ret = recv_result(sock_fd);
- close(sock_fd);
- if(ret == SECURITY_SERVER_API_SUCCESS)
- {
- LOGD("Permission granted\n");
- }
- else if(ret == SECURITY_SERVER_API_ERROR_ACCESS_DENIED)
- {
- RUNNER_ASSERT_MSG(false, "Permission denied");
- }
- else
- {
- LOGD("ret = %d", ret);
- RUNNER_ASSERT_MSG(false, "Recv error");
+
+ const char *object_label = "tc06objectlabel";
+ const char *access_rights = "r";
+ const char *access_rights_ext = "rw";
+ const char *subject_label = "tc06subjectlabel";
+
+ int result1 = -1;
+ int result2 = -1;
+
+ smack_accesses *handle;
+ RUNNER_ASSERT(0 == smack_accesses_new(&handle));
+ RUNNER_ASSERT(0 == smack_accesses_add(handle,
+ subject_label,
+ object_label,
+ access_rights));
+ RUNNER_ASSERT(0 == smack_accesses_apply(handle));
+ smack_accesses_free(handle);
+
+ int pid = fork();
+ RUNNER_ASSERT(-1 != pid);
+
+ if (0 == pid) {
+ // child
+ if (0 != smack_set_label_for_self(subject_label)) {
+ LogDebug("child, failed");
+ exit(1);
+ }
+
+ LogDebug("child, create_new_socket");
+ int sockfd = create_new_socket();
+
+ LogDebug("child, listen");
+ if (listen(sockfd, 5) < 0) {
+ LogDebug("child, exit");
+ exit(1);
+ }
+ LogDebug("child, accept");
+
+ struct sockaddr_un client_addr;
+ socklen_t client_len = sizeof(client_addr);
+ int csockfd;
+ while(0 <= (csockfd = accept(sockfd,(struct sockaddr*)&client_addr, &client_len))) {
+ LogDebug("child, loop");
+ close(csockfd);
+ }
+ LogDebug("Exit!");
+ exit(1);
+ } else {
+ // parent
+ LogDebug("Parent, sleep 2");
+ sleep(1);
+ int sockfd = connect_to_testserver();
+ LogDebug("Parent: sockfd: " << sockfd);
+ if (sockfd >= 0) {
+ result1 = security_server_check_privilege_by_sockfd(
+ sockfd,
+ object_label,
+ access_rights);
+ result2 = security_server_check_privilege_by_sockfd(
+ sockfd,
+ object_label,
+ access_rights_ext);
+ }
+ LogDebug("Parent: Close desc");
+ close(sockfd);
+ LogDebug("Parent: killing child");
+ kill(pid, SIGKILL);
}
+
+ int status;
+ waitpid(pid, &status, 0);
+
+ RUNNER_ASSERT(SECURITY_SERVER_API_SUCCESS == result1);
+ RUNNER_ASSERT(SECURITY_SERVER_API_ERROR_ACCESS_DENIED == result2);
}
-RUNNER_TEST(tc_requesting_cookie_for_same_pid_with_different_path)
+/*
+ * test: security_server_check_privilege_by_sockfd
+ * description: This test will create dummy server that will accept connection
+ * and die. The client will try to check access rights using connection descriptor.
+ * Unfortunatelly in this cases smack_set_label_for_self will not change label
+ * connected with unix socket. Thats why this test will fail.
+ * expected: Function call with access rights set to "r" should return SUCCESS,
+ * with "rw" should return ACCESS DENIED.
+ */
+RUNNER_TEST(tc07_check_privilege_by_sockfd)
{
- LOGI(" Exiting this process to cycle different process as same PID.\n");
- LOGI(" Please look at the test server's terminal for the result\n");
- cur_pid = getpid();
- sock_fd = connect_to_testserver();
- if(sock_fd < 1)
- {
- RUNNER_ASSERT_MSG(false, "Socket connection error");
- }
- unsigned char buf[32] = {255, 255, 255, 255, };
- int size;
+ const char *object_label = "tc07objectlabel";
+ const char *access_rights = "r";
+ const char *access_rights_ext = "rw";
+ const char *subject_label = "tc07subjectlabel";
- memcpy(buf + 4, cookie, 20);
- memcpy(buf + 24, &cur_pid, sizeof(int));
- int ret = getuid();
- memcpy(buf + 28, &ret, sizeof(int));
+ int result1 = -1;
+ int result2 = -1;
- size = write(sock_fd, buf, 32);
- if(size < 32)
- {
- close(sock_fd);
- RUNNER_ASSERT_MSG(false, "Cannot send");
- }
- if(sock_fd > 0)
- close(sock_fd);
-}
+ smack_accesses *handle;
+ RUNNER_ASSERT(0 == smack_accesses_new(&handle));
+ RUNNER_ASSERT(0 == smack_accesses_add(handle,
+ subject_label,
+ object_label,
+ access_rights));
+ RUNNER_ASSERT(0 == smack_accesses_apply(handle));
+ smack_accesses_free(handle);
+ int pid = fork();
+ RUNNER_ASSERT(-1 != pid);
-int main(int argc, char *argv[])
-{
- /* needed for dlog to work properly
- * during tests guid changes and dlog looses permission to write logs
- * printing log now opens file descriptor with proper privileges */
- LOGD("%s starts", argv[0]);
-
- g_group_num = 0;
- g_perm_num = 0;
-
- int ret = getuid();
- if(ret != 0)
- {
- printf("You must be root to test. Current UID: %d\nExiting...\n", ret);
+ if (0 == pid) {
+ // child
+ LogDebug("child, create_new_socket");
+ int sockfd = create_new_socket();
+
+ if (0 != smack_set_label_for_self(subject_label)) {
+ LogDebug("child, failed");
+ exit(1);
+ }
+
+ LogDebug("child, listen");
+ if (listen(sockfd, 5) < 0) {
+ LogDebug("child, exit");
+ exit(1);
+ }
+ LogDebug("child, accept");
+
+ struct sockaddr_un client_addr;
+ socklen_t client_len = sizeof(client_addr);
+ int csockfd;
+ while(0 <= (csockfd = accept(sockfd,(struct sockaddr*)&client_addr, &client_len))) {
+ LogDebug("child, loop");
+ close(csockfd);
+ }
+ LogDebug("Exit!");
exit(1);
+ } else {
+ // parent
+ LogDebug("Parent, sleep 2");
+ sleep(2);
+ int sockfd = connect_to_testserver();
+ LogDebug("Parent: sockfd: " << sockfd);
+ if (sockfd >= 0) {
+ result1 = security_server_check_privilege_by_sockfd(
+ sockfd,
+ object_label,
+ access_rights);
+ result2 = security_server_check_privilege_by_sockfd(
+ sockfd,
+ object_label,
+ access_rights_ext);
+ }
+ LogDebug("Parent: Close desc");
+ close(sockfd);
+ LogDebug("Parent: killing child");
+ kill(pid, SIGKILL);
}
- int argcc = 7;
- char *argvv[] = {argv[0], "-s", "mylabel", "-o", "objlabel", "-a", "rx"};
-
- system("touch /opt/home/root/pid_cycle");
- privilege_control(argcc, argvv);
+ int status;
+ waitpid(pid, &status, 0);
- LOGD("Strting test. My PID is %d", getpid());
+ RUNNER_ASSERT(SECURITY_SERVER_API_SUCCESS == result1);
+ RUNNER_ASSERT(SECURITY_SERVER_API_ERROR_ACCESS_DENIED == result2);
+}
- int status =
+int main(int argc, char *argv[])
+{
+ return
DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, argv);
-
- if(g_groups != NULL)
- free(g_groups);
- if(g_permissions != NULL)
- free(g_permissions);
- return status;
}