}
}
-Cynara::Cynara() : m_eventFd(eventfd(0, 0)), m_cynaraFd(m_eventFd), m_cynaraFdEvents(0), m_terminate(false)
+Cynara::Cynara()
{
- if (m_eventFd == -1) {
- LogErrno("creating eventfd");
- ThrowMsg(CynaraException::UnknownError, "Error while creating eventfd");
- }
-
- cynara_async_configuration *p_conf = nullptr;
- checkCynaraError(cynara_async_configuration_create(&p_conf),
- "Cannot create cynara async configuration");
- auto confPtr = makeUnique(p_conf, cynara_async_configuration_destroy);
-
- checkCynaraError(cynara_async_configuration_set_cache_size(p_conf, CACHE_SIZE),
- "Cannot set cynara async configuration cache size");
- checkCynaraError(
- cynara_async_initialize(&m_cynara, p_conf, &Cynara::statusCallback, this),
- "Cannot connect to Cynara policy interface.");
-
- m_thread = std::thread(&Cynara::run, this);
+ cynara_configuration *p_conf = nullptr;
+ checkCynaraError(cynara_configuration_create(&p_conf),
+ "Cannot create cynara configuration");
+ auto confPtr = makeUnique(p_conf, cynara_configuration_destroy);
+ checkCynaraError(cynara_configuration_set_cache_size(p_conf, CACHE_SIZE),
+ "Cannot set cynara cache size");
+ checkCynaraError(cynara_initialize(&m_cynara, p_conf),
+ "Cannot connect to Cynara policy interface.");
}
Cynara::~Cynara()
{
- LogDebug("Sending terminate event to Cynara thread");
- m_terminate = true;
- threadNotifyPut();
- m_thread.join();
-
- // Critical section
- std::lock_guard<std::mutex> guard(m_mutex);
- cynara_async_finish(m_cynara);
-}
-
-void Cynara::threadNotifyPut()
-{
- if (eventfd_write(m_eventFd, 1))
- LogErrno("writing to eventfd");
+ cynara_finish(m_cynara);
}
-void Cynara::threadNotifyGet()
-{
- eventfd_t value;
- if (eventfd_read(m_eventFd, &value))
- LogErrno("reading from eventfd");
-}
-
-void Cynara::statusCallback(int oldFd, int newFd, cynara_async_status status)
-{
- LogDebug("Cynara status callback. " <<
- "Status = " << status << ", oldFd = " << oldFd << ", newFd = " << newFd);
-
- if (newFd == -1) {
- m_cynaraFdEvents = 0;
- } else {
- m_cynaraFd = newFd;
- switch (status) {
- case CYNARA_STATUS_FOR_READ:
- m_cynaraFdEvents = POLLIN;
- break;
- case CYNARA_STATUS_FOR_RW:
- m_cynaraFdEvents = POLLIN | POLLOUT;
- break;
- }
- }
-
- std::atomic_thread_fence(std::memory_order_release);
- threadNotifyPut();
-}
-
-void Cynara::statusCallback(int oldFd, int newFd, cynara_async_status status,
- void *ptr)
-{
- static_cast<Cynara *>(ptr)->statusCallback(oldFd, newFd, status);
-}
-
-void Cynara::responseCallback(cynara_check_id checkId,
- cynara_async_call_cause cause, int response, void *ptr)
-{
- LogDebug("Response for received for Cynara check id: " << checkId);
-
- auto promise = static_cast<std::promise<bool>*>(ptr);
-
- switch (cause) {
- case CYNARA_CALL_CAUSE_ANSWER:
- LogDebug("Cynara cause: ANSWER: " << response);
- promise->set_value(response == CYNARA_API_ACCESS_ALLOWED);
- break;
-
- case CYNARA_CALL_CAUSE_CANCEL:
- LogDebug("Cynara cause: CANCEL");
- promise->set_value(CYNARA_API_ACCESS_DENIED);
- break;
-
- case CYNARA_CALL_CAUSE_FINISH:
- LogDebug("Cynara cause: FINISH");
- promise->set_value(CYNARA_API_ACCESS_DENIED);
- break;
-
- case CYNARA_CALL_CAUSE_SERVICE_NOT_AVAILABLE:
- LogError("Cynara cause: SERVICE_NOT_AVAILABLE");
-
- try {
- ThrowMsg(CynaraException::ServiceNotAvailable,
- "Cynara service not available");
- } catch (...) {
- promise->set_exception(std::current_exception());
- }
- break;
- }
-}
-
-void Cynara::run()
-{
- LogInfo("Cynara thread started");
- while (true) {
- std::atomic_thread_fence(std::memory_order_acquire);
- struct pollfd pollFds[2] = {{m_eventFd, POLLIN, 0}, {m_cynaraFd, m_cynaraFdEvents, 0}};
- int ret = poll(pollFds, 2, -1);
-
- if (ret == -1) {
- Assert(errno == EINTR);
- continue;
- }
-
- // Check eventfd for termination signal
- if (pollFds[0].revents) {
- threadNotifyGet();
- if (m_terminate) {
- LogInfo("Cynara thread terminated");
- return;
- }
- }
-
- // Check if Cynara fd is ready for processing
- if (pollFds[1].revents) {
- try {
- // Critical section
- std::lock_guard<std::mutex> guard(m_mutex);
-
- checkCynaraError(cynara_async_process(m_cynara),
- "Unexpected error returned by cynara_async_process");
- } catch (const CynaraException::Base &e) {
- LogError("Error while processing Cynara events: " << e.DumpToString());
- }
- }
- }
-}
bool Cynara::check(const std::string &label, const std::string &privilege,
const std::string &user, const std::string &session)
{
std::lock_guard<std::mutex> lock(m_api_mutex);
- // TODO remove the async API here in refactoring later
- // introduced in 2015 with multithreaded security-manager in mind
LogDebug("check: client = " << label << ", user = " << user <<
", privilege = " << privilege << ", session = " << session);
- std::promise<bool> promise;
- auto future = promise.get_future();
-
- // Critical section
- {
- std::lock_guard<std::mutex> guard(m_mutex);
-
- int ret = cynara_async_check_cache(m_cynara,
+ int ret = cynara_check(m_cynara,
label.c_str(), session.c_str(), user.c_str(), privilege.c_str());
- if (ret != CYNARA_API_CACHE_MISS)
- return checkCynaraError(ret, "Error while checking Cynara cache");
-
- LogDebug("Cynara cache miss");
-
- cynara_check_id check_id;
- checkCynaraError(
- cynara_async_create_request(m_cynara,
- label.c_str(), session.c_str(), user.c_str(), privilege.c_str(),
- &check_id, &Cynara::responseCallback, &promise),
- "Cannot check permission with Cynara.");
-
- LogDebug("Waiting for response to Cynara query id " << check_id);
- }
-
- return future.get();
+ return ret == CYNARA_API_ACCESS_ALLOWED;
}
} // namespace SecurityManager