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 * @brief Implementation of the service methods
33 #include <dpl/log/log.h>
34 #include <tzplatform_config.h>
36 #include "protocols.h"
37 #include "privilege_db.h"
39 #include "smack-common.h"
40 #include "smack-rules.h"
41 #include "smack-labels.h"
43 #include "service_impl.h"
45 namespace SecurityManager {
46 namespace ServiceImpl {
48 static uid_t getGlobalUserId(void)
50 static uid_t globaluid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
55 * Unifies user data of apps installed for all users
56 * @param uid peer's uid - may be changed during process
57 * @param cynaraUserStr string to which cynara user parameter will be put
59 static void checkGlobalUser(uid_t &uid, std::string &cynaraUserStr)
61 static uid_t globaluid = getGlobalUserId();
62 if (uid == 0 || uid == globaluid) {
64 cynaraUserStr = CYNARA_ADMIN_WILDCARD;
66 cynaraUserStr = std::to_string(static_cast<unsigned int>(uid));
69 static inline bool isSubDir(const char *parent, const char *subdir)
71 while (*parent && *subdir)
72 if (*parent++ != *subdir++)
75 return (*subdir == '/');
78 static inline bool installRequestAuthCheck(const app_inst_req &req, uid_t uid)
84 if (!pwd && errno != EINTR) {
85 LogError("getpwuid failed with '" << uid
86 << "' as parameter: " << strerror(errno));
91 std::unique_ptr<char, std::function<void(void*)>> home(
92 realpath(pwd->pw_dir, NULL), free);
94 LogError("realpath failed with '" << pwd->pw_dir
95 << "' as parameter: " << strerror(errno));
99 for (const auto &appPath : req.appPaths) {
100 std::unique_ptr<char, std::function<void(void*)>> real_path(
101 realpath(appPath.first.c_str(), NULL), free);
102 if (!real_path.get()) {
103 LogError("realpath failed with '" << appPath.first.c_str()
104 << "' as parameter: " << strerror(errno));
107 LogDebug("Requested path is '" << appPath.first.c_str()
108 << "'. User's HOME is '" << pwd->pw_dir << "'");
109 if (!isSubDir(home.get(), real_path.get())) {
110 LogWarning("User's apps may have registered folders only in user's home dir");
114 app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
115 if (pathType == SECURITY_MANAGER_PATH_PUBLIC) {
116 LogWarning("Only root can register SECURITY_MANAGER_PATH_PUBLIC path");
123 int appInstall(const app_inst_req &req, uid_t uid)
125 bool pkgIdIsNew = false;
126 std::vector<std::string> addedPermissions;
127 std::vector<std::string> removedPermissions;
131 if (uid != req.uid) {
132 LogError("User " << uid <<
133 " is denied to install application for user " << req.uid);
134 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
140 checkGlobalUser(uid, uidstr);
142 if (!installRequestAuthCheck(req, uid)) {
143 LogError("Request from uid " << uid << " for app installation denied");
144 return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
147 std::string smackLabel;
148 if (!generateAppLabel(req.pkgId, smackLabel)) {
149 LogError("Cannot generate Smack label for package: " << req.pkgId);
150 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
153 LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
154 << ", generated smack label: " << smackLabel);
156 // create null terminated array of strings for permissions
157 std::unique_ptr<const char *[]> pp_permissions(new const char* [req.privileges.size() + 1]);
158 for (size_t i = 0; i < req.privileges.size(); ++i) {
159 LogDebug(" Permission = " << req.privileges[i]);
160 pp_permissions[i] = req.privileges[i].c_str();
162 pp_permissions[req.privileges.size()] = nullptr;
165 std::vector<std::string> oldPkgPrivileges, newPkgPrivileges;
167 LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
168 << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
170 PrivilegeDb::getInstance().BeginTransaction();
173 bool ret = PrivilegeDb::getInstance().GetAppPkgId(req.appId, pkg);
174 if (ret == true && pkg != req.pkgId) {
175 LogError("Application already installed with different package id");
176 PrivilegeDb::getInstance().RollbackTransaction();
177 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
179 PrivilegeDb::getInstance().GetPkgPrivileges(req.pkgId, uid, oldPkgPrivileges);
180 PrivilegeDb::getInstance().AddApplication(req.appId, req.pkgId, uid, pkgIdIsNew);
181 PrivilegeDb::getInstance().UpdateAppPrivileges(req.appId, uid, req.privileges);
182 PrivilegeDb::getInstance().GetPkgPrivileges(req.pkgId, uid, newPkgPrivileges);
183 CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges,
185 PrivilegeDb::getInstance().CommitTransaction();
186 LogDebug("Application installation commited to database");
187 } catch (const PrivilegeDb::Exception::IOError &e) {
188 LogError("Cannot access application database: " << e.DumpToString());
189 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
190 } catch (const PrivilegeDb::Exception::InternalError &e) {
191 PrivilegeDb::getInstance().RollbackTransaction();
192 LogError("Error while saving application info to database: " << e.DumpToString());
193 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
194 } catch (const CynaraException::Base &e) {
195 PrivilegeDb::getInstance().RollbackTransaction();
196 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
197 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
198 } catch (const std::bad_alloc &e) {
199 PrivilegeDb::getInstance().RollbackTransaction();
200 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
201 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
205 for (const auto &appPath : req.appPaths) {
206 const std::string &path = appPath.first;
207 app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
208 int result = setupPath(req.pkgId, path, pathType);
211 LogError("setupPath() failed");
212 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
217 LogDebug("Adding Smack rules for new pkgId " << req.pkgId);
218 if (!SmackRules::installPackageRules(req.pkgId)) {
219 LogError("Failed to apply package-specific smack rules");
220 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
224 return SECURITY_MANAGER_API_SUCCESS;
227 int appUninstall(const std::string &appId, uid_t uid)
230 std::string smackLabel;
231 bool appExists = true;
232 bool removePkg = false;
234 checkGlobalUser(uid, uidstr);
237 std::vector<std::string> oldPkgPrivileges, newPkgPrivileges;
239 PrivilegeDb::getInstance().BeginTransaction();
240 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
241 LogWarning("Application " << appId <<
242 " not found in database while uninstalling");
243 PrivilegeDb::getInstance().RollbackTransaction();
247 LogDebug("Uninstall parameters: appId: " << appId << ", pkgId: " << pkgId
248 << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
250 if (!generateAppLabel(pkgId, smackLabel)) {
251 LogError("Cannot generate Smack label for package: " << pkgId);
252 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
255 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, oldPkgPrivileges);
256 PrivilegeDb::getInstance().UpdateAppPrivileges(appId, uid, std::vector<std::string>());
257 PrivilegeDb::getInstance().RemoveApplication(appId, uid, removePkg);
258 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, newPkgPrivileges);
259 CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges,
261 PrivilegeDb::getInstance().CommitTransaction();
262 LogDebug("Application uninstallation commited to database");
264 } catch (const PrivilegeDb::Exception::IOError &e) {
265 LogError("Cannot access application database: " << e.DumpToString());
266 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
267 } catch (const PrivilegeDb::Exception::InternalError &e) {
268 PrivilegeDb::getInstance().RollbackTransaction();
269 LogError("Error while removing application info from database: " << e.DumpToString());
270 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
271 } catch (const CynaraException::Base &e) {
272 PrivilegeDb::getInstance().RollbackTransaction();
273 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
274 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
275 } catch (const std::bad_alloc &e) {
276 PrivilegeDb::getInstance().RollbackTransaction();
277 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
278 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
284 LogDebug("Removing Smack rules for deleted pkgId " << pkgId);
285 if (!SmackRules::uninstallPackageRules(pkgId)) {
286 LogError("Error on uninstallation of package-specific smack rules");
287 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
292 return SECURITY_MANAGER_API_SUCCESS;
295 int getPkgId(const std::string &appId, std::string &pkgId)
297 LogDebug("appId: " << appId);
300 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
301 LogWarning("Application " << appId << " not found in database");
302 return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
304 LogDebug("pkgId: " << pkgId);
306 } catch (const PrivilegeDb::Exception::Base &e) {
307 LogError("Error while getting pkgId from database: " << e.DumpToString());
308 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
311 return SECURITY_MANAGER_API_SUCCESS;
314 int getAppGroups(const std::string &appId, uid_t uid, pid_t pid, std::unordered_set<gid_t> &gids)
318 std::string smackLabel;
319 std::string uidStr = std::to_string(uid);
320 std::string pidStr = std::to_string(pid);
322 LogDebug("appId: " << appId);
324 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
325 LogWarning("Application " << appId << " not found in database");
326 return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
328 LogDebug("pkgId: " << pkgId);
330 if (!generateAppLabel(pkgId, smackLabel)) {
331 LogError("Cannot generate Smack label for package: " << pkgId);
332 return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
334 LogDebug("smack label: " << smackLabel);
336 std::vector<std::string> privileges;
337 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, privileges);
338 /*there is also a need of checking, if privilege is granted to all users*/
339 size_t tmp = privileges.size();
340 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, getGlobalUserId(), privileges);
341 /*privileges needs to be sorted and with no duplications - for cynara sake*/
342 std::inplace_merge(privileges.begin(), privileges.begin() + tmp, privileges.end());
343 privileges.erase( unique( privileges.begin(), privileges.end() ), privileges.end() );
345 for (const auto &privilege : privileges) {
346 std::vector<std::string> gidsTmp;
347 PrivilegeDb::getInstance().GetPrivilegeGroups(privilege, gidsTmp);
348 if (!gidsTmp.empty()) {
349 LogDebug("Considering privilege " << privilege << " with " <<
350 gidsTmp.size() << " groups assigned");
351 if (Cynara::getInstance().check(smackLabel, privilege, uidStr, pidStr)) {
352 for_each(gidsTmp.begin(), gidsTmp.end(), [&] (std::string group)
354 struct group *grp = getgrnam(group.c_str());
356 LogError("No such group: " << group.c_str());
359 gids.insert(grp->gr_gid);
361 LogDebug("Cynara allowed, adding groups");
363 LogDebug("Cynara denied, not adding groups");
366 } catch (const PrivilegeDb::Exception::Base &e) {
367 LogError("Database error: " << e.DumpToString());
368 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
369 } catch (const CynaraException::Base &e) {
370 LogError("Error while querying Cynara for permissions: " << e.DumpToString());
371 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
372 } catch (const std::bad_alloc &e) {
373 LogError("Memory allocation failed: " << e.what());
374 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
377 return SECURITY_MANAGER_API_SUCCESS;
380 int userAdd(uid_t uidAdded, int userType, uid_t uid)
383 return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
386 case SM_USER_TYPE_SYSTEM:
387 case SM_USER_TYPE_ADMIN:
388 case SM_USER_TYPE_GUEST:
389 case SM_USER_TYPE_NORMAL:
392 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
395 //TODO add policy information to cynara regarding user default privileges based on user_type
399 return SECURITY_MANAGER_API_SUCCESS;
402 int userDelete(uid_t uidDeleted, uid_t uid)
404 int ret = SECURITY_MANAGER_API_SUCCESS;
406 return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
408 //TODO remove policy information from cynara
410 /*Uninstall all user apps*/
411 std::vector<std::string> userApps;
413 PrivilegeDb::getInstance().GetUserApps(uidDeleted, userApps);
414 } catch (const PrivilegeDb::Exception::Base &e) {
415 LogError("Error while getting user apps from database: " << e.DumpToString());
416 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
419 for (auto &app: userApps) {
420 if (appUninstall(app, uidDeleted) != SECURITY_MANAGER_API_SUCCESS) {
421 /*if uninstallation of this app fails, just go on trying to uninstall another ones.
422 we do not have anything special to do about that matter - user will be deleted anyway.*/
423 ret = SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
430 } /* namespace ServiceImpl */
431 } /* namespace SecurityManager */