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