14fbcbf87c6632d572d5a3c90b1ce53db6496cc4
[platform/core/security/security-manager.git] / src / client / client-security-manager.cpp
1 /*
2  *  Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Rafal Krypa <r.krypa@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  *
18  *      Security Manager library header
19  */
20 /*
21  * @file        client-security-manager.cpp
22  * @author      Pawel Polawski <p.polawski@samsung.com>
23  * @author      Rafal Krypa <r.krypa@samsung.com>
24  * @version     1.0
25  * @brief       This file contain client side implementation of security-manager API
26  */
27
28 #include <cstdio>
29 #include <utility>
30
31 #include <unistd.h>
32 #include <grp.h>
33 #include <dirent.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/xattr.h>
37 #include <sys/smack.h>
38 #include <sys/capability.h>
39
40 #include <dpl/log/log.h>
41 #include <dpl/exception.h>
42
43 #include <message-buffer.h>
44 #include <client-common.h>
45 #include <protocols.h>
46 #include <smack-common.h>
47
48 #include <security-manager.h>
49
50
51
52 SECURITY_MANAGER_API
53 int security_manager_app_inst_req_new(app_inst_req **pp_req)
54 {
55     if (!pp_req)
56         return SECURITY_MANAGER_ERROR_INPUT_PARAM;
57
58     try {
59         *pp_req = new app_inst_req;
60     } catch (std::bad_alloc& ex) {
61         return SECURITY_MANAGER_ERROR_MEMORY;
62     }
63     (*pp_req)->uid = 0;
64
65     return SECURITY_MANAGER_SUCCESS;
66 }
67
68 SECURITY_MANAGER_API
69 void security_manager_app_inst_req_free(app_inst_req *p_req)
70 {
71     delete p_req;
72 }
73
74 SECURITY_MANAGER_API
75 int security_manager_app_inst_req_set_uid(app_inst_req *p_req,
76                                           const uid_t uid)
77 {
78     if (!p_req)
79         return SECURITY_MANAGER_ERROR_INPUT_PARAM;
80
81     p_req->uid = uid;
82
83     return SECURITY_MANAGER_SUCCESS;
84 }
85
86 SECURITY_MANAGER_API
87 int security_manager_app_inst_req_set_app_id(app_inst_req *p_req, const char *app_id)
88 {
89     if (!p_req || !app_id)
90         return SECURITY_MANAGER_ERROR_INPUT_PARAM;
91
92     p_req->appId = app_id;
93
94     return SECURITY_MANAGER_SUCCESS;
95 }
96
97 SECURITY_MANAGER_API
98 int security_manager_app_inst_req_set_pkg_id(app_inst_req *p_req, const char *pkg_id)
99 {
100     if (!p_req || !pkg_id)
101         return SECURITY_MANAGER_ERROR_INPUT_PARAM;
102
103     p_req->pkgId = pkg_id;
104
105     return SECURITY_MANAGER_SUCCESS;
106 }
107
108 SECURITY_MANAGER_API
109 int security_manager_app_inst_req_add_privilege(app_inst_req *p_req, const char *privilege)
110 {
111     if (!p_req || !privilege)
112         return SECURITY_MANAGER_ERROR_INPUT_PARAM;
113
114     p_req->privileges.push_back(privilege);
115
116     return SECURITY_MANAGER_SUCCESS;
117 }
118
119 SECURITY_MANAGER_API
120 int security_manager_app_inst_req_add_path(app_inst_req *p_req, const char *path, const int path_type)
121 {
122     if (!p_req || !path || (path_type < 0) || (path_type >= SECURITY_MANAGER_ENUM_END))
123         return SECURITY_MANAGER_ERROR_INPUT_PARAM;
124
125     p_req->appPaths.push_back(std::make_pair(path, path_type));
126
127     return SECURITY_MANAGER_SUCCESS;
128 }
129
130 SECURITY_MANAGER_API
131 int security_manager_app_install(const app_inst_req *p_req)
132 {
133     using namespace SecurityManager;
134     MessageBuffer send, recv;
135
136     return try_catch([&] {
137         //checking parameters
138         if (!p_req)
139             return SECURITY_MANAGER_ERROR_INPUT_PARAM;
140         if (p_req->appId.empty() || p_req->pkgId.empty())
141             return SECURITY_MANAGER_ERROR_REQ_NOT_COMPLETE;
142
143         //put data into buffer
144         Serialization::Serialize(send, (int)SecurityModuleCall::APP_INSTALL);
145         Serialization::Serialize(send, p_req->appId);
146         Serialization::Serialize(send, p_req->pkgId);
147         Serialization::Serialize(send, p_req->privileges);
148         Serialization::Serialize(send, p_req->appPaths);
149         Serialization::Serialize(send, p_req->uid);
150
151         //send buffer to server
152         int retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv);
153         if (retval != SECURITY_MANAGER_API_SUCCESS) {
154             LogError("Error in sendToServer. Error code: " << retval);
155             return SECURITY_MANAGER_ERROR_UNKNOWN;
156         }
157
158         //receive response from server
159         Deserialization::Deserialize(recv, retval);
160         switch(retval) {
161             case SECURITY_MANAGER_API_SUCCESS:
162                 return SECURITY_MANAGER_SUCCESS;
163             case SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED:
164                 return SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED;
165             default:
166                 return SECURITY_MANAGER_ERROR_UNKNOWN;
167         }
168
169     });
170 }
171
172 SECURITY_MANAGER_API
173 int security_manager_app_uninstall(const app_inst_req *p_req)
174 {
175     using namespace SecurityManager;
176     MessageBuffer send, recv;
177
178     return try_catch([&] {
179         //checking parameters
180         if (!p_req)
181             return SECURITY_MANAGER_ERROR_INPUT_PARAM;
182         if (p_req->appId.empty())
183             return SECURITY_MANAGER_ERROR_REQ_NOT_COMPLETE;
184
185         //put data into buffer
186         Serialization::Serialize(send, (int)SecurityModuleCall::APP_UNINSTALL);
187         Serialization::Serialize(send, p_req->appId);
188
189         //send buffer to server
190         int retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv);
191         if (retval != SECURITY_MANAGER_API_SUCCESS) {
192             LogError("Error in sendToServer. Error code: " << retval);
193             return SECURITY_MANAGER_ERROR_UNKNOWN;
194         }
195
196         //receive response from server
197         Deserialization::Deserialize(recv, retval);
198         if (retval != SECURITY_MANAGER_API_SUCCESS)
199             return SECURITY_MANAGER_ERROR_UNKNOWN;
200
201         return SECURITY_MANAGER_SUCCESS;;
202     });
203 }
204
205 SECURITY_MANAGER_API
206 int security_manager_get_app_pkgid(char **pkg_id, const char *app_id)
207 {
208     using namespace SecurityManager;
209     MessageBuffer send, recv;
210
211     LogDebug("security_manager_get_app_pkgid() called");
212
213     return try_catch([&] {
214         //checking parameters
215
216         if (app_id == NULL) {
217             LogError("security_manager_app_get_pkgid: app_id is NULL");
218             return SECURITY_MANAGER_ERROR_INPUT_PARAM;
219         }
220
221         if (pkg_id == NULL) {
222             LogError("security_manager_app_get_pkgid: pkg_id is NULL");
223             return SECURITY_MANAGER_ERROR_INPUT_PARAM;
224         }
225
226         //put data into buffer
227         Serialization::Serialize(send, static_cast<int>(SecurityModuleCall::APP_GET_PKGID));
228         Serialization::Serialize(send, std::string(app_id));
229
230         //send buffer to server
231         int retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv);
232         if (retval != SECURITY_MANAGER_API_SUCCESS) {
233             LogDebug("Error in sendToServer. Error code: " << retval);
234             return SECURITY_MANAGER_ERROR_UNKNOWN;
235         }
236
237         //receive response from server
238         Deserialization::Deserialize(recv, retval);
239         if (retval != SECURITY_MANAGER_API_SUCCESS)
240             return SECURITY_MANAGER_ERROR_UNKNOWN;
241
242         std::string pkgIdString;
243         Deserialization::Deserialize(recv, pkgIdString);
244         if (pkgIdString.empty()) {
245             LogError("Unexpected empty pkgId");
246             return SECURITY_MANAGER_ERROR_UNKNOWN;
247         }
248
249         *pkg_id = strdup(pkgIdString.c_str());
250         if (*pkg_id == NULL) {
251             LogError("Failed to allocate memory for pkgId");
252             return SECURITY_MANAGER_ERROR_MEMORY;
253         }
254
255         return SECURITY_MANAGER_SUCCESS;
256     });
257 }
258
259 static bool setup_smack(const char *label)
260 {
261     int labelSize = strlen(label);
262
263     // Set Smack label for open socket file descriptors
264
265     std::unique_ptr<DIR, std::function<int(DIR*)>> dir(
266         opendir("/proc/self/fd"), closedir);
267     if (!dir.get()) {
268         LogError("Unable to read list of open file descriptors: " <<
269             strerror(errno));
270         return SECURITY_MANAGER_ERROR_UNKNOWN;
271     }
272
273     do {
274         errno = 0;
275         struct dirent *dirEntry = readdir(dir.get());
276         if (dirEntry == nullptr) {
277             if (errno == 0) // NULL return value also signals end of directory
278                 break;
279
280             LogError("Unable to read list of open file descriptors: " <<
281                 strerror(errno));
282             return SECURITY_MANAGER_ERROR_UNKNOWN;
283         }
284
285         // Entries with numerical names specify file descriptors, ignore the rest
286         if (!isdigit(dirEntry->d_name[0]))
287             continue;
288
289         struct stat statBuf;
290         int fd = atoi(dirEntry->d_name);
291         int ret = fstat(fd, &statBuf);
292         if (ret != 0) {
293             LogWarning("fstat failed on file descriptor " << fd << ": " <<
294                 strerror(errno));
295             continue;
296         }
297         if (S_ISSOCK(statBuf.st_mode)) {
298             ret = fsetxattr(fd, XATTR_NAME_SMACKIPIN, label, labelSize, 0);
299             if (ret != 0) {
300                 LogError("Setting Smack label failed on file descriptor " <<
301                     fd << ": " << strerror(errno));
302                 return SECURITY_MANAGER_ERROR_UNKNOWN;
303             }
304
305             ret = fsetxattr(fd, XATTR_NAME_SMACKIPOUT, label, labelSize, 0);
306             if (ret != 0) {
307                 LogError("Setting Smack label failed on file descriptor " <<
308                     fd << ": " << strerror(errno));
309                 return SECURITY_MANAGER_ERROR_UNKNOWN;
310             }
311         }
312     } while (true);
313
314     // Set Smack label of current process
315     smack_set_label_for_self(label);
316
317     return SECURITY_MANAGER_SUCCESS;
318 }
319
320 SECURITY_MANAGER_API
321 int security_manager_set_process_label_from_appid(const char *app_id)
322 {
323     char *pkg_id;
324     int ret;
325     std::string appLabel;
326
327     LogDebug("security_manager_set_process_label_from_appid() called");
328
329     if (smack_smackfs_path() == NULL)
330         return SECURITY_MANAGER_SUCCESS;
331
332     ret = security_manager_get_app_pkgid(&pkg_id, app_id);
333     if (ret != SECURITY_MANAGER_SUCCESS) {
334         return ret;
335     }
336
337     if (SecurityManager::generateAppLabel(std::string(pkg_id), appLabel)) {
338         ret = setup_smack(appLabel.c_str());
339         if (ret != SECURITY_MANAGER_SUCCESS) {
340             LogError("Failed to set smack label " << appLabel << " for current process");
341         }
342     }
343     else {
344         ret = SECURITY_MANAGER_ERROR_UNKNOWN;
345     }
346
347     free(pkg_id);
348     return ret;
349 }
350
351 SECURITY_MANAGER_API
352 int security_manager_set_process_groups_from_appid(const char *app_id)
353 {
354     using namespace SecurityManager;
355     MessageBuffer send, recv;
356     int ret;
357
358     LogDebug("security_manager_set_process_groups_from_appid() called");
359
360     return try_catch([&] {
361         //checking parameters
362
363         if (app_id == nullptr) {
364             LogError("app_id is NULL");
365             return SECURITY_MANAGER_ERROR_INPUT_PARAM;
366         }
367
368         //put data into buffer
369         Serialization::Serialize(send, static_cast<int>(SecurityModuleCall::APP_GET_GROUPS));
370         Serialization::Serialize(send, std::string(app_id));
371
372         //send buffer to server
373         int retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv);
374         if (retval != SECURITY_MANAGER_API_SUCCESS) {
375             LogDebug("Error in sendToServer. Error code: " << retval);
376             return SECURITY_MANAGER_ERROR_UNKNOWN;
377         }
378
379         //receive response from server
380         Deserialization::Deserialize(recv, retval);
381         if (retval != SECURITY_MANAGER_API_SUCCESS)
382             return SECURITY_MANAGER_ERROR_UNKNOWN;
383
384         //How many new groups?
385         int newGroupsCnt;
386         Deserialization::Deserialize(recv, newGroupsCnt);
387
388         //And how many groups do we belong to already?
389         int oldGroupsCnt;
390         ret = getgroups(0, nullptr);
391         if (ret == -1) {
392             LogError("Unable to get list of current supplementary groups: " <<
393                 strerror(errno));
394             return SECURITY_MANAGER_ERROR_UNKNOWN;
395         }
396         oldGroupsCnt = ret;
397
398         //Allocate an array for both old and new groups gids
399         std::unique_ptr<gid_t[]> groups(new gid_t[oldGroupsCnt + newGroupsCnt]);
400         if (!groups.get()) {
401             LogError("Memory allocation failed.");
402             return SECURITY_MANAGER_ERROR_MEMORY;
403         }
404
405         //Get the old groups from process
406         ret = getgroups(oldGroupsCnt, groups.get());
407         if (ret == -1) {
408             LogError("Unable to get list of current supplementary groups: " <<
409                 strerror(errno));
410             return SECURITY_MANAGER_ERROR_UNKNOWN;
411         }
412
413         //Get the new groups from server response
414         for (int i = 0; i < newGroupsCnt; ++i) {
415             gid_t gid;
416             Deserialization::Deserialize(recv, gid);
417             groups.get()[oldGroupsCnt + i] = gid;
418             LogDebug("Adding process to group " << gid);
419         }
420
421         //Apply the modified groups list
422         ret = setgroups(oldGroupsCnt + newGroupsCnt, groups.get());
423         if (ret == -1) {
424             LogError("Unable to get list of current supplementary groups: " <<
425                 strerror(errno));
426             return SECURITY_MANAGER_ERROR_UNKNOWN;
427         }
428
429         return SECURITY_MANAGER_SUCCESS;
430     });
431 }
432
433 SECURITY_MANAGER_API
434 int security_manager_drop_process_privileges(void)
435 {
436     LogDebug("security_manager_drop_process_privileges() called");
437
438     int ret;
439     cap_t cap = cap_init();
440     if (!cap) {
441         LogError("Unable to allocate capability object");
442         return SECURITY_MANAGER_ERROR_MEMORY;
443     }
444
445     ret = cap_clear(cap);
446     if (ret) {
447         LogError("Unable to initialize capability object");
448         cap_free(cap);
449         return SECURITY_MANAGER_ERROR_UNKNOWN;
450     }
451
452     ret = cap_set_proc(cap);
453     if (ret) {
454         LogError("Unable to drop process capabilities");
455         cap_free(cap);
456         return SECURITY_MANAGER_ERROR_UNKNOWN;
457     }
458
459     cap_free(cap);
460     return SECURITY_MANAGER_SUCCESS;
461 }
462
463 SECURITY_MANAGER_API
464 int security_manager_prepare_app(const char *app_id)
465 {
466     LogDebug("security_manager_prepare_app() called");
467     int ret;
468
469     ret = security_manager_set_process_label_from_appid(app_id);
470     if (ret != SECURITY_MANAGER_SUCCESS)
471         return ret;
472
473     ret = security_manager_set_process_groups_from_appid(app_id);
474     if (ret != SECURITY_MANAGER_SUCCESS)
475         return ret;
476
477     ret = security_manager_drop_process_privileges();
478     return ret;
479 }