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();
171 PrivilegeDb::getInstance().GetPkgPrivileges(req.pkgId, uid, oldPkgPrivileges);
172 PrivilegeDb::getInstance().AddApplication(req.appId, req.pkgId, uid, pkgIdIsNew);
173 PrivilegeDb::getInstance().UpdateAppPrivileges(req.appId, uid, req.privileges);
174 PrivilegeDb::getInstance().GetPkgPrivileges(req.pkgId, uid, newPkgPrivileges);
175 CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges,
177 PrivilegeDb::getInstance().CommitTransaction();
178 LogDebug("Application installation commited to database");
179 } catch (const PrivilegeDb::Exception::IOError &e) {
180 LogError("Cannot access application database: " << e.DumpToString());
181 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
182 } catch (const PrivilegeDb::Exception::InternalError &e) {
183 PrivilegeDb::getInstance().RollbackTransaction();
184 LogError("Error while saving application info to database: " << e.DumpToString());
185 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
186 } catch (const CynaraException::Base &e) {
187 PrivilegeDb::getInstance().RollbackTransaction();
188 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
189 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
190 } catch (const std::bad_alloc &e) {
191 PrivilegeDb::getInstance().RollbackTransaction();
192 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
193 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
197 for (const auto &appPath : req.appPaths) {
198 const std::string &path = appPath.first;
199 app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
200 int result = setupPath(req.pkgId, path, pathType);
203 LogError("setupPath() failed");
204 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
209 LogDebug("Adding Smack rules for new pkgId " << req.pkgId);
210 if (!SmackRules::installPackageRules(req.pkgId)) {
211 LogError("Failed to apply package-specific smack rules");
212 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
216 return SECURITY_MANAGER_API_SUCCESS;
219 int appUninstall(const std::string &appId, uid_t uid)
222 std::string smackLabel;
223 bool appExists = true;
224 bool removePkg = false;
226 checkGlobalUser(uid, uidstr);
229 std::vector<std::string> oldPkgPrivileges, newPkgPrivileges;
231 PrivilegeDb::getInstance().BeginTransaction();
232 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
233 LogWarning("Application " << appId <<
234 " not found in database while uninstalling");
235 PrivilegeDb::getInstance().RollbackTransaction();
239 LogDebug("Uninstall parameters: appId: " << appId << ", pkgId: " << pkgId
240 << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
242 if (!generateAppLabel(pkgId, smackLabel)) {
243 LogError("Cannot generate Smack label for package: " << pkgId);
244 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
247 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, oldPkgPrivileges);
248 PrivilegeDb::getInstance().UpdateAppPrivileges(appId, uid, std::vector<std::string>());
249 PrivilegeDb::getInstance().RemoveApplication(appId, uid, removePkg);
250 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, newPkgPrivileges);
251 CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges,
253 PrivilegeDb::getInstance().CommitTransaction();
254 LogDebug("Application uninstallation commited to database");
256 } catch (const PrivilegeDb::Exception::IOError &e) {
257 LogError("Cannot access application database: " << e.DumpToString());
258 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
259 } catch (const PrivilegeDb::Exception::InternalError &e) {
260 PrivilegeDb::getInstance().RollbackTransaction();
261 LogError("Error while removing application info from database: " << e.DumpToString());
262 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
263 } catch (const CynaraException::Base &e) {
264 PrivilegeDb::getInstance().RollbackTransaction();
265 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
266 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
267 } catch (const std::bad_alloc &e) {
268 PrivilegeDb::getInstance().RollbackTransaction();
269 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
270 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
276 LogDebug("Removing Smack rules for deleted pkgId " << pkgId);
277 if (!SmackRules::uninstallPackageRules(pkgId)) {
278 LogError("Error on uninstallation of package-specific smack rules");
279 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
284 return SECURITY_MANAGER_API_SUCCESS;
287 int getPkgId(const std::string &appId, std::string &pkgId)
289 LogDebug("appId: " << appId);
292 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
293 LogWarning("Application " << appId << " not found in database");
294 return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
296 LogDebug("pkgId: " << pkgId);
298 } catch (const PrivilegeDb::Exception::Base &e) {
299 LogError("Error while getting pkgId from database: " << e.DumpToString());
300 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
303 return SECURITY_MANAGER_API_SUCCESS;
306 int getAppGroups(const std::string &appId, uid_t uid, pid_t pid, std::unordered_set<gid_t> &gids)
310 std::string smackLabel;
311 std::string uidStr = std::to_string(uid);
312 std::string pidStr = std::to_string(pid);
314 LogDebug("appId: " << appId);
316 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
317 LogWarning("Application " << appId << " not found in database");
318 return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
320 LogDebug("pkgId: " << pkgId);
322 if (!generateAppLabel(pkgId, smackLabel)) {
323 LogError("Cannot generate Smack label for package: " << pkgId);
324 return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
326 LogDebug("smack label: " << smackLabel);
328 std::vector<std::string> privileges;
329 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, privileges);
330 /*there is also a need of checking, if privilege is granted to all users*/
331 size_t tmp = privileges.size();
332 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, getGlobalUserId(), privileges);
333 /*privileges needs to be sorted and with no duplications - for cynara sake*/
334 std::inplace_merge(privileges.begin(), privileges.begin() + tmp, privileges.end());
335 privileges.erase( unique( privileges.begin(), privileges.end() ), privileges.end() );
337 for (const auto &privilege : privileges) {
338 std::vector<std::string> gidsTmp;
339 PrivilegeDb::getInstance().GetPrivilegeGroups(privilege, gidsTmp);
340 if (!gidsTmp.empty()) {
341 LogDebug("Considering privilege " << privilege << " with " <<
342 gidsTmp.size() << " groups assigned");
343 if (Cynara::getInstance().check(smackLabel, privilege, uidStr, pidStr)) {
344 for_each(gidsTmp.begin(), gidsTmp.end(), [&] (std::string group)
346 struct group *grp = getgrnam(group.c_str());
348 LogError("No such group: " << group.c_str());
351 gids.insert(grp->gr_gid);
353 LogDebug("Cynara allowed, adding groups");
355 LogDebug("Cynara denied, not adding groups");
358 } catch (const PrivilegeDb::Exception::Base &e) {
359 LogError("Database error: " << e.DumpToString());
360 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
361 } catch (const CynaraException::Base &e) {
362 LogError("Error while querying Cynara for permissions: " << e.DumpToString());
363 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
364 } catch (const std::bad_alloc &e) {
365 LogError("Memory allocation failed: " << e.what());
366 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
369 return SECURITY_MANAGER_API_SUCCESS;
372 } /* namespace ServiceImpl */
373 } /* namespace SecurityManager */