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