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
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 security-manager service.
29 #include <sys/socket.h>
30 #include <sys/types.h>
33 #include <unordered_set>
36 #include <dpl/log/log.h>
37 #include <dpl/serialization.h>
38 #include <tzplatform_config.h>
40 #include "privilege_db.h"
41 #include "protocols.h"
42 #include "security-manager.h"
44 #include "smack-common.h"
45 #include "smack-rules.h"
46 #include "smack-labels.h"
48 namespace SecurityManager {
50 const InterfaceID IFACE = 1;
54 static uid_t getGlobalUserId(void) {
55 static uid_t globaluid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
60 * Unifies user data of apps installed for all users
61 * @param uid peer's uid - may be changed during process
62 * @param cynaraUserStr string to which cynara user parameter will be put
64 static void checkGlobalUser(uid_t &uid, std::string &cynaraUserStr)
66 static uid_t globaluid = getGlobalUserId();
67 if (uid == 0 || uid == globaluid) {
69 cynaraUserStr = CYNARA_ADMIN_WILDCARD;
71 cynaraUserStr = std::to_string(static_cast<unsigned int>(uid));
79 GenericSocketService::ServiceDescriptionVector Service::GetServiceDescription()
81 return ServiceDescriptionVector {
82 {SERVICE_SOCKET, "security-manager", IFACE},
86 void Service::accept(const AcceptEvent &event)
88 LogDebug("Accept event. ConnectionID.sock: " << event.connectionID.sock <<
89 " ConnectionID.counter: " << event.connectionID.counter <<
90 " ServiceID: " << event.interfaceID);
92 auto &info = m_connectionInfoMap[event.connectionID.counter];
93 info.interfaceID = event.interfaceID;
96 void Service::write(const WriteEvent &event)
98 LogDebug("WriteEvent. ConnectionID: " << event.connectionID.sock <<
99 " Size: " << event.size <<
100 " Left: " << event.left);
103 m_serviceManager->Close(event.connectionID);
106 void Service::process(const ReadEvent &event)
108 LogDebug("Read event for counter: " << event.connectionID.counter);
109 auto &info = m_connectionInfoMap[event.connectionID.counter];
110 info.buffer.Push(event.rawBuffer);
112 // We can get several requests in one package.
113 // Extract and process them all
114 while (processOne(event.connectionID, info.buffer, info.interfaceID));
117 void Service::close(const CloseEvent &event)
119 LogDebug("CloseEvent. ConnectionID: " << event.connectionID.sock);
120 m_connectionInfoMap.erase(event.connectionID.counter);
123 static bool getPeerID(int sock, uid_t &uid, pid_t &pid) {
125 socklen_t len = sizeof(cr);
127 if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &cr, &len)) {
136 bool Service::processOne(const ConnectionID &conn, MessageBuffer &buffer,
137 InterfaceID interfaceID)
139 LogDebug("Iteration begin. Interface = " << interfaceID);
141 //waiting for all data
142 if (!buffer.Ready()) {
152 if(!getPeerID(conn.sock, uid, pid)) {
153 LogError("Closing socket because of error: unable to get peer's uid and pid");
154 m_serviceManager->Close(conn);
158 if (IFACE == interfaceID) {
160 // deserialize API call type
162 Deserialization::Deserialize(buffer, call_type_int);
163 SecurityModuleCall call_type = static_cast<SecurityModuleCall>(call_type_int);
166 case SecurityModuleCall::APP_INSTALL:
167 LogDebug("call_type: SecurityModuleCall::APP_INSTALL");
168 processAppInstall(buffer, send, uid);
170 case SecurityModuleCall::APP_UNINSTALL:
171 LogDebug("call_type: SecurityModuleCall::APP_UNINSTALL");
172 processAppUninstall(buffer, send, uid);
174 case SecurityModuleCall::APP_GET_PKGID:
175 processGetPkgId(buffer, send);
177 case SecurityModuleCall::APP_GET_GROUPS:
178 processGetAppGroups(buffer, send, uid, pid);
181 LogError("Invalid call: " << call_type_int);
182 Throw(ServiceException::InvalidAction);
184 // if we reach this point, the protocol is OK
186 } Catch (MessageBuffer::Exception::Base) {
187 LogError("Broken protocol.");
188 } Catch (ServiceException::Base) {
189 LogError("Broken protocol.");
190 } catch (std::exception &e) {
191 LogError("STD exception " << e.what());
193 LogError("Unknown exception");
197 LogError("Wrong interface");
202 m_serviceManager->Write(conn, send.Pop());
204 LogError("Closing socket because of error");
205 m_serviceManager->Close(conn);
211 static inline bool isSubDir(const char *parent, const char *subdir)
213 while (*parent && *subdir)
214 if (*parent++ != *subdir++)
217 return (*subdir == '/');
220 static inline bool installRequestAuthCheck(const app_inst_req &req, uid_t uid)
226 if (!pwd && errno != EINTR) {
227 LogError("getpwuid failed with '" << uid
228 << "' as paramter: " << strerror(errno));
233 std::unique_ptr<char, std::function<void(void*)>> home(
234 realpath(pwd->pw_dir, NULL), free);
236 LogError("realpath failed with '" << pwd->pw_dir
237 << "' as paramter: " << strerror(errno));
241 for (const auto &appPath : req.appPaths) {
242 std::unique_ptr<char, std::function<void(void*)>> real_path(
243 realpath(appPath.first.c_str(), NULL), free);
244 if (!real_path.get()) {
245 LogError("realpath failed with '" << appPath.first.c_str()
246 << "' as paramter: " << strerror(errno));
249 LogDebug("Requested path is '" << appPath.first.c_str()
250 << "'. User's HOME is '" << pwd->pw_dir << "'");
251 if (!isSubDir(home.get(), real_path.get())) {
252 LogWarning("User's apps may have registered folders only in user's home dir");
256 app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
257 if (pathType == SECURITY_MANAGER_PATH_PUBLIC) {
258 LogWarning("Only root can register SECURITY_MANAGER_PATH_PUBLIC path");
265 bool Service::processAppInstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid)
267 bool pkgIdIsNew = false;
268 std::vector<std::string> addedPermissions;
269 std::vector<std::string> removedPermissions;
271 // deserialize request data
273 Deserialization::Deserialize(buffer, req.appId);
274 Deserialization::Deserialize(buffer, req.pkgId);
275 Deserialization::Deserialize(buffer, req.privileges);
276 Deserialization::Deserialize(buffer, req.appPaths);
278 checkGlobalUser(uid, uidstr);
280 if(!installRequestAuthCheck(req, uid)) {
281 LogError("Request from uid " << uid << " for app installation denied");
282 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED);
286 std::string smackLabel;
287 if (!generateAppLabel(req.pkgId, smackLabel)) {
288 LogError("Cannot generate Smack label for package: " << req.pkgId);
289 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
293 LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
294 << ", generated smack label: " << smackLabel);
296 // create null terminated array of strings for permissions
297 std::unique_ptr<const char *[]> pp_permissions(new const char* [req.privileges.size() + 1]);
298 for (size_t i = 0; i < req.privileges.size(); ++i) {
299 LogDebug(" Permission = " << req.privileges[i]);
300 pp_permissions[i] = req.privileges[i].c_str();
302 pp_permissions[req.privileges.size()] = nullptr;
305 std::vector<std::string> oldPkgPrivileges, newPkgPrivileges;
307 LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
308 << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
310 m_privilegeDb.BeginTransaction();
311 m_privilegeDb.GetPkgPrivileges(req.pkgId, uid, oldPkgPrivileges);
312 m_privilegeDb.AddApplication(req.appId, req.pkgId, uid, pkgIdIsNew);
313 m_privilegeDb.UpdateAppPrivileges(req.appId, uid, req.privileges);
314 m_privilegeDb.GetPkgPrivileges(req.pkgId, uid, newPkgPrivileges);
315 CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges,
317 m_privilegeDb.CommitTransaction();
318 LogDebug("Application installation commited to database");
319 } catch (const PrivilegeDb::Exception::InternalError &e) {
320 m_privilegeDb.RollbackTransaction();
321 LogError("Error while saving application info to database: " << e.DumpToString());
323 } catch (const CynaraException::Base &e) {
324 m_privilegeDb.RollbackTransaction();
325 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
327 } catch (const std::bad_alloc &e) {
328 m_privilegeDb.RollbackTransaction();
329 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
334 for (const auto &appPath : req.appPaths) {
335 const std::string &path = appPath.first;
336 app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
337 int result = setupPath(req.pkgId, path, pathType);
340 LogError("setupPath() failed");
346 LogDebug("Adding Smack rules for new pkgId " << req.pkgId);
347 if (!SmackRules::installPackageRules(req.pkgId)) {
348 LogError("Failed to apply package-specific smack rules");
354 Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
358 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
362 bool Service::processAppUninstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid)
364 // deserialize request data
367 std::string smackLabel;
368 bool appExists = true;
369 bool removePkg = false;
371 Deserialization::Deserialize(buffer, appId);
373 checkGlobalUser(uid, uidstr);
376 std::vector<std::string> oldPkgPrivileges, newPkgPrivileges;
378 m_privilegeDb.BeginTransaction();
379 if (!m_privilegeDb.GetAppPkgId(appId, pkgId)) {
380 LogWarning("Application " << appId <<
381 " not found in database while uninstalling");
382 m_privilegeDb.RollbackTransaction();
386 LogDebug("Uninstall parameters: appId: " << appId << ", pkgId: " << pkgId
387 << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
389 if (!generateAppLabel(pkgId, smackLabel)) {
390 LogError("Cannot generate Smack label for package: " << pkgId);
394 m_privilegeDb.GetPkgPrivileges(pkgId, uid, oldPkgPrivileges);
395 m_privilegeDb.UpdateAppPrivileges(appId, uid, std::vector<std::string>());
396 m_privilegeDb.RemoveApplication(appId, uid, removePkg);
397 m_privilegeDb.GetPkgPrivileges(pkgId, uid, newPkgPrivileges);
398 CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges,
400 m_privilegeDb.CommitTransaction();
401 LogDebug("Application uninstallation commited to database");
403 } catch (const PrivilegeDb::Exception::InternalError &e) {
404 m_privilegeDb.RollbackTransaction();
405 LogError("Error while removing application info from database: " << e.DumpToString());
407 } catch (const CynaraException::Base &e) {
408 m_privilegeDb.RollbackTransaction();
409 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
411 } catch (const std::bad_alloc &e) {
412 m_privilegeDb.RollbackTransaction();
413 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
420 LogDebug("Removing Smack rules for deleted pkgId " << pkgId);
421 if (!SmackRules::uninstallPackageRules(pkgId)) {
422 LogError("Error on uninstallation of package-specific smack rules");
429 Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
433 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
437 bool Service::processGetPkgId(MessageBuffer &buffer, MessageBuffer &send)
439 // deserialize request data
443 Deserialization::Deserialize(buffer, appId);
444 LogDebug("appId: " << appId);
447 if (!m_privilegeDb.GetAppPkgId(appId, pkgId)) {
448 LogWarning("Application " << appId << " not found in database");
449 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT);
452 LogDebug("pkgId: " << pkgId);
454 } catch (const PrivilegeDb::Exception::InternalError &e) {
455 LogError("Error while getting pkgId from database: " << e.DumpToString());
456 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
461 Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
462 Serialization::Serialize(send, pkgId);
466 bool Service::processGetAppGroups(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid)
468 std::unordered_set<gid_t> gids;
473 std::string smackLabel;
474 std::string uidStr = std::to_string(uid);
475 std::string pidStr = std::to_string(pid);
477 Deserialization::Deserialize(buffer, appId);
478 LogDebug("appId: " << appId);
480 if (!m_privilegeDb.GetAppPkgId(appId, pkgId)) {
481 LogWarning("Application " << appId << " not found in database");
482 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT);
485 LogDebug("pkgId: " << pkgId);
487 if (!generateAppLabel(pkgId, smackLabel)) {
488 LogError("Cannot generate Smack label for package: " << pkgId);
489 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT);
492 LogDebug("smack label: " << smackLabel);
494 std::vector<std::string> privileges;
495 m_privilegeDb.GetPkgPrivileges(pkgId, uid, privileges);
496 /*there is also a need of checking, if privilege is granted to all users*/
497 size_t tmp = privileges.size();
498 m_privilegeDb.GetPkgPrivileges(pkgId, getGlobalUserId(), privileges);
499 /*privileges needs to be sorted and with no duplications - for cynara sake*/
500 std::inplace_merge(privileges.begin(), privileges.begin() + tmp, privileges.end());
501 privileges.erase( unique( privileges.begin(), privileges.end() ), privileges.end() );
503 for (const auto &privilege : privileges) {
504 std::vector<std::string> gidsTmp;
505 m_privilegeDb.GetPrivilegeGroups(privilege, gidsTmp);
506 if (!gidsTmp.empty()) {
507 LogDebug("Considering privilege " << privilege << " with " <<
508 gidsTmp.size() << " groups assigned");
509 if (m_cynara.check(smackLabel, privilege, uidStr, pidStr)) {
510 for_each(gidsTmp.begin(), gidsTmp.end(), [&] (std::string group)
512 struct group *grp = getgrnam(group.c_str());
514 LogError("No such group: " << group.c_str());
517 gids.insert(grp->gr_gid);
519 LogDebug("Cynara allowed, adding groups");
521 LogDebug("Cynara denied, not adding groups");
524 } catch (const PrivilegeDb::Exception::InternalError &e) {
525 LogError("Database error: " << e.DumpToString());
526 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
528 } catch (const CynaraException::Base &e) {
529 LogError("Error while querying Cynara for permissions: " << e.DumpToString());
530 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
532 } catch (const std::bad_alloc &e) {
533 LogError("Memory allocation failed: " << e.what());
534 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY);
539 Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
540 Serialization::Serialize(send, static_cast<int>(gids.size()));
541 for (const auto &gid : gids) {
542 Serialization::Serialize(send, gid);
548 } // namespace SecurityManager