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;
130 if ((!uid) && (req.uid))
132 checkGlobalUser(uid, uidstr);
134 if (!installRequestAuthCheck(req, uid)) {
135 LogError("Request from uid " << uid << " for app installation denied");
136 return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
139 std::string smackLabel;
140 if (!generateAppLabel(req.pkgId, smackLabel)) {
141 LogError("Cannot generate Smack label for package: " << req.pkgId);
142 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
145 LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
146 << ", generated smack label: " << smackLabel);
148 // create null terminated array of strings for permissions
149 std::unique_ptr<const char *[]> pp_permissions(new const char* [req.privileges.size() + 1]);
150 for (size_t i = 0; i < req.privileges.size(); ++i) {
151 LogDebug(" Permission = " << req.privileges[i]);
152 pp_permissions[i] = req.privileges[i].c_str();
154 pp_permissions[req.privileges.size()] = nullptr;
157 std::vector<std::string> oldPkgPrivileges, newPkgPrivileges;
159 LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
160 << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
162 PrivilegeDb::getInstance().BeginTransaction();
163 PrivilegeDb::getInstance().GetPkgPrivileges(req.pkgId, uid, oldPkgPrivileges);
164 PrivilegeDb::getInstance().AddApplication(req.appId, req.pkgId, uid, pkgIdIsNew);
165 PrivilegeDb::getInstance().UpdateAppPrivileges(req.appId, uid, req.privileges);
166 PrivilegeDb::getInstance().GetPkgPrivileges(req.pkgId, uid, newPkgPrivileges);
167 CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges,
169 PrivilegeDb::getInstance().CommitTransaction();
170 LogDebug("Application installation commited to database");
171 } catch (const PrivilegeDb::Exception::IOError &e) {
172 LogError("Cannot access application database: " << e.DumpToString());
173 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
174 } catch (const PrivilegeDb::Exception::InternalError &e) {
175 PrivilegeDb::getInstance().RollbackTransaction();
176 LogError("Error while saving application info to database: " << e.DumpToString());
177 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
178 } catch (const CynaraException::Base &e) {
179 PrivilegeDb::getInstance().RollbackTransaction();
180 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
181 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
182 } catch (const std::bad_alloc &e) {
183 PrivilegeDb::getInstance().RollbackTransaction();
184 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
185 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
189 for (const auto &appPath : req.appPaths) {
190 const std::string &path = appPath.first;
191 app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
192 int result = setupPath(req.pkgId, path, pathType);
195 LogError("setupPath() failed");
196 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
201 LogDebug("Adding Smack rules for new pkgId " << req.pkgId);
202 if (!SmackRules::installPackageRules(req.pkgId)) {
203 LogError("Failed to apply package-specific smack rules");
204 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
208 return SECURITY_MANAGER_API_SUCCESS;
211 int appUninstall(const std::string &appId, uid_t uid)
214 std::string smackLabel;
215 bool appExists = true;
216 bool removePkg = false;
218 checkGlobalUser(uid, uidstr);
221 std::vector<std::string> oldPkgPrivileges, newPkgPrivileges;
223 PrivilegeDb::getInstance().BeginTransaction();
224 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
225 LogWarning("Application " << appId <<
226 " not found in database while uninstalling");
227 PrivilegeDb::getInstance().RollbackTransaction();
231 LogDebug("Uninstall parameters: appId: " << appId << ", pkgId: " << pkgId
232 << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
234 if (!generateAppLabel(pkgId, smackLabel)) {
235 LogError("Cannot generate Smack label for package: " << pkgId);
236 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
239 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, oldPkgPrivileges);
240 PrivilegeDb::getInstance().UpdateAppPrivileges(appId, uid, std::vector<std::string>());
241 PrivilegeDb::getInstance().RemoveApplication(appId, uid, removePkg);
242 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, newPkgPrivileges);
243 CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges,
245 PrivilegeDb::getInstance().CommitTransaction();
246 LogDebug("Application uninstallation commited to database");
248 } catch (const PrivilegeDb::Exception::IOError &e) {
249 LogError("Cannot access application database: " << e.DumpToString());
250 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
251 } catch (const PrivilegeDb::Exception::InternalError &e) {
252 PrivilegeDb::getInstance().RollbackTransaction();
253 LogError("Error while removing application info from database: " << e.DumpToString());
254 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
255 } catch (const CynaraException::Base &e) {
256 PrivilegeDb::getInstance().RollbackTransaction();
257 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
258 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
259 } catch (const std::bad_alloc &e) {
260 PrivilegeDb::getInstance().RollbackTransaction();
261 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
262 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
268 LogDebug("Removing Smack rules for deleted pkgId " << pkgId);
269 if (!SmackRules::uninstallPackageRules(pkgId)) {
270 LogError("Error on uninstallation of package-specific smack rules");
271 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
276 return SECURITY_MANAGER_API_SUCCESS;
279 int getPkgId(const std::string &appId, std::string &pkgId)
281 LogDebug("appId: " << appId);
284 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
285 LogWarning("Application " << appId << " not found in database");
286 return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
288 LogDebug("pkgId: " << pkgId);
290 } catch (const PrivilegeDb::Exception::Base &e) {
291 LogError("Error while getting pkgId from database: " << e.DumpToString());
292 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
295 return SECURITY_MANAGER_API_SUCCESS;
298 int getAppGroups(const std::string &appId, uid_t uid, pid_t pid, std::unordered_set<gid_t> &gids)
302 std::string smackLabel;
303 std::string uidStr = std::to_string(uid);
304 std::string pidStr = std::to_string(pid);
306 LogDebug("appId: " << appId);
308 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
309 LogWarning("Application " << appId << " not found in database");
310 return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
312 LogDebug("pkgId: " << pkgId);
314 if (!generateAppLabel(pkgId, smackLabel)) {
315 LogError("Cannot generate Smack label for package: " << pkgId);
316 return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
318 LogDebug("smack label: " << smackLabel);
320 std::vector<std::string> privileges;
321 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, privileges);
322 /*there is also a need of checking, if privilege is granted to all users*/
323 size_t tmp = privileges.size();
324 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, getGlobalUserId(), privileges);
325 /*privileges needs to be sorted and with no duplications - for cynara sake*/
326 std::inplace_merge(privileges.begin(), privileges.begin() + tmp, privileges.end());
327 privileges.erase( unique( privileges.begin(), privileges.end() ), privileges.end() );
329 for (const auto &privilege : privileges) {
330 std::vector<std::string> gidsTmp;
331 PrivilegeDb::getInstance().GetPrivilegeGroups(privilege, gidsTmp);
332 if (!gidsTmp.empty()) {
333 LogDebug("Considering privilege " << privilege << " with " <<
334 gidsTmp.size() << " groups assigned");
335 if (Cynara::getInstance().check(smackLabel, privilege, uidStr, pidStr)) {
336 for_each(gidsTmp.begin(), gidsTmp.end(), [&] (std::string group)
338 struct group *grp = getgrnam(group.c_str());
340 LogError("No such group: " << group.c_str());
343 gids.insert(grp->gr_gid);
345 LogDebug("Cynara allowed, adding groups");
347 LogDebug("Cynara denied, not adding groups");
350 } catch (const PrivilegeDb::Exception::Base &e) {
351 LogError("Database error: " << e.DumpToString());
352 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
353 } catch (const CynaraException::Base &e) {
354 LogError("Error while querying Cynara for permissions: " << e.DumpToString());
355 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
356 } catch (const std::bad_alloc &e) {
357 LogError("Memory allocation failed: " << e.what());
358 return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
361 return SECURITY_MANAGER_API_SUCCESS;
364 } /* namespace ServiceImpl */
365 } /* namespace SecurityManager */