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