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 PrivilegeDb::getInstance().BeginTransaction();
315 PrivilegeDb::getInstance().GetPkgPrivileges(req.pkgId, uid, oldPkgPrivileges);
316 PrivilegeDb::getInstance().AddApplication(req.appId, req.pkgId, uid, pkgIdIsNew);
317 PrivilegeDb::getInstance().UpdateAppPrivileges(req.appId, uid, req.privileges);
318 PrivilegeDb::getInstance().GetPkgPrivileges(req.pkgId, uid, newPkgPrivileges);
319 CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges,
321 PrivilegeDb::getInstance().CommitTransaction();
322 LogDebug("Application installation commited to database");
323 } catch (const PrivilegeDb::Exception::IOError &e) {
324 LogError("Cannot access application database: " << e.DumpToString());
326 } catch (const PrivilegeDb::Exception::InternalError &e) {
327 PrivilegeDb::getInstance().RollbackTransaction();
328 LogError("Error while saving application info to database: " << e.DumpToString());
330 } catch (const CynaraException::Base &e) {
331 PrivilegeDb::getInstance().RollbackTransaction();
332 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
334 } catch (const std::bad_alloc &e) {
335 PrivilegeDb::getInstance().RollbackTransaction();
336 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
341 for (const auto &appPath : req.appPaths) {
342 const std::string &path = appPath.first;
343 app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
344 int result = setupPath(req.pkgId, path, pathType);
347 LogError("setupPath() failed");
353 LogDebug("Adding Smack rules for new pkgId " << req.pkgId);
354 if (!SmackRules::installPackageRules(req.pkgId)) {
355 LogError("Failed to apply package-specific smack rules");
361 Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
365 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
369 bool Service::processAppUninstall(MessageBuffer &buffer, MessageBuffer &send, uid_t uid)
371 // deserialize request data
374 std::string smackLabel;
375 bool appExists = true;
376 bool removePkg = false;
378 Deserialization::Deserialize(buffer, appId);
380 checkGlobalUser(uid, uidstr);
383 std::vector<std::string> oldPkgPrivileges, newPkgPrivileges;
385 PrivilegeDb::getInstance().BeginTransaction();
386 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
387 LogWarning("Application " << appId <<
388 " not found in database while uninstalling");
389 PrivilegeDb::getInstance().RollbackTransaction();
393 LogDebug("Uninstall parameters: appId: " << appId << ", pkgId: " << pkgId
394 << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
396 if (!generateAppLabel(pkgId, smackLabel)) {
397 LogError("Cannot generate Smack label for package: " << pkgId);
401 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, oldPkgPrivileges);
402 PrivilegeDb::getInstance().UpdateAppPrivileges(appId, uid, std::vector<std::string>());
403 PrivilegeDb::getInstance().RemoveApplication(appId, uid, removePkg);
404 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, newPkgPrivileges);
405 CynaraAdmin::UpdatePackagePolicy(smackLabel, uidstr, oldPkgPrivileges,
407 PrivilegeDb::getInstance().CommitTransaction();
408 LogDebug("Application uninstallation commited to database");
410 } catch (const PrivilegeDb::Exception::IOError &e) {
411 LogError("Cannot access application database: " << e.DumpToString());
413 } catch (const PrivilegeDb::Exception::InternalError &e) {
414 PrivilegeDb::getInstance().RollbackTransaction();
415 LogError("Error while removing application info from database: " << e.DumpToString());
417 } catch (const CynaraException::Base &e) {
418 PrivilegeDb::getInstance().RollbackTransaction();
419 LogError("Error while setting Cynara rules for application: " << e.DumpToString());
421 } catch (const std::bad_alloc &e) {
422 PrivilegeDb::getInstance().RollbackTransaction();
423 LogError("Memory allocation while setting Cynara rules for application: " << e.what());
430 LogDebug("Removing Smack rules for deleted pkgId " << pkgId);
431 if (!SmackRules::uninstallPackageRules(pkgId)) {
432 LogError("Error on uninstallation of package-specific smack rules");
439 Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
443 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
447 bool Service::processGetPkgId(MessageBuffer &buffer, MessageBuffer &send)
449 // deserialize request data
453 Deserialization::Deserialize(buffer, appId);
454 LogDebug("appId: " << appId);
457 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
458 LogWarning("Application " << appId << " not found in database");
459 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT);
462 LogDebug("pkgId: " << pkgId);
464 } catch (const PrivilegeDb::Exception::Base &e) {
465 LogError("Error while getting pkgId from database: " << e.DumpToString());
466 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
471 Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
472 Serialization::Serialize(send, pkgId);
476 bool Service::processGetAppGroups(MessageBuffer &buffer, MessageBuffer &send, uid_t uid, pid_t pid)
478 std::unordered_set<gid_t> gids;
483 std::string smackLabel;
484 std::string uidStr = std::to_string(uid);
485 std::string pidStr = std::to_string(pid);
487 Deserialization::Deserialize(buffer, appId);
488 LogDebug("appId: " << appId);
490 if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
491 LogWarning("Application " << appId << " not found in database");
492 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT);
495 LogDebug("pkgId: " << pkgId);
497 if (!generateAppLabel(pkgId, smackLabel)) {
498 LogError("Cannot generate Smack label for package: " << pkgId);
499 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT);
502 LogDebug("smack label: " << smackLabel);
504 std::vector<std::string> privileges;
505 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, privileges);
506 /*there is also a need of checking, if privilege is granted to all users*/
507 size_t tmp = privileges.size();
508 PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, getGlobalUserId(), privileges);
509 /*privileges needs to be sorted and with no duplications - for cynara sake*/
510 std::inplace_merge(privileges.begin(), privileges.begin() + tmp, privileges.end());
511 privileges.erase( unique( privileges.begin(), privileges.end() ), privileges.end() );
513 for (const auto &privilege : privileges) {
514 std::vector<std::string> gidsTmp;
515 PrivilegeDb::getInstance().GetPrivilegeGroups(privilege, gidsTmp);
516 if (!gidsTmp.empty()) {
517 LogDebug("Considering privilege " << privilege << " with " <<
518 gidsTmp.size() << " groups assigned");
519 if (Cynara::getInstance().check(smackLabel, privilege, uidStr, pidStr)) {
520 for_each(gidsTmp.begin(), gidsTmp.end(), [&] (std::string group)
522 struct group *grp = getgrnam(group.c_str());
524 LogError("No such group: " << group.c_str());
527 gids.insert(grp->gr_gid);
529 LogDebug("Cynara allowed, adding groups");
531 LogDebug("Cynara denied, not adding groups");
534 } catch (const PrivilegeDb::Exception::Base &e) {
535 LogError("Database error: " << e.DumpToString());
536 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
538 } catch (const CynaraException::Base &e) {
539 LogError("Error while querying Cynara for permissions: " << e.DumpToString());
540 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_SERVER_ERROR);
542 } catch (const std::bad_alloc &e) {
543 LogError("Memory allocation failed: " << e.what());
544 Serialization::Serialize(send, SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY);
549 Serialization::Serialize(send, SECURITY_MANAGER_API_SUCCESS);
550 Serialization::Serialize(send, static_cast<int>(gids.size()));
551 for (const auto &gid : gids) {
552 Serialization::Serialize(send, gid);
558 } // namespace SecurityManager