New path types for application installation in security-manager
[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
31 #include <cstring>
32 #include <algorithm>
33
34 #include <dpl/log/log.h>
35 #include <tzplatform_config.h>
36
37 #include "protocols.h"
38 #include "privilege_db.h"
39 #include "cynara.h"
40 #include "smack-rules.h"
41 #include "smack-labels.h"
42 #include "security-manager.h"
43
44 #include "service_impl.h"
45
46 namespace SecurityManager {
47 namespace ServiceImpl {
48
49 static const std::string ADMIN_PRIVILEGE = "http://tizen.org/privilege/systemsettings.admin";
50 static const std::string SELF_PRIVILEGE = "http://tizen.org/privilege/systemsettings";
51
52 namespace {
53
54 static inline int validatePolicy(policy_entry &policyEntry, std::string uidStr, bool &forAdmin, CynaraAdminPolicy &cyap)
55 {
56     LogDebug("Authenticating and validating policy update request for user with id: " << uidStr);
57     LogDebug("[policy_entry] app: " << policyEntry.appId
58             << " user: " << policyEntry.user
59             << " privilege: " << policyEntry.privilege
60             << " current: " << policyEntry.currentLevel
61             << " max: " << policyEntry.maxLevel);
62     //automagically fill missing fields:
63     if (policyEntry.user.empty()) {
64         policyEntry.user = uidStr;
65     };
66
67     std::string client;
68     int level;
69
70     if (policyEntry.currentLevel.empty()) { //for admin
71         if (policyEntry.appId.empty()
72             || policyEntry.privilege.empty()) {
73             LogError("Bad admin update request");
74             return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
75         };
76
77         if (!policyEntry.maxLevel.compare(SECURITY_MANAGER_DELETE)) {
78             level = CYNARA_ADMIN_DELETE;
79         } else {
80             try {
81                 level = CynaraAdmin::getInstance().convertToPolicyType(policyEntry.maxLevel);
82             } catch (const std::out_of_range& e) {
83                 LogError("policy max level cannot be: " << policyEntry.maxLevel);
84                 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
85             };
86         };
87         forAdmin = true;
88
89     } else if (policyEntry.maxLevel.empty()) { //for self
90         if (policyEntry.user.compare(uidStr)
91             || !policyEntry.appId.compare(SECURITY_MANAGER_ANY)
92             || !policyEntry.privilege.compare(SECURITY_MANAGER_ANY)
93             || policyEntry.appId.empty()
94             || policyEntry.privilege.empty()) {
95             LogError("Bad privacy manager update request");
96             return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
97         };
98
99         if (!policyEntry.currentLevel.compare(SECURITY_MANAGER_DELETE)) {
100             level = CYNARA_ADMIN_DELETE;
101         } else {
102             try {
103                 level = CynaraAdmin::getInstance().convertToPolicyType(policyEntry.currentLevel);
104             } catch (const std::out_of_range& e) {
105                 LogError("policy current level cannot be: " << policyEntry.currentLevel);
106                 return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
107             };
108         };
109         forAdmin = false;
110
111     } else { //neither => bad request
112         return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
113     };
114
115     if (!policyEntry.user.compare(SECURITY_MANAGER_ANY))
116         policyEntry.user = CYNARA_ADMIN_WILDCARD;
117     if (!policyEntry.privilege.compare(SECURITY_MANAGER_ANY))
118         policyEntry.privilege = CYNARA_ADMIN_WILDCARD;
119     if (policyEntry.appId.compare(SECURITY_MANAGER_ANY))
120         generateAppLabel(policyEntry.appId, client);
121     else
122         client = CYNARA_ADMIN_WILDCARD;
123
124     cyap = std::move(CynaraAdminPolicy(
125         client,
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 static inline bool installRequestAuthCheck(const app_inst_req &req, uid_t uid)
167 {
168     struct passwd *pwd;
169     do {
170         errno = 0;
171         pwd = getpwuid(uid);
172         if (!pwd && errno != EINTR) {
173             LogError("getpwuid failed with '" << uid
174                     << "' as parameter: " << strerror(errno));
175             return false;
176         }
177     } while (!pwd);
178
179     std::unique_ptr<char, std::function<void(void*)>> home(
180         realpath(pwd->pw_dir, NULL), free);
181     if (!home.get()) {
182             LogError("realpath failed with '" << pwd->pw_dir
183                     << "' as parameter: " << strerror(errno));
184             return false;
185     }
186
187     for (const auto &appPath : req.appPaths) {
188         std::unique_ptr<char, std::function<void(void*)>> real_path(
189             realpath(appPath.first.c_str(), NULL), free);
190         if (!real_path.get()) {
191             LogError("realpath failed with '" << appPath.first.c_str()
192                     << "' as parameter: " << strerror(errno));
193             return false;
194         }
195         LogDebug("Requested path is '" << appPath.first.c_str()
196                 << "'. User's HOME is '" << pwd->pw_dir << "'");
197         if (!isSubDir(home.get(), real_path.get())) {
198             LogWarning("User's apps may have registered folders only in user's home dir");
199             return false;
200         }
201
202         app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
203         if (pathType == SECURITY_MANAGER_PATH_PUBLIC) {
204             LogWarning("Only root can register SECURITY_MANAGER_PATH_PUBLIC path");
205             return false;
206         }
207     }
208     return true;
209 }
210
211 int appInstall(const app_inst_req &req, uid_t uid)
212 {
213     std::vector<std::string> addedPermissions;
214     std::vector<std::string> removedPermissions;
215     std::vector<std::string> pkgContents;
216     std::string uidstr;
217     if (uid) {
218         if (uid != req.uid) {
219             LogError("User " << uid <<
220                      " is denied to install application for user " << req.uid);
221             return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
222         }
223     } else {
224         if (req.uid)
225             uid = req.uid;
226     }
227     checkGlobalUser(uid, uidstr);
228
229     if (!installRequestAuthCheck(req, uid)) {
230         LogError("Request from uid " << uid << " for app installation denied");
231         return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
232     }
233
234     std::string smackLabel;
235     if (!generateAppLabel(req.appId, smackLabel)) {
236         LogError("Cannot generate Smack label for application: " << req.appId);
237         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
238     }
239
240     LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
241             << ", generated smack label: " << smackLabel);
242
243     // create null terminated array of strings for permissions
244     std::unique_ptr<const char *[]> pp_permissions(new const char* [req.privileges.size() + 1]);
245     for (size_t i = 0; i < req.privileges.size(); ++i) {
246         LogDebug("  Permission = " << req.privileges[i]);
247         pp_permissions[i] = req.privileges[i].c_str();
248     }
249     pp_permissions[req.privileges.size()] = nullptr;
250
251     try {
252         std::vector<std::string> oldAppPrivileges;
253         LogDebug("Install parameters: appId: " << req.appId << ", pkgId: " << req.pkgId
254                  << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
255
256         PrivilegeDb::getInstance().BeginTransaction();
257         std::string pkg;
258         bool ret = PrivilegeDb::getInstance().GetAppPkgId(req.appId, pkg);
259         if (ret == true && pkg != req.pkgId) {
260             LogError("Application already installed with different package id");
261             PrivilegeDb::getInstance().RollbackTransaction();
262             return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
263         }
264         PrivilegeDb::getInstance().GetAppPrivileges(req.appId, uid, oldAppPrivileges);
265         PrivilegeDb::getInstance().AddApplication(req.appId, req.pkgId, uid);
266         PrivilegeDb::getInstance().UpdateAppPrivileges(req.appId, uid, req.privileges);
267         /* Get all application ids in the package to generate rules withing the package */
268         PrivilegeDb::getInstance().GetAppIdsForPkgId(req.pkgId, pkgContents);
269         CynaraAdmin::getInstance().UpdateAppPolicy(smackLabel, uidstr, oldAppPrivileges,
270                                          req.privileges);
271         PrivilegeDb::getInstance().CommitTransaction();
272         LogDebug("Application installation commited to database");
273     } catch (const PrivilegeDb::Exception::IOError &e) {
274         LogError("Cannot access application database: " << e.DumpToString());
275         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
276     } catch (const PrivilegeDb::Exception::InternalError &e) {
277         PrivilegeDb::getInstance().RollbackTransaction();
278         LogError("Error while saving application info to database: " << e.DumpToString());
279         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
280     } catch (const CynaraException::Base &e) {
281         PrivilegeDb::getInstance().RollbackTransaction();
282         LogError("Error while setting Cynara rules for application: " << e.DumpToString());
283         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
284     } catch (const std::bad_alloc &e) {
285         PrivilegeDb::getInstance().RollbackTransaction();
286         LogError("Memory allocation while setting Cynara rules for application: " << e.what());
287         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
288     }
289
290     // register paths
291     for (const auto &appPath : req.appPaths) {
292         const std::string &path = appPath.first;
293         app_install_path_type pathType = static_cast<app_install_path_type>(appPath.second);
294         int result = setupPath(req.appId, path, pathType);
295
296         if (!result) {
297             LogError("setupPath() failed");
298             return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
299         }
300     }
301
302     LogDebug("Adding Smack rules for new appId: " << req.appId << " with pkgId: "
303             << req.pkgId << ". Applications in package: " << pkgContents.size());
304     if (!SmackRules::installApplicationRules(req.appId, req.pkgId, pkgContents)) {
305         LogError("Failed to apply package-specific smack rules");
306         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
307     }
308
309     return SECURITY_MANAGER_API_SUCCESS;
310 }
311
312 int appUninstall(const std::string &appId, uid_t uid)
313 {
314     std::string pkgId;
315     std::string smackLabel;
316     std::vector<std::string> pkgContents;
317     bool appExists = true;
318     bool removePkg = false;
319     std::string uidstr;
320     checkGlobalUser(uid, uidstr);
321
322     try {
323         std::vector<std::string> oldAppPrivileges;
324
325         PrivilegeDb::getInstance().BeginTransaction();
326         if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
327             LogWarning("Application " << appId <<
328                 " not found in database while uninstalling");
329             PrivilegeDb::getInstance().RollbackTransaction();
330             appExists = false;
331         } else {
332
333             LogDebug("Uninstall parameters: appId: " << appId << ", pkgId: " << pkgId
334                      << ", uidstr " << uidstr << ", generated smack label: " << smackLabel);
335
336             if (!generateAppLabel(appId, smackLabel)) {
337                 LogError("Cannot generate Smack label for package: " << pkgId);
338                 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
339             }
340
341             /* Before we remove the app from the database, let's fetch all apps in the package
342                 that this app belongs to, this will allow us to remove all rules withing the
343                 package that the app appears in */
344             PrivilegeDb::getInstance().GetAppIdsForPkgId(pkgId, pkgContents);
345             PrivilegeDb::getInstance().GetAppPrivileges(appId, uid, oldAppPrivileges);
346             PrivilegeDb::getInstance().UpdateAppPrivileges(appId, uid, std::vector<std::string>());
347             PrivilegeDb::getInstance().RemoveApplication(appId, uid, removePkg);
348             CynaraAdmin::getInstance().UpdateAppPolicy(smackLabel, uidstr, oldAppPrivileges,
349                                              std::vector<std::string>());
350             PrivilegeDb::getInstance().CommitTransaction();
351             LogDebug("Application uninstallation commited to database");
352         }
353     } catch (const PrivilegeDb::Exception::IOError &e) {
354         LogError("Cannot access application database: " << e.DumpToString());
355         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
356     } catch (const PrivilegeDb::Exception::InternalError &e) {
357         PrivilegeDb::getInstance().RollbackTransaction();
358         LogError("Error while removing application info from database: " << e.DumpToString());
359         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
360     } catch (const CynaraException::Base &e) {
361         PrivilegeDb::getInstance().RollbackTransaction();
362         LogError("Error while setting Cynara rules for application: " << e.DumpToString());
363         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
364     } catch (const std::bad_alloc &e) {
365         PrivilegeDb::getInstance().RollbackTransaction();
366         LogError("Memory allocation while setting Cynara rules for application: " << e.what());
367         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
368     }
369
370     if (appExists) {
371
372         if (removePkg) {
373             LogDebug("Removing Smack rules for deleted pkgId " << pkgId);
374             if (!SmackRules::uninstallPackageRules(pkgId)) {
375                 LogError("Error on uninstallation of package-specific smack rules");
376                 return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
377             }
378         }
379         LogDebug ("Removing smack rules for deleted appId " << appId);
380         if (!SmackRules::uninstallApplicationRules(appId, pkgId, pkgContents)) {
381             LogError("Error during uninstallation of application-specific smack rules");
382             return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
383         }
384     }
385
386     return SECURITY_MANAGER_API_SUCCESS;
387 }
388
389 int getPkgId(const std::string &appId, std::string &pkgId)
390 {
391     LogDebug("appId: " << appId);
392
393     try {
394         if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
395             LogWarning("Application " << appId << " not found in database");
396             return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
397         } else {
398             LogDebug("pkgId: " << pkgId);
399         }
400     } catch (const PrivilegeDb::Exception::Base &e) {
401         LogError("Error while getting pkgId from database: " << e.DumpToString());
402         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
403     }
404
405     return SECURITY_MANAGER_API_SUCCESS;
406 }
407
408 int getAppGroups(const std::string &appId, uid_t uid, pid_t pid, std::unordered_set<gid_t> &gids)
409 {
410     try {
411         std::string pkgId;
412         std::string smackLabel;
413         std::string uidStr = std::to_string(uid);
414         std::string pidStr = std::to_string(pid);
415
416         LogDebug("appId: " << appId);
417
418         if (!PrivilegeDb::getInstance().GetAppPkgId(appId, pkgId)) {
419             LogWarning("Application " << appId << " not found in database");
420             return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
421         }
422         LogDebug("pkgId: " << pkgId);
423         if (!generatePkgLabel(pkgId, smackLabel)) {
424             LogError("Cannot generate Smack label for pkgId: " << pkgId);
425             return SECURITY_MANAGER_API_ERROR_NO_SUCH_OBJECT;
426         }
427         LogDebug("smack label: " << smackLabel);
428
429         std::vector<std::string> privileges;
430         PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, uid, privileges);
431         /*there is also a need of checking, if privilege is granted to all users*/
432         size_t tmp = privileges.size();
433         PrivilegeDb::getInstance().GetPkgPrivileges(pkgId, getGlobalUserId(), privileges);
434         /*privileges needs to be sorted and with no duplications - for cynara sake*/
435         std::inplace_merge(privileges.begin(), privileges.begin() + tmp, privileges.end());
436         privileges.erase( unique( privileges.begin(), privileges.end() ), privileges.end() );
437
438         for (const auto &privilege : privileges) {
439             std::vector<std::string> gidsTmp;
440             PrivilegeDb::getInstance().GetPrivilegeGroups(privilege, gidsTmp);
441             if (!gidsTmp.empty()) {
442                 LogDebug("Considering privilege " << privilege << " with " <<
443                     gidsTmp.size() << " groups assigned");
444                 if (Cynara::getInstance().check(smackLabel, privilege, uidStr, pidStr)) {
445                     for_each(gidsTmp.begin(), gidsTmp.end(), [&] (std::string group)
446                     {
447                         struct group *grp = getgrnam(group.c_str());
448                         if (grp == NULL) {
449                                 LogError("No such group: " << group.c_str());
450                                 return;
451                         }
452                         gids.insert(grp->gr_gid);
453                     });
454                     LogDebug("Cynara allowed, adding groups");
455                 } else
456                     LogDebug("Cynara denied, not adding groups");
457             }
458         }
459     } catch (const PrivilegeDb::Exception::Base &e) {
460         LogError("Database error: " << e.DumpToString());
461         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
462     } catch (const CynaraException::Base &e) {
463         LogError("Error while querying Cynara for permissions: " << e.DumpToString());
464         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
465     } catch (const std::bad_alloc &e) {
466         LogError("Memory allocation failed: " << e.what());
467         return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
468     }
469
470     return SECURITY_MANAGER_API_SUCCESS;
471 }
472
473 int userAdd(uid_t uidAdded, int userType, uid_t uid)
474 {
475     if (uid != 0)
476         return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
477
478     try {
479         CynaraAdmin::getInstance().UserInit(uidAdded, static_cast<security_manager_user_type>(userType));
480     } catch (CynaraException::InvalidParam &e) {
481         return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
482     }
483     return SECURITY_MANAGER_API_SUCCESS;
484 }
485
486 int userDelete(uid_t uidDeleted, uid_t uid)
487 {
488     int ret = SECURITY_MANAGER_API_SUCCESS;
489     if (uid != 0)
490         return SECURITY_MANAGER_API_ERROR_AUTHENTICATION_FAILED;
491
492     /*Uninstall all user apps*/
493     std::vector<std::string> userApps;
494     try {
495         PrivilegeDb::getInstance().GetUserApps(uidDeleted, userApps);
496     } catch (const PrivilegeDb::Exception::Base &e) {
497         LogError("Error while getting user apps from database: " << e.DumpToString());
498         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
499     }
500
501     for (auto &app: userApps) {
502         if (appUninstall(app, uidDeleted) != SECURITY_MANAGER_API_SUCCESS) {
503         /*if uninstallation of this app fails, just go on trying to uninstall another ones.
504         we do not have anything special to do about that matter - user will be deleted anyway.*/
505             ret = SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
506         }
507     }
508
509     CynaraAdmin::getInstance().UserRemove(uidDeleted);
510
511     return ret;
512 }
513
514 int policyUpdate(const std::vector<policy_entry> &policyEntries, uid_t uid, pid_t pid, const std::string &smackLabel)
515 {
516     enum {
517         NOT_CHECKED,
518         IS_NOT_ADMIN,
519         IS_ADMIN
520     }  isAdmin = NOT_CHECKED;
521
522     try {
523         std::string uidStr = std::to_string(uid);
524         std::string pidStr = std::to_string(pid);
525
526         if (policyEntries.size() == 0) {
527             LogError("Validation failed: policy update request is empty");
528             return SECURITY_MANAGER_API_ERROR_BAD_REQUEST;
529         };
530
531         if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
532             LogError("Not enough permission to call: " << __FUNCTION__);
533             return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
534         };
535
536         std::vector<CynaraAdminPolicy> validatedPolicies;
537
538         for (auto &entry : const_cast<std::vector<policy_entry>&>(policyEntries)) {
539             bool forAdmin = false;
540             CynaraAdminPolicy cyap("", "", "", CYNARA_ADMIN_NONE, "");
541             int ret = validatePolicy(entry, uidStr, forAdmin, cyap);
542
543             if (forAdmin && (isAdmin == NOT_CHECKED)) {
544                 isAdmin = Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)?IS_ADMIN:IS_NOT_ADMIN;
545             };
546
547             if (ret == SECURITY_MANAGER_API_SUCCESS) {
548                 if (!forAdmin
549                     || (forAdmin && (isAdmin == IS_ADMIN))) {
550                     validatedPolicies.push_back(std::move(cyap));
551                 } else {
552                     LogError("Not enough privilege to enforce admin policy");
553                     return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
554                 };
555
556             } else
557                 return ret;
558         };
559
560             // Apply updates
561         CynaraAdmin::getInstance().SetPolicies(validatedPolicies);
562
563     } catch (const CynaraException::Base &e) {
564         LogError("Error while updating Cynara rules: " << e.DumpToString());
565         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
566     } catch (const std::bad_alloc &e) {
567         LogError("Memory allocation error while updating Cynara rules: " << e.what());
568         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
569     }
570
571     return SECURITY_MANAGER_API_SUCCESS;
572 }
573
574 int getConfiguredPolicy(bool forAdmin, const policy_entry &filter, uid_t uid, pid_t pid,
575     const std::string &smackLabel, std::vector<policy_entry> &policyEntries)
576 {
577     try {
578         std::string uidStr = std::to_string(uid);
579         std::string pidStr = std::to_string(pid);
580
581         if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
582             LogError("Not enough permission to call: " << __FUNCTION__);
583             return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
584         };
585
586         LogDebug("Filter is: C: " << filter.appId
587                     << ", U: " << filter.user
588                     << ", P: " << filter.privilege
589                     << ", current: " << filter.currentLevel
590                     << ", max: " << filter.maxLevel
591                     );
592
593         std::vector<CynaraAdminPolicy> listOfPolicies;
594
595         //convert appId to smack label
596         std::string appLabel;
597         if (!filter.appId.compare(SECURITY_MANAGER_ANY))
598             appLabel = CYNARA_ADMIN_ANY;
599         else
600             generateAppLabel(filter.appId, appLabel);
601
602         std::string user = (!filter.user.compare(SECURITY_MANAGER_ANY))? CYNARA_ADMIN_ANY: filter.user;
603         std::string privilege = (!filter.privilege.compare(SECURITY_MANAGER_ANY))? CYNARA_ADMIN_ANY: filter.privilege;
604
605         LogDebug("App: " << filter.appId << ", Label: " << appLabel);
606
607         if (forAdmin) {
608             if (!Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
609                 LogError("Not enough privilege to access admin enforced policies: " << __FUNCTION__);
610                 return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
611                 };
612
613             //Fetch privileges from ADMIN bucket
614             CynaraAdmin::getInstance().ListPolicies(
615                 CynaraAdmin::Buckets.at(Bucket::ADMIN),
616                 appLabel,
617                 user,
618                 privilege,
619                 listOfPolicies
620                 );
621             LogDebug("ADMIN - number of policies matched: " << listOfPolicies.size());
622         } else {
623             if (uidStr.compare(user)) {
624                 if (!Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
625                     LogWarning("Not enough privilege to access other user's personal policies. Limiting query to personal privileges.");
626                     user = uidStr;
627                 };
628             };
629             //Fetch privileges from PRIVACY_MANAGER bucket
630             CynaraAdmin::getInstance().ListPolicies(
631                 CynaraAdmin::Buckets.at(Bucket::PRIVACY_MANAGER),
632                 appLabel,
633                 user,
634                 privilege,
635                 listOfPolicies
636                 );
637             LogDebug("PRIVACY MANAGER - number of policies matched: " << listOfPolicies.size());
638         };
639
640         for (const auto &policy : listOfPolicies) {
641             //ignore "jump to bucket" entries
642             if (policy.result ==  CYNARA_ADMIN_BUCKET)
643                 continue;
644
645             policy_entry pe;
646
647             pe.appId = strcmp(policy.client, CYNARA_ADMIN_WILDCARD) ? generateAppNameFromLabel(policy.client) : SECURITY_MANAGER_ANY;
648             pe.user =  strcmp(policy.user, CYNARA_ADMIN_WILDCARD) ? policy.user : SECURITY_MANAGER_ANY;
649             pe.privilege = strcmp(policy.privilege, CYNARA_ADMIN_WILDCARD) ? policy.privilege : pe.privilege = SECURITY_MANAGER_ANY;
650             pe.currentLevel = CynaraAdmin::getInstance().convertToPolicyDescription(policy.result);
651
652             if (!forAdmin) {
653                 // All policy entries in PRIVACY_MANAGER should be fully-qualified
654                 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
655                     CynaraAdmin::getInstance().GetPrivilegeManagerMaxLevel(
656                         policy.client, policy.user, policy.privilege));
657             } else {
658                 // Cannot reliably calculate maxLavel for policies from ADMIN bucket
659                 pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(CYNARA_ADMIN_ALLOW);
660             }
661
662
663             LogDebug(
664                 "[policy_entry] app: " << pe.appId
665                 << " user: " << pe.user
666                 << " privilege: " << pe.privilege
667                 << " current: " << pe.currentLevel
668                 << " max: " << pe.maxLevel
669                 );
670
671             policyEntries.push_back(pe);
672         };
673
674     } catch (const CynaraException::Base &e) {
675         LogError("Error while listing Cynara rules: " << e.DumpToString());
676         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
677     } catch (const std::bad_alloc &e) {
678         LogError("Memory allocation error while listing Cynara rules: " << e.what());
679         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
680     }
681
682
683     return SECURITY_MANAGER_API_SUCCESS;
684 }
685
686 int getPolicy(const policy_entry &filter, uid_t uid, pid_t pid, const std::string &smackLabel, std::vector<policy_entry> &policyEntries)
687 {
688     try {
689         std::string uidStr = std::to_string(uid);
690         std::string pidStr = std::to_string(pid);
691
692         if (!Cynara::getInstance().check(smackLabel, SELF_PRIVILEGE, uidStr, pidStr)) {
693             LogWarning("Not enough permission to call: " << __FUNCTION__);
694             return SECURITY_MANAGER_API_ERROR_ACCESS_DENIED;
695         };
696
697         LogDebug("Filter is: C: " << filter.appId
698                     << ", U: " << filter.user
699                     << ", P: " << filter.privilege
700                     << ", current: " << filter.currentLevel
701                     << ", max: " << filter.maxLevel
702                     );
703
704         std::vector<uid_t> listOfUsers;
705
706         if (Cynara::getInstance().check(smackLabel, ADMIN_PRIVILEGE, uidStr, pidStr)) {
707             LogDebug("User is privileged");
708             if (filter.user.compare(SECURITY_MANAGER_ANY)) {
709                 LogDebug("Limitting Cynara query to user: " << filter.user);
710                 try {
711                     listOfUsers.push_back(static_cast<uid_t>(std::stoul(filter.user)));
712                 } catch (std::invalid_argument &e) {
713                     LogError("Invalid UID: " << e.what());
714                 };
715             } else
716                 CynaraAdmin::getInstance().ListUsers(listOfUsers);
717         } else {
718             LogWarning("Not enough privilege to fetch user policy for all users by user: " << uid);
719             LogDebug("Fetching personal policy for user: " << uid);
720             listOfUsers.push_back(uid);
721         };
722         LogDebug("Fetching policy for " << listOfUsers.size() << " users");
723
724         for (const uid_t &uid : listOfUsers) {
725             LogDebug("User: " << uid);
726             std::string userStr = std::to_string(uid);
727             std::vector<std::string> listOfApps;
728
729             if (filter.appId.compare(SECURITY_MANAGER_ANY)) {
730                 LogDebug("Limitting Cynara query to app: " << filter.appId);
731                 listOfApps.push_back(filter.appId);
732             } else {
733                 PrivilegeDb::getInstance().GetUserApps(uid, listOfApps);
734                 LogDebug("Found apps: " << listOfApps.size());
735             };
736
737             for (const std::string &appId : listOfApps) {
738                 LogDebug("App: " << appId);
739                 std::string smackLabelForApp;
740                 std::vector<std::string> listOfPrivileges;
741
742                 generateAppLabel(appId, smackLabelForApp);
743                 // FIXME: also fetch privileges of global applications
744                 PrivilegeDb::getInstance().GetAppPrivileges(appId, uid, listOfPrivileges);
745
746                 if (filter.privilege.compare(SECURITY_MANAGER_ANY)) {
747                     LogDebug("Limitting Cynara query to privilege: " << filter.privilege);
748                     // FIXME: this filtering should be already performed by method fetching the privileges
749                     if (std::find(listOfPrivileges.begin(), listOfPrivileges.end(),
750                         filter.privilege) == listOfPrivileges.end()) {
751                         LogDebug("Application " << appId <<
752                             " doesn't have the filteres privilege " << filter.privilege);
753                         continue;
754                     }
755                     listOfPrivileges.clear();
756                     listOfPrivileges.push_back(filter.privilege);
757                 }
758
759                 LogDebug("Privileges matching filter - " << filter.privilege << ": " << listOfPrivileges.size());
760
761                 for (const std::string &privilege : listOfPrivileges) {
762                     LogDebug("Privilege: " << privilege);
763                     policy_entry pe;
764
765                     pe.appId = appId;
766                     pe.user = userStr;
767                     pe.privilege = privilege;
768
769                     pe.currentLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
770                         CynaraAdmin::getInstance().GetPrivilegeManagerCurrLevel(
771                             smackLabelForApp, userStr, privilege));
772
773                     pe.maxLevel = CynaraAdmin::getInstance().convertToPolicyDescription(
774                         CynaraAdmin::getInstance().GetPrivilegeManagerMaxLevel(
775                             smackLabelForApp, userStr, privilege));
776
777                     LogDebug(
778                         "[policy_entry] app: " << pe.appId
779                         << " user: " << pe.user
780                         << " privilege: " << pe.privilege
781                         << " current: " << pe.currentLevel
782                         << " max: " << pe.maxLevel
783                         );
784
785                     policyEntries.push_back(pe);
786                 };
787             };
788         };
789
790     } catch (const CynaraException::Base &e) {
791         LogError("Error while listing Cynara rules: " << e.DumpToString());
792         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
793     } catch (const std::bad_alloc &e) {
794         LogError("Memory allocation error while listing Cynara rules: " << e.what());
795         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
796     }
797
798     return SECURITY_MANAGER_API_SUCCESS;
799 }
800
801 int policyGetDesc(std::vector<std::string> &levels)
802 {
803     int ret = SECURITY_MANAGER_API_SUCCESS;
804
805     try {
806         CynaraAdmin::getInstance().ListPoliciesDescriptions(levels);
807     } catch (const CynaraException::OutOfMemory &e) {
808         LogError("Error - out of memory while querying Cynara for policy descriptions list: " << e.DumpToString());
809         return SECURITY_MANAGER_API_ERROR_OUT_OF_MEMORY;
810     } catch (const CynaraException::InvalidParam &e) {
811         LogError("Error - invalid parameter while querying Cynara for policy descriptions list: " << e.DumpToString());
812         return SECURITY_MANAGER_API_ERROR_INPUT_PARAM;
813     } catch (const CynaraException::ServiceNotAvailable &e) {
814         LogError("Error - service not available while querying Cynara for policy descriptions list: " << e.DumpToString());
815         return SECURITY_MANAGER_API_ERROR_NO_SUCH_SERVICE;
816     } catch (const CynaraException::Base &e) {
817         LogError("Error while getting policy descriptions list from Cynara: " << e.DumpToString());
818         return SECURITY_MANAGER_API_ERROR_SERVER_ERROR;
819     }
820
821     return ret;
822 }
823
824 } /* namespace ServiceImpl */
825 } /* namespace SecurityManager */