8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-29 06:43:03 +01:00
firebird-mirror/src/jrd/extds/ValidatePassword.cpp
asfernandes 436b531774 Misc.
2016-01-31 00:06:06 +00:00

290 lines
6.7 KiB
C++

/*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (the "License");
* you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
* http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Alexander Peshkov
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2016 Alexander Peshkov <peshkoff@mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include "firebird.h"
#include "fb_exception.h"
#include "iberror.h"
#include "../jrd.h"
#include "../common/isc_f_proto.h"
#include "../common/db_alias.h"
#include "../common/isc_proto.h"
#include "../common/Auth.h"
#include "../common/classes/GetPlugins.h"
using namespace Jrd;
using namespace Firebird;
namespace {
class DummyCryptKey FB_FINAL :
public Firebird::AutoIface<Firebird::ICryptKeyImpl<DummyCryptKey, Firebird::CheckStatusWrapper> >
{
public:
// ICryptKey implementation
void setSymmetric(Firebird::CheckStatusWrapper* status, const char* type, unsigned keyLength, const void* key)
{ }
void setAsymmetric(Firebird::CheckStatusWrapper* status, const char* type, unsigned encryptKeyLength,
const void* encryptKey, unsigned decryptKeyLength, const void* decryptKey)
{ }
const void* getEncryptKey(unsigned* length)
{
*length = 0;
return NULL;
}
const void* getDecryptKey(unsigned* length)
{
*length = 0;
return NULL;
}
};
class SBlock;
class CBlock FB_FINAL : public RefCntIface<IClientBlockImpl<CBlock, CheckStatusWrapper> >
{
public:
CBlock(const string& p_login, const string& p_password)
: login(p_login), password(p_password)
{ }
// Firebird::IClientBlock implementation
int release()
{
return 1;
}
const char* getLogin()
{
return login.c_str();
}
const char* getPassword()
{
return password.c_str();
}
const unsigned char* getData(unsigned int* length)
{
*length = data.getCount();
return data.begin();
}
void putData(CheckStatusWrapper* status, unsigned int length, const void* d);
Firebird::ICryptKey* newKey(Firebird::CheckStatusWrapper* status)
{
return &dummyCryptKey;
}
private:
const string& login;
const string& password;
DummyCryptKey dummyCryptKey;
UCharBuffer data;
friend class SBlock;
SBlock* sBlock;
};
class SBlock FB_FINAL : public AutoIface<IServerBlockImpl<SBlock, CheckStatusWrapper> >
{
public:
explicit SBlock(CBlock* par)
: cBlock(par)
{
cBlock->sBlock = this;
}
// Firebird::IServerBlock implementation
const char* getLogin()
{
return cBlock->getLogin();
}
const unsigned char* getData(unsigned int* length)
{
*length = data.getCount();
return data.begin();
}
void putData(CheckStatusWrapper* status, unsigned int length, const void* d);
Firebird::ICryptKey* newKey(Firebird::CheckStatusWrapper* status)
{
return &dummyCryptKey;
}
private:
DummyCryptKey dummyCryptKey;
UCharBuffer data;
friend class CBlock;
CBlock* cBlock;
};
void CBlock::putData(CheckStatusWrapper* status, unsigned int length, const void* d)
{
void* to = sBlock->data.getBuffer(length);
memcpy(to, d, length);
}
void SBlock::putData(CheckStatusWrapper* status, unsigned int length, const void* d)
{
void* to = cBlock->data.getBuffer(length);
memcpy(to, d, length);
}
} // anonymous namespace
namespace EDS {
void validatePassword(thread_db* tdbb, const PathName& file, ClumpletWriter& dpb)
{
// Peliminary checks - should we really validate password ourself
if (!dpb.find(isc_dpb_user_name)) // check for user name presence
return;
if (ISC_check_if_remote(file, false)) // check for remote connection
return;
UserId* usr = tdbb->getAttachment()->att_user;
if (!usr->usr_auth_block.hasData()) // check for embedded attachment
return;
Arg::Gds loginError(isc_login_error);
// Build list of client/server plugins
RefPtr<Config> config;
PathName list;
expandDatabaseName(file, list /* unused value */, &config);
PathName serverList = config->getPlugins(IPluginManager::TYPE_AUTH_SERVER);
PathName clientList = config->getPlugins(IPluginManager::TYPE_AUTH_CLIENT);
Auth::mergeLists(list, serverList, clientList);
if (!list.hasData())
{
Arg::Gds noPlugins(isc_random);
noPlugins << "No matching client/server authentication plugins configured for execute statement in embedded datasource";
iscLogStatus(NULL, noPlugins.value());
#ifdef DEV_BUILD
loginError << noPlugins;
#endif
loginError.raise();
}
// Analyze DPB
string login;
if (dpb.find(isc_dpb_user_name))
{
dpb.getString(login);
fb_utils::dpbItemUpper(login);
}
string password;
if (dpb.find(isc_dpb_password))
dpb.getString(password);
// Try each plugin from the merged list
for (GetPlugins<IClient> client(IPluginManager::TYPE_AUTH_CLIENT, config, list.c_str());
client.hasData(); client.next())
{
GetPlugins<IServer> server(IPluginManager::TYPE_AUTH_SERVER, config, client.name());
if (!server.hasData())
continue;
CBlock cBlock(login, password);
SBlock sBlock(&cBlock);
Auth::WriterImplementation writer;
writer.setPlugin(client.name());
const int MAXLIMIT = 100;
for (int limit = 0; limit < MAXLIMIT; ++limit) // avoid endless AUTH_MORE_DATA loop
{
LocalStatus ls;
CheckStatusWrapper s(&ls);
ISC_STATUS code = isc_login;
switch (client.plugin()->authenticate(&s, &cBlock))
{
case IAuth::AUTH_SUCCESS:
case IAuth::AUTH_MORE_DATA:
break;
case IAuth::AUTH_CONTINUE:
limit = MAXLIMIT;
continue;
case IAuth::AUTH_FAILED:
if (s.getState() & Firebird::IStatus::STATE_ERRORS)
{
iscLogStatus("Authentication failed, client plugin:", &s);
code = isc_login_error;
}
(Arg::Gds(code)
#ifdef DEV_BUILD
<< Arg::StatusVector(&s)
#endif
).raise();
break; // compiler silencer
}
switch (server.plugin()->authenticate(&s, &sBlock, &writer))
{
case IAuth::AUTH_SUCCESS:
dpb.deleteWithTag(isc_dpb_user_name);
dpb.deleteWithTag(isc_dpb_password);
writer.store(&dpb, isc_dpb_auth_block);
return;
case IAuth::AUTH_CONTINUE:
limit = MAXLIMIT;
continue;
case IAuth::AUTH_MORE_DATA:
break;
case IAuth::AUTH_FAILED:
if (s.getState() & Firebird::IStatus::STATE_ERRORS)
{
iscLogStatus("Authentication faled, server plugin:", &s);
code = isc_login_error;
}
(Arg::Gds(code)
#ifdef DEV_BUILD
<< Arg::StatusVector(&s)
#endif
).raise();
break; // compiler silencer
}
}
}
Arg::Gds(isc_login).raise();
}
} // namespace EDS