2 * Copyright (c) 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
19 * @file service_impl.cpp
20 * @author Michal Witanowski <m.witanowski@samsung.com>
21 * @author Jacek Bukarewicz <j.bukarewicz@samsung.com>
22 * @author Rafal Krypa <r.krypa@samsung.com>
23 * @author Krzysztof Sasiak <k.sasiak@samsung.com>
24 * @brief Implementation of the service methods
30 #include <sys/socket.h>
35 #include <dpl/log/log.h>
36 #include <tzplatform_config.h>
38 #include "protocols.h"
39 #include "privilege_db.h"
41 #include "smack-rules.h"
42 #include "smack-labels.h"
43 #include "security-manager.h"
44 #include "zone-utils.h"
46 #include "service_impl.h"
47 #include "master-req.h"
49 namespace SecurityManager {
50 namespace ServiceImpl {
52 static const std::string ADMIN_PRIVILEGE = "http://tizen.org/privilege/systemsettings.admin";
53 static const std::string SELF_PRIVILEGE = "http://tizen.org/privilege/systemsettings";
57 static inline int validatePolicy(policy_entry &policyEntry, std::string uidStr, bool &forAdmin, CynaraAdminPolicy &cyap)
59 LogDebug("Authenticating and validating policy update request for user with id: " << uidStr);
60 LogDebug("[policy_entry] app: " << policyEntry.appId
61 << " user: " << policyEntry.user
62 << " privilege: " << policyEntry.privilege
63 << " current: " << policyEntry.currentLevel
64 << " max: " << policyEntry.maxLevel);
65 //automagically fill missing fields:
66 if (policyEntry.user.empty()) {
67 policyEntry.user = uidStr;
72 if (policyEntry.currentLevel.empty()) { //for admin
73 if (policyEntry.appId.empty()
74 || policyEntry.privilege.empty()) {
75 LogError("Bad admin update request");
76 return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
79 if (!policyEntry.maxLevel.compare(SECURITY_MANAGER_DELETE)) {
80 level = CYNARA_ADMIN_DELETE;
83 level = CynaraAdmin::getInstance().convertToPolicyType(policyEntry.maxLevel);
84 } catch (const std::out_of_range& e) {
85 LogError("policy max level cannot be: " << policyEntry.maxLevel);
86 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
91 } else if (policyEntry.maxLevel.empty()) { //for self
92 if (policyEntry.user.compare(uidStr)
93 || !policyEntry.appId.compare(SECURITY_MANAGER_ANY)
94 || !policyEntry.privilege.compare(SECURITY_MANAGER_ANY)
95 || policyEntry.appId.empty()
96 || policyEntry.privilege.empty()) {
97 LogError("Bad privacy manager update request");
98 return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
101 if (!policyEntry.currentLevel.compare(SECURITY_MANAGER_DELETE)) {
102 level = CYNARA_ADMIN_DELETE;
105 level = CynaraAdmin::getInstance().convertToPolicyType(policyEntry.currentLevel);
106 } catch (const std::out_of_range& e) {
107 LogError("policy current level cannot be: " << policyEntry.currentLevel);
108 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
113 } else { //neither => bad request
114 return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
117 if (!policyEntry.user.compare(SECURITY_MANAGER_ANY))
118 policyEntry.user = CYNARA_ADMIN_WILDCARD;
119 if (!policyEntry.privilege.compare(SECURITY_MANAGER_ANY))
120 policyEntry.privilege = CYNARA_ADMIN_WILDCARD;
122 cyap = std::move(CynaraAdminPolicy(
123 policyEntry.appId.compare(SECURITY_MANAGER_ANY) ?
124 SmackLabels::generateAppLabel(policyEntry.appId) : CYNARA_ADMIN_WILDCARD,
126 policyEntry.privilege,
128 (forAdmin)?CynaraAdmin::Buckets.at(Bucket::ADMIN):CynaraAdmin::Buckets.at(Bucket::PRIVACY_MANAGER)));
130 LogDebug("Policy update request authenticated and validated successfully");
131 return SECURITY_MANAGER_API_SUCCESS;
133 } // end of anonymous namespace
135 static uid_t getGlobalUserId(void)
137 static uid_t globaluid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
142 * Unifies user data of apps installed for all users
143 * @param uid peer's uid - may be changed during process
144 * @param cynaraUserStr string to which cynara user parameter will be put
146 static void checkGlobalUser(uid_t &uid, std::string &cynaraUserStr)
148 static uid_t globaluid = getGlobalUserId();
149 if (uid == 0 || uid == globaluid) {
151 cynaraUserStr = CYNARA_ADMIN_WILDCARD;
153 cynaraUserStr = std::to_string(static_cast<unsigned int>(uid));
156 static inline bool isSubDir(const char *parent, const char *subdir)
158 while (*parent && *subdir)
159 if (*parent++ != *subdir++)
162 return (*subdir == '/');
165 bool getPeerID(int sock, uid_t &uid, pid_t &pid)
168 socklen_t len = sizeof(cr);
170 if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &cr, &len)) {
179 static bool getUserAppDir(const uid_t &uid, std::string &userAppDir)
181 struct tzplatform_context *tz_ctx = nullptr;
183 if (tzplatform_context_create(&tz_ctx))
186 if (tzplatform_context_set_user(tz_ctx, uid)) {
187 tzplatform_context_destroy(tz_ctx);
192 enum tzplatform_variable id =
193 (uid == getGlobalUserId()) ? TZ_SYS_RW_APP : TZ_USER_APP;
194 const char *appDir = tzplatform_context_getenv(tz_ctx, id);
196 tzplatform_context_destroy(tz_ctx);
203 tzplatform_context_destroy(tz_ctx);
209 static inline bool installRequestAuthCheck(const app_inst_req &req, uid_t uid, bool &isCorrectPath, std::string &appPath)
211 std::string userHome;
212 std::string userAppDir;
213 std::stringstream correctPath;
215 if (uid != getGlobalUserId())
216 LogDebug("Installation type: single user");
218 LogDebug("Installation type: global installation");
220 if (!getUserAppDir(uid, userAppDir)) {
221 LogError("Failed getting app dir for user uid: " << uid);
225 appPath = userAppDir;
227 correctPath << userAppDir << "/" << req.pkgId << "/" << req.appId;
228 LogDebug("correctPath: " << correctPath.str());
230 for (const auto &appPath : req.appPaths) {
231 std::unique_ptr<char, std::function<void(void*)>> real_path(
232 realpath(appPath.first.c_str(), NULL), free);
233 if (!real_path.get()) {
234 LogError("realpath failed with '" << appPath.first.c_str()
235 << "' as parameter: " << strerror(errno));
238 LogDebug("Requested path is '" << appPath.first.c_str()
239 << "'. User's APPS_DIR is '" << userAppDir << "'");
240 if (!isSubDir(userAppDir.c_str(), real_path.get())) {
241 LogWarning("User's apps may have registered folders only in user's APPS_DIR");
245 if (!isSubDir(correctPath.str().c_str(), real_path.get())) {
246 LogWarning("Installation is outside correct path: " << correctPath.str());
249 isCorrectPath = true;
251 app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
252 if (pathType == SECURITY_MANAGER_PATH_PUBLIC) {
253 LogWarning("Only root can register SECURITY_MANAGER_PATH_PUBLIC path");
260 static inline bool getZoneId(std::string &zoneId)
262 if (!getZoneIdFromPid(getpid(), zoneId)) {
263 LogError("Failed to get zone ID from current PID");
267 // This function should be called under slave mode only - assumes, that we work inside zone
268 if (zoneId == ZONE_HOST) {
269 LogError("We should not run in host - refusing request");
276 int appInstall(const app_inst_req &req, uid_t uid, bool isSlave)
278 std::vector<std::string> addedPermissions;
279 std::vector<std::string> removedPermissions;
280 std::vector<std::string> pkgContents;
282 bool isCorrectPath = false;
284 std::string appLabel;
285 std::string pkgLabel;
289 if (!getZoneId(zoneId)) {
290 LogError("Failed to get Zone ID.");
291 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
296 if (uid != req.uid) {
297 LogError("User " << uid <<
298 " is denied to install application for user " << req.uid);
299 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
305 checkGlobalUser(uid, uidstr);
307 if (!installRequestAuthCheck(req, uid, isCorrectPath, appPath)) {
308 LogError("Request from uid " << uid << " for app installation denied");
309 return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
312 // create null terminated array of strings for permissions
313 std::unique_ptr<const char *[]> pp_permissions(new const char* [req.privileges.size() + 1]);
314 for (size_t i = 0; i < req.privileges.size(); ++i) {
315 LogDebug(" Permission = " << req.privileges[i]);
316 pp_permissions[i] = req.privileges[i].c_str();
318 pp_permissions[req.privileges.size()] = nullptr;
321 std::vector<std::string> oldAppPrivileges;
323 appLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(req.appId), zoneId);
324 /* NOTE: we don't use pkgLabel here, but generate it for pkgId validation */
325 pkgLabel = zoneSmackLabelGenerate(SmackLabels::generatePkgLabel(req.pkgId), zoneId);
326 LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
327 << ", uidstr " << uidstr
328 << ", app label: " << appLabel << ", pkg label: " << pkgLabel);
330 PrivilegeDb::getInstance().BeginTransaction();
332 bool ret = PrivilegeDb::getInstance().GetAppPkgId(req.appId, pkg);
333 if (ret == true && pkg != req.pkgId) {
334 LogError("Application already installed with different package id");
335 PrivilegeDb::getInstance().RollbackTransaction();
336 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
338 PrivilegeDb::getInstance().GetAppPrivileges(req.appId, uid, oldAppPrivileges);
339 PrivilegeDb::getInstance().AddApplication(req.appId, req.pkgId, uid);
340 PrivilegeDb::getInstance().UpdateAppPrivileges(req.appId, uid, req.privileges);
341 /* Get all application ids in the package to generate rules withing the package */
342 PrivilegeDb::getInstance().GetAppIdsForPkgId(req.pkgId, pkgContents);
345 int ret = MasterReq::CynaraPolicyUpdate(req.appId, uidstr, oldAppPrivileges,
347 if (ret != SECURITY_MANAGER_API_SUCCESS) {
348 PrivilegeDb::getInstance().RollbackTransaction();
349 LogError("Error while processing request on master: " << ret);
353 CynaraAdmin::getInstance().UpdateAppPolicy(appLabel, uidstr, oldAppPrivileges,
357 PrivilegeDb::getInstance().CommitTransaction();
358 LogDebug("Application installation commited to database");
359 } catch (const PrivilegeDb::Exception::IOError &e) {
360 LogError("Cannot access application database: " << e.DumpToString());
361 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
362 } catch (const PrivilegeDb::Exception::InternalError &e) {
363 PrivilegeDb::getInstance().RollbackTransaction();
364 LogError("Error while saving application info to database: " << e.DumpToString());
365 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
366 } catch (const CynaraException::Base &e) {
367 PrivilegeDb::getInstance().RollbackTransaction();
368 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
369 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
370 } catch (const SmackException::InvalidLabel &e) {
371 PrivilegeDb::getInstance().RollbackTransaction();
372 LogError("Error while generating Smack labels: " << e.DumpToString());
373 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
374 } catch (const std::bad_alloc &e) {
375 PrivilegeDb::getInstance().RollbackTransaction();
376 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
377 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
382 SmackLabels::setupCorrectPath(req.pkgId, req.appId, appPath, zoneId);
385 for (const auto &appPath : req.appPaths) {
386 const std::string &path = appPath.first;
387 app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
388 SmackLabels::setupPath(req.appId, path, pathType, zoneId);
392 LogDebug("Requesting master to add rules for new appId: " << req.appId << " with pkgId: "
393 << req.pkgId << ". Applications in package: " << pkgContents.size());
394 int ret = MasterReq::SmackInstallRules(req.appId, req.pkgId, pkgContents);
395 if (ret != SECURITY_MANAGER_API_SUCCESS) {
396 LogError("Master failed to apply package-specific smack rules: " << ret);
400 LogDebug("Adding Smack rules for new appId: " << req.appId << " with pkgId: "
401 << req.pkgId << ". Applications in package: " << pkgContents.size());
402 SmackRules::installApplicationRules(req.appId, req.pkgId, pkgContents);
404 } catch (const SmackException::Base &e) {
405 LogError("Error while applying Smack policy for application: " << e.DumpToString());
406 return SECURITY_MANAGER_API_ERROR_SETTING_FILE_LABEL_FAILED;
407 } catch (const SecurityManager::Exception &e) {
408 LogError("Security Manager exception: " << e.DumpToString());
409 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
410 }catch (const std::bad_alloc &e) {
411 LogError("Memory allocation error: " << e.what());
412 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
415 return SECURITY_MANAGER_API_SUCCESS;
418 int appUninstall(const std::string &appId, uid_t uid, bool isSlave)
421 std::string smackLabel;
422 std::vector<std::string> pkgContents;
423 bool appExists = true;
424 bool removePkg = false;
426 checkGlobalUser(uid, uidstr);
430 if (!getZoneId(zoneId)) {
431 LogError("Failed to get Zone ID.");
432 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
437 std::vector<std::string> oldAppPrivileges;
439 PrivilegeDb::getInstance().BeginTransaction();
440 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
441 LogWarning("Application " << appId <<
442 " not found in database while uninstalling");
443 PrivilegeDb::getInstance().RollbackTransaction();
446 smackLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(appId), zoneId);
447 LogDebug("Uninstall parameters: appId: " << appId << ", pkgId: " << pkgId
448 << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
450 /* Before we remove the app from the database, let's fetch all apps in the package
451 that this app belongs to, this will allow us to remove all rules withing the
452 package that the app appears in */
453 PrivilegeDb::getInstance().GetAppIdsForPkgId(pkgId, pkgContents);
454 PrivilegeDb::getInstance().GetAppPrivileges(appId, uid, oldAppPrivileges);
455 PrivilegeDb::getInstance().UpdateAppPrivileges(appId, uid, std::vector<std::string>());
456 PrivilegeDb::getInstance().RemoveApplication(appId, uid, removePkg);
459 int ret = MasterReq::CynaraPolicyUpdate(appId, uidstr, oldAppPrivileges,
460 std::vector<std::string>());
461 if (ret != SECURITY_MANAGER_API_SUCCESS) {
462 PrivilegeDb::getInstance().RollbackTransaction();
463 LogError("Error while processing request on master: " << ret);
467 CynaraAdmin::getInstance().UpdateAppPolicy(smackLabel, uidstr, oldAppPrivileges,
468 std::vector<std::string>());
471 PrivilegeDb::getInstance().CommitTransaction();
472 LogDebug("Application uninstallation commited to database");
474 } catch (const PrivilegeDb::Exception::IOError &e) {
475 LogError("Cannot access application database: " << e.DumpToString());
476 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
477 } catch (const PrivilegeDb::Exception::InternalError &e) {
478 PrivilegeDb::getInstance().RollbackTransaction();
479 LogError("Error while removing application info from database: " << e.DumpToString());
480 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
481 } catch (const CynaraException::Base &e) {
482 PrivilegeDb::getInstance().RollbackTransaction();
483 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
484 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
485 } catch (const SmackException::InvalidLabel &e) {
486 PrivilegeDb::getInstance().RollbackTransaction();
487 LogError("Error while generating Smack labels: " << e.DumpToString());
488 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
489 } catch (const std::bad_alloc &e) {
490 PrivilegeDb::getInstance().RollbackTransaction();
491 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
492 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
498 LogDebug("Delegating Smack rules removal for deleted pkgId " << pkgId <<
500 int ret = MasterReq::SmackUninstallRules(appId, pkgId, pkgContents, removePkg);
501 if (ret != SECURITY_MANAGER_API_SUCCESS) {
502 LogError("Error while processing uninstall request on master: " << ret);
507 LogDebug("Removing Smack rules for deleted pkgId " << pkgId);
508 SmackRules::uninstallPackageRules(pkgId);
511 LogDebug ("Removing smack rules for deleted appId " << appId);
512 SmackRules::uninstallApplicationRules(appId, pkgId, pkgContents, zoneId);
514 } catch (const SmackException::Base &e) {
515 LogError("Error while removing Smack rules for application: " << e.DumpToString());
516 return SECURITY_MANAGER_API_ERROR_SETTING_FILE_LABEL_FAILED;
517 } catch (const SecurityManager::Exception &e) {
518 LogError("Security Manager error: " << e.DumpToString());
519 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
520 } catch (const std::bad_alloc &e) {
521 LogError("Memory allocation error: " << e.what());
522 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
526 return SECURITY_MANAGER_API_SUCCESS;
529 int getPkgId(const std::string &appId, std::string &pkgId)
531 LogDebug("appId: " << appId);
534 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
535 LogWarning("Application " << appId << " not found in database");
536 return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
538 LogDebug("pkgId: " << pkgId);
540 } catch (const PrivilegeDb::Exception::Base &e) {
541 LogError("Error while getting pkgId from database: " << e.DumpToString());
542 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
545 return SECURITY_MANAGER_API_SUCCESS;
548 int getAppGroups(const std::string &appId, uid_t uid, pid_t pid, bool isSlave,
549 std::unordered_set<gid_t> &gids)
551 // FIXME Temporary solution, see below
554 if (!getZoneId(zoneId)) {
555 LogError("Failed to get Zone ID.");
556 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
562 std::string smackLabel;
563 std::string uidStr = std::to_string(uid);
564 std::string pidStr = std::to_string(pid);
566 LogDebug("appId: " << appId);
568 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
569 LogWarning("Application " << appId << " not found in database");
570 return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
572 LogDebug("pkgId: " << pkgId);
574 // FIXME getAppGroups should work without generating zone-specific labels when
575 // Smack Namespaces will work
576 smackLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(appId), zoneId);
577 LogDebug("smack label: " << smackLabel);
579 std::vector<std::string> privileges;
580 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, privileges);
581 /*there is also a need of checking, if privilege is granted to all users*/
582 size_t tmp = privileges.size();
583 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, getGlobalUserId(), privileges);
584 /*privileges needs to be sorted and with no duplications - for cynara sake*/
585 std::inplace_merge(privileges.begin(), privileges.begin() + tmp, privileges.end());
586 privileges.erase(unique(privileges.begin(), privileges.end()), privileges.end());
588 for (const auto &privilege : privileges) {
589 std::vector<std::string> gidsTmp;
590 PrivilegeDb::getInstance().GetPrivilegeGroups(privilege, gidsTmp);
591 if (!gidsTmp.empty()) {
592 LogDebug("Considering privilege " << privilege << " with " <<
593 gidsTmp.size() << " groups assigned");
594 // TODO: create method in Cynara class for fetching all privileges of an application
595 if (Cynara::getInstance().check(smackLabel, privilege, uidStr, pidStr)) {
596 for_each(gidsTmp.begin(), gidsTmp.end(), [&] (std::string group) {
597 struct group *grp = getgrnam(group.c_str());
599 LogError("No such group: " << group.c_str());
602 gids.insert(grp->gr_gid);
604 LogDebug("Cynara allowed, adding groups");
606 LogDebug("Cynara denied, not adding groups");
609 } catch (const PrivilegeDb::Exception::Base &e) {
610 LogError("Database error: " << e.DumpToString());
611 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
612 } catch (const CynaraException::Base &e) {
613 LogError("Error while querying Cynara for permissions: " << e.DumpToString());
614 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
615 } catch (const SmackException::InvalidLabel &e) {
616 LogError("Error while generating Smack labels: " << e.DumpToString());
617 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
618 } catch (const std::bad_alloc &e) {
619 LogError("Memory allocation failed: " << e.what());
620 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
623 return SECURITY_MANAGER_API_SUCCESS;
626 int userAdd(uid_t uidAdded, int userType, uid_t uid, bool isSlave)
629 return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
632 int ret = MasterReq::CynaraUserInit(uidAdded,
633 static_cast<security_manager_user_type>(userType));
634 if (ret != SECURITY_MANAGER_API_SUCCESS) {
635 LogError("Master failed to initialize user " << uidAdded << " of type " << userType);
640 CynaraAdmin::getInstance().UserInit(uidAdded, static_cast<security_manager_user_type>(userType));
641 } catch (CynaraException::InvalidParam &e) {
642 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
646 return SECURITY_MANAGER_API_SUCCESS;
649 int userDelete(uid_t uidDeleted, uid_t uid, bool isSlave)
651 int ret = SECURITY_MANAGER_API_SUCCESS;
653 return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
655 /*Uninstall all user apps*/
656 std::vector<std::string> userApps;
658 PrivilegeDb::getInstance().GetUserApps(uidDeleted, userApps);
659 } catch (const PrivilegeDb::Exception::Base &e) {
660 LogError("Error while getting user apps from database: " << e.DumpToString());
661 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
664 for (auto &app: userApps) {
665 if (appUninstall(app, uidDeleted, isSlave) != SECURITY_MANAGER_API_SUCCESS) {
666 /*if uninstallation of this app fails, just go on trying to uninstall another ones.
667 we do not have anything special to do about that matter - user will be deleted anyway.*/
668 ret = SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
673 int ret = MasterReq::CynaraUserRemove(uidDeleted);
675 LogError("Master failed to delete user " << uidDeleted);
679 CynaraAdmin::getInstance().UserRemove(uidDeleted);
685 int policyUpdate(const std::vector<policy_entry> &policyEntries, uid_t uid, pid_t pid, const std::string &smackLabel)
691 } isAdmin = NOT_CHECKED;
694 std::string uidStr = std::to_string(uid);
695 std::string pidStr = std::to_string(pid);
697 if (policyEntries.size() == 0) {
698 LogError("Validation failed: policy update request is empty");
699 return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
702 if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
703 LogError("Not enough permission to call: " << __FUNCTION__);
704 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
707 std::vector<CynaraAdminPolicy> validatedPolicies;
709 for (auto &entry : const_cast<std::vector<policy_entry>&>(policyEntries)) {
710 bool forAdmin = false;
711 CynaraAdminPolicy cyap("", "", "", CYNARA_ADMIN_NONE, "");
712 int ret = validatePolicy(entry, uidStr, forAdmin, cyap);
714 if (forAdmin && (isAdmin == NOT_CHECKED)) {
715 isAdmin = Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)?IS_ADMIN:IS_NOT_ADMIN;
718 if (ret == SECURITY_MANAGER_API_SUCCESS) {
720 || (forAdmin && (isAdmin == IS_ADMIN))) {
721 validatedPolicies.push_back(std::move(cyap));
723 LogError("Not enough privilege to enforce admin policy");
724 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
732 CynaraAdmin::getInstance().SetPolicies(validatedPolicies);
734 } catch (const CynaraException::Base &e) {
735 LogError("Error while updating Cynara rules: " << e.DumpToString());
736 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
737 } catch (const std::bad_alloc &e) {
738 LogError("Memory allocation error while updating Cynara rules: " << e.what());
739 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
742 return SECURITY_MANAGER_API_SUCCESS;
745 int getConfiguredPolicy(bool forAdmin, const policy_entry &filter, uid_t uid, pid_t pid,
746 const std::string &smackLabel, std::vector<policy_entry> &policyEntries)
749 std::string uidStr = std::to_string(uid);
750 std::string pidStr = std::to_string(pid);
752 if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
753 LogError("Not enough permission to call: " << __FUNCTION__);
754 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
757 LogDebug("Filter is: C: " << filter.appId
758 << ", U: " << filter.user
759 << ", P: " << filter.privilege
760 << ", current: " << filter.currentLevel
761 << ", max: " << filter.maxLevel
764 std::vector<CynaraAdminPolicy> listOfPolicies;
766 //convert appId to smack label
767 std::string appLabel = filter.appId.compare(SECURITY_MANAGER_ANY) ? SmackLabels::generateAppLabel(filter.appId) : CYNARA_ADMIN_ANY;
768 std::string user = filter.user.compare(SECURITY_MANAGER_ANY) ? filter.user : CYNARA_ADMIN_ANY;
769 std::string privilege = filter.privilege.compare(SECURITY_MANAGER_ANY) ? filter.privilege : CYNARA_ADMIN_ANY;
771 LogDebug("App: " << filter.appId << ", Label: " << appLabel);
774 if (!Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
775 LogError("Not enough privilege to access admin enforced policies: " << __FUNCTION__);
776 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
779 //Fetch privileges from ADMIN bucket
780 CynaraAdmin::getInstance().ListPolicies(
781 CynaraAdmin::Buckets.at(Bucket::ADMIN),
787 LogDebug("ADMIN - number of policies matched: " << listOfPolicies.size());
789 if (uidStr.compare(user)) {
790 if (!Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
791 LogWarning("Not enough privilege to access other user's personal policies. Limiting query to personal privileges.");
795 //Fetch privileges from PRIVACY_MANAGER bucket
796 CynaraAdmin::getInstance().ListPolicies(
797 CynaraAdmin::Buckets.at(Bucket::PRIVACY_MANAGER),
803 LogDebug("PRIVACY MANAGER - number of policies matched: " << listOfPolicies.size());
806 for (const auto &policy : listOfPolicies) {
807 //ignore "jump to bucket" entries
808 if (policy.result == CYNARA_ADMIN_BUCKET)
813 pe.appId = strcmp(policy.client, CYNARA_ADMIN_WILDCARD) ? SmackLabels::generateAppNameFromLabel(policy.client) : SECURITY_MANAGER_ANY;
814 pe.user = strcmp(policy.user, CYNARA_ADMIN_WILDCARD) ? policy.user : SECURITY_MANAGER_ANY;
815 pe.privilege = strcmp(policy.privilege, CYNARA_ADMIN_WILDCARD) ? policy.privilege : pe.privilege = SECURITY_MANAGER_ANY;
816 pe.currentLevel = CynaraAdmin::getInstance().convertToPolicyDescription(policy.result);
819 // All policy entries in PRIVACY_MANAGER should be fully-qualified
820 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
821 CynaraAdmin::getInstance().GetPrivilegeManagerMaxLevel(
822 policy.client, policy.user, policy.privilege));
824 // Cannot reliably calculate maxLavel for policies from ADMIN bucket
825 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(CYNARA_ADMIN_ALLOW);
830 "[policy_entry] app: " << pe.appId
831 << " user: " << pe.user
832 << " privilege: " << pe.privilege
833 << " current: " << pe.currentLevel
834 << " max: " << pe.maxLevel
837 policyEntries.push_back(pe);
840 } catch (const CynaraException::Base &e) {
841 LogError("Error while listing Cynara rules: " << e.DumpToString());
842 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
843 } catch (const SmackException::InvalidLabel &e) {
844 LogError("Error while generating Smack labels: " << e.DumpToString());
845 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
846 } catch (const std::bad_alloc &e) {
847 LogError("Memory allocation error while listing Cynara rules: " << e.what());
848 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
852 return SECURITY_MANAGER_API_SUCCESS;
855 int getPolicy(const policy_entry &filter, uid_t uid, pid_t pid, const std::string &smackLabel, std::vector<policy_entry> &policyEntries)
858 std::string uidStr = std::to_string(uid);
859 std::string pidStr = std::to_string(pid);
861 if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
862 LogWarning("Not enough permission to call: " << __FUNCTION__);
863 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
866 LogDebug("Filter is: C: " << filter.appId
867 << ", U: " << filter.user
868 << ", P: " << filter.privilege
869 << ", current: " << filter.currentLevel
870 << ", max: " << filter.maxLevel
873 std::vector<uid_t> listOfUsers;
875 if (Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
876 LogDebug("User is privileged");
877 if (filter.user.compare(SECURITY_MANAGER_ANY)) {
878 LogDebug("Limitting Cynara query to user: " << filter.user);
880 listOfUsers.push_back(static_cast<uid_t>(std::stoul(filter.user)));
881 } catch (std::invalid_argument &e) {
882 LogError("Invalid UID: " << e.what());
885 CynaraAdmin::getInstance().ListUsers(listOfUsers);
887 LogWarning("Not enough privilege to fetch user policy for all users by user: " << uid);
888 LogDebug("Fetching personal policy for user: " << uid);
889 listOfUsers.push_back(uid);
891 LogDebug("Fetching policy for " << listOfUsers.size() << " users");
893 for (const uid_t &uid : listOfUsers) {
894 LogDebug("User: " << uid);
895 std::string userStr = std::to_string(uid);
896 std::vector<std::string> listOfApps;
898 if (filter.appId.compare(SECURITY_MANAGER_ANY)) {
899 LogDebug("Limitting Cynara query to app: " << filter.appId);
900 listOfApps.push_back(filter.appId);
902 PrivilegeDb::getInstance().GetUserApps(uid, listOfApps);
903 LogDebug("Found apps: " << listOfApps.size());
906 for (const std::string &appId : listOfApps) {
907 LogDebug("App: " << appId);
908 std::string smackLabelForApp = SmackLabels::generateAppLabel(appId);
909 std::vector<std::string> listOfPrivileges;
911 // FIXME: also fetch privileges of global applications
912 PrivilegeDb::getInstance().GetAppPrivileges(appId, uid, listOfPrivileges);
914 if (filter.privilege.compare(SECURITY_MANAGER_ANY)) {
915 LogDebug("Limitting Cynara query to privilege: " << filter.privilege);
916 // FIXME: this filtering should be already performed by method fetching the privileges
917 if (std::find(listOfPrivileges.begin(), listOfPrivileges.end(),
918 filter.privilege) == listOfPrivileges.end()) {
919 LogDebug("Application " << appId <<
920 " doesn't have the filteres privilege " << filter.privilege);
923 listOfPrivileges.clear();
924 listOfPrivileges.push_back(filter.privilege);
927 LogDebug("Privileges matching filter - " << filter.privilege << ": " << listOfPrivileges.size());
929 for (const std::string &privilege : listOfPrivileges) {
930 LogDebug("Privilege: " << privilege);
935 pe.privilege = privilege;
937 pe.currentLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
938 CynaraAdmin::getInstance().GetPrivilegeManagerCurrLevel(
939 smackLabelForApp, userStr, privilege));
941 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
942 CynaraAdmin::getInstance().GetPrivilegeManagerMaxLevel(
943 smackLabelForApp, userStr, privilege));
946 "[policy_entry] app: " << pe.appId
947 << " user: " << pe.user
948 << " privilege: " << pe.privilege
949 << " current: " << pe.currentLevel
950 << " max: " << pe.maxLevel
953 policyEntries.push_back(pe);
958 } catch (const CynaraException::Base &e) {
959 LogError("Error while listing Cynara rules: " << e.DumpToString());
960 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
961 } catch (const SmackException::InvalidLabel &e) {
962 LogError("Error while generating Smack labels: " << e.DumpToString());
963 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
964 } catch (const std::bad_alloc &e) {
965 LogError("Memory allocation error while listing Cynara rules: " << e.what());
966 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
969 return SECURITY_MANAGER_API_SUCCESS;
972 int policyGetDesc(std::vector<std::string> &levels)
974 int ret = SECURITY_MANAGER_API_SUCCESS;
977 CynaraAdmin::getInstance().ListPoliciesDescriptions(levels);
978 } catch (const CynaraException::OutOfMemory &e) {
979 LogError("Error - out of memory while querying Cynara for policy descriptions list: " << e.DumpToString());
980 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
981 } catch (const CynaraException::InvalidParam &e) {
982 LogError("Error - invalid parameter while querying Cynara for policy descriptions list: " << e.DumpToString());
983 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
984 } catch (const CynaraException::ServiceNotAvailable &e) {
985 LogError("Error - service not available while querying Cynara for policy descriptions list: " << e.DumpToString());
986 return SECURITY_MANAGER_API_ERROR_NO_SUCH_SERVICE;
987 } catch (const CynaraException::Base &e) {
988 LogError("Error while getting policy descriptions list from Cynara: " << e.DumpToString());
989 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
995 } /* namespace ServiceImpl */
996 } /* namespace SecurityManager */