8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 15:23:03 +01:00

Added a sample of authentication plugin based on shared secret key

This commit is contained in:
AlexPeshkoff 2020-02-07 20:36:20 +03:00
parent 696673bca1
commit 57e7035411
9 changed files with 1048 additions and 2 deletions

View File

@ -98,6 +98,11 @@ $(FIREBIRD)/examples/README:
$(CP) $(ROOT)/examples/*.* $(FIREBIRD)/examples/
$(CP) $(ROOT)/examples/api/*.* $(FIREBIRD)/examples/api/
$(CP) $(ROOT)/examples/dbcrypt/*.* $(FIREBIRD)/examples/dbcrypt/
$(CP) $(ROOT)/examples/extauth/* $(FIREBIRD)/examples/extauth/
ifeq ($(TOMCRYPT_BUILD_FLG),Y)
mkdir -p $(FIREBIRD)/examples/extauth/tomcrypt.include
$(CP) $(ROOT)/extern/libtomcrypt/src/headers/* $(FIREBIRD)/examples/extauth/tomcrypt.include
endif
$(CP) $(ROOT)/examples/include/*.* $(FIREBIRD)/examples/include/
$(CP) $(ROOT)/examples/interfaces/*.* $(FIREBIRD)/examples/interfaces/
$(CP) $(ROOT)/examples/package/*.* $(FIREBIRD)/examples/package/

View File

@ -1216,6 +1216,7 @@ dnl # output
mkdir -p gen/\$fb_tgt/firebird/examples/api
mkdir -p gen/\$fb_tgt/firebird/examples/dbcrypt
mkdir -p gen/\$fb_tgt/firebird/examples/empbuild
mkdir -p gen/\$fb_tgt/firebird/examples/extauth
mkdir -p gen/\$fb_tgt/firebird/examples/include
mkdir -p gen/\$fb_tgt/firebird/examples/interfaces
mkdir -p gen/\$fb_tgt/firebird/examples/package

View File

@ -0,0 +1,452 @@
/*
* Simple shared-key based authentication plugin
* Each node (firebird server) contains same key which is used to authenticate cross-server
* connections. Each connection coming from one node to another has on target same
* login as it was on source node.
*
* 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
* https://www.firebirdsql.org/en/initial-developer-s-public-license-version-1-0/
*
* 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 Peshkoff
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2020 Alexander Peshkoff <peshkoff@mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include <memory>
#include <atomic>
#include "TcWrapper.h"
#define HANDSHAKE_DEBUG(A)
const unsigned LOGINSIZE = 128u;
const unsigned RANDSIZE = 32u;
const unsigned SALTLEN = 8u;
typedef unsigned int ULong;
using namespace std;
namespace {
IMaster* master = NULL;
class PluginModule : public IPluginModuleImpl<PluginModule, ThrowStatusWrapper>
{
public:
PluginModule()
: pluginManager(NULL)
{ }
~PluginModule()
{
if (pluginManager)
{
pluginManager->unregisterModule(this);
doClean();
}
}
void registerMe(IPluginManager* m)
{
pluginManager = m;
pluginManager->registerModule(this);
}
void doClean()
{
pluginManager = NULL;
}
void threadDetach()
{ }
private:
IPluginManager* pluginManager;
};
template <class P>
class Factory : public IPluginFactoryImpl<Factory<P>, ThrowStatusWrapper>
{
public:
// IPluginFactory implementation
IPluginBase* createPlugin(ThrowStatusWrapper* status, IPluginConfig* factoryParameter)
{
IPluginBase* p = new P(status, factoryParameter);
p->addRef();
return p;
}
};
//
// Common RSA helper
//
class PluginData
{
public:
PluginData(ThrowStatusWrapper* status, IPluginConfig* cnf)
: refCounter(0), owner(NULL), iniLvl(0)
{
hash.init(status);
iniLvl = 1;
pseudoRand.init(status);
iniLvl = 2;
AutoRelease<IConfig> conf(cnf->getDefaultConfig(status));
if (!conf)
return;
AutoRelease<IConfigEntry> ce(conf->find(status, "Key"));
if (!ce)
return;
// import a key
unsigned char key[4096];
unsigned keySize = readHexKey(status, ce->getValue(), key, sizeof(key));
check(status, rsa_import(key, keySize, &privateKey),
"ExtAuth plugin failed to initialize - error importing private RSA key");
iniLvl = 3;
}
~PluginData()
{
if (iniLvl >= 3)
rsa_free(&privateKey);
if (iniLvl >= 2)
pseudoRand.fini();
if (iniLvl >= 1)
hash.fini();
}
protected:
atomic<int> refCounter;
IReferenceCounted* owner;
PseudoRandom pseudoRand;
HashSha256 hash;
rsa_key privateKey;
int iniLvl;
};
//
// Client plugin
//
class ExtAuthClient : public IClientImpl<ExtAuthClient, ThrowStatusWrapper>, public PluginData
{
public:
ExtAuthClient(ThrowStatusWrapper* status, IPluginConfig* cnf)
: PluginData(status, cnf),
ignorePassword(false),
ignoreLogin(false)
{
AutoRelease<IConfig> conf(cnf->getDefaultConfig(status));
if (conf)
{
AutoRelease<IConfigEntry> igPass(conf->find(status, "IgnorePassword"));
if (igPass)
ignorePassword = igPass->getBoolValue();
AutoRelease<IConfigEntry> igLgn(conf->find(status, "IgnoreLogin"));
if (igLgn)
ignoreLogin = igLgn->getBoolValue();
}
}
// IClient implementation
int authenticate(ThrowStatusWrapper* status, IClientBlock* cBlock);
int release()
{
if (--refCounter == 0)
{
delete this;
return 0;
}
return 1;
}
void addRef()
{
++refCounter;
}
void setOwner(IReferenceCounted* o)
{
owner = o;
}
IReferenceCounted* getOwner()
{
return owner;
}
private:
bool ignorePassword, ignoreLogin;
};
int ExtAuthClient::authenticate(ThrowStatusWrapper* status, IClientBlock* cBlock)
{
try
{
// did we initialize correctly?
if (iniLvl < 3)
return AUTH_CONTINUE;
// check for missing login from the user
if ((!ignoreLogin) && cBlock->getLogin())
return AUTH_CONTINUE;
// check for missing password from the user
if ((!ignorePassword) && cBlock->getPassword())
return AUTH_CONTINUE;
// check for presence of authenticatiion block
IAuthBlock* authBlock = cBlock->getAuthBlock(status);
if (!authBlock)
return AUTH_CONTINUE;
if (!authBlock->first(status))
return AUTH_CONTINUE;
// and for presence of user name in that authenticatiion block
const char* login = NULL;
do
{
const char* type = authBlock->getType();
if (type && (strcmp(type, "USER") == 0))
{
login = authBlock->getName();
if (login)
break;
}
} while(authBlock->next(status));
if (!login)
return AUTH_CONTINUE;
// check if server started to talk to us
unsigned dl = 0;
const unsigned char* data = cBlock->getData(&dl);
if (dl == 0 || !data)
return AUTH_MORE_DATA;
// decrypt message
unsigned char bytes[RANDSIZE + LOGINSIZE + 1];
unsigned long outlen = RANDSIZE;
int result = 0;
check(status, rsa_decrypt_key(data, dl, bytes, &outlen, NULL, 0, hash.index, &result, &privateKey),
"Error decrypting message");
if (outlen < RANDSIZE)
error(status, "Malformed data from server - missing random block");
// next append login to random block
unsigned len = strlen(login);
if (len > LOGINSIZE)
len = LOGINSIZE;
memcpy(&bytes[RANDSIZE], login, len);
// calc hash for whole block
hash_state state;
sha256_init(&state);
check(status, sha256_process(&state, bytes, RANDSIZE + len), "Error hashing message");
unsigned char digest[256 / 8];
check(status, sha256_done(&state, digest), "Error extracting hash");
// build message
unsigned char msg[4096];
// put login to it
memcpy(msg, login, len);
msg[len++] = 0;
// append sign of hash to it
unsigned long signLen = sizeof(msg) - len;
unsigned char* sign = &msg[len];
check(status, rsa_sign_hash(digest, sizeof digest, sign, &signLen, &pseudoRand.state,
pseudoRand.index, hash.index, SALTLEN, &privateKey), "Error signing message hash");
// send message
cBlock->putData(status, len + signLen, msg);
// output the wire crypt key
ICryptKey* cKey = cBlock->newKey(status);
cKey->setSymmetric(status, "Symmetric", RANDSIZE, bytes);
HANDSHAKE_DEBUG( fprintf(stderr, "Key ="); for (unsigned n = 0; n < RANDSIZE; ++n)
fprintf(stderr, " %02u", bytes[n]); fprintf(stderr, "\n"); )
return AUTH_SUCCESS;
}
catch(const FbException& ex)
{
status->setErrors(ex.getStatus()->getErrors());
return AUTH_FAILED;
}
}
//
// Server plugin
//
class ExtAuthServer : public IServerImpl<ExtAuthServer, ThrowStatusWrapper>, public PluginData
{
public:
ExtAuthServer(ThrowStatusWrapper* status, IPluginConfig* cnf)
: PluginData(status, cnf), sentData(false)
{ }
// IServer implementation
int authenticate(ThrowStatusWrapper* status, IServerBlock* sBlock, IWriter* writerInterface);
void setDbCryptCallback(ThrowStatusWrapper* status, ICryptKeyCallback* cryptCallback)
{ }
int release()
{
if (--refCounter == 0)
{
delete this;
return 0;
}
return 1;
}
void addRef()
{
++refCounter;
}
void setOwner(IReferenceCounted* o)
{
owner = o;
}
IReferenceCounted* getOwner()
{
return owner;
}
private:
unsigned char msg[RANDSIZE + LOGINSIZE];
bool sentData;
};
int ExtAuthServer::authenticate(ThrowStatusWrapper* status, IServerBlock* sBlock, IWriter* writerInterface)
{
try
{
// did we initialize correctly?
if (iniLvl < 3)
return AUTH_CONTINUE;
unsigned dl = 0;
const unsigned char* data = sBlock->getData(&dl);
if (!sentData)
{
// fbassert(dl == 0 && !data);
// build message: first of all get some randomness
pseudoRand.getDsc()->read(msg, RANDSIZE, &pseudoRand.state);
// now encrypt that random block
unsigned char encrypted[4096];
unsigned long encLen = sizeof encrypted;
check(status, rsa_encrypt_key(msg, RANDSIZE, encrypted, &encLen, NULL, 0,
&pseudoRand.state, pseudoRand.index, hash.index, &privateKey), "Error encrypting message");
// send message
sBlock->putData(status, encLen, encrypted);
sentData = true;
return AUTH_MORE_DATA;
}
// decompose message
const char* login = reinterpret_cast<const char*>(data);
unsigned len = strnlen(login, dl);
if (len == dl)
error(status, "Wrong data from client - no signature in a message");
if (len == 0)
error(status, "Wrong data from client - empty login");
if (len > LOGINSIZE)
error(status, "Wrong data from client - login too long");
memcpy(&msg[RANDSIZE], data, len);
const unsigned char* sign = &data[len + 1];
unsigned long signLen = dl - (len + 1);
// calc hash for message
hash_state state;
sha256_init(&state);
check(status, sha256_process(&state, msg, RANDSIZE + len), "Error hashing message");
unsigned char digest[256 / 8];
check(status, sha256_done(&state, digest), "Error extracting hash");
// validate signature
int result = 0;
int err = rsa_verify_hash(sign, signLen, digest, sizeof digest, hash.index, SALTLEN, &result, &privateKey);
if (err != CRYPT_INVALID_PACKET)
check(status, err, "Error verifying digital signature");
else
result = 0;
if (!result)
error(status, "Malformed data from client - invalid digital signature");
// output the wire crypt key
ICryptKey* cKey = sBlock->newKey(status);
cKey->setSymmetric(status, "Symmetric", RANDSIZE, msg);
HANDSHAKE_DEBUG( fprintf(stderr, "Key ="); for (unsigned n = 0; n < RANDSIZE; ++n)
fprintf(stderr, " %02x", msg[n]); fprintf(stderr, "\n"); )
// store received login name in auth block
writerInterface->add(status, login);
return AUTH_SUCCESS;
}
catch(const FbException& ex)
{
status->setErrors(ex.getStatus()->getErrors());
}
return AUTH_FAILED;
}
//
// Static variables
//
PluginModule module;
Factory<ExtAuthClient> clientFactory;
Factory<ExtAuthServer> serverFactory;
} // anonymous namespace
#if defined(_WIN32)
#define FB_DLL_EXPORT __declspec(dllexport)
#else
#define FB_DLL_EXPORT
#endif
extern "C" void FB_DLL_EXPORT FB_PLUGIN_ENTRY_POINT(IMaster* m)
{
master = m;
IPluginManager* pluginManager = master->getPluginManager();
module.registerMe(pluginManager);
pluginManager->registerPluginFactory(IPluginManager::TYPE_AUTH_CLIENT, "ExtAuth", &clientFactory);
pluginManager->registerPluginFactory(IPluginManager::TYPE_AUTH_SERVER, "ExtAuth", &serverFactory);
}

64
examples/extauth/INSTALL Normal file
View File

@ -0,0 +1,64 @@
0. Brief description.
ExtAuth plugin is useful when you want to run 'execute statement on external' statement
connecting to databases on non-local servers but do not wish to explicitly add login and
password to your PL/SQL code. When 2 servers completely trust each other this plugin may
be used to enable access to remote database without entering login and password in SQL
code. To ensure that connection comes from trusted source shared secret key (placed into
plugin's .conf file) is used. That means that the value of a "Key" parameter should be
exacly the same for all trusting each other hosts. Pay attention - SQL name of connected
user on remote host may not match local logon, it depends also upon mappings on remote
host.
1. Before starting the build.
This authentication plugin is using TomCrypt (https://www.libtom.net/LibTomCrypt/) library.
Firebird since v.4 is actively using it. Depending upon build type tomcrypt binary may be
included or not included into your package. In a case when it's included you will find
appropriate H-files in tomcrypt.include subdir. If not that means that native OS library
is used and you should also work with it. Depending upon your OS you will may be need
to install development package for tomcrypt.
2. Building plugin.
Type 'make' in this directory. Build system supposes that it was not moved out of standard
firebird tree. In a case when you did it manually you will sooner of all have to change
Makefile appropriately. If you use firebird with different operating systems and/or hardware
you should build plugin for each used configuration.
3. Installing plugin.
Makefile has install target (make install) which may be used for current box. However
this is not full solution because plugin is supposed to be used to connect at least two
separate servers. See 'Testing' for more details.
4.Testing.
- imagine you have to hosts: host1 and host2;
- generate configuration file using extauth_keygen utility on any of them (only ONCE -
on ONE host !!!);
- copy that file and plugin itself to $FIREBIRD/plugins directory on each host;
- modife firebird.cond, it should contain something like:
AuthServer = Srp256, ExtAuth
AuthClient = Srp256, ExtAuth
lines, certainly something else may be used instead recommended Srp256;
- if you need WIN_SSPI plugin please add it AFTER ExtAuth;
- do not forget to restart firebird after reconfiguring it;
- create minimal required mapping on host1:
CREATE MAPPING EXT USING PLUGIN EXTAUTH FROM ANY USER TO USER EXTUSER;
- run the following script on host2:
^SET TERM ^;
EXECUTE BLOCK RETURNS(REMNAME CHAR(32)) AS BEGIN
EXECUTE STATEMENT 'SELECT CURRENT_USER FROM RDB$DATABASE'
ON EXTERNAL 'host1:employee' INTO :REMNAME;
SUSPEND;
END^
SET TERM ;^
you should get something like this:
REMNAME
==============================
EXTUSER
- explicitly specifying login and/or password in SQL statement normally deactivates
this plugin but one can use IgnoreLogin and IgnorePassword parameters to change that.

78
examples/extauth/Makefile Normal file
View File

@ -0,0 +1,78 @@
# 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
# https://www.firebirdsql.org/en/initial-developer-s-public-license-version-1-0/
#
# 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 Peshkoff
# for the Firebird Open Source RDBMS project.
#
# Copyright (c) 2020 Alexander Peshkoff <peshkoff@mail.ru>
# and all contributors signed below.
#
# All Rights Reserved.
# Contributor(s): ______________________________________.
ROOT=../..
#ROOT=$(shell cd ../..; pwd)
PLUGINS=$(ROOT)/plugins
BIN=$(ROOT)/bin
LIB=$(ROOT)/lib
LIB_PREFIX=lib
SHRLIB_EXT=so
makePluginName=$(PLUGINS)/$(LIB_PREFIX)$(1).$(SHRLIB_EXT)
TOMCRYPT_COMPILE=-DLTC_PTHREAD -DUSE_LTM -DLTM_DESC
OwnInclude=$(shell [ -d tomcrypt.include ] && echo Yes || echo No)
ifeq ($(OwnInclude), Yes)
TOMCRYPT_COMPILE += -Itomcrypt.include
TOMCRYPT_LINK=-L$(LIB)/.tm
endif
BLD_SIMPLE_KEY_AUTH=libExtAuth.so
SIMPLE_KEY_AUTH=$(call makePluginName,ExtAuth)
BLD_KEYGEN=extauth_keygen
KEYGEN=$(BIN)/$(BLD_KEYGEN)
KEYGEN_objects=keygen.o
TCWRAP_objects=TcWrapper.o
KEY_AUTH_objects=ExtAuth.o
CXXFLAGS=-std=c++11 -pthread -I$(ROOT)/include -fPIC $(TOMCRYPT_COMPILE)
LDFLAGS=-pthread -L$(LIB) -Wl,-rpath,'$$ORIGIN/../lib' $(TOMCRYPT_LINK)
LINK=c++
LINK_LIBS=-lfbclient -ltomcrypt
.PHONY: all keygen plugin install
all: keygen plugin
keygen: $(BLD_KEYGEN)
$(BLD_KEYGEN): $(KEYGEN_objects) $(TCWRAP_objects)
$(LINK) $(LDFLAGS) $^ -o $@ $(LINK_LIBS)
plugin: $(BLD_SIMPLE_KEY_AUTH)
$(BLD_SIMPLE_KEY_AUTH): $(KEY_AUTH_objects) $(TCWRAP_objects)
$(LINK) -shared $(LDFLAGS) $^ -o $@ $(LINK_LIBS)
clean:
rm -f *.o* $(BLD_KEYGEN) $(BLD_SIMPLE_KEY_AUTH)
install: $(SIMPLE_KEY_AUTH) $(KEYGEN)
$(SIMPLE_KEY_AUTH): $(BLD_SIMPLE_KEY_AUTH)
cp $^ $@
$(KEYGEN): $(BLD_KEYGEN)
cp $^ $@

View File

@ -0,0 +1,122 @@
/*
* Tomcrypt library <= firebird : c++ wrapper.
*
* 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
* https://www.firebirdsql.org/en/initial-developer-s-public-license-version-1-0/
*
* 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 Peshkoff
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2020 Alexander Peshkoff <peshkoff@mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include "TcWrapper.h"
namespace {
// LTC hack
class GInit
{
public:
GInit()
{
ltc_mp = ltm_desc;
}
};
GInit gInit;
}
void error(ThrowStatusWrapper* status, const char* text)
{
if (! status)
throw text;
ISC_STATUS_ARRAY v;
v[0] = isc_arg_gds;
v[1] = isc_random;
v[2] = isc_arg_string;
v[3] = (ISC_STATUS) text;
v[4] = isc_arg_end;
throw FbException(status, v);
}
void check(ThrowStatusWrapper* status, int err, const char* text)
{
if (err == CRYPT_OK)
return;
char buf[256];
sprintf(buf, "%s: %s", text, error_to_string(err));
error(status, buf);
}
unsigned readHexKey(ThrowStatusWrapper* status, const char* hex, unsigned char* key, unsigned bufSize)
{
unsigned char* k = key;
const char* const end = hex + strlen(hex) - 1;
for (const char* s = hex; s < end; s += 2)
{
if (k - key >= bufSize)
break;
// FF
char ss[3];
ss[0] = s[0];
ss[1] = s[1];
ss[2] = 0;
unsigned c = strtoul(ss, NULL, 16);
if (c > 255)
error(status, "Key format error");
*k++ = static_cast<unsigned char>(c);
}
return k - key;
}
void PseudoRandom::init(ThrowStatusWrapper* status)
{
// LTC hack
ltc_mp = ltm_desc;
// register yarrow
index = register_prng(&yarrow_desc);
if (index == -1)
error(status, "Error registering PRNG yarrow");
// setup the PRNG
check(status, yarrow_start(&state), "Error starting PRNG yarrow");
check(status, rng_make_prng(64, index, &state, NULL), "Error setting up PRNG yarrow");
}
void PseudoRandom::fini()
{
yarrow_done(&state);
}
const PseudoRandom::PrngDescriptor* PseudoRandom::getDsc()
{
return &yarrow_desc;
}
void Hash::init(ThrowStatusWrapper* status, const ltc_hash_descriptor* desc)
{
// LTC hack
ltc_mp = ltm_desc;
/* register SHA256 */
index = register_hash(desc);
if (index == -1)
error(status, "Error registering SHA256");
}

View File

@ -0,0 +1,210 @@
/*
* Tomcrypt library <= firebird : c++ wrapper.
*
* 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
* https://www.firebirdsql.org/en/initial-developer-s-public-license-version-1-0/
*
* 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 Peshkoff
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2020 Alexander Peshkoff <peshkoff@mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include <tomcrypt.h>
#include <firebird/Interface.h>
using namespace Firebird;
#include <stdio.h>
void error(ThrowStatusWrapper* status, const char* text);
void check(ThrowStatusWrapper* status, int err, const char* text);
unsigned readHexKey(ThrowStatusWrapper* status, const char* hex, unsigned char* key, unsigned bufSize);
class PseudoRandom
{
public:
#if CRYPT > 0x0100
typedef ltc_prng_descriptor PrngDescriptor;
#else
typedef _prng_descriptor PrngDescriptor;
#endif
void init(ThrowStatusWrapper* status);
void fini();
const PrngDescriptor* getDsc();
int index;
prng_state state;
};
class Hash
{
protected:
void init(ThrowStatusWrapper* status, const ltc_hash_descriptor* desc);
public:
void fini()
{ }
int index;
};
class HashSha1 : public Hash
{
public:
void init(ThrowStatusWrapper* status)
{
Hash::init(status, &sha1_desc);
}
};
class HashSha256 : public Hash
{
public:
void init(ThrowStatusWrapper* status)
{
Hash::init(status, &sha256_desc);
}
};
// controls reference counter of the object where points
enum NoIncrement {NO_INCREMENT};
template <typename T>
class RefPtr
{
public:
RefPtr() : ptr(NULL)
{ }
explicit RefPtr(T* p) : ptr(p)
{
if (ptr)
{
ptr->addRef();
}
}
// This special form of ctor is used to create refcounted ptr from interface,
// returned by a function (which increments counter on return)
RefPtr(NoIncrement x, T* p) : ptr(p)
{ }
RefPtr(const RefPtr& r) : ptr(r.ptr)
{
if (ptr)
{
ptr->addRef();
}
}
~RefPtr()
{
if (ptr)
{
ptr->release();
}
}
T* operator=(T* p)
{
return assign(p);
}
T* operator=(const RefPtr& r)
{
return assign(r.ptr);
}
operator T*()
{
return ptr;
}
T* operator->()
{
return ptr;
}
operator const T*() const
{
return ptr;
}
const T* operator->() const
{
return ptr;
}
bool operator !() const
{
return !ptr;
}
bool operator ==(const RefPtr& r) const
{
return ptr == r.ptr;
}
bool operator !=(const RefPtr& r) const
{
return ptr != r.ptr;
}
void clear() throw() // Used after detach/commit/close/etc., i.e. release() not needed
{
ptr = NULL;
}
void assignNoIncrement(T* const p)
{
assign(NULL);
ptr = p;
}
private:
T* assign(T* const p)
{
if (ptr != p)
{
if (p)
{
p->addRef();
}
T* tmp = ptr;
ptr = p;
if (tmp)
{
tmp->release();
}
}
return ptr;
}
T* ptr;
};
// Often used form of RefPtr
template <class R>
class AutoRelease : public RefPtr<R>
{
public:
AutoRelease(R* r)
: RefPtr<R>(NO_INCREMENT, r)
{ }
};

View File

@ -0,0 +1,73 @@
/*
* RSA key generate.
*
* 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
* https://www.firebirdsql.org/en/initial-developer-s-public-license-version-1-0/
*
* 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 Peshkoff
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2020 Alexander Peshkoff <peshkoff@mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include "TcWrapper.h"
int main(int ac, char** av)
{
try
{
int len = ac > 1 ? atoi(av[1]) : 2048;
PseudoRandom pseudoRand;
pseudoRand.init(NULL);
rsa_key key;
check(NULL, rsa_make_key(&pseudoRand.state, pseudoRand.index, len / 8, 65537, &key),
"Error making RSA key");
unsigned char outbuf[4096];
unsigned long outlen = sizeof outbuf;
check(NULL, rsa_export(outbuf, &outlen, PK_PRIVATE, &key),
"Error exporting private RSA key");
const char* const file = "ExtAuth.conf";
FILE* conf = fopen(file, "w");
if (!conf)
{
perror(file);
return 1;
}
fprintf(conf, "Key = ");
for (unsigned i = 0; i < outlen; ++i)
fprintf(conf, "%02x", outbuf[i]);
fprintf(conf, "\n#IgnoreLogin = No\n#IgnorePassword = No\n");
if (fclose(conf) != 0)
{
perror(file);
return 1;
}
printf("Wrote configuration file %s\n", file);
}
catch (const char* message)
{
fprintf(stderr, "%s\n", message);
return 1;
}
return 0;
}

View File

@ -65,7 +65,8 @@ stat12.e Event wait and signaling.
stat12t.e
WHENEVER SQLERROR and BASED_ON clause are illustrated by many programs.
^L
Embedded Dynamic SQL
@ -84,7 +85,8 @@ dyn5.e Demonstrate dynamic reallocation of SQLDA and 'describe' statement.
dynfull.e A full_dsql program (process unknown statements).
VARY struct is used by dyn3.e, dynfull.e.
^L
API Interface
@ -140,3 +142,42 @@ SQLCODE extraction from status is covered by several programs.
Zero transaction handle is covered in several programs, ex. api14.e.
Object-oriented API (interfaces)
Program Description
--------- --------------------------------------------------------
01.create.cpp / A sample of creating new database and new table in it.
01.create.pas Has pascal (delphi) implementation.
02.update.cpp UPDATE statement with parameters.
03.select.cpp SELECT statement without input parameters.
04.print_table.cpp Open cursor from attachment and access blob data.
05.user_metadata.cpp Cursor with user-implemented interface of message format.
06.fb_message.cpp Use of static messages and decfloat values.
07.blob.cpp Loading data into blob and reading it.
08.events.cpp Working with events.
09.service.cpp Using services: prints server version and db statistics.
10.backup.cpp Using services: backup database.
11.batch.cpp Working with batch interface.
12.batch_isc.cpp Working with batch interface from ISC API.
FbSampleAtomic typedef required in many examples.
dbcrypt - a sample of XOR database encryption (do not use in production!!!)
extauth - authentication for cross-server connections based on having same secret key on all servers