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);
277 Deserialization::Deserialize(buffer, req.uid);
280 if ((!uid) && (req.uid))
282 checkGlobalUser(uid, uidstr);
284 if(!installRequestAuthCheck(req, uid)) {
285 LogError("Request from uid " << uid << " for app installation denied");
286 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED);
290 std::string smackLabel;
291 if (!generateAppLabel(req.pkgId, smackLabel)) {
292 LogError("Cannot generate Smack label for package: " << req.pkgId);
293 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
297 LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
298 << ", generated smack label: " << smackLabel);
300 // create null terminated array of strings for permissions
301 std::unique_ptr<const char *[]> pp_permissions(new const char* [req.privileges.size() + 1]);
302 for (size_t i = 0; i < req.privileges.size(); ++i) {
303 LogDebug(" Permission = " << req.privileges[i]);
304 pp_permissions[i] = req.privileges[i].c_str();
306 pp_permissions[req.privileges.size()] = nullptr;
309 std::vector<std::string> oldPkgPrivileges, newPkgPrivileges;
311 LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
312 << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
314 m_privilegeDb.BeginTransaction();
315 m_privilegeDb.GetPkgPrivileges(req.pkgId, uid, oldPkgPrivileges);
316 m_privilegeDb.AddApplication(req.appId, req.pkgId, uid, pkgIdIsNew);
317 m_privilegeDb.UpdateAppPrivileges(req.appId, uid, req.privileges);
318 m_privilegeDb.GetPkgPrivileges(req.pkgId, uid, newPkgPrivileges);
319 CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges,
321 m_privilegeDb.CommitTransaction();
322 LogDebug("Application installation commited to database");
323 } catch (const PrivilegeDb::Exception::InternalError &e) {
324 m_privilegeDb.RollbackTransaction();
325 LogError("Error while saving application info to database: " << e.DumpToString());
327 } catch (const CynaraException::Base &e) {
328 m_privilegeDb.RollbackTransaction();
329 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
331 } catch (const std::bad_alloc &e) {
332 m_privilegeDb.RollbackTransaction();
333 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
338 for (const auto &appPath : req.appPaths) {
339 const std::string &path = appPath.first;
340 app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
341 int result = setupPath(req.pkgId, path, pathType);
344 LogError("setupPath() failed");
350 LogDebug("Adding Smack rules for new pkgId " << req.pkgId);
351 if (!SmackRules::installPackageRules(req.pkgId)) {
352 LogError("Failed to apply package-specific smack rules");
358 Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
362 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
366 bool Service::processAppUninstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid)
368 // deserialize request data
371 std::string smackLabel;
372 bool appExists = true;
373 bool removePkg = false;
375 Deserialization::Deserialize(buffer, appId);
377 checkGlobalUser(uid, uidstr);
380 std::vector<std::string> oldPkgPrivileges, newPkgPrivileges;
382 m_privilegeDb.BeginTransaction();
383 if (!m_privilegeDb.GetAppPkgId(appId, pkgId)) {
384 LogWarning("Application " << appId <<
385 " not found in database while uninstalling");
386 m_privilegeDb.RollbackTransaction();
390 LogDebug("Uninstall parameters: appId: " << appId << ", pkgId: " << pkgId
391 << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
393 if (!generateAppLabel(pkgId, smackLabel)) {
394 LogError("Cannot generate Smack label for package: " << pkgId);
398 m_privilegeDb.GetPkgPrivileges(pkgId, uid, oldPkgPrivileges);
399 m_privilegeDb.UpdateAppPrivileges(appId, uid, std::vector<std::string>());
400 m_privilegeDb.RemoveApplication(appId, uid, removePkg);
401 m_privilegeDb.GetPkgPrivileges(pkgId, uid, newPkgPrivileges);
402 CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges,
404 m_privilegeDb.CommitTransaction();
405 LogDebug("Application uninstallation commited to database");
407 } catch (const PrivilegeDb::Exception::InternalError &e) {
408 m_privilegeDb.RollbackTransaction();
409 LogError("Error while removing application info from database: " << e.DumpToString());
411 } catch (const CynaraException::Base &e) {
412 m_privilegeDb.RollbackTransaction();
413 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
415 } catch (const std::bad_alloc &e) {
416 m_privilegeDb.RollbackTransaction();
417 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
424 LogDebug("Removing Smack rules for deleted pkgId " << pkgId);
425 if (!SmackRules::uninstallPackageRules(pkgId)) {
426 LogError("Error on uninstallation of package-specific smack rules");
433 Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
437 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
441 bool Service::processGetPkgId(MessageBuffer &buffer, MessageBuffer &send)
443 // deserialize request data
447 Deserialization::Deserialize(buffer, appId);
448 LogDebug("appId: " << appId);
451 if (!m_privilegeDb.GetAppPkgId(appId, pkgId)) {
452 LogWarning("Application " << appId << " not found in database");
453 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT);
456 LogDebug("pkgId: " << pkgId);
458 } catch (const PrivilegeDb::Exception::InternalError &e) {
459 LogError("Error while getting pkgId from database: " << e.DumpToString());
460 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
465 Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
466 Serialization::Serialize(send, pkgId);
470 bool Service::processGetAppGroups(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid)
472 std::unordered_set<gid_t> gids;
477 std::string smackLabel;
478 std::string uidStr = std::to_string(uid);
479 std::string pidStr = std::to_string(pid);
481 Deserialization::Deserialize(buffer, appId);
482 LogDebug("appId: " << appId);
484 if (!m_privilegeDb.GetAppPkgId(appId, pkgId)) {
485 LogWarning("Application " << appId << " not found in database");
486 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT);
489 LogDebug("pkgId: " << pkgId);
491 if (!generateAppLabel(pkgId, smackLabel)) {
492 LogError("Cannot generate Smack label for package: " << pkgId);
493 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT);
496 LogDebug("smack label: " << smackLabel);
498 std::vector<std::string> privileges;
499 m_privilegeDb.GetPkgPrivileges(pkgId, uid, privileges);
500 /*there is also a need of checking, if privilege is granted to all users*/
501 size_t tmp = privileges.size();
502 m_privilegeDb.GetPkgPrivileges(pkgId, getGlobalUserId(), privileges);
503 /*privileges needs to be sorted and with no duplications - for cynara sake*/
504 std::inplace_merge(privileges.begin(), privileges.begin() + tmp, privileges.end());
505 privileges.erase( unique( privileges.begin(), privileges.end() ), privileges.end() );
507 for (const auto &privilege : privileges) {
508 std::vector<std::string> gidsTmp;
509 m_privilegeDb.GetPrivilegeGroups(privilege, gidsTmp);
510 if (!gidsTmp.empty()) {
511 LogDebug("Considering privilege " << privilege << " with " <<
512 gidsTmp.size() << " groups assigned");
513 if (m_cynara.check(smackLabel, privilege, uidStr, pidStr)) {
514 for_each(gidsTmp.begin(), gidsTmp.end(), [&] (std::string group)
516 struct group *grp = getgrnam(group.c_str());
518 LogError("No such group: " << group.c_str());
521 gids.insert(grp->gr_gid);
523 LogDebug("Cynara allowed, adding groups");
525 LogDebug("Cynara denied, not adding groups");
528 } catch (const PrivilegeDb::Exception::InternalError &e) {
529 LogError("Database error: " << e.DumpToString());
530 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
532 } catch (const CynaraException::Base &e) {
533 LogError("Error while querying Cynara for permissions: " << e.DumpToString());
534 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
536 } catch (const std::bad_alloc &e) {
537 LogError("Memory allocation failed: " << e.what());
538 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY);
543 Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
544 Serialization::Serialize(send, static_cast<int>(gids.size()));
545 for (const auto &gid : gids) {
546 Serialization::Serialize(send, gid);
552 } // namespace SecurityManager