000410fb9a3fcc854b9216e1015267d72ed10580
[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
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     if (m_creatorPid == getpid())
81         remove();
82 }
83
84 TemporaryTestUser::GumdRunner TemporaryTestUser::m_runner = TemporaryTestUser::GumdRunner();
85
86 TemporaryTestUser::GumdRunner::GumdRunner()
87 {
88     int sock[2];
89     int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
90     RUNNER_ASSERT_MSG(ret != -1, "socketpair() failed");
91
92     pid_t pid = fork();
93     RUNNER_ASSERT_MSG(pid != -1, "fork() failed");
94     if (pid) { // parent
95         m_sock = sock[0];
96         close(sock[1]);
97         return;
98     } else { // child
99         m_sock = sock[1];
100         close(sock[0]);
101         prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0); // Don't outlive parent process
102         run(); // Never returns
103     }
104 }
105
106 TemporaryTestUser::GumdRunner::~GumdRunner()
107 {
108     close(m_sock);
109 }
110
111 bool TemporaryTestUser::GumdRunner::userCreate(std::string userName,
112     GumUserType userType, bool offline, uid_t &uid, gid_t &gid)
113 {
114     put(static_cast<int>(opType::USER_CREATE));
115     put(userName.size());
116     put(userName.c_str(), userName.size());
117     put(userType);
118     put(offline);
119
120     bool ret = get<bool>();
121     if (ret) {
122         uid = get<uid_t>();
123         gid = get<gid_t>();
124     }
125     return ret;
126 }
127
128 bool TemporaryTestUser::GumdRunner::userRemove(uid_t uid, bool offline)
129 {
130     put(static_cast<int>(opType::USER_REMOVE));
131     put(uid);
132     put(offline);
133     return get<bool>();
134 }
135
136
137 void TemporaryTestUser::GumdRunner::run()
138 {
139     DEFINE_SMARTPTR(g_object_unref, GumUser, GumUserPtr);
140
141     while (true) {
142         switch(static_cast<opType>(get<int>())) {
143         case opType::USER_CREATE:
144             {
145                 size_t userNameLen = get<size_t>();
146                 std::unique_ptr<char[]> userNamePtr(new char[userNameLen + 1]);
147                 get(userNamePtr.get(), userNameLen);
148                 userNamePtr[userNameLen] = '\0';
149                 GumUserType userType = get<GumUserType>();
150                 bool offline = get<bool>();
151
152                 bool result = false;
153                 uid_t uid;
154                 gid_t gid;
155
156                 GumUserPtr userPtr(gum_user_create_sync(offline));
157                 if (userPtr) {
158                     g_object_set(G_OBJECT(userPtr.get()),
159                         "username", userNamePtr.get(),
160                         "usertype", userType,
161                         nullptr);
162                     gboolean ret = gum_user_add_sync(userPtr.get());
163                     if (ret == TRUE) {
164                         g_object_get(G_OBJECT(userPtr.get()), "uid", &uid, nullptr);
165                         g_object_get(G_OBJECT(userPtr.get()), "gid", &gid, nullptr);
166                         result = true;
167                     }
168                 }
169
170                 put(result);
171                 if (result) {
172                     put(uid);
173                     put(gid);
174                 }
175             }
176             break;
177
178         case opType::USER_REMOVE:
179             {
180                 uid_t uid = get<uid_t>();
181                 bool offline = get<bool>();
182                 bool result = false;
183
184                 GumUserPtr userPtr(gum_user_get_sync(uid, offline));
185                 if (userPtr) {
186                     gboolean ret = gum_user_delete_sync(userPtr.get(), TRUE);
187                     result = (ret == TRUE);
188                 }
189                 put(static_cast<bool>(result));
190             }
191             break;
192         }
193     }
194 }
195
196 void TemporaryTestUser::GumdRunner::get(void *buf, size_t cnt)
197 {
198     int ret;
199     for (size_t pos = 0; pos < cnt; pos += ret) {
200         ret = TEMP_FAILURE_RETRY(
201             read(m_sock, static_cast<char *>(buf) + pos, cnt - pos));
202         RUNNER_ASSERT_MSG(ret != -1, "read() failed");
203     }
204 }
205
206 void TemporaryTestUser::GumdRunner::put(const void *buf, size_t cnt)
207 {
208     int ret;
209     for (size_t pos = 0; pos < cnt; pos += ret) {
210         ret = TEMP_FAILURE_RETRY(
211             write(m_sock, static_cast<const char *>(buf) + pos, cnt - pos));
212         RUNNER_ASSERT_MSG(ret != -1, "write() failed");
213     }
214 }
215
216 template<typename T>
217 T TemporaryTestUser::GumdRunner::get()
218 {
219     T x;
220     get(&x, sizeof(x));
221     return std::move(x);
222 }
223
224 template<typename T>
225 void TemporaryTestUser::GumdRunner::put(const T x)
226 {
227     put(&x, sizeof(x));
228 }