2 * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Rafal Krypa <r.krypa@samsung.com>
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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
18 * Security Manager library header
21 * @file client-security-manager.cpp
22 * @author Pawel Polawski <p.polawski@samsung.com>
23 * @author Rafal Krypa <r.krypa@samsung.com>
25 * @brief This file contain client side implementation of security-manager API
34 #include <sys/types.h>
36 #include <sys/xattr.h>
37 #include <sys/smack.h>
38 #include <sys/capability.h>
40 #include <dpl/log/log.h>
41 #include <dpl/exception.h>
43 #include <message-buffer.h>
44 #include <client-common.h>
45 #include <protocols.h>
46 #include <smack-common.h>
47 #include <service_impl.h>
48 #include <file-lock.h>
50 #include <security-manager.h>
53 * Mapping of lib_retcode error codes to theirs strings equivalents
55 static std::map<enum lib_retcode, std::string> lib_retcode_string_map = {
56 {SECURITY_MANAGER_SUCCESS, "Success"},
57 {SECURITY_MANAGER_ERROR_UNKNOWN, "Unknown error"},
58 {SECURITY_MANAGER_ERROR_INPUT_PARAM, "Invalid function parameter was given"},
59 {SECURITY_MANAGER_ERROR_MEMORY, "Memory allocation error"},
60 {SECURITY_MANAGER_ERROR_REQ_NOT_COMPLETE, "Incomplete data in application request"},
61 {SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED, "User does not have sufficient "
62 "rigths to perform an operation"}
66 const char *security_manager_strerror(enum lib_retcode rc)
69 return lib_retcode_string_map.at(rc).c_str();
70 } catch (const std::out_of_range &e) {
71 return "Unknown error code";
76 int security_manager_app_inst_req_new(app_inst_req **pp_req)
79 return SECURITY_MANAGER_ERROR_INPUT_PARAM;
82 *pp_req = new app_inst_req;
83 } catch (std::bad_alloc& ex) {
84 return SECURITY_MANAGER_ERROR_MEMORY;
86 (*pp_req)->uid = geteuid();
88 return SECURITY_MANAGER_SUCCESS;
92 void security_manager_app_inst_req_free(app_inst_req *p_req)
98 int security_manager_app_inst_req_set_uid(app_inst_req *p_req,
102 return SECURITY_MANAGER_ERROR_INPUT_PARAM;
106 return SECURITY_MANAGER_SUCCESS;
110 int security_manager_app_inst_req_set_app_id(app_inst_req *p_req, const char *app_id)
112 if (!p_req || !app_id)
113 return SECURITY_MANAGER_ERROR_INPUT_PARAM;
115 p_req->appId = app_id;
117 return SECURITY_MANAGER_SUCCESS;
121 int security_manager_app_inst_req_set_pkg_id(app_inst_req *p_req, const char *pkg_id)
123 if (!p_req || !pkg_id)
124 return SECURITY_MANAGER_ERROR_INPUT_PARAM;
126 p_req->pkgId = pkg_id;
128 return SECURITY_MANAGER_SUCCESS;
132 int security_manager_app_inst_req_add_privilege(app_inst_req *p_req, const char *privilege)
134 if (!p_req || !privilege)
135 return SECURITY_MANAGER_ERROR_INPUT_PARAM;
137 p_req->privileges.push_back(privilege);
139 return SECURITY_MANAGER_SUCCESS;
143 int security_manager_app_inst_req_add_path(app_inst_req *p_req, const char *path, const int path_type)
145 if (!p_req || !path || (path_type < 0) || (path_type >= SECURITY_MANAGER_ENUM_END))
146 return SECURITY_MANAGER_ERROR_INPUT_PARAM;
148 p_req->appPaths.push_back(std::make_pair(path, path_type));
150 return SECURITY_MANAGER_SUCCESS;
154 int security_manager_app_install(const app_inst_req *p_req)
156 using namespace SecurityManager;
158 return try_catch([&] {
159 //checking parameters
161 return SECURITY_MANAGER_ERROR_INPUT_PARAM;
162 if (p_req->appId.empty() || p_req->pkgId.empty())
163 return SECURITY_MANAGER_ERROR_REQ_NOT_COMPLETE;
169 SecurityManager::FileLocker serviceLock(SecurityManager::SERVICE_LOCK_FILE);
170 if ((offlineMode = serviceLock.Locked())) {
171 LogInfo("Working in offline mode.");
172 retval = SecurityManager::ServiceImpl::appInstall(*p_req, geteuid());
174 } catch (const SecurityManager::FileLocker::Exception::Base &e) {
178 MessageBuffer send, recv;
180 //put data into buffer
181 Serialization::Serialize(send, (int)SecurityModuleCall::APP_INSTALL);
182 Serialization::Serialize(send, p_req->appId);
183 Serialization::Serialize(send, p_req->pkgId);
184 Serialization::Serialize(send, p_req->privileges);
185 Serialization::Serialize(send, p_req->appPaths);
186 Serialization::Serialize(send, p_req->uid);
188 //send buffer to server
189 retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv);
190 if (retval != SECURITY_MANAGER_API_SUCCESS) {
191 LogError("Error in sendToServer. Error code: " << retval);
192 return SECURITY_MANAGER_ERROR_UNKNOWN;
195 //receive response from server
196 Deserialization::Deserialize(recv, retval);
199 case SECURITY_MANAGER_API_SUCCESS:
200 return SECURITY_MANAGER_SUCCESS;
201 case SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED:
202 return SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED;
203 case SECURITY_MANAGER_API_ERROR_INPUT_PARAM:
204 return SECURITY_MANAGER_ERROR_INPUT_PARAM;
206 return SECURITY_MANAGER_ERROR_UNKNOWN;
213 int security_manager_app_uninstall(const app_inst_req *p_req)
215 using namespace SecurityManager;
216 MessageBuffer send, recv;
218 return try_catch([&] {
219 //checking parameters
221 return SECURITY_MANAGER_ERROR_INPUT_PARAM;
222 if (p_req->appId.empty())
223 return SECURITY_MANAGER_ERROR_REQ_NOT_COMPLETE;
225 //put data into buffer
226 Serialization::Serialize(send, (int)SecurityModuleCall::APP_UNINSTALL);
227 Serialization::Serialize(send, p_req->appId);
229 //send buffer to server
230 int retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv);
231 if (retval != SECURITY_MANAGER_API_SUCCESS) {
232 LogError("Error in sendToServer. Error code: " << retval);
233 return SECURITY_MANAGER_ERROR_UNKNOWN;
236 //receive response from server
237 Deserialization::Deserialize(recv, retval);
238 if (retval != SECURITY_MANAGER_API_SUCCESS)
239 return SECURITY_MANAGER_ERROR_UNKNOWN;
241 return SECURITY_MANAGER_SUCCESS;;
246 int security_manager_get_app_pkgid(char **pkg_id, const char *app_id)
248 using namespace SecurityManager;
249 MessageBuffer send, recv;
251 LogDebug("security_manager_get_app_pkgid() called");
253 return try_catch([&] {
254 //checking parameters
256 if (app_id == NULL) {
257 LogError("security_manager_app_get_pkgid: app_id is NULL");
258 return SECURITY_MANAGER_ERROR_INPUT_PARAM;
261 if (pkg_id == NULL) {
262 LogError("security_manager_app_get_pkgid: pkg_id is NULL");
263 return SECURITY_MANAGER_ERROR_INPUT_PARAM;
266 //put data into buffer
267 Serialization::Serialize(send, static_cast<int>(SecurityModuleCall::APP_GET_PKGID));
268 Serialization::Serialize(send, std::string(app_id));
270 //send buffer to server
271 int retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv);
272 if (retval != SECURITY_MANAGER_API_SUCCESS) {
273 LogDebug("Error in sendToServer. Error code: " << retval);
274 return SECURITY_MANAGER_ERROR_UNKNOWN;
277 //receive response from server
278 Deserialization::Deserialize(recv, retval);
279 if (retval != SECURITY_MANAGER_API_SUCCESS)
280 return SECURITY_MANAGER_ERROR_UNKNOWN;
282 std::string pkgIdString;
283 Deserialization::Deserialize(recv, pkgIdString);
284 if (pkgIdString.empty()) {
285 LogError("Unexpected empty pkgId");
286 return SECURITY_MANAGER_ERROR_UNKNOWN;
289 *pkg_id = strdup(pkgIdString.c_str());
290 if (*pkg_id == NULL) {
291 LogError("Failed to allocate memory for pkgId");
292 return SECURITY_MANAGER_ERROR_MEMORY;
295 return SECURITY_MANAGER_SUCCESS;
299 static bool setup_smack(const char *label)
301 int labelSize = strlen(label);
303 // Set Smack label for open socket file descriptors
305 std::unique_ptr<DIR, std::function<int(DIR*)>> dir(
306 opendir("/proc/self/fd"), closedir);
308 LogError("Unable to read list of open file descriptors: " <<
310 return SECURITY_MANAGER_ERROR_UNKNOWN;
315 struct dirent *dirEntry = readdir(dir.get());
316 if (dirEntry == nullptr) {
317 if (errno == 0) // NULL return value also signals end of directory
320 LogError("Unable to read list of open file descriptors: " <<
322 return SECURITY_MANAGER_ERROR_UNKNOWN;
325 // Entries with numerical names specify file descriptors, ignore the rest
326 if (!isdigit(dirEntry->d_name[0]))
330 int fd = atoi(dirEntry->d_name);
331 int ret = fstat(fd, &statBuf);
333 LogWarning("fstat failed on file descriptor " << fd << ": " <<
337 if (S_ISSOCK(statBuf.st_mode)) {
338 ret = fsetxattr(fd, XATTR_NAME_SMACKIPIN, label, labelSize, 0);
340 LogError("Setting Smack label failed on file descriptor " <<
341 fd << ": " << strerror(errno));
342 return SECURITY_MANAGER_ERROR_UNKNOWN;
345 ret = fsetxattr(fd, XATTR_NAME_SMACKIPOUT, label, labelSize, 0);
347 LogError("Setting Smack label failed on file descriptor " <<
348 fd << ": " << strerror(errno));
349 return SECURITY_MANAGER_ERROR_UNKNOWN;
354 // Set Smack label of current process
355 smack_set_label_for_self(label);
357 return SECURITY_MANAGER_SUCCESS;
361 int security_manager_set_process_label_from_appid(const char *app_id)
365 std::string appLabel;
367 LogDebug("security_manager_set_process_label_from_appid() called");
369 if (smack_smackfs_path() == NULL)
370 return SECURITY_MANAGER_SUCCESS;
372 ret = security_manager_get_app_pkgid(&pkg_id, app_id);
373 if (ret != SECURITY_MANAGER_SUCCESS) {
377 if (SecurityManager::generateAppLabel(std::string(pkg_id), appLabel)) {
378 ret = setup_smack(appLabel.c_str());
379 if (ret != SECURITY_MANAGER_SUCCESS) {
380 LogError("Failed to set smack label " << appLabel << " for current process");
384 ret = SECURITY_MANAGER_ERROR_UNKNOWN;
392 int security_manager_set_process_groups_from_appid(const char *app_id)
394 using namespace SecurityManager;
395 MessageBuffer send, recv;
398 LogDebug("security_manager_set_process_groups_from_appid() called");
400 return try_catch([&] {
401 //checking parameters
403 if (app_id == nullptr) {
404 LogError("app_id is NULL");
405 return SECURITY_MANAGER_ERROR_INPUT_PARAM;
408 //put data into buffer
409 Serialization::Serialize(send, static_cast<int>(SecurityModuleCall::APP_GET_GROUPS));
410 Serialization::Serialize(send, std::string(app_id));
412 //send buffer to server
413 int retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv);
414 if (retval != SECURITY_MANAGER_API_SUCCESS) {
415 LogDebug("Error in sendToServer. Error code: " << retval);
416 return SECURITY_MANAGER_ERROR_UNKNOWN;
419 //receive response from server
420 Deserialization::Deserialize(recv, retval);
421 if (retval != SECURITY_MANAGER_API_SUCCESS)
422 return SECURITY_MANAGER_ERROR_UNKNOWN;
424 //How many new groups?
426 Deserialization::Deserialize(recv, newGroupsCnt);
428 //And how many groups do we belong to already?
430 ret = getgroups(0, nullptr);
432 LogError("Unable to get list of current supplementary groups: " <<
434 return SECURITY_MANAGER_ERROR_UNKNOWN;
438 //Allocate an array for both old and new groups gids
439 std::unique_ptr<gid_t[]> groups(new gid_t[oldGroupsCnt + newGroupsCnt]);
441 LogError("Memory allocation failed.");
442 return SECURITY_MANAGER_ERROR_MEMORY;
445 //Get the old groups from process
446 ret = getgroups(oldGroupsCnt, groups.get());
448 LogError("Unable to get list of current supplementary groups: " <<
450 return SECURITY_MANAGER_ERROR_UNKNOWN;
453 //Get the new groups from server response
454 for (int i = 0; i < newGroupsCnt; ++i) {
456 Deserialization::Deserialize(recv, gid);
457 groups.get()[oldGroupsCnt + i] = gid;
458 LogDebug("Adding process to group " << gid);
461 //Apply the modified groups list
462 ret = setgroups(oldGroupsCnt + newGroupsCnt, groups.get());
464 LogError("Unable to get list of current supplementary groups: " <<
466 return SECURITY_MANAGER_ERROR_UNKNOWN;
469 return SECURITY_MANAGER_SUCCESS;
474 int security_manager_drop_process_privileges(void)
476 LogDebug("security_manager_drop_process_privileges() called");
479 cap_t cap = cap_init();
481 LogError("Unable to allocate capability object");
482 return SECURITY_MANAGER_ERROR_MEMORY;
485 ret = cap_clear(cap);
487 LogError("Unable to initialize capability object");
489 return SECURITY_MANAGER_ERROR_UNKNOWN;
492 ret = cap_set_proc(cap);
494 LogError("Unable to drop process capabilities");
496 return SECURITY_MANAGER_ERROR_UNKNOWN;
500 return SECURITY_MANAGER_SUCCESS;
504 int security_manager_prepare_app(const char *app_id)
506 LogDebug("security_manager_prepare_app() called");
509 ret = security_manager_set_process_label_from_appid(app_id);
510 if (ret != SECURITY_MANAGER_SUCCESS)
513 ret = security_manager_set_process_groups_from_appid(app_id);
514 if (ret != SECURITY_MANAGER_SUCCESS)
517 ret = security_manager_drop_process_privileges();
522 int security_manager_user_req_new(user_req **pp_req)
525 return SECURITY_MANAGER_ERROR_INPUT_PARAM;
527 *pp_req = new user_req;
528 } catch (std::bad_alloc& ex) {
529 return SECURITY_MANAGER_ERROR_MEMORY;
531 return SECURITY_MANAGER_SUCCESS;
535 void security_manager_user_req_free(user_req *p_req)
541 int security_manager_user_req_set_uid(user_req *p_req, uid_t uid)
544 return SECURITY_MANAGER_ERROR_INPUT_PARAM;
548 return SECURITY_MANAGER_SUCCESS;
552 int security_manager_user_req_set_user_type(user_req *p_req, security_manager_user_type utype)
555 return SECURITY_MANAGER_ERROR_INPUT_PARAM;
557 p_req->utype = static_cast<int>(utype);
559 return SECURITY_MANAGER_SUCCESS;
563 int security_manager_user_add(const user_req *p_req)
567 return SECURITY_MANAGER_ERROR_UNKNOWN;
571 int security_manager_user_delete(const user_req *p_req)
575 return SECURITY_MANAGER_ERROR_UNKNOWN;