Add tests for cynara-creds-dbus
[platform/core/test/security-tests.git] / src / cynara-tests / test_cases_helpers.cpp
1 /*
2  * Copyright (c) 2015-2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /**
17  * @file        test_cases_helpers.cpp
18  * @author      Aleksander Zdyb <a.zdyb@samsung.com>
19  * @version     1.0
20  * @brief       Tests for cynara-helper-credentials-socket and cynara-helper-credentials-dbus
21  */
22
23 #include <cstdlib>
24 #include <functional>
25 #include <string>
26 #include <sys/types.h>
27 #include <sys/un.h>
28 #include <unistd.h>
29 #include <utility>
30
31 #include <dbus/dbus.h>
32
33 #include <tests_common.h>
34 #include <access_provider.h>
35 #include <dpl/test/test_runner.h>
36 #include <memory.h>
37 #include <synchronization_pipe.h>
38 #include <tests_common.h>
39 #include <uds.h>
40 #include <passwd_access.h>
41
42 #include <cynara_test_helpers.h>
43 #include <cynara_test_helpers_dbus.h>
44
45 class ProcessCredentials {
46 public:
47     ProcessCredentials() {}
48
49     const std::string &label(void) const {
50         return m_label;
51     }
52
53     uid_t uid(void) const {
54         return PasswdAccess::uid(APP_USER);
55     }
56
57     gid_t gid(void) const {
58         return PasswdAccess::gid("users");
59     }
60
61 private:
62     std::string m_label = "cynara_helpers";
63 };
64
65 pid_t runInChild(const std::function<void(void)> &process) {
66     pid_t pid = fork();
67     RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "fork failed");
68
69     if (pid == 0) {
70         process();
71         exit(EXIT_SUCCESS);
72     }
73
74     return pid;
75 }
76
77 void udsServer(SynchronizationPipe &pipe, const struct sockaddr_un &sockaddr,
78                const struct ProcessCredentials &peerCredentials) {
79     SecurityServer::AccessProvider ap(peerCredentials.label());
80     ap.applyAndSwithToUser(peerCredentials.uid(), peerCredentials.gid());
81     pipe.claimChildEp();
82
83     int sock = UDSHelpers::createServer(&sockaddr);
84     SockUniquePtr sockPtr(&sock);
85     pipe.post();
86     int clientSock = UDSHelpers::acceptClient(sock);
87
88     UDSHelpers::waitForDisconnect(clientSock);
89 }
90
91 typedef std::function<void(int sock, pid_t pid,
92         const ProcessCredentials &peerCredentials)> SocketAssertionFn;
93
94 void socketTestTemplate(SocketAssertionFn assertion, const std::string &scope) {
95     const auto sockaddr = UDSHelpers::makeAbstractAddress("helper_" + scope + ".socket");
96     const ProcessCredentials peerCredentials;
97
98     SynchronizationPipe pipe;
99
100     pid_t pid = runInChild(std::bind(udsServer, std::ref(pipe), std::cref(sockaddr),
101                            std::cref(peerCredentials)));
102
103     pipe.claimParentEp();
104     pipe.wait();
105     int sock = UDSHelpers::createClient(&sockaddr);
106     SockUniquePtr sockPtr(&sock);
107
108     assertion(sock, pid, peerCredentials);
109 }
110
111 RUNNER_TEST_GROUP_INIT(cynara_creds_socket)
112
113 RUNNER_CHILD_TEST_SMACK(tccs01_socket_credentials_client_smack)
114 {
115     socketTestTemplate([] (int sock, pid_t, const ProcessCredentials &peerCredentials) {
116         CStringPtr label(CynaraHelperCredentials::socketGetClient(sock, CLIENT_METHOD_SMACK));
117         RUNNER_ASSERT_MSG(peerCredentials.label() == label.get(),
118                           "Labels don't match ret = " << label.get()
119                           << "; expected = " << peerCredentials.label());
120     }, "tccs01");
121 }
122
123 RUNNER_CHILD_TEST_SMACK(tccs02_socket_credentials_client_pid)
124 {
125     socketTestTemplate([] (int sock, pid_t pid, const ProcessCredentials &) {
126         CStringPtr clientPidStr(CynaraHelperCredentials::socketGetClient(sock, CLIENT_METHOD_PID));
127         pid_t clientPid = std::stoi(clientPidStr.get());
128         RUNNER_ASSERT_MSG(pid == clientPid, "PIDs don't match ret = " << clientPid
129                           << "; expected = " << pid);
130     }, "tccs02");
131 }
132
133 RUNNER_CHILD_TEST_SMACK(tccs03_socket_credentials_user_uid)
134 {
135     socketTestTemplate([] (int sock, pid_t, const ProcessCredentials &peerCredentials) {
136         CStringPtr uidStr(CynaraHelperCredentials::socketGetUser(sock, USER_METHOD_UID));
137         uid_t uid = std::stoul(uidStr.get());
138         RUNNER_ASSERT_MSG(peerCredentials.uid() == uid, "UIDs don't match ret = " << uid
139                           << "; expected = "<< peerCredentials.uid());
140     }, "tccs03");
141 }
142
143 RUNNER_CHILD_TEST_SMACK(tccs04_socket_credentials_user_gid)
144 {
145     socketTestTemplate([] (int sock, pid_t, const ProcessCredentials &peerCredentials) {
146         CStringPtr gidStr(CynaraHelperCredentials::socketGetUser(sock, USER_METHOD_GID));
147         gid_t gid = std::stoul(gidStr.get());
148         RUNNER_ASSERT_MSG(peerCredentials.gid() == gid, "GIDs don't match ret = " << gid
149                           << "; expected = "<< peerCredentials.gid());
150     }, "tccs04");
151 }
152
153 RUNNER_CHILD_TEST_SMACK(tccs05_cynara_creds_socket_pid)
154 {
155     const auto sockaddr = UDSHelpers::makeAbstractAddress("helper_tccs05.socket");
156     const ProcessCredentials peerCredentials;
157
158     SynchronizationPipe pipe;
159     pid_t expectedPid = runInChild(std::bind(udsServer, std::ref(pipe), std::cref(sockaddr),
160                                    std::cref(peerCredentials)));
161
162     pipe.claimParentEp();
163     pipe.wait();
164     int sock = UDSHelpers::createClient(&sockaddr);
165     SockUniquePtr sockPtr(&sock);
166
167     pid_t helperPid = CynaraHelperCredentials::socketGetPid(sock);
168     RUNNER_ASSERT_MSG(helperPid == expectedPid, "PIDs don't match ret = " << helperPid
169                       << "; expected = " << expectedPid);
170 }
171
172 // TODO: Create utility namespace for DBus, maybe?
173 DBusConnectionPtr createDBusConnection(const std::string &name) {
174     DBusError err;
175
176     dbus_error_init(&err);
177     DBusConnection *conn = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
178     RUNNER_ASSERT_MSG(dbus_error_is_set(&err) != 1, "Error in dbus_bus_get: " << err.message);
179     dbus_connection_set_exit_on_disconnect(conn, FALSE);
180
181     DBusConnectionPtr ret(conn, [] (DBusConnection *conn) {
182         dbus_connection_close(conn);
183         dbus_connection_unref(conn);
184     });
185
186     if (name.empty() == false) {
187         dbus_bus_request_name(conn, name.c_str(), DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
188         RUNNER_ASSERT_MSG(dbus_error_is_set(&err) != TRUE,
189                           "Error in dbus_bus_request_name: " << err.message);
190     }
191
192     return ret;
193 }
194
195 void dbusServer(SynchronizationPipe &pipe, const std::string &requestedName,
196                 const ProcessCredentials &peerCredentials) {
197     // for DBus connection, System must have access to our peer creds as well.
198     SecurityServer::AccessProvider systemAp("System");
199     systemAp.addObjectRule(peerCredentials.label(), "rwx");
200     systemAp.apply();
201
202     SecurityServer::AccessProvider ap(peerCredentials.label());
203     ap.addObjectRule("System", "w");
204     ap.addObjectRule("System::Run", "x");
205     ap.addObjectRule("System::Shared", "x"); // for GDB
206     ap.addObjectRule("User", "r"); // for /usr/lib/debug access
207     ap.applyAndSwithToUser(peerCredentials.uid(), peerCredentials.gid());
208     pipe.claimChildEp();
209
210     auto conn = createDBusConnection(requestedName);
211     pipe.post();
212     pipe.wait();
213 }
214
215 typedef std::function<void(DBusConnectionPtr conn, pid_t pid,
216                            const std::string &requestedName,
217                            const ProcessCredentials &peerCredentials)> DBusAssertionFn;
218
219 void dbusTestTemplate(DBusAssertionFn assertion, const std::string &/*scope*/) {
220     std::string requestedName = "tests.dbus.cynara";
221     const ProcessCredentials peerCredentials;
222
223     SynchronizationPipe pipe;
224     pid_t pid = runInChild(std::bind(dbusServer, std::ref(pipe), std::cref(requestedName),
225                            std::cref(peerCredentials)));
226
227     pipe.claimParentEp();
228     pipe.wait();
229
230     auto conn = createDBusConnection("");
231     assertion(std::move(conn), pid, requestedName, peerCredentials);
232     pipe.post();
233 }
234
235 RUNNER_TEST_GROUP_INIT(cynara_creds_dbus)
236
237 RUNNER_TEST_SMACK(tccd01_dbus_credentials_client_pid) {
238     dbusTestTemplate([] (DBusConnectionPtr conn, pid_t pid, const std::string &requestedName,
239                          const ProcessCredentials &) {
240         CStringPtr clientPidStr(CynaraHelperCredentials::dbusGetClient(std::move(conn),
241             requestedName.c_str(), CLIENT_METHOD_PID, CYNARA_API_SUCCESS));
242         pid_t clientPid = std::stoi(clientPidStr.get());
243         RUNNER_ASSERT_MSG(pid == clientPid, "PIDs don't match ret = " << clientPid
244                           << "; expected = " << pid);
245     }, "tccd01");
246 }
247
248 RUNNER_TEST_SMACK(tccd02_dbus_credentials_client_smack) {
249     dbusTestTemplate([] (DBusConnectionPtr conn, pid_t, const std::string &requestedName,
250                          const ProcessCredentials &peerCredentials) {
251         CStringPtr label(CynaraHelperCredentials::dbusGetClient(std::move(conn),
252             requestedName.c_str(), CLIENT_METHOD_SMACK, CYNARA_API_SUCCESS));
253         RUNNER_ASSERT_MSG(peerCredentials.label() == label.get(),
254                           "Labels don't match ret = " << label.get()
255                           << "; expected = " << peerCredentials.label());
256     }, "tccd02");
257 }
258
259 RUNNER_TEST_SMACK(tccd03_dbus_credentials_user_uid) {
260     dbusTestTemplate([] (DBusConnectionPtr conn, pid_t, const std::string &requestedName,
261                          const ProcessCredentials &peerCredentials) {
262         CStringPtr uidStr(CynaraHelperCredentials::dbusGetUser(std::move(conn),
263             requestedName.c_str(), USER_METHOD_UID, CYNARA_API_SUCCESS));
264         uid_t uid = std::stoul(uidStr.get());
265         RUNNER_ASSERT_MSG(peerCredentials.uid() == uid, "UIDs don't match ret = " << uid
266                           << "; expected = "<< peerCredentials.uid());
267     }, "tccd03");
268 }
269
270 RUNNER_TEST_SMACK(tccd04_dbus_credentials_pid) {
271     dbusTestTemplate([] (DBusConnectionPtr conn, pid_t expectedPid,
272                          const std::string &requestedName, const ProcessCredentials &) {
273         auto helperPid = CynaraHelperCredentials::dbusGetPid(std::move(conn),
274             requestedName.c_str(), CYNARA_API_SUCCESS);
275         RUNNER_ASSERT_MSG(helperPid == expectedPid, "PIDs don't match ret = " << helperPid
276                           << "; expected = " << expectedPid);
277     }, "tccd04");
278 }