1
0
mirror of https://github.com/binary-kitchen/doorlockd synced 2024-12-23 02:34:27 +01:00
doorlockd-mirror/doorlockd/lib/logic.cpp

261 lines
6.5 KiB
C++
Raw Normal View History

#include <errno.h>
2015-05-11 20:40:26 +02:00
#define LDAP_DEPRECATED 1
#include <ldap.h>
2015-05-11 00:18:22 +02:00
#include "logic.h"
#include "util.h"
2015-05-11 00:18:22 +02:00
Logic::Logic(const std::chrono::seconds tokenTimeout,
const std::string &ldapUri,
const std::string &bindDN,
const std::string &webPrefix,
const std::string &serDev,
2015-09-23 15:33:27 +02:00
const unsigned int baudrate,
std::condition_variable &onClientUpdate) :
2015-05-11 00:18:22 +02:00
_logger(Logger::get()),
2015-09-23 15:33:27 +02:00
_door(serDev, baudrate),
2015-05-13 16:40:30 +02:00
_tokenTimeout(tokenTimeout),
2015-09-24 18:15:05 +02:00
_onClientUpdate(onClientUpdate),
2015-05-24 19:15:47 +02:00
_ldapUri(ldapUri),
2015-05-13 16:40:30 +02:00
_bindDN(bindDN),
2015-09-22 18:22:15 +02:00
_webPrefix(webPrefix)
2015-05-11 00:18:22 +02:00
{
srand(time(NULL));
2015-05-12 17:35:57 +02:00
_createNewToken(false);
2015-09-24 18:57:32 +02:00
_door.setDoorCallback(std::bind(&Logic::_doorCallback,
this,
std::placeholders::_1));
_tokenUpdater = std::thread([this] () {
2015-05-12 17:35:57 +02:00
while (_run)
{
std::unique_lock<std::mutex> l(_mutex);
2015-05-21 13:35:30 +02:00
_tokenCondition.wait_for(l, _tokenTimeout);
2015-05-12 17:35:57 +02:00
if (_run == false)
{
break;
} else {
_createNewToken(true);
}
}
});
2015-05-11 00:18:22 +02:00
}
Logic::~Logic()
{
2015-05-12 17:35:57 +02:00
_run = false;
2015-05-21 13:35:30 +02:00
_tokenCondition.notify_one();
2015-05-12 17:35:57 +02:00
_tokenUpdater.join();
2015-05-11 00:18:22 +02:00
}
Response Logic::processDoor(const DoorCommand &doorCommand)
2015-05-11 00:18:22 +02:00
{
Response response;
switch (doorCommand) {
case DoorCommand::Lock:
response = _lock();
break;
case DoorCommand::Unlock:
response = _unlock();
break;
default:
response.code = Response::Code::UnknownCommand;
response.message = "Unknown DoorCommand";
break;
2015-05-11 00:18:22 +02:00
}
return response;
}
2015-05-11 00:18:22 +02:00
Response Logic::request(const Request &request)
{
std::unique_lock<std::mutex> l(_mutex);
Response response;
DoorCommand doorCommand;
switch (request.command) {
case Request::Command::Lock:
doorCommand = DoorCommand::Lock;
break;
case Request::Command::Unlock:
doorCommand = DoorCommand::Unlock;
break;
default:
response.code = Response::Code::UnknownCommand;
response.message = "Unknown Command";
goto out;
}
2015-05-11 00:18:22 +02:00
response = _checkToken(request.token);
if (!response) {
goto out;
2015-05-11 00:18:22 +02:00
}
_logger(LogLevel::info, " -> Token check successful");
2015-05-11 00:18:22 +02:00
response = _checkLDAP(request.user, request.password);
if (!response) {
goto out;
2015-05-11 00:18:22 +02:00
}
_logger(LogLevel::info, " -> LDAP check successful");
response = processDoor(doorCommand);
_logger(LogLevel::info, " -> Door Command successful");
2015-05-12 01:28:02 +02:00
out:
return response;
2015-05-11 00:18:22 +02:00
}
Response Logic::_lock()
2015-05-11 00:18:22 +02:00
{
Response response;
if (_door.state() == Door::State::Locked)
2015-05-11 00:18:22 +02:00
{
response.code = Response::Code::AlreadyLocked;
response.message = "Unable to lock: already closed";
} else {
_createNewToken(false);
response.code = Response::Code::Success;
response.message = "Success";
2015-05-11 00:18:22 +02:00
}
2015-05-12 15:59:04 +02:00
_door.lock();
return response;
2015-05-11 00:18:22 +02:00
}
Response Logic::_unlock()
2015-05-11 00:18:22 +02:00
{
Response response;
const auto oldState = _door.state();
_door.unlock();
_createNewToken(false);
if (oldState == Door::State::Unlocked)
{
response.code = Response::Code::AlreadyUnlocked;
response.message = "Unable to unlock: already unlocked";
_logger(response.message, LogLevel::info);
} else {
response.code = Response::Code::Success;
response.message = "Success";
}
return response;
2015-05-11 00:18:22 +02:00
}
Response Logic::_checkToken(std::string token) const
2015-05-11 00:18:22 +02:00
{
std::transform(token.begin(),
token.end(),
token.begin(),
::toupper);
if (token == _curToken)
return Response(Response::Code::Success);
if (_prevValid == true && token == _prevToken)
return Response(Response::Code::Success);
_logger("Check Token failed: got \"" + token
+ "\", expected \"" + _curToken +"\"",
LogLevel::error);
return Response(Response::InvalidToken,
"User provided invalid token");
2015-05-11 00:18:22 +02:00
}
Response Logic::_checkLDAP(const std::string &user,
const std::string &password)
2015-05-11 00:18:22 +02:00
{
2015-05-11 20:40:26 +02:00
constexpr int BUFFERSIZE = 1024;
char buffer[BUFFERSIZE];
Response retval;
2015-05-11 20:40:26 +02:00
int rc = -1;
LDAP* ld = nullptr;
unsigned long version = LDAP_VERSION3;
_logger(LogLevel::info, " Trying to authenticate as user \"%s\"", user.c_str());
2015-05-11 20:40:26 +02:00
snprintf(buffer, BUFFERSIZE, _bindDN.c_str(), user.c_str());
2015-05-24 19:15:47 +02:00
rc = ldap_initialize(&ld, _ldapUri.c_str());
2015-05-11 20:40:26 +02:00
if(rc != LDAP_SUCCESS)
{
retval.message = (std::string)"LDAP initialize error: "
+ ldap_err2string(rc);
retval.code = Response::Code::LDAPInit;
2015-05-11 20:40:26 +02:00
goto out2;
}
rc = ldap_set_option(ld,
LDAP_OPT_PROTOCOL_VERSION,
(void*)&version);
if (rc != LDAP_SUCCESS)
{
retval.code = Response::Code::LDAPInit;
retval.message = "LDAP set version failed";
2015-05-11 20:40:26 +02:00
goto out;
}
rc = ldap_simple_bind_s(ld, buffer, password.c_str());
if (rc != LDAP_SUCCESS)
{
retval = Response::Code::InvalidCredentials;
retval.message = "Credential check for user \"" + user
+ "\" failed: " + ldap_err2string(rc);
2015-05-11 20:40:26 +02:00
goto out;
}
retval.code = Response::Code::Success;
retval.message = "";
2015-05-11 20:40:26 +02:00
out:
ldap_unbind(ld);
ld = nullptr;
out2:
return retval;
2015-05-11 00:18:22 +02:00
}
2015-05-12 17:35:57 +02:00
void Logic::_createNewToken(const bool stillValid)
2015-05-11 00:18:22 +02:00
{
// Todo Mutex einführen
2015-05-11 00:18:22 +02:00
_prevToken = _curToken;
_prevValid = stillValid;
_curToken = toHexString((((uint64_t)rand())<<32) | ((uint64_t)rand()));
2015-05-11 00:18:22 +02:00
std::ostringstream message;
message << "New token: " << _curToken
<< " old token: " << _prevToken << " is "
<< (_prevValid?"still":"not") << " valid";
_logger(message, LogLevel::notice);
2015-09-24 18:15:05 +02:00
_onClientUpdate.notify_all();
}
Clientmessage Logic::getClientMessage()
2015-09-24 18:57:32 +02:00
{
std::lock_guard<std::mutex> l(_mutex);
Clientmessage retval(_webPrefix + _curToken,
_door.state() == Door::State::Unlocked,
_doormessage);
2015-09-24 18:57:32 +02:00
// Reset doormessage
_doormessage = Doormessage();
2015-09-24 18:57:32 +02:00
return retval;
2015-09-24 18:57:32 +02:00
}
void Logic::_doorCallback(Doormessage doormessage)
{
2015-09-24 18:57:32 +02:00
std::lock_guard<std::mutex> l(_mutex);
_doormessage = doormessage;
_onClientUpdate.notify_all();
2015-05-11 00:18:22 +02:00
}