Add tests for cynara-creds-gdbus
[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 #include <glib-object.h>
33 #include <gio/gio.h>
34
35 #include <tests_common.h>
36 #include <access_provider.h>
37 #include <dpl/test/test_runner.h>
38 #include <memory.h>
39 #include <synchronization_pipe.h>
40 #include <tests_common.h>
41 #include <uds.h>
42 #include <passwd_access.h>
43
44 #include <cynara_test_helpers.h>
45 #include <cynara_test_helpers_dbus.h>
46 #include <cynara-creds-gdbus.h>
47
48 class ProcessCredentials {
49 public:
50     ProcessCredentials() {}
51
52     const std::string &label(void) const {
53         return m_label;
54     }
55
56     uid_t uid(void) const {
57         return PasswdAccess::uid(APP_USER);
58     }
59
60     gid_t gid(void) const {
61         return PasswdAccess::gid("users");
62     }
63
64 private:
65     std::string m_label = "cynara_helpers";
66 };
67
68 pid_t runInChild(const std::function<void(void)> &process) {
69     pid_t pid = fork();
70     RUNNER_ASSERT_ERRNO_MSG(pid >= 0, "fork failed");
71
72     if (pid == 0) {
73         process();
74         exit(EXIT_SUCCESS);
75     }
76
77     return pid;
78 }
79
80 void udsServer(SynchronizationPipe &pipe, const struct sockaddr_un &sockaddr,
81                const struct ProcessCredentials &peerCredentials) {
82     SecurityServer::AccessProvider ap(peerCredentials.label());
83     ap.applyAndSwithToUser(peerCredentials.uid(), peerCredentials.gid());
84     pipe.claimChildEp();
85
86     int sock = UDSHelpers::createServer(&sockaddr);
87     SockUniquePtr sockPtr(&sock);
88     pipe.post();
89     int clientSock = UDSHelpers::acceptClient(sock);
90
91     UDSHelpers::waitForDisconnect(clientSock);
92 }
93
94 typedef std::function<void(int sock, pid_t pid,
95         const ProcessCredentials &peerCredentials)> SocketAssertionFn;
96
97 void socketTestTemplate(SocketAssertionFn assertion, const std::string &scope) {
98     const auto sockaddr = UDSHelpers::makeAbstractAddress("helper_" + scope + ".socket");
99     const ProcessCredentials peerCredentials;
100
101     SynchronizationPipe pipe;
102
103     pid_t pid = runInChild(std::bind(udsServer, std::ref(pipe), std::cref(sockaddr),
104                            std::cref(peerCredentials)));
105
106     pipe.claimParentEp();
107     pipe.wait();
108     int sock = UDSHelpers::createClient(&sockaddr);
109     SockUniquePtr sockPtr(&sock);
110
111     assertion(sock, pid, peerCredentials);
112 }
113
114 RUNNER_TEST_GROUP_INIT(cynara_creds_socket)
115
116 RUNNER_CHILD_TEST_SMACK(tccs01_socket_credentials_client_smack)
117 {
118     socketTestTemplate([] (int sock, pid_t, const ProcessCredentials &peerCredentials) {
119         CStringPtr label(CynaraHelperCredentials::socketGetClient(sock, CLIENT_METHOD_SMACK));
120         RUNNER_ASSERT_MSG(peerCredentials.label() == label.get(),
121                           "Labels don't match ret = " << label.get()
122                           << "; expected = " << peerCredentials.label());
123     }, "tccs01");
124 }
125
126 RUNNER_CHILD_TEST_SMACK(tccs02_socket_credentials_client_pid)
127 {
128     socketTestTemplate([] (int sock, pid_t pid, const ProcessCredentials &) {
129         CStringPtr clientPidStr(CynaraHelperCredentials::socketGetClient(sock, CLIENT_METHOD_PID));
130         pid_t clientPid = std::stoi(clientPidStr.get());
131         RUNNER_ASSERT_MSG(pid == clientPid, "PIDs don't match ret = " << clientPid
132                           << "; expected = " << pid);
133     }, "tccs02");
134 }
135
136 RUNNER_CHILD_TEST_SMACK(tccs03_socket_credentials_user_uid)
137 {
138     socketTestTemplate([] (int sock, pid_t, const ProcessCredentials &peerCredentials) {
139         CStringPtr uidStr(CynaraHelperCredentials::socketGetUser(sock, USER_METHOD_UID));
140         uid_t uid = std::stoul(uidStr.get());
141         RUNNER_ASSERT_MSG(peerCredentials.uid() == uid, "UIDs don't match ret = " << uid
142                           << "; expected = "<< peerCredentials.uid());
143     }, "tccs03");
144 }
145
146 RUNNER_CHILD_TEST_SMACK(tccs04_socket_credentials_user_gid)
147 {
148     socketTestTemplate([] (int sock, pid_t, const ProcessCredentials &peerCredentials) {
149         CStringPtr gidStr(CynaraHelperCredentials::socketGetUser(sock, USER_METHOD_GID));
150         gid_t gid = std::stoul(gidStr.get());
151         RUNNER_ASSERT_MSG(peerCredentials.gid() == gid, "GIDs don't match ret = " << gid
152                           << "; expected = "<< peerCredentials.gid());
153     }, "tccs04");
154 }
155
156 RUNNER_CHILD_TEST_SMACK(tccs05_cynara_creds_socket_pid)
157 {
158     const auto sockaddr = UDSHelpers::makeAbstractAddress("helper_tccs05.socket");
159     const ProcessCredentials peerCredentials;
160
161     SynchronizationPipe pipe;
162     pid_t expectedPid = runInChild(std::bind(udsServer, std::ref(pipe), std::cref(sockaddr),
163                                    std::cref(peerCredentials)));
164
165     pipe.claimParentEp();
166     pipe.wait();
167     int sock = UDSHelpers::createClient(&sockaddr);
168     SockUniquePtr sockPtr(&sock);
169
170     pid_t helperPid = CynaraHelperCredentials::socketGetPid(sock);
171     RUNNER_ASSERT_MSG(helperPid == expectedPid, "PIDs don't match ret = " << helperPid
172                       << "; expected = " << expectedPid);
173 }
174
175 // TODO: Create utility namespace for DBus, maybe?
176 DBusConnectionPtr createDBusConnection(const std::string &name) {
177     DBusError err;
178
179     dbus_error_init(&err);
180     DBusConnection *conn = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
181     RUNNER_ASSERT_MSG(dbus_error_is_set(&err) != 1, "Error in dbus_bus_get: " << err.message);
182     dbus_connection_set_exit_on_disconnect(conn, FALSE);
183
184     DBusConnectionPtr ret(conn, [] (DBusConnection *conn) {
185         dbus_connection_close(conn);
186         dbus_connection_unref(conn);
187     });
188
189     if (name.empty() == false) {
190         dbus_bus_request_name(conn, name.c_str(), DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
191         RUNNER_ASSERT_MSG(dbus_error_is_set(&err) != TRUE,
192                           "Error in dbus_bus_request_name: " << err.message);
193     }
194
195     return ret;
196 }
197
198 void dbusServer(SynchronizationPipe &pipe, const std::string &requestedName,
199                 const ProcessCredentials &peerCredentials) {
200     // for DBus connection, System must have access to our peer creds as well.
201     SecurityServer::AccessProvider systemAp("System");
202     systemAp.addObjectRule(peerCredentials.label(), "rwx");
203     systemAp.apply();
204
205     SecurityServer::AccessProvider ap(peerCredentials.label());
206     ap.addObjectRule("System", "w");
207     ap.addObjectRule("System::Run", "x");
208     ap.addObjectRule("System::Shared", "x"); // for GDB
209     ap.addObjectRule("User", "r"); // for /usr/lib/debug access
210     ap.applyAndSwithToUser(peerCredentials.uid(), peerCredentials.gid());
211     pipe.claimChildEp();
212
213     auto conn = createDBusConnection(requestedName);
214     pipe.post();
215     pipe.wait();
216 }
217
218 typedef std::function<void(DBusConnectionPtr conn, pid_t pid,
219                            const std::string &requestedName,
220                            const ProcessCredentials &peerCredentials)> DBusAssertionFn;
221
222 void dbusTestTemplate(DBusAssertionFn assertion, const std::string &/*scope*/) {
223     std::string requestedName = "tests.dbus.cynara";
224     const ProcessCredentials peerCredentials;
225
226     SynchronizationPipe pipe;
227     pid_t pid = runInChild(std::bind(dbusServer, std::ref(pipe), std::cref(requestedName),
228                            std::cref(peerCredentials)));
229
230     pipe.claimParentEp();
231     pipe.wait();
232
233     auto conn = createDBusConnection("");
234     assertion(std::move(conn), pid, requestedName, peerCredentials);
235     pipe.post();
236 }
237
238 RUNNER_TEST_GROUP_INIT(cynara_creds_dbus)
239
240 RUNNER_TEST_SMACK(tccd01_dbus_credentials_client_pid) {
241     dbusTestTemplate([] (DBusConnectionPtr conn, pid_t pid, const std::string &requestedName,
242                          const ProcessCredentials &) {
243         CStringPtr clientPidStr(CynaraHelperCredentials::dbusGetClient(std::move(conn),
244             requestedName.c_str(), CLIENT_METHOD_PID, CYNARA_API_SUCCESS));
245         pid_t clientPid = std::stoi(clientPidStr.get());
246         RUNNER_ASSERT_MSG(pid == clientPid, "PIDs don't match ret = " << clientPid
247                           << "; expected = " << pid);
248     }, "tccd01");
249 }
250
251 RUNNER_TEST_SMACK(tccd02_dbus_credentials_client_smack) {
252     dbusTestTemplate([] (DBusConnectionPtr conn, pid_t, const std::string &requestedName,
253                          const ProcessCredentials &peerCredentials) {
254         CStringPtr label(CynaraHelperCredentials::dbusGetClient(std::move(conn),
255             requestedName.c_str(), CLIENT_METHOD_SMACK, CYNARA_API_SUCCESS));
256         RUNNER_ASSERT_MSG(peerCredentials.label() == label.get(),
257                           "Labels don't match ret = " << label.get()
258                           << "; expected = " << peerCredentials.label());
259     }, "tccd02");
260 }
261
262 RUNNER_TEST_SMACK(tccd03_dbus_credentials_user_uid) {
263     dbusTestTemplate([] (DBusConnectionPtr conn, pid_t, const std::string &requestedName,
264                          const ProcessCredentials &peerCredentials) {
265         CStringPtr uidStr(CynaraHelperCredentials::dbusGetUser(std::move(conn),
266             requestedName.c_str(), USER_METHOD_UID, CYNARA_API_SUCCESS));
267         uid_t uid = std::stoul(uidStr.get());
268         RUNNER_ASSERT_MSG(peerCredentials.uid() == uid, "UIDs don't match ret = " << uid
269                           << "; expected = "<< peerCredentials.uid());
270     }, "tccd03");
271 }
272
273 RUNNER_TEST_SMACK(tccd04_dbus_credentials_pid) {
274     dbusTestTemplate([] (DBusConnectionPtr conn, pid_t expectedPid,
275                          const std::string &requestedName, const ProcessCredentials &) {
276         auto helperPid = CynaraHelperCredentials::dbusGetPid(std::move(conn),
277             requestedName.c_str(), CYNARA_API_SUCCESS);
278         RUNNER_ASSERT_MSG(helperPid == expectedPid, "PIDs don't match ret = " << helperPid
279                           << "; expected = " << expectedPid);
280     }, "tccd04");
281 }
282
283 GDBusConnectionPtr createGDBusConnection() {
284     GDBusConnection *conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
285
286     return GDBusConnectionPtr(conn, [] (GDBusConnection *conn) {
287         g_object_unref(G_OBJECT(conn));
288     });
289 }
290
291
292 typedef std::function<void(GDBusConnectionPtr conn, pid_t pid,
293                            const std::string &requestedName,
294                            const ProcessCredentials &peerCredentials)> GDBusAssertionFn;
295
296 void gdbusTestTemplate(GDBusAssertionFn assertion, const std::string &/*scope*/) {
297     std::string requestedName = "tests.dbus.cynara";
298     const ProcessCredentials peerCredentials;
299
300     SynchronizationPipe pipe;
301     pid_t pid = runInChild(std::bind(dbusServer, std::ref(pipe), std::cref(requestedName),
302                            std::cref(peerCredentials)));
303
304     pipe.claimParentEp();
305     pipe.wait();
306
307     auto conn = createGDBusConnection();
308     assertion(std::move(conn), pid, requestedName, peerCredentials);
309     pipe.post();
310 }
311
312
313 RUNNER_TEST_GROUP_INIT(cynara_creds_gdbus)
314
315 RUNNER_TEST_SMACK(tccgd01_gdbus_credentials_client_pid) {
316     gdbusTestTemplate([] (GDBusConnectionPtr conn, pid_t pid, const std::string &requestedName,
317                           const ProcessCredentials &) {
318         GStringPtr clientPidStr(CynaraHelperCredentials::gdbusGetClient(std::move(conn),
319                                 requestedName.c_str(), CLIENT_METHOD_PID));
320         pid_t clientPid = std::stoi(clientPidStr.get());
321         RUNNER_ASSERT_MSG(pid == clientPid, "PIDs don't match ret = " << clientPid
322                           << "; expected = " << pid);
323     }, "tccgd01");
324 }
325
326 RUNNER_TEST_SMACK(tccgd02_gdbus_credentials_client_smack) {
327     gdbusTestTemplate([] (GDBusConnectionPtr conn, pid_t, const std::string &requestedName,
328                           const ProcessCredentials &peerCredentials) {
329         GStringPtr label(CynaraHelperCredentials::gdbusGetClient(std::move(conn),
330                          requestedName.c_str(), CLIENT_METHOD_SMACK));
331         RUNNER_ASSERT_MSG(peerCredentials.label() == label.get(),
332                           "Labels don't match ret = " << label.get()
333                           << "; expected = " << peerCredentials.label());
334     }, "tccgd02");
335 }
336
337 RUNNER_TEST_SMACK(tccgd03_gdbus_credentials_user_uid) {
338     gdbusTestTemplate([] (GDBusConnectionPtr conn, pid_t, const std::string &requestedName,
339                           const ProcessCredentials &peerCredentials) {
340         GStringPtr uidStr(CynaraHelperCredentials::gdbusGetUser(std::move(conn),
341                           requestedName.c_str(), USER_METHOD_UID));
342         uid_t uid = std::stoul(uidStr.get());
343         RUNNER_ASSERT_MSG(peerCredentials.uid() == uid, "UIDs don't match ret = " << uid
344                           << "; expected = "<< peerCredentials.uid());
345     }, "tccgd03");
346 }
347
348 RUNNER_TEST_SMACK(tccgd04_gdbus_credentials_pid) {
349     gdbusTestTemplate([] (GDBusConnectionPtr conn, pid_t expectedPid,
350                           const std::string &requestedName, const ProcessCredentials &) {
351         auto helperPid = CynaraHelperCredentials::gdbusGetPid(std::move(conn),
352                          requestedName.c_str());
353         RUNNER_ASSERT_MSG(helperPid == expectedPid, "PIDs don't match ret = " << helperPid
354                           << "; expected = " << expectedPid);
355     }, "tccgd04");
356 }