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