PageRenderTime 45ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/src/service/logic/Logic.cpp

https://gitlab.com/admin-github-cloud/cynara
C++ | 572 lines | 466 code | 80 blank | 26 comment | 58 complexity | dbc2e13e7340820abaf9159ab42dde21 MD5 | raw file
  1. /*
  2. * Copyright (c) 2014-2016 Samsung Electronics Co., Ltd All Rights Reserved
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /**
  17. * @file src/service/logic/Logic.cpp
  18. * @author Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
  19. * @author Zofia Abramowska <z.abramowska@samsung.com>
  20. * @author Pawel Wieczorek <p.wieczorek2@samsung.com>
  21. * @version 1.0
  22. * @brief This file implements main class of logic layer in cynara service
  23. */
  24. #include <csignal>
  25. #include <cinttypes>
  26. #include <functional>
  27. #include <memory>
  28. #include <vector>
  29. #include <attributes/attributes.h>
  30. #include <log/log.h>
  31. #include <common.h>
  32. #include <log/log.h>
  33. #include <exceptions/BucketNotExistsException.h>
  34. #include <exceptions/DatabaseCorruptedException.h>
  35. #include <exceptions/DatabaseException.h>
  36. #include <exceptions/DefaultBucketDeletionException.h>
  37. #include <exceptions/DefaultBucketSetNoneException.h>
  38. #include <exceptions/InvalidBucketIdException.h>
  39. #include <exceptions/PluginErrorException.h>
  40. #include <exceptions/PluginNotFoundException.h>
  41. #include <exceptions/UnexpectedErrorException.h>
  42. #include <exceptions/UnknownPolicyTypeException.h>
  43. #include <request/AdminCheckRequest.h>
  44. #include <request/AgentActionRequest.h>
  45. #include <request/AgentRegisterRequest.h>
  46. #include <request/CancelRequest.h>
  47. #include <request/CheckRequest.h>
  48. #include <request/DescriptionListRequest.h>
  49. #include <request/EraseRequest.h>
  50. #include <request/InsertOrUpdateBucketRequest.h>
  51. #include <request/ListRequest.h>
  52. #include <request/MonitorEntriesPutRequest.h>
  53. #include <request/MonitorEntryPutRequest.h>
  54. #include <request/MonitorGetEntriesRequest.h>
  55. #include <request/MonitorGetFlushRequest.h>
  56. #include <request/RemoveBucketRequest.h>
  57. #include <request/RequestContext.h>
  58. #include <request/SetPoliciesRequest.h>
  59. #include <request/SignalRequest.h>
  60. #include <request/SimpleCheckRequest.h>
  61. #include <response/AdminCheckResponse.h>
  62. #include <response/AgentRegisterResponse.h>
  63. #include <response/CancelResponse.h>
  64. #include <response/CheckResponse.h>
  65. #include <response/CodeResponse.h>
  66. #include <response/DescriptionListResponse.h>
  67. #include <response/ListResponse.h>
  68. #include <response/MonitorGetEntriesResponse.h>
  69. #include <response/SimpleCheckResponse.h>
  70. #include <types/Policy.h>
  71. #include <main/Cynara.h>
  72. #include <agent/AgentManager.h>
  73. #include <sockets/SocketManager.h>
  74. #include <storage/Storage.h>
  75. #include <cynara-plugin.h>
  76. #include <cynara-agent.h>
  77. #include "Logic.h"
  78. namespace Cynara {
  79. Logic::Logic() : m_dbCorrupted(false) {
  80. }
  81. Logic::~Logic() {
  82. }
  83. void Logic::execute(const RequestContext &context UNUSED, const SignalRequest &request) {
  84. LOGD("Processing signal: [%d]", request.signalNumber());
  85. switch (request.signalNumber()) {
  86. case SIGTERM:
  87. LOGI("SIGTERM received!");
  88. m_socketManager->mainLoopStop();
  89. break;
  90. }
  91. }
  92. void Logic::execute(const RequestContext &context, const AdminCheckRequest &request) {
  93. PolicyResult result;
  94. bool bucketValid = true;
  95. if (m_dbCorrupted) {
  96. bucketValid = false;
  97. } else {
  98. try {
  99. result = m_storage->checkPolicy(request.key(), request.startBucket(),
  100. request.recursive());
  101. } catch (const BucketNotExistsException &ex) {
  102. bucketValid = false;
  103. }
  104. }
  105. context.returnResponse(AdminCheckResponse(result, bucketValid, m_dbCorrupted,
  106. request.sequenceNumber()));
  107. }
  108. void Logic::execute(const RequestContext &context, const AgentActionRequest &request) {
  109. AgentTalkerPtr talkerPtr = m_agentManager->getTalker(context.responseQueue(),
  110. request.sequenceNumber());
  111. if (!talkerPtr) {
  112. LOGD("Received response from agent with invalid request id: [%" PRIu16 "]",
  113. request.sequenceNumber());
  114. return;
  115. }
  116. CheckContextPtr checkContextPtr = m_checkRequestManager.getContext(talkerPtr);
  117. if (!checkContextPtr) {
  118. LOGE("No matching check context for agent talker.");
  119. m_agentManager->removeTalker(talkerPtr);
  120. return;
  121. }
  122. if (!checkContextPtr->cancelled()) {
  123. PluginData data(request.data().begin(), request.data().end());
  124. if (request.type() == CYNARA_MSG_TYPE_CANCEL) {
  125. // Nothing to do for now
  126. } else if (request.type() == CYNARA_MSG_TYPE_ACTION) {
  127. update(checkContextPtr->m_key, checkContextPtr->m_checkId, data,
  128. checkContextPtr->m_requestContext, checkContextPtr->m_plugin);
  129. } else {
  130. LOGE("Invalid response type [%d] in response from agent <%s>",
  131. static_cast<int>(request.type()), talkerPtr->agentType().c_str());
  132. // TODO: disconnect agent
  133. }
  134. }
  135. m_agentManager->removeTalker(talkerPtr);
  136. m_checkRequestManager.removeRequest(checkContextPtr);
  137. }
  138. void Logic::execute(const RequestContext &context, const AgentRegisterRequest &request) {
  139. auto result = m_agentManager->registerAgent(request.agentType(), context.responseQueue());
  140. context.returnResponse(AgentRegisterResponse(result, request.sequenceNumber()));
  141. }
  142. void Logic::execute(const RequestContext &context, const CancelRequest &request) {
  143. CheckContextPtr checkContextPtr = m_checkRequestManager.getContext(context.responseQueue(),
  144. request.sequenceNumber());
  145. if (!checkContextPtr) {
  146. LOGD("Cancel request id: [%" PRIu16 "] with no matching request in progress.",
  147. request.sequenceNumber());
  148. return;
  149. }
  150. if (checkContextPtr->cancelled())
  151. return;
  152. checkContextPtr->cancel();
  153. checkContextPtr->m_agentTalker->cancel();
  154. LOGD("Returning response for cancel request id: [%" PRIu16 "].", request.sequenceNumber());
  155. context.returnResponse(CancelResponse(request.sequenceNumber()));
  156. }
  157. void Logic::execute(const RequestContext &context, const CheckRequest &request) {
  158. PolicyResult result(PredefinedPolicyType::DENY);
  159. if (check(context, request.key(), request.sequenceNumber(), result)) {
  160. m_auditLog.log(request.key(), result);
  161. context.returnResponse(CheckResponse(result, request.sequenceNumber()));
  162. }
  163. }
  164. bool Logic::check(const RequestContext &context, const PolicyKey &key,
  165. ProtocolFrameSequenceNumber checkId, PolicyResult &result) {
  166. if (m_checkRequestManager.getContext(context.responseQueue(), checkId)) {
  167. LOGE("Check request for checkId: [%" PRIu16 "] is already processing", checkId);
  168. return false;
  169. }
  170. result = (m_dbCorrupted ? PredefinedPolicyType::DENY : m_storage->checkPolicy(key));
  171. switch (result.policyType()) {
  172. case PredefinedPolicyType::ALLOW :
  173. LOGD("check of policy key <%s> returned ALLOW", key.toString().c_str());
  174. return true;
  175. case PredefinedPolicyType::DENY :
  176. LOGD("check of policy key <%s> returned DENY", key.toString().c_str());
  177. return true;
  178. }
  179. return pluginCheck(context, key, checkId, result);
  180. }
  181. bool Logic::pluginCheck(const RequestContext &context, const PolicyKey &key,
  182. ProtocolFrameSequenceNumber checkId, PolicyResult &result) {
  183. LOGD("Trying to check policy: <%s> in plugin.", key.toString().c_str());
  184. ExternalPluginPtr plugin = m_pluginManager->getPlugin(result.policyType());
  185. if (!plugin) {
  186. LOGE("Plugin not found for policy: [0x%x]", result.policyType());
  187. result = PolicyResult(PredefinedPolicyType::DENY);
  188. return true;
  189. }
  190. ServicePluginInterfacePtr servicePlugin =
  191. std::dynamic_pointer_cast<ServicePluginInterface>(plugin);
  192. if (!servicePlugin) {
  193. result = PolicyResult(PredefinedPolicyType::DENY);
  194. return true;
  195. }
  196. AgentType requiredAgent;
  197. PluginData pluginData;
  198. auto ret = servicePlugin->check(key.client().toString(), key.user().toString(),
  199. key.privilege().toString(), result, requiredAgent, pluginData);
  200. switch (ret) {
  201. case ServicePluginInterface::PluginStatus::ANSWER_READY:
  202. return true;
  203. case ServicePluginInterface::PluginStatus::ANSWER_NOTREADY: {
  204. result = PolicyResult(PredefinedPolicyType::DENY);
  205. AgentTalkerPtr agentTalker = m_agentManager->createTalker(requiredAgent);
  206. if (!agentTalker) {
  207. LOGE("Required agent talker for: <%s> could not be created.",
  208. requiredAgent.c_str());
  209. return true;
  210. }
  211. if (!m_checkRequestManager.createContext(key, context, checkId, servicePlugin,
  212. agentTalker)) {
  213. LOGE("Check context for checkId: [%" PRIu16 "] could not be created.",
  214. checkId);
  215. m_agentManager->removeTalker(agentTalker);
  216. return true;
  217. }
  218. agentTalker->send(pluginData);
  219. }
  220. return false;
  221. default:
  222. result = PolicyResult(PredefinedPolicyType::DENY);
  223. return true;
  224. }
  225. }
  226. bool Logic::update(const PolicyKey &key, ProtocolFrameSequenceNumber checkId,
  227. const PluginData &agentData, const RequestContext &context,
  228. const ServicePluginInterfacePtr &plugin) {
  229. LOGD("Check update: <%s>:[%" PRIu16 "]", key.toString().c_str(), checkId);
  230. PolicyResult result;
  231. bool answerReady = false;
  232. auto ret = plugin->update(key.client().toString(), key.user().toString(),
  233. key.privilege().toString(), agentData, result);
  234. switch (ret) {
  235. case ServicePluginInterface::PluginStatus::SUCCESS:
  236. answerReady = true;
  237. break;
  238. case ServicePluginInterface::PluginStatus::ERROR:
  239. result = PolicyResult(PredefinedPolicyType::DENY);
  240. answerReady = true;
  241. break;
  242. default:
  243. throw PluginErrorException(key);
  244. }
  245. if (answerReady && context.responseQueue()) {
  246. m_auditLog.log(key, result);
  247. context.returnResponse(CheckResponse(result, checkId));
  248. return true;
  249. }
  250. return false;
  251. }
  252. void Logic::execute(const RequestContext &context, const DescriptionListRequest &request) {
  253. auto descriptions = m_pluginManager->getPolicyDescriptions();
  254. descriptions.insert(descriptions.begin(), predefinedPolicyDescr.begin(),
  255. predefinedPolicyDescr.end());
  256. context.returnResponse(DescriptionListResponse(descriptions, m_dbCorrupted,
  257. request.sequenceNumber()));
  258. }
  259. void Logic::execute(const RequestContext &context, const EraseRequest &request) {
  260. auto code = CodeResponse::Code::OK;
  261. if (m_dbCorrupted) {
  262. code = CodeResponse::Code::DB_CORRUPTED;
  263. } else {
  264. try {
  265. m_storage->erasePolicies(request.startBucket(), request.recursive(), request.filter());
  266. onPoliciesChanged();
  267. } catch (const DatabaseException &ex) {
  268. code = CodeResponse::Code::FAILED;
  269. } catch (const BucketNotExistsException &ex) {
  270. code = CodeResponse::Code::NO_BUCKET;
  271. }
  272. }
  273. context.returnResponse(CodeResponse(code, request.sequenceNumber()));
  274. }
  275. void Logic::execute(const RequestContext &context, const InsertOrUpdateBucketRequest &request) {
  276. auto code = CodeResponse::Code::OK;
  277. if (m_dbCorrupted) {
  278. code = CodeResponse::Code::DB_CORRUPTED;
  279. } else {
  280. try {
  281. checkSinglePolicyType(request.result().policyType(), true, true);
  282. m_storage->addOrUpdateBucket(request.bucketId(), request.result());
  283. onPoliciesChanged();
  284. } catch (const DatabaseException &ex) {
  285. code = CodeResponse::Code::FAILED;
  286. } catch (const DefaultBucketSetNoneException &ex) {
  287. code = CodeResponse::Code::NOT_ALLOWED;
  288. } catch (const InvalidBucketIdException &ex) {
  289. code = CodeResponse::Code::NOT_ALLOWED;
  290. } catch (const UnknownPolicyTypeException &ex) {
  291. code = CodeResponse::Code::NO_POLICY_TYPE;
  292. }
  293. }
  294. context.returnResponse(CodeResponse(code, request.sequenceNumber()));
  295. }
  296. void Logic::execute(const RequestContext &context, const ListRequest &request) {
  297. bool bucketValid = true;
  298. std::vector<Policy> policies;
  299. if (m_dbCorrupted) {
  300. bucketValid = false;
  301. } else {
  302. try {
  303. policies = m_storage->listPolicies(request.bucket(), request.filter());
  304. } catch (const BucketNotExistsException &ex) {
  305. bucketValid = false;
  306. }
  307. }
  308. context.returnResponse(ListResponse(policies, bucketValid, m_dbCorrupted,
  309. request.sequenceNumber()));
  310. }
  311. void Logic::execute(const RequestContext &context, const RemoveBucketRequest &request) {
  312. auto code = CodeResponse::Code::OK;
  313. if (m_dbCorrupted) {
  314. code = CodeResponse::Code::DB_CORRUPTED;
  315. } else {
  316. try {
  317. m_storage->deleteBucket(request.bucketId());
  318. onPoliciesChanged();
  319. } catch (const DatabaseException &ex) {
  320. code = CodeResponse::Code::FAILED;
  321. } catch (const BucketNotExistsException &ex) {
  322. code = CodeResponse::Code::NO_BUCKET;
  323. } catch (const DefaultBucketDeletionException &ex) {
  324. code = CodeResponse::Code::NOT_ALLOWED;
  325. }
  326. }
  327. context.returnResponse(CodeResponse(code, request.sequenceNumber()));
  328. }
  329. void Logic::execute(const RequestContext &context, const SetPoliciesRequest &request) {
  330. auto code = CodeResponse::Code::OK;
  331. if (m_dbCorrupted) {
  332. code = CodeResponse::Code::DB_CORRUPTED;
  333. } else {
  334. try {
  335. checkPoliciesTypes(request.policiesToBeInsertedOrUpdated(), true, false);
  336. m_storage->insertPolicies(request.policiesToBeInsertedOrUpdated());
  337. m_storage->deletePolicies(request.policiesToBeRemoved());
  338. onPoliciesChanged();
  339. } catch (const DatabaseException &ex) {
  340. code = CodeResponse::Code::FAILED;
  341. } catch (const BucketNotExistsException &ex) {
  342. code = CodeResponse::Code::NO_BUCKET;
  343. } catch (const UnknownPolicyTypeException &ex) {
  344. code = CodeResponse::Code::NO_POLICY_TYPE;
  345. }
  346. }
  347. context.returnResponse(CodeResponse(code, request.sequenceNumber()));
  348. }
  349. void Logic::execute(const RequestContext &context, const SimpleCheckRequest &request) {
  350. int retValue = CYNARA_API_SUCCESS;
  351. PolicyResult result;
  352. PolicyKey key = request.key();
  353. result = m_storage->checkPolicy(key);
  354. switch (result.policyType()) {
  355. case PredefinedPolicyType::ALLOW:
  356. LOGD("simple check of policy key <%s> returned ALLOW", key.toString().c_str());
  357. break;
  358. case PredefinedPolicyType::DENY:
  359. LOGD("simple check of policy key <%s> returned DENY", key.toString().c_str());
  360. break;
  361. default: {
  362. ExternalPluginPtr plugin = m_pluginManager->getPlugin(result.policyType());
  363. if (!plugin) {
  364. LOGE("Plugin not found for policy: [0x%x]", result.policyType());
  365. result = PolicyResult(PredefinedPolicyType::DENY);
  366. retValue = CYNARA_API_SUCCESS;
  367. break;
  368. }
  369. ServicePluginInterfacePtr servicePlugin =
  370. std::dynamic_pointer_cast<ServicePluginInterface>(plugin);
  371. if (!servicePlugin) {
  372. LOGE("Couldn't cast plugin pointer to ServicePluginInterface");
  373. result = PolicyResult(PredefinedPolicyType::DENY);
  374. retValue = CYNARA_API_SUCCESS;
  375. break;
  376. }
  377. AgentType requiredAgent;
  378. PluginData pluginData;
  379. auto ret = servicePlugin->check(key.client().toString(), key.user().toString(),
  380. key.privilege().toString(), result, requiredAgent,
  381. pluginData);
  382. switch (ret) {
  383. case ServicePluginInterface::PluginStatus::ANSWER_READY:
  384. LOGD("simple check of policy key <%s> in plugin returned [" PRIu16 "]",
  385. key.toString().c_str(), result.policyType());
  386. break;
  387. case ServicePluginInterface::PluginStatus::ANSWER_NOTREADY:
  388. retValue = CYNARA_API_ACCESS_NOT_RESOLVED;
  389. break;
  390. default:
  391. result = PolicyResult(PredefinedPolicyType::DENY);
  392. retValue = CYNARA_API_SUCCESS;
  393. }
  394. }
  395. }
  396. m_auditLog.log(request.key(), result);
  397. context.returnResponse(SimpleCheckResponse(retValue, result,
  398. request.sequenceNumber()));
  399. }
  400. void Logic::sendMonitorResponses(void) {
  401. if (m_monitorLogic.shouldSend()) {
  402. auto responses = m_monitorLogic.getResponses();
  403. for (auto &response : responses) {
  404. auto responseInfo = response.info;
  405. auto &responseVec = response.entries;
  406. responseInfo.context.returnResponse(MonitorGetEntriesResponse(responseVec,
  407. responseInfo.seq));
  408. }
  409. }
  410. }
  411. void Logic::execute(const RequestContext &context, const MonitorGetEntriesRequest &request) {
  412. m_monitorLogic.addClient(context, request.sequenceNumber(), request.bufferSize());
  413. sendMonitorResponses();
  414. }
  415. void Logic::execute(const RequestContext &context, const MonitorGetFlushRequest &request UNUSED) {
  416. m_monitorLogic.flushClient(context);
  417. sendMonitorResponses();
  418. }
  419. void Logic::execute(const RequestContext &context UNUSED, const MonitorEntriesPutRequest &request) {
  420. for (unsigned i = 0; i < request.monitorEntries().size(); i++) {
  421. m_monitorLogic.addEntry(request.monitorEntries()[i]);
  422. sendMonitorResponses();
  423. }
  424. }
  425. void Logic::execute(const RequestContext &context UNUSED, const MonitorEntryPutRequest &request) {
  426. m_monitorLogic.addEntry(request.monitorEntry());
  427. sendMonitorResponses();
  428. }
  429. void Logic::checkPoliciesTypes(const std::map<PolicyBucketId, std::vector<Policy>> &policies,
  430. bool allowBucket, bool allowNone) {
  431. for (const auto &group : policies) {
  432. for (const auto &policy : group.second) {
  433. checkSinglePolicyType(policy.result().policyType(), allowBucket, allowNone);
  434. }
  435. }
  436. }
  437. void Logic::checkSinglePolicyType(const PolicyType &policyType, bool allowBucket, bool allowNone) {
  438. if (allowBucket && policyType == PredefinedPolicyType::BUCKET)
  439. return;
  440. if (allowNone && policyType == PredefinedPolicyType::NONE)
  441. return;
  442. for (const auto &descr : predefinedPolicyDescr) {
  443. if (descr.type == policyType)
  444. return;
  445. }
  446. m_pluginManager->checkPolicyType(policyType);
  447. }
  448. void Logic::contextClosed(const RequestContext &context) {
  449. LOGD("context closed");
  450. LinkId linkId = context.responseQueue();
  451. m_agentManager->cleanupAgent(linkId, [&](const AgentTalkerPtr &talker) -> void {
  452. handleAgentTalkerDisconnection(talker); });
  453. m_checkRequestManager.cancelRequests(linkId,
  454. [&](const CheckContextPtr &checkContextPtr) -> void {
  455. handleClientDisconnection(checkContextPtr); });
  456. m_monitorLogic.removeClient(context);
  457. }
  458. void Logic::onPoliciesChanged(void) {
  459. m_storage->save();
  460. m_socketManager->disconnectAllClients();
  461. m_pluginManager->invalidateAll();
  462. //todo remove all saved contexts (if there will be any saved contexts)
  463. }
  464. void Logic::handleAgentTalkerDisconnection(const AgentTalkerPtr &agentTalkerPtr) {
  465. CheckContextPtr checkContextPtr = m_checkRequestManager.getContext(agentTalkerPtr);
  466. if (checkContextPtr == nullptr) {
  467. LOGE("No matching check context for agent talker.");
  468. return;
  469. }
  470. RequestContext &context = checkContextPtr->m_requestContext;
  471. if (!checkContextPtr->cancelled() && context.responseQueue()) {
  472. PolicyResult result(PredefinedPolicyType::DENY);
  473. m_auditLog.log(checkContextPtr->m_key, result);
  474. context.returnResponse(CheckResponse(result, checkContextPtr->m_checkId));
  475. }
  476. m_checkRequestManager.removeRequest(checkContextPtr);
  477. }
  478. void Logic::handleClientDisconnection(const CheckContextPtr &checkContextPtr) {
  479. LOGD("Handle client disconnection");
  480. if (!checkContextPtr->cancelled()) {
  481. checkContextPtr->cancel();
  482. checkContextPtr->m_agentTalker->cancel();
  483. }
  484. }
  485. void Logic::loadDb(void) {
  486. try {
  487. m_storage->load();
  488. } catch (const DatabaseCorruptedException &) {
  489. m_dbCorrupted = true;
  490. }
  491. }
  492. } // namespace Cynara