3f959a9a2808088f77b749665471ff2c35ec9719
[platform/core/security/security-manager.git] / src / common / service_impl.cpp
1 /*
2  *  Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Rafal Krypa <r.krypa@samsung.com>
5  *
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
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
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
17  */
18 /*
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  * @author      Krzysztof Sasiak <k.sasiak@samsung.com>
24  * @brief       Implementation of the service methods
25  */
26
27 #include <grp.h>
28 #include <limits.h>
29 #include <pwd.h>
30 #include <sys/socket.h>
31
32 #include <cstring>
33 #include <algorithm>
34
35 #include <dpl/log/log.h>
36 #include <tzplatform_config.h>
37
38 #include <config.h>
39 #include "protocols.h"
40 #include "privilege_db.h"
41 #include "cynara.h"
42 #include "smack-rules.h"
43 #include "smack-labels.h"
44 #include "security-manager.h"
45 #include "zone-utils.h"
46
47 #include "service_impl.h"
48 #include "master-req.h"
49
50 namespace SecurityManager {
51
52 static const std::string ADMIN_PRIVILEGE = "http://tizen.org/privilege/systemsettings.admin";
53 static const std::string SELF_PRIVILEGE = "http://tizen.org/privilege/systemsettings";
54
55 namespace {
56
57 static inline int validatePolicy(policy_entry &policyEntry, std::string uidStr, bool &forAdmin, CynaraAdminPolicy &cyap)
58 {
59     LogDebug("Authenticating and validating policy update request for user with id: " << uidStr);
60     LogDebug("[policy_entry] app: " << policyEntry.appId
61             << " user: " << policyEntry.user
62             << " privilege: " << policyEntry.privilege
63             << " current: " << policyEntry.currentLevel
64             << " max: " << policyEntry.maxLevel);
65     //automagically fill missing fields:
66     if (policyEntry.user.empty()) {
67         policyEntry.user = uidStr;
68     };
69
70     int level;
71
72     if (policyEntry.currentLevel.empty()) { //for admin
73         if (policyEntry.appId.empty()
74             || policyEntry.privilege.empty()) {
75             LogError("Bad admin update request");
76             return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
77         };
78
79         if (!policyEntry.maxLevel.compare(SECURITY_MANAGER_DELETE)) {
80             level = CYNARA_ADMIN_DELETE;
81         } else {
82             try {
83                 level = CynaraAdmin::getInstance().convertToPolicyType(policyEntry.maxLevel);
84             } catch (const std::out_of_range& e) {
85                 LogError("policy max level cannot be: " << policyEntry.maxLevel);
86                 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
87             };
88         };
89         forAdmin = true;
90
91     } else if (policyEntry.maxLevel.empty()) { //for self
92         if (policyEntry.user.compare(uidStr)
93             || !policyEntry.appId.compare(SECURITY_MANAGER_ANY)
94             || !policyEntry.privilege.compare(SECURITY_MANAGER_ANY)
95             || policyEntry.appId.empty()
96             || policyEntry.privilege.empty()) {
97             LogError("Bad privacy manager update request");
98             return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
99         };
100
101         if (!policyEntry.currentLevel.compare(SECURITY_MANAGER_DELETE)) {
102             level = CYNARA_ADMIN_DELETE;
103         } else {
104             try {
105                 level = CynaraAdmin::getInstance().convertToPolicyType(policyEntry.currentLevel);
106             } catch (const std::out_of_range& e) {
107                 LogError("policy current level cannot be: " << policyEntry.currentLevel);
108                 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
109             };
110         };
111         forAdmin = false;
112
113     } else { //neither => bad request
114         return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
115     };
116
117     if (!policyEntry.user.compare(SECURITY_MANAGER_ANY))
118         policyEntry.user = CYNARA_ADMIN_WILDCARD;
119     if (!policyEntry.privilege.compare(SECURITY_MANAGER_ANY))
120         policyEntry.privilege = CYNARA_ADMIN_WILDCARD;
121
122     cyap = std::move(CynaraAdminPolicy(
123         policyEntry.appId.compare(SECURITY_MANAGER_ANY) ?
124             SmackLabels::generateAppLabel(policyEntry.appId) : CYNARA_ADMIN_WILDCARD,
125         policyEntry.user,
126         policyEntry.privilege,
127         level,
128         (forAdmin)?CynaraAdmin::Buckets.at(Bucket::ADMIN):CynaraAdmin::Buckets.at(Bucket::PRIVACY_MANAGER)));
129
130     LogDebug("Policy update request authenticated and validated successfully");
131     return SECURITY_MANAGER_API_SUCCESS;
132 }
133 } // end of anonymous namespace
134
135 ServiceImpl::ServiceImpl()
136 {
137 }
138
139 ServiceImpl::~ServiceImpl()
140 {
141 }
142
143 uid_t ServiceImpl::getGlobalUserId(void)
144 {
145     static uid_t globaluid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
146     return globaluid;
147 }
148
149 /**
150  * Unifies user data of apps installed for all users
151  * @param  uid            peer's uid - may be changed during process
152  * @param  cynaraUserStr  string to which cynara user parameter will be put
153  */
154 void ServiceImpl::checkGlobalUser(uid_t &uid, std::string &cynaraUserStr)
155 {
156     static uid_t globaluid = getGlobalUserId();
157     if (uid == 0 || uid == globaluid) {
158         uid = globaluid;
159         cynaraUserStr = CYNARA_ADMIN_WILDCARD;
160     } else {
161         cynaraUserStr = std::to_string(static_cast<unsigned int>(uid));
162     }
163 }
164
165 bool ServiceImpl::isSubDir(const char *parent, const char *subdir)
166 {
167     while (*parent && *subdir)
168         if (*parent++ != *subdir++)
169             return false;
170
171     return (*subdir == '/');
172 }
173
174 bool ServiceImpl::getUserAppDir(const uid_t &uid, std::string &userAppDir)
175 {
176     struct tzplatform_context *tz_ctx = nullptr;
177
178     if (tzplatform_context_create(&tz_ctx))
179             return false;
180
181     if (tzplatform_context_set_user(tz_ctx, uid)) {
182         tzplatform_context_destroy(tz_ctx);
183         tz_ctx = nullptr;
184         return false;
185     }
186
187     enum tzplatform_variable id =
188             (uid == getGlobalUserId()) ? TZ_SYS_RW_APP : TZ_USER_APP;
189     const char *appDir = tzplatform_context_getenv(tz_ctx, id);
190     if (!appDir) {
191         tzplatform_context_destroy(tz_ctx);
192         tz_ctx = nullptr;
193         return false;
194     }
195
196     userAppDir = appDir;
197
198     tzplatform_context_destroy(tz_ctx);
199     tz_ctx = nullptr;
200
201     return true;
202 }
203
204 bool ServiceImpl::installRequestAuthCheck(const app_inst_req &req, uid_t uid, bool &isCorrectPath, std::string &appPath)
205 {
206     std::string userHome;
207     std::string userAppDir;
208     std::stringstream correctPath;
209
210     if (uid != getGlobalUserId())
211         LogDebug("Installation type: single user");
212     else
213         LogDebug("Installation type: global installation");
214
215     if (!getUserAppDir(uid, userAppDir)) {
216         LogError("Failed getting app dir for user uid: " << uid);
217         return false;
218     }
219
220     appPath = userAppDir;
221     correctPath.clear();
222     correctPath << userAppDir << "/" << req.pkgId << "/" << req.appId;
223     LogDebug("correctPath: " << correctPath.str());
224
225     for (const auto &appPath : req.appPaths) {
226         std::unique_ptr<char, std::function<void(void*)>> real_path(
227             realpath(appPath.first.c_str(), NULL), free);
228         if (!real_path.get()) {
229             LogError("realpath failed with '" << appPath.first.c_str()
230                     << "' as parameter: " << strerror(errno));
231             return false;
232         }
233         LogDebug("Requested path is '" << appPath.first.c_str()
234                 << "'. User's APPS_DIR is '" << userAppDir << "'");
235         if (!isSubDir(userAppDir.c_str(), real_path.get())) {
236             LogWarning("User's apps may have registered folders only in user's APPS_DIR");
237             return false;
238         }
239
240         if (!isSubDir(correctPath.str().c_str(), real_path.get())) {
241             LogWarning("Installation is outside correct path: " << correctPath.str());
242             //return false;
243         } else
244             isCorrectPath = true;
245
246         app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
247         if (pathType == SECURITY_MANAGER_PATH_PUBLIC) {
248             LogWarning("Only root can register SECURITY_MANAGER_PATH_PUBLIC path");
249             return false;
250         }
251     }
252     return true;
253 }
254
255 bool ServiceImpl::getZoneId(std::string &zoneId)
256 {
257     if (!getZoneIdFromPid(getpid(), zoneId)) {
258         LogError("Failed to get zone ID from current PID");
259         return false;
260     }
261
262     // This function should be called under slave mode only - assumes, that we work inside zone
263     if (zoneId == ZONE_HOST) {
264         LogError("We should not run in host - refusing request");
265         return false;
266     }
267
268     return true;
269 }
270
271 int ServiceImpl::appInstall(const app_inst_req &req, uid_t uid, bool isSlave)
272 {
273     std::vector<std::string> addedPermissions;
274     std::vector<std::string> removedPermissions;
275     std::vector<std::string> pkgContents;
276     std::string uidstr;
277     bool isCorrectPath = false;
278     std::string appPath;
279     std::string appLabel;
280     std::string pkgLabel;
281
282     std::string zoneId;
283     if (isSlave) {
284         if (!getZoneId(zoneId)) {
285             LogError("Failed to get Zone ID.");
286             return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
287         }
288     }
289
290     if (uid) {
291         if (uid != req.uid) {
292             LogError("User " << uid <<
293                      " is denied to install application for user " << req.uid);
294             return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
295         }
296     } else {
297         if (req.uid)
298             uid = req.uid;
299     }
300     checkGlobalUser(uid, uidstr);
301
302     if (!installRequestAuthCheck(req, uid, isCorrectPath, appPath)) {
303         LogError("Request from uid " << uid << " for app installation denied");
304         return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
305     }
306
307     try {
308         std::vector<std::string> oldAppPrivileges;
309
310         appLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(req.appId), zoneId);
311         /* NOTE: we don't use pkgLabel here, but generate it for pkgId validation */
312         pkgLabel = zoneSmackLabelGenerate(SmackLabels::generatePkgLabel(req.pkgId), zoneId);
313         LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
314                  << ", uidstr " << uidstr
315                  << ", app label: " << appLabel << ", pkg label: " << pkgLabel);
316
317         PrivilegeDb::getInstance().BeginTransaction();
318         std::string pkg;
319         bool ret = PrivilegeDb::getInstance().GetAppPkgId(req.appId, pkg);
320         if (ret == true && pkg != req.pkgId) {
321             LogError("Application already installed with different package id");
322             PrivilegeDb::getInstance().RollbackTransaction();
323             return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
324         }
325         PrivilegeDb::getInstance().GetAppPrivileges(req.appId, uid, oldAppPrivileges);
326         PrivilegeDb::getInstance().AddApplication(req.appId, req.pkgId, uid);
327         PrivilegeDb::getInstance().UpdateAppPrivileges(req.appId, uid, req.privileges);
328         /* Get all application ids in the package to generate rules withing the package */
329         PrivilegeDb::getInstance().GetAppIdsForPkgId(req.pkgId, pkgContents);
330
331         if (isSlave) {
332             int ret = MasterReq::CynaraPolicyUpdate(req.appId, uidstr, oldAppPrivileges,
333                                                     req.privileges);
334             if (ret != SECURITY_MANAGER_API_SUCCESS) {
335                 PrivilegeDb::getInstance().RollbackTransaction();
336                 LogError("Error while processing request on master: " << ret);
337                 return ret;
338             }
339         } else {
340             CynaraAdmin::getInstance().UpdateAppPolicy(appLabel, uidstr, oldAppPrivileges,
341                                                        req.privileges);
342         }
343
344         PrivilegeDb::getInstance().CommitTransaction();
345         LogDebug("Application installation commited to database");
346     } catch (const PrivilegeDb::Exception::IOError &e) {
347         LogError("Cannot access application database: " << e.DumpToString());
348         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
349     } catch (const PrivilegeDb::Exception::InternalError &e) {
350         PrivilegeDb::getInstance().RollbackTransaction();
351         LogError("Error while saving application info to database: " << e.DumpToString());
352         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
353     } catch (const CynaraException::Base &e) {
354         PrivilegeDb::getInstance().RollbackTransaction();
355         LogError("Error while setting Cynara rules for application: " << e.DumpToString());
356         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
357     } catch (const SmackException::InvalidLabel &e) {
358         PrivilegeDb::getInstance().RollbackTransaction();
359         LogError("Error while generating Smack labels: " << e.DumpToString());
360         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
361     } catch (const std::bad_alloc &e) {
362         PrivilegeDb::getInstance().RollbackTransaction();
363         LogError("Memory allocation while setting Cynara rules for application: " << e.what());
364         return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
365     }
366
367     try {
368         if (isCorrectPath)
369             SmackLabels::setupCorrectPath(req.pkgId, req.appId, appPath, zoneId);
370
371         // register paths
372         for (const auto &appPath : req.appPaths) {
373             const std::string &path = appPath.first;
374             app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
375             SmackLabels::setupPath(req.appId, path, pathType, zoneId);
376         }
377
378         if (isSlave) {
379             LogDebug("Requesting master to add rules for new appId: " << req.appId << " with pkgId: "
380                     << req.pkgId << ". Applications in package: " << pkgContents.size());
381             int ret = MasterReq::SmackInstallRules(req.appId, req.pkgId, pkgContents);
382             if (ret != SECURITY_MANAGER_API_SUCCESS) {
383                 LogError("Master failed to apply package-specific smack rules: " << ret);
384                 return ret;
385             }
386         } else {
387             LogDebug("Adding Smack rules for new appId: " << req.appId << " with pkgId: "
388                     << req.pkgId << ". Applications in package: " << pkgContents.size());
389             SmackRules::installApplicationRules(req.appId, req.pkgId, pkgContents);
390         }
391     } catch (const SmackException::Base &e) {
392         LogError("Error while applying Smack policy for application: " << e.DumpToString());
393         return SECURITY_MANAGER_API_ERROR_SETTING_FILE_LABEL_FAILED;
394     } catch (const SecurityManager::Exception &e) {
395         LogError("Security Manager exception: " << e.DumpToString());
396         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
397     }catch (const std::bad_alloc &e) {
398         LogError("Memory allocation error: " << e.what());
399         return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
400     }
401
402     return SECURITY_MANAGER_API_SUCCESS;
403 }
404
405 int ServiceImpl::appUninstall(const std::string &appId, uid_t uid, bool isSlave)
406 {
407     std::string pkgId;
408     std::string smackLabel;
409     std::vector<std::string> pkgContents;
410     bool appExists = true;
411     bool removePkg = false;
412     std::string uidstr;
413     checkGlobalUser(uid, uidstr);
414
415     std::string zoneId;
416     if (isSlave) {
417         if (!getZoneId(zoneId)) {
418             LogError("Failed to get Zone ID.");
419             return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
420         }
421     }
422
423     try {
424         std::vector<std::string> oldAppPrivileges;
425
426         PrivilegeDb::getInstance().BeginTransaction();
427         if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
428             LogWarning("Application " << appId <<
429                 " not found in database while uninstalling");
430             PrivilegeDb::getInstance().RollbackTransaction();
431             appExists = false;
432         } else {
433             smackLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(appId), zoneId);
434             LogDebug("Uninstall parameters: appId: " << appId << ", pkgId: " << pkgId
435                      << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
436
437             /* Before we remove the app from the database, let's fetch all apps in the package
438                 that this app belongs to, this will allow us to remove all rules withing the
439                 package that the app appears in */
440             PrivilegeDb::getInstance().GetAppIdsForPkgId(pkgId, pkgContents);
441             PrivilegeDb::getInstance().GetAppPrivileges(appId, uid, oldAppPrivileges);
442             PrivilegeDb::getInstance().UpdateAppPrivileges(appId, uid, std::vector<std::string>());
443             PrivilegeDb::getInstance().RemoveApplication(appId, uid, removePkg);
444
445             if (isSlave) {
446                 int ret = MasterReq::CynaraPolicyUpdate(appId, uidstr, oldAppPrivileges,
447                                                         std::vector<std::string>());
448                 if (ret != SECURITY_MANAGER_API_SUCCESS) {
449                     PrivilegeDb::getInstance().RollbackTransaction();
450                     LogError("Error while processing request on master: " << ret);
451                     return ret;
452                 }
453             } else {
454                 CynaraAdmin::getInstance().UpdateAppPolicy(smackLabel, uidstr, oldAppPrivileges,
455                                                            std::vector<std::string>());
456             }
457
458             PrivilegeDb::getInstance().CommitTransaction();
459             LogDebug("Application uninstallation commited to database");
460         }
461     } catch (const PrivilegeDb::Exception::IOError &e) {
462         LogError("Cannot access application database: " << e.DumpToString());
463         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
464     } catch (const PrivilegeDb::Exception::InternalError &e) {
465         PrivilegeDb::getInstance().RollbackTransaction();
466         LogError("Error while removing application info from database: " << e.DumpToString());
467         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
468     } catch (const CynaraException::Base &e) {
469         PrivilegeDb::getInstance().RollbackTransaction();
470         LogError("Error while setting Cynara rules for application: " << e.DumpToString());
471         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
472     } catch (const SmackException::InvalidLabel &e) {
473         PrivilegeDb::getInstance().RollbackTransaction();
474         LogError("Error while generating Smack labels: " << e.DumpToString());
475         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
476     } catch (const std::bad_alloc &e) {
477         PrivilegeDb::getInstance().RollbackTransaction();
478         LogError("Memory allocation while setting Cynara rules for application: " << e.what());
479         return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
480     }
481
482     if (appExists) {
483         try {
484             if (isSlave) {
485                 LogDebug("Delegating Smack rules removal for deleted pkgId " << pkgId <<
486                          " to master");
487                 int ret = MasterReq::SmackUninstallRules(appId, pkgId, pkgContents, removePkg);
488                 if (ret != SECURITY_MANAGER_API_SUCCESS) {
489                     LogError("Error while processing uninstall request on master: " << ret);
490                     return ret;
491                 }
492             } else {
493                 if (removePkg) {
494                     LogDebug("Removing Smack rules for deleted pkgId " << pkgId);
495                     SmackRules::uninstallPackageRules(pkgId);
496                 }
497
498                 LogDebug ("Removing smack rules for deleted appId " << appId);
499                 SmackRules::uninstallApplicationRules(appId, pkgId, pkgContents, zoneId);
500             }
501         } catch (const SmackException::Base &e) {
502             LogError("Error while removing Smack rules for application: " << e.DumpToString());
503             return SECURITY_MANAGER_API_ERROR_SETTING_FILE_LABEL_FAILED;
504         } catch (const SecurityManager::Exception &e) {
505             LogError("Security Manager error: " << e.DumpToString());
506             return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
507         } catch (const std::bad_alloc &e) {
508             LogError("Memory allocation error: " << e.what());
509             return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
510         }
511     }
512
513     return SECURITY_MANAGER_API_SUCCESS;
514 }
515
516 int ServiceImpl::getPkgId(const std::string &appId, std::string &pkgId)
517 {
518     LogDebug("appId: " << appId);
519
520     try {
521         if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
522             LogWarning("Application " << appId << " not found in database");
523             return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
524         } else {
525             LogDebug("pkgId: " << pkgId);
526         }
527     } catch (const PrivilegeDb::Exception::Base &e) {
528         LogError("Error while getting pkgId from database: " << e.DumpToString());
529         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
530     }
531
532     return SECURITY_MANAGER_API_SUCCESS;
533 }
534
535 int ServiceImpl::getAppGroups(const std::string &appId, uid_t uid, pid_t pid, bool isSlave,
536         std::unordered_set<gid_t> &gids)
537 {
538     // FIXME Temporary solution, see below
539     std::string zoneId;
540     if (isSlave) {
541         if (!getZoneId(zoneId)) {
542             LogError("Failed to get Zone ID.");
543             return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
544         }
545     }
546
547     try {
548         std::string pkgId;
549         std::string smackLabel;
550         std::string uidStr = std::to_string(uid);
551         std::string pidStr = std::to_string(pid);
552
553         LogDebug("appId: " << appId);
554
555         if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
556             LogWarning("Application " << appId << " not found in database");
557             return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
558         }
559         LogDebug("pkgId: " << pkgId);
560
561         // FIXME getAppGroups should work without generating zone-specific labels when
562         //       Smack Namespaces will work
563         smackLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(appId), zoneId);
564         LogDebug("smack label: " << smackLabel);
565
566         std::vector<std::string> privileges;
567         PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, privileges);
568         /*there is also a need of checking, if privilege is granted to all users*/
569         size_t tmp = privileges.size();
570         PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, getGlobalUserId(), privileges);
571         /*privileges needs to be sorted and with no duplications - for cynara sake*/
572         std::inplace_merge(privileges.begin(), privileges.begin() + tmp, privileges.end());
573         privileges.erase(unique(privileges.begin(), privileges.end()), privileges.end());
574
575         for (const auto &privilege : privileges) {
576             std::vector<std::string> gidsTmp;
577             PrivilegeDb::getInstance().GetPrivilegeGroups(privilege, gidsTmp);
578             if (!gidsTmp.empty()) {
579                 LogDebug("Considering privilege " << privilege << " with " <<
580                     gidsTmp.size() << " groups assigned");
581                 // TODO: create method in Cynara class for fetching all privileges of an application
582                 if (Cynara::getInstance().check(smackLabel, privilege, uidStr, pidStr)) {
583                     for_each(gidsTmp.begin(), gidsTmp.end(), [&] (std::string group) {
584                         struct group *grp = getgrnam(group.c_str());
585                         if (grp == NULL) {
586                                 LogError("No such group: " << group.c_str());
587                                 return;
588                         }
589                         gids.insert(grp->gr_gid);
590                     });
591                     LogDebug("Cynara allowed, adding groups");
592                 } else
593                     LogDebug("Cynara denied, not adding groups");
594             }
595         }
596     } catch (const PrivilegeDb::Exception::Base &e) {
597         LogError("Database error: " << e.DumpToString());
598         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
599     } catch (const CynaraException::Base &e) {
600         LogError("Error while querying Cynara for permissions: " << e.DumpToString());
601         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
602     } catch (const SmackException::InvalidLabel &e) {
603         LogError("Error while generating Smack labels: " << e.DumpToString());
604         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
605     } catch (const std::bad_alloc &e) {
606         LogError("Memory allocation failed: " << e.what());
607         return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
608     }
609
610     return SECURITY_MANAGER_API_SUCCESS;
611 }
612
613 int ServiceImpl::userAdd(uid_t uidAdded, int userType, uid_t uid, bool isSlave)
614 {
615     if (uid != 0)
616         return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
617
618     if (isSlave) {
619         int ret = MasterReq::CynaraUserInit(uidAdded,
620                                             static_cast<security_manager_user_type>(userType));
621         if (ret != SECURITY_MANAGER_API_SUCCESS) {
622             LogError("Master failed to initialize user " << uidAdded << " of type " << userType);
623             return ret;
624         }
625     } else {
626         try {
627             CynaraAdmin::getInstance().UserInit(uidAdded, static_cast<security_manager_user_type>(userType));
628         } catch (CynaraException::InvalidParam &e) {
629             return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
630         }
631     }
632
633     return SECURITY_MANAGER_API_SUCCESS;
634 }
635
636 int ServiceImpl::userDelete(uid_t uidDeleted, uid_t uid, bool isSlave)
637 {
638     int ret = SECURITY_MANAGER_API_SUCCESS;
639     if (uid != 0)
640         return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
641
642     /*Uninstall all user apps*/
643     std::vector<std::string> userApps;
644     try {
645         PrivilegeDb::getInstance().GetUserApps(uidDeleted, userApps);
646     } catch (const PrivilegeDb::Exception::Base &e) {
647         LogError("Error while getting user apps from database: " << e.DumpToString());
648         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
649     }
650
651     for (auto &app: userApps) {
652         if (appUninstall(app, uidDeleted, isSlave) != SECURITY_MANAGER_API_SUCCESS) {
653         /*if uninstallation of this app fails, just go on trying to uninstall another ones.
654         we do not have anything special to do about that matter - user will be deleted anyway.*/
655             ret = SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
656         }
657     }
658
659     if (isSlave) {
660         int ret = MasterReq::CynaraUserRemove(uidDeleted);
661         if (ret) {
662             LogError("Master failed to delete user " << uidDeleted);
663             return ret;
664         }
665     } else {
666         CynaraAdmin::getInstance().UserRemove(uidDeleted);
667     }
668
669     return ret;
670 }
671
672 int ServiceImpl::policyUpdate(const std::vector<policy_entry> &policyEntries, uid_t uid, pid_t pid, const std::string &smackLabel)
673 {
674     enum {
675         NOT_CHECKED,
676         IS_NOT_ADMIN,
677         IS_ADMIN
678     }  isAdmin = NOT_CHECKED;
679
680     try {
681         std::string uidStr = std::to_string(uid);
682         std::string pidStr = std::to_string(pid);
683
684         if (policyEntries.size() == 0) {
685             LogError("Validation failed: policy update request is empty");
686             return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
687         };
688
689         if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
690             LogError("Not enough permission to call: " << __FUNCTION__);
691             return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
692         };
693
694         std::vector<CynaraAdminPolicy> validatedPolicies;
695
696         for (auto &entry : const_cast<std::vector<policy_entry>&>(policyEntries)) {
697             bool forAdmin = false;
698             CynaraAdminPolicy cyap("", "", "", CYNARA_ADMIN_NONE, "");
699             int ret = validatePolicy(entry, uidStr, forAdmin, cyap);
700
701             if (forAdmin && (isAdmin == NOT_CHECKED)) {
702                 isAdmin = Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)?IS_ADMIN:IS_NOT_ADMIN;
703             };
704
705             if (ret == SECURITY_MANAGER_API_SUCCESS) {
706                 if (!forAdmin
707                     || (forAdmin && (isAdmin == IS_ADMIN))) {
708                     validatedPolicies.push_back(std::move(cyap));
709                 } else {
710                     LogError("Not enough privilege to enforce admin policy");
711                     return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
712                 };
713
714             } else
715                 return ret;
716         };
717
718             // Apply updates
719         CynaraAdmin::getInstance().SetPolicies(validatedPolicies);
720
721     } catch (const CynaraException::Base &e) {
722         LogError("Error while updating Cynara rules: " << e.DumpToString());
723         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
724     } catch (const std::bad_alloc &e) {
725         LogError("Memory allocation error while updating Cynara rules: " << e.what());
726         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
727     }
728
729     return SECURITY_MANAGER_API_SUCCESS;
730 }
731
732 int ServiceImpl::getConfiguredPolicy(bool forAdmin, const policy_entry &filter, uid_t uid, pid_t pid,
733     const std::string &smackLabel, std::vector<policy_entry> &policyEntries)
734 {
735     try {
736         std::string uidStr = std::to_string(uid);
737         std::string pidStr = std::to_string(pid);
738
739         if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
740             LogError("Not enough permission to call: " << __FUNCTION__);
741             return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
742         };
743
744         LogDebug("Filter is: C: " << filter.appId
745                     << ", U: " << filter.user
746                     << ", P: " << filter.privilege
747                     << ", current: " << filter.currentLevel
748                     << ", max: " << filter.maxLevel
749                     );
750
751         std::vector<CynaraAdminPolicy> listOfPolicies;
752
753         //convert appId to smack label
754         std::string appLabel = filter.appId.compare(SECURITY_MANAGER_ANY) ? SmackLabels::generateAppLabel(filter.appId) : CYNARA_ADMIN_ANY;
755         std::string user = filter.user.compare(SECURITY_MANAGER_ANY) ? filter.user : CYNARA_ADMIN_ANY;
756         std::string privilege = filter.privilege.compare(SECURITY_MANAGER_ANY) ? filter.privilege : CYNARA_ADMIN_ANY;
757
758         LogDebug("App: " << filter.appId << ", Label: " << appLabel);
759
760         if (forAdmin) {
761             if (!Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
762                 LogError("Not enough privilege to access admin enforced policies: " << __FUNCTION__);
763                 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
764                 };
765
766             //Fetch privileges from ADMIN bucket
767             CynaraAdmin::getInstance().ListPolicies(
768                 CynaraAdmin::Buckets.at(Bucket::ADMIN),
769                 appLabel,
770                 user,
771                 privilege,
772                 listOfPolicies
773                 );
774             LogDebug("ADMIN - number of policies matched: " << listOfPolicies.size());
775         } else {
776             if (uidStr.compare(user)) {
777                 if (!Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
778                     LogWarning("Not enough privilege to access other user's personal policies. Limiting query to personal privileges.");
779                     user = uidStr;
780                 };
781             };
782             //Fetch privileges from PRIVACY_MANAGER bucket
783             CynaraAdmin::getInstance().ListPolicies(
784                 CynaraAdmin::Buckets.at(Bucket::PRIVACY_MANAGER),
785                 appLabel,
786                 user,
787                 privilege,
788                 listOfPolicies
789                 );
790             LogDebug("PRIVACY MANAGER - number of policies matched: " << listOfPolicies.size());
791         };
792
793         for (const auto &policy : listOfPolicies) {
794             //ignore "jump to bucket" entries
795             if (policy.result ==  CYNARA_ADMIN_BUCKET)
796                 continue;
797
798             policy_entry pe;
799
800             pe.appId = strcmp(policy.client, CYNARA_ADMIN_WILDCARD) ? SmackLabels::generateAppNameFromLabel(policy.client) : SECURITY_MANAGER_ANY;
801             pe.user =  strcmp(policy.user, CYNARA_ADMIN_WILDCARD) ? policy.user : SECURITY_MANAGER_ANY;
802             pe.privilege = strcmp(policy.privilege, CYNARA_ADMIN_WILDCARD) ? policy.privilege : pe.privilege = SECURITY_MANAGER_ANY;
803             pe.currentLevel = CynaraAdmin::getInstance().convertToPolicyDescription(policy.result);
804
805             if (!forAdmin) {
806                 // All policy entries in PRIVACY_MANAGER should be fully-qualified
807                 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
808                     CynaraAdmin::getInstance().GetPrivilegeManagerMaxLevel(
809                         policy.client, policy.user, policy.privilege));
810             } else {
811                 // Cannot reliably calculate maxLavel for policies from ADMIN bucket
812                 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(CYNARA_ADMIN_ALLOW);
813             }
814
815
816             LogDebug(
817                 "[policy_entry] app: " << pe.appId
818                 << " user: " << pe.user
819                 << " privilege: " << pe.privilege
820                 << " current: " << pe.currentLevel
821                 << " max: " << pe.maxLevel
822                 );
823
824             policyEntries.push_back(pe);
825         };
826
827     } catch (const CynaraException::Base &e) {
828         LogError("Error while listing Cynara rules: " << e.DumpToString());
829         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
830     } catch (const SmackException::InvalidLabel &e) {
831         LogError("Error while generating Smack labels: " << e.DumpToString());
832         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
833     } catch (const std::bad_alloc &e) {
834         LogError("Memory allocation error while listing Cynara rules: " << e.what());
835         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
836     }
837
838
839     return SECURITY_MANAGER_API_SUCCESS;
840 }
841
842 int ServiceImpl::getPolicy(const policy_entry &filter, uid_t uid, pid_t pid, const std::string &smackLabel, std::vector<policy_entry> &policyEntries)
843 {
844     try {
845         std::string uidStr = std::to_string(uid);
846         std::string pidStr = std::to_string(pid);
847
848         if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
849             LogWarning("Not enough permission to call: " << __FUNCTION__);
850             return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
851         };
852
853         LogDebug("Filter is: C: " << filter.appId
854                     << ", U: " << filter.user
855                     << ", P: " << filter.privilege
856                     << ", current: " << filter.currentLevel
857                     << ", max: " << filter.maxLevel
858                     );
859
860         std::vector<uid_t> listOfUsers;
861
862         if (Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
863             LogDebug("User is privileged");
864             if (filter.user.compare(SECURITY_MANAGER_ANY)) {
865                 LogDebug("Limitting Cynara query to user: " << filter.user);
866                 try {
867                     listOfUsers.push_back(static_cast<uid_t>(std::stoul(filter.user)));
868                 } catch (std::invalid_argument &e) {
869                     LogError("Invalid UID: " << e.what());
870                 };
871             } else
872                 CynaraAdmin::getInstance().ListUsers(listOfUsers);
873         } else {
874             LogWarning("Not enough privilege to fetch user policy for all users by user: " << uid);
875             LogDebug("Fetching personal policy for user: " << uid);
876             listOfUsers.push_back(uid);
877         };
878         LogDebug("Fetching policy for " << listOfUsers.size() << " users");
879
880         for (const uid_t &uid : listOfUsers) {
881             LogDebug("User: " << uid);
882             std::string userStr = std::to_string(uid);
883             std::vector<std::string> listOfApps;
884
885             if (filter.appId.compare(SECURITY_MANAGER_ANY)) {
886                 LogDebug("Limitting Cynara query to app: " << filter.appId);
887                 listOfApps.push_back(filter.appId);
888             } else {
889                 PrivilegeDb::getInstance().GetUserApps(uid, listOfApps);
890                 LogDebug("Found apps: " << listOfApps.size());
891             };
892
893             for (const std::string &appId : listOfApps) {
894                 LogDebug("App: " << appId);
895                 std::string smackLabelForApp = SmackLabels::generateAppLabel(appId);
896                 std::vector<std::string> listOfPrivileges;
897
898                 // FIXME: also fetch privileges of global applications
899                 PrivilegeDb::getInstance().GetAppPrivileges(appId, uid, listOfPrivileges);
900
901                 if (filter.privilege.compare(SECURITY_MANAGER_ANY)) {
902                     LogDebug("Limitting Cynara query to privilege: " << filter.privilege);
903                     // FIXME: this filtering should be already performed by method fetching the privileges
904                     if (std::find(listOfPrivileges.begin(), listOfPrivileges.end(),
905                         filter.privilege) == listOfPrivileges.end()) {
906                         LogDebug("Application " << appId <<
907                             " doesn't have the filteres privilege " << filter.privilege);
908                         continue;
909                     }
910                     listOfPrivileges.clear();
911                     listOfPrivileges.push_back(filter.privilege);
912                 }
913
914                 LogDebug("Privileges matching filter - " << filter.privilege << ": " << listOfPrivileges.size());
915
916                 for (const std::string &privilege : listOfPrivileges) {
917                     LogDebug("Privilege: " << privilege);
918                     policy_entry pe;
919
920                     pe.appId = appId;
921                     pe.user = userStr;
922                     pe.privilege = privilege;
923
924                     pe.currentLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
925                         CynaraAdmin::getInstance().GetPrivilegeManagerCurrLevel(
926                             smackLabelForApp, userStr, privilege));
927
928                     pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
929                         CynaraAdmin::getInstance().GetPrivilegeManagerMaxLevel(
930                             smackLabelForApp, userStr, privilege));
931
932                     LogDebug(
933                         "[policy_entry] app: " << pe.appId
934                         << " user: " << pe.user
935                         << " privilege: " << pe.privilege
936                         << " current: " << pe.currentLevel
937                         << " max: " << pe.maxLevel
938                         );
939
940                     policyEntries.push_back(pe);
941                 };
942             };
943         };
944
945     } catch (const CynaraException::Base &e) {
946         LogError("Error while listing Cynara rules: " << e.DumpToString());
947         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
948     } catch (const SmackException::InvalidLabel &e) {
949         LogError("Error while generating Smack labels: " << e.DumpToString());
950         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
951     } catch (const std::bad_alloc &e) {
952         LogError("Memory allocation error while listing Cynara rules: " << e.what());
953         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
954     }
955
956     return SECURITY_MANAGER_API_SUCCESS;
957 }
958
959 int ServiceImpl::policyGetDesc(std::vector<std::string> &levels)
960 {
961     int ret = SECURITY_MANAGER_API_SUCCESS;
962
963     try {
964         CynaraAdmin::getInstance().ListPoliciesDescriptions(levels);
965     } catch (const CynaraException::OutOfMemory &e) {
966         LogError("Error - out of memory while querying Cynara for policy descriptions list: " << e.DumpToString());
967         return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
968     } catch (const CynaraException::InvalidParam &e) {
969         LogError("Error - invalid parameter while querying Cynara for policy descriptions list: " << e.DumpToString());
970         return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
971     } catch (const CynaraException::ServiceNotAvailable &e) {
972         LogError("Error - service not available while querying Cynara for policy descriptions list: " << e.DumpToString());
973         return SECURITY_MANAGER_API_ERROR_NO_SUCH_SERVICE;
974     } catch (const CynaraException::Base &e) {
975         LogError("Error while getting policy descriptions list from Cynara: " << e.DumpToString());
976         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
977     }
978
979     return ret;
980 }
981
982 int ServiceImpl::getPrivilegesMappings(const std::string &version_from,
983                           const std::string &version_to,
984                           const std::vector<std::string> &privileges,
985                           std::vector<std::string> &mappings)
986 {
987     int errorRet;
988     try {
989         std::string finalVersionTo;
990         if (version_to.empty()) {
991             finalVersionTo = Config::PRIVILEGE_VERSION;
992         } else {
993             finalVersionTo = version_to;
994         }
995
996         PrivilegeDb::getInstance().BeginTransaction();
997         if (privileges.size() == 0) {
998             PrivilegeDb::getInstance().GetDefaultMapping(version_from, finalVersionTo, mappings);
999         } else if ( privileges.size() == 1) {
1000             PrivilegeDb::getInstance().GetPrivilegeMappings(version_from, finalVersionTo,
1001                                                             privileges.front(), mappings);
1002         } else {
1003             PrivilegeDb::getInstance().GetPrivilegesMappings(version_from, finalVersionTo,
1004                                                              privileges, mappings);
1005         }
1006         PrivilegeDb::getInstance().CommitTransaction();
1007         return SECURITY_MANAGER_API_SUCCESS;
1008     } catch (const PrivilegeDb::Exception::IOError &e) {
1009         LogError("Cannot access application database: " << e.DumpToString());
1010         errorRet = SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
1011     } catch (const PrivilegeDb::Exception::InternalError &e) {
1012         LogError("Error while getting privilege mapping from database: " << e.DumpToString());
1013         errorRet = SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
1014     } catch (const std::bad_alloc &e) {
1015         LogError("Memory allocation failed: " << e.what());
1016         errorRet = SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
1017     } catch (const std::exception &e) {
1018         LogError("Some exception thrown : " << e.what());
1019         errorRet = SECURITY_MANAGER_API_ERROR_UNKNOWN;
1020     } catch (...) {
1021         LogError("Unknown exception thrown");
1022         errorRet = SECURITY_MANAGER_API_ERROR_UNKNOWN;
1023     }
1024     PrivilegeDb::getInstance().RollbackTransaction();
1025     return errorRet;
1026 }
1027
1028 int ServiceImpl::policyGetGroups(std::vector<std::string> &groups)
1029 {
1030     int ret = SECURITY_MANAGER_API_SUCCESS;
1031
1032     try {
1033         PrivilegeDb::getInstance().GetGroups(groups);
1034     } catch (const PrivilegeDb::Exception::Base &e) {
1035         LogError("Error while getting groups from database: " << e.DumpToString());
1036         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
1037     }
1038
1039     return ret;
1040 }
1041
1042 } /* namespace SecurityManager */