Change smack labeling to be appId based.
[platform/core/security/security-manager.git] / src / common / cynara.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        cynara.cpp
20  * @author      Rafal Krypa <r.krypa@samsung.com>
21  * @brief       Wrapper class for Cynara interface
22  */
23
24 #include <cstring>
25 #include "cynara.h"
26
27 #include <dpl/log/log.h>
28
29 namespace SecurityManager {
30
31
32 CynaraAdminPolicy::CynaraAdminPolicy(const std::string &client, const std::string &user,
33         const std::string &privilege, Operation operation,
34         const std::string &bucket)
35 {
36     this->client = strdup(client.c_str());
37     this->user = strdup(user.c_str());
38     this->privilege = strdup(privilege.c_str());
39     this->bucket = strdup(bucket.c_str());
40
41     if (this->bucket == nullptr || this->client == nullptr ||
42         this->user == nullptr || this->privilege == nullptr) {
43         free(this->bucket);
44         free(this->client);
45         free(this->user);
46         free(this->privilege);
47         ThrowMsg(CynaraException::OutOfMemory,
48                 std::string("Error in CynaraAdminPolicy allocation."));
49     }
50
51     this->result = static_cast<int>(operation);
52     this->result_extra = nullptr;
53 }
54
55 CynaraAdminPolicy::CynaraAdminPolicy(const std::string &client, const std::string &user,
56     const std::string &privilege, const std::string &goToBucket,
57     const std::string &bucket)
58 {
59     this->bucket = strdup(bucket.c_str());
60     this->client = strdup(client.c_str());
61     this->user = strdup(user.c_str());
62     this->privilege = strdup(privilege.c_str());
63     this->result_extra = strdup(goToBucket.c_str());
64     this->result = CYNARA_ADMIN_BUCKET;
65
66     if (this->bucket == nullptr || this->client == nullptr ||
67         this->user == nullptr || this->privilege == nullptr ||
68         this->result_extra == nullptr) {
69         free(this->bucket);
70         free(this->client);
71         free(this->user);
72         free(this->privilege);
73         free(this->result_extra);
74         ThrowMsg(CynaraException::OutOfMemory,
75                 std::string("Error in CynaraAdminPolicy allocation."));
76     }
77 }
78
79 CynaraAdminPolicy::CynaraAdminPolicy(CynaraAdminPolicy &&that)
80 {
81     bucket = that.bucket;
82     client = that.client;
83     user = that.user;
84     privilege = that.privilege;
85     result_extra = that.result_extra;
86     result = that.result;
87
88     that.bucket = nullptr;
89     that.client = nullptr;
90     that.user = nullptr;
91     that.privilege = nullptr;
92     that.result_extra = nullptr;
93 }
94
95 CynaraAdminPolicy::~CynaraAdminPolicy()
96 {
97     free(this->bucket);
98     free(this->client);
99     free(this->user);
100     free(this->privilege);
101     free(this->result_extra);
102 }
103
104 static bool checkCynaraError(int result, const std::string &msg)
105 {
106     switch (result) {
107         case CYNARA_API_SUCCESS:
108         case CYNARA_API_ACCESS_ALLOWED:
109             return true;
110         case CYNARA_API_ACCESS_DENIED:
111             return false;
112         case CYNARA_API_OUT_OF_MEMORY:
113             ThrowMsg(CynaraException::OutOfMemory, msg);
114         case CYNARA_API_INVALID_PARAM:
115             ThrowMsg(CynaraException::InvalidParam, msg);
116         case CYNARA_API_SERVICE_NOT_AVAILABLE:
117             ThrowMsg(CynaraException::ServiceNotAvailable, msg);
118         default:
119             ThrowMsg(CynaraException::UnknownError, msg);
120     }
121 }
122
123 CynaraAdmin::CynaraAdmin()
124 {
125     checkCynaraError(
126         cynara_admin_initialize(&m_CynaraAdmin),
127         "Cannot connect to Cynara administrative interface.");
128 }
129
130 CynaraAdmin::~CynaraAdmin()
131 {
132     cynara_admin_finish(m_CynaraAdmin);
133 }
134
135 CynaraAdmin &CynaraAdmin::getInstance()
136 {
137     static CynaraAdmin cynaraAdmin;
138     return cynaraAdmin;
139 }
140
141 void CynaraAdmin::SetPolicies(const std::vector<CynaraAdminPolicy> &policies)
142 {
143     std::vector<const struct cynara_admin_policy *> pp_policies(policies.size() + 1);
144
145     LogDebug("Sending " << policies.size() << " policies to Cynara");
146     for (std::size_t i = 0; i < policies.size(); ++i) {
147         pp_policies[i] = static_cast<const struct cynara_admin_policy *>(&policies[i]);
148         LogDebug("policies[" << i << "] = {" <<
149             ".bucket = " << pp_policies[i]->bucket << ", " <<
150             ".client = " << pp_policies[i]->client << ", " <<
151             ".user = " << pp_policies[i]->user << ", " <<
152             ".privilege = " << pp_policies[i]->privilege << ", " <<
153             ".result = " << pp_policies[i]->result << ", " <<
154             ".result_extra = " << pp_policies[i]->result_extra << "}");
155     }
156
157     pp_policies[policies.size()] = nullptr;
158
159     checkCynaraError(
160         cynara_admin_set_policies(m_CynaraAdmin, pp_policies.data()),
161         "Error while updating Cynara policy.");
162 }
163
164 void CynaraAdmin::UpdateAppPolicy(
165     const std::string &label,
166     const std::string &user,
167     const std::vector<std::string> &oldPrivileges,
168     const std::vector<std::string> &newPrivileges)
169 {
170     CynaraAdmin cynaraAdmin;
171     std::vector<CynaraAdminPolicy> policies;
172
173     // Perform sort-merge join on oldPrivileges and newPrivileges.
174     // Assume that they are already sorted and without duplicates.
175     auto oldIter = oldPrivileges.begin();
176     auto newIter = newPrivileges.begin();
177
178     while (oldIter != oldPrivileges.end() && newIter != newPrivileges.end()) {
179         int compare = oldIter->compare(*newIter);
180         if (compare == 0) {
181             LogDebug("(user = " << user << " label = " << label << ") " <<
182                 "keeping privilege " << *newIter);
183             ++oldIter;
184             ++newIter;
185             continue;
186         } else if (compare < 0) {
187             LogDebug("(user = " << user << " label = " << label << ") " <<
188                 "removing privilege " << *oldIter);
189             policies.push_back(CynaraAdminPolicy(label, user, *oldIter,
190                     CynaraAdminPolicy::Operation::Delete));
191             ++oldIter;
192         } else {
193             LogDebug("(user = " << user << " label = " << label << ") " <<
194                 "adding privilege " << *newIter);
195             policies.push_back(CynaraAdminPolicy(label, user, *newIter,
196                     CynaraAdminPolicy::Operation::Allow));
197             ++newIter;
198         }
199     }
200
201     for (; oldIter != oldPrivileges.end(); ++oldIter) {
202         LogDebug("(user = " << user << " label = " << label << ") " <<
203             "removing privilege " << *oldIter);
204         policies.push_back(CynaraAdminPolicy(label, user, *oldIter,
205                     CynaraAdminPolicy::Operation::Delete));
206     }
207
208     for (; newIter != newPrivileges.end(); ++newIter) {
209         LogDebug("(user = " << user << " label = " << label << ") " <<
210             "adding privilege " << *newIter);
211         policies.push_back(CynaraAdminPolicy(label, user, *newIter,
212                     CynaraAdminPolicy::Operation::Allow));
213     }
214
215     cynaraAdmin.SetPolicies(policies);
216 }
217
218 Cynara::Cynara()
219 {
220     checkCynaraError(
221         cynara_initialize(&m_Cynara, nullptr),
222         "Cannot connect to Cynara policy interface.");
223 }
224
225 Cynara::~Cynara()
226 {
227     cynara_finish(m_Cynara);
228 }
229
230 Cynara &Cynara::getInstance()
231 {
232     static Cynara cynara;
233     return cynara;
234 }
235
236 bool Cynara::check(const std::string &label, const std::string &privilege,
237         const std::string &user, const std::string &session)
238 {
239     return checkCynaraError(
240         cynara_check(m_Cynara,
241             label.c_str(), session.c_str(), user.c_str(), privilege.c_str()),
242         "Cannot check permission with Cynara.");
243 }
244
245 } // namespace SecurityManager