Adjusting security-manager tests to run with onlycap
[platform/core/test/security-tests.git] / src / common / temp_test_user.cpp
1 /*
2  * Copyright (c) 2015 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 /*
18  * @file        temp_test_user.cpp
19  * @author      Jan Cybulski (j.cybulski@partner.samsung.com)
20  * @author      Rafal Krypa (j.cybulski@samsung.com)
21  * @version     1.0
22  * @brief       File with class for users management
23  */
24
25
26 #include <memory.h>
27 #include <tests_common.h>
28 #include <temp_test_user.h>
29 #include <glib-object.h>
30 #include <dpl/test/test_runner.h>
31 #include <unistd.h>
32 #include <signal.h>
33 #include <sys/prctl.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36
37
38 void TemporaryTestUser::create(void)
39 {
40     if (m_uid != 0)
41         remove();
42
43 /*
44     Below line of code is a hack for Gumd commit that removes Smack management capabilities:
45
46     | commit 9b45c1afa49103dcb4101f4b28bf7c145f3294a6
47     |/  Author: Yunmi Ha <yunmi.ha@samsung.com>
48     |   Date:   Tue Jul 5 13:40:16 2016 +0900
49     |
50     |       Remove smack capability
51     |
52     |       with wearable profile, CAP_MAC_ADMIN and CAP_MAC_OVERRIDE capabilities are removed.
53     |       (can't use useradd/del/modify function without offline option.)
54     |       with other profile, only CAP_MAC_OVERRIDE capability is removed.
55     |
56     |       For this, gumd launcher was changed to systemd.
57     |
58     |       Change-Id: Ic95fceed41afc41e37e93606c3abf830536ac7d6
59     |       Signed-off-by: Yunmi Ha <yunmi.ha@samsung.com>
60 */
61     m_offline = true;
62
63     bool ret = m_runner.userCreate(m_userName, m_userType, m_offline, m_uid, m_gid);
64     RUNNER_ASSERT_MSG(ret, "Failed to add user");
65     RUNNER_ASSERT_MSG(m_uid != 0, "Something strange happened during user creation. uid == 0.");
66     RUNNER_ASSERT_MSG(m_gid != 0, "Something strange happened during user creation. gid == 0.");
67 }
68
69 void TemporaryTestUser::remove(void)
70 {
71     if (m_uid == 0)
72         return;
73
74     m_runner.userRemove(m_uid, m_offline);
75     m_uid = m_gid = 0;
76 }
77
78 TemporaryTestUser::~TemporaryTestUser()
79 {
80     this->remove();
81 }
82
83 TemporaryTestUser::GumdRunner TemporaryTestUser::m_runner = TemporaryTestUser::GumdRunner();
84
85 TemporaryTestUser::GumdRunner::GumdRunner()
86 {
87     int sock[2];
88     int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
89     RUNNER_ASSERT_MSG(ret != -1, "socketpair() failed");
90
91     pid_t pid = fork();
92     RUNNER_ASSERT_MSG(pid != -1, "fork() failed");
93     if (pid) { // parent
94         m_sock = sock[0];
95         close(sock[1]);
96         return;
97     } else { // child
98         m_sock = sock[1];
99         close(sock[0]);
100         prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); // Don't outlive parent process
101         run(); // Never returns
102     }
103 }
104
105 TemporaryTestUser::GumdRunner::~GumdRunner()
106 {
107     close(m_sock);
108 }
109
110 bool TemporaryTestUser::GumdRunner::userCreate(std::string userName,
111     GumUserType userType, bool offline, uid_t &uid, gid_t &gid)
112 {
113     put(static_cast<int>(opType::USER_CREATE));
114     put(userName.size());
115     put(userName.c_str(), userName.size());
116     put(userType);
117     put(offline);
118
119     bool ret = get<bool>();
120     if (ret) {
121         uid = get<uid_t>();
122         gid = get<gid_t>();
123     }
124     return ret;
125 }
126
127 bool TemporaryTestUser::GumdRunner::userRemove(uid_t uid, bool offline)
128 {
129     put(static_cast<int>(opType::USER_REMOVE));
130     put(uid);
131     put(offline);
132     return get<bool>();
133 }
134
135
136 void TemporaryTestUser::GumdRunner::run()
137 {
138     DEFINE_SMARTPTR(g_object_unref, GumUser, GumUserPtr);
139
140     while (true) {
141         switch(static_cast<opType>(get<int>())) {
142         case opType::USER_CREATE:
143             {
144                 size_t userNameLen = get<size_t>();
145                 std::unique_ptr<char[]> userNamePtr(new char[userNameLen + 1]);
146                 get(userNamePtr.get(), userNameLen);
147                 userNamePtr[userNameLen] = '\0';
148                 GumUserType userType = get<GumUserType>();
149                 bool offline = get<bool>();
150
151                 bool result = false;
152                 uid_t uid;
153                 gid_t gid;
154
155                 GumUserPtr userPtr(gum_user_create_sync(offline));
156                 if (userPtr) {
157                     g_object_set(G_OBJECT(userPtr.get()),
158                         "username", userNamePtr.get(),
159                         "usertype", userType,
160                         nullptr);
161                     gboolean ret = gum_user_add_sync(userPtr.get());
162                     if (ret == TRUE) {
163                         g_object_get(G_OBJECT(userPtr.get()), "uid", &uid, nullptr);
164                         g_object_get(G_OBJECT(userPtr.get()), "gid", &gid, nullptr);
165                         result = true;
166                     }
167                 }
168
169                 put(result);
170                 if (result) {
171                     put(uid);
172                     put(gid);
173                 }
174             }
175             break;
176
177         case opType::USER_REMOVE:
178             {
179                 uid_t uid = get<uid_t>();
180                 bool offline = get<bool>();
181                 bool result = false;
182
183                 GumUserPtr userPtr(gum_user_get_sync(uid, offline));
184                 if (userPtr) {
185                     gboolean ret = gum_user_delete_sync(userPtr.get(), TRUE);
186                     result = (ret == TRUE);
187                 }
188                 put(static_cast<bool>(result));
189             }
190             break;
191         }
192     }
193 }
194
195 void TemporaryTestUser::GumdRunner::get(void *buf, size_t cnt)
196 {
197     int ret;
198     for (size_t pos = 0; pos < cnt; pos += ret) {
199         ret = TEMP_FAILURE_RETRY(
200             read(m_sock, static_cast<char *>(buf) + pos, cnt - pos));
201         RUNNER_ASSERT_MSG(ret != -1, "read() failed");
202     }
203 }
204
205 void TemporaryTestUser::GumdRunner::put(const void *buf, size_t cnt)
206 {
207     int ret;
208     for (size_t pos = 0; pos < cnt; pos += ret) {
209         ret = TEMP_FAILURE_RETRY(
210             write(m_sock, static_cast<const char *>(buf) + pos, cnt - pos));
211         RUNNER_ASSERT_MSG(ret != -1, "write() failed");
212     }
213 }
214
215 template<typename T>
216 T TemporaryTestUser::GumdRunner::get()
217 {
218     T x;
219     get(&x, sizeof(x));
220     return std::move(x);
221 }
222
223 template<typename T>
224 void TemporaryTestUser::GumdRunner::put(const T x)
225 {
226     put(&x, sizeof(x));
227 }