Remove libprivilege leftover
[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     try {
313         std::vector<std::string> oldAppPrivileges;
314
315         appLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(req.appId), zoneId);
316         /* NOTE: we don't use pkgLabel here, but generate it for pkgId validation */
317         pkgLabel = zoneSmackLabelGenerate(SmackLabels::generatePkgLabel(req.pkgId), zoneId);
318         LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
319                  << ", uidstr " << uidstr
320                  << ", app label: " << appLabel << ", pkg label: " << pkgLabel);
321
322         PrivilegeDb::getInstance().BeginTransaction();
323         std::string pkg;
324         bool ret = PrivilegeDb::getInstance().GetAppPkgId(req.appId, pkg);
325         if (ret == true && pkg != req.pkgId) {
326             LogError("Application already installed with different package id");
327             PrivilegeDb::getInstance().RollbackTransaction();
328             return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
329         }
330         PrivilegeDb::getInstance().GetAppPrivileges(req.appId, uid, oldAppPrivileges);
331         PrivilegeDb::getInstance().AddApplication(req.appId, req.pkgId, uid);
332         PrivilegeDb::getInstance().UpdateAppPrivileges(req.appId, uid, req.privileges);
333         /* Get all application ids in the package to generate rules withing the package */
334         PrivilegeDb::getInstance().GetAppIdsForPkgId(req.pkgId, pkgContents);
335
336         if (isSlave) {
337             int ret = MasterReq::CynaraPolicyUpdate(req.appId, uidstr, oldAppPrivileges,
338                                                     req.privileges);
339             if (ret != SECURITY_MANAGER_API_SUCCESS) {
340                 PrivilegeDb::getInstance().RollbackTransaction();
341                 LogError("Error while processing request on master: " << ret);
342                 return ret;
343             }
344         } else {
345             CynaraAdmin::getInstance().UpdateAppPolicy(appLabel, uidstr, oldAppPrivileges,
346                                                        req.privileges);
347         }
348
349         PrivilegeDb::getInstance().CommitTransaction();
350         LogDebug("Application installation commited to database");
351     } catch (const PrivilegeDb::Exception::IOError &e) {
352         LogError("Cannot access application database: " << e.DumpToString());
353         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
354     } catch (const PrivilegeDb::Exception::InternalError &e) {
355         PrivilegeDb::getInstance().RollbackTransaction();
356         LogError("Error while saving application info to database: " << e.DumpToString());
357         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
358     } catch (const CynaraException::Base &e) {
359         PrivilegeDb::getInstance().RollbackTransaction();
360         LogError("Error while setting Cynara rules for application: " << e.DumpToString());
361         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
362     } catch (const SmackException::InvalidLabel &e) {
363         PrivilegeDb::getInstance().RollbackTransaction();
364         LogError("Error while generating Smack labels: " << e.DumpToString());
365         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
366     } catch (const std::bad_alloc &e) {
367         PrivilegeDb::getInstance().RollbackTransaction();
368         LogError("Memory allocation while setting Cynara rules for application: " << e.what());
369         return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
370     }
371
372     try {
373         if (isCorrectPath)
374             SmackLabels::setupCorrectPath(req.pkgId, req.appId, appPath, zoneId);
375
376         // register paths
377         for (const auto &appPath : req.appPaths) {
378             const std::string &path = appPath.first;
379             app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
380             SmackLabels::setupPath(req.appId, path, pathType, zoneId);
381         }
382
383         if (isSlave) {
384             LogDebug("Requesting master to add rules for new appId: " << req.appId << " with pkgId: "
385                     << req.pkgId << ". Applications in package: " << pkgContents.size());
386             int ret = MasterReq::SmackInstallRules(req.appId, req.pkgId, pkgContents);
387             if (ret != SECURITY_MANAGER_API_SUCCESS) {
388                 LogError("Master failed to apply package-specific smack rules: " << ret);
389                 return ret;
390             }
391         } else {
392             LogDebug("Adding Smack rules for new appId: " << req.appId << " with pkgId: "
393                     << req.pkgId << ". Applications in package: " << pkgContents.size());
394             SmackRules::installApplicationRules(req.appId, req.pkgId, pkgContents);
395         }
396     } catch (const SmackException::Base &e) {
397         LogError("Error while applying Smack policy for application: " << e.DumpToString());
398         return SECURITY_MANAGER_API_ERROR_SETTING_FILE_LABEL_FAILED;
399     } catch (const SecurityManager::Exception &e) {
400         LogError("Security Manager exception: " << e.DumpToString());
401         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
402     }catch (const std::bad_alloc &e) {
403         LogError("Memory allocation error: " << e.what());
404         return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
405     }
406
407     return SECURITY_MANAGER_API_SUCCESS;
408 }
409
410 int appUninstall(const std::string &appId, uid_t uid, bool isSlave)
411 {
412     std::string pkgId;
413     std::string smackLabel;
414     std::vector<std::string> pkgContents;
415     bool appExists = true;
416     bool removePkg = false;
417     std::string uidstr;
418     checkGlobalUser(uid, uidstr);
419
420     std::string zoneId;
421     if (isSlave) {
422         if (!getZoneId(zoneId)) {
423             LogError("Failed to get Zone ID.");
424             return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
425         }
426     }
427
428     try {
429         std::vector<std::string> oldAppPrivileges;
430
431         PrivilegeDb::getInstance().BeginTransaction();
432         if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
433             LogWarning("Application " << appId <<
434                 " not found in database while uninstalling");
435             PrivilegeDb::getInstance().RollbackTransaction();
436             appExists = false;
437         } else {
438             smackLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(appId), zoneId);
439             LogDebug("Uninstall parameters: appId: " << appId << ", pkgId: " << pkgId
440                      << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
441
442             /* Before we remove the app from the database, let's fetch all apps in the package
443                 that this app belongs to, this will allow us to remove all rules withing the
444                 package that the app appears in */
445             PrivilegeDb::getInstance().GetAppIdsForPkgId(pkgId, pkgContents);
446             PrivilegeDb::getInstance().GetAppPrivileges(appId, uid, oldAppPrivileges);
447             PrivilegeDb::getInstance().UpdateAppPrivileges(appId, uid, std::vector<std::string>());
448             PrivilegeDb::getInstance().RemoveApplication(appId, uid, removePkg);
449
450             if (isSlave) {
451                 int ret = MasterReq::CynaraPolicyUpdate(appId, uidstr, oldAppPrivileges,
452                                                         std::vector<std::string>());
453                 if (ret != SECURITY_MANAGER_API_SUCCESS) {
454                     PrivilegeDb::getInstance().RollbackTransaction();
455                     LogError("Error while processing request on master: " << ret);
456                     return ret;
457                 }
458             } else {
459                 CynaraAdmin::getInstance().UpdateAppPolicy(smackLabel, uidstr, oldAppPrivileges,
460                                                            std::vector<std::string>());
461             }
462
463             PrivilegeDb::getInstance().CommitTransaction();
464             LogDebug("Application uninstallation commited to database");
465         }
466     } catch (const PrivilegeDb::Exception::IOError &e) {
467         LogError("Cannot access application database: " << e.DumpToString());
468         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
469     } catch (const PrivilegeDb::Exception::InternalError &e) {
470         PrivilegeDb::getInstance().RollbackTransaction();
471         LogError("Error while removing application info from database: " << e.DumpToString());
472         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
473     } catch (const CynaraException::Base &e) {
474         PrivilegeDb::getInstance().RollbackTransaction();
475         LogError("Error while setting Cynara rules for application: " << e.DumpToString());
476         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
477     } catch (const SmackException::InvalidLabel &e) {
478         PrivilegeDb::getInstance().RollbackTransaction();
479         LogError("Error while generating Smack labels: " << e.DumpToString());
480         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
481     } catch (const std::bad_alloc &e) {
482         PrivilegeDb::getInstance().RollbackTransaction();
483         LogError("Memory allocation while setting Cynara rules for application: " << e.what());
484         return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
485     }
486
487     if (appExists) {
488         try {
489             if (isSlave) {
490                 LogDebug("Delegating Smack rules removal for deleted pkgId " << pkgId <<
491                          " to master");
492                 int ret = MasterReq::SmackUninstallRules(appId, pkgId, pkgContents, removePkg);
493                 if (ret != SECURITY_MANAGER_API_SUCCESS) {
494                     LogError("Error while processing uninstall request on master: " << ret);
495                     return ret;
496                 }
497             } else {
498                 if (removePkg) {
499                     LogDebug("Removing Smack rules for deleted pkgId " << pkgId);
500                     SmackRules::uninstallPackageRules(pkgId);
501                 }
502
503                 LogDebug ("Removing smack rules for deleted appId " << appId);
504                 SmackRules::uninstallApplicationRules(appId, pkgId, pkgContents, zoneId);
505             }
506         } catch (const SmackException::Base &e) {
507             LogError("Error while removing Smack rules for application: " << e.DumpToString());
508             return SECURITY_MANAGER_API_ERROR_SETTING_FILE_LABEL_FAILED;
509         } catch (const SecurityManager::Exception &e) {
510             LogError("Security Manager error: " << e.DumpToString());
511             return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
512         } catch (const std::bad_alloc &e) {
513             LogError("Memory allocation error: " << e.what());
514             return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
515         }
516     }
517
518     return SECURITY_MANAGER_API_SUCCESS;
519 }
520
521 int getPkgId(const std::string &appId, std::string &pkgId)
522 {
523     LogDebug("appId: " << appId);
524
525     try {
526         if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
527             LogWarning("Application " << appId << " not found in database");
528             return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
529         } else {
530             LogDebug("pkgId: " << pkgId);
531         }
532     } catch (const PrivilegeDb::Exception::Base &e) {
533         LogError("Error while getting pkgId from database: " << e.DumpToString());
534         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
535     }
536
537     return SECURITY_MANAGER_API_SUCCESS;
538 }
539
540 int getAppGroups(const std::string &appId, uid_t uid, pid_t pid, bool isSlave,
541         std::unordered_set<gid_t> &gids)
542 {
543     // FIXME Temporary solution, see below
544     std::string zoneId;
545     if (isSlave) {
546         if (!getZoneId(zoneId)) {
547             LogError("Failed to get Zone ID.");
548             return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
549         }
550     }
551
552     try {
553         std::string pkgId;
554         std::string smackLabel;
555         std::string uidStr = std::to_string(uid);
556         std::string pidStr = std::to_string(pid);
557
558         LogDebug("appId: " << appId);
559
560         if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
561             LogWarning("Application " << appId << " not found in database");
562             return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
563         }
564         LogDebug("pkgId: " << pkgId);
565
566         // FIXME getAppGroups should work without generating zone-specific labels when
567         //       Smack Namespaces will work
568         smackLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(appId), zoneId);
569         LogDebug("smack label: " << smackLabel);
570
571         std::vector<std::string> privileges;
572         PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, privileges);
573         /*there is also a need of checking, if privilege is granted to all users*/
574         size_t tmp = privileges.size();
575         PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, getGlobalUserId(), privileges);
576         /*privileges needs to be sorted and with no duplications - for cynara sake*/
577         std::inplace_merge(privileges.begin(), privileges.begin() + tmp, privileges.end());
578         privileges.erase(unique(privileges.begin(), privileges.end()), privileges.end());
579
580         for (const auto &privilege : privileges) {
581             std::vector<std::string> gidsTmp;
582             PrivilegeDb::getInstance().GetPrivilegeGroups(privilege, gidsTmp);
583             if (!gidsTmp.empty()) {
584                 LogDebug("Considering privilege " << privilege << " with " <<
585                     gidsTmp.size() << " groups assigned");
586                 // TODO: create method in Cynara class for fetching all privileges of an application
587                 if (Cynara::getInstance().check(smackLabel, privilege, uidStr, pidStr)) {
588                     for_each(gidsTmp.begin(), gidsTmp.end(), [&] (std::string group) {
589                         struct group *grp = getgrnam(group.c_str());
590                         if (grp == NULL) {
591                                 LogError("No such group: " << group.c_str());
592                                 return;
593                         }
594                         gids.insert(grp->gr_gid);
595                     });
596                     LogDebug("Cynara allowed, adding groups");
597                 } else
598                     LogDebug("Cynara denied, not adding groups");
599             }
600         }
601     } catch (const PrivilegeDb::Exception::Base &e) {
602         LogError("Database error: " << e.DumpToString());
603         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
604     } catch (const CynaraException::Base &e) {
605         LogError("Error while querying Cynara for permissions: " << e.DumpToString());
606         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
607     } catch (const SmackException::InvalidLabel &e) {
608         LogError("Error while generating Smack labels: " << e.DumpToString());
609         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
610     } catch (const std::bad_alloc &e) {
611         LogError("Memory allocation failed: " << e.what());
612         return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
613     }
614
615     return SECURITY_MANAGER_API_SUCCESS;
616 }
617
618 int userAdd(uid_t uidAdded, int userType, uid_t uid, bool isSlave)
619 {
620     if (uid != 0)
621         return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
622
623     if (isSlave) {
624         int ret = MasterReq::CynaraUserInit(uidAdded,
625                                             static_cast<security_manager_user_type>(userType));
626         if (ret != SECURITY_MANAGER_API_SUCCESS) {
627             LogError("Master failed to initialize user " << uidAdded << " of type " << userType);
628             return ret;
629         }
630     } else {
631         try {
632             CynaraAdmin::getInstance().UserInit(uidAdded, static_cast<security_manager_user_type>(userType));
633         } catch (CynaraException::InvalidParam &e) {
634             return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
635         }
636     }
637
638     return SECURITY_MANAGER_API_SUCCESS;
639 }
640
641 int userDelete(uid_t uidDeleted, uid_t uid, bool isSlave)
642 {
643     int ret = SECURITY_MANAGER_API_SUCCESS;
644     if (uid != 0)
645         return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
646
647     /*Uninstall all user apps*/
648     std::vector<std::string> userApps;
649     try {
650         PrivilegeDb::getInstance().GetUserApps(uidDeleted, userApps);
651     } catch (const PrivilegeDb::Exception::Base &e) {
652         LogError("Error while getting user apps from database: " << e.DumpToString());
653         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
654     }
655
656     for (auto &app: userApps) {
657         if (appUninstall(app, uidDeleted, isSlave) != SECURITY_MANAGER_API_SUCCESS) {
658         /*if uninstallation of this app fails, just go on trying to uninstall another ones.
659         we do not have anything special to do about that matter - user will be deleted anyway.*/
660             ret = SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
661         }
662     }
663
664     if (isSlave) {
665         int ret = MasterReq::CynaraUserRemove(uidDeleted);
666         if (ret) {
667             LogError("Master failed to delete user " << uidDeleted);
668             return ret;
669         }
670     } else {
671         CynaraAdmin::getInstance().UserRemove(uidDeleted);
672     }
673
674     return ret;
675 }
676
677 int policyUpdate(const std::vector<policy_entry> &policyEntries, uid_t uid, pid_t pid, const std::string &smackLabel)
678 {
679     enum {
680         NOT_CHECKED,
681         IS_NOT_ADMIN,
682         IS_ADMIN
683     }  isAdmin = NOT_CHECKED;
684
685     try {
686         std::string uidStr = std::to_string(uid);
687         std::string pidStr = std::to_string(pid);
688
689         if (policyEntries.size() == 0) {
690             LogError("Validation failed: policy update request is empty");
691             return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
692         };
693
694         if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
695             LogError("Not enough permission to call: " << __FUNCTION__);
696             return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
697         };
698
699         std::vector<CynaraAdminPolicy> validatedPolicies;
700
701         for (auto &entry : const_cast<std::vector<policy_entry>&>(policyEntries)) {
702             bool forAdmin = false;
703             CynaraAdminPolicy cyap("", "", "", CYNARA_ADMIN_NONE, "");
704             int ret = validatePolicy(entry, uidStr, forAdmin, cyap);
705
706             if (forAdmin && (isAdmin == NOT_CHECKED)) {
707                 isAdmin = Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)?IS_ADMIN:IS_NOT_ADMIN;
708             };
709
710             if (ret == SECURITY_MANAGER_API_SUCCESS) {
711                 if (!forAdmin
712                     || (forAdmin && (isAdmin == IS_ADMIN))) {
713                     validatedPolicies.push_back(std::move(cyap));
714                 } else {
715                     LogError("Not enough privilege to enforce admin policy");
716                     return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
717                 };
718
719             } else
720                 return ret;
721         };
722
723             // Apply updates
724         CynaraAdmin::getInstance().SetPolicies(validatedPolicies);
725
726     } catch (const CynaraException::Base &e) {
727         LogError("Error while updating Cynara rules: " << e.DumpToString());
728         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
729     } catch (const std::bad_alloc &e) {
730         LogError("Memory allocation error while updating Cynara rules: " << e.what());
731         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
732     }
733
734     return SECURITY_MANAGER_API_SUCCESS;
735 }
736
737 int getConfiguredPolicy(bool forAdmin, const policy_entry &filter, uid_t uid, pid_t pid,
738     const std::string &smackLabel, std::vector<policy_entry> &policyEntries)
739 {
740     try {
741         std::string uidStr = std::to_string(uid);
742         std::string pidStr = std::to_string(pid);
743
744         if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
745             LogError("Not enough permission to call: " << __FUNCTION__);
746             return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
747         };
748
749         LogDebug("Filter is: C: " << filter.appId
750                     << ", U: " << filter.user
751                     << ", P: " << filter.privilege
752                     << ", current: " << filter.currentLevel
753                     << ", max: " << filter.maxLevel
754                     );
755
756         std::vector<CynaraAdminPolicy> listOfPolicies;
757
758         //convert appId to smack label
759         std::string appLabel = filter.appId.compare(SECURITY_MANAGER_ANY) ? SmackLabels::generateAppLabel(filter.appId) : CYNARA_ADMIN_ANY;
760         std::string user = filter.user.compare(SECURITY_MANAGER_ANY) ? filter.user : CYNARA_ADMIN_ANY;
761         std::string privilege = filter.privilege.compare(SECURITY_MANAGER_ANY) ? filter.privilege : CYNARA_ADMIN_ANY;
762
763         LogDebug("App: " << filter.appId << ", Label: " << appLabel);
764
765         if (forAdmin) {
766             if (!Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
767                 LogError("Not enough privilege to access admin enforced policies: " << __FUNCTION__);
768                 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
769                 };
770
771             //Fetch privileges from ADMIN bucket
772             CynaraAdmin::getInstance().ListPolicies(
773                 CynaraAdmin::Buckets.at(Bucket::ADMIN),
774                 appLabel,
775                 user,
776                 privilege,
777                 listOfPolicies
778                 );
779             LogDebug("ADMIN - number of policies matched: " << listOfPolicies.size());
780         } else {
781             if (uidStr.compare(user)) {
782                 if (!Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
783                     LogWarning("Not enough privilege to access other user's personal policies. Limiting query to personal privileges.");
784                     user = uidStr;
785                 };
786             };
787             //Fetch privileges from PRIVACY_MANAGER bucket
788             CynaraAdmin::getInstance().ListPolicies(
789                 CynaraAdmin::Buckets.at(Bucket::PRIVACY_MANAGER),
790                 appLabel,
791                 user,
792                 privilege,
793                 listOfPolicies
794                 );
795             LogDebug("PRIVACY MANAGER - number of policies matched: " << listOfPolicies.size());
796         };
797
798         for (const auto &policy : listOfPolicies) {
799             //ignore "jump to bucket" entries
800             if (policy.result ==  CYNARA_ADMIN_BUCKET)
801                 continue;
802
803             policy_entry pe;
804
805             pe.appId = strcmp(policy.client, CYNARA_ADMIN_WILDCARD) ? SmackLabels::generateAppNameFromLabel(policy.client) : SECURITY_MANAGER_ANY;
806             pe.user =  strcmp(policy.user, CYNARA_ADMIN_WILDCARD) ? policy.user : SECURITY_MANAGER_ANY;
807             pe.privilege = strcmp(policy.privilege, CYNARA_ADMIN_WILDCARD) ? policy.privilege : pe.privilege = SECURITY_MANAGER_ANY;
808             pe.currentLevel = CynaraAdmin::getInstance().convertToPolicyDescription(policy.result);
809
810             if (!forAdmin) {
811                 // All policy entries in PRIVACY_MANAGER should be fully-qualified
812                 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
813                     CynaraAdmin::getInstance().GetPrivilegeManagerMaxLevel(
814                         policy.client, policy.user, policy.privilege));
815             } else {
816                 // Cannot reliably calculate maxLavel for policies from ADMIN bucket
817                 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(CYNARA_ADMIN_ALLOW);
818             }
819
820
821             LogDebug(
822                 "[policy_entry] app: " << pe.appId
823                 << " user: " << pe.user
824                 << " privilege: " << pe.privilege
825                 << " current: " << pe.currentLevel
826                 << " max: " << pe.maxLevel
827                 );
828
829             policyEntries.push_back(pe);
830         };
831
832     } catch (const CynaraException::Base &e) {
833         LogError("Error while listing Cynara rules: " << e.DumpToString());
834         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
835     } catch (const SmackException::InvalidLabel &e) {
836         LogError("Error while generating Smack labels: " << e.DumpToString());
837         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
838     } catch (const std::bad_alloc &e) {
839         LogError("Memory allocation error while listing Cynara rules: " << e.what());
840         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
841     }
842
843
844     return SECURITY_MANAGER_API_SUCCESS;
845 }
846
847 int getPolicy(const policy_entry &filter, uid_t uid, pid_t pid, const std::string &smackLabel, std::vector<policy_entry> &policyEntries)
848 {
849     try {
850         std::string uidStr = std::to_string(uid);
851         std::string pidStr = std::to_string(pid);
852
853         if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
854             LogWarning("Not enough permission to call: " << __FUNCTION__);
855             return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
856         };
857
858         LogDebug("Filter is: C: " << filter.appId
859                     << ", U: " << filter.user
860                     << ", P: " << filter.privilege
861                     << ", current: " << filter.currentLevel
862                     << ", max: " << filter.maxLevel
863                     );
864
865         std::vector<uid_t> listOfUsers;
866
867         if (Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
868             LogDebug("User is privileged");
869             if (filter.user.compare(SECURITY_MANAGER_ANY)) {
870                 LogDebug("Limitting Cynara query to user: " << filter.user);
871                 try {
872                     listOfUsers.push_back(static_cast<uid_t>(std::stoul(filter.user)));
873                 } catch (std::invalid_argument &e) {
874                     LogError("Invalid UID: " << e.what());
875                 };
876             } else
877                 CynaraAdmin::getInstance().ListUsers(listOfUsers);
878         } else {
879             LogWarning("Not enough privilege to fetch user policy for all users by user: " << uid);
880             LogDebug("Fetching personal policy for user: " << uid);
881             listOfUsers.push_back(uid);
882         };
883         LogDebug("Fetching policy for " << listOfUsers.size() << " users");
884
885         for (const uid_t &uid : listOfUsers) {
886             LogDebug("User: " << uid);
887             std::string userStr = std::to_string(uid);
888             std::vector<std::string> listOfApps;
889
890             if (filter.appId.compare(SECURITY_MANAGER_ANY)) {
891                 LogDebug("Limitting Cynara query to app: " << filter.appId);
892                 listOfApps.push_back(filter.appId);
893             } else {
894                 PrivilegeDb::getInstance().GetUserApps(uid, listOfApps);
895                 LogDebug("Found apps: " << listOfApps.size());
896             };
897
898             for (const std::string &appId : listOfApps) {
899                 LogDebug("App: " << appId);
900                 std::string smackLabelForApp = SmackLabels::generateAppLabel(appId);
901                 std::vector<std::string> listOfPrivileges;
902
903                 // FIXME: also fetch privileges of global applications
904                 PrivilegeDb::getInstance().GetAppPrivileges(appId, uid, listOfPrivileges);
905
906                 if (filter.privilege.compare(SECURITY_MANAGER_ANY)) {
907                     LogDebug("Limitting Cynara query to privilege: " << filter.privilege);
908                     // FIXME: this filtering should be already performed by method fetching the privileges
909                     if (std::find(listOfPrivileges.begin(), listOfPrivileges.end(),
910                         filter.privilege) == listOfPrivileges.end()) {
911                         LogDebug("Application " << appId <<
912                             " doesn't have the filteres privilege " << filter.privilege);
913                         continue;
914                     }
915                     listOfPrivileges.clear();
916                     listOfPrivileges.push_back(filter.privilege);
917                 }
918
919                 LogDebug("Privileges matching filter - " << filter.privilege << ": " << listOfPrivileges.size());
920
921                 for (const std::string &privilege : listOfPrivileges) {
922                     LogDebug("Privilege: " << privilege);
923                     policy_entry pe;
924
925                     pe.appId = appId;
926                     pe.user = userStr;
927                     pe.privilege = privilege;
928
929                     pe.currentLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
930                         CynaraAdmin::getInstance().GetPrivilegeManagerCurrLevel(
931                             smackLabelForApp, userStr, privilege));
932
933                     pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
934                         CynaraAdmin::getInstance().GetPrivilegeManagerMaxLevel(
935                             smackLabelForApp, userStr, privilege));
936
937                     LogDebug(
938                         "[policy_entry] app: " << pe.appId
939                         << " user: " << pe.user
940                         << " privilege: " << pe.privilege
941                         << " current: " << pe.currentLevel
942                         << " max: " << pe.maxLevel
943                         );
944
945                     policyEntries.push_back(pe);
946                 };
947             };
948         };
949
950     } catch (const CynaraException::Base &e) {
951         LogError("Error while listing Cynara rules: " << e.DumpToString());
952         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
953     } catch (const SmackException::InvalidLabel &e) {
954         LogError("Error while generating Smack labels: " << e.DumpToString());
955         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
956     } catch (const std::bad_alloc &e) {
957         LogError("Memory allocation error while listing Cynara rules: " << e.what());
958         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
959     }
960
961     return SECURITY_MANAGER_API_SUCCESS;
962 }
963
964 int policyGetDesc(std::vector<std::string> &levels)
965 {
966     int ret = SECURITY_MANAGER_API_SUCCESS;
967
968     try {
969         CynaraAdmin::getInstance().ListPoliciesDescriptions(levels);
970     } catch (const CynaraException::OutOfMemory &e) {
971         LogError("Error - out of memory while querying Cynara for policy descriptions list: " << e.DumpToString());
972         return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
973     } catch (const CynaraException::InvalidParam &e) {
974         LogError("Error - invalid parameter while querying Cynara for policy descriptions list: " << e.DumpToString());
975         return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
976     } catch (const CynaraException::ServiceNotAvailable &e) {
977         LogError("Error - service not available while querying Cynara for policy descriptions list: " << e.DumpToString());
978         return SECURITY_MANAGER_API_ERROR_NO_SUCH_SERVICE;
979     } catch (const CynaraException::Base &e) {
980         LogError("Error while getting policy descriptions list from Cynara: " << e.DumpToString());
981         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
982     }
983
984     return ret;
985 }
986
987 } /* namespace ServiceImpl */
988 } /* namespace SecurityManager */